ورک‌فلوهای قابل استفاده مجدد در گیت‌هاب (GitHub Reusable Workflows) مکانیزمی برای استخراج منطق تکراری CI/CD به یک کامپوننت مشترک است که نگهداری، تست و هم‌راستایی سیاست‌ها را در چند مخزن ممکن می‌کند و جایگزین عملی کپی-پیست YAML است.

در پروژه‌های متعددی که خط لوله CI/CD را برای سازمان‌ها راه‌اندازی کرده‌ام، بارها دیده‌ام که هر مخزن، نسخه‌ای متفاوت از همان Workflow را دارد. نتیجه، به‌روزرسانی‌های دستی، ناسازگاری سیاست‌ها و به‌مرور، بدهی فنی سنگین است. GitHub در اکتبر ۲۰۲۱، ویژگی Reusable Workflows را معرفی کرد تا این مشکل را حل کند. با این ویژگی، می‌توانید یک Workflow را یک‌بار تعریف کنید و در چندین مخزن فراخوانی کنید. آمار نشان می‌دهد سازمان‌هایی که Reusable Workflows را جدی گرفته‌اند، زمان نگهداری CI/CD را تا ۶۰ درصد کاهش داده‌اند. در این نوشتار، این ویژگی را از پایه تا الگوهای پیشرفته بررسی می‌کنم.

هر بار که یک Workflow را کپی می‌کنید، یک بدهی کوچک ایجاد کرده‌اید. ده مخزن که همان Workflow را کپی کرده‌اند، ده بدهی است که هر کدام در زمانی متفاوت، فراخوانی می‌شوند. Reusable Workflows، این بدهی را حذف می‌کند.

چرا Reusable Workflows حیاتی است؟

در سازمان‌هایی که چندین مخزن دارند، هر مخزن معمولاً به Workflowهای مشابه نیاز دارد: تست، بیلد، دیپلوی، انتشار. بدون Reusable Workflows، این نیاز به کپی-پیست منجر می‌شود.

مشکلات کپی-پیست YAML

  • به‌روزرسانی دشوار: هر تغییر، باید در همه نسخه‌ها اعمال شود.
  • ناسازگاری: نسخه‌ها به‌تدریج از هم واگرا می‌شوند.
  • تست ضعیف: هر نسخه ممکن است در محیط متفاوتی تست شده باشد.
  • تکرار دانش: تیم‌های جدید باید الگوها را از صفر یاد بگیرند.
  • خطای انسانی: ویرایش هر نسخه، احتمال خطا را چند برابر می‌کند.

مزایای Reusable Workflows

  • منبع واحد حقیقت: یک Workflow، یک محل نگهداری.
  • به‌روزرسانی یکجا: تغییر در یک جا، در همه مخازن اعمال می‌شود.
  • هم‌راستایی سیاست‌ها: همه مخازن از یک سیاست پیروی می‌کنند.
  • تست متمرکز: یک Workflow، یک مجموعه تست.
  • کاهش بدهی فنی: نگهداری ساده‌تر، بدهی کمتر.

در GitHub Actions راهنمای خودکارسازی گردش کار به‌طور مفصل درباره ساختار Workflowها بحث کرده‌ام. CI/CD برای پروژه‌های وردپرسی چگونه پیاده‌سازی می‌شود؟ نمونه عملی این نیاز را نشان می‌دهد.

هزینه سازمانی کپی-پیست

تصور کنید سازمانی با ۵۰ مخزن، هر کدام یک Workflow ۲۰۰ خطی دارد. اگر یک آسیب‌پذیری امنیتی در Workflow کشف شود، باید ۵۰ فایل ویرایش شود. با Reusable Workflows، یک فایل ویرایش می‌شود. چرا وردپرس منابع هاست را زیاد مصرف می‌کند و کاهش مصرف به همین اصل در لایه زیرساخت اشاره دارد.

تفاوت با Composite Actions و Workflow Templates

GitHub سه مکانیزم مشابه اما متفاوت برای بازاستفاده ارائه می‌دهد.

ویژگی Reusable Workflow Composite Action Workflow Template
سطح کل Workflow چند Step فایل شروع
محل تعریف .github/workflows/ action.yml template repository
فراخوانی uses در سطح Job uses در سطح Step یک‌بار، هنگام ایجاد
Secret inherit یا explicit explicit بسته به محتوا

Reusable Workflow

کل یک Workflow را به‌عنوان کامپوننت فراخوانی می‌کند. مناسب برای الگوهای کامل مانند «بیلد، تست، دیپلوی».

Composite Action

مجموعه‌ای از Stepها را به یک Action تبدیل می‌کند. مناسب برای الگوهای کوچک‌تر مانند «نصب Node و اجرای تست».

Workflow Template

یک مخزن Template که هنگام ایجاد مخزن جدید، فایل‌های Workflow را کپی می‌کند. مناسب برای شروع سریع، اما پس از ایجاد، دیگر هم‌راستا نیست. هم‌روندی در گیت‌هاب اکشنز به الگوهای مشابه اشاره دارد.

انتخاب درست

  • اگر کل Workflow تکراری است: Reusable Workflow.
  • اگر چند Step تکراری است: Composite Action.
  • اگر فقط شروع سریع لازم است: Workflow Template.
  • ترکیب هر سه نیز ممکن است.

مبانی Reusable Workflows

Reusable Workflow در پوشه .github/workflows/ تعریف می‌شود و با کلید workflow_call قابل فراخوانی می‌شود.

ساختار پایه

# .github/workflows/reusable-test.yml
name: Reusable Test

on:
  workflow_call:
    inputs:
      node-version:
        required: false
        type: string
        default: "20"
      run-lint:
        required: false
        type: boolean
        default: true
    secrets:
      NPM_TOKEN:
        required: false

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: ${{ inputs.node-version }}
      - run: npm ci
      - if: ${{ inputs.run-lint }}
        run: npm run lint
      - run: npm test

فراخوانی از مخزن دیگر

# .github/workflows/main.yml
name: CI

on:
  push:
    branches: [main]

jobs:
  test:
    uses: my-org/shared-workflows/.github/workflows/reusable-test.yml@main
    with:
      node-version: "20"
      run-lint: true
    secrets:
      NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

فراخوانی از همان مخزن

jobs:
  test:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: "20"

ساختار Reference

ساختار فراخوانی از مخزن دیگر:

{owner}/{repo}/.github/workflows/{filename}@{ref}

{ref} می‌تواند شاخه، تگ یا SHA باشد. استفاده از SHA، امن‌ترین گزینه است. برنچ در Git راهنمای مدیریت شاخه‌ها به اهمیت Refها اشاره دارد.

محدودیت‌ها

  • Reusable Workflow نمی‌تواند خودش در سطح Workflow فراخوانی شود.
  • Reusable Workflow از workflow_call فقط استفاده می‌کند، نه on: push.
  • حداکثر ۴ سطح Nesting مجاز است.
  • حداکثر ۲۰ Reusable Workflow در یک زنجیره.

ورودی‌ها، خروجی‌ها و Secretها

Reusable Workflows، رابط ورودی و خروجی مشخصی دارند.

Inputs

سه نوع Input پشتیبانی می‌شود: string، number، boolean. Inputها می‌توانند اجباری (required: true) یا اختیاری با مقدار پیش‌فرض باشند.

on:
  workflow_call:
    inputs:
      environment:
        required: true
        type: string
      replicas:
        required: false
        type: number
        default: 1
      debug:
        required: false
        type: boolean
        default: false

Outputs

Outputها به Workflow فراخوانی‌کننده بازمی‌گردند. مناسب برای انتقال داده‌هایی مانند URL دیپلوی، شناسه Build یا نتیجه تست.

on:
  workflow_call:
    outputs:
      deploy-url:
        description: URL of the deployed app
        value: ${{ jobs.deploy.outputs.url }}

jobs:
  deploy:
    runs-on: ubuntu-latest
    outputs:
      url: ${{ steps.deploy.outputs.url }}
    steps:
      - id: deploy
        run: echo "url=https://example.com" >> $GITHUB_OUTPUT

Secrets

دو روش برای انتقال Secret وجود دارد:

  • Explicit: هر Secret به‌صورت جداگانه تعریف و ارسال می‌شود.
  • inherit: همه Secretهای فراخوانی‌کننده، به‌صورت خودکار منتقل می‌شوند.
# Explicit
jobs:
  deploy:
    uses: org/shared/.github/workflows/deploy.yml@main
    secrets:
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}

# Inherit
jobs:
  deploy:
    uses: org/shared/.github/workflows/deploy.yml@main
    secrets: inherit

روش inherit ساده‌تر است اما کنترل کمتری دارد. برای Workflowهای حساس، روش Explicit توصیه می‌شود. هدرهای امنیتی HTTP (Security Headers) چه کاربردی دارند؟ به اهمیت کنترل دسترسی اشاره دارد.

GITHUB_TOKEN

GITHUB_TOKEN به‌طور خودکار در Reusable Workflow در دسترس است. اما دسترسی آن، بسته به permissions تعریف‌شده در سطح Workflow است. این نکته در دیپلوی و انتشار حساس است.

الگوهای فراخوانی

چند الگوی رایج برای استفاده از Reusable Workflows وجود دارد.

الگوی تک‌مرحله‌ای

یک Job که یک Reusable Workflow را فراخوانی می‌کند:

jobs:
  test:
    uses: org/shared/.github/workflows/test.yml@main

الگوی چندمرحله‌ای

چند Job که به‌ترتیب چند Reusable Workflow را فراخوانی می‌کنند:

jobs:
  test:
    uses: org/shared/.github/workflows/test.yml@main
  build:
    needs: test
    uses: org/shared/.github/workflows/build.yml@main
  deploy:
    needs: build
    uses: org/shared/.github/workflows/deploy.yml@main
    with:
      environment: production

الگوی Matrix با Reusable

ترکیب Matrix با Reusable Workflows، امکان اجرای موازی چند نسخه را فراهم می‌کند:

jobs:
  test:
    strategy:
      matrix:
        node: [18, 20, 22]
    uses: org/shared/.github/workflows/test.yml@main
    with:
      node-version: ${{ matrix.node }}

الگوی Environment-based

یک Reusable Workflow که بر اساس ورودی environment، رفتار متفاوتی دارد:

jobs:
  deploy:
    uses: org/shared/.github/workflows/deploy.yml@main
    with:
      environment: staging
    secrets:
      TOKEN: ${{ secrets.STAGING_TOKEN }}

در هم‌روندی در گیت‌هاب اکشنز به اهمیت تفکیک محیط‌ها اشاره کرده‌ام. GitLab برای تیم‌های DevOps: راهنمای کامل از CI/CD تا امنیت و انتشار نیز به این موضوع می‌پردازد.

Nesting و پیچیدگی

Reusable Workflows می‌توانند خودشان Reusable Workflow فراخوانی کنند. این ویژگی، امکان ساخت کتابخانه‌های پیچیده را فراهم می‌کند اما خطرات خاص خود را دارد.

محدودیت‌های Nesting

  • حداکثر ۴ سطح Nesting.
  • حداکثر ۲۰ Reusable Workflow در یک زنجیره.
  • خطای Nesting بیش از حد، پیام خطای GitHub را فعال می‌کند.

الگوی Layered

الگوی Layered، لایه‌های انتزاعی می‌سازد: Low-Level (مثل نصب وابستگی)، Mid-Level (مثل تست)، High-Level (مثل انتشار). این الگو، خوانایی و نگهداری را بهبود می‌بخشد اما در Depth بیش از حد، پیچیدگی ایجاد می‌کند.

هزینه Nesting

هر سطح Nesting، سرباری از نظر زمان و پیچیدگی Debugging دارد. توصیه، بیش از دو سطح Nesting نیست مگر آنکه سود واضح باشد. مونولیتیک یا میکروسرویس؟ راهنمای انتخاب به همین اصل در معماری نرم‌افزار اشاره دارد.

امنیت و کنترل دسترسی

Reusable Workflows، سطح حمله جدیدی ایجاد می‌کنند که باید مدیریت شود.

Ref و امنیت

استفاده از @main در Ref، ساده اما خطرناک است. اگر شاخه main مخزن Reusable تغییر کند، همه مخازن فراخوانی‌کننده تحت تأثیر قرار می‌گیرند. بهترین رویه، استفاده از SHA یا Tag است.

uses: org/shared/.github/workflows/test.yml@a1b2c3d4e5f6

دسترسی مخازن

در تنظیمات Reusable Workflow، می‌توانید دسترسی را محدود کنید:

  • دسترسی به همه مخازن: پیش‌فرض ساده اما خطرناک.
  • دسترسی به مخازن مشخص: امن‌تر، نیازمند نگهداری.
  • دسترسی به سازمان: تعادل بین امنیت و سادگی.

Secrets و دسترسی

هر Secret که در Reusable Workflow استفاده می‌شود، باید با دقت مدیریت شود. Secretهای حساس، تنها با روش Explicit منتقل شوند. امنیت در PHP به اصول مشابه اشاره دارد.

Permissions

در Reusable Workflow، permissions در سطح Workflow تعریف می‌شود و می‌تواند محدودتر از فراخوانی‌کننده باشد. همیشه از کمترین دسترسی لازم استفاده کنید.

permissions:
  contents: read
  packages: write

Injection و Untrusted Input

اگر Reusable Workflow، ورودی از منابع نامطمئن (مانند نام PR) دریافت می‌کند، باید از Injection جلوگیری شود. استفاده از env و پرهیز از درج مستقیم ورودی در دستورات.

# ناامن
- run: echo ${{ inputs.pr_title }}

# امن
- env:
    PR_TITLE: ${{ inputs.pr_title }}
  run: echo "$PR_TITLE"

در تزریق SQL (SQL Injection) چیست و چگونه می‌توان از آن دفاع کرد؟ به اصول مشابه در لایه دیتابیس اشاره کرده‌ام.

تست Reusable Workflows

Reusable Workflows باید مثل هر کامپوننت نرم‌افزاری، تست شوند.

تست در مخزن Reusable

هر Reusable Workflow باید یک Workflow تست در مخزن خود داشته باشد که آن را با ورودی‌های نمونه فراخوانی کند:

# .github/workflows/test-reusable.yml
name: Test Reusable
on:
  push:
    branches: [main]

jobs:
  test-with-defaults:
    uses: ./.github/workflows/reusable-test.yml
  test-with-custom:
    uses: ./.github/workflows/reusable-test.yml
    with:
      node-version: "18"
      run-lint: false

نسخه‌بندی

Reusable Workflows باید نسخه‌بندی شوند. الگوی رایج، استفاده از Tagهای SemVer است:

uses: org/shared/.github/workflows/test.yml@v1

با این الگو، تغییرات Backward-Compatible در v1.x اعمال می‌شوند و تغییرات Breaking در v2.0. چگونه تعارض گیت را بدون از دست دادن کدها حل کنیم؟ به اهمیت مدیریت نسخه اشاره دارد.

CI/CD برای Reusable Workflows

مخزن Reusable باید خودش CI/CD داشته باشد: Lint YAML، تست، نسخه‌بندی خودکار. بهترین ابزارهای CI/CD؛ کدام برای پروژه شما مناسب است؟ مقایسه عملی ارائه می‌دهد.

مستندسازی

هر Reusable Workflow باید README داشته باشد که ورودی‌ها، خروجی‌ها، Secretها و مثال‌های استفاده را توضیح دهد. برنامه کسب‌وکار (Business Plan) چگونه نوشته می‌شود؟ به اهمیت مستندسازی اشاره دارد.

اشتباهات رایج

  • استفاده از @main: شکننده و ناامن. از SHA یا Tag استفاده کنید.
  • نبود تست: Reusable Workflow بدون تست، خطر شکست در Production دارد.
  • نبود مستندسازی: تیم‌ها نمی‌دانند چه ورودی‌هایی لازم است.
  • Nesting بیش از حد: پیچیدگی Debugging را چند برابر می‌کند.
  • Secrets با inherit به‌صورت گسترده: سطح حمله را افزایش می‌دهد.
  • Refهای متغیر: استفاده از Refهای پویا، رفتار غیرقابل پیش‌بینی ایجاد می‌کند.
  • نبود Versioning: تغییرات Breaking، مخازن فراخوانی‌کننده را می‌شکند.
  • Naming ضعیف: نام‌های مبهم، استفاده را دشوار می‌کند.
  • نبود دسترسی محدود: همه مخازن سازمان، دسترسی کامل دارند.
  • نبود Fallback: اگر Reusable Workflow از دسترس خارج شود، فراخوانی‌کننده‌ها شکست می‌خورند.

در رفع خطاهای رایج Git راهنمای کاربردی به خطاهای مشابه اشاره کرده‌ام. اشتباهات رایج امنیت وب (Web Security) کدامند؟ نیز به این موضوع می‌پردازد. اشتباهات رایج در توسعه قالب و افزونه وردپرس نیز به خطاهای توسعه اشاره دارد.

اشتباهات پیشرفته

  • نبود Idempotency: اجرای مکرر، وضعیت را خراب می‌کند.
  • نبود Matrix Management: استفاده نادرست از Matrix، منابع را هدر می‌دهد.
  • نادیده گرفتن Concurrency: چند فراخوانی همزمان، منابع مشترک را خراب می‌کند. هم‌روندی در گیت‌هاب اکشنز به این موضوع می‌پردازد.
  • نبود Observability: لاگ و متریک Reusable Workflow، در مخزن اصلی دیده نمی‌شود.
  • نبود SLA: اگر مخزن Reusable در دسترس نباشد، همه مخازن متوقف می‌شوند.

الگوهای پیشرفته و مقیاس‌پذیری

برای سازمان‌های بزرگ، Reusable Workflows باید در مقیاس طراحی شوند.

الگوی Layered Library

سه لایه تعریف کنید:

  • Atomic: Workflowهای کوچک (نصب، تست، بیلد).
  • Composite: ترکیب Atomic برای سناریوهای پیچیده‌تر.
  • Project-Specific: Workflowهای اختصاصی پروژه که از Composite استفاده می‌کنند.

الگوی Multi-Repo

در سازمان‌هایی با چند مخزن، Reusable Workflows در یک مخزن مرکزی shared-workflows قرار می‌گیرند و همه مخازن از آن استفاده می‌کنند. این الگو، منبع واحد حقیقت را تضمین می‌کند.

الگوی Conditional Use

ممکن است یک Reusable Workflow، بسته به شرایط، رفتار متفاوتی داشته باشد. این کار با Inputهای Boolean انجام می‌شود:

jobs:
  deploy:
    uses: org/shared/.github/workflows/deploy.yml@v1
    with:
      strategy: blue-green
      run-smoke-tests: true

الگوی Hybrid با Composite

ترکیب Reusable Workflows و Composite Actions، انعطاف بالایی می‌دهد. Composite برای Stepهای مکرر، Reusable برای Jobهای مکرر. آموزش Docker با مثال‌های واقعی به الگوهای مشابه در Container اشاره دارد.

مقیاس‌پذیری و Cache

در سازمان‌های بزرگ، Cache نقش کلیدی دارد. Reusable Workflows باید از Cacheهای مشترک استفاده کنند تا زمان اجرا کاهش یابد. ابزارهای بهینه‌سازی عملکرد وب به استراتژی‌های Cache اشاره دارد.

Observability

برای پایش Reusable Workflows، از GitHub Insights یا ابزارهای بیرونی استفاده کنید. لاگ‌های متمرکز، امکان تحلیل رفتار را فراهم می‌کنند. بهترین ابزارهای مانیتورینگ سرور؛ کدام برای شما مناسب است؟ به ابزارهای پایش اشاره دارد.

Cross-Repository Workflows

در برخی سناریوها، یک Workflow باید روی چند مخزن اثر بگذارد. این کار با GitHub Apps یا Trigger از طریق API انجام می‌شود. وبهوک‌های گیت‌هاب: چرا بیشتر تیم‌ها از قدرت واقعی آن بی‌خبرند؟ به این الگو اشاره دارد.

Onboarding تیم‌های جدید

Reusable Workflows، Onboarding تیم‌های جدید را ساده می‌کند. تیم جدید، تنها با فراخوانی Workflowهای موجود، می‌تواند در روز اول CI/CD داشته باشد. همکاری بین‌تیمی در سازمان: چرا سیلوهای سازمانی بزرگ‌ترین قاتل نوآوری هستند؟ به این هم‌راستایی اشاره دارد.

Integration با GitOps

Reusable Workflows، پایه GitOps است. تغییرات زیرساخت، از طریق PR و Workflow اعمال می‌شوند. گیت در توسعه وردپرس راهنمای حرفه‌ای به GitOps اشاره دارد. هوک‌های سمت سرور در گیت‌هاب: چرا بیشتر تیم‌ها پتانسیل امنیتی و اتوماسیون آن را نادیده می‌گیرند؟ و هوک‌های سمت کلاینت در گیت‌هاب: چرا با یک فلگ ساده دور زده می‌شوند و چگونه جلوی آن را بگیریم؟ نیز به این معماری اشاره دارند.

Integration با Worktrees

در پروژه‌های پیچیده، Worktreeها امکان کار موازی روی چند شاخه را فراهم می‌کنند. ورک‌تری‌ها در گیت‌هاب به این الگو اشاره دارد. Reusable Workflows می‌توانند در هر Worktree اجرا شوند.

پرسش‌های پرتکرار درباره Reusable Workflows

Reusable Workflow در گیت‌هاب چیست؟

مکانیزمی برای استخراج منطق تکراری CI/CD به یک کامپوننت مشترک که می‌تواند در چند مخزن فراخوانی شود و به‌جای کپی-پیست YAML، منبع واحد حقیقت ایجاد کند.

تفاوت Reusable Workflow و Composite Action چیست؟

Reusable Workflow کل Workflow را فراخوانی می‌کند. Composite Action مجموعه‌ای از Stepها را. اولی برای الگوهای کامل، دومی برای الگوهای کوچک‌تر.

چگونه Reusable Workflow را از مخزن دیگر فراخوانی کنیم؟

با استفاده از uses: owner/repo/.github/workflows/file.yml@ref در سطح Job. Ref می‌تواند شاخه، تگ یا SHA باشد. SHA امن‌ترین گزینه است.

حداکثر Nesting Reusable Workflows چقدر است؟

حداکثر ۴ سطح Nesting و ۲۰ Reusable Workflow در یک زنجیره.

آیا می‌توان Secretها را به Reusable Workflow منتقل کرد؟

بله، به دو روش: Explicit (هر Secret جداگانه) یا inherit (همه Secretها به‌طور خودکار). روش Explicit امن‌تر است.

چگونه Reusable Workflow را تست کنیم؟

با یک Workflow تست در مخزن Reusable که آن را با ورودی‌های نمونه فراخوانی می‌کند. همچنین CI/CD برای خود مخزن Reusable.

آیا Reusable Workflows بر امنیت اثر دارند؟

بله، سطح حمله جدیدی ایجاد می‌کنند. برای امنیت، از SHA در Ref، دسترسی محدود، Secretهای Explicit و Permissions کم استفاده کنید.

چه زمانی از Reusable Workflow استفاده نکنیم؟

وقتی منطق تکراری کوچک است (Composite Action بهتر است)، یا وقتی نیاز به سفارشی‌سازی گسترده دارد و انتزاع بیشتر مضر است.

چگونه Reusable Workflow را نسخه‌بندی کنیم؟

با Tagهای SemVer (@v1، @v1.2.3). تغییرات Backward-Compatible در v1.x، تغییرات Breaking در v2.0.

آیا Reusable Workflows با Self-Hosted Runner کار می‌کنند؟

بله، Reusable Workflows مستقل از نوع Runner هستند. تنها شرط، دسترسی Runner به مخزن Reusable است.

Reusable Workflows، ابزاری برای تبدیل CI/CD از کپی-پیست به معماری ماژولار است. اگر تجربه‌ای در پیاده‌سازی این الگو در سازمان خود دارید، به‌خصوص اگر با چالش مقیاس‌پذیری یا امنیت مواجه شده‌اید، آن را در دیدگاه‌ها بنویسید. تجربه شما می‌تواند راهنمای تیم بعدی باشد. 🔄⚙️