افزودن 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 – تغییرات فعلی