راهاندازی یکپارچهسازی مداوم (CI) برای مسیر شما بسیار مهم است، چون به پیدا کردن اشتباهها کمک میکند.
مخزنهای Exercism (از جمله مخزنهای مسیرها) برای اجرای CI خود از GitHub Actions استفاده میکنند. GitHub Actions بر پایهی _workflow_ها هستند؛ workflowها اسکریپتهایی را تعریف میکنند که هر بار رویداد مشخصی رخ دهد (مثلاً push کردن یک commit) بهطور خودکار اجرا میشوند. برای اطلاعات بیشتر دربارهی workflowهای GitHub Actions، مستندات workflowها را ببینید.
مسیرها همراه با تعدادی workflow از پیش نصبشده عرضه میشوند که بیشترشان را نباید تغییر دهید (به آنها workflowهای مشترک میگویند).
با این حال، یک workflow هست که باید تغییرش دهید: workflow مربوط به test.yml.
هدف workflow مربوط به test.yml این است که بررسی کند تمرینهای مسیر در وضعیت درستی قرار دارند.
این workflow طوری تنظیم شده است که وقتی روی شاخهی main یا روی شاخهی یک pull request یک push انجام میشود، بهطور خودکار اجرا شود (در اصطلاح GitHub Actions: trigger میشود).
خود workflow نباید کار زیادی انجام دهد، جز این موارد:
همانطور که گفته شد، تمرینها با یک اسکریپت بررسی میشوند، یعنی اسکریپت bin/verify-exercises (bash).
این اسکریپت تقریباً آماده است و کارهای زیر را انجام میدهد:
unskip_tests را فراخوانی میکند که در آن میتوانید testها را در فایلهای test خود unskip کنید (اختیاری)run_tests را فراخوانی میکند که در آن باید testها را اجرا کنید (الزامی)توابع run_tests و unskip_tests تنها مواردی هستند که باید پیادهسازی کنید.
اگر مسیر شما از skip کردن testها پشتیبانی میکند، باید مطمئن شویم هنگام بررسی راهحل example/exemplar یک تمرین، هیچ testی skip نمیشود. بهطور کلی، مسیرها به دو روش از «unskip کردن» testها پشتیبانی میکنند:
test.skip به test.SKIP_TESTS=false.اگر skip کردن testها مبتنی بر فایل باشد (همان گزینهی اولی که بالا گفته شد)، تابع unskip_tests را ویرایش کنید تا فایلهای test را تغییر دهید (code موجود از قبل حلقه زدن روی فایلهای test را مدیریت میکند).
تابع unskip_test روی یک کپی از پوشهی تمرین اجرا میشود، پس با خیال راحت فایلها را هرطور که صلاح میدانید تغییر دهید.
فایل bin/verify-exercises file در مسیر Arturo از sed استفاده میکند تا testها را درون فایلهای test از حالت skip خارج کند:
unskip_tests() {
jq -r '.files.test[]' .meta/config.json | while read -r test_file; do
sed -i 's/test.skip/test/g' "${test_file}"
done
}
اگر خارج کردن testها از حالت skip نیازمند تنظیم یک متغیر محیطی است، مطمئن شوید که آن را در تابع run_tests تنظیم کردهاید.
تابع run_tests مسئول اجرای testهای یک تمرین است.
وقتی این تابع فراخوانی میشود، فایلهای example/exemplar از قبل در فایلهای راهحل (stub) کپی شدهاند، بنابراین فقط باید فرمان درست را برای اجرای testها فراخوانی کنید.
اگر همهی testها موفق شوند، تابع باید کد خروجی صفر برگرداند؛ در غیر این صورت باید یک کد خروجی غیرصفر برگرداند.
تابع run_tests روی یک کپی از پوشهی تمرین اجرا میشود، پس با خیال راحت فایلها را هرطور که صلاح میدانید تغییر دهید.
گزینهی پیشفرض برای اسکریپت بررسی تمرینها، استفاده از ابزارهای خود زبان (SDK یا فایل اجرایی و از این قبیل) است که بیشتر مسیرها از آن استفاده میکنند. هر مسیر روش خودش را برای اجرای testها دارد، اما معمولاً فقط یک فرمان است.
فایل bin/verify-exercises file در مسیر Arturo تابع run_tests را طوری تغییر میدهد که فقط فرمان arturo را روی فایل test فراخوانی کند:
run_tests() {
arturo tester.art
}
گزینهی دوم این است که تمرینها را با اجرای test runner مسیر بررسی کنید. البته این بستگی دارد به اینکه مسیر یک test runner کارآمد داشته باشد.
اگر مسیر شما هنوز test runner ندارد، میتوانید یکی از این دو کار را بکنید:
تغییرات زیر باید در اسکریپت پیشفرض bin/verify-exercises اعمال شود:
docker در دسترس استdocker run ایمیج Docker مربوط به test runner را روی هر تمرین اجرا کنیدjq بررسی کنید که فایل results.json برگرداندهشده از کانتینر Docker نشان دهد همهی testها موفق شدهاندunskip_test و فراخوانی آن را حذف کنیدمزیت اصلی این روش این است که بیشترین شباهت را به نحوهی اجرای testها در محیط تولید (روی وبسایت) دارد. با این روش، احتمال اینکه مواردی که در CI موفق شدهاند در محیط تولید شکست بخورند کمتر است. عیب این روش این است که معمولاً کندتر است، چون باید ایمیج Docker را pull کرد و سربار Docker هم روی آن میآید.
فایل bin/verify-exercises file در مسیر Unison بررسیای اضافه میکند تا مطمئن شود فرمان docker هم نصب است:
required_tool docker
سپس ایمیج test runner مسیر را pull میکند:
docker pull exercism/unison-test-runner
بعد تابع run_tests را تغییر میدهد تا با docker run، test runner را روی تمرین فعلی (که در پوشهی کاری قرار دارد) اجرا کند و پس از آن با یک فرمان jq وضعیت درست را بررسی کند:
run_tests() {
local slug
slug="${1}"
docker run \
--rm \
--network none \
--mount type=bind,src="${PWD}",dst=/solution \
--mount type=bind,src="${PWD}",dst=/output \
--tmpfs /tmp:rw \
exercism/unison-test-runner "${slug}" "/solution" "/output"
jq -e '.status == "pass"' "${PWD}/results.json" >/dev/null 2>&1
}
در پایان، باید نحوهی فراخوانی فرمان run_tests را تغییر دهیم، چون اکنون به slug نیاز دارد:
run_tests "${slug}"
حالا که اسکریپت verify-exercises تمام شده، وقت آن است که workflow مربوط به test.yml را نهایی کنیم.
اینکه این کار را چگونه انجام دهیم، به گزینهای بستگی دارد که برای پیادهسازی اسکریپت verify-exercises انتخاب شده است.
اگر اسکریپت verify-exercises مستقیماً از ابزارهای زبان استفاده میکند، workflow مربوط به test باید این موارد را نصب کند:
وقتی این کار انجام شد، verify-exercises باید همانطور که انتظار دارید کار کند و CI را با موفقیت راهاندازی کردهاید!
برای نمونه، workflow مربوط به test.yml در مسیر Arturo را ببینید:
name: Test
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
ci:
runs-on: ubuntu-22.04
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Install dependencies
run: |
sudo apt-get update
sudo apt-get install libgtk-3-dev libwebkit2gtk-4.0-dev libmpfr-dev
- name: Install Arturo
run: bin/install-arturo
env:
GH_TOKEN: ${{ github.token }}
- name: Verify all exercises
run: bin/verify-exercises
گزینهی دوم این است که تمرینها را با اجرای test runner مسیر بررسی کنید. این گزینه دو شرط دارد:
verify-exercises از ایمیج Docker مربوط به test runner برای اجرای testهای یک تمرین استفاده کنداگر مسیر شما هنوز test runner ندارد، میتوانید یکی از این دو کار را بکنید:
این روش چند مزیت دارد:
عیب اصلی آن این است که احتمالاً کندتر است، چون باید ایمیج Docker را pull کرد و سربار Docker هم به آن اضافه میشود.
چند راه برای pull کردن ایمیج Docker مربوط به test runner وجود دارد:
verify-exercises.
این همان روشی است که مسیر Unison به کار میبرد.خب، کدام روش را به کار ببریم؟
توصیه میکنیم حداقل گزینهی شماره ۱ را پیاده کنید تا اسکریپت verify-exercises مستقل باشد.
اگر ایمیج شما بهطور خاص بزرگ است، ممکن است پیادهسازی گزینهی ۳ هم مفید باشد، چون ایمیج ساختهشدهی Docker را در cache مربوط به GitHub Actions ذخیره میکند.
اجراهای بعدی میتوانند ایمیج Docker را بهجای دانلود از cache بخوانند که برای کارایی بهتر است (لطفاً برای اطمینان اندازهگیری کنید).
گزینهی سوم و جایگزین، ترکیبی از دو گزینهی قبلی است.
اینجا هم از ایمیج Docker مربوط به test runner استفاده میکنیم، با این تفاوت که این بار اسکریپت verify-exercises را درون همان ایمیج Docker اجرا میکنیم.
برای فعال کردن این گزینه، باید container مربوط به workflow را روی test runner تنظیم کنیم:
container:
image: exercism/vimscript-test-runner
سپس میتوانیم مرحلههای نصب وابستگیها و ابزارها را رد کنیم (چون آنها از قبل درون ایمیج Docker مربوط به test runner نصب شدهاند) و به اجرای اسکریپت bin/verify-exercises بپردازیم.
workflow مربوط به test.yml در مسیر vimscript از این گزینه استفاده میکند:
name: Verify Exercises
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
jobs:
ci:
runs-on: ubuntu-24.04
container:
image: exercism/vimscript-test-runner
steps:
- name: Checkout repository
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332
- name: Verify all exercises
run: bin/verify-exercises