From 5f19bc146dd2726f6a447365e2fac10051f7e020 Mon Sep 17 00:00:00 2001 From: FORESTIER Fabien <fabien.forestier@soprasteria.com> Date: Mon, 8 Apr 2019 15:59:35 +0200 Subject: [PATCH] Update CI/CD workflow and variable config handling --- .gitlab-ci.yml | 62 +++++++++++------ Dockerfile | 4 +- angular.json | 19 ++---- config/config-dev.json | 8 +++ config/config-rec.json | 8 +++ docker-compose.yml | 10 +-- package.json | 4 +- src/app/app.module.ts | 43 ++++++------ src/app/components/index.ts | 34 ++++++++++ .../list/organizations.component.ts | 1 + src/app/services/app-config.service.ts | 26 +++++++ src/app/services/index.ts | 16 +++++ src/app/services/organization.service.ts | 13 ++-- src/app/services/resource.service.ts | 12 ++-- src/assets/config/config.json | 8 +++ src/assets/swagger/organizations.json | 68 ------------------- src/assets/swagger/resources.json | 68 ------------------- src/environments/environment.dev.ts | 13 ---- src/environments/environment.prod.ts | 6 ++ src/environments/environment.rec.ts | 13 ---- src/environments/environment.ts | 7 -- src/main.ts | 16 ++++- 22 files changed, 212 insertions(+), 247 deletions(-) create mode 100644 config/config-dev.json create mode 100644 config/config-rec.json create mode 100644 src/app/components/index.ts create mode 100644 src/app/services/app-config.service.ts create mode 100644 src/app/services/index.ts create mode 100644 src/assets/config/config.json delete mode 100644 src/assets/swagger/organizations.json delete mode 100644 src/assets/swagger/resources.json delete mode 100644 src/environments/environment.dev.ts create mode 100644 src/environments/environment.prod.ts delete mode 100644 src/environments/environment.rec.ts diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2202721..71334d6 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -4,39 +4,61 @@ stages: build_development: stage: build + tags: + - build only: - - master + - development script: - - export NODE_ENV=DEV - - docker-compose --project-name admin-gui-dev build --build-arg env=dev admin-gui + - export TAG=dev + - export APP_PORT=8090 + - export CONFIG_FILE_PATH=./config/config.json + - docker-compose build --build-arg conf=dev admin-gui + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker-compose push + +build_release: + stage: build + tags: + - build + only: + - tags + except: + - /^(?!master).+@/ + script: + - export TAG=$(echo $CI_COMMIT_TAG | sed 's/v//g') + - export APP_PORT=8090 + - export CONFIG_FILE_PATH=./config/config.json + - docker-compose build --build-arg conf=prod admin-gui + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker-compose push deploy_development: stage: deploy only: - - master + - development script: - - export NODE_ENV=DEV - - docker-compose --project-name admin-gui-dev up -d + - export TAG=dev + - export APP_PORT=8090 + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - docker-compose pull + - export CONFIG_FILE_PATH=./config/config-dev.json + - docker-compose --project-name admin-gui-${TAG} up -d --force-recreate environment: name: development - # url: - -build_staging: - stage: build - only: - - staging - script: - - export NODE_ENV=REC - - sed -i 's/DEV_/REC_/g' docker-compose.yml - - docker-compose --project-name admin-gui-rec build --build-arg env=rec admin-gui deploy_staging: stage: deploy only: - - staging + - development + when: manual script: - - export NODE_ENV=REC - - sed -i 's/DEV_/REC_/g' docker-compose.yml - - docker-compose --project-name admin-gui-rec up -d + - export TAG=staging + - export APP_PORT=8190 + - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY + - TAG=dev docker-compose pull + - docker tag $CI_REGISTRY/refonte-data/admin-gui:dev $CI_REGISTRY/refonte-data/admin-gui:${TAG} + - docker push $CI_REGISTRY/refonte-data/admin-gui:${TAG} + - export CONFIG_FILE_PATH=./config/config-rec.json + - docker-compose --project-name admin-gui-${TAG} up -d --force-recreate environment: name: staging diff --git a/Dockerfile b/Dockerfile index d6a76d8..a385161 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,10 +9,10 @@ RUN npm install # Copy the project COPY . /app -ARG env +ARG conf # Building the Angular app /dist -RUN npm run build:${env} +RUN npm run build:${conf} # Stage 1, based on Nginx, to have only the compiled app FROM nginx diff --git a/angular.json b/angular.json index ff8bfd7..c6a5c19 100644 --- a/angular.json +++ b/angular.json @@ -23,33 +23,28 @@ "src/assets" ], "styles": [ - "src/styles.scss", + "src/styles.scss" ], "scripts": [] }, "configurations": { "development": { - "fileReplacements": [ - { - "replace": "src/environments/environment.ts", - "with": "src/environments/environment.dev.ts" - } - ], - "optimization": true, + "optimization": false, "outputHashing": "all", - "sourceMap": false, - "extractCss": true, + "sourceMap": true, + "extractCss": false, "namedChunks": false, "aot": true, "extractLicenses": true, "vendorChunk": false, - "buildOptimizer": true + "buildOptimizer": false, + "fileReplacements": [] }, "recette": { "fileReplacements": [ { "replace": "src/environments/environment.ts", - "with": "src/environments/environment.rec.ts" + "with": "src/environments/environment.prod.ts" } ], "optimization": true, diff --git a/config/config-dev.json b/config/config-dev.json new file mode 100644 index 0000000..3320942 --- /dev/null +++ b/config/config-dev.json @@ -0,0 +1,8 @@ +{ + "organizations": { + "url": "https://kong-dev.alpha.grandlyon.com/organizations/" + }, + "resources": { + "url": "https://kong-dev.alpha.grandlyon.com/resources/resources/" + } +} \ No newline at end of file diff --git a/config/config-rec.json b/config/config-rec.json new file mode 100644 index 0000000..4955a9a --- /dev/null +++ b/config/config-rec.json @@ -0,0 +1,8 @@ +{ + "organizations": { + "url": "https://kong-rec.alpha.grandlyon.com/organizations/" + }, + "resources": { + "url": "https://kong-rec.alpha.grandlyon.com/resources/resources/" + } +} \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index adbbe04..1efb1d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,13 +1,13 @@ -version: "2" +version: "3.1" services: admin-gui: - container_name: admin-gui-${NODE_ENV} - build: - context: ./ + build: . + image: registry.alpha.grandlyon.com/refonte-data/admin-gui:${TAG} volumes: - ./nginx.conf.template:/etc/nginx/conf.d/default.conf + - ${CONFIG_FILE_PATH}:/usr/share/nginx/html/assets/config/config.json ports: - - ${DEV_APP_PORT}:80 + - ${APP_PORT}:80 restart: unless-stopped \ No newline at end of file diff --git a/package.json b/package.json index c08ce54..44e295b 100644 --- a/package.json +++ b/package.json @@ -5,8 +5,8 @@ "ng": "ng", "start": "ng serve", "build": "ng build", - "build:dev": "ng build --prod --configuration=development", - "build:rec": "ng build --prod --configuration=recette", + "build:dev": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration=development", + "build:prod": "node --max_old_space_size=4096 ./node_modules/@angular/cli/bin/ng build --configuration=production", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" diff --git a/src/app/app.module.ts b/src/app/app.module.ts index dae310c..c5e0ccd 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,35 +1,27 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; +import { NgModule, APP_INITIALIZER } from '@angular/core'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; import { AppComponent } from './app.component'; -import { OrganizationsComponent } from './components/organizations/list/organizations.component'; -import { OrganizationService } from './services/organization.service'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { HttpClientModule } from '@angular/common/http'; import { RouterModule } from '@angular/router'; -import { MenuComponent } from './components/menu/menu.component'; import { AppRoutingModule } from './app.routing.module'; -import { WelcomeComponent } from './components/welcome/welcome.component'; -import { OrganizationDetailComponent } from './components/organizations/detail/organization-detail.component'; -import { OrganizationFormComponent } from './components/organizations/edit/organization-form.component'; -import { PaginatorComponent } from './components/paginator/paginator.component'; -import { ResourcesComponent } from './components/resources/list/resources.component'; -import { ResourceService } from './services/resource.service'; -import { ResourceFormComponent } from './components/resources/edit/resource-form.component'; -import { ResourceDetailComponent } from './components/resources/detail/resource-detail.component'; +import { AppServices, AppConfigService } from './services'; +import { AppComponents } from './components'; + +export function initAppConfig(appConfigService: AppConfigService) { + return (): Promise<any> => { + return new Promise((resolve, reject) => { + appConfigService.load(); + resolve(); + }); + }; +} @NgModule({ declarations: [ AppComponent, - OrganizationsComponent, - PaginatorComponent, - OrganizationDetailComponent, - OrganizationFormComponent, - MenuComponent, - WelcomeComponent, - ResourcesComponent, - ResourceFormComponent, - ResourceDetailComponent, + ...AppComponents, ], imports: [ AppRoutingModule, @@ -41,8 +33,13 @@ import { ResourceDetailComponent } from './components/resources/detail/resource- ReactiveFormsModule, ], providers: [ - OrganizationService, - ResourceService, + ...AppServices, + { + provide: APP_INITIALIZER, + useFactory: initAppConfig, + deps: [AppConfigService], + multi: true, + }, ], bootstrap: [AppComponent] }) diff --git a/src/app/components/index.ts b/src/app/components/index.ts new file mode 100644 index 0000000..c120701 --- /dev/null +++ b/src/app/components/index.ts @@ -0,0 +1,34 @@ +import { MenuComponent } from './menu/menu.component'; +import { OrganizationDetailComponent } from './organizations/detail/organization-detail.component'; +import { OrganizationFormComponent } from './organizations/edit/organization-form.component'; +import { OrganizationsComponent } from './organizations/list/organizations.component'; +import { PaginatorComponent } from './paginator/paginator.component'; +import { ResourceDetailComponent } from './resources/detail/resource-detail.component'; +import { ResourceFormComponent } from './resources/edit/resource-form.component'; +import { ResourcesComponent } from './resources/list/resources.component'; +import { WelcomeComponent } from './welcome/welcome.component'; + +export { + MenuComponent, + OrganizationDetailComponent, + OrganizationFormComponent, + OrganizationsComponent, + PaginatorComponent, + ResourceDetailComponent, + ResourceFormComponent, + ResourcesComponent, + WelcomeComponent, +}; + +// tslint:disable-next-line:variable-name +export const AppComponents = [ + MenuComponent, + OrganizationDetailComponent, + OrganizationFormComponent, + OrganizationsComponent, + PaginatorComponent, + ResourceDetailComponent, + ResourceFormComponent, + ResourcesComponent, + WelcomeComponent, +]; diff --git a/src/app/components/organizations/list/organizations.component.ts b/src/app/components/organizations/list/organizations.component.ts index a0299af..17d063f 100644 --- a/src/app/components/organizations/list/organizations.component.ts +++ b/src/app/components/organizations/list/organizations.component.ts @@ -56,6 +56,7 @@ export class OrganizationsComponent implements OnInit { private search() { this.organizationsService.getOrganizations() .subscribe((items: OrganizationRO) => { + console.log(items); this.organizations = items.organizations; this.totalElement = items.totalCount; diff --git a/src/app/services/app-config.service.ts b/src/app/services/app-config.service.ts new file mode 100644 index 0000000..edabf90 --- /dev/null +++ b/src/app/services/app-config.service.ts @@ -0,0 +1,26 @@ +import { Injectable } from '@angular/core'; + +export class AppConfig { + organizations: { + url: string; + }; + resources: { + url: string; + }; +} + +export let APP_CONFIG: AppConfig; + +@Injectable() +export class AppConfigService { + + constructor() { } + + public load() { + return new Promise((resolve, reject) => { + const conf = new AppConfig(); + APP_CONFIG = Object.assign(conf, window['adminGuiEnvConfig']); + resolve(); + }); + } +} diff --git a/src/app/services/index.ts b/src/app/services/index.ts new file mode 100644 index 0000000..24455cc --- /dev/null +++ b/src/app/services/index.ts @@ -0,0 +1,16 @@ +import { AppConfigService } from './app-config.service'; +import { OrganizationService } from './organization.service'; +import { ResourceService } from './resource.service'; + +export { + AppConfigService, + OrganizationService, + ResourceService, +}; + +// tslint:disable-next-line:variable-name +export const AppServices = [ + AppConfigService, + OrganizationService, + ResourceService, +]; diff --git a/src/app/services/organization.service.ts b/src/app/services/organization.service.ts index 2343797..c536056 100644 --- a/src/app/services/organization.service.ts +++ b/src/app/services/organization.service.ts @@ -3,7 +3,8 @@ import { Observable , Subject } from 'rxjs'; import { map } from 'rxjs/operators'; import { HttpClient } from '@angular/common/http'; import { Organization, IOrganization, OrganizationRO } from '../models/organization.model'; -import { environment } from 'src/environments/environment'; +import { APP_CONFIG } from './app-config.service'; + @Injectable() export class OrganizationService { @@ -30,7 +31,7 @@ export class OrganizationService { query += '&offset=' + (this.pageNumber ? (this.pageNumber - 1) * this.limit : 0); query += '&sort_by=' + this.sortOptions.value + '.' + this.sortOptions.order; - return this._httpClient.get<IOrganization[]>(environment.organizations.url + query, { observe: 'response' }).pipe( + return this._httpClient.get<IOrganization[]>(APP_CONFIG.organizations.url + query, { observe: 'response' }).pipe( map((response) => { const totalCount = response.headers.get('Content-Range'); const organizations = []; @@ -42,7 +43,7 @@ export class OrganizationService { } findById(id): Observable<Organization> { - return this._httpClient.get<IOrganization>(environment.organizations.url + id).pipe( + return this._httpClient.get<IOrganization>(APP_CONFIG.organizations.url + id).pipe( map((response) => { return new Organization(response); } @@ -50,12 +51,12 @@ export class OrganizationService { } delete(id) { - return this._httpClient.delete(environment.organizations.url + id); + return this._httpClient.delete(APP_CONFIG.organizations.url + id); } replaceOrCreate(data: Organization): Observable<Organization> { if (data.id) { - return this._httpClient.put<IOrganization>(environment.organizations.url + data.id, data).pipe( + return this._httpClient.put<IOrganization>(APP_CONFIG.organizations.url + data.id, data).pipe( map((response) => { return new Organization(response); } @@ -65,7 +66,7 @@ export class OrganizationService { data.links.forEach((link) => { delete link.id; }); - return this._httpClient.post<IOrganization>(environment.organizations.url, data).pipe( + return this._httpClient.post<IOrganization>(APP_CONFIG.organizations.url, data).pipe( map((response) => { return new Organization(response); } diff --git a/src/app/services/resource.service.ts b/src/app/services/resource.service.ts index ed890a2..d1b0d38 100644 --- a/src/app/services/resource.service.ts +++ b/src/app/services/resource.service.ts @@ -3,7 +3,7 @@ import { Observable , Subject } from 'rxjs'; import { map } from 'rxjs/operators'; import { HttpClient } from '@angular/common/http'; import { Resource, IResource, ResourceRO } from '../models/resource.model'; -import { environment } from 'src/environments/environment'; +import { APP_CONFIG } from './app-config.service'; @Injectable() export class ResourceService { @@ -30,7 +30,7 @@ export class ResourceService { query += '&offset=' + (this.pageNumber ? (this.pageNumber - 1) * this.limit : 0); query += '&sort_by=' + this.sortOptions.value + '.' + this.sortOptions.order; - return this._httpClient.get<IResource[]>(environment.resources.url + query, { observe: 'response' }).pipe( + return this._httpClient.get<IResource[]>(APP_CONFIG.resources.url + query, { observe: 'response' }).pipe( map((response) => { const totalCount = response.headers.get('Content-Range'); const resources = []; @@ -42,7 +42,7 @@ export class ResourceService { } findById(id): Observable<Resource> { - return this._httpClient.get<IResource>(environment.resources.url + id).pipe( + return this._httpClient.get<IResource>(APP_CONFIG.resources.url + id).pipe( map((response) => { return new Resource(response); } @@ -50,18 +50,18 @@ export class ResourceService { } delete(id) { - return this._httpClient.delete(environment.resources.url + id); + return this._httpClient.delete(APP_CONFIG.resources.url + id); } replaceOrCreate(data): Observable<Resource> { if (data.id) { - return this._httpClient.put<IResource>(environment.resources.url + data.id, data).pipe( + return this._httpClient.put<IResource>(APP_CONFIG.resources.url + data.id, data).pipe( map((response) => { return new Resource(response); } )); } - return this._httpClient.post<IResource>(environment.resources.url, data).pipe( + return this._httpClient.post<IResource>(APP_CONFIG.resources.url, data).pipe( map((response) => { return new Resource(response); } diff --git a/src/assets/config/config.json b/src/assets/config/config.json new file mode 100644 index 0000000..3320942 --- /dev/null +++ b/src/assets/config/config.json @@ -0,0 +1,8 @@ +{ + "organizations": { + "url": "https://kong-dev.alpha.grandlyon.com/organizations/" + }, + "resources": { + "url": "https://kong-dev.alpha.grandlyon.com/resources/resources/" + } +} \ No newline at end of file diff --git a/src/assets/swagger/organizations.json b/src/assets/swagger/organizations.json deleted file mode 100644 index 073cfc4..0000000 --- a/src/assets/swagger/organizations.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "description": "The actors API description", - "version": "1.0", - "title": "Actors example" - }, - "basePath": "/localhost:3001", - "tags": [], - "schemes": ["http"], - "paths": { - "/organizations": { - "get": { - "summary": "Get all organizations", - "responses": { - "200": { - "description": "" - } - }, - "tags": ["organizations"], - "produces": ["application/json"], - "consumes": ["application/json"] - }, - "post": { - "summary": "Create one organization", - "parameters": [{ - "name": "Organization", - "required": true, - "in": "body", - "schema": { - "$ref": "#/definitions/Organization" - } - }], - "responses": { - "201": { - "description": "The record has been successfully created." - } - }, - "tags": ["organizations"], - "produces": ["application/json"], - "consumes": ["application/json"] - } - } - }, - "definitions": { - "Organization": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "website": { - "type": "string" - }, - "logo": { - "type": "string" - } - }, - "required": ["id", "name", "description"] - } - } -} \ No newline at end of file diff --git a/src/assets/swagger/resources.json b/src/assets/swagger/resources.json deleted file mode 100644 index 073cfc4..0000000 --- a/src/assets/swagger/resources.json +++ /dev/null @@ -1,68 +0,0 @@ -{ - "swagger": "2.0", - "info": { - "description": "The actors API description", - "version": "1.0", - "title": "Actors example" - }, - "basePath": "/localhost:3001", - "tags": [], - "schemes": ["http"], - "paths": { - "/organizations": { - "get": { - "summary": "Get all organizations", - "responses": { - "200": { - "description": "" - } - }, - "tags": ["organizations"], - "produces": ["application/json"], - "consumes": ["application/json"] - }, - "post": { - "summary": "Create one organization", - "parameters": [{ - "name": "Organization", - "required": true, - "in": "body", - "schema": { - "$ref": "#/definitions/Organization" - } - }], - "responses": { - "201": { - "description": "The record has been successfully created." - } - }, - "tags": ["organizations"], - "produces": ["application/json"], - "consumes": ["application/json"] - } - } - }, - "definitions": { - "Organization": { - "type": "object", - "properties": { - "id": { - "type": "number" - }, - "name": { - "type": "string" - }, - "description": { - "type": "string" - }, - "website": { - "type": "string" - }, - "logo": { - "type": "string" - } - }, - "required": ["id", "name", "description"] - } - } -} \ No newline at end of file diff --git a/src/environments/environment.dev.ts b/src/environments/environment.dev.ts deleted file mode 100644 index c6dcbcb..0000000 --- a/src/environments/environment.dev.ts +++ /dev/null @@ -1,13 +0,0 @@ - -const kongBaseUrl = 'https://kong-dev.alpha.grandlyon.com'; - -export const environment = { - production: true, - - organizations: { - url: kongBaseUrl + '/organizations/', - }, - resources: { - url: kongBaseUrl + '/resources/', - }, -}; diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts new file mode 100644 index 0000000..cc68086 --- /dev/null +++ b/src/environments/environment.prod.ts @@ -0,0 +1,6 @@ + +const kongBaseUrl = 'https://kong-dev.alpha.grandlyon.com'; + +export const environment = { + production: true, +}; diff --git a/src/environments/environment.rec.ts b/src/environments/environment.rec.ts deleted file mode 100644 index 90736b8..0000000 --- a/src/environments/environment.rec.ts +++ /dev/null @@ -1,13 +0,0 @@ - -const kongBaseUrl = 'https://kong-rec.alpha.grandlyon.com'; - -export const environment = { - production: true, - - organizations: { - url: kongBaseUrl + '/organizations/', - }, - resources: { - url: kongBaseUrl + '/resources/', - }, -}; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index ad23462..0fe39f1 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -4,12 +4,5 @@ export const environment = { production: false, - - organizations: { - url: 'http://localhost:3000/organizations/', - }, - resources: { - url: 'http://localhost:3003/resources/', - }, }; diff --git a/src/main.ts b/src/main.ts index 91ec6da..475ba5a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -8,5 +8,17 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(AppModule) - .catch(err => console.log(err)); +fetch('./assets/config/config.json') + .then(response => response.json()) + .then((config) => { + if (!config) { + return; + } + + // Store the response so that your ConfigService can read it. + window['adminGuiEnvConfig'] = config; + + platformBrowserDynamic().bootstrapModule(AppModule) + .catch(err => console.log(err)); + + }); -- GitLab