init
This commit is contained in:
commit
932d4ad420
46 changed files with 5800 additions and 0 deletions
223
bin/bugzilla.ts
Normal file
223
bin/bugzilla.ts
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
#!/usr/bin/env node
|
||||
// Standalone Bugzilla CLI — interact with Bugzilla REST API directly
|
||||
import yargs from "yargs"
|
||||
import { hideBin } from "yargs/helpers"
|
||||
import { BugzillaClient } from "../lib/bugzilla/client"
|
||||
import { loadConfig } from "../lib/bugzilla/config"
|
||||
|
||||
function getClient() {
|
||||
const config = loadConfig()
|
||||
return new BugzillaClient(config)
|
||||
}
|
||||
|
||||
yargs(hideBin(process.argv))
|
||||
.scriptName("bugzilla")
|
||||
.usage("$0 <command> [options]")
|
||||
|
||||
.command(
|
||||
"get <id>",
|
||||
"Get a bug by ID",
|
||||
(y) => y.positional("id", { type: "number", demandOption: true }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const bug = await client.getBug(argv.id as number)
|
||||
console.log(JSON.stringify(bug, null, 2))
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"search",
|
||||
"Search for bugs",
|
||||
(y) =>
|
||||
y
|
||||
.option("product", { type: "string", alias: "p" })
|
||||
.option("component", { type: "string", alias: "c" })
|
||||
.option("status", { type: "string", alias: "s" })
|
||||
.option("summary", { type: "string" })
|
||||
.option("limit", { type: "number", default: 50 }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const config = loadConfig()
|
||||
const bugs = await client.searchBugs({
|
||||
product: argv.product ?? config.product,
|
||||
component: argv.component ?? config.component,
|
||||
status: argv.status,
|
||||
summary: argv.summary,
|
||||
limit: argv.limit,
|
||||
})
|
||||
for (const bug of bugs) {
|
||||
console.log(`#${bug.id} [${bug.severity}] (${bug.status}) ${bug.summary}`)
|
||||
}
|
||||
console.log(`\n${bugs.length} bug(s) found`)
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"create",
|
||||
"Create a new bug",
|
||||
(y) =>
|
||||
y
|
||||
.option("summary", { type: "string", alias: "s", demandOption: true })
|
||||
.option("description", { type: "string", alias: "d" })
|
||||
.option("priority", { type: "string", default: "Normal" })
|
||||
.option("severity", { type: "string", default: "normal" })
|
||||
.option("product", { type: "string", alias: "p" })
|
||||
.option("component", { type: "string", alias: "c" }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const config = loadConfig()
|
||||
const id = await client.createBug({
|
||||
product: argv.product ?? config.product,
|
||||
component: argv.component ?? config.component,
|
||||
summary: argv.summary,
|
||||
description: argv.description,
|
||||
priority: argv.priority,
|
||||
severity: argv.severity,
|
||||
})
|
||||
console.log(`Created bug #${id}`)
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"update <id>",
|
||||
"Update a bug",
|
||||
(y) =>
|
||||
y
|
||||
.positional("id", { type: "number", demandOption: true })
|
||||
.option("summary", { type: "string", alias: "s" })
|
||||
.option("status", { type: "string" })
|
||||
.option("resolution", { type: "string" })
|
||||
.option("priority", { type: "string" }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const payload: Record<string, any> = {}
|
||||
if (argv.summary) payload.summary = argv.summary
|
||||
if (argv.status) payload.status = argv.status
|
||||
if (argv.resolution) payload.resolution = argv.resolution
|
||||
if (argv.priority) payload.priority = argv.priority
|
||||
await client.updateBug(argv.id as number, payload)
|
||||
console.log(`Updated bug #${argv.id}`)
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"comments <id>",
|
||||
"List comments on a bug",
|
||||
(y) => y.positional("id", { type: "number", demandOption: true }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const comments = await client.getComments(argv.id as number)
|
||||
for (const c of comments) {
|
||||
console.log(`--- Comment #${c.count} by ${c.creator} (${c.time}) ---`)
|
||||
console.log(c.text)
|
||||
console.log()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"comment <id>",
|
||||
"Add a comment to a bug",
|
||||
(y) =>
|
||||
y
|
||||
.positional("id", { type: "number", demandOption: true })
|
||||
.option("text", { type: "string", alias: "t", demandOption: true }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
await client.addComment(argv.id as number, argv.text as string)
|
||||
console.log(`Comment added to bug #${argv.id}`)
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"products",
|
||||
"List accessible products",
|
||||
() => {},
|
||||
async () => {
|
||||
const client = getClient()
|
||||
const products = await client.getAccessibleProducts()
|
||||
for (const p of products) {
|
||||
const compCount = p.components?.length ?? 0
|
||||
console.log(`#${p.id} ${p.name} (${compCount} components) — ${p.description}`)
|
||||
}
|
||||
console.log(`\n${products.length} product(s)`)
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"product <name>",
|
||||
"Get product details and its components",
|
||||
(y) => y.positional("name", { type: "string", demandOption: true }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const product = await client.getProduct(argv.name as string)
|
||||
console.log(`Product: ${product.name} (#${product.id})`)
|
||||
console.log(`Description: ${product.description}`)
|
||||
console.log(`Active: ${product.is_active}`)
|
||||
console.log(`\nComponents:`)
|
||||
for (const c of product.components ?? []) {
|
||||
const status = c.is_active ? "active" : "inactive"
|
||||
console.log(` ${c.name} (${status}) — ${c.description}`)
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"create-product",
|
||||
"Create a new product",
|
||||
(y) =>
|
||||
y
|
||||
.option("name", { type: "string", alias: "n", demandOption: true })
|
||||
.option("description", { type: "string", alias: "d", demandOption: true })
|
||||
.option("version", { type: "string", default: "unspecified" }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const id = await client.createProduct({
|
||||
name: argv.name,
|
||||
description: argv.description,
|
||||
version: argv.version,
|
||||
})
|
||||
console.log(`Created product #${id}: ${argv.name}`)
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"components <product>",
|
||||
"List components for a product",
|
||||
(y) => y.positional("product", { type: "string", demandOption: true }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const components = await client.getComponents(argv.product as string)
|
||||
for (const c of components) {
|
||||
const status = c.is_active ? "active" : "inactive"
|
||||
console.log(`#${c.id} ${c.name} (${status}) — ${c.description}`)
|
||||
}
|
||||
console.log(`\n${components.length} component(s)`)
|
||||
}
|
||||
)
|
||||
|
||||
.command(
|
||||
"create-component",
|
||||
"Create a new component",
|
||||
(y) =>
|
||||
y
|
||||
.option("product", { type: "string", alias: "p", demandOption: true })
|
||||
.option("name", { type: "string", alias: "n", demandOption: true })
|
||||
.option("description", { type: "string", alias: "d", demandOption: true })
|
||||
.option("assignee", { type: "string", alias: "a", demandOption: true }),
|
||||
async (argv) => {
|
||||
const client = getClient()
|
||||
const id = await client.createComponent({
|
||||
product: argv.product,
|
||||
name: argv.name,
|
||||
description: argv.description,
|
||||
default_assignee: argv.assignee,
|
||||
})
|
||||
console.log(`Created component #${id}: ${argv.name} (in ${argv.product})`)
|
||||
}
|
||||
)
|
||||
|
||||
.demandCommand(1, "Please specify a command")
|
||||
.strict()
|
||||
.help()
|
||||
.parse()
|
||||
29
bin/main.ts
Normal file
29
bin/main.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#!/usr/bin/env node
|
||||
// mime-todo CLI — spec-compliant issue lifecycle management
|
||||
import { CLI } from "../lib/cli/CLI"
|
||||
import { CreateCommand } from "../lib/commands/CreateCommand"
|
||||
import { StartCommand } from "../lib/commands/StartCommand"
|
||||
import { DoneCommand } from "../lib/commands/DoneCommand"
|
||||
import { HoldCommand } from "../lib/commands/HoldCommand"
|
||||
import { CancelCommand } from "../lib/commands/CancelCommand"
|
||||
import { IssueListCommand } from "../lib/commands/IssueListCommand"
|
||||
import { IssueShowCommand } from "../lib/commands/IssueShowCommand"
|
||||
import { SprintsCommand } from "../lib/commands/SprintsCommand"
|
||||
import { IssuesInSprintCommand } from "../lib/commands/IssuesInSprintCommand"
|
||||
import { PushCommand } from "../lib/commands/PushCommand"
|
||||
import { InitCommand } from "../lib/commands/InitCommand"
|
||||
|
||||
const cli = new CLI({ prog: "todo", description: "MIME TODO issue tracker" })
|
||||
cli.bootstrap([
|
||||
InitCommand,
|
||||
CreateCommand,
|
||||
StartCommand,
|
||||
DoneCommand,
|
||||
HoldCommand,
|
||||
CancelCommand,
|
||||
IssueListCommand,
|
||||
IssueShowCommand,
|
||||
SprintsCommand,
|
||||
IssuesInSprintCommand,
|
||||
PushCommand,
|
||||
])
|
||||
Loading…
Add table
Add a link
Reference in a new issue