From f9a1cddde572107d8e98815db71544ebe065242a Mon Sep 17 00:00:00 2001 From: Zabilsya Date: Tue, 26 Nov 2024 23:24:24 +0600 Subject: [PATCH] [DOP-21434] create docker image and docker ci --- .dockerignore | 12 +++++ .github/workflows/ci.yml | 35 -------------- .github/workflows/linters.yml | 44 ++++++++++++++++++ .github/workflows/release.yml | 71 +++++++++++++++++++++++++++++ .gitignore | 5 +- docker/Dockerfile | 28 ++++++++++++ docker/env.sh | 29 ++++++++++++ docker/nginx.conf | 16 +++++++ package.json | 2 +- src/index.html | 1 + src/shared/config/axios/instance.ts | 2 +- src/types/index.d.ts | 6 +++ 12 files changed, 213 insertions(+), 38 deletions(-) create mode 100644 .dockerignore delete mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/linters.yml create mode 100644 .github/workflows/release.yml create mode 100644 docker/Dockerfile create mode 100644 docker/env.sh create mode 100644 docker/nginx.conf diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..f762c3d5 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,12 @@ +.git/ +.github/ +.dockerignore +.gitignore +./docker/Dockerfile +*docker-compose* + +.husky/ +node_modules/ +public/env-config.js +env-config.js +dist/ \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 6d952eca..00000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: SyncMaster UI CI - -on: - pull_request: - branches: - - '**' - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - name: Checkout repository - uses: actions/checkout@v3 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '20' - cache: 'yarn' - - - name: Install dependencies - run: yarn - - - name: Run Types check - run: yarn type-check - - - name: Run ESLint - run: yarn lint - - - name: Run Prettier check - run: yarn prettier:check - - - name: Build project - run: yarn build diff --git a/.github/workflows/linters.yml b/.github/workflows/linters.yml new file mode 100644 index 00000000..d5eae691 --- /dev/null +++ b/.github/workflows/linters.yml @@ -0,0 +1,44 @@ +name: Code analysis + +on: + push: + branches: + - develop + pull_request: + branches-ignore: + - master + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + linters: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + + - name: Install modules + run: yarn install --frozen-lockfile + + - name: Cache modules + uses: actions/cache@v4 + with: + path: ./node_modules + key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + restore-keys: | + ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} + ${{ runner.os }}-yarn- + + - name: Run Type check + run: yarn run type-check + + - name: Run ESLint + run: npx eslint + + - name: Run Prettier + run: npx prettier --check + + - name: Build project + run: yarn run build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 00000000..3f3dad1e --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,71 @@ +name: Release + +on: + push: + branches: + - develop + tags: + - '[0-9]+.[0-9]+.[0-9]+' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref }} + cancel-in-progress: true + +jobs: + release: + name: Build & push backend image to Dockerhub + runs-on: ubuntu-latest + if: github.repository == 'MobileTeleSystems/syncmaster-ui' # prevent running on forks + + steps: + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Checkout code + uses: actions/checkout@v4 + + - name: Set tag + id: set_tag + run: | + if [[ "${{ github.ref_type }}" == "branch" && "${{ github.ref_name }}" == "develop" ]]; then + echo "TAG=mtsrus/syncmaster-ui:develop" >> $GITHUB_ENV + elif [[ "${{ github.ref_type }}" == "tag" ]]; then + echo "TAG=mtsrus/syncmaster-ui:latest,mtsrus/syncmaster-ui:${{ github.ref_name }}" >> $GITHUB_ENV + fi + + - name: Build UI image + uses: docker/build-push-action@v6 + with: + tags: ${{ env.TAG }} + context: . + file: ./docker/Dockerfile + target: prod + pull: true + push: true + cache-to: type=inline + cache-from: mtsrus/syncmaster-ui:develop + platforms: | + linux/amd64 + linux/arm64/v8 + provenance: mode=max + + - name: Update DockerHub Description + uses: peter-evans/dockerhub-description@v4 + if: github.ref_type == 'tag' + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + # this requires token with read+write+delete permissions. read+write is not enough! + password: ${{ secrets.DOCKERHUB_TOKEN }} + repository: mtsrus/syncmaster-ui + short-description: ${{ github.event.repository.description }} + enable-url-completion: true diff --git a/.gitignore b/.gitignore index 38f45faa..736864e2 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,7 @@ yarn-error.log /**/generated -/**/build \ No newline at end of file +/**/build + +public/env-config.js +env-config.js \ No newline at end of file diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 00000000..50704135 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,28 @@ +FROM node:23.1.0 AS build + +WORKDIR /app + +COPY .yarnrc.yml . +COPY .yarn ./.yarn + +COPY package.json yarn.lock ./ +RUN yarn install --immutable + +COPY . . +RUN yarn build + + +FROM nginx:stable AS prod + +WORKDIR /usr/share/nginx/html + +COPY ./docker/nginx.conf /etc/nginx/conf.d/default.conf +COPY --from=build /app/dist . + +COPY ./docker/env.sh env.sh +COPY .env .env +RUN chmod +x env.sh + +EXPOSE 3000 + +CMD ["/bin/bash", "-c", "/usr/share/nginx/html/env.sh && nginx -g \"daemon off;\""] diff --git a/docker/env.sh b/docker/env.sh new file mode 100644 index 00000000..ff3aa0ef --- /dev/null +++ b/docker/env.sh @@ -0,0 +1,29 @@ +#!/bin/bash + +# Recreate config file +rm -rf env-config.js +touch env-config.js + +# Add assignment +echo "window.env = {" >> env-config.js + +# Read each line in .env file +# Each line represents key=value pairs +while read -r line || [[ -n "$line" ]]; +do + # Split env variables by character `=` + if printf '%s\n' "$line" | grep -q -e '='; then + varname=$(printf '%s\n' "$line" | sed -e 's/=.*//') + varvalue=$(printf '%s\n' "$line" | sed -e 's/^[^=]*=//') + fi + + # Read value of current variable if exists as Environment variable + value=$(printf '%s\n' "${!varname}") + # Otherwise use value from .env file + [[ -z $value ]] && value=${varvalue} + + # Append configuration property to JS file + echo " $varname: \"$value\"," >> env-config.js +done < .env + +echo "}" >> env-config.js \ No newline at end of file diff --git a/docker/nginx.conf b/docker/nginx.conf new file mode 100644 index 00000000..43455e36 --- /dev/null +++ b/docker/nginx.conf @@ -0,0 +1,16 @@ +server { + listen 3000; + + location / { + root /usr/share/nginx/html; + index index.html index.htm; + try_files $uri $uri/ /index.html; + } + + error_page 500 502 503 504 /50x.html; + + location = /50x.html { + root /usr/share/nginx/html; + } + +} \ No newline at end of file diff --git a/package.json b/package.json index d6e6155d..24447767 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "description": "Initial settings for react app", "license": "UNLICENSED", "scripts": { - "start": "cross-env NODE_ENV=development webpack serve", + "start": "./docker/env.sh && mkdir -p ./public && cp env-config.js ./public/ && cross-env NODE_ENV=development webpack serve", "start:prod": "cross-env NODE_ENV=production webpack serve", "build": "rimraf ./dist && cross-env NODE_OPTIONS=--max_old_space_size=8192 && cross-env NODE_ENV=production webpack", "lint": "eslint .", diff --git a/src/index.html b/src/index.html index aa4e0767..e3a6686d 100644 --- a/src/index.html +++ b/src/index.html @@ -5,6 +5,7 @@ SyncMaster +
diff --git a/src/shared/config/axios/instance.ts b/src/shared/config/axios/instance.ts index f2e98dd3..86705701 100644 --- a/src/shared/config/axios/instance.ts +++ b/src/shared/config/axios/instance.ts @@ -3,7 +3,7 @@ import axios from 'axios'; import { requestInterceptor, responseSuccessInterceptor } from './interceptors'; export const axiosInstance = axios.create({ - baseURL: process.env.API_URL, + baseURL: window.env.API_URL, headers: { Accept: 'application/json', 'Content-Type': 'application/json', diff --git a/src/types/index.d.ts b/src/types/index.d.ts index 2158b266..e8bf734b 100644 --- a/src/types/index.d.ts +++ b/src/types/index.d.ts @@ -1,4 +1,10 @@ declare module '*.less' { const content: Record; export default content; +} + +interface Window { + env: { + API_URL: string; + }; } \ No newline at end of file