برنامه نویسی

افزودن lint-staged به برنامه‌های NestJS و Angular، امکان نسخه‌سازی معنایی frontend

Summarize this content to 400 words in Persian Lang از زمانی که نسخه از طریق nx-semantic-release افزونه با تجزیه و تحلیل تغییرات مربوط به آن صورت می گیرد Typescript واردات، باید این تغییرات را به حداقل برسانیم، برای انجام این کار، به پروژه https://www.npmjs.com/package/lint-staged متصل می شویم و سخت گیری را به آن اضافه می کنیم. Typescript کد

1. اضافه کردن lint-staged برای قالب بندی کد هنگام انجام

این ابزار اسکریپت های خاصی را با هر commit اجرا می کند، به طوری که قالب بندی کد در 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. ما در حال به روز رسانی اسکریپت آماده و بخش lint-staged در root package.json هستیم.

را prepare اسکریپت پس از نصب به طور خودکار ایجاد می شود lint-staged، من آن را حذف نکردم، فقط روش راه اندازی را کمی تغییر دادم، آن را اجرا کردم npx.

در پروژه های کوچک، pre-commit قلاب با lint-staged به سرعت کار می‌کند، اما اگر پروژه بزرگ باشد، می‌تواند طولانی‌تر کار کند، در این صورت برای همه توسعه‌دهندگان آسان‌تر است که روی یک سبک قالب‌بندی مشترک به توافق برسند تا تعداد فایل‌هایی را که لینترها باید بررسی کنند، کاهش دهند.

در pre-commit قلاب، نیازی به تجویز عملیات سنگین مختلف نیست، به عنوان مثال: تولید مشتری frontend، چنین عملیاتی بهتر است در CI/CD یا به صورت محلی با دست در صورت نیاز، و نه برای هر commit.

به روز رسانی بخشی از 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، باید همه فایل ها را به آن اضافه کنید 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 در برنامه frontend و اضافه کردن دستور semantic-release به پیکربندی NX آن

قبلا در پست ها، ما را راه اندازی کردیم Nginx هنگامی که نسخه پشتیبان برنامه تغییر کرد، ارتقا دهید.

به منظور برای Nginx تصویر با یک جلوی تعبیه شده که فقط زمانی که قسمت ظاهری تغییر می کند مونتاژ می شود، باید قسمت جلویی را نسخه سازی کنیم و از نسخه آن در منطق های بعدی استفاده کنیم. Docker تصاویر و Kubernetes قالب ها

نسخه‌سازی معنایی نیاز به الف دارد package.json برای کار با کتابخانه یا برنامه، بنابراین آن را به برنامه frontend اضافه کرده و مشخص می کنیم “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. افزودن یک متغیر محیط پویا جدید

افزودن یک متغیر جدید با نسخه برنامه frontend به فایل .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” را راه اندازی می کنیم و منتظر تکمیل موفقیت آمیز تست ها هستیم

هنگامی که فایل های زیادی را تغییر می دهیم یا پارامترهای devops را تغییر می دهیم یا وابستگی های جدید نصب می کنیم، باید به صورت محلی مطمئن شویم که همه چیز در حالت “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. جایگزین کردن چک برای نشانگر انتشار در نظر commit با یک بررسی برای نشانگر انتشار پرش

در پست قبلی نشانگر را اضافه کردم [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 مشاهده تجزیه کننده، در یک پروژه بزرگ فقط برای مدت طولانی کار می کند.

در این پست نشان دادم که چگونه می‌توانید با نسخه‌سازی فرانت‌اند سرعت استقرار را افزایش دهید و همین کار را با میکروسرویس‌ها نیز انجام دهید.

طرح ها

از آنجایی که من موفق به تکمیل نکات اصلی در devops شدم، پست‌های زیر قبلاً حاوی توضیحات مختصری از توسعه ویژگی‌های اصلی است که قصد انجام آن را داشتم.

در پست بعدی، یک ماژول webhook در 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..460257364bb4ce8e23fe761fb21c9ca74 – تغییرات فعلی

از زمانی که نسخه از طریق nx-semantic-release افزونه با تجزیه و تحلیل تغییرات مربوط به آن صورت می گیرد Typescript واردات، باید این تغییرات را به حداقل برسانیم، برای انجام این کار، به پروژه https://www.npmjs.com/package/lint-staged متصل می شویم و سخت گیری را به آن اضافه می کنیم. Typescript کد

1. اضافه کردن lint-staged برای قالب بندی کد هنگام انجام

این ابزار اسکریپت های خاصی را با هر commit اجرا می کند، به طوری که قالب بندی کد در 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. ما در حال به روز رسانی اسکریپت آماده و بخش lint-staged در root package.json هستیم.

را prepare اسکریپت پس از نصب به طور خودکار ایجاد می شود lint-staged، من آن را حذف نکردم، فقط روش راه اندازی را کمی تغییر دادم، آن را اجرا کردم npx.

در پروژه های کوچک، pre-commit قلاب با lint-staged به سرعت کار می‌کند، اما اگر پروژه بزرگ باشد، می‌تواند طولانی‌تر کار کند، در این صورت برای همه توسعه‌دهندگان آسان‌تر است که روی یک سبک قالب‌بندی مشترک به توافق برسند تا تعداد فایل‌هایی را که لینترها باید بررسی کنند، کاهش دهند.

در pre-commit قلاب، نیازی به تجویز عملیات سنگین مختلف نیست، به عنوان مثال: تولید مشتری frontend، چنین عملیاتی بهتر است در CI/CD یا به صورت محلی با دست در صورت نیاز، و نه برای هر commit.

به روز رسانی بخشی از 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، باید همه فایل ها را به آن اضافه کنید 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 در برنامه frontend و اضافه کردن دستور semantic-release به پیکربندی NX آن

قبلا در پست ها، ما را راه اندازی کردیم Nginx هنگامی که نسخه پشتیبان برنامه تغییر کرد، ارتقا دهید.

به منظور برای Nginx تصویر با یک جلوی تعبیه شده که فقط زمانی که قسمت ظاهری تغییر می کند مونتاژ می شود، باید قسمت جلویی را نسخه سازی کنیم و از نسخه آن در منطق های بعدی استفاده کنیم. Docker تصاویر و Kubernetes قالب ها

نسخه‌سازی معنایی نیاز به الف دارد package.json برای کار با کتابخانه یا برنامه، بنابراین آن را به برنامه frontend اضافه کرده و مشخص می کنیم "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. افزودن یک متغیر محیط پویا جدید

افزودن یک متغیر جدید با نسخه برنامه frontend به فایل .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” را راه اندازی می کنیم و منتظر تکمیل موفقیت آمیز تست ها هستیم

هنگامی که فایل های زیادی را تغییر می دهیم یا پارامترهای devops را تغییر می دهیم یا وابستگی های جدید نصب می کنیم، باید به صورت محلی مطمئن شویم که همه چیز در حالت “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. جایگزین کردن چک برای نشانگر انتشار در نظر commit با یک بررسی برای نشانگر انتشار پرش

در پست قبلی نشانگر را اضافه کردم [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 مشاهده تجزیه کننده، در یک پروژه بزرگ فقط برای مدت طولانی کار می کند.

در این پست نشان دادم که چگونه می‌توانید با نسخه‌سازی فرانت‌اند سرعت استقرار را افزایش دهید و همین کار را با میکروسرویس‌ها نیز انجام دهید.

طرح ها

از آنجایی که من موفق به تکمیل نکات اصلی در devops شدم، پست‌های زیر قبلاً حاوی توضیحات مختصری از توسعه ویژگی‌های اصلی است که قصد انجام آن را داشتم.

در پست بعدی، یک ماژول webhook در 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..460257364bb4ce8e23fe761fb21c9ca74 – تغییرات فعلی

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا