chore(bounty): overhaul bounty automation with TypeScript pipeline and CI job#2636
chore(bounty): overhaul bounty automation with TypeScript pipeline and CI job#2636tusharmath merged 15 commits intomainfrom
Conversation
.github/workflows/bounty.yml
Outdated
| propagate-bounty-label: | ||
| name: Propagate bounty label to PR | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| issues: write | ||
| pull-requests: write | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Copy bounty label from linked issue to PR | ||
| run: npx tsx .github/scripts/bounty/propagate-label.ts --pr ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --token ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
Critical: Job will fail on non-pull_request events
This job is missing an if condition to prevent it from running on issues and pull_request_target events. When an issue is assigned/unassigned, this job will execute and ${{ github.event.pull_request.number }} will be null/undefined, causing the script to fail.
Fix:
propagate-bounty-label:
name: Propagate bounty label to PR
if: github.event_name == 'pull_request'
runs-on: ubuntu-latest| propagate-bounty-label: | |
| name: Propagate bounty label to PR | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Copy bounty label from linked issue to PR | |
| run: npx tsx .github/scripts/bounty/propagate-label.ts --pr ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --token ${{ secrets.GITHUB_TOKEN }} | |
| propagate-bounty-label: | |
| name: Propagate bounty label to PR | |
| if: github.event_name == 'pull_request' | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| pull-requests: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Copy bounty label from linked issue to PR | |
| run: npx tsx .github/scripts/bounty/propagate-label.ts --pr ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --token ${{ secrets.GITHUB_TOKEN }} | |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
.github/scripts/bounty/github-api.ts
Outdated
| const req = https.request(options, (res) => { | ||
| let data = ""; | ||
| res.on("data", (chunk: string) => (data += chunk)); | ||
| res.on("end", () => { | ||
| try { | ||
| resolve(data ? (JSON.parse(data) as T) : ({} as T)); | ||
| } catch { | ||
| resolve({} as T); | ||
| } | ||
| }); |
There was a problem hiding this comment.
Critical: HTTP errors are silently ignored
The request method doesn't check the HTTP status code. API errors (4xx, 5xx) will be treated as successful responses, causing scripts to continue execution with invalid data. This will lead to silent failures in production.
Fix:
const req = https.request(options, (res) => {
let data = "";
res.on("data", (chunk: string) => (data += chunk));
res.on("end", () => {
if (res.statusCode && res.statusCode >= 400) {
reject(new Error(`HTTP ${res.statusCode}: ${data}`));
return;
}
try {
resolve(data ? (JSON.parse(data) as T) : ({} as T));
} catch (e) {
reject(e);
}
});
});| const req = https.request(options, (res) => { | |
| let data = ""; | |
| res.on("data", (chunk: string) => (data += chunk)); | |
| res.on("end", () => { | |
| try { | |
| resolve(data ? (JSON.parse(data) as T) : ({} as T)); | |
| } catch { | |
| resolve({} as T); | |
| } | |
| }); | |
| const req = https.request(options, (res) => { | |
| let data = ""; | |
| res.on("data", (chunk: string) => (data += chunk)); | |
| res.on("end", () => { | |
| if (res.statusCode && res.statusCode >= 400) { | |
| reject(new Error(`HTTP ${res.statusCode}: ${data}`)); | |
| return; | |
| } | |
| try { | |
| resolve(data ? (JSON.parse(data) as T) : ({} as T)); | |
| } catch { | |
| reject(new Error("Failed to parse JSON response")); | |
| } | |
| }); | |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
.github/workflows/bounty.yml
Outdated
| sync-issue: | ||
| name: Sync issue bounty labels | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| issues: write | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
| - name: Sync bounty labels | ||
| run: npx tsx .github/scripts/bounty/v2/sync-issue.ts --issue ${{ github.event.issue.number }} --repo ${{ github.repository }} --token ${{ secrets.GITHUB_TOKEN }} |
There was a problem hiding this comment.
The sync-issue job will fail when triggered by pull_request events because github.event.issue.number is undefined for those events. The job needs a conditional to only run on issues events:
if: github.event_name == 'issues'Without this, the workflow will crash with "cannot read property 'number' of undefined" whenever a PR is opened/edited/reopened.
| sync-issue: | |
| name: Sync issue bounty labels | |
| runs-on: ubuntu-latest | |
| permissions: | |
| issues: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Sync bounty labels | |
| run: npx tsx .github/scripts/bounty/v2/sync-issue.ts --issue ${{ github.event.issue.number }} --repo ${{ github.repository }} --token ${{ secrets.GITHUB_TOKEN }} | |
| sync-issue: | |
| name: Sync issue bounty labels | |
| runs-on: ubuntu-latest | |
| if: github.event_name == 'issues' | |
| permissions: | |
| issues: write | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Sync bounty labels | |
| run: npx tsx .github/scripts/bounty/v2/sync-issue.ts --issue ${{ github.event.issue.number }} --repo ${{ github.repository }} --token ${{ secrets.GITHUB_TOKEN }} |
Spotted by Graphite
Is this helpful? React 👍 or 👎 to let us know.
Summary
Overhaul the bounty label automation system with a new TypeScript pipeline, Rust-based CI job generation, and consolidated label definitions.
Context
The previous bounty automation was a collection of loosely coupled shell/script files. This PR replaces it with a clean
parse/plan/executepipeline written in TypeScript, adds a Rustforge_cijob to generate the bounty workflow, consolidates label naming to the canonical emoji format, and removes thetimeoutfield from MCP server configs that was added prematurely.Changes
sync-issue.ts,sync-pr.ts,rules.ts,types.ts,api.ts) with full test coverage — replaces legacy shell scriptsbounty_job.rs,bounty.rs) added toforge_cifor generating the.github/workflows/bounty.ymlfile programmatically.github/labels.json— canonical names now use the emoji format (bounty: 💰 $N); old plain-text names moved to aliases; genericbountylabel removedUse Cases,Implementation Ideas, andContributionfields, plus a stricter pre-submission checklisttimeoutfield removed fromMcpHttpServerandMcpStdioServer— related tests and dead code cleaned up.gitignorefixed — removed the broadjobs/rule that was incorrectly shadowingcrates/forge_ci/src/jobs/package.jsongainstest:bounty,bounty:sync-issue, andbounty:sync-prnpm scriptsTesting