diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 000000000..557f156b4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,8 @@ +node_modules +.github +dist +coverage +Makefile +.gitignore +*keys.ts +*.keys.json diff --git a/.gitignore b/.gitignore index 93e5cb260..6cf093c1c 100644 --- a/.gitignore +++ b/.gitignore @@ -52,3 +52,6 @@ Thumbs.db # stryker temp files .stryker-tmp + +#ENV VARIABLES +.env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..24f6ebb5b --- /dev/null +++ b/Dockerfile @@ -0,0 +1,42 @@ +FROM node:14 AS development + +ENV USERNAME timetracker +ENV HOME /home/${USERNAME} + +RUN useradd -ms /bin/bash ${USERNAME} + +WORKDIR ${HOME}/time-tracker-ui +COPY . . +RUN rm -f .env +RUN chown ${USERNAME}:${USERNAME} -R ${HOME}/time-tracker-ui + +USER ${USERNAME} +RUN npm cache clean --force && npm install +EXPOSE 4200 +EXPOSE 9876 +CMD npm run config && ${HOME}/time-tracker-ui/node_modules/.bin/ng serve --host 0.0.0.0 --disableHostCheck + + + +FROM development as build +COPY .env . +RUN npm run config && npm run build + + + +FROM nginx:1.21 AS production + +ENV USERNAME app +RUN useradd -ms /bin/bash ${USERNAME} + +COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=build /home/timetracker/time-tracker-ui/dist/time-tracker /usr/share/nginx/html + +RUN chown -R ${USERNAME}:${USERNAME} /var/cache/nginx && \ + chown -R ${USERNAME}:${USERNAME} /var/log/nginx && \ + chown -R ${USERNAME}:${USERNAME} /etc/nginx/conf.d +RUN touch /var/run/nginx.pid && chown -R ${USERNAME}:${USERNAME} /var/run/nginx.pid + +USER ${USERNAME} + +EXPOSE 4200 \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..d86ace915 --- /dev/null +++ b/Makefile @@ -0,0 +1,71 @@ +override SHELL := /bin/bash + +.PHONY: help +help: ## Show this help message. + @echo 'Usage:' + @echo ' make [target] ...' + @echo + @echo 'Targets:' + @grep --no-filename -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | \ + sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' + +.PHONY: build +build: ## Create docker image with dependencies needed for development. + docker-compose build + +.PHONY: cleanup +cleanup: ## Delete image timetracker_ui + docker rmi timetracker_ui + +.PHONY: run +run: ## Execute timetracker_ui docker containe. + docker-compose --env-file ./.env up -d + +.PHONY: logs +logs: ## Show logs of timetracker_ui. + docker logs -f timetracker_ui + +.PHONY: stop +stop: ## Stop container timetracker_ui. + docker-compose stop + +.PHONY: restart +restart: ## Restart container timetracker_ui. + docker-compose stop + docker-compose up -d + +.PHONY: remove +remove: ## Delete container timetracker_ui. + docker-compose down --volumes --remove-orphans --rmi local + +.PHONY: test +test: ## Run all tests on docker container timetracker_ui. + docker-compose --env-file ./.env up -d + docker exec -it timetracker_ui bash -c "npm run test" + +.PHONY: publish +publish: ## Publish the container image timetracker_ui. + docker tag timetracker_ui:latest $(registry_url)/timetracker_ui:latest + docker push $(registry_url)/timetracker_ui:latest + +.PHONY: build_prod +build_prod: ## Create docker image with dependencies needed for production. + docker build --target production -t timetracker_ui_prod -f Dockerfile . + +.PHONY: run_prod +run_prod: ## Execute timetracker_ui_prod docker container. + docker run -d -p 4200:4200 --name timetracker_ui_prod timetracker_ui_prod + +.PHONY: remove_prod +remove_prod: ## Delete container timetracker_ui_pro. + docker stop timetracker_ui_prod + docker rm timetracker_ui_prod + +.PHONY: publish_prod +publish_prod: ## Publish the container image timetracker_ui_prod. + docker tag timetracker_ui_prod:latest $(registry_url)/timetracker_ui_prod:latest + docker push $(registry_url)/timetracker_ui_prod:latest + +.PHONY: login +login: ## Login in respository of docker images. + az acr login --name $(container_registry) diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 000000000..d7516c1a1 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,31 @@ +version: '3.9' +services: + time-tracker-ui: + container_name: timetracker_ui + image: timetracker_ui + build: + target: development + context: . + dockerfile: ./Dockerfile + ports: + - 4200:4200 + - 9876:9876 + environment: + AUTHORITY: ${AUTHORITY} + CLIENT_ID: ${CLIENT_ID} + SCOPES: ${SCOPES} + STACK_EXCHANGE_ID: ${STACK_EXCHANGE_ID} + STACK_EXCHANGE_ACCESS_TOKEN: ${STACK_EXCHANGE_ACCESS_TOKEN} + AZURE_APP_CONFIGURATION_CONNECTION_STRING: ${AZURE_APP_CONFIGURATION_CONNECTION_STRING} + AUTHORITY_JSON: ${AUTHORITY_JSON} + CLIENT_ID_JSON: ${CLIENT_ID_JSON} + SCOPES_JSON: ${SCOPES_JSON} + volumes: + - ./src:/home/timetracker/time-tracker-ui/src/ + - ./scripts:/home/timetracker/time-tracker-ui/scripts/ + - ./e2e:/home/timetracker/time-tracker-ui/e2e/ + - ./coverage:/home/timetracker/time-tracker-ui/coverage + - ./angular.json:/home/timetracker/time-tracker-ui/angular.json + - ./karma.conf.js:/home/timetracker/time-tracker-ui/karma.conf.js + - ./package.json:/home/timetracker/time-tracker-ui/package.json + - ./webpack.config.js:/home/timetracker/time-tracker-ui/webpack.config.js diff --git a/nginx.conf b/nginx.conf new file mode 100644 index 000000000..824374fdc --- /dev/null +++ b/nginx.conf @@ -0,0 +1,12 @@ +server { + listen 4200; + + root /usr/share/nginx/html; + index index.html; + + server_name _; + + location / { + try_files $uri /index.html; + } +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index eac419d50..d03a23ce6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7877,6 +7877,11 @@ "is-obj": "^2.0.0" } }, + "dotenv": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-14.2.0.tgz", + "integrity": "sha512-05POuPJyPpO6jqzTNweQFfAyMSD4qa4lvsMOWyTRTdpHKy6nnnN+IYWaXF+lHivhBH/ufDKlR4IWCAN3oPnHuw==" + }, "duplexer2": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", diff --git a/package.json b/package.json index d4b451b0d..3b8aa8974 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "time-tracker", "version": "1.61.0", "scripts": { + "config": "ts-node ./scripts/setenv.ts", "preinstall": "npx npm-force-resolutions", "ng": "ng", "start": "ng serve", @@ -44,6 +45,7 @@ "datatables.net-responsive": "2.2.6", "datatables.net-responsive-dt": "2.2.6", "date-fns": "2.22.1", + "dotenv": "^14.2.0", "jquery": "3.5.1", "jszip": "3.7.0", "minimist": "1.2.5", diff --git a/scripts/setenv.ts b/scripts/setenv.ts new file mode 100644 index 000000000..0c07a1b30 --- /dev/null +++ b/scripts/setenv.ts @@ -0,0 +1,34 @@ +const { writeFile } = require('fs'); +require('dotenv').config(); + +const pathJs = `./src/environments/keys.ts` +const contentKeys = +`export const AUTHORITY = '${process.env.AUTHORITY}'; +export const CLIENT_ID = '${process.env.CLIENT_ID}'; +export const SCOPES = ['${process.env.SCOPES}']; +export const STACK_EXCHANGE_ID = '${process.env.STACK_EXCHANGE_ID}'; +export const STACK_EXCHANGE_ACCESS_TOKEN = '${process.env.STACK_EXCHANGE_ACCESS_TOKEN}'; +export const AZURE_APP_CONFIGURATION_CONNECTION_STRING = '${process.env.AZURE_APP_CONFIGURATION_CONNECTION_STRING}'; +`; + +writeFile(pathJs, contentKeys, function (err) { + if (err) { + console.log(err); + } + console.log(`Wrote variables to ${pathJs}`); +}); + +const pathJson = `./src/environments/.keys.json` +const contentKeysJson = +`{ + "authority": "${process.env.AUTHORITY_JSON}", + "client_id": "${process.env.CLIENT_ID_JSON}", + "scopes": ["${process.env.SCOPES_JSON}"] +}`; + +writeFile(pathJson, contentKeysJson, function (err) { + if (err) { + console.log(err); + } + console.log(`Wrote variables to ${pathJson}`); +});