import type { Argv, ArgumentsCamelCase } from "yargs" import { CLICommand } from "../cli/CLICommand" import { parseTodoFile, writeTodoFile } from "../file" import { getCurrentBranch, commitFileWithBody } from "../git" import { validateStatusTransition } from "../issue" export class CancelCommand extends CLICommand { readonly name = "cancel " readonly help = "Cancel an issue" readonly description = "Set issue to cancelled (must be on issue branch or develop)" addArguments(yargs: Argv): Argv { return yargs .positional("id", { type: "number", demandOption: true }) .option("reason", { type: "string", demandOption: true, description: "Reason for cancellation", }) } async execute(args: ArgumentsCamelCase): Promise { const todo = await parseTodoFile() const issue = todo.issues.find(i => i.id === args.id) if (!issue) { console.error(`Issue #${args.id} not found`) return 1 } // Cancel allowed from develop (if open) or issue branch (if in-progress/hold) const issueBranch = `${issue.type}/${issue.id}` const branch = getCurrentBranch() if (branch !== "develop" && branch !== issueBranch) { console.error(`Must be on develop or ${issueBranch} to cancel (currently on ${branch})`) return 1 } const err = validateStatusTransition(issue.status, "cancelled") if (err) { console.error(err) return 1 } issue.status = "cancelled" writeTodoFile(todo) commitFileWithBody( "TODO", `todo(${issue.id}): cancelled`, args.reason as string ) console.log(`Issue #${issue.id} is now cancelled`) return 0 } }