برنامه نویسی

توسعه، آزمایش و استقرار برنامه های افزودنی خود را برای همه CI های محبوب از یک پایگاه کد واحد

💡 تصویر ویژگی یک خط لوله معمولی CI/CD را نشان می دهد که بخشی از آن توسط OpenAI DALL-E ترسیم شده است، اما در این مقاله، ما می خواهیم چیزی مفید را توسعه دهیم.

فهرست مطالب

این یک آموزش نسبتاً کوتاه در مورد چگونگی توسعه، آزمایش و استقرار پسوندهای CI برای GitHub Actions، Azure Pipelines و CircleCI از یک monorepo است و بر اساس تجربه ایجاد افزونه‌های Qodana CI است.

از قالب های رسمی شروع کنید

بیایید پشته فناوری را برای برنامه های افزودنی CI خود انتخاب کنیم.

باشه انتخاب نمیکنم من فقط به شما می گویم که چرا از TypeScript و node.js برای برنامه های افزودنی استفاده کردم.

مزایای استفاده از اقدامات مبتنی بر JS:

  • انعطاف پذیرتر از رویکردهای مبتنی بر bash/Dockerfile
  • نوشتن تست ها نسبتا ساده است

منفی

پس بیایید یک اقدام مبتنی بر TypeScript بنویسیم!

اقدامات GitHub

خواندن اسناد اقدامات GitHub راحت‌تر از Azure بود، بنابراین توصیه می‌کنم شروع به نوشتن و آزمایش برنامه‌های افزودنی خود در GitHub با استفاده از اقدامات قالب/تایپ اسکریپت-اکشن رسمی کنید. الگوی ذکر شده نقطه شروع خوبی را فراهم می کند. من مراحل را در اینجا تکرار نمی کنم. با آن بازی کنید، چیزهای ساده بنویسید و سپس برای مراحل بعدی به اینجا برگردید.

خطوط لوله لاجورد

GitHub Actions بر روی زیرساخت Azure ساخته شده است، بنابراین انتقال اکشن GitHub شما به Azure Pipelines باید نسبتا آسان باشد.

بنابراین،

  • “عمل” تبدیل به “وظیفه” می شود
  • کمی متفاوت بسته بندی شده، توزیع شده و به روشی دیگر نصب شده است

و تعریف تکلیف task.json همان عمل یک است action.yml.

برای مثال داشتن موارد زیر action.yml:

name: 'Your name here'
description: 'Provide a description here'
author: 'Your name or organization here'
inputs:
  milliseconds: # change this
    required: true
    description: 'input description here'
    default: 'default value if applicable'
runs:
  using: 'node16'
  main: 'dist/index.js'
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

“به راحتی” به وظیفه Azure زیر ترجمه می شود:

{
  "$schema": "https://raw.githubusercontent.com/Microsoft/azure-pipelines-task-lib/master/tasks.schema.json",
  "id": "822d6cb9-d4d1-431b-9513-e7db7d718a49",
  "name": "YourTaskNameHere",
  "friendlyName": "Your name here",
  "description": "Provide a description here",
  "helpMarkDown": "Provide a longer description here",
  "author": "Your name or organization here",
  "version": {
    "Major": 1,
    "Minor": 0,
    "Patch": 0
  },
  "instanceNameFormat": "YourTaskNameHere",
  "inputs": [
    {
      "name": "milliseconds",
      "type": "string",
      "label": "label name here",
      "defaultValue": "default value if applicable",
      "required": true,
      "helpMarkDown": "input description here"
    }
  ],
  "execution": {
    "Node10": {
      "target": "index.js"
    }
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

از یک مثال ساده، می توان متوجه شد که چرا پیشنهاد کردم با GitHub Actions شروع کنید. اما بیایید ادامه دهیم.

برای شروع کار جدید Azure Pipelines براق خود، پیشنهاد می کنم فقط دایرکتوری اکشن را کپی کنید و سپس مراحل را از اسناد رسمی Azure پیاده سازی کنید – این کار بسیار ساده است.

  1. ايجاد كردن vss-extension.json
  2. ايجاد كردن task.json و آن را در خود قرار دهید dist دایرکتوری (در واقع بهتر است آن را پس از نام وظیفه نامگذاری کنید)
  3. اگر از هر روشی استفاده کردید از @actions/core یا @actions/github در اقدام خود، باید آنها را با روش های مربوطه جایگزین کنید azure-pipelines-task-lib (به عنوان مثال core.getInput -> tl.getInput)

API از azure-pipelines-task-lib شبیه است به @actions/core و دیگر @actions/* کتابخانه ها به عنوان مثال، ما یک روش برای به دست آوردن پارامترهای ورودی داریم:

export function getInputs(): Inputs {
  return {
    milliseconds: core.getInput('milliseconds'),
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و همینطور برای Azure Pipelines:

export function getInputs(): Inputs {
  return {
    milliseconds: tl.getInput('milliseconds'),
  }
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای موارد واقعی تر، در صورت تمایل به کاوش در ابزارهای پایگاه کد Qodana GitHub Actions و ابزارهای وظیفه Azure Pipelines ما بپردازید.

monorepo را ایجاد کنید

ما قصد داریم از فضاهای کاری npm برای مدیریت monorepo استفاده کنیم.
کد عملکرد و وظیفه خود را در زیر شاخه ها قرار دهید (مثلاً github) از monorepo تازه ایجاد شده شما. و سپس یک را ایجاد کنید package.json فایل در دایرکتوری ریشه

{
  "name": "@org/ci",
  "version": "1.0.0",
  "description": "Common code for CI extensions",
  "license": "Apache-2.0",
  "workspaces": [
    "github",
    "azure"
  ],
  "devDependencies": {
    "typescript": "latest",
    "eslint": "latest",
    "eslint-plugin-github": "latest",
    "eslint-plugin-jest": "latest",
    "prettier": "latest",
    "ts-node": "latest"
  }
}

وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

بنابراین ساختار monorepo به شکل زیر است:

...
├── action.yaml
├── github/
├── azure/
└── package.json
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

پس از اجرای تنظیمات فضای کاری، می توانید وظایف و اقدامات را از دایرکتوری ریشه اجرا کنید. به عنوان مثال، برای اجرای build وظیفه از github دایرکتوری، می توانید از دستور زیر استفاده کنید:

npm run -w github build 
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

کد را بین اقدامات و وظایف به اشتراک بگذارید

با ارزش ترین بخش استفاده از رویکرد monorepo از اینجا شروع می شود: می توانید کد را بین اقدامات و وظایف خود به اشتراک بگذارید.

قرار است مراحل زیر را انجام دهیم:

  1. ایجاد یک common دایرکتوری در ریشه monorepo، یک پروژه فرعی برای کد مشترک
  2. به روز رسانی tsconfig.json پیکربندی های کامپایلر از همه زیرمجموعه ها برای ساخت پروژه مناسب

در ابتدا بیایید پایه را ایجاد کنیم tsconfigtsconfig.base.json با تنظیمات پایه ای که قرار است در همه پروژه های فرعی استفاده شود:

{
  "compilerOptions": {
    "target": "es6",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "composite": true
  },
  "exclude": ["node_modules", "**/*.test.ts", "*/lib/**"]
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس یک ساده ایجاد کنید tsconfig.json در ریشه پروژه:

{
  "references": [
    { "path": "common" },
    { "path": "azure" },
    { "path": "github" }
  ],
  "files": []
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

سپس common/tsconfig.json:

{
  "extends": "../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./lib",
    "rootDir": "."
  },
  "files": ["include your files here or use typical include/exclude patterns"]
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و در نهایت، به روز رسانی tsconfig.json فایل های موجود در پروژه های فرعی (آنها اساساً یکسان هستند، به عنوان مثال github/tsconfig.json):

{
  "extends": "../tsconfig.base.json",
  "compilerOptions": {
    "outDir": "./lib",
    "rootDir": "./src"
  },
  "references": [
    { "path": "../common" }
  ]
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

اکنون می توانید از کد اشتراک گذاری شده استفاده کنید common دایرکتوری در اقدامات و وظایف شما. به عنوان مثال، ما یک qodana.ts فایل در common دایرکتوری که حاوی تابع است getQodanaUrl که URL را به ابزار Qodana CLI برمی گرداند. و ما از آن هم در اعمال و هم در وظایف استفاده می کنیم.

CleanShot 2023-06-18 در 16 54 11@2x

بسازید و منتشر کنید

شما در حال حاضر گردش‌های کاری GitHub را از قالب پیکربندی کرده‌اید تا اقدامات شما را در نسخه‌های مخزن خود منتشر کند.
برای نسخه‌های خودکار، از GH CLI استفاده می‌کنیم، و یک اسکریپت ساده داریم که یک تغییرات در نسخه‌های مخزن منتشر می‌کند:

#!/usr/bin/env bash
previous_tag=0
for current_tag in $(git tag --sort=-creatordate)
do

if [ "$previous_tag" != 0 ];then
    printf "## Changelog\n"
    git log ${current_tag}...${previous_tag} --pretty=format:'* %h %s' --reverse | grep -v Merge
    printf "\n"
    break
fi
previous_tag=${current_tag}
done
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و گردش کار GitHub که آن را اجرا می کند:

name: 'Release'
on:
  push:
    tags:
      - '*'
permissions:
  contents: write

jobs:
  github:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
        with:
          fetch-depth: 0
      - run: |
          ./changelog.sh > changelog.md
          gh release create ${GITHUB_REF##*/} -F changelog.md
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

برای انتشار وظایف Azure Pipelines، می توانید از رویکرد رسمی Azure استفاده کنید. با این حال، همچنین می توانید همین کار را در زیرساخت اقدامات GitHub انجام دهید زیرا ابزار ناشر آنها را می توان در هر جایی نصب کرد. بنابراین، در مورد ما، با یک کار گردش کار ساده GitHub حل می شود:

  azure:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Set Node.js 12.x
        uses: actions/setup-node@v3.6.0
        with:
          node-version: 12.x
      - name: Install dependencies
        run: npm ci && cd vsts/QodanaScan && npm ci && npm i -g tfx-cli
      - name: Package and publish
        run: |
          cd vsts && npm run azure
          mv JetBrains.qodana-*.vsix qodana.vsix
          tfx extension publish --publisher JetBrains --vsix qodana.vsix -t $AZURE_TOKEN
        env:
          AZURE_TOKEN: ${{ secrets.AZURE_TOKEN }}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با این تنظیم، هر انتشار به طور خودکار در هر فشار برچسب اتفاق می افتد.

git tag -a v1.0.0 -m "v1.0.0" && git push origin v1.0.0
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

CleanShot 2023-06-18 در 16 55 34@2x

CircleCI

آه، بله، این مقاله به گوی CircleCI نیز اشاره کرده است… راه اندازی CircleCI ساده است اما از پسوندهای TypeScript پشتیبانی نمی کند، بنابراین باید کد خود را در یک تصویر داکر یا یک باینری بسته بندی کنید و آن را در آنجا اجرا کنید. تنها دلیلی که در این پست گنجانده شده است این است که ما گوی خود را با رویکرد monorepo می سازیم که به خوبی کار می کند.

فقط قالب رسمی orb را پیاده سازی کنید و آن را در monorepo خود قرار دهید، بنابراین ساختار به شکل زیر است:

...
├── action.yaml
├── github/
├── azure/
├── src/            # orb source code here
└── package.json
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

و تعهد را فراموش نکنید .circleci/ دایرکتوری به مخزن خود برای ایجاد CircleCI lint، آزمایش و انتشار orb خود.

CleanShot 2023-06-18 at 16 49 57@2x

اگر این پست ده واکنش در اینجا داشته باشد، قسمت دوم را درباره انتشار و آزمایش خطوط لوله Azure و گوی های CircleCI اضافه خواهم کرد.

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

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

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

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