ورکفلوهای قابل استفاده مجدد در گیتهاب: چرا کپی-پیست YAML، بزرگترین بدهی فنی CI/CD است؟
آموزش -complete-guide گیت هاب درباره ورکفلوهای قابل استفاده مجدد به شما کمک میکند تا با درک عمیق مفاهیم پیشرفته، گردشکارهای حرفهای را پیادهسازی کنید، خطاهای رایج را شناسایی و رفع نمایید و بهرهوری تیم توسعه را به شکل چشمگیری افزایش دهید.
ورکفلوهای قابل استفاده مجدد در گیتهاب (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 از کپی-پیست به معماری ماژولار است. اگر تجربهای در پیادهسازی این الگو در سازمان خود دارید، بهخصوص اگر با چالش مقیاسپذیری یا امنیت مواجه شدهاید، آن را در دیدگاهها بنویسید. تجربه شما میتواند راهنمای تیم بعدی باشد. 🔄⚙️