fix(tools): port remaining GitHub-specific paths to Forgejo (5 fixes) #1

Open
opened 2026-08-06 19:59:30 +03:00 by slaid098 · 0 comments
Owner

Контекст

После миграции с GitHub на Forgejo основной pipeline (ISSUE→IMPLEMENT→CI→REVIEW→MERGE→MEMORY) портирован и работает (коммиты 93e7843, 0fbf1d9, 9dabc57 на main в Forgejo). Однако аудит выявил 3 бага и 2 гэпа — оставшиеся GitHub-specific пути, которые нужно закрыть для полной паритетности.

ВАЖНО: портированные tools живут в репозитории opencode-config на Forgejo (ветка main). Для работы нужно клонировать: git clone https://slaid098:2cbcfa4b8f269bed7f1323b418cc7c11637f5cb7@git.slaid098.dev/slaid098/opencode-config.git и работать в клоне. Портированный код — в .opencode/tools/_shared.ts (Forgejo dispatch через callForgejoGh), .opencode/scripts/pipeline-status.py (_forgejo_pr_view, _forgejo_gh_dispatch, _forgejo_ci_rollup), и т.д.

Env: FORGEJO_URL=https://git.slaid098.dev, FORGEJO_TOKEN=2cbcfa4b8f269bed7f1323b418cc7c11637f5cb7.

Задача

Применить 5 фиксов:

Fix #1 (BUG, high) — create-readme.ts хардкод github.com

Файл: .opencode/tools/create-readme.ts, ~строка 62-64.

Текущее: хардкод https://github.com/slaid098/${args.repo_name}.git в clone URL генерируемого README.

Фикс: брать host из FORGEJO_URL если задан, иначе github.com:

const host = process.env.FORGEJO_URL ? new URL(process.env.FORGEJO_URL).host : "github.com"
const cloneLine = args.include_clone !== false
  ? `git clone https://${host}/slaid098/${args.repo_name}.git\n`
  : ""

Fix #2 (GAP, medium) — pipeline-status.py headRefName возвращает пустую строку

Файл: .opencode/scripts/pipeline-status.py, функция _forgejo_pr_view.

Forgejo вкладывает ветку в pr.head.ref, не top-level headRefName. run-pipeline Template C/D получает пустую ветку для fix-ci сабагента.

Фикс: добавить маппинг перед generic fallback:

if fields == "headRefName":
    return 0, json.dumps({"headRefName": pr.get("head", {}).get("ref", "")}), ""
if fields == "baseRefName":
    return 0, json.dumps({"baseRefName": pr.get("base", {}).get("ref", "")}), ""
if fields:
    return 0, json.dumps({fields: pr.get(fields, "")}), ""

Fix #3 (BUG, medium) — project-status.py branch-protection field names

Файл: .opencode/scripts/project-status.py, функция _check_branch_protection.

Текущее: string-match на GitHub field names (pull_request, required_status_checks), которых нет в Forgejo BranchProtection schema (там enable_status_check, required_approvals, block_on_rejected_reviews). Всегда WARN даже при настроенной защите.

Фикс: матчить Forgejo field names:

if out and "enable_status_check" in out and "required_approvals" in out:
    return CheckResult(CheckStatus.OK, "branch protection", "main защищён (PR + checks)")

Также: 404 (no rule) → WARN "branch protection: правило не настроено", не "gh api не отвечает".

Fix #4 (GAP, low) — release skill не портирован

Файл: .opencode/skills/release/SKILL.md + нет release tool.

Forgejo endpoint: POST /api/v1/repos/{owner}/{repo}/releases.

Фикс: добавить release dispatch в _shared.ts для gh release create <tag>POST /repos/{full}/releases body {tag_name, name, body}. Создать release.ts tool-обёртку по аналогии с merge-pr.ts. Обновить release SKILL.md.

Fix #5 (GAP, low) — gh issue list не диспетчеризуется

Файл: .opencode/scripts/pipeline-status.py, _forgejo_gh_dispatch.

Сейчас диспетчеризуется только gh issue view. gh issue list (используется в bug-discovery skill для dup-check) спавнит реальный gh → fail на Forgejo.

Фикс: добавить dispatch gh issue list --repo <R>GET /repos/{repo}/issues?state=open.

Контракты

  • GitHub fallback сохранён: если FORGEJO_URL не задан, всё работает как раньше.
  • Диспетчеризация: FORGEJO_URL set → Forgejo path; unset → GitHub path.
  • API endpoints подтверждены live (аудит прошёл GET-запросы).
  • Все 5 фиксов — в одном PR.

Инварианты

  • Существующий pipeline (ISSUE→MERGE→MEMORY) не ломается — фиксы additive.
  • create-readme.ts GitHub fallback (без FORGEJO_URL) выдаёт тот же github.com URL.
  • pipeline-status.py CI gate (через statusCheckRollup → commit-status) НЕ затрагивается.
  • TypeScript compiles (npm run typecheck зелёный). Python — ruff/mypy если настроены.

Граничные случаи

  • Fix #2: pr.head может быть null для удалённой ветки — использовать .get("head", {}) безопасно.
  • Fix #3: branch protection может не существовать (404) — обрабатывать отдельно от "API не отвечает".
  • Fix #4: release с attachment (binary assets) — вне scope, только tag_name/name/body.
  • Fix #5: gh issue list с --state closed или --label — маппить на query params Forgejo API.

Влияние на связанные компоненты

  • create-readme tool: Fix #1 → все новые README указывают на правильный хост.
  • run-pipeline skill: Fix #2 → fix-ci сабагент получает корректную ветку.
  • project-status oracle: Fix #3 → корректный verdict при настроенной branch protection.
  • release skill: Fix #4 → работает на Forgejo (сейчас падает).
  • bug-discovery/issue skills: Fix #5 → dup-check работает на Forgejo.

Вне scope

  • Smoke-test pipeline (отдельный issue D, зависит от этого merge).
  • Зеркалирование на GitLab/Codeberg.
  • Порт gh run list/gh run view.

Критерии приемки

  • create-readme.ts: при FORGEJO_URL=https://git.slaid098.dev генерирует git clone https://git.slaid098.dev/slaid098/<repo>.git. Без FORGEJO_URLgithub.com.
  • pipeline-status.py: gh pr view N --json headRefName возвращает реальную ветку (не "").
  • project-status.py: при существующей branch protection с enable_status_check + required_approvals → OK. При 404 → WARN "правило не настроено".
  • release tool: создаёт release на Forgejo через POST /repos/{full}/releases. Возвращает URL.
  • pipeline-status.py: gh issue list --repo slaid098/opencode-config возвращает JSON list issues.
  • CI зелёный: bootstrap, lint, typecheck, test (3.13), complexity.
  • GitHub fallback не сломан.
## Контекст После миграции с GitHub на Forgejo основной pipeline (ISSUE→IMPLEMENT→CI→REVIEW→MERGE→MEMORY) портирован и работает (коммиты 93e7843, 0fbf1d9, 9dabc57 на main в Forgejo). Однако аудит выявил 3 бага и 2 гэпа — оставшиеся GitHub-specific пути, которые нужно закрыть для полной паритетности. ВАЖНО: портированные tools живут в репозитории `opencode-config` на Forgejo (ветка `main`). Для работы нужно клонировать: `git clone https://slaid098:2cbcfa4b8f269bed7f1323b418cc7c11637f5cb7@git.slaid098.dev/slaid098/opencode-config.git` и работать в клоне. Портированный код — в `.opencode/tools/_shared.ts` (Forgejo dispatch через `callForgejoGh`), `.opencode/scripts/pipeline-status.py` (`_forgejo_pr_view`, `_forgejo_gh_dispatch`, `_forgejo_ci_rollup`), и т.д. Env: `FORGEJO_URL=https://git.slaid098.dev`, `FORGEJO_TOKEN=2cbcfa4b8f269bed7f1323b418cc7c11637f5cb7`. ## Задача Применить 5 фиксов: ### Fix #1 (BUG, high) — `create-readme.ts` хардкод `github.com` Файл: `.opencode/tools/create-readme.ts`, ~строка 62-64. Текущее: хардкод `https://github.com/slaid098/${args.repo_name}.git` в clone URL генерируемого README. Фикс: брать host из `FORGEJO_URL` если задан, иначе `github.com`: ```ts const host = process.env.FORGEJO_URL ? new URL(process.env.FORGEJO_URL).host : "github.com" const cloneLine = args.include_clone !== false ? `git clone https://${host}/slaid098/${args.repo_name}.git\n` : "" ``` ### Fix #2 (GAP, medium) — `pipeline-status.py` `headRefName` возвращает пустую строку Файл: `.opencode/scripts/pipeline-status.py`, функция `_forgejo_pr_view`. Forgejo вкладывает ветку в `pr.head.ref`, не top-level `headRefName`. `run-pipeline` Template C/D получает пустую ветку для fix-ci сабагента. Фикс: добавить маппинг перед generic fallback: ```python if fields == "headRefName": return 0, json.dumps({"headRefName": pr.get("head", {}).get("ref", "")}), "" if fields == "baseRefName": return 0, json.dumps({"baseRefName": pr.get("base", {}).get("ref", "")}), "" if fields: return 0, json.dumps({fields: pr.get(fields, "")}), "" ``` ### Fix #3 (BUG, medium) — `project-status.py` branch-protection field names Файл: `.opencode/scripts/project-status.py`, функция `_check_branch_protection`. Текущее: string-match на GitHub field names (`pull_request`, `required_status_checks`), которых нет в Forgejo `BranchProtection` schema (там `enable_status_check`, `required_approvals`, `block_on_rejected_reviews`). Всегда WARN даже при настроенной защите. Фикс: матчить Forgejo field names: ```python if out and "enable_status_check" in out and "required_approvals" in out: return CheckResult(CheckStatus.OK, "branch protection", "main защищён (PR + checks)") ``` Также: 404 (no rule) → WARN "branch protection: правило не настроено", не "gh api не отвечает". ### Fix #4 (GAP, low) — `release` skill не портирован Файл: `.opencode/skills/release/SKILL.md` + нет `release` tool. Forgejo endpoint: `POST /api/v1/repos/{owner}/{repo}/releases`. Фикс: добавить `release` dispatch в `_shared.ts` для `gh release create <tag>` → `POST /repos/{full}/releases` body `{tag_name, name, body}`. Создать `release.ts` tool-обёртку по аналогии с `merge-pr.ts`. Обновить `release` SKILL.md. ### Fix #5 (GAP, low) — `gh issue list` не диспетчеризуется Файл: `.opencode/scripts/pipeline-status.py`, `_forgejo_gh_dispatch`. Сейчас диспетчеризуется только `gh issue view`. `gh issue list` (используется в `bug-discovery` skill для dup-check) спавнит реальный `gh` → fail на Forgejo. Фикс: добавить dispatch `gh issue list --repo <R>` → `GET /repos/{repo}/issues?state=open`. ## Контракты - GitHub fallback сохранён: если `FORGEJO_URL` не задан, всё работает как раньше. - Диспетчеризация: `FORGEJO_URL` set → Forgejo path; unset → GitHub path. - API endpoints подтверждены live (аудит прошёл GET-запросы). - Все 5 фиксов — в одном PR. ## Инварианты - Существующий pipeline (ISSUE→MERGE→MEMORY) не ломается — фиксы additive. - `create-readme.ts` GitHub fallback (без `FORGEJO_URL`) выдаёт тот же `github.com` URL. - `pipeline-status.py` CI gate (через `statusCheckRollup` → commit-status) НЕ затрагивается. - TypeScript compiles (`npm run typecheck` зелёный). Python — `ruff`/`mypy` если настроены. ## Граничные случаи - Fix #2: `pr.head` может быть `null` для удалённой ветки — использовать `.get("head", {})` безопасно. - Fix #3: branch protection может не существовать (404) — обрабатывать отдельно от "API не отвечает". - Fix #4: release с attachment (binary assets) — вне scope, только `tag_name`/`name`/`body`. - Fix #5: `gh issue list` с `--state closed` или `--label` — маппить на query params Forgejo API. ## Влияние на связанные компоненты - `create-readme` tool: Fix #1 → все новые README указывают на правильный хост. - `run-pipeline` skill: Fix #2 → fix-ci сабагент получает корректную ветку. - `project-status` oracle: Fix #3 → корректный verdict при настроенной branch protection. - `release` skill: Fix #4 → работает на Forgejo (сейчас падает). - `bug-discovery`/`issue` skills: Fix #5 → dup-check работает на Forgejo. ## Вне scope - Smoke-test pipeline (отдельный issue D, зависит от этого merge). - Зеркалирование на GitLab/Codeberg. - Порт `gh run list`/`gh run view`. ## Критерии приемки - [ ] `create-readme.ts`: при `FORGEJO_URL=https://git.slaid098.dev` генерирует `git clone https://git.slaid098.dev/slaid098/<repo>.git`. Без `FORGEJO_URL` — `github.com`. - [ ] `pipeline-status.py`: `gh pr view N --json headRefName` возвращает реальную ветку (не `""`). - [ ] `project-status.py`: при существующей branch protection с `enable_status_check` + `required_approvals` → OK. При 404 → WARN "правило не настроено". - [ ] `release` tool: создаёт release на Forgejo через `POST /repos/{full}/releases`. Возвращает URL. - [ ] `pipeline-status.py`: `gh issue list --repo slaid098/opencode-config` возвращает JSON list issues. - [ ] CI зелёный: bootstrap, lint, typecheck, test (3.13), complexity. - [ ] GitHub fallback не сломан.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: slaid098/opencode-config#1
No description provided.