From 5b99474494661e4f01968a7d6482cfff6180db18 Mon Sep 17 00:00:00 2001
From: ncastejon <castejon.nicolas@gmail.com>
Date: Tue, 6 Nov 2018 09:39:12 +0100
Subject: [PATCH] Add CI configuration (docker + gitlab)

---
 .gitlab-ci.yml                                | 21 ++++++
 Dockerfile                                    | 25 +++++++
 angular.json                                  |  4 +-
 docker-compose.yml                            | 12 ++++
 nginx.conf.template                           | 10 +++
 package.json                                  |  1 +
 .../list/organization.datasource.ts           | 51 --------------
 src/app/services/organization.service.ts      | 10 +--
 src/assets/swagger/organizations.json         | 68 +++++++++++++++++++
 src/assets/swagger/resources.json             | 68 +++++++++++++++++++
 src/environments/environment.prod.ts          |  6 +-
 src/environments/environment.ts               | 11 +--
 12 files changed, 217 insertions(+), 70 deletions(-)
 create mode 100644 .gitlab-ci.yml
 create mode 100644 Dockerfile
 create mode 100644 docker-compose.yml
 create mode 100644 nginx.conf.template
 delete mode 100644 src/app/components/organizations/list/organization.datasource.ts
 create mode 100644 src/assets/swagger/organizations.json
 create mode 100644 src/assets/swagger/resources.json

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000..3d6fd32
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,21 @@
+stages:
+  - build
+  - deploy
+
+build:
+  stage: build
+  only:
+    - master
+  script:
+    - docker-compose --project-name admin-gui build
+
+deploy:
+  stage: deploy
+  only:
+    - master
+  script:
+    - docker-compose --project-name admin-gui up -d
+  environment:
+    name: development
+    url: https://data-reloaded-dev.alpha.grandlyon.com
+
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..f406035
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,25 @@
+# Stage 0, based on Node.js, to build and compile Angular
+FROM node:8.10.0 as builder
+
+# Copy the package.json file first in order to cache the modules
+COPY ./package.json /app/package.json
+WORKDIR /app
+# Install npm dependencies
+RUN npm install
+# Copy the project
+COPY . /app
+
+# Building the Angular app /dist 
+RUN npm run build:production
+
+# Stage 1, based on Nginx, to have only the compiled app
+FROM nginx
+
+COPY --from=builder /app/dist /usr/share/nginx/html
+RUN ls -l /usr/share/nginx/html
+EXPOSE 80
+
+CMD ["nginx", "-g", "daemon off;"]
+
+
+
diff --git a/angular.json b/angular.json
index e94d058..17f09f0 100644
--- a/angular.json
+++ b/angular.json
@@ -13,7 +13,7 @@
         "build": {
           "builder": "@angular-devkit/build-angular:browser",
           "options": {
-            "outputPath": "dist/admin-gui",
+            "outputPath": "dist",
             "index": "src/index.html",
             "main": "src/main.ts",
             "polyfills": "src/polyfills.ts",
@@ -23,7 +23,7 @@
               "src/assets"
             ],
             "styles": [
-              "src/styles.scss",
+              "src/styles.scss"
             ],
             "scripts": []
           },
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..784a03b
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,12 @@
+version: "2"
+
+services:
+  admin-gui:
+    container_name: admin-gui
+    build:
+      context: ./
+    volumes: 
+      - ./nginx.conf.template:/etc/nginx/conf.d/default.conf
+    ports: 
+      - 8083:80
+  
\ No newline at end of file
diff --git a/nginx.conf.template b/nginx.conf.template
new file mode 100644
index 0000000..bd5c9ac
--- /dev/null
+++ b/nginx.conf.template
@@ -0,0 +1,10 @@
+server {
+    # staging server is listening on the port 8080
+    listen 80   ;
+    server_name _;
+    root /usr/share/nginx/html/;
+
+    location / {
+        try_files $uri$args /index.html;
+    }
+}
diff --git a/package.json b/package.json
index 7cc38cb..83f31d4 100644
--- a/package.json
+++ b/package.json
@@ -5,6 +5,7 @@
     "ng": "ng",
     "start": "ng serve",
     "build": "ng build",
+    "build:production": "ng build --prod --configuration=production",
     "test": "ng test",
     "lint": "ng lint",
     "e2e": "ng e2e"
diff --git a/src/app/components/organizations/list/organization.datasource.ts b/src/app/components/organizations/list/organization.datasource.ts
deleted file mode 100644
index b874e3f..0000000
--- a/src/app/components/organizations/list/organization.datasource.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-// import { MatPaginator, MatSort } from '@angular/material';
-// import { OrganizationService } from '../../../services/organization.service';
-// import { CollectionViewer, DataSource } from '@angular/cdk/collections';
-// import { Observable } from 'rxjs/Observable';
-// import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-// import { Organization, OrganizationRO } from 'src/app/models/organization.model';
-
-// export class OrganizationDataSource implements DataSource<Organization> {
-
-//   subject: BehaviorSubject<Organization[]>;
-//   subjectCount = new BehaviorSubject<number>(null);
-
-//   constructor(
-//     private service: OrganizationService,
-//     private paginator: MatPaginator,
-//     private sorter?: MatSort,
-//     private filter?: any,
-//   ) {
-//     this.paginator.page.subscribe(() => this.loadPage());
-//     if (sorter) {
-//       this.sorter.sortChange.subscribe(() => {
-//         this.loadPage();
-//       });
-//     }
-//   }
-
-//   connect(): Observable<Organization[]> {
-//     this.subject = new BehaviorSubject([]);
-//     this.loadPage();
-//     return this.subject;
-//   }
-
-//   private loadPage() {
-//     const offset = this.paginator.pageIndex * this.paginator.pageSize;
-//     const limit = this.paginator.pageSize;
-//     let order;
-//     if (this.sorter && this.sorter.direction) {
-//       order = `${this.sorter.active}.${this.sorter.direction}`;
-//     }
-//     this.service.getOrganizations({ offset, limit, order, where: this.filter })
-//       .subscribe((items: OrganizationRO) => {
-//         this.subject.next(items.organizations);
-//         this.subjectCount.next(items.totalCount);
-//       });
-//   }
-
-//   disconnect(collectionViewer: CollectionViewer): void {
-//     this.subject.complete();
-//   }
-
-// }
diff --git a/src/app/services/organization.service.ts b/src/app/services/organization.service.ts
index 2ea35b2..dda8880 100644
--- a/src/app/services/organization.service.ts
+++ b/src/app/services/organization.service.ts
@@ -31,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.backend.url + '/organizations' + query, { observe: 'response' }).pipe(
+    return this._httpClient.get<IOrganization[]>(environment.organizations.url + query, { observe: 'response' }).pipe(
       map((response) => {
         const totalCount = response.headers.get('Content-Range');
         const organizations = [];
@@ -43,7 +43,7 @@ export class OrganizationService {
   }
 
   findById(id): Observable<Organization> {
-    return this._httpClient.get<IOrganization>(environment.backend.url + '/organizations/' + id).pipe(
+    return this._httpClient.get<IOrganization>(environment.organizations.url + id).pipe(
       map((response) => {
         return new Organization(response);
       }
@@ -51,19 +51,19 @@ export class OrganizationService {
   }
 
   delete(id) {
-    return this._httpClient.delete(environment.backend.url + '/organizations/' + id);
+    return this._httpClient.delete(environment.organizations.url + id);
   }
 
   replaceOrCreate(data): Observable<Organization> {
     console.log('replaceOrCreate ', data);
     if (data.id) {
-      return this._httpClient.put<IOrganization>(environment.backend.url + '/organizations/' + data.id, data).pipe(
+      return this._httpClient.put<IOrganization>(environment.organizations.url + data.id, data).pipe(
         map((response) => {
           return new Organization(response);
         }
         ));
     }
-    return this._httpClient.post<IOrganization>(environment.backend.url + '/organizations/', data).pipe(
+    return this._httpClient.post<IOrganization>(environment.organizations.url, data).pipe(
       map((response) => {
         return new Organization(response);
       }
diff --git a/src/assets/swagger/organizations.json b/src/assets/swagger/organizations.json
new file mode 100644
index 0000000..073cfc4
--- /dev/null
+++ b/src/assets/swagger/organizations.json
@@ -0,0 +1,68 @@
+{
+  "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
new file mode 100644
index 0000000..073cfc4
--- /dev/null
+++ b/src/assets/swagger/resources.json
@@ -0,0 +1,68 @@
+{
+  "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.prod.ts b/src/environments/environment.prod.ts
index 29b3400..a8eb3be 100644
--- a/src/environments/environment.prod.ts
+++ b/src/environments/environment.prod.ts
@@ -1,10 +1,10 @@
 
-const servicesProxyUrl = 'https://data-intothesky.alpha.grandlyon.com';
+const kongBaseUrl = 'https://kong.alpha.grandlyon.com';
 
 export const environment = {
   production: true,
 
-  backend: {
-    url: servicesProxyUrl + '/backend',
+  organizations: {
+    url: kongBaseUrl + '/organizations/',
   },
 };
diff --git a/src/environments/environment.ts b/src/environments/environment.ts
index 590ecbb..0e14e20 100644
--- a/src/environments/environment.ts
+++ b/src/environments/environment.ts
@@ -5,15 +5,8 @@
 export const environment = {
   production: false,
 
-  backend: {
-    url: 'http://localhost:3000',
+  organizations: {
+    url: 'http://localhost:3000/organizations/',
   },
 };
 
-/*
- * In development mode, to ignore zone related error stack frames such as
- * `zone.run`, `zoneDelegate.invokeTask` for easier debugging, you can
- * import the following file, but please comment it out in production mode
- * because it will have performance impact when throw error
- */
-// import 'zone.js/dist/zone-error';  // Included with Angular CLI.
-- 
GitLab