Робочі процеси CI
Щодо робочих процесів та (більшості) їхніх допоміжних скриптів дивіться теки workflow і scripts у .github
Мітки PR
Наступні робочі процеси працюють разом для автоматичного керування мітками для затвердження PR:
| Файл | Тригер | Привілеї |
|---|---|---|
pr-review-trigger.yml | pull_request_review | Мінімальні (no secrets) |
pr-approval-labels.yml | pull_request_target, workflow_run, schedule | Токен GitHub App для редагування міток та читання на рівні org/team |
blog-publish-labels.yml | schedule (daily 7 AM UTC) | App token + SLACK_WEBHOOK_URL secret |
Управління мітками
missing:docs-approval— додається, коли очікується затвердження з боку командиdocs-approvers; вилучається одразу після отримання затвердження.missing:sig-approval— додається, коли очікується затвердження з боку команди SIG (визначається змінами у файлах та.github/component-owners.yml); вилучається одразу після отримання затвердження від членів SIG або коли компоненти SIG не зачіпаються.ready-to-be-merged— додається, коли отримані всі необхідні затвердження; в іншому випадку вилучається. Для PR, що містять міткуPUBLISH_DATE_LABELS(зараз:blog), ця мітка також обмежується датою публікації, знайденій в змінених файлах.
Дата публікації
Скрипт сканує кожен змінений файл на наявність рядка, що починається з date: (зазвичай з front matter вмісту Markdown). Якщо він знаходить дату в майбутньому, мітка ready-to-be-merged утримується до настання цієї дати (UTC). Це допомагає запобігти злиттю вмісту до запланованої дати публікації.
Перевірка застосовується до PR, що містять будь-яку мітку, зазначену у змінній середовища PUBLISH_DATE_LABELS, яка задається у кожному файлі YAML робочого процесу (наразі: blog). Додавання мітки розширює дію перевірки на інші типи PR.
Якщо PR містить кілька файлів з різними датами, мітка блокується за останньою датою — весь вміст повинен бути готовий до злиття.
Режими роботи скрипту
Скрипт pr-approval-labels.sh обробляє один PR (встановлюється через змінну середовища PR). Він викликається файлом pr-approval-labels.yml при подіях PR та файлом blog-publish-check.sh у пакетному режимі.
Скрипт blog-publish-check.sh відповідає за пакетну обробку: він
перевіряє всі відкриті PR, що містять будь-яку мітку PUBLISH_DATE_LABELS, і запускає
pr-approval-labels.sh для кожного з них. Використовується тригером
blog-publish-labels.yml schedule (щодня о 7
ранку за UTC), тому PR, дата публікації якого настає вночі, автоматично отримує
ready-to-be-merged без необхідності нового коміту.
Для чого два робочі процеси?
Подія GitHub pull_request_review немає опції _target. Це означає, що робочий процес запускається отриманням рецензування на fork PR і виконується в контексті форку і не має доступу до секретів базового репозиторію.
Щоб обійти це обмеження, система використовує workflow_run chaining pattern:
pr-review-triggerвиконується для кожної рецензії (затвердження чи відхилення). Відбувається збереження номеру PR у вигляді артефакту — секрети не потрібні.pr-approval-labelsзапускається черезworkflow_run(коли попередній робочий процес відпрацював). Він запускається в контексті базового репозиторію з повним доступом до GitHub App token, завантажує артефакт та оновлює міти.
У разі змін вмісту (opened, reopened, synchronize), pr-approval-labels запускається безпосередньо через pull_request_target.
sequenceDiagram
participant R as Reviewer
participant GH as GitHub
participant T as pr-review-trigger
participant L as pr-approval-labels
R->>GH: Submits review (approve/request changes/dismiss)
Note over GH: pull_request_review event
GH->>T: Trigger (fork context, no secrets)
T->>T: Save PR number as artifact
T->>GH: Upload artifact, workflow completes
Note over GH: workflow_run event (completed)
GH->>L: Trigger (base repository context, with secrets)
L->>L: Download PR number artifact
L->>L: Run pr-approval-labels.sh
L->>GH: Add/remove labelsМодель безпеки
pr-review-trigger: спеціально є мінімальним — немає секретів, прав доступу й так далі. Ігнорує коментаріreview.state == "commented", оскільки коментарі на впливають на затвердження.pr-approval-labels: запускається з токеном GitHub App (OTELBOT_DOCS_CLIENT_ID/OTELBOT_DOCS_PRIVATE_KEY), що має права на читання на рівні org/team та редагує мітки PR. Використанняpull_request_targetтаworkflow_runдозволяє бути впевненим, що виконання відбувається у контексті базового репозиторію.blog-publish-labels: запускається за розкладом з токеном GitHub App та секретомSLACK_WEBHOOK_URL. Завжди виконується у довіреному контексті базового репозиторію (події розкладу не мають варіанту для форків).
Мітки публікацій у блозі
Робочий процес blog-publish-labels.yml запускається щодня о 7:00 за UTC. Він виконує скрипт blog-publish-check.sh, який перебирає всі відкриті PR із міткою blog і для кожного з них викликає скрипт pr-approval-labels.sh. Коли до будь-якого з них застосовується новий статус ready-to-be-merged, надсилається сповіщення у Slack. Ви також можете запустити його вручну за допомогою workflow_dispatch із вхідним параметром force_notify, щоб надіслати тестове сповіщення у Slack. Коли force_notify має значення true, крок позначення міткою повністю пропускається («сухий запуск») — надсилається лише тестовий вміст повідомлення у Slack.
| Файл робочого процесу | Тригер | Необхідні секрети |
|---|---|---|
blog-publish-labels.yml | schedule (щодня о 7:00 за UTC), workflow_dispatch (ручне тестування через force_notify) | OTELBOT_DOCS_PRIVATE_KEY, SLACK_WEBHOOK_URL |
Сповіщення в Slack надсилається лише тоді, коли мітка переходить з відсутньої до присутньої під час цього запуску — повторні щоденні запуски для вже промаркованого PR не надсилають повторні сповіщення. При ручному запуску робочого процесу встановіть force_notify у true, щоб надіслати одноразове тестове сповіщення (мітки не застосовуються), щоб ви могли перевірити форматування Slack.
Налаштування вебхука Slack
Робочий процес використовує Slack Workflow Builder webhook trigger, що дозволяє не інженерам керувати форматом повідомлення без зміни коду робочого процесу.
Створення вебхука:
У Slack: Інструменти → Workflow Builder → Новий робочий процес → Почати з нуля
Виберіть тригер: Webhook
Оголосіть одну змінну — назва:
pr_list, тип: ТекстДодайте крок: Надіслати повідомлення до потрібного каналу, з тілом:
:newspaper: *Blog posts ready to publish* The following PRs have reached their publish date and all required approvals — they are ready to be merged: {{pr_list}} Have a great day! :sunny:Далі натисніть Додати кнопку і налаштуйте:
- Назва:
Review and merge - Колір: Primary (зелений)
- Дія: Відкрити посилання
- URL:
https://github.com/open-telemetry/opentelemetry.io/issues?q=is%3Apr+state%3Aopen+label%3Ablog+label%3Aready-to-be-merged
- Назва:
Опублікуйте робочий процес і скопіюйте URL вебхука
Додайте його до репозиторію: Налаштування → Секрети та змінні → Дії → Новий секрет репозиторію, назва:
SLACK_WEBHOOK_URL
Payload, що надсилається робочим процесом:
{
"pr_list": "• #123: Add blog post: OTel 1.0 — https://github.com/.../pull/123\n• #456: Announce: new SIG — https://github.com/.../pull/456"
}
Кожен PR є пунктом списку з його заголовком та URL. Slack автоматично створює посилання для простих URL. Кілька PR, позначених в один день, обʼєднуються в одне повідомлення — один виклик вебхука незалежно від кількості готових PR.
sequenceDiagram
participant GH as GitHub
participant W as blog-publish-labels
participant B as blog-publish-check.sh
participant L as pr-approval-labels.sh
participant S as Slack
Note over GH: schedule event (daily, 7 AM UTC)
GH->>W: Trigger (base repository context, with secrets)
W->>B: Run blog-publish-check.sh
B->>GH: Query open PRs with PUBLISH_DATE_LABELS labels
GH-->>B: List of PRs
loop Each PR
B->>L: Run pr-approval-labels.sh (PR=number)
L->>GH: Add/remove labels
end
alt Any PR newly labeled ready-to-be-merged
W->>S: POST Slack notification with PR links
endДирективи виправлення PR
Файл pr-actions.yml дозволяє учасникам запускати певні fix скрипти шляхом додавання коментарів до PR:
/fixзапускаєnpm run fix./fix:<name>запускаєnpm run fix:<name>(наприклад,/fix:format)./fix:allпереадресує на/fixоскільки семантика команд була змінена (#9291)./fix:ALLпереадресує наfix:all, тож супровідники можуть запускатиfix:all.
Директива повинна бути першим рядком коментаря; будь-які наступні рядки ігноруються, тож ви можете додати пояснення після неї. Сам робочий процес запускається на будь-який коментар, тіло якого починається з /fix (наприклад, /fixup потрапляє в конвеєр і отримує зворотний звʼязок про недійсну директиву, тоді як коментар, що починається з пробілу, або з /fix лише на пізнішому рядку, не запускає робочий процес взагалі).
Вони запускаються у чотириступеневому конвеєрі:
ack(надійний): як тільки отримує вказівку, відповідає коментарем 🔄 «у процесі виконання», що містить посилання на коментар із вказівкою та на сам запуск.generate-patch(ненадійний): перевіряє гілку PR, запускає команду виправлення, очищає кеш посилань і завантажує артефакт латки (site.patch), до 1024 КБ.apply-patch(надійний): викликає робочий процесreusable-apply-patch.yml— отримується з основної гілки, ніколи не з PR, який застосовує латку за допомогою токена GitHub App і додає коміт у гілку PR. Пропускається, якщо команда не внесла змін.report(надійний): замінює підтвердження на остаточний результат, коли це можливо, або публікує новий коментар з результатом, коли підтвердження не існує, наприклад, для закритих PR. Кожна директива зазвичай відповідає одному коментарю, який посилається на директиву та на запуск, який її створив. Це охоплює всі директиви, які запускають робочий процес, включаючи недійсні директиви (такі як/fixupабо/fix please), бездіяльні запуски та помилки, що виникають до створення будь-якого латки.
Директиви виконуються лише для відкритих PR (включаючи чернетки PR): у закритому або обʼєднаному PR команда виправлення ніколи не запускається, а завдання звіту пояснює причину. Стан PR береться з корисного навантаження тригера, тому жоден виконавець не витрачається на саме виправлення.
Конвеєр працює лише в канонічному репозиторії open-telemetry, де існують облікові дані бота. Fork PR працюють нормально, події issue_comment спрацьовують у базовому репозиторії, але робочий процес пропускає себе всередині форків.
Директиви дотримуються семантики «останнього переможного варіанту»: новий коментар /fix у PR скасовує поточний запуск цього PR (який все одно видає результат ⚠️), оскільки паралельні запуски виправлення на одній гілці не мають сенсу — другий push все одно завершиться невдачею, щойно гілка буде переміщена.
Парсер директив знаходиться у scripts/gh/pr-fix/, генерування латок — у дії npm-script-patch, а коментарі з визнанням та результатами створюються за допомогою scripts/gh/patch-report/; всі вони проходять модульне тестування за допомогою команди npm run test:local-tools.
Прибирання
Робочий процес housekeeping.yml запускається для затверджених команд виправлення — зазвичай fix-and-test:all, або скрипт npm, що запускається вручну (лише для супровідників) — щодня о 21:37 за UTC, приблизно через 12 годин після виконання інших щоденних автоматизованих завдань, і публікує всі отримані зміни у вигляді PR. Це другий виклик дій з повторного використання латок, а також потік планового обслуговування, що став поштовхом для створення #6592.
Він запускає триступеневий конвеєр:
generate-patch: запускає команди прибирання через дію npm-script-patch і завантажує зміни як артефакт латки. На відміну від конвеєра/fix, весь запуск є надійним: тригери розкладу та виклику завжди виконують код зі стандартної гілки. Невдала команда призводить до невдачі завдання, але будь-які виправлення, які вона створила, все одно публікуються з попередженням про часткові результати в тілі PR.publish-patch: викликає робочий процесreusable-patch-pr.yml, аналогreusable-apply-patch.ymlдля процесів виклику без контексту PR, який примусово робить push латки в стабільну гілкуotelbot/housekeeping, відтворювану зmainна кожному запуску, і відкриває для неї PR, якщо він ще не відкритий. Таким чином, одночасно існує не більше одного PR для прибирання, завжди містить останні результати. Будь-які коміти, направлені в гілку, вручну або через/fix, будуть перезаписані наступним запуском, тому зливайте PR негайно, якщо ви робити push комітів в нього. Пропускається, коли команда не створила змін, залишаючи будь-який відкритий PR для прибирання без змін. Автоматичне злиття безпечне для PR прибирання за умови, що застарілі схвалення скасовуються при push комітів: необхідні огляди залишаються контролем над контентом, отриманим від машини та інтернету, навіть при примусових pushes.report-failure: створює тікет відстеження у разі невдачі через звітність про невдачі робочого процесу; коли виправлення були опубліковані, тікет посилається на PR для прибирання.
Робочий процес refcache-refresh.yml також запускається щодня та торкається refcache.json, Отже, ці два PR від ботів можуть конфліктувати залежно від порядку злиття. Конфлікти вирішуються автоматично, оскільки обидві гілки синхронізуються з main під час кожного запуску. Перенесення refcache-refresh у модуль багаторазових дій з накладення латок — що усуває такі конфлікти за самою своєю суттю — відстежується в плані проєкту.
Автоматичне злиття локалізацій
Робочий процес locale-auto-merge.yml дозволяє кураторам локалі вмикати функцію GitHub auto-merge для PR, що стосуються виключно локалі, за допомогою директиви /auto-merge (або /auto-merge:enable / /auto-merge:disable) в коментарі до PR —правила розміщення дивіться у допоміжному файлі README. Він працює як бот DOCS, який має привілеї, необхідні для перемикання опції «обʼєднати, коли буде готово» в умовах захисту гілки; CODEOWNERS та необхідні перевірки залишаються жорстким барʼєром для обʼєднання.
Тонкий робочий процес делегує завдання помічнику в scripts/gh/locale-auto-merge/, який перед дією застосовує два обмеження: кожен змінений файл повинен належати локалі, а коментатор повинен бути членом команди docs-<loc>-maintainers для кожної локалі, якої торкається PR. Правила придатності та авторизації помічника (і як їх перевірити локально) знаходяться в його README; його модульні та інтеграційні тести виконуються за допомогою npm run test:local-tools. Використання для учасників описано в посібнику з локалізації.
Гілки інтеграції специфікацій
Запланований робочий процес specs-integration.yml керує циклом оновлення сайту для вихідних репозиторіїв специфікацій (які auto-update-versions.yml тому виключає). Він виконує одне матричне завдання для кожного вихідного репозиторію: між випусками кожне завдання відстежує невипущені зміни з вихідного репозиторію через чернетковий PR («гілку інтеграції»); щойно вихідний репозиторій випускає нову версію, воно фіналізує цю гілку та PR у PR випуску.
| Матричне завдання | Вихідний репозиторій | Slag гілки |
|---|---|---|
otel | opentelemetry-specification | spec |
semconv | semantic-conventions | semconv |
Кожне завдання делегує крок «вибір режиму, версії та гілки» спільному помічнику scripts/gh/specs/pick-branch.mjs. Помічник:
- Обирає
MODEзапуску:dev, поки версія, зафіксована в main, є останнім випуском upstream, таrelease, коли існує новіший випуск. - Записує
MODE,VERSIONтаBRANCHу$GITHUB_ENVдля наступних кроків. - Відкриває відстежувальне питання (мітка
<slug>-integration-warning, дедуплікація) при виявленні проблем, таких як кілька застарілих інтеграційних гілок.
Останній крок scripts/gh/specs/create-or-finalize-pr.mjs створює або фіналізує PR відповідно до MODE: у режимі dev він відкриває чернетковий інтеграційний PR, якщо його не існує; у режимі release він створює або фіналізує PR випуску. Він перезаписує лише текст PR, який створила автоматизація: заголовок або тіло, відредаговані супровідником, залишаються без змін.
Режими запуску
Обидва помічники автоматично обирають між режимом dry-run та write і виводять банер [mode], пояснюючи свій вибір:
| Контекст | Стандартна поведінка | Перевизначення |
|---|---|---|
| GitHub Actions | write | pass --dry-run |
| Local (anywhere else) | dry-run | pass --no-dry-run |
Локально, dry-run все ще виконує всі команди git/gh лише для читання (щоб перевірка дедуплікації питань виконувалася), але пропускає записи. З --no-dry-run помічники використовують ваші локальні облікові дані gh; якщо GITHUB_ENV не встановлено, pick-branch виводить лише MODE/VERSION/BRANCH в stdout — експортуйте їх для передачі в локальний запуск create-or-finalize-pr. Спробуйте:
scripts/gh/specs/pick-branch.mjs --spec otel
scripts/gh/specs/pick-branch.mjs --spec semconv --no-dry-run
scripts/gh/specs/create-or-finalize-pr.mjs --help
Чиста логіка знаходиться в index.mjs кожного помічника і покривається файлами *.test.mjs у тій же теці (npm run test:local-tools для їх запуску).
Повідомлення про помилки робочого процесу
reusable-report-failure.yml відкриває (або коментує) відстежувану проблему, коли робочий процес, що викликає, не вдається. Як його підключити, необовʼязкові вхідні дані та поведінка контексту процесу, що викликає, документуються в заголовку файлу робочого процесу; логіка проблеми знаходиться в scripts/gh/report-failure/
(npm run test:local-tools).
Інші робочі процеси
Репозиторій також містить кілька інших робочих процесів:
| Робочий процес | Призначення |
|---|---|
check-links.yml | Перевірка посилань за допомогою htmltest, а також пілотний проєкт Lychee без блокування |
check-text.yml | Перевірка термінології Textlint |
check-i18n.yml | Перевірка локалізації front matter |
check-spelling.yml | Перевірка орфографії |
test.yml | Запуск тестів (виключає test:base) |
auto-update-registry.yml | Автоматичне оновлення версій пакетів реєстру |
auto-update-versions.yml | Автоматичне оновлення версій компонентів OTel (крім репозиторіїв специфікацій) |
build-dev.yml | Збірка для розробки та попередній перегляд |
lint-scripts.yml | Перевірка скриптів за допомогою ShellCheck |
label-manager.yml | Керування мітками PR (мітки компонентів та процес затвердження) |
component-owners.yml | Призначення рецензентів на основі власності на компоненти |