| #!/usr/bin/env tsx |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| import * as url from "url"; |
| import yargs from "yargs"; |
| import { hideBin } from "yargs/helpers"; |
| import { GitHubRestApi, type GitHubApi } from "./api.js"; |
| import { computeIssuePatch } from "./rules.js"; |
| import { applyPatch, printPlan, resolveToken } from "./sync-issue.js"; |
| import type { Patch } from "./types.js"; |
|
|
| const BOUNTY_LABEL_PREFIX = "bounty"; |
|
|
| export interface PlanAllIssuesInput { |
| api: GitHubApi; |
| } |
|
|
| |
| |
| export async function planAllIssues({ api }: PlanAllIssuesInput): Promise<Patch> { |
| const issues = await api.listIssuesWithLabelPrefix(BOUNTY_LABEL_PREFIX); |
| const ops = issues.flatMap((issue) => { |
| const currentLabels = new Set(issue.labels.map((l) => l.name)); |
| return computeIssuePatch({ issue, currentLabels }).ops; |
| }); |
| return { ops }; |
| } |
|
|
| |
| |
| export async function syncAllIssues({ api }: PlanAllIssuesInput): Promise<Patch> { |
| const patch = await planAllIssues({ api }); |
| await applyPatch(patch, api); |
| return patch; |
| } |
|
|
| |
| |
| |
|
|
| if (process.argv[1] === url.fileURLToPath(import.meta.url)) { |
| const argv = await yargs(hideBin(process.argv)) |
| .option("repo", { type: "string", demandOption: true, description: "owner/repo" }) |
| .option("token", { |
| type: "string", |
| description: "GitHub token (falls back to GITHUB_TOKEN env var or `gh auth token`)", |
| }) |
| .option("execute", { |
| type: "boolean", |
| default: false, |
| description: "Apply the patch. Without this flag only the plan is printed.", |
| }) |
| .strict() |
| .parseAsync(); |
|
|
| const [owner, repo] = argv.repo.split("/") as [string, string]; |
| const token = resolveToken(argv.token); |
| const api = new GitHubRestApi(owner, repo, token); |
|
|
| if (argv.execute) { |
| const patch = await syncAllIssues({ api }); |
| if (patch.ops.length === 0) { |
| console.log("All issues already in sync — no changes needed."); |
| } |
| } else { |
| const patch = await planAllIssues({ api }); |
| printPlan(patch, "All bounty issues"); |
| } |
| } |
|
|