diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 000000000..51e60c1ec --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,61 @@ +name: Build and Deploy + +on: + push: + branches: + - master + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Node.js + uses: actions/setup-node@v3 + with: + node-version: "10" + + - name: Install nvm + run: | + curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.2/install.sh | bash + . ~/.nvm/nvm.sh + nvm install 10 + nvm use 10 + + - name: Install dependencies + run: | + npm i --legacy-peer-deps + npm i --save-dev @types/jasmine@3.6.2 --legacy-peer-deps + + - name: Build production + env: + NODE_OPTIONS: --max-old-space-size=4096 + run: npm run build:production + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_EMAIL }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build Docker image + run: docker build --platform linux/amd64 -t rannybal2024/nimble-frontend-service:${{ github.run_number }} . + + - name: Push Docker image + run: docker push rannybal2024/nimble-frontend-service:${{ github.run_number }} + + - name: Update Kubernetes deployment with new image + run: | + sed -i 's|IMAGE_TAG|rannybal2024/nimble-frontend-service:${{ github.run_number }}|' kubernetes/deploy.yml + + - name: Set up kubeconfig + run: echo "${{ secrets.KUBECONFIG }}" > $HOME/kube-config.yaml + + - name: Apply Kubernetes deployment + run: kubectl --kubeconfig=$HOME/kube-config.yaml apply -f kubernetes/deploy.yml + + - name: Clean up kubeconfig + run: rm -f $HOME/kube-config.yaml diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..84bcdb242 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,2 @@ +FROM nginx +COPY dist/ /usr/share/nginx/html \ No newline at end of file diff --git a/kubernetes/deploy.yml b/kubernetes/deploy.yml index 085d55e9b..132f3ea90 100644 --- a/kubernetes/deploy.yml +++ b/kubernetes/deploy.yml @@ -1,55 +1,59 @@ -apiVersion: extensions/v1beta1 +apiVersion: apps/v1 kind: Deployment metadata: + namespace: nimble-platform labels: - app: nimble-platform - name: frontend-service + nim-prod: frontend-service name: frontend-service spec: replicas: 1 selector: matchLabels: - app: nimble-platform - name: frontend-service - strategy: - rollingUpdate: - maxSurge: 1 - maxUnavailable: 1 - type: RollingUpdate - revisionHistoryLimit: 5 + nim-prod: frontend-service template: metadata: labels: - app: nimble-platform - name: frontend-service + nim-prod: frontend-service spec: + imagePullSecrets: + - name: do-registry containers: - - image: nimbleplatform/frontend-service - imagePullPolicy: Always - name: frontend-service - ports: - - containerPort: 8080 - name: http - protocol: TCP - resources: - requests: - cpu: 200m - memory: 256Mi + - env: + - name: CONFIG_SERVER_FAILFAST + value: "true" + - name: CONFIG_SERVER_URI + value: http://config-server:8888 + - name: DISCOVERY_ENABLED + value: "true" + - name: DISCOVERY_PREFER_IP + value: "false" + - name: DISCOVERY_SERVER_URI + value: http://service-discovery:8761 + - name: LOGSTASH_URI + value: logstash:5000 + - name: SPRING_PROFILES_ACTIVE + value: docker + - name: _JAVA_OPTIONS + value: -Xmx512m -Xms50m + image: IMAGE_TAG #assigned on runtime by github-action + imagePullPolicy: Always + name: frontend-service + ports: + - containerPort: 80 + restartPolicy: Always --- - +apiVersion: v1 kind: Service metadata: - name: frontend-service + namespace: nimble-platform labels: - app: nimble-platform - name: frontend-service + nim-prod: frontend-service + name: frontend-service spec: ports: - name: http - protocol: TCP - port: 8080 - targetPort: 8080 + port: 80 + targetPort: 80 selector: - app: nimble-platform - name: frontend-service + nim-prod: frontend-service diff --git a/package.json b/package.json index 741ccc0f6..1d385ff24 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "zone.js": "~0.8" }, "devDependencies": { + "@ngtools/webpack": "~7.3", "@types/angular": "~1.6", "@types/angular-animate": "~1.5", "@types/angular-cookies": "~1.4", @@ -72,14 +73,32 @@ "@types/angular-resource": "~1.5", "@types/angular-route": "~1.3", "@types/angular-sanitize": "~1.3", + "@types/core-js": "~2.5", "@types/file-saver": "~1.3", - "@types/jasmine": "~2.8", + "@types/jasmine": "^3.6.11", + "@types/jquery": "~3.3", "@types/lunr": "~2.1", + "@types/node": "~10.12", "@types/underscore": "~1.8", + "angular-router-loader": "~0.8", + "angular2-template-loader": "~0.6", + "awesome-typescript-loader": "~5.2", "babel-cli": "~6.26", + "babel-core": "~6.26", + "babel-loader": "~7.1", "babel-preset-angular2": "~0.0", + "babel-preset-env": "~1.7", "canonical-path": "~0.0", + "clean-webpack-plugin": "~0.1", "concurrently": "~3.6", + "copy-webpack-plugin": "~5.0", + "cross-env": "~5.2", + "css-loader": "~1.0", + "cssnano": "~4.1", + "del-cli": "~1.1", + "file-loader": "~4.0", + "html-loader": "~0.5", + "html-webpack-plugin": "4.0.0-beta.5", "http-server-legacy": "~0.11", "jasmine": "~3.2", "jasmine-core": "~3.1", @@ -89,48 +108,29 @@ "karma-jasmine": "~1.1", "karma-jasmine-html-reporter": "~1.1", "karma-phantomjs-launcher": "~1.0", + "lite-server": "~2.4", "lodash": "~4.17", + "mini-css-extract-plugin": "~0.7", + "node-sass": "~4.12", + "optimize-css-assets-webpack-plugin": "~5.0", "phantomjs-prebuilt": "~2.1", "protractor": "~5.3", "rollup": "~0.57", "rollup-plugin-commonjs": "~9.1", "rollup-plugin-node-resolve": "~3.3", "rollup-plugin-uglify": "~3.0", - "source-map-explorer": "~1.5", - "tslint": "~5.10", - "typings": "~2.1", - "@ngtools/webpack": "~7.3", - "@types/core-js": "~2.5", - "@types/node": "~10.12", - "angular-router-loader": "~0.8", - "angular2-template-loader": "~0.6", - "awesome-typescript-loader": "~5.2", - "babel-core": "~6.26", - "babel-loader": "~7.1", - "babel-preset-env": "~1.7", - "clean-webpack-plugin": "~0.1", - "copy-webpack-plugin": "~5.0", - "cross-env": "~5.2", - "css-loader": "~1.0", - "cssnano": "~4.1", - "del-cli": "~1.1", - "file-loader": "~4.0", - "html-loader": "~0.5", - "html-webpack-plugin": "4.0.0-beta.5", - "lite-server": "~2.4", - "mini-css-extract-plugin": "~0.7", - "node-sass": "~4.12", - "optimize-css-assets-webpack-plugin": "~5.0", "sass-loader": "~7.1", + "source-map-explorer": "~1.5", "style-loader": "~0.23", "to-string-loader": "~1.1", + "tslint": "~5.10", "typescript": "~3.2", + "typings": "~2.1", "uglifyjs-webpack-plugin": "~2.0", "webpack": "~4.29", "webpack-cli": "~3.2", "webpack-dev-server": "~3.1", - "webpack-merge": "~4.2", - "@types/jquery": "~3.3" + "webpack-merge": "~4.2" }, "repository": {} } diff --git a/src/app/app.component.html b/src/app/app.component.html index d45e2f115..174d6dc81 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -181,13 +181,13 @@ -
b((U-e)/(h=i+1))&&B("overflow"),e+=(c-a)*h,a=c,r=0;r
U&&B("overflow"),F==a){for(m=e,l=s;!(m<(u=l<=o?g:o+v<=l?v:l-o));l+=s)d=m-u,A=s-u,S.push(k(T(u+d%A,0))),m=b(d/A);S.push(k(T(m,0))),o=R(e,h,i==t),e=0,++i}++e,++a}return S.join("")}if(u={version:"1.4.1",ucs2:{decode:D,encode:P},decode:K,encode:G,toASCII:function(n){return M(n,function(n){return d.test(n)?"xn--"+G(n):n})},toUnicode:function(n){return M(n,function(n){return A.test(n)?K(n.slice(4).toLowerCase()):n})}},"object"==o(e(0))&&e(0))void 0===(t=function(){return u}.call(a,e,a,n))||(n.exports=t);else if(c&&m)if(n.exports==c)m.exports=u;else for(F in u)u.hasOwnProperty(F)&&(c[F]=u[F]);else r.punycode=u}(void 0)}).call(this,e(7)(n),e(8))},function(n,a,e){"use strict";n.exports=function(n){return n.webpackPolyfill||(n.deprecate=function(){},n.paths=[],n.children||(n.children=[]),Object.defineProperty(n,"loaded",{enumerable:!0,get:function(){return n.l}}),Object.defineProperty(n,"id",{enumerable:!0,get:function(){return n.i}}),n.webpackPolyfill=1),n}},function(n,a,e){"use strict";var i,t="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(n){return typeof n}:function(n){return n&&"function"==typeof Symbol&&n.constructor===Symbol&&n!==Symbol.prototype?"symbol":typeof n};i=function(){return this}();try{i=i||new Function("return this")()}catch(n){"object"===("undefined"==typeof window?"undefined":t(window))&&(i=window)}n.exports=i}])}); \ No newline at end of file diff --git a/src/assets/js/countries-list/index.es5.min.js.map b/src/assets/js/countries-list/index.es5.min.js.map new file mode 100644 index 000000000..b027fa928 --- /dev/null +++ b/src/assets/js/countries-list/index.es5.min.js.map @@ -0,0 +1 @@ +{"version":3,"file":"index.es5.min.js","sources":["index.js"],"sourcesContent":["'use strict';\n\nconst continents = require('./continents.json');\nconst countries = require('./countries.emoji.json');\nconst languages = require('./languages.json');\nconst languagesAll = require('./languages.all.json');\nconst { ucs2 } = require('punycode');\nconst\n // \"Regional Indicator Symbol Letter A\" - \"Latin Capital Letter A\"\n UNICODE_BASE = 127462 - 'A'.charCodeAt(0),\n // Country code should contain exactly 2 uppercase characters from A..Z\n COUNTRY_CODE_REGEX = /^[A-Z]{2}$/;\n\nconst getEmojiFlag = (countryCode) => {\n if (!COUNTRY_CODE_REGEX.test(countryCode)) {\n return '';\n }\n\n return ucs2.encode(\n countryCode\n .split('')\n .map(letter => UNICODE_BASE + letter.charCodeAt(0))\n );\n};\n\nconst getUnicode = (emoji) => {\n return ucs2.decode(emoji)\n .map(code => 'U+' + Number(code).toString(16).toUpperCase())\n .join(' ');\n};\n\nmodule.exports = {\n continents,\n countries,\n languages,\n languagesAll,\n\n getEmojiFlag,\n getUnicode,\n};\n"],"names":[],"mappings":";;;;;;AAEA,MAAM,UAAU,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;AAChD,MAAM,SAAS,GAAG,OAAO,CAAC,wBAAwB,CAAC,CAAC;AACpD,MAAM,SAAS,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;AAC9C,MAAM,YAAY,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAAC;AACrD,MAAM,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;AACrC,MAEE,YAAY,GAAG,MAAM,GAAG,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC;MAEzC,kBAAkB,GAAG,YAAY,CAAC;;AAEpC,MAAM,YAAY,GAAG,CAAC,WAAW,KAAK;EACpC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,WAAW,CAAC,EAAE;IACzC,OAAO,EAAE,CAAC;GACX;;EAED,OAAO,IAAI,CAAC,MAAM;IAChB,WAAW;OACR,KAAK,CAAC,EAAE,CAAC;OACT,GAAG,CAAC,MAAM,IAAI,YAAY,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;GACtD,CAAC;CACH,CAAC;;AAEF,MAAM,UAAU,GAAG,CAAC,KAAK,KAAK;EAC5B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;KACtB,GAAG,CAAC,IAAI,IAAI,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;KAC3D,IAAI,CAAC,GAAG,CAAC,CAAC;CACd,CAAC;;AAEF,MAAM,CAAC,OAAO,GAAG;EACf,UAAU;EACV,SAAS;EACT,SAAS;EACT,YAAY;;EAEZ,YAAY;EACZ,UAAU;CACX,CAAC;;;;"} \ No newline at end of file diff --git a/src/assets/js/countries-list/index.es5.min.test.js b/src/assets/js/countries-list/index.es5.min.test.js new file mode 100644 index 000000000..ceae216c0 --- /dev/null +++ b/src/assets/js/countries-list/index.es5.min.test.js @@ -0,0 +1,24 @@ +const fs = require('fs'); +const es5 = require('./index.es5.min.js'); +const lib = require('./index.js'); + +test('has proper ES5 export', () => { + expect(typeof es5).toBe('object'); + expect(typeof lib).toBe('object'); + + Object.keys(lib).forEach(prop => { + expect(es5.hasOwnProperty(prop)).toBeTruthy(); + }); +}); + +test('loads ES5 - + + - - + + - +