Add labels to issue creation
Some checks failed
ci / test (pull_request) Has been cancelled

This commit is contained in:
codex-bot-andresmgsl 2026-08-18 00:45:00 +00:00
parent ee0cb85c7b
commit 7b372eb2dc
2 changed files with 73 additions and 0 deletions

View file

@ -686,6 +686,7 @@ issue
.option('-b, --body <body>', 'issue body (markdown)')
.option('--body-file <path>', 'read the issue body from a file')
.option('--assignee <username...>', 'assign the issue to one or more users')
.option('--label <name...>', 'apply one or more labels by name')
.action(async (options) => {
try {
const config = loadConfig();
@ -697,6 +698,9 @@ issue
if (options.assignee && options.assignee.length) {
payload.assignees = options.assignee;
}
if (options.label && options.label.length) {
payload.labels = await resolveLabelIds(client, options.owner, options.repo, options.label);
}
const result = await client.createIssue(options.owner, options.repo, payload);
console.log(`Issue created: #${result.number} ${result.title}`);
console.log(`URL: ${result.html_url}`);

View file

@ -77,6 +77,75 @@ test('issue create --body-file reports unreadable files cleanly', () => {
}
});
test('issue create resolves repeated label names into the initial create payload', async () => {
const cfg = path.join(os.tmpdir(), `stoke-cfg-${process.pid}-issue-labels.json`);
const requests = [];
const server = http.createServer((req, res) => {
let data = '';
req.on('data', (chunk) => { data += chunk; });
req.on('end', () => {
requests.push({ method: req.method, url: req.url, body: data });
res.writeHead(req.method === 'POST' ? 201 : 200, { 'Content-Type': 'application/json' });
if (req.method === 'GET') {
res.end(JSON.stringify([
{ id: 107, name: 'ready', color: '0e8a16' },
{ id: 100, name: 'enhancement', color: '84b6eb' },
]));
} else {
res.end(JSON.stringify({ number: 27, title: 'Probe', html_url: 'https://forge.test/o/r/issues/27' }));
}
});
});
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
const { port } = server.address();
fs.writeFileSync(cfg, JSON.stringify({ url: `http://127.0.0.1:${port}`, token: 'tok' }));
try {
const res = await spawnAsync(
['issue', 'create', '-o', 'o', '-r', 'r', '-t', 'Probe', '--label', 'ready', '--label', 'enhancement'],
{ STOKE_CONFIG_FILE: cfg },
);
assert.equal(res.status, 0, res.stderr);
assert.deepEqual(requests.map(({ method }) => method), ['GET', 'POST']);
assert.match(requests[0].url, /^\/api\/v1\/repos\/o\/r\/labels\?/);
assert.equal(requests[1].url, '/api/v1/repos/o/r/issues');
assert.deepEqual(JSON.parse(requests[1].body), {
title: 'Probe',
body: '',
labels: [107, 100],
});
} finally {
await new Promise((resolve) => server.close(resolve));
fs.unlinkSync(cfg);
}
});
test('issue create rejects an unknown label before creating the issue', async () => {
const cfg = path.join(os.tmpdir(), `stoke-cfg-${process.pid}-unknown-issue-label.json`);
let createRequests = 0;
const server = http.createServer((req, res) => {
if (req.method === 'POST') createRequests += 1;
res.writeHead(200, { 'Content-Type': 'application/json' });
res.end(JSON.stringify([{ id: 107, name: 'ready', color: '0e8a16' }]));
});
await new Promise((resolve) => server.listen(0, '127.0.0.1', resolve));
const { port } = server.address();
fs.writeFileSync(cfg, JSON.stringify({ url: `http://127.0.0.1:${port}`, token: 'tok' }));
try {
const res = await spawnAsync(
['issue', 'create', '-o', 'o', '-r', 'r', '-t', 'Probe', '--label', 'nonexistent'],
{ STOKE_CONFIG_FILE: cfg },
);
assert.equal(res.status, 1);
assert.match(res.stderr, /Label not found in o\/r: nonexistent/);
assert.equal(createRequests, 0);
} finally {
await new Promise((resolve) => server.close(resolve));
fs.unlinkSync(cfg);
}
});
test('pr show validates --number before any network call', () => {
const cfg = path.join(os.tmpdir(), `stoke-cfg-${process.pid}.json`);
fs.writeFileSync(cfg, JSON.stringify({ url: 'https://forge.test', token: 'tok' }));