Добавляем lint-staged в NestJS и Angular приложения, включаем семантическое версионирование фронтенда

от автора

Предыдущая статья: Семантическое версионирование NestJS и Angular приложений в NX-монорепозитории

Так как версионирование через плагин nx-semantic-release происходит путем анализа изменений по связанным Typescript-импортам, то нам нужно минимизировать эти изменения, для этого в проект подключаем https://www.npmjs.com/package/lint-staged и добавляем строгости в Typescript-код.

1. Добавляем lint-staged для форматирования кода при коммите

Эта утилита запускает определенные скрипты при каждом коммите, для того чтобы форматирование кода в git-репозитории было всегда одинаковым и не важно как именно разработчик настроил свою локальную среду разработки.

Команды

npx mrm@2 lint-staged 

Вывод консоли

$ npx mrm@2 lint-staged Running lint-staged... Update package.json Installing husky...  added 1 package, removed 1 package, and audited 2765 packages in 18s  331 packages are looking for funding   run `npm fund` for details  49 vulnerabilities (31 moderate, 18 high)  To address issues that do not require attention, run:   npm audit fix  To address all issues possible (including breaking changes), run:   npm audit fix --force  Some issues need review, and may require choosing a different dependency.  Run `npm audit` for details. husky - Git hooks installed husky - created .husky/pre-commit 

2. Обновляем prepare скрипт и секцию lint-staged в корневом package.json

Скрипт prepare автоматически появляется после установки lint-staged, я не стал его убирать просто немного изменил способ запуска, запускаю через npx.

В небольших проектах pre-commit-хук с lint-staged отрабатывает быстро, но если проект большой то он может работать дольше, в таком случаи проще всем разработчикам договориться об общем стиле форматирования, для того чтобы уменьшить количество файлов которые необходимо будет проверить линтерам.

В pre-commit-хук не стоит прописывать различные тяжелые операции, например: генерацию фронтенд клиента, такие операции лучше производить в CI/CD или локально руками по необходимости, а не на каждый коммит.

Обновляем часть файла package.json

{   "scripts": {     // ...     "prepare": "npx -y husky install"     // ...   },   // ...   "lint-staged": {     "*.{js,ts}": "eslint --fix",     "*.{js,ts,css,scss,md}": "prettier --ignore-unknown --write",     "*.js": "eslint --cache --fix"   }   // ... } 

3. Запускаем форматирование lint-staged-ом вручную

Для того чтобы можно было вручную проверить работу lint-staged необходимо добавить все файлы в stage запустить его через npx.

Команды

git add . npx lint-staged 

Вывод консоли

 npx lint-staged ✔ Preparing lint-staged... ✔ Running tasks for staged files... ✔ Applying modifications from tasks... ✔ Cleaning up temporary files... 

4. Обновляем package.json и NX-конфигурацию в бэкенд приложении

Так как в предыдущем посте мы отключали публикацию в npm, то у нас не происходила смена версии приложения в исходном коде, для того чтобы версия в исходном коде сменилась и при этом публикация в npm не запускалась, нужно добавить опцию "private": true.

Обновляем файл apps/server/package.json

{   "name": "server",   "version": "0.0.3",   "private": true,   "scripts": {},   "dependencies": {     "pm2": ">=5.3.0",     "dotenv": ">=16.3.1"   },   "devScripts": ["manual:prepare", "serve:dev:server"],   "prodScripts": ["manual:prepare", "start:prod:server"],   "testsScripts": ["test:server"] } 

Обновляем часть файла apps/server/package.json

{   "name": "server",   // ...   "targets": {     // ...     "semantic-release": {       "executor": "@theunderscorer/nx-semantic-release:semantic-release",       "options": {         "github": true,         "changelog": true,         "npm": true,         "tagFormat": "server-v${VERSION}"       }     }   } } 

5. Создаем package.json в фронтенд приложении и добавляем команду semantic-release в его NX-конфигурацию

Ранее в постах мы запускали передеплой Nginx при изменениях версии бэкенд приложения.

Для того чтобы Nginx-образ с встроенным фронтендом собирался только при изменениях фронтенда нам нужно версионировать фронтенд и использовать его версию в дальнейших логиках с Docker-образами и Kubernetes-шаблонами.

Для работы семантического версионирования необходимо наличие package.json у библиотеки или приложения, поэтому мы добавляем его в фронтенд приложение и указываем "private": true.

Создаем файл apps/client/package.json

{   "name": "client",   "version": "0.0.1",   "private": true } 

Добавляем новый таргет в файл apps/client/project.json

{   "name": "client",   // ...   "targets": {     // ...     "semantic-release": {       "executor": "@theunderscorer/nx-semantic-release:semantic-release",       "options": {         "github": true,         "changelog": true,         "npm": true,         "tagFormat": "client-v${VERSION}"       }     }   } } 

6. Добавляем новую динамическую переменную окружения

Добавляем новую переменную с версией фронтенд приложения в файл .kubernetes/set-env.sh и .docker/set-env.sh

export CLIENT_VERSION=$(cd ./apps/client && npm pkg get version --workspaces=false | tr -d \") 

7. Обновляем деплоймент файл

Обновляем файл .kubernetes/templates/client/3.deployment.yaml

apiVersion: apps/v1 kind: Deployment metadata:   namespace: '%NAMESPACE%'   name: %NAMESPACE%-client spec:   replicas: 1   selector:     matchLabels:       pod: %NAMESPACE%-client-container   template:     metadata:       namespace: '%NAMESPACE%'       labels:         app: %NAMESPACE%-client         pod: %NAMESPACE%-client-container     spec:       containers:         - name: %NAMESPACE%-client           image: ghcr.io/nestjs-mod/nestjs-mod-fullstack-nginx:%CLIENT_VERSION%           imagePullPolicy: IfNotPresent           ports:             - containerPort: %NGINX_PORT%           envFrom:             - configMapRef:                 name: %NAMESPACE%-config             - configMapRef:                 name: %NAMESPACE%-client-config           resources:             requests:               memory: 128Mi               cpu: 100m             limits:               memory: 512Mi               cpu: 300m       imagePullSecrets:         - name: docker-regcred 

8. Обновляем CI/CD-конфигурацию деплоя для Kubernetes и «Docker Compose»

Обновляем часть файла .github/workflows/kubernetes.yml и .github/workflows/docker-compose.workflows.yml

jobs:   # ...   check-nginx-image:     runs-on: ubuntu-latest     needs: [release]     continue-on-error: true     steps:       - name: Checkout repository         if: ${{ !contains(github.event.head_commit.message, '[skip cache]') && !contains(github.event.head_commit.message, '[skip nginx cache]') }}         uses: actions/checkout@v4       - name: Set ENV vars         if: ${{ !contains(github.event.head_commit.message, '[skip cache]') && !contains(github.event.head_commit.message, '[skip nginx cache]') }}         id: version         run: |           echo "client_version="$(cd ./apps/client && npm pkg get version --workspaces=false | tr -d \") >> "$GITHUB_OUTPUT"       - name: Check exists docker image         if: ${{ !contains(github.event.head_commit.message, '[skip cache]') && !contains(github.event.head_commit.message, '[skip nginx cache]') }}         id: check-exists         run: |           export TOKEN=$(curl -u ${{ github.actor }}:${{ secrets.GITHUB_TOKEN }} https://${{ env.REGISTRY }}/token\?scope\="repository:${{ env.NGINX_IMAGE_NAME}}:pull" | jq -r .token)           curl --head --fail -H "Authorization: Bearer $TOKEN" https://${{ env.REGISTRY }}/v2/${{ env.NGINX_IMAGE_NAME}}/manifests/${{ steps.version.outputs.client_version }}       - name: Store result of check exists docker image         id: store-check-exists         if: ${{ !contains(github.event.head_commit.message, '[skip cache]') && !contains(github.event.head_commit.message, '[skip nginx cache]') && !contains(needs.check-exists.outputs.result, 'HTTP/2 404') }}         run: |           echo "conclusion=success" >> "$GITHUB_OUTPUT"     outputs:       result: ${{ steps.store-check-exists.outputs.conclusion }}   # ...   build-and-push-nginx-image:     runs-on: ubuntu-latest     needs: [build-and-push-builder-image, check-nginx-image]     permissions:       contents: read       packages: write       attestations: write       id-token: write     steps:       - name: Checkout repository         if: ${{ needs.check-nginx-image.outputs.result != 'success' || contains(github.event.head_commit.message, '[skip cache]') || contains(github.event.head_commit.message, '[skip nginx cache]') }}         uses: actions/checkout@v4       - name: Set ENV vars         if: ${{ needs.check-nginx-image.outputs.result != 'success' || contains(github.event.head_commit.message, '[skip cache]') || contains(github.event.head_commit.message, '[skip nginx cache]') }}         id: version         run: |           echo "root_version="$(npm pkg get version --workspaces=false | tr -d \") >> "$GITHUB_OUTPUT"           echo "client_version="$(cd ./apps/client && npm pkg get version --workspaces=false | tr -d \") >> "$GITHUB_OUTPUT"       - name: Log in to the Container registry         if: ${{ needs.check-nginx-image.outputs.result != 'success' || contains(github.event.head_commit.message, '[skip cache]') || contains(github.event.head_commit.message, '[skip nginx cache]') }}         uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1         with:           registry: ${{ env.REGISTRY }}           username: ${{ github.actor }}           password: ${{ secrets.GITHUB_TOKEN }}       - name: Generate and build production code         if: ${{ needs.check-nginx-image.outputs.result != 'success' || contains(github.event.head_commit.message, '[skip cache]') || contains(github.event.head_commit.message, '[skip nginx cache]') }}         run: |           mkdir -p dist           docker run -v ./dist:/usr/src/app/dist -v ./apps:/usr/src/app/apps -v ./libs:/usr/src/app/libs ${{ env.REGISTRY}}/${{ env.BUILDER_IMAGE_NAME}}:${{ steps.version.outputs.root_version }}       - name: Build and push Docker image         if: ${{ needs.check-nginx-image.outputs.result != 'success' || contains(github.event.head_commit.message, '[skip cache]') || contains(github.event.head_commit.message, '[skip nginx cache]') }}         id: push         uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4         with:           context: .           push: true           file: ./.docker/nginx.Dockerfile           tags: ${{ env.REGISTRY}}/${{ env.NGINX_IMAGE_NAME}}:${{ steps.version.outputs.client_version }},${{ env.REGISTRY}}/${{ env.NGINX_IMAGE_NAME}}:latest           cache-from: type=registry,ref=${{ env.REGISTRY}}/${{ env.NGINX_IMAGE_NAME}}:${{ steps.version.outputs.client_version }}           cache-to: type=inline       - name: Generate artifact attestation         continue-on-error: true         if: ${{ needs.check-nginx-image.outputs.result != 'success' || contains(github.event.head_commit.message, '[skip cache]') || contains(github.event.head_commit.message, '[skip nginx cache]') }}         uses: actions/attest-build-provenance@v1         with:           subject-name: ${{ env.REGISTRY }}/${{ env.NGINX_IMAGE_NAME}}           subject-digest: ${{ steps.push.outputs.digest }}           push-to-registry: true 

9. Обновляем локальный сборщик Docker-образов

Обновляем файл .docker/build-images.sh

#!/bin/bash set -e  # We check the existence of a local image with the specified tag, if it does not exist, we start building the image export IMG=${REGISTRY}/${BUILDER_IMAGE_NAME}:${ROOT_VERSION} && [ -n "$(docker images -q $IMG)" ] || docker build --network host -t "${REGISTRY}/${BUILDER_IMAGE_NAME}:${ROOT_VERSION}" -t "${REGISTRY}/${BUILDER_IMAGE_NAME}:latest" -f ./.docker/builder.Dockerfile . --progress=plain  # We build all applications docker run --network host -v ./dist:/usr/src/app/dist -v ./apps:/usr/src/app/apps -v ./libs:/usr/src/app/libs ${REGISTRY}/${BUILDER_IMAGE_NAME}:${ROOT_VERSION}  # We check the existence of a local image with the specified tag, if it does not exist, we start building the image export IMG=${REGISTRY}/${BASE_SERVER_IMAGE_NAME}:${ROOT_VERSION} && [ -n "$(docker images -q $IMG)" ] || docker build --network host -t "${REGISTRY}/${BASE_SERVER_IMAGE_NAME}:${ROOT_VERSION}" -t "${REGISTRY}/${BASE_SERVER_IMAGE_NAME}:latest" -f ./.docker/base-server.Dockerfile . --progress=plain  # We check the existence of a local image with the specified tag, if it does not exist, we start building the image export IMG=${REGISTRY}/${SERVER_IMAGE_NAME}:${SERVER_VERSION} && [ -n "$(docker images -q $IMG)" ] || docker build --network host -t "${REGISTRY}/${SERVER_IMAGE_NAME}:${SERVER_VERSION}" -t "${REGISTRY}/${SERVER_IMAGE_NAME}:latest" -f ./.docker/server.Dockerfile . --progress=plain --build-arg=\"BASE_SERVER_IMAGE_TAG=${ROOT_VERSION}\"  # We check the existence of a local image with the specified tag, if it does not exist, we start building the image export IMG=${REGISTRY}/${MIGRATIONS_IMAGE_NAME}:${ROOT_VERSION} && [ -n "$(docker images -q $IMG)" ] || docker build --network host -t "${REGISTRY}/${MIGRATIONS_IMAGE_NAME}:${ROOT_VERSION}" -t "${REGISTRY}/${MIGRATIONS_IMAGE_NAME}:latest" -f ./.docker/migrations.Dockerfile . --progress=plain  # We check the existence of a local image with the specified tag, if it does not exist, we start building the image export IMG=${REGISTRY}/${NGINX_IMAGE_NAME}:${CLIENT_VERSION} && [ -n "$(docker images -q $IMG)" ] || docker build --network host -t "${REGISTRY}/${NGINX_IMAGE_NAME}:${CLIENT_VERSION}" -t "${REGISTRY}/${NGINX_IMAGE_NAME}:latest" -f ./.docker/nginx.Dockerfile . --progress=plain  # We check the existence of a local image with the specified tag, if it does not exist, we start building the image export IMG=${REGISTRY}/${E2E_TESTS_IMAGE_NAME}:${ROOT_VERSION} && [ -n "$(docker images -q $IMG)" ] || docker build --network host -t "${REGISTRY}/${E2E_TESTS_IMAGE_NAME}:${ROOT_VERSION}" -t "${REGISTRY}/${E2E_TESTS_IMAGE_NAME}:latest" -f ./.docker/e2e-tests.Dockerfile . --progress=plain  

10. Обновляем конфигурацию для локального запуска «Docker Compose» режима

Обновляем файл .docker/docker-compose-full.yml

version: '3' networks:   nestjs-mod-fullstack-network:     driver: 'bridge' services:   nestjs-mod-fullstack-postgre-sql:     image: 'bitnami/postgresql:15.5.0'     container_name: 'nestjs-mod-fullstack-postgre-sql'     networks:       - 'nestjs-mod-fullstack-network'     healthcheck:       test:         - 'CMD-SHELL'         - 'pg_isready -U postgres'       interval: '5s'       timeout: '5s'       retries: 5     tty: true     restart: 'always'     environment:       POSTGRESQL_USERNAME: '${SERVER_POSTGRE_SQL_POSTGRESQL_USERNAME}'       POSTGRESQL_PASSWORD: '${SERVER_POSTGRE_SQL_POSTGRESQL_PASSWORD}'       POSTGRESQL_DATABASE: '${SERVER_POSTGRE_SQL_POSTGRESQL_DATABASE}'     volumes:       - 'nestjs-mod-fullstack-postgre-sql-volume:/bitnami/postgresql'   nestjs-mod-fullstack-postgre-sql-migrations:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-migrations:${ROOT_VERSION}'     container_name: 'nestjs-mod-fullstack-postgre-sql-migrations'     networks:       - 'nestjs-mod-fullstack-network'     tty: true     environment:       NX_SKIP_NX_CACHE: 'true'       SERVER_ROOT_DATABASE_URL: '${SERVER_ROOT_DATABASE_URL}'       SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}'     depends_on:       nestjs-mod-fullstack-postgre-sql:         condition: 'service_healthy'     working_dir: '/usr/src/app'     volumes:       - './../apps:/usr/src/app/apps'       - './../libs:/usr/src/app/libs'   nestjs-mod-fullstack-server:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-server:${SERVER_VERSION}'     container_name: 'nestjs-mod-fullstack-server'     networks:       - 'nestjs-mod-fullstack-network'     healthcheck:       test: ['CMD-SHELL', 'npx -y wait-on --timeout= --interval=1000 --window --verbose --log http://localhost:${SERVER_PORT}/api/health']       interval: 30s       timeout: 10s       retries: 10     tty: true     environment:       SERVER_APP_DATABASE_URL: '${SERVER_APP_DATABASE_URL}'       SERVER_PORT: '${SERVER_PORT}'     restart: 'always'     depends_on:       nestjs-mod-fullstack-postgre-sql:         condition: service_healthy       nestjs-mod-fullstack-postgre-sql-migrations:         condition: service_completed_successfully   nestjs-mod-fullstack-nginx:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-nginx:${CLIENT_VERSION}'     container_name: 'nestjs-mod-fullstack-nginx'     networks:       - 'nestjs-mod-fullstack-network'     healthcheck:       test: ['CMD-SHELL', 'curl -so /dev/null http://localhost:${NGINX_PORT} || exit 1']       interval: 30s       timeout: 10s       retries: 10     environment:       SERVER_PORT: '${SERVER_PORT}'       NGINX_PORT: '${NGINX_PORT}'     restart: 'always'     depends_on:       nestjs-mod-fullstack-server:         condition: service_healthy     ports:       - '${NGINX_PORT}:${NGINX_PORT}'   nestjs-mod-fullstack-e2e-tests:     image: 'ghcr.io/nestjs-mod/nestjs-mod-fullstack-e2e-tests:${ROOT_VERSION}'     container_name: 'nestjs-mod-fullstack-e2e-tests'     networks:       - 'nestjs-mod-fullstack-network'     environment:       BASE_URL: 'http://nestjs-mod-fullstack-nginx:${NGINX_PORT}'     depends_on:       nestjs-mod-fullstack-nginx:         condition: service_healthy     working_dir: '/usr/src/app'     volumes:       - './../apps:/usr/src/app/apps'       - './../libs:/usr/src/app/libs'   nestjs-mod-fullstack-https-portal:     image: steveltn/https-portal:1     container_name: 'nestjs-mod-fullstack-https-portal'     networks:       - 'nestjs-mod-fullstack-network'     ports:       - '80:80'       - '443:443'     links:       - nestjs-mod-fullstack-nginx     restart: always     environment:       STAGE: '${HTTPS_PORTAL_STAGE}'       DOMAINS: '${SERVER_DOMAIN} -> http://nestjs-mod-fullstack-nginx:${NGINX_PORT}'     depends_on:       nestjs-mod-fullstack-nginx:         condition: service_healthy     volumes:       - nestjs-mod-fullstack-https-portal-volume:/var/lib/https-portal volumes:   nestjs-mod-fullstack-postgre-sql-volume:     name: 'nestjs-mod-fullstack-postgre-sql-volume'   nestjs-mod-fullstack-https-portal-volume:     name: 'nestjs-mod-fullstack-https-portal-volume' 

11. Запускаем локальный «Docker Compose» режим и ждем успешного прохождения тестов

Когда мы изменяем много файлов или изменяем пармаметры девопс или устанавливаем новые зависимости, то нам необходимо локально убедится что все работает в режиме "Docker Compose", так как процесс сборки в CI/CD тратит бесплатные лимиты в случаи использования публичных раннеров, а также нагружает и удлиняет процесс деплоя при использовании собственных маломощных раннеров.

Локальный запуск в режиме "Docker Compose" также позволяет выявить проблемы которые могут появится при запуске через Kubernetes, так как сборка Docker-образов происходит почти одинаково.

При локальном запуске мы можем скачать и подключить Docker-образа которые использовались в Kubernetes, это помогает при поиске багов которые не повторяются на наших машинах и на наших локально собранных Docker-образах.

Команды

npm run docker-compose-full:prod:start docker logs nestjs-mod-fullstack-e2e-tests 

Вывод консоли

$ docker logs nestjs-mod-fullstack-e2e-tests  > @nestjs-mod-fullstack/source@0.0.0 test:e2e > ./node_modules/.bin/nx run-many --exclude=@nestjs-mod-fullstack/source --all -t=e2e --skip-nx-cache=true --output-style=stream-without-prefixes  NX  Falling back to ts-node for local typescript execution. This may be a little slower.  - To fix this, ensure @swc-node/register and @swc/core have been installed   NX   Running target e2e for 2 projects:  - client-e2e - server-e2e    > nx run client-e2e:e2e  > playwright test   Running 6 tests using 3 workers   6 passed (4.9s)  To open last HTML report run:    npx playwright show-report ../../dist/.playwright/apps/client-e2e/playwright-report   > nx run server-e2e:e2e  Setting up...  PASS   server-e2e  apps/server-e2e/src/server/server.spec.ts   GET /api     ✓ should return a message (32 ms)     ✓ should create and return a demo object (38 ms)     ✓ should get demo object by id (9 ms)     ✓ should get all demo object (7 ms)     ✓ should delete demo object by id (8 ms)     ✓ should get all demo object (6 ms) Test Suites: 1 passed, 1 total Tests:       6 passed, 6 total Snapshots:   0 total Time:        0.789 s Ran all test suites. Tearing down...     NX   Successfully ran target e2e for 2 projects 

12. Заменяем проверку наличия метки release в комментарии коммита на проверку наличия метки skip release

В предыдущем посте я добавлял метку [release] по которой мы принимали решение о необходимости запуска создания релиза, это было больше как пример, в реальности эту метку всегда забывают написать и приходится делать лишний не важный коммит для форсирования создания релиза.

Для того чтобы релиз всегда пробовал запустится заменим метку [release] на [skip release] и поменяем логику работы, теперь если встречаем указанную метку мы пропускаем шаг создания релиза.

Обновляем файл .github/workflows/kubernetes.yml

name: 'Kubernetes'  on:   push:     branches: ['master'] env:   REGISTRY: ghcr.io   BASE_SERVER_IMAGE_NAME: ${{ github.repository }}-base-server   BUILDER_IMAGE_NAME: ${{ github.repository }}-builder   MIGRATIONS_IMAGE_NAME: ${{ github.repository }}-migrations   SERVER_IMAGE_NAME: ${{ github.repository }}-server   NGINX_IMAGE_NAME: ${{ github.repository }}-nginx   E2E_TESTS_IMAGE_NAME: ${{ github.repository }}-e2e-tests   COMPOSE_INTERACTIVE_NO_CLI: 1   NX_DAEMON: false   NX_PARALLEL: false   NX_SKIP_NX_CACHE: true   DISABLE_SERVE_STATIC: true jobs:   release:     runs-on: ubuntu-latest     permissions:       contents: write # to be able to publish a GitHub release       issues: write # to be able to comment on released issues       pull-requests: write # to be able to comment on released pull requests       id-token: write # to enable use of OIDC for npm provenance     steps:       - uses: actions/checkout@v4         if: ${{ !contains(github.event.head_commit.message, '[skip release]') }}       - run: npm install --prefer-offline --no-audit --progress=false         if: ${{ !contains(github.event.head_commit.message, '[skip release]') }}       - run: npm run nx -- run-many --target=semantic-release --all --parallel=false         if: ${{ !contains(github.event.head_commit.message, '[skip release]') }}         env:           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # ... 

13. Добавляем строгости коду

Помимо настроек lint-staged для приведения кода к общему стилю, необходимо также иметь и общие параметры eslint и typescript-compilerOptions с дополнительными правилами строгости кода.

Обычно я не трогаю стандартные настройки eslint И prettier, просто добавляю немного строгости в корневой Typescript-конфиг.

Добавляем дополнительные правила в tsconfig.base.json

{   // ...   "compilerOptions": {     // ...     "allowSyntheticDefaultImports": true,     "strictNullChecks": true,     "noImplicitOverride": true,     "strictPropertyInitialization": true,     "noImplicitReturns": true,     "noFallthroughCasesInSwitch": true,     "esModuleInterop": true,     "noImplicitAny": false     // ...   }   // ... } 

Запускаем npm run manual:prepare и чиним все что сломалось и перезапускаем повторно до тех пор пока все ошибки не исправим.

14. Коммитим код и ждем успешного создания релизов и прохождения тестов

Текущий результат работы CI/CD: https://github.com/nestjs-mod/nestjs-mod-fullstack/actions/runs/10904254598
Текущий сайт: https://fullstack.nestjs-mod.com

Заключение

Если в проекте имеются другие файлы которые могут меняться в зависимости от настроек среды разработки, эти файлы также нужно указать в правилах lint-staged.

Строгость тоже можно еще сильнее сделать как и правила eslint, но каждый раз нужно замерять время работы, так например правило eslint для сортировки импортов запускает парсер ast-представления, в большом проекте это просто очень долго работает.

В этом посте я показал как можно ускорить деплой за счет версионирования фронтенда, таким же образом можно поступать и с микросервисами.

Планы

Так как основные моменты по девопс мне удалось завершить, то в следующих постах уже будут краткие описания разработки основных фич которые я планировал сделать.

В следующем посте я создам вебхук-модуль на NestJS для предоставления оповещений о наших событиях сторонним сервисам…

Ссылки

https://nestjs.com — официальный сайт фреймворка
https://nestjs-mod.com — официальный сайт дополнительных утилит
https://fullstack.nestjs-mod.com — сайт из поста
https://github.com/nestjs-mod/nestjs-mod-fullstack — проект из поста
https://github.com/nestjs-mod/nestjs-mod-fullstack/compare/2f9b6eddb32a9777fabda81afa92d9aaebd432cc..460257364bb4ce8e23fe761fbc9ca7462bc89b61 — изменения


ссылка на оригинал статьи https://habr.com/ru/articles/844148/