docs(prd-1): create PRD #1 - Forgejo platform support [skip ci]
- Lean adapter architecture: ~8 new files, reuse existing Octokit REST code - REST-based data fetching to replace GitHub GraphQL queries - Platform detection via explicit input + env-var auto-detection - Custom Forgejo CI workflows with action self-test - 10 milestones across 4 phases Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
ade221fd1c
commit
411eb3d69d
1 file changed
+335
@@ -0,0 +1,335 @@
|
|||||||
|
# PRD #1: Forgejo Platform Support with Upstream-Compatible Architecture
|
||||||
|
|
||||||
|
**Issue**: [#1](https://git.wxs.ro/actions/claude-code-action/issues/1)
|
||||||
|
**Priority**: High
|
||||||
|
**Created**: 2026-02-25
|
||||||
|
**Revised**: 2026-02-25 (post senior engineer review)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Problem
|
||||||
|
|
||||||
|
The `claude-code-action` is tightly coupled to GitHub APIs (Octokit REST, GraphQL, `@actions/github`, OIDC token exchange). This makes it unusable with Forgejo Actions, despite Forgejo being workflow-compatible with GitHub Actions. We need Forgejo support while keeping upstream merges as painless as possible.
|
||||||
|
|
||||||
|
## Solution
|
||||||
|
|
||||||
|
Adopt a **lean adapter approach**: only create new files for functionality that is genuinely different on Forgejo, and **re-use existing `src/github/` code wherever Octokit REST is already compatible** with Forgejo's API. Make minimal, surgical modifications to entry points and `action.yml`.
|
||||||
|
|
||||||
|
### Key Insight: Octokit REST Works with Forgejo
|
||||||
|
|
||||||
|
Octokit REST methods (comments, permissions, branches, actor validation) work with Forgejo when `baseUrl` is set to the Forgejo instance's `/api/v1` endpoint. Forgejo mirrors GitHub's REST API paths. This means most of `src/github/` can be re-used directly — **we do NOT need to duplicate 20+ files**.
|
||||||
|
|
||||||
|
### What Truly Needs Forgejo-Specific Code
|
||||||
|
|
||||||
|
Only **4 areas** require new Forgejo implementations:
|
||||||
|
|
||||||
|
| Area | Why It's Different | New File |
|
||||||
|
|------|--------------------|----------|
|
||||||
|
| **Token handling** | No OIDC exchange with Anthropic; use `GITHUB_TOKEN`/`FORGEJO_TOKEN` directly | `src/forgejo/token.ts` |
|
||||||
|
| **Data fetching** | Forgejo has no GraphQL; must replace 3 GraphQL queries with multiple REST calls | `src/forgejo/data/fetcher.ts` |
|
||||||
|
| **Comment URL formatting** | Forgejo URLs differ from GitHub URLs (job links, PR links, branch links) | `src/forgejo/comment-logic.ts` |
|
||||||
|
| **CI status / Actions API** | Forgejo Actions API is less mature; `downloadJobLogForWorkflowRun` may not exist | `src/mcp/forgejo-actions-server.ts` |
|
||||||
|
|
||||||
|
### What Re-Uses Existing Code (No Duplication)
|
||||||
|
|
||||||
|
These `src/github/` modules work with Forgejo via Octokit REST as-is:
|
||||||
|
|
||||||
|
| Module | Why It Works |
|
||||||
|
|--------|-------------|
|
||||||
|
| `validation/permissions.ts` | `octokit.repos.getCollaboratorPermissionLevel()` exists in Forgejo API |
|
||||||
|
| `validation/actor.ts` | `octokit.users.getByUsername()` works on Forgejo |
|
||||||
|
| `validation/trigger.ts` | Pure logic — reads webhook payload fields, no API calls |
|
||||||
|
| `operations/comments/create-initial.ts` | `octokit.rest.issues.createComment()` works on Forgejo |
|
||||||
|
| `operations/comments/update-claude-comment.ts` | `octokit.rest.issues.updateComment()` works on Forgejo |
|
||||||
|
| `operations/branch.ts` | `octokit.rest.git.getRef()`, `octokit.rest.repos.get()` work on Forgejo |
|
||||||
|
| `operations/git-config.ts` | Uses `GITHUB_SERVER_URL` for noreply domain — works since Forgejo sets this var |
|
||||||
|
| `utils/sanitizer.ts` | Pure logic, no API dependency |
|
||||||
|
| `utils/image-downloader.ts` | Uses Octokit REST for fetching — should work |
|
||||||
|
| `context.ts` | `@actions/github` reads `GITHUB_EVENT_PATH` — Forgejo sets this |
|
||||||
|
| `data/formatter.ts` | Pure formatting logic |
|
||||||
|
| `api/config.ts` | Reads `GITHUB_API_URL` / `GITHUB_SERVER_URL` — Forgejo sets these |
|
||||||
|
|
||||||
|
### Architecture: Lean Adapter
|
||||||
|
|
||||||
|
```
|
||||||
|
src/
|
||||||
|
├── platform/
|
||||||
|
│ └── detector.ts # NEW - Platform detection (+ action.yml `platform` input)
|
||||||
|
├── forgejo/
|
||||||
|
│ ├── token.ts # NEW - Direct token (skip OIDC)
|
||||||
|
│ ├── data/
|
||||||
|
│ │ └── fetcher.ts # NEW - REST-based data fetching (replaces GraphQL)
|
||||||
|
│ └── comment-logic.ts # NEW - Forgejo URL formatting for comments
|
||||||
|
├── mcp/
|
||||||
|
│ ├── forgejo-actions-server.ts # NEW - Forgejo CI status MCP server
|
||||||
|
│ └── install-mcp-server.ts # MODIFIED - platform routing for MCP config
|
||||||
|
├── github/ # REUSED - existing code, no modifications
|
||||||
|
│ └── ...
|
||||||
|
├── entrypoints/
|
||||||
|
│ └── run.ts # MODIFIED - platform branch for token setup
|
||||||
|
├── modes/
|
||||||
|
│ ├── tag/index.ts # MODIFIED - swap data fetcher + comment logic
|
||||||
|
│ └── agent/index.ts # MODIFIED - swap token setup
|
||||||
|
action.yml # MODIFIED - platform input, conditional steps
|
||||||
|
```
|
||||||
|
|
||||||
|
**~8 new/modified files** instead of ~25. The existing `src/github/` code is re-used, not duplicated.
|
||||||
|
|
||||||
|
### Why This Approach
|
||||||
|
|
||||||
|
| Approach | Upstream Merge Effort | Maintenance | Chosen? |
|
||||||
|
|----------|----------------------|-------------|---------|
|
||||||
|
| **Lean adapter (reuse + minimal new files)** | Low (3-4 conflict-prone files) | Low | **Yes** |
|
||||||
|
| Full abstraction layer (20+ new files) | Near-zero conflicts but high maintenance syncing duplicated code | High | No |
|
||||||
|
| Modify GitHub files in-place | High conflict rate on every upstream pull | Low | No |
|
||||||
|
| Complete fork with divergence | No merges possible after a while | Very high | No |
|
||||||
|
|
||||||
|
### Honest Merge-Conflict Assessment
|
||||||
|
|
||||||
|
These files **will be modified** and are the merge-conflict surface when pulling upstream:
|
||||||
|
|
||||||
|
| File | What We Change | Conflict Risk |
|
||||||
|
|------|---------------|---------------|
|
||||||
|
| `src/entrypoints/run.ts` | Platform branch at top for token/client setup | **Medium** - upstream's most active file |
|
||||||
|
| `src/modes/tag/index.ts` | Swap `fetchGitHubData` call + comment logic based on platform | **Medium** |
|
||||||
|
| `src/modes/agent/index.ts` | Swap token setup based on platform | **Low** - simpler file |
|
||||||
|
| `src/mcp/install-mcp-server.ts` | Platform routing for MCP server selection | **Low-Medium** |
|
||||||
|
| `action.yml` | Add `platform` input, conditional Forgejo steps | **Low** - additive changes |
|
||||||
|
|
||||||
|
**Mitigation strategy**: Keep all platform changes at the **top** of functions (early return / branch pattern). Avoid restructuring existing code flow. When upstream modifies these files, conflicts will be localized to our small additions, not interleaved throughout.
|
||||||
|
|
||||||
|
## Technical Analysis
|
||||||
|
|
||||||
|
### Platform Detection Strategy
|
||||||
|
|
||||||
|
Use an **explicit `platform` input** (most reliable) with env-var auto-detection as fallback:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// src/platform/detector.ts
|
||||||
|
export function detectPlatform(): "github" | "forgejo" {
|
||||||
|
// 1. Explicit input (most reliable)
|
||||||
|
const platformInput = process.env.PLATFORM;
|
||||||
|
if (platformInput === "forgejo") return "forgejo";
|
||||||
|
if (platformInput === "github") return "github";
|
||||||
|
|
||||||
|
// 2. Auto-detect from environment
|
||||||
|
// FORGEJO is set by Forgejo runner v7.0+ (not in older runners)
|
||||||
|
if (process.env.FORGEJO === "true") return "forgejo";
|
||||||
|
|
||||||
|
// Check GITHUB_SERVER_URL — if not github.com, likely Forgejo/Gitea
|
||||||
|
const serverUrl = process.env.GITHUB_SERVER_URL || "";
|
||||||
|
if (serverUrl && !serverUrl.includes("github.com")) {
|
||||||
|
return "forgejo";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "github";
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
New `action.yml` input:
|
||||||
|
```yaml
|
||||||
|
platform:
|
||||||
|
description: "Platform to run on: 'auto' (default), 'github', or 'forgejo'"
|
||||||
|
required: false
|
||||||
|
default: "auto"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Key Technical Differences
|
||||||
|
|
||||||
|
1. **No GraphQL**: Forgejo is REST-only. The 3 GraphQL queries in `src/github/api/queries/github.ts` (PR_QUERY, ISSUE_QUERY, USER_QUERY) must be replaced with **5-8 separate paginated REST calls**:
|
||||||
|
- `GET /repos/{owner}/{repo}/pulls/{index}` - PR details
|
||||||
|
- `GET /repos/{owner}/{repo}/pulls/{index}/files` - changed files (paginated)
|
||||||
|
- `GET /repos/{owner}/{repo}/pulls/{index}/commits` - commits (paginated)
|
||||||
|
- `GET /repos/{owner}/{repo}/issues/{index}/comments` - issue-level comments (paginated)
|
||||||
|
- `GET /repos/{owner}/{repo}/pulls/{index}/reviews` - reviews (paginated)
|
||||||
|
- For each review: `GET /repos/{owner}/{repo}/pulls/{index}/reviews/{id}/comments`
|
||||||
|
- `GET /repos/{owner}/{repo}/issues/{index}` - issue details
|
||||||
|
|
||||||
|
Use `Promise.all()` to run independent calls in parallel and mitigate latency.
|
||||||
|
|
||||||
|
2. **API base URL**: Forgejo uses `/api/v1` (vs GitHub's `/api/v3`). Octokit REST methods work when `baseUrl` is set correctly since Forgejo mirrors GitHub's endpoint paths.
|
||||||
|
|
||||||
|
3. **Token handling**: No OIDC token exchange with Anthropic. The existing `OVERRIDE_GITHUB_TOKEN` code path in `token.ts` (line 130-135) already short-circuits the OIDC flow — for Forgejo we just need to use `GITHUB_TOKEN` or `FORGEJO_TOKEN` directly.
|
||||||
|
|
||||||
|
4. **Bot identity**: No GitHub App bot. The action runs as the token owner. Default `bot_id` (41898282) is meaningless on Forgejo — need sensible defaults.
|
||||||
|
|
||||||
|
5. **`pull_request_target` event**: May not exist in Forgejo. The existing `context.ts` maps it to `pull_request` (line 188), so it degrades gracefully.
|
||||||
|
|
||||||
|
6. **GitHub MCP Server**: The `ghcr.io/github/github-mcp-server` Docker image referenced in `install-mcp-server.ts` (line 214) won't work. Skip on Forgejo — it's only included when `hasGitHubMcpTools` is true.
|
||||||
|
|
||||||
|
7. **Forgejo Actions API gaps**: `actions.downloadJobLogForWorkflowRun()` used in the CI MCP server may not exist. Need to verify and implement alternative (direct API call or skip).
|
||||||
|
|
||||||
|
### `action.yml` Required Modifications
|
||||||
|
|
||||||
|
| Line(s) | Current | Problem | Fix |
|
||||||
|
|----------|---------|---------|-----|
|
||||||
|
| 103 | `default: "41898282"` (bot_id) | Meaningless on Forgejo | Make platform-aware; use token owner identity on Forgejo |
|
||||||
|
| 107 | `default: "claude[bot]"` (bot_name) | Doesn't exist on Forgejo | Same — detect from token or use configurable default |
|
||||||
|
| 163-166 | `uses: oven-sh/setup-bun@...` | References GitHub release; may fail on isolated Forgejo runners | Add conditional: if bun already available, skip; otherwise use direct curl install |
|
||||||
|
| 166 | `token: ${{ inputs.github_token \|\| github.token }}` | Used to fetch bun release from GitHub | On Forgejo, `github.token` is the Forgejo token — may not auth to GitHub; provide fallback |
|
||||||
|
| 285-294 | "Revoke app token" step | Calls `${GITHUB_API_URL}/installation/token` which doesn't exist on Forgejo | Make conditional: `if: platform != 'forgejo'` or detect and skip |
|
||||||
|
| N/A | Missing | No `platform` input | Add `platform` input (auto/github/forgejo) |
|
||||||
|
|
||||||
|
### `base-action/` Directory
|
||||||
|
|
||||||
|
`run.ts` imports directly from `base-action/src/`:
|
||||||
|
- `validate-env.ts` - checks env vars for Claude CLI (platform-agnostic)
|
||||||
|
- `setup-claude-code-settings.ts` - writes Claude settings (platform-agnostic)
|
||||||
|
- `install-plugins.ts` - installs Claude plugins (platform-agnostic)
|
||||||
|
- `prepare-prompt.ts` - prepares prompt file (platform-agnostic)
|
||||||
|
- `run-claude.ts` / `run-claude-sdk.ts` - runs Claude CLI (platform-agnostic)
|
||||||
|
|
||||||
|
**Conclusion**: `base-action/` is platform-independent. No modifications needed.
|
||||||
|
|
||||||
|
### MCP Server Naming Strategy
|
||||||
|
|
||||||
|
**Keep existing server names** (`github_comment`, `github_ci`, `github_file_ops`, `github_inline_comment`) even for Forgejo implementations. These are internal identifiers referenced in hardcoded tool name lists in `src/modes/tag/index.ts` (lines 127-152):
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
"mcp__github_comment__update_claude_comment",
|
||||||
|
"mcp__github_ci__get_ci_status",
|
||||||
|
"mcp__github_file_ops__commit_files",
|
||||||
|
```
|
||||||
|
|
||||||
|
Renaming would require modifying the tool name lists — more merge-conflict surface for zero user benefit. The MCP server config in `install-mcp-server.ts` will point these names to either GitHub or Forgejo server implementations based on platform.
|
||||||
|
|
||||||
|
## CI/CD Workflows
|
||||||
|
|
||||||
|
### Handling Upstream `.github/workflows/`
|
||||||
|
|
||||||
|
The upstream repo has 13 workflows in `.github/workflows/`. Strategy:
|
||||||
|
|
||||||
|
- **Do NOT delete or modify** `.github/workflows/` files (merge conflicts)
|
||||||
|
- Create `.forgejo/workflows/` with our custom workflows
|
||||||
|
- **Configure Forgejo runner** to only read from `.forgejo/workflows/` (runner-level `DEFAULT_ACTIONS_URL` and workflow directory settings)
|
||||||
|
- **Document this as a setup requirement** — if runners aren't configured, upstream workflows will attempt to run and fail loudly (missing secrets, OIDC endpoints, etc.)
|
||||||
|
|
||||||
|
### Custom Forgejo Workflows
|
||||||
|
|
||||||
|
#### 1. CI Test Workflow (`.forgejo/workflows/ci.yml`)
|
||||||
|
- Triggers on push to main and PRs
|
||||||
|
- Runs `bun install` and `bun test`
|
||||||
|
- Lints with biome (matching upstream's toolchain)
|
||||||
|
|
||||||
|
#### 2. Action Self-Test Workflow (`.forgejo/workflows/test-action.yml`)
|
||||||
|
- **Tests the action itself** on Forgejo
|
||||||
|
- Creates a test issue via API, triggers the action with a simple prompt
|
||||||
|
- Verifies: platform detection returns "forgejo", comment is created on the issue, action completes successfully
|
||||||
|
- Validates end-to-end: token handling, Octokit REST calls, comment posting
|
||||||
|
- Runs on a schedule (weekly) and on PRs that modify `src/`, `action.yml`, or `.forgejo/`
|
||||||
|
|
||||||
|
#### 3. Upstream Sync Check (`.forgejo/workflows/upstream-sync.yml`)
|
||||||
|
- Scheduled workflow (weekly) + manual trigger
|
||||||
|
- Fetches `upstream/main`, compares with our `main` using `git rev-list`
|
||||||
|
- Creates an issue if upstream has new commits we haven't merged
|
||||||
|
- Includes commit count and summary of changed files to help assess merge effort
|
||||||
|
|
||||||
|
## Milestones
|
||||||
|
|
||||||
|
### Phase 1 - Foundation (parallel, no dependencies)
|
||||||
|
|
||||||
|
- [ ] **M1: Platform detection + `action.yml` modifications** — Add `platform` input to `action.yml`. Create `src/platform/detector.ts` with explicit input + env-var auto-detection. Add conditional logic to skip "Revoke app token" step on Forgejo. Fix bun installation to handle Forgejo runners (direct curl fallback).
|
||||||
|
- Files: `action.yml` (MODIFIED), `src/platform/detector.ts` (NEW)
|
||||||
|
- Success: `detectPlatform()` returns "forgejo" in Forgejo runner, "github" in GitHub runner. `action.yml` doesn't error on Forgejo.
|
||||||
|
|
||||||
|
- [ ] **M2: Forgejo token handling** — Create `src/forgejo/token.ts` that returns `GITHUB_TOKEN` / `FORGEJO_TOKEN` directly (no OIDC, no Anthropic exchange). Wire into `run.ts` with an early platform branch before the existing `setupGitHubToken()` call.
|
||||||
|
- Files: `src/forgejo/token.ts` (NEW), `src/entrypoints/run.ts` (MODIFIED — surgical addition at top of `run()`)
|
||||||
|
- Depends on: M1
|
||||||
|
- Success: Token is available without OIDC on Forgejo. GitHub path unchanged.
|
||||||
|
|
||||||
|
- [ ] **M3: Forgejo CI workflows** — Create `.forgejo/workflows/` with CI, self-test, and upstream sync workflows. Document runner configuration requirements.
|
||||||
|
- Files: `.forgejo/workflows/ci.yml`, `.forgejo/workflows/test-action.yml`, `.forgejo/workflows/upstream-sync.yml` (all NEW)
|
||||||
|
- Success: CI runs tests on push. Upstream `.github/workflows/` don't interfere.
|
||||||
|
|
||||||
|
### Phase 2 - Core Data Fetching (the hard part)
|
||||||
|
|
||||||
|
- [ ] **M4a: Forgejo REST data fetching — PR/Issue basics** — Implement REST-based fetching for PR details, issue details, changed files, and commits. Produce output matching the `FetchDataResult` type that existing code expects.
|
||||||
|
- Files: `src/forgejo/data/fetcher.ts` (NEW)
|
||||||
|
- Depends on: M1, M2
|
||||||
|
- Success: Can fetch PR/issue title, body, author, state, files, commits from Forgejo REST API.
|
||||||
|
|
||||||
|
- [ ] **M4b: Forgejo REST data fetching — Comments, reviews, inline comments** — Extend the fetcher with paginated comment/review fetching, including nested inline review comments (requires per-review API calls). Implement TOCTOU filtering using the same `filterCommentsToTriggerTime` / `filterReviewsToTriggerTime` functions (reuse from `src/github/data/fetcher.ts` — these are pure logic). Use `Promise.all()` for parallel API calls.
|
||||||
|
- Files: `src/forgejo/data/fetcher.ts` (extend from M4a)
|
||||||
|
- Depends on: M4a
|
||||||
|
- Success: Full parity with GitHub GraphQL data fetch. All comments, reviews, and inline comments included with proper TOCTOU filtering.
|
||||||
|
|
||||||
|
- [ ] **M5: Forgejo comment URL formatting** — Create `src/forgejo/comment-logic.ts` with Forgejo-specific URL patterns for job links, branch links, and PR creation links (used in tracking comment updates).
|
||||||
|
- Files: `src/forgejo/comment-logic.ts` (NEW)
|
||||||
|
- Depends on: M1
|
||||||
|
- Success: Comment formatting produces correct Forgejo URLs.
|
||||||
|
|
||||||
|
### Phase 3 - Integration (wiring it together)
|
||||||
|
|
||||||
|
- [ ] **M6: MCP server platform routing** — Modify `install-mcp-server.ts` to select GitHub or Forgejo server implementations based on platform. Create `src/mcp/forgejo-actions-server.ts` for CI status (may be a subset of GitHub's if some Actions API endpoints don't exist in Forgejo). Keep MCP server names identical (`github_comment`, `github_ci`, etc.) to avoid touching tool name lists. For comment/file-ops/inline-comment servers, the existing GitHub implementations likely work via Octokit REST — verify and use directly.
|
||||||
|
- Files: `src/mcp/install-mcp-server.ts` (MODIFIED), `src/mcp/forgejo-actions-server.ts` (NEW, possibly)
|
||||||
|
- Depends on: M4b, M5
|
||||||
|
- Success: Claude can update comments, query CI status on Forgejo. MCP tools work end-to-end.
|
||||||
|
|
||||||
|
- [ ] **M7: Entry point + mode handler integration** — Wire platform detection into mode handlers. In `tag/index.ts`: swap `fetchGitHubData` for Forgejo fetcher + comment logic. In `agent/index.ts`: swap token setup. Keep changes surgical — platform branch at the top of functions, existing flow untouched.
|
||||||
|
- Files: `src/modes/tag/index.ts` (MODIFIED), `src/modes/agent/index.ts` (MODIFIED)
|
||||||
|
- Depends on: M4b, M5, M6
|
||||||
|
- Success: Action runs end-to-end on Forgejo for both tag and agent modes.
|
||||||
|
|
||||||
|
### Phase 4 - Validation & Polish
|
||||||
|
|
||||||
|
- [ ] **M8: End-to-end testing on Forgejo** — Test complete workflows: issue trigger (@claude mention), PR review, agent mode (workflow_dispatch with prompt), tag mode. Verify comment updates, branch creation, file commits, CI status queries.
|
||||||
|
- Depends on: M7
|
||||||
|
- Success: All supported trigger types work on Forgejo. Self-test workflow passes.
|
||||||
|
|
||||||
|
- [ ] **M9: Documentation & upstream merge validation** — Document Forgejo-specific setup (runner configuration, token setup, `platform: forgejo` input). Create `CLAUDE.md` for the project. Perform a fresh `git fetch upstream && git merge upstream/main` to verify conflicts are minimal and easily resolvable. Document the merge process.
|
||||||
|
- Depends on: M8
|
||||||
|
- Success: Clean or trivially-resolvable upstream merge. Clear setup docs.
|
||||||
|
|
||||||
|
### Milestone Dependency Graph
|
||||||
|
|
||||||
|
```
|
||||||
|
M1 ──> M2 ──> M4a ──> M4b ──┬──> M6 ──> M7 ──> M8 ──> M9
|
||||||
|
M1 ──> M5 ───────────────────┘
|
||||||
|
M3 (independent, anytime)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Parallel opportunities:**
|
||||||
|
- M3 is fully independent — can run anytime
|
||||||
|
- M5 and M2 can run in parallel (both only depend on M1)
|
||||||
|
- M4a can start as soon as M2 is done
|
||||||
|
- M6 and M7 are sequential (M7 depends on M6)
|
||||||
|
|
||||||
|
## Execution Plan
|
||||||
|
|
||||||
|
| Phase | Milestones | Files Touched | Parallel? |
|
||||||
|
|-------|-----------|---------------|-----------|
|
||||||
|
| 1 | M1, M2, M3 | `action.yml`, `src/platform/detector.ts`, `src/forgejo/token.ts`, `src/entrypoints/run.ts`, `.forgejo/workflows/*` | M1 first, then M2+M3 in parallel |
|
||||||
|
| 2 | M4a, M4b, M5 | `src/forgejo/data/fetcher.ts`, `src/forgejo/comment-logic.ts` | M5 parallel with M4a/M4b |
|
||||||
|
| 3 | M6, M7 | `src/mcp/install-mcp-server.ts`, `src/mcp/forgejo-actions-server.ts`, `src/modes/tag/index.ts`, `src/modes/agent/index.ts` | Sequential |
|
||||||
|
| 4 | M8, M9 | Tests, docs, `CLAUDE.md` | Sequential |
|
||||||
|
|
||||||
|
## Risk Assessment
|
||||||
|
|
||||||
|
| Risk | Likelihood | Impact | Mitigation |
|
||||||
|
|------|-----------|--------|------------|
|
||||||
|
| Upstream refactors `run.ts` or mode handlers | Medium | High | Keep entry point changes to <10 lines; use early-return pattern; platform branch at top of functions |
|
||||||
|
| Octokit REST methods behave differently on Forgejo | Low | Medium | Test each used method early in M4a; fall back to raw `fetch()` if needed |
|
||||||
|
| Forgejo webhook payloads differ from `@octokit/webhooks-types` | Medium | Medium | Test with real Forgejo webhooks; key check: `payload.issue.pull_request` field for `is_pull` detection |
|
||||||
|
| `pull_request_target` event missing in Forgejo | High | Low | Already handled — `context.ts:188` maps it to `pull_request` |
|
||||||
|
| Forgejo Actions API missing endpoints (downloadJobLog) | Medium | Medium | Degrade gracefully — CI MCP server may offer fewer tools on Forgejo |
|
||||||
|
| `oven-sh/setup-bun` action fails on isolated Forgejo runners | Medium | Medium | Add direct curl bun install as fallback in `action.yml` |
|
||||||
|
| Upstream `.github/workflows/` run and fail on Forgejo | Medium | Low | Document runner configuration; provide `.forgejo/workflows/` overrides |
|
||||||
|
| Upstream adds new features requiring new GraphQL fields | Certain | Low | New features won't have Forgejo support until we add REST equivalents to `forgejo/data/fetcher.ts` |
|
||||||
|
|
||||||
|
## Success Criteria
|
||||||
|
|
||||||
|
1. Action runs on Forgejo for issue, PR, and workflow_dispatch triggers
|
||||||
|
2. Claude can read issue/PR context, post comments, create branches, and commit files on Forgejo
|
||||||
|
3. `git fetch upstream && git merge upstream/main` produces conflicts only in the 3-4 files we modified, and those conflicts are resolvable in <15 minutes
|
||||||
|
4. Self-test workflow validates the action works on every PR
|
||||||
|
5. Upstream sync workflow alerts when new upstream changes are available
|
||||||
|
6. Total new files: ~6-8 (not 25+)
|
||||||
|
|
||||||
|
## Out of Scope (for now)
|
||||||
|
|
||||||
|
- GitHub Enterprise Server support
|
||||||
|
- Gitea support (similar to Forgejo but may diverge)
|
||||||
|
- `pull_request_target` event support
|
||||||
|
- SSH signing on Forgejo (can be added later)
|
||||||
|
- GitHub MCP Server equivalent for Forgejo (the `ghcr.io/github/github-mcp-server` image)
|
||||||
|
- Full Forgejo Actions API parity (downloadJobLog may be missing)
|
||||||
Reference in new issue
Block a user