مسیری راهنما از «CI چیست؟» تا ایمیجهای کانتینری امضاشده و مستقرشده: Zaryn چطور هر push و درخواست ادغام را در کانتینری جدا میسازد، چطور یک .zev-ci.json بنویسید، و دروازههایی که main را سالم نگه میدارند. اول تصویر، هر گام با توضیح.
آموزش⏱ حدود ۳۰ دقیقه◔ از صفر تا پیشرفته☰ ۱۵ فصل
یاد میگیرید
✓یکپارچهسازی پیوسته (CI) چیست و شما را از چه چیزهایی نجات میدهد
✓یک push چطور در Zaryn به ساختی در کانتینری قفلشده تبدیل میشود
✓نوشتن .zev-ci.json: گامها، ایمیجها، شبکه، حافظه و زمان
✓دروازههایی که جلوی ادغام بد را میگیرند: آزمونها، ارزیابیها و هشدارها
✓ساخت ایمیجهای کانتینری امضاشده و استقرارشان
لازم دارید
•یک مخزن روی Zaryn (اگر ندارید شروع سریع را ببینید)
•فرمان zev، با ورود انجامشده
•آزمونهایی که با یک فرمان اجرا شوند (به هر زبانی)
این آموزش از ایدهٔ CI تا انتشار ایمیجهای امضاشده را فصل به فصل پیش میبرد. اگر میدانید CI چیست، از نقشهٔ راه بالا به [روشن کردنش](#۴-روشن-کردنش) بروید.
## ۱. CI چیست
```diagram
type: flow
title: هر push، بررسیشده با یک ماشین
loop: در هر push و هر درخواست ادغام
---
push میکنید | `zev push`: کامیتهای تازهتان به Zaryn میرسند | | ⇡
~ خودکار
ساخت و آزمون | در کانتینری تمیز و جدا، هر بار به یک شکل | accent | ⚙
~ چند ثانیه تا چند دقیقه بعد
یک حکم | ✓ یا ✗ روی کامیت و درخواست ادغام، با لاگها | good | ✓
```
**یکپارچهسازی پیوسته** (CI) یعنی هر بار که کسی push میکند، ماشینی پروژه را در محیطی تمیز میسازد و میآزماید و نتیجه را کنار کامیت میگذارد. دیگر لازم نیست کسی یادش بماند آزمونها را اجرا کند، و «روی رایانهٔ من کار میکند» دیگر استدلال نیست: ساخت در کانتینری تمیز یا موفق است یا نه.
## ۲. شما را از چه چیزهایی نجات میدهد
```diagram
type: cards
title: بدون CI، و با آن
---
🖥 | «روی رایانهٔ من کار میکند» | یک فایل جامانده یا تنظیمی محلی ساختِ خراب را پنهان میکند | bad
💥 | main خراب | کسی ادغام میکند، همه pull میکنند، هیچ چیز کامپایل نمیشود | bad
🐢 | بازبینی کند | بازبینها آزمونها را دستی اجرا میکنند، یا نمیکنند | warn
✅ | حکمی روی هر تغییر | هر درخواست ادغام نشان میدهد ساخته و از آزمون رد میشود یا نه | good
🛡 | دروازهها | تغییری که آزمون را رد میکند، سنجهای را بدتر میکند یا وابستگی ناامن دارد ادغام نمیشود | good
📦 | انتشار از همان ساخت | همان چیزی که از آزمون گذشت منتشر میشود، امضاشده | good
```
## ۳. Zaryn چطور اجرایش میکند
```diagram
type: graph
title: از یک push تا یک حکم
alt: zev push به Zaryn میرسد که یک webhook امضاشده به zev-ci میفرستد؛ zev-ci مخزن را با بات CI کلون میکند و هر گام را در کانتینر داکر قفلشدهٔ خودش اجرا میکند و وضعیت، artifactها و SBOM را به Zaryn برمیگرداند
legend: path=push؛ path2=حکم
height: 46
---
node you | zev push | 10 22 | laptop | | کامیتهای شما، یا یک درخواست ادغام
node api | Zaryn | 38 22 | cloud | accent | برای مخزنهایی که CI روشن دارند یک webhook امضاشده به CI میفرستد
node ci | zev-ci | 66 22 | ci | | با بات CI کلون میکند، سپس هر گام را اجرا میکند
box هر گام | 78 4 20 36 | good
node box | یک کانتینر | 88 22 | lock | good | بیشبکه مگر خواسته شود، ریشهٔ فقطخواندنی، بیقابلیت، با محدودیت حافظه، پردازنده و زمان
link you api | | path
link api ci | webhook امضاشده | path
link ci box | هر گام | path
link ci api | | hidden
step حکم برمیگردد | وضعیت، لاگها، artifactها و SBOM به Zaryn برمیگردند و مخزن، درخواست ادغام و `zev ci status` نشانشان میدهند.
link api ci | dim |
link ci api | path2 | وضعیت
```
هر گام در یک **کانتینر تازه و قفلشده** اجرا میشود: بیشبکه مگر آن گام بخواهد، با سیستمفایل ریشهٔ فقطخواندنی، بی هیچ قابلیت لینوکسی، و با محدودیت حافظه، پردازنده، شمار فرایندها و زمان. یک گام نمیتواند اعتبارنامههای سرور یا کد مخزن دیگری را بخواند، پس CI حتی برای کدی که خودتان ننوشتهاید امن است.
## ۴. روشن کردنش
```diagram
type: flow
title: یک فرمان
---
zev ci enable | در پوشهٔ مخزن، یا Enable CI در داشبورد آن | accent | ⏻
~ push
نخستین اجرا | zev push: Zaryn یک ساخت را شروع میکند | | ▶
~ هنوز پیکربندی ندارید؟
بیپیکربندی | zev-ci پروژه را میشناسد و ساخت و آزمون معمولش را اجرا میکند | good | ✨
```
```bash
zev ci enable
zev push
```
هنوز `.zev-ci.json` ندارید؟ CI مخزن را نگاه میکند و فرمانهای معمول را اجرا میکند:
```diagram
type: cards
---
⚡ | Zig | `build.zig`: آخرین Zig پایدار را نصب و `zig build test` را اجرا میکند |
🦀 | Rust | `Cargo.toml`: `cargo build --release`، سپس `cargo test` |
🐹 | Go | `go.mod`: `go build ./...`، سپس `go test ./...` |
🟩 | Node | `package.json`: `npm ci` (یا install)، سپس اگر اسکریپت آزمون باشد `npm test` |
🐍 | Python | `requirements.txt` یا `pyproject.toml`: آنها و pytest را نصب و pytest را اجرا میکند |
🐳 | Dockerfile | یک ایمیج کانتینری امضاشده میسازد، حتی بی هیچ پیکربندی دیگری | accent
```
## ۵. نخستین pipeline شما
وقتی پیشفرضها آن چیزی نیستند که میخواهید، یک `.zev-ci.json` در ریشهٔ مخزن بگذارید:
```json
{
"image": "python:3.12-alpine",
"timeout_seconds": 300,
"steps": [
{ "name": "copy-source", "run": "cp -r /mnt/source/. /workspace/" },
{ "name": "install", "run": "pip install --target /workspace/.deps -r requirements.txt", "allow_network": true },
{ "name": "test", "run": "PYTHONPATH=/workspace/.deps python -m pytest -q" },
{ "name": "package", "run": "mkdir -p dist && tar czf dist/app.tar.gz src" }
],
"artifacts": ["dist/app.tar.gz"]
}
```
```diagram
type: flow
title: آن فایل چه میکند
---
copy-source | کد، از `/mnt/source` فقطخواندنی به `/workspace` | | 📁
~ سپس
install | وابستگیها؛ فقط همین گام میتواند از اینترنت استفاده کند | warn | 🌐
~ سپس
test | pytest: شکست، اجرا را همینجا متوقف میکند | accent | 🧪
~ سپس
package | `dist/app.tar.gz` را میسازد که به عنوان artifact نگه داشته میشود | good | 📦
```
گامها به ترتیب اجرا میشوند و **با نخستین شکست میایستند**. فایل را کامیت و push کنید: اجرای بعدی از آن استفاده میکند.
## ۶. نتیجه را ببینید
```bash
zev ci status # recent runs, and the error of the latest failure
```
```diagram
type: cards
---
🧾 | مخزن | هر کامیت اجرای خودش را نشان میدهد؛ برای خروجی هر گام بازش کنید | accent
🔀 | درخواستهای ادغام | بررسی کنار بازبینی است: سبز، یا قرمز با گامی که شکست خورد |
⌨️ | ترمینال | `zev ci status` اجراهای اخیر و دلیل شکست آخری را فهرست میکند |
🤖 | عاملهای هوش مصنوعی | `zev mcp` وضعیت CI را به صورت یک ابزار به عاملها میدهد |
```
## ۷. گامها، ایمیجها و فضای کار
```diagram
type: graph
title: یک فضای کار، مشترک میان همهٔ گامهای یک اجرا
alt: مخزن به صورت فقطخواندنی در /mnt/source سوار میشود؛ گام اول آن را به /workspace کپی میکند که همهٔ گامهای بعدی میبینند؛ artifactها در پایان از /workspace برداشته میشوند
height: 38
---
node src | /mnt/source | 10 18 | folder | | مخزن شما، فقطخواندنی
node ws | /workspace | 46 18 | storage | accent | مشترک میان گامهای یک اجرا، در پایان پاک میشود
node s1 | گام ۱ | 46 6 | ci | |
node s2 | گام ۲ | 70 6 | ci | | آنچه گام ۱ گذاشته را میبیند
node art | artifactها | 86 30 | file | good | مسیرهایی در /workspace که پس از اجرای موفق نگه داشته میشوند
link src ws | کپی | path
link s1 ws | | dim
link s2 ws | | dim
link ws art | | path2
```
- `image` ایمیج کانتینری پیشفرض است؛ یک گام میتواند با `"image": "…"` ایمیج خودش را داشته باشد (یک گام Node و یک گام Go در یک pipeline).
- `run` یک فرمان پوسته است (`sh -c`). هر چه یک گام در `/workspace` بنویسد برای گام بعدی هست.
- فقط `/workspace` و یک `/tmp` کوچک نوشتنیاند؛ بقیه فقطخواندنی است.
## ۸. شبکه، حافظه و زمان
```diagram
type: cards
title: یک گام چه چیزی میتواند بخواهد
---
🌐 | allow_network | دسترسی اینترنت فقط برای همین گام، برای نصب وابستگیها | warn
🎯 | allowed_hosts | اینترنت، ولی فقط به همین میزبانها | good
🧠 | memory | `"2g"`: حافظهٔ بیشتر (پیشفرض 512m، بی swap) |
⏱ | timeout_seconds | برای هر گام یا کل pipeline، از ۱ تا ۲۱۶۰۰ (پیشفرض ۱۲۰) |
```
طرح شما سقف را تعیین میکند، هر چه فایل بخواهد:
```diagram
type: stats
---
400 | دقیقهٔ CI در ماه، رایگان | ۲ پردازنده، ۴ گیگابایت، ۳۰ دقیقه برای هر گام | 4 |
10,000 | دقیقهٔ CI در ماه، پریمیوم | ۴ پردازنده، ۸ گیگابایت، ۲ ساعت برای هر گام | 100 | accent
```
اجرایی که از دقیقههای ماه بگذرد بیدرنگ میایستد و همین را میگوید.
## ۹. آنچه ساختید را نگه دارید
`"artifacts": ["dist/app.tar.gz"]` آن فایلها را پس از یک اجرای **موفق** نگه میدارد: روی IPFS پین میشوند، پس هر کدام یک نشانی محتوایی دارد که هر کسی میتواند دانلود و بررسی کند، و به کامیتی که آن را ساخت گره خورده است. اجرای ناموفق چیزی نگه نمیدارد.
```diagram
type: flow
title: راه بیرون یک artifact
---
ساختهشده | `dist/app.tar.gz` در /workspace | | 📦
~ اجرا موفق بود
پینشده | روی IPFS: یک CID ساختهشده از بایتهایش | accent | 📌
~ کنار اجرا نشان داده میشود
دانلودپذیر | از خود اجرا، برای هر کسی که میتواند مخزن را بخواند | good | ⇣
```
## ۱۰. از کار انجامشده بگذرید
```diagram
type: flow
title: ورودی یکسان، نتیجهٔ یکسان، بیکار
or: وگرنه
---
ورودیها | هش درخت سورس، ایمیج و فرمان دقیق | | 🧩
~ قبلاً موفق بوده؟
گذشتن | نتیجهٔ ذخیرهشده به کار میرود: ۰٫۵۳ ثانیه شد ۰٫۰۱ ثانیه | good | ⏭
? اجرا | و نتیجه فقط اگر موفق باشد نگه داشته میشود
```
وقتی حافظهسازی (memoization) روی سرور CI روشن است، گامی که سورس، ایمیج و فرمانش قبلاً موفق بوده از حافظهٔ پنهان داده میشود. شکستها هرگز ذخیره نمیشوند، پس یک آزمون ناپایدار پنهان نمیماند. چون گام ردشده چیزی در فضای کار نمیگذارد، برای pipelineهایی مناسب است که گامهایشان به هم وابسته نیستند. [چطور کار میکند](/docs/fa/memoized-ci).
## ۱۱. جلوی تغییری را که چیزی را بدتر میکند بگیرید
آزمونها یا موفقاند یا ناموفق؛ عددها جابهجا میشوند. **ارزیابیها** عددهای هر کامیت را نگه میدارند (زمان ساخت، اندازهٔ باینری، بنچمارکها، پوشش، دقت مدل) و جلوی درخواست ادغامی را که یکی را بیش از حد مجازش بدتر کند میگیرند:
```bash
zev eval init # once: zev finds what to run and measure
zev eval run # compares this commit with main; exits 1 on a regression
```
```diagram
type: cards
---
= | build_time: ثابت | +1.1%، درون حد مجاز ۱۰٪ |
✓ | tests.passed: بهتر | ۲۱۲ ← ۲۱۴ | good
✗ | binary: بدتر | +12.2%، بیرون از ۱٪: درخواست ادغام مسدود میشود | bad
```
`zev eval run` را به صورت یک گام، یا از هر CI دیگری اجرا کنید. همهچیز دربارهٔ ارزیابیها: [ارزیابیها و تبار](/docs/fa/evals-and-lineage).
## ۱۲. روی چیزی ناامن نسازید
```json
{ "advisories": { "fail_on": "high" }, "steps": [ … ] }
```
```diagram
type: flow
title: پیش از نخستین گام بررسی میشود
or: وگرنه
---
پرسش از Zaryn | آیا هشدار حلنشدهای با شدت «high» یا بیشتر از راه تبار به این مخزن میرسد؟ | | 🔎
~ هیچ
اجرا | گامها مثل همیشه شروع میشوند | good | ▶
? یکی میرسد | اجرا پیش از هر گامی شکست میخورد تا چیزی که از آن ساخته شده منتشر نشود | bad
```
اگر Zaryn نتواند پاسخ دهد، اجرا بهجای گذشتن بیبررسی شکست میخورد. [هشدارها](/docs/fa/advisories).
## ۱۳. ایمیجهای کانتینری امضاشده بسازید
```json
{
"steps": [{ "name": "test", "run": "cp -r /mnt/source/. . && make test" }],
"images": [{}]
}
```
```diagram
type: flow
title: از یک اجرای موفق تا ایمیجی که هر کسی میتواند بسنجد
---
ساخت | BuildKit بیروت، در کانتینری دورریختنی بی هیچ اعتبارنامهای | | 🏗
~ سپس
SBOM | همهٔ بستههای درونش، فهرستشده با syft، آفلاین | | 📋
~ سپس
ارسال | به رجیستری Zaryn، با بات CI | accent | ⇡
~ سپس
گواهی | Zaryn گواهی منشأ SLSA را امضا میکند و ساخت را به لاگ شفافیت میافزاید | good | ✍
```
`{}` فایل `Dockerfile` مخزن را به صورت `<owner>/<repo>` میسازد. هر وقت لازم شد `name`، `context`، `tags` (`{branch}`، `{sha}`، `{pr}`) یا چند `platforms` (پریمیوم) بیفزایید. ببینید: [کانتینرها](/docs/fa/packages-containers).
## ۱۴. مستقرش کنید
```diagram
type: graph
title: main مستقر میشود، درخواستهای ادغام پیشنمایش میگیرند
alt: یک اجرای موفق روی main ایمیج امضاشده را روی هدف prod مستقر میکند؛ هر درخواست ادغام پیشنمایش خودش را میگیرد که با ادغام برداشته میشود
height: 36
---
node ci | یک اجرای موفق | 12 18 | ci | accent | فقط digestهایی که CI ساخته و امضا کرده مستقر میشوند
node prod | prod | 60 8 | server | good | `"deploy": {"target": "prod", "app": "web", "branches": ["main"]}`
node prev | pr-42.preview… | 60 30 | server | | `"preview"`: هر درخواست ادغام به صورت برنامهٔ خودش، با ادغام برداشته میشود
link ci prod | main | path
link ci prev | درخواست ادغام | path2
```
یک ایمیج میتواند خودش را روی سرورهای خودتان که عامل Zaryn را اجرا میکنند مستقر کند: `main` روی محیط اصلی، هر درخواست ادغام روی یک نشانی پیشنمایش. فقط ایمیجهایی که CI ساخته و امضا کرده مستقر میشوند، و فقط روی هدفهایی که استقرار از CI را میپذیرند.
## ۱۵. محدودیتها، و وقتی شروع نمیشود
```diagram
type: cards
title: راهحلهای سریع
---
🔌 | push هیچ چیزی را شروع نمیکند | CI روشن نیست: `zev ci enable`، یا Enable CI در داشبورد | warn
🌐 | نصبها شکست میخورند | گام شبکه ندارد: `"allow_network": true` (یا `allowed_hosts`) بیفزایید | warn
⏱ | پس از ۲ دقیقه کشته میشود | محدودیت زمان پیشفرض گام: `timeout_seconds` را بیشتر کنید |
🧠 | هنگام ساخت کشته میشود | حافظه تمام شده: `memory` را در حد طرحتان بیشتر کنید |
📉 | «minutes used up» | دقیقههای CI این ماه تمام شده: ماه بعد، یا پریمیوم |
```
از اینکه CI چیست تا ایمیجهای امضاشده و مستقرشده آمدید. بعد: [CI حافظهدار](/docs/fa/memoized-ci) با جزئیات، [ارزیابیها و تبار](/docs/fa/evals-and-lineage) برای هر نوع سنجه، و [هشدارها](/docs/fa/advisories).
یکپارچهسازی پیوسته (CI) یعنی هر بار که کسی push میکند، ماشینی پروژه را در محیطی تمیز میسازد و میآزماید و نتیجه را کنار کامیت میگذارد. دیگر لازم نیست کسی یادش بماند آزمونها را اجرا کند، و «روی رایانهٔ من کار میکند» دیگر استدلال نیست: ساخت در کانتینری تمیز یا موفق است یا نه.
هر گام در یک کانتینر تازه و قفلشده اجرا میشود: بیشبکه مگر آن گام بخواهد، با سیستمفایل ریشهٔ فقطخواندنی، بی هیچ قابلیت لینوکسی، و با محدودیت حافظه، پردازنده، شمار فرایندها و زمان. یک گام نمیتواند اعتبارنامههای سرور یا کد مخزن دیگری را بخواند، پس CI حتی برای کدی که خودتان ننوشتهاید امن است.
"artifacts": ["dist/app.tar.gz"] آن فایلها را پس از یک اجرای موفق نگه میدارد: روی IPFS پین میشوند، پس هر کدام یک نشانی محتوایی دارد که هر کسی میتواند دانلود و بررسی کند، و به کامیتی که آن را ساخت گره خورده است. اجرای ناموفق چیزی نگه نمیدارد.
راه بیرون یک artifact
📦
ساختهشده
dist/app.tar.gz در /workspace
اجرا موفق بود
📌
پینشده
روی IPFS: یک CID ساختهشده از بایتهایش
کنار اجرا نشان داده میشود
⇣
دانلودپذیر
از خود اجرا، برای هر کسی که میتواند مخزن را بخواند
نتیجهٔ ذخیرهشده به کار میرود: ۰٫۵۳ ثانیه شد ۰٫۰۱ ثانیه
وگرنه
اجرا
و نتیجه فقط اگر موفق باشد نگه داشته میشود
وقتی حافظهسازی (memoization) روی سرور CI روشن است، گامی که سورس، ایمیج و فرمانش قبلاً موفق بوده از حافظهٔ پنهان داده میشود. شکستها هرگز ذخیره نمیشوند، پس یک آزمون ناپایدار پنهان نمیماند. چون گام ردشده چیزی در فضای کار نمیگذارد، برای pipelineهایی مناسب است که گامهایشان به هم وابسته نیستند. چطور کار میکند.
آزمونها یا موفقاند یا ناموفق؛ عددها جابهجا میشوند. ارزیابیها عددهای هر کامیت را نگه میدارند (زمان ساخت، اندازهٔ باینری، بنچمارکها، پوشش، دقت مدل) و جلوی درخواست ادغامی را که یکی را بیش از حد مجازش بدتر کند میگیرند:
Terminal
zev eval init # once: zev finds what to run and measurezev eval run # compares this commit with main; exits 1 on a regression
=
build_time: ثابت
+1.1%، درون حد مجاز ۱۰٪
✓
tests.passed: بهتر
۲۱۲ ← ۲۱۴
✗
binary: بدتر
+12.2%، بیرون از ۱٪: درخواست ادغام مسدود میشود
zev eval run را به صورت یک گام، یا از هر CI دیگری اجرا کنید. همهچیز دربارهٔ ارزیابیها: ارزیابیها و تبار.
از یک اجرای موفق تا ایمیجی که هر کسی میتواند بسنجد
🏗
ساخت
BuildKit بیروت، در کانتینری دورریختنی بی هیچ اعتبارنامهای
سپس
📋
SBOM
همهٔ بستههای درونش، فهرستشده با syft، آفلاین
سپس
⇡
ارسال
به رجیستری Zaryn، با بات CI
سپس
✍
گواهی
Zaryn گواهی منشأ SLSA را امضا میکند و ساخت را به لاگ شفافیت میافزاید
{} فایل Dockerfile مخزن را به صورت <owner>/<repo> میسازد. هر وقت لازم شد name، context، tags ({branch}، {sha}، {pr}) یا چند platforms (پریمیوم) بیفزایید. ببینید: کانتینرها.
main مستقر میشود، درخواستهای ادغام پیشنمایش میگیرند
یک ایمیج میتواند خودش را روی سرورهای خودتان که عامل Zaryn را اجرا میکنند مستقر کند: main روی محیط اصلی، هر درخواست ادغام روی یک نشانی پیشنمایش. فقط ایمیجهایی که CI ساخته و امضا کرده مستقر میشوند، و فقط روی هدفهایی که استقرار از CI را میپذیرند.