Skip to content

Commit

Permalink
build app config
Browse files Browse the repository at this point in the history
  • Loading branch information
wwelling committed Dec 4, 2021
1 parent 46d340a commit c155532
Show file tree
Hide file tree
Showing 13 changed files with 498 additions and 55 deletions.
1 change: 1 addition & 0 deletions config/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
appConfig.*.json
14 changes: 14 additions & 0 deletions config/appConfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"ui": {
"ssl": false,
"host": "localhost",
"port": 4000,
"nameSpace": "/"
},
"rest": {
"ssl": true,
"host": "api7.dspace.org",
"port": 443,
"nameSpace": "/server"
}
}
8 changes: 4 additions & 4 deletions scripts/set-env.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { writeFile } from 'fs';
import { environment as commonEnv } from '../src/environments/environment.common';
import { GlobalConfig } from '../src/config/global-config.interface';
import { AppConfig } from '../src/config/app-config.interface';
import { ServerConfig } from '../src/config/server-config.interface';
import { hasValue } from '../src/app/shared/empty.util';

Expand Down Expand Up @@ -42,7 +42,7 @@ const processEnv = {
process.env.DSPACE_REST_PORT,
process.env.DSPACE_REST_NAMESPACE,
process.env.DSPACE_REST_SSL)
} as GlobalConfig;
} as AppConfig;

import(environmentFilePath)
.then((file) => generateEnvironmentFile(merge.all([commonEnv, file.environment, processEnv], mergeOptions)))
Expand All @@ -51,7 +51,7 @@ import(environmentFilePath)
generateEnvironmentFile(merge(commonEnv, processEnv, mergeOptions))
});

function generateEnvironmentFile(file: GlobalConfig): void {
function generateEnvironmentFile(file: AppConfig): void {
file.production = production;
buildBaseUrls(file);
const contents = `export const environment = ` + JSON.stringify(file);
Expand Down Expand Up @@ -86,7 +86,7 @@ function createServerConfig(host?: string, port?: string, nameSpace?: string, ss
return result;
}

function buildBaseUrls(config: GlobalConfig): void {
function buildBaseUrls(config: AppConfig): void {
for (const key in config) {
if (config.hasOwnProperty(key) && config[key].host) {
config[key].baseUrl = [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@ import { NotificationsService } from '../notifications.service';
import { NotificationType } from '../models/notification-type';
import { notificationsReducer } from '../notifications.reducers';
import { NotificationOptions } from '../models/notification-options.model';
import { INotificationBoardOptions } from '../../../../config/notifications-config.interfaces';
import { GlobalConfig } from '../../../../config/global-config.interface';
import { Notification } from '../models/notification.model';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { TranslateLoaderMock } from '../../mocks/translate-loader.mock';
Expand All @@ -33,16 +31,6 @@ describe('NotificationComponent', () => {
/* tslint:disable:no-empty */
notifications: []
});
const envConfig: GlobalConfig = {
notifications: {
rtl: false,
position: ['top', 'right'],
maxStack: 8,
timeOut: 5000,
clickToClose: true,
animate: 'scale'
} as INotificationBoardOptions,
} as any;

TestBed.configureTestingModule({
imports: [
Expand Down
13 changes: 0 additions & 13 deletions src/app/shared/notifications/notifications.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { of as observableOf } from 'rxjs';
import { NewNotificationAction, RemoveAllNotificationsAction, RemoveNotificationAction } from './notifications.actions';
import { Notification } from './models/notification.model';
import { NotificationType } from './models/notification-type';
import { GlobalConfig } from '../../../config/global-config.interface';
import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
import { TranslateLoaderMock } from '../mocks/translate-loader.mock';
import { storeModuleConfig } from '../../app.reducer';
Expand All @@ -19,18 +18,6 @@ describe('NotificationsService test', () => {
select: observableOf(true)
});
let service: NotificationsService;
let envConfig: GlobalConfig;

envConfig = {
notifications: {
rtl: false,
position: ['top', 'right'],
maxStack: 8,
timeOut: 5000,
clickToClose: true,
animate: 'scale'
},
} as any;

beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
Expand Down
1 change: 1 addition & 0 deletions src/assets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
appConfig.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { InjectionToken } from '@angular/core';
import { Config } from './config.interface';
import { ServerConfig } from './server-config.interface';
import { CacheConfig } from './cache-config.interface';
Expand All @@ -14,7 +15,7 @@ import { AuthConfig } from './auth-config.interfaces';
import { UIServerConfig } from './ui-server-config.interface';
import { MediaViewerConfig } from './media-viewer-config.interface';

export interface GlobalConfig extends Config {
interface AppConfig extends Config {
ui: UIServerConfig;
rest: ServerConfig;
production: boolean;
Expand All @@ -33,3 +34,10 @@ export interface GlobalConfig extends Config {
themes: ThemeConfig[];
mediaViewer: MediaViewerConfig;
}

const APP_CONFIG = new InjectionToken<AppConfig>('APP_CONFIG');

export {
AppConfig,
APP_CONFIG
};
151 changes: 151 additions & 0 deletions src/config/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import * as colors from 'colors';
import * as fs from 'fs';
import { join } from 'path';
import { AppConfig } from './app-config.interface';
import { Config } from './config.interface';
import { DefaultAppConfig } from './default-app-config';
import { ServerConfig } from './server-config.interface';

const CONFIG_PATH = join(process.cwd(), 'config');

const APP_CONFIG_PATH = join(CONFIG_PATH, 'appConfig.json');

type Environment = 'production' | 'development' | 'test';

const getEnvironment = (): Environment => {
let environment: Environment = 'development';
if (!!process.env.NODE_ENV) {
switch (process.env.NODE_ENV) {
case 'prod':
case 'production':
environment = 'production';
break;
case 'test':
environment = 'test';
break;
case 'dev':
case 'development':
break;
default:
console.warn(`Unknown NODE_ENV ${process.env.NODE_ENV}. Defaulting to development`);
}
}

return environment;
};

const getDistConfigPath = (env: Environment) => {
// determine app config filename variations
let envVariations;
switch (env) {
case 'production':
envVariations = ['prod', 'production'];
break;
case 'test':
envVariations = ['test'];
break;
case 'development':
default:
envVariations = ['dev', 'development']
}

// check if any environment variations of app config exist
for (const envVariation of envVariations) {
const altDistConfigPath = join(CONFIG_PATH, `appConfig.${envVariation}.json`);
if (fs.existsSync(altDistConfigPath)) {
return altDistConfigPath;
}
}

// return default config/appConfig.json
return APP_CONFIG_PATH;
};

const overrideWithConfig = (config: Config, pathToConfig: string) => {
try {
console.log(`Overriding app config with ${pathToConfig}`);
const externalConfig = fs.readFileSync(pathToConfig, 'utf8');
Object.assign(config, JSON.parse(externalConfig));
} catch (err) {
console.error(err);
}
};

const overrideWithEnvironment = (config: Config, key: string = '') => {
for (const property in config) {
const variable = `${key}${!!key ? '_' : ''}${property.toUpperCase()}`;
const innerConfig = config[property];
if (!!innerConfig) {
if (typeof innerConfig === 'object') {
overrideWithEnvironment(innerConfig, variable);
} else {
if (!!process.env[variable]) {
console.log(`Applying environment variable ${variable} with value ${process.env[variable]}`);
config[property] = process.env[variable];
}
}
}
}
};

const buildBaseUrl = (config: ServerConfig): void => {
config.baseUrl = [
config.ssl ? 'https://' : 'http://',
config.host,
config.port && config.port !== 80 && config.port !== 443 ? `:${config.port}` : '',
config.nameSpace && config.nameSpace.startsWith('/') ? config.nameSpace : `/${config.nameSpace}`
].join('');
};

export const buildAppConfig = (destConfigPath: string): AppConfig => {
// start with default app config
const appConfig: AppConfig = new DefaultAppConfig();

// determine which dist app config by environment
const env = getEnvironment();

switch (env) {
case 'production':
console.log(`Building ${colors.red.bold(`production`)} app config`);
break;
case 'test':
console.log(`Building ${colors.blue.bold(`test`)} app config`);
break;
default:
console.log(`Building ${colors.green.bold(`development`)} app config`);
}

// override with dist config
const distConfigPath = getDistConfigPath(env);
if (fs.existsSync(distConfigPath)) {
overrideWithConfig(appConfig, distConfigPath);
} else {
console.warn(`Unable to find dist config file at ${distConfigPath}`);
}

// override with external config if specified by environment variable `APP_CONFIG_PATH`
const externalConfigPath = process.env.APP_CONFIG_PATH;
if (!!externalConfigPath) {
if (fs.existsSync(externalConfigPath)) {
overrideWithConfig(appConfig, externalConfigPath);
} else {
console.warn(`Unable to find external config file at ${externalConfigPath}`);
}
}

// override with environment variables
overrideWithEnvironment(appConfig);

// apply build defined production
appConfig.production = env === 'production';

// build base URLs
buildBaseUrl(appConfig.ui);
buildBaseUrl(appConfig.rest);

fs.writeFileSync(destConfigPath, JSON.stringify(appConfig, null, 2));

console.log(`Angular ${colors.bold('appConfig.json')} file generated correctly at ${colors.bold(destConfigPath)} \n`);

return appConfig;
}
Loading

0 comments on commit c155532

Please sign in to comment.