У статті детально описується, як налаштувати автоматизовані релізи Rust-проєктів із використанням сучасних інструментів. Пояснюється, для чого застосовується git-cliff при створенні changelog, як release-plz допомагає керувати версіями й виконувати публікацію на crates.io, а також яку роль відіграє cargo-dist у збірці бінарників для різних операційних систем. Окремо розглянуто інтеграцію Dependabot і Mergify, що дозволяє своєчасно оновлювати залежності й уникати рутинної роботи. Матеріал показує, як поєднання цих інструментів робить процес випуску нових версій швидким, надійним та зручним навіть для великих проєктів.
Уявіть собі розробника на ім’я nuhro . Він написав свою першу програму на Rust, і вона щасливо працює на його машині. Він також надіслав бінарний файл/exe кільком довірливим друзям, і всім їм сподобалася програма після того, як вони її сліпо виконали. Гарні вібрації!
Потім одного дня він вирішив поділитися цією невеликою програмою зі світом (також відомою як Reddit). Для цього він зрозумів, що йому потрібно випустити програму. Інакше як же користувачі інтернету (які можуть використовувати різні ОС/платформи) встановлять/запустять програму, правда?
І так, це було у 2019 році, коли було опубліковано перший проєкт на Rust та автоматизував процес релізу за допомогою запозиченого робочого процесу GitHub Actions від ripgrepo_O. Повертаючись до сьогодення, якщо ви хочете випустити проект Rust, цілком ймовірно, що ви зіткнетеся з такими інструментами для випуску Rust:
cargo-releaseвсе про випуск іржавого ящика.
cargo-smart-release: автоматично випускати складні робочі простори cargo з генерацією журналу змін.
cargo-unleashІнструменти автоматизації випуску для масивних монорепозиторіїв.
Ми можемо перерахувати тут інші інструменти, але, якщо коротко, все, що ми хочемо зробити, це:
Переконайтеся, що проєкт готовий до випуску . Це може включати оновлену версію/журнал змін/залежності.
Позначте новий реліз.
Опублікуйте нову версію на різних платформах (crates.io, GitHub тощо)
Тут ми збираємося змішати найпотужніші інструменти, щоб створити відьмину суміш — найкращий спосіб публікації контейнерів Rust. Дехто може назвати це токсичним варивом, яке може отруїти когось через надмірну автоматизацію. Дехто може назвати це квитком в один кінець до пекла автоматизації. Дехто може…
Отже, ось список інструментів, які ми будемо використовувати:
git-cliff Генератор журналу змін з широкими можливостями налаштування. Автоматизує створення журналу змін.
release-plz Опублікувати контейнери Rust з CI з вимогою щодо випуску. Обробляє оновлення залежностей, керування версіями та випуск crates.io.
cargo-dist Упаковка для застосунків Rust, що підлягає транспортуванню. Створює релізи та упаковки GitHub для різних платформ.
Dependabot Автоматизовані оновлення залежностей, вбудовані в GitHub. Оновлює залежності дій Rust та GitHub.
Mergify Автоматизований інструмент CI/CD для оптимізації. Автоматично об’єднує
Dependabotзапити на зняття.
З мінімальними налаштуваннями ми можемо зробити ці інструменти безперешкодно інтегрованими один з одним, і зрештою, все, що нам потрібно зробити, це просто натиснути кнопку, щоб запустити новий реліз. Іншими словами, найкраще в цьому процесі релізу те, що майже все обробляється в незалежній інтерфейсі, тобто в діях GitHub, тому ми навіть пальцем не ворухнемо.
А тепер, давайте візьмемося за роботу!
git-cliff– один з моїх великих проєктів, який широко використовується в екосистемі Rust для автоматизації створення журналу змін.
git-cliff — це інструмент командного рядка (написаний на Rust ), який надає високо настроюваний спосіб створення журналів змін з історії git. Він підтримує використання користувацьких регулярних виразів для зміни журналів змін, які здебільшого базуються на звичайних коммітах . Завдяки шаблонізатору, натхненному Jinja2/Django, за допомогою одного файлу конфігурації можна застосовувати широкий спектр форматів для журналу змін.Більше інформації та прикладів можна знайти в репозиторії GitHub .
Для нашого формату журналу змін ми можемо просто використовувати конфігурацію за замовчуванням, яка виводить щось на кшталт наступного:
# Changelog All notable changes to this project will be documented in this file. ## [unreleased] ### Documentation - Add link to emacs package support git-cliff (#307)
Для цієї конфігурації спочатку нам слід встановити git-cliff:
cargo install git-cliff --locked
Тоді ми можемо ініціалізувати його наступним чином:
git cliff --init
Це створить cliff.tomlу поточному каталозі, і ви можете закомітувати його в кореневому каталозі вашого репозиторію, щоб release-plzотримати його.
Якщо ви хочете створити складніший журнал змін, ви можете переглянути приклади або скористатися конфігурацією , якаgit-cliff відповідає наступному:
$ git cliff # Changelog All notable changes to this project will be documented in this file. ## [unreleased] ### 📚 Documentation - _(readme)_ Add link to emacs package support git-cliff ([#307](https://github.com/orhun/git-cliff/issues/307)) - ([fa471c7](https://github.com/orhun/git-cliff/commit/fa471c7178dce184ca6fe5bbb24b9c2db96d68ce))
Чудово, тепер ми готові налаштувати власне інструмент для зняття важеля!
release-plz створює повністю автоматизований конвеєр релізів, що дозволяє вам легко випускати зміни частіше, без побоюючись помилок чи інших незначних помилок, які ви можете зробити під час випуску з терміналу.
На відміну від git-cliff, нам насправді не потрібно встановлювати його release-plzяк інструмент командного рядка. Це тому, що release-plzвін запускається з CI (GitHub Actions), і ми нічого локально не робимо для релізів. Однак нам все ще потрібно налаштувати деякі речі щодо того, як ми хочемо релізувати наш проект.
Для налаштування release-plzстворіть release-plz.tomlз наступним вмістом у кореневому каталозі вашого репозиторію:
[workspace] # path of the git-cliff configuration changelog_config = "cliff.toml" # enable changelog updates changelog_update = true # update dependencies with `cargo update` dependencies_update = true # create tags for the releases git_tag_enable = true # disable GitHub releases git_release_enable = false # labels for the release PR pr_labels = ["release"] # disallow updating repositories with uncommitted changes allow_dirty = false # disallow packaging with uncommitted changes publish_allow_dirty = false # disable running `cargo-semver-checks` semver_check = false
Важливими опціями тут є:
changelog_config: має вказувати наgit-cliffконфігурацію, яку ми створили в попередньому розділі.
dependencies_update: встановлення цього значенняtrueозначає, що ви хочете запускатиcargo updateперед кожним релізом. Увімкнення цього параметра для оновлення транзитивних залежностей не завадить, оскільки ми вже будемо оновлювати основні залежності за допомогою Dependabot у наступних кроках.
git_tag_enable: встановіть це значення,trueщоб створити тег для нових релізів.
git_release_enable: переконайтеся, що ви встановили це значення,falseоскільки ми не хочемоrelease-plzстворювати реліз GitHub для нас, оскільки ця частина буде обробленаcargo-dist.
Щодо наступного кроку, нам слід створити фактичну автоматизацію релізу, яка відповідає за виконання release-plzкожного коміту, що надсилається до репозиторію, та створення “release PR”.
https://github.com/orhun/daktilo/pull/51
Після об’єднання релізного PR, release-plzвиявляє, що є зміна версії, Cargo.tomlі запускає cargo publishреліз нової версії на crates.io .
А, тож нам, мабуть, потрібно налаштувати секрети для токена публікації тощо, чи не так? Так! І кілька дозволів також. Ви можете переглянути release-plzдокументацію для отримання детальнішої інформації, але ось короткий виклад:
1. Змініть «Дозволи робочого процесу», щоб дозволити GitHub Actions створювати та затверджувати запити на зняття (pull requests) у Репозиторій > Налаштування > Дії > Загальні.
2. Створіть новий PAT (персональний токен доступу) (дрібнозернистий або класичний) з правильними правами доступу до репозиторію та додайте його до репозиторію як секретний ключ з назвою RELEASE_PLZ_TOKEN.
3. На crates.io згенеруйте новий токен з publish-newправами publish-updateдоступу та додайте його до репозиторію як секрет з назвою CARGO_REGISTRY_TOKEN.
4. Ми нарешті можемо створити наш робочий процес дій GitHub у.github/workflows/release-plz.yml
name: Continuous Deployment
on:
push:
branches:
- main
jobs:
release-plz:
name: Release-plz
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.RELEASE_PLZ_TOKEN }}
- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
- name: Run release-plz
uses: MarcoIeni/[email protected]
env:
GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
Щоб розбити це на частини:
Ми клонуємо всю історію git за допомогою
fetch-depth: 0, що необхідно для визначення наступної версії та створення журналу змін.
Ми встановлюємо стабільну версію Rust (чому б і ні?!)
Як останній крок, ми біжимо
release-plz, чорт забирай!
З : Вау, вау, вау, гей, гей, гей, що там з GITHUB_TOKEN: ${{ secrets.RELEASE_PLZ_TOKEN }}? Просто використовуйте ${{ secrets.GITHUB_TOKEN }}bro, який визначено як `за замовчуванням` для кожного репозиторію.
В : Гарне питання! Якщо ви використовуєте GITHUB_TOKEN, це означає, що ви збираєтеся автентифікуватися від імені GitHub Actions.
З : То що ж тут не так?
A : Ну, робочі процеси, що запускаються , on: push: tags не працюватимуть, якщо тег створено GitHub Actions. Тому ми використовуємо персональний токен доступу, який є способом сказати: «Шановні GitHub Actions, запускаю, release-plz,далі створюю тег, тому, будь ласка, запустіть подальші робочі процеси». Крім того, таким чином нам не потрібно вказувати дозволи робочого процесу за допомогою permissions:ключа. Ви можете дізнатися більше про це тут .
Тепер ми просто готові працювати над нашим проєктом як завжди, і release-plzстворимо PR-запит на реліз для наших змін, і ми зможемо об’єднати його для створення нового релізу, коли будемо готові!
З : Що робити, якщо хочу запустити/тестувати release-plzлокально?
A : Можете, якщо хочете! Запит на оновлення – це просто вивід release-plz updateкоманди, тож ви можете запустити його локально та побачити, що змінилося з точки зору журналу змін тощо. Також, якщо ви хочете створити запит на оновлення з командного рядка, ви можете просто виконати release-plz release-pr!
cargo-dist спрощує розповсюдження бінарних файлів, розбиваючи процес на кілька кроків, таких як планування, збірка, публікація та оголошення. Це просто інструмент для створення цієї чудової сторінки випуску разом із бінарними артефактами та інсталяторами:
https://github.com/orhun/daktilo/releases/tag/v0.4.0
Подібно до release-plz, cargo-distце інструмент, який ми не будемо використовувати локально, а запускатимемо його з CI. Однак його потрібно встановити, щоб налаштувати CI (сам для себе) вперше.
Отже, почнемо з встановлення cargo-dist:
cargo install cargo-dist --locked
Ви також можете скористатися cargo-dist-installerдля встановлення cargo-dist(тобто бінарним інсталятором), якщо бажаєте:
cargo_dist_version="0.3.1"
curl --proto '=https' --tlsv1.2 -LsSf https://github.com/axodotdev/cargo-dist/releases/download/v{version}/cargo-dist-installer.sh | sh
Також у нас буде інсталятор, як показано вище, після того, як він cargo distзробить свою справу.
cargo dist init
Вау, що трапилося?
Наведена вище команда генерує .github/workflows/release.ymlфайл для обробки релізів GitHub. Також вона додає наступний розділ до вашого проєкту Cargo.toml:
# The profile that 'cargo dist' will build with [profile.dist] inherits = "release" lto = "thin" # Config for 'cargo dist' [workspace.metadata.dist] # The preferred cargo-dist version to use in CI (Cargo.toml SemVer syntax) cargo-dist-version = "0.3.1" # CI backends to support ci = ["github"] # The installers to generate for each app installers = ["shell", "powershell"] # Target platforms to build apps for (Rust target-triple syntax) targets = [ "x86_64-unknown-linux-gnu", "aarch64-apple-darwin", "x86_64-apple-darwin", "x86_64-pc-windows-msvc", ] # Publish jobs to run in CI pr-run-mode = "upload"
Ви можете оновити цю конфігурацію, щоб легко налаштувати cargo-distта змінити параметри випуску.
З : А як щодо нових випусків/важливих змін
cargo-dist? Чи потрібно мені видалити конфігурацію та почати все спочатку?A : Ви можете просто запустити
cargo dist initще раз, щоб повторно згенерувати конфігурацію випуску!З : Круто! Чи
cargo-distперевіряє оновлення файлу робочого процесу? Що робити, якщо треба внести зміни до згенерованого робочого процесу дій GitHub (наприклад, встановити залежності Linux)?A : Просто встановіть такі значення в конфігурації, щоб уникнути попередження про «застарілий» статус:
[workspace.metadata.dist] # Ignore out-of-date contents allow-dirty = ["ci"]
З : Як можливо провести тестування cargo-distна місці?
Легко :
$ cargo dist plan
announcing v0.1.0
automated-rust-releases 0.1.0
automated-rust-releases-installer.sh
automated-rust-releases-installer.ps1
automated-rust-releases-aarch64-apple-darwin.tar.xz
[bin] automated-rust-releases
[misc] LICENSE-MIT
[checksum] automated-rust-releases-aarch64-apple-darwin.tar.xz.sha256
automated-rust-releases-x86_64-apple-darwin.tar.xz
[bin] automated-rust-releases
[misc] LICENSE-MIT
[checksum] automated-rust-releases-x86_64-apple-darwin.tar.xz.sha256
automated-rust-releases-x86_64-pc-windows-msvc.zip
[bin] automated-rust-releases.exe
[misc] LICENSE-MIT
[checksum] automated-rust-releases-x86_64-pc-windows-msvc.zip.sha256
automated-rust-releases-x86_64-unknown-linux-gnu.tar.xz
[bin] automated-rust-releases
[misc] LICENSE-MIT
[checksum] automated-rust-releases-x86_64-unknown-linux-gnu.tar.xz.sha256
І запустіть, cargo dist buildякщо ви дійсно хочете зібрати артефакти. Також, якщо ви встановите pr-run-modeце uploadв конфігурації, артефакти будуть зібрані та завантажені як artifacts.zipпов’язаний коміт на GitHub.
Тепер ми готові створювати артефакти та випускати їх на GitHub! Залишилося кілька кроків, перш ніж ми створимо реліз та продемонструємо все.
Dependabot— це інструмент, вбудований у GitHub, для автоматичного оновлення залежностей проєкту шляхом створення пул-реквестів.
Ми можемо просто налаштувати це, створивши .github/dependabot.yml:
version: 2
updates:
# Maintain dependencies for Cargo
- package-ecosystem: cargo
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
# Maintain dependencies for GitHub Actions
- package-ecosystem: github-actions
directory: "/"
schedule:
interval: daily
open-pull-requests-limit: 10
Тепер Dependabotпочнеться створення пул-реквестів для залежностей Rust/GitHub Actions, коли вони застаріють:
https://github.com/orhun/systeroid/pull/141
Mergify— це оптимізатор конвеєра CI/CD, який керує вашими пул-реквестами, автоматизує робочий процес GitHub та оптимізує ваші витрати на CI.
Ми будемо використовувати Mergifyдля:
Автоматично об’єднувати
Dependabotзапити на зняття.
Оновіть до останньої
mainгілки для пул-реквестів.
Давайте створимо конфігурацію в .github/mergify.yml:
pull_request_rules:
- name: Automatic merge for Dependabot pull requests
conditions:
- author=dependabot[bot]
actions:
merge:
method: squash
- name: Automatic update to the main branch for pull requests
conditions:
- -conflict # skip PRs with conflicts
- -draft # skip GH draft PRs
- -author=dependabot[bot] # skip dependabot PRs
actions:
update:
Нарешті, нам потрібно створити обліковий запис на https://mergify.com та додати наш репозиторій GitHub до панелі інструментів:
Тепер Mergifyпочнеться обробка відкритих пул-реквестів:
Запити Dependabotна зняття тепер об’єднуються автоматично!
Весь код/конфігурація доступна тут: https://github.com/orhun/automated-rust-releases
release-plzвже створили для нас PR-запит:
https://github.com/orhun/automated-rust-releases/pull/1
cargo-distперевірки також проходять. Давайте натиснемо кнопку об’єднання та створимо реліз:
Після злиття, release-plzотримує нову версію з Cargo.tomlта надсилає її до crates.io:
release-plzтакож створює новий тег, який запускає cargo-dist:
cargo-distзбирає артефакти та завантажує їх до релізу GitHub:
https://github.com/orhun/automated-rust-releases/releases/tag/v0.1.1
Як бачите, cargo-distтакож аналізує журнал змін (який генерується git-cliff) та додає його до релізу. (Зверніть увагу, що вам насправді потрібно створити файл CHANGELOG.md у кореневому каталозі вашого репозиторію, щоб це працювало.)
Давайте спробуємо інсталятор на практиці:
$ curl --proto '=https' --tlsv1.2 -LsSf https://github.com/orhun/automated-rust-releases/releases/download/v0.1.1/automated-rust-releases-installer.sh | sh downloading automated-rust-releases 0.1.1 x86_64-unknown-linux-gnu installing to /home/orhun/.cargo/bin automated-rust-releases everything's installed!
А коли ми його запускаємо:
$ automated-rust-releases Hello, world!
Для останнього проєкту daktilo (CLI-програма, що перетворює клавіатуру на друкарську машинку) була застосована ця автоматизація випуску, яка продемонструвала гарні результати. Наразі очікуються наступні покращення:
git-cliff: краща інтеграція з GitHub (тобто додавання імен учасників до журналів змін * )
release-plz: встановлення версії у звіті про виклик випуску за допомогою команди *
cargo-dist: крос-компіляція *
Дайте мені знати, якщо у вас є пропозиції та ідеї! Щасливого випуску!