@spec-wave/cli 0.5.2 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -75,6 +75,7 @@ export async function generatePlan({ issueNumber }) {
|
|
|
75
75
|
git(`git config user.name "spec-wave[bot]"`);
|
|
76
76
|
git(`git add "${filePath}"`);
|
|
77
77
|
git(`git commit -m "docs: generate plan.md for ${slug} [spec-wave]"`);
|
|
78
|
+
git('git pull --rebase');
|
|
78
79
|
git('git push');
|
|
79
80
|
|
|
80
81
|
// Remove trigger label
|
|
@@ -84,7 +85,7 @@ export async function generatePlan({ issueNumber }) {
|
|
|
84
85
|
await commentOnIssue(
|
|
85
86
|
token, owner, repo, parseInt(issueNumber, 10),
|
|
86
87
|
`📋 **plan.md gerado automaticamente!**\n\n` +
|
|
87
|
-
`📄 Arquivo: [\`${filePath}\`](
|
|
88
|
+
`📄 Arquivo: [\`${filePath}\`](https://github.com/${owner}/${repo}/blob/main/${filePath})\n\n` +
|
|
88
89
|
`Revise o plano e, quando estiver pronto, valide a Feature: mova o card para **✅ Ready** ou use:\n` +
|
|
89
90
|
`\`\`\`\ngh issue edit ${issueNumber} --add-label "spec-wave:ready"\n\`\`\``
|
|
90
91
|
);
|
|
@@ -68,6 +68,7 @@ export async function generateSpec({ issueNumber }) {
|
|
|
68
68
|
git(`git config user.name "spec-wave[bot]"`);
|
|
69
69
|
git(`git add "${filePath}"`);
|
|
70
70
|
git(`git commit -m "docs: generate spec.md for ${slug} [spec-wave]"`);
|
|
71
|
+
git('git pull --rebase');
|
|
71
72
|
git('git push');
|
|
72
73
|
|
|
73
74
|
// Remove trigger label
|
|
@@ -77,7 +78,7 @@ export async function generateSpec({ issueNumber }) {
|
|
|
77
78
|
await commentOnIssue(
|
|
78
79
|
token, owner, repo, parseInt(issueNumber, 10),
|
|
79
80
|
`📋 **spec.md gerado automaticamente!**\n\n` +
|
|
80
|
-
`📄 Arquivo: [\`${filePath}\`](
|
|
81
|
+
`📄 Arquivo: [\`${filePath}\`](https://github.com/${owner}/${repo}/blob/main/${filePath})\n\n` +
|
|
81
82
|
`Revise a especificação e, quando estiver pronto, gere o plano técnico: mova o card para **📋 Plan** ou use:\n` +
|
|
82
83
|
`\`\`\`\ngh issue edit ${issueNumber} --add-label "spec-wave:plan"\n\`\`\``
|
|
83
84
|
);
|
|
@@ -2,54 +2,9 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { resolveToken } from '../api/auth.mjs';
|
|
4
4
|
import { getIssue, removeLabel, addLabel, commentOnIssue } from '../api/github-rest.mjs';
|
|
5
|
-
import { addProjectItem, setItemSingleSelect, getSingleSelectField } from '../api/github-graphql.mjs';
|
|
6
5
|
import { slugify } from '../lib/slugify.mjs';
|
|
7
6
|
import { CONFIG_FILE, REQUIRED_PLAN_SECTIONS, REQUIRED_SPEC_SECTIONS } from '../config.mjs';
|
|
8
7
|
|
|
9
|
-
// Opção nativa do campo Status do GitHub Projects (Todo / In Progress / Done).
|
|
10
|
-
const DONE_STAGE = 'Done';
|
|
11
|
-
|
|
12
|
-
// Resolve um campo SINGLE_SELECT pelo nome: usa o .spec-wave.json, cai para o
|
|
13
|
-
// formato legado (etapaFieldId/stageOptions) e, por fim, consulta o Project.
|
|
14
|
-
async function resolveField(token, project, name) {
|
|
15
|
-
if (project.fields && project.fields[name]) return project.fields[name];
|
|
16
|
-
if (name === 'Etapa' && project.etapaFieldId) {
|
|
17
|
-
return { id: project.etapaFieldId, options: project.stageOptions || {} };
|
|
18
|
-
}
|
|
19
|
-
return await getSingleSelectField(token, project.id, name);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// Move o item da issue para a Etapa "🎉 Done" no board. Best-effort: loga e
|
|
23
|
-
// segue se o .spec-wave.json não tiver o Project ou o campo não for encontrado.
|
|
24
|
-
async function moveToDone(token, issue) {
|
|
25
|
-
const configPath = path.join(process.cwd(), CONFIG_FILE);
|
|
26
|
-
if (!existsSync(configPath)) {
|
|
27
|
-
console.warn(`${CONFIG_FILE} não encontrado — status do board não atualizado.`);
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
let project;
|
|
31
|
-
try {
|
|
32
|
-
project = (JSON.parse(readFileSync(configPath, 'utf-8')).project) || {};
|
|
33
|
-
} catch (err) {
|
|
34
|
-
console.warn(`${CONFIG_FILE} corrompido (${err.message}) — status do board não atualizado.`);
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
if (!project.id) {
|
|
38
|
-
console.warn(`Project não configurado no ${CONFIG_FILE} — status do board não atualizado.`);
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
// addProjectItem é idempotente: retorna o item existente se a issue já está no board.
|
|
42
|
-
const itemId = await addProjectItem(token, project.id, issue.node_id);
|
|
43
|
-
const field = await resolveField(token, project, 'Status');
|
|
44
|
-
const optionId = field?.options?.[DONE_STAGE];
|
|
45
|
-
if (field?.id && optionId) {
|
|
46
|
-
await setItemSingleSelect(token, project.id, itemId, field.id, optionId);
|
|
47
|
-
console.log(`Status do board atualizado para "${DONE_STAGE}".`);
|
|
48
|
-
} else {
|
|
49
|
-
console.warn(`Etapa "${DONE_STAGE}" não encontrada no Project — status do board não atualizado.`);
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
8
|
export async function validate({ issueNumber }) {
|
|
54
9
|
const token = await resolveToken();
|
|
55
10
|
const [envOwner, envRepo] = (process.env.GITHUB_REPOSITORY || '').split('/');
|
|
@@ -114,23 +69,14 @@ export async function validate({ issueNumber }) {
|
|
|
114
69
|
process.exit(1);
|
|
115
70
|
}
|
|
116
71
|
|
|
117
|
-
// Validação passou: adiciona label plan-approved
|
|
72
|
+
// Validação passou: adiciona label plan-approved.
|
|
118
73
|
await addLabel(token, owner, repo, parseInt(issueNumber, 10), 'spec-wave:plan-approved');
|
|
119
74
|
|
|
120
|
-
let doneOk = false;
|
|
121
|
-
try {
|
|
122
|
-
await moveToDone(token, issue);
|
|
123
|
-
doneOk = !!DONE_STAGE;
|
|
124
|
-
} catch (err) {
|
|
125
|
-
console.warn(`Falha ao atualizar status do board: ${err.message}`);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
75
|
await commentOnIssue(
|
|
129
76
|
token, owner, repo, parseInt(issueNumber, 10),
|
|
130
77
|
`✅ **Validação concluída com sucesso!**\n\n` +
|
|
131
78
|
`- [\`${specPath}\`](${specPath}) ✓\n` +
|
|
132
79
|
`- [\`${planPath}\`](${planPath}) ✓\n\n` +
|
|
133
|
-
(doneOk ? `Status movido para **${DONE_STAGE}**. ` : '') +
|
|
134
80
|
`A Feature está pronta para decomposição. Use:\n` +
|
|
135
81
|
`\`\`\`\ngh issue edit ${issueNumber} --add-label "spec-wave:decompose"\n\`\`\``
|
|
136
82
|
);
|