@sanity/cli 8.22.1 → 8.23.0
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/dist/actions/context/watchJob.js +9 -3
- package/dist/actions/context/watchJob.js.map +1 -1
- package/dist/actions/deploy/blueprintManaged.js +59 -0
- package/dist/actions/deploy/blueprintManaged.js.map +1 -0
- package/dist/actions/deploy/deployApp.js +117 -1
- package/dist/actions/deploy/deployApp.js.map +1 -1
- package/dist/actions/deploy/deployRunner.js.map +1 -1
- package/dist/actions/deploy/deployStudio.js +6 -31
- package/dist/actions/deploy/deployStudio.js.map +1 -1
- package/dist/actions/exec/runScript.worker.js +6 -2
- package/dist/actions/exec/runScript.worker.js.map +1 -1
- package/dist/actions/init/bootstrapLocalTemplate.js +35 -11
- package/dist/actions/init/bootstrapLocalTemplate.js.map +1 -1
- package/dist/actions/init/createMediaLibraryCliConfig.js +12 -0
- package/dist/actions/init/createMediaLibraryCliConfig.js.map +1 -0
- package/dist/actions/init/determineMediaLibraryTemplate.js +14 -0
- package/dist/actions/init/determineMediaLibraryTemplate.js.map +1 -0
- package/dist/actions/init/initAction.js +35 -6
- package/dist/actions/init/initAction.js.map +1 -1
- package/dist/actions/init/initApp.js +81 -6
- package/dist/actions/init/initApp.js.map +1 -1
- package/dist/actions/init/offerAspectPull.js +81 -0
- package/dist/actions/init/offerAspectPull.js.map +1 -0
- package/dist/actions/init/project/getProjectDetails.js +25 -2
- package/dist/actions/init/project/getProjectDetails.js.map +1 -1
- package/dist/actions/init/templates/index.js +3 -0
- package/dist/actions/init/templates/index.js.map +1 -1
- package/dist/actions/init/templates/mediaLibraryConfig.js +51 -0
- package/dist/actions/init/templates/mediaLibraryConfig.js.map +1 -0
- package/dist/actions/media/aspectName.js +8 -0
- package/dist/actions/media/aspectName.js.map +1 -0
- package/dist/actions/media/aspectSync/contract.js +163 -0
- package/dist/actions/media/aspectSync/contract.js.map +1 -0
- package/dist/actions/media/aspectSync/syncAspects.js +115 -0
- package/dist/actions/media/aspectSync/syncAspects.js.map +1 -0
- package/dist/actions/media/cliConfigFields.js +192 -0
- package/dist/actions/media/cliConfigFields.js.map +1 -0
- package/dist/actions/media/pullAspects.js +225 -0
- package/dist/actions/media/pullAspects.js.map +1 -0
- package/dist/actions/media/resolveMediaLibraryId.js +83 -0
- package/dist/actions/media/resolveMediaLibraryId.js.map +1 -0
- package/dist/commands/context/build.js +2 -2
- package/dist/commands/context/build.js.map +1 -1
- package/dist/commands/context/entries/get.js +83 -0
- package/dist/commands/context/entries/get.js.map +1 -0
- package/dist/commands/context/entries/list.js +82 -0
- package/dist/commands/context/entries/list.js.map +1 -0
- package/dist/commands/context/entries/rebuild.js +95 -0
- package/dist/commands/context/entries/rebuild.js.map +1 -0
- package/dist/commands/context/issues/apply.js +86 -0
- package/dist/commands/context/issues/apply.js.map +1 -0
- package/dist/commands/context/issues/dismiss.js +52 -0
- package/dist/commands/context/issues/dismiss.js.map +1 -0
- package/dist/commands/context/issues/get.js +105 -0
- package/dist/commands/context/issues/get.js.map +1 -0
- package/dist/commands/context/issues/list.js +128 -0
- package/dist/commands/context/issues/list.js.map +1 -0
- package/dist/commands/context/issues/reopen.js +53 -0
- package/dist/commands/context/issues/reopen.js.map +1 -0
- package/dist/commands/context/issues/resolve.js +137 -0
- package/dist/commands/context/issues/resolve.js.map +1 -0
- package/dist/commands/context/jobs/get.js +2 -2
- package/dist/commands/context/jobs/get.js.map +1 -1
- package/dist/commands/context/query.js +92 -0
- package/dist/commands/context/query.js.map +1 -0
- package/dist/commands/deploy.js +13 -0
- package/dist/commands/deploy.js.map +1 -1
- package/dist/commands/media/prune-aspect-data.js +170 -0
- package/dist/commands/media/prune-aspect-data.js.map +1 -0
- package/dist/commands/media/pull-aspects.js +309 -0
- package/dist/commands/media/pull-aspects.js.map +1 -0
- package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js +17 -0
- package/dist/exports/invokeSanityCli/commandPolicies/mcpPolicy.js.map +1 -1
- package/dist/services/context.js +96 -3
- package/dist/services/context.js.map +1 -1
- package/dist/services/mediaLibraries.js +175 -8
- package/dist/services/mediaLibraries.js.map +1 -1
- package/oclif.manifest.json +2930 -2241
- package/package.json +6 -5
- package/templates/media-library-config/README.md +52 -0
- package/templates/media-library-config/eslint.config.txt +52 -0
- package/templates/media-library-config/src/fields/caption.tsx +29 -0
- package/templates/media-library-config/src/fields/notes.tsx +54 -0
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
|
+
import { spinner } from '@sanity/cli-core/ux';
|
|
5
|
+
import { isHttpError } from '@sanity/client';
|
|
6
|
+
import { formatJobFailure, watchJob } from '../../../actions/context/watchJob.js';
|
|
7
|
+
import { formatKeyValue } from '../../../actions/debug/output.js';
|
|
8
|
+
import { rebuildEntry } from '../../../services/context.js';
|
|
9
|
+
const rebuildEntryDebug = subdebug('context:entries:rebuild');
|
|
10
|
+
export class RebuildEntryCommand extends SanityCommand {
|
|
11
|
+
static args = {
|
|
12
|
+
knowledgeBaseId: Args.string({
|
|
13
|
+
description: 'Knowledge base ID',
|
|
14
|
+
required: true
|
|
15
|
+
}),
|
|
16
|
+
path: Args.string({
|
|
17
|
+
description: 'Entry path, as listed by `sanity context entries list`',
|
|
18
|
+
required: true
|
|
19
|
+
})
|
|
20
|
+
};
|
|
21
|
+
static description = 'Rebuild one entry from its sources';
|
|
22
|
+
static examples = [
|
|
23
|
+
{
|
|
24
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds',
|
|
25
|
+
description: 'Start a rebuild and return the job ID'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds --watch',
|
|
29
|
+
description: 'Rebuild an entry and wait for it to finish (non-zero exit on failure)'
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
static flags = {
|
|
33
|
+
watch: Flags.boolean({
|
|
34
|
+
default: false,
|
|
35
|
+
description: 'Wait for the rebuild to finish, exiting non-zero if it fails'
|
|
36
|
+
})
|
|
37
|
+
};
|
|
38
|
+
async run() {
|
|
39
|
+
const { knowledgeBaseId, path } = this.args;
|
|
40
|
+
const { watch } = this.flags;
|
|
41
|
+
let accepted;
|
|
42
|
+
const spin = spinner('Starting rebuild').start();
|
|
43
|
+
try {
|
|
44
|
+
accepted = await rebuildEntry(knowledgeBaseId, path);
|
|
45
|
+
spin.succeed('Rebuild started');
|
|
46
|
+
} catch (error) {
|
|
47
|
+
spin.fail();
|
|
48
|
+
rebuildEntryDebug('Error starting rebuild', error);
|
|
49
|
+
if (isHttpError(error) && error.statusCode === 404) {
|
|
50
|
+
this.error(`Entry "${path}" not found on knowledge base "${knowledgeBaseId}"`, {
|
|
51
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
this.error(`Failed to start rebuild: ${getErrorMessage(error)}`, {
|
|
55
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
const { affectedEntries, jobId } = accepted;
|
|
59
|
+
const padTo = 19 // "Shares sources with" is the longest key
|
|
60
|
+
;
|
|
61
|
+
this.log(formatKeyValue('Job ID', jobId, {
|
|
62
|
+
padTo
|
|
63
|
+
}));
|
|
64
|
+
// Other entries citing the same sources can change when they are next rebuilt
|
|
65
|
+
if (affectedEntries.length > 0) {
|
|
66
|
+
const paths = affectedEntries.map((entry)=>entry.path).join(', ');
|
|
67
|
+
this.log(formatKeyValue('Shares sources with', paths, {
|
|
68
|
+
padTo
|
|
69
|
+
}));
|
|
70
|
+
}
|
|
71
|
+
this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`);
|
|
72
|
+
if (!watch) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
let job;
|
|
76
|
+
try {
|
|
77
|
+
job = await watchJob(knowledgeBaseId, jobId, {
|
|
78
|
+
label: 'Rebuilding entry',
|
|
79
|
+
successText: 'Entry rebuilt'
|
|
80
|
+
});
|
|
81
|
+
} catch (error) {
|
|
82
|
+
rebuildEntryDebug('Error watching rebuild job', error);
|
|
83
|
+
this.error(`Failed to watch rebuild job: ${getErrorMessage(error)}`, {
|
|
84
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
if (job.status !== 'succeeded') {
|
|
88
|
+
this.error(formatJobFailure('Rebuild', job), {
|
|
89
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
//# sourceMappingURL=rebuild.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/context/entries/rebuild.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {isHttpError} from '@sanity/client'\n\nimport {formatJobFailure, watchJob} from '../../../actions/context/watchJob.js'\nimport {formatKeyValue} from '../../../actions/debug/output.js'\nimport {rebuildEntry} from '../../../services/context.js'\n\nconst rebuildEntryDebug = subdebug('context:entries:rebuild')\n\nexport class RebuildEntryCommand extends SanityCommand<typeof RebuildEntryCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n path: Args.string({\n description: 'Entry path, as listed by `sanity context entries list`',\n required: true,\n }),\n }\n\n static override description = 'Rebuild one entry from its sources'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds',\n description: 'Start a rebuild and return the job ID',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 billing/refunds --watch',\n description: 'Rebuild an entry and wait for it to finish (non-zero exit on failure)',\n },\n ]\n\n static override flags = {\n watch: Flags.boolean({\n default: false,\n description: 'Wait for the rebuild to finish, exiting non-zero if it fails',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId, path} = this.args\n const {watch} = this.flags\n\n let accepted\n const spin = spinner('Starting rebuild').start()\n try {\n accepted = await rebuildEntry(knowledgeBaseId, path)\n spin.succeed('Rebuild started')\n } catch (error) {\n spin.fail()\n rebuildEntryDebug('Error starting rebuild', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Entry \"${path}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to start rebuild: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n const {affectedEntries, jobId} = accepted\n const padTo = 19 // \"Shares sources with\" is the longest key\n this.log(formatKeyValue('Job ID', jobId, {padTo}))\n // Other entries citing the same sources can change when they are next rebuilt\n if (affectedEntries.length > 0) {\n const paths = affectedEntries.map((entry) => entry.path).join(', ')\n this.log(formatKeyValue('Shares sources with', paths, {padTo}))\n }\n this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`)\n\n if (!watch) {\n return\n }\n\n let job\n try {\n job = await watchJob(knowledgeBaseId, jobId, {\n label: 'Rebuilding entry',\n successText: 'Entry rebuilt',\n })\n } catch (error) {\n rebuildEntryDebug('Error watching rebuild job', error)\n this.error(`Failed to watch rebuild job: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (job.status !== 'succeeded') {\n this.error(formatJobFailure('Rebuild', job), {exit: exitCodes.RUNTIME_ERROR})\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","spinner","isHttpError","formatJobFailure","watchJob","formatKeyValue","rebuildEntry","rebuildEntryDebug","RebuildEntryCommand","args","knowledgeBaseId","string","description","required","path","examples","command","flags","watch","boolean","default","run","accepted","spin","start","succeed","error","fail","statusCode","exit","RUNTIME_ERROR","affectedEntries","jobId","padTo","log","length","paths","map","entry","join","job","label","successText","status"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,gBAAgB,EAAEC,QAAQ,QAAO,uCAAsC;AAC/E,SAAQC,cAAc,QAAO,mCAAkC;AAC/D,SAAQC,YAAY,QAAO,+BAA8B;AAEzD,MAAMC,oBAAoBR,SAAS;AAEnC,OAAO,MAAMS,4BAA4BV;IACvC,OAAgBW,OAAO;QACrBC,iBAAiBf,KAAKgB,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACAC,MAAMnB,KAAKgB,MAAM,CAAC;YAChBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,qCAAoC;IAElE,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;QACA;YACEI,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,OAAgBK,QAAQ;QACtBC,OAAOtB,MAAMuB,OAAO,CAAC;YACnBC,SAAS;YACTR,aAAa;QACf;IACF,EAAqB;IAErB,MAAaS,MAAqB;QAChC,MAAM,EAACX,eAAe,EAAEI,IAAI,EAAC,GAAG,IAAI,CAACL,IAAI;QACzC,MAAM,EAACS,KAAK,EAAC,GAAG,IAAI,CAACD,KAAK;QAE1B,IAAIK;QACJ,MAAMC,OAAOtB,QAAQ,oBAAoBuB,KAAK;QAC9C,IAAI;YACFF,WAAW,MAAMhB,aAAaI,iBAAiBI;YAC/CS,KAAKE,OAAO,CAAC;QACf,EAAE,OAAOC,OAAO;YACdH,KAAKI,IAAI;YACTpB,kBAAkB,0BAA0BmB;YAC5C,IAAIxB,YAAYwB,UAAUA,MAAME,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACF,KAAK,CAAC,CAAC,OAAO,EAAEZ,KAAK,+BAA+B,EAAEJ,gBAAgB,CAAC,CAAC,EAAE;oBAC7EmB,MAAMhC,UAAUiC,aAAa;gBAC/B;YACF;YACA,IAAI,CAACJ,KAAK,CAAC,CAAC,yBAAyB,EAAE1B,gBAAgB0B,QAAQ,EAAE;gBAC/DG,MAAMhC,UAAUiC,aAAa;YAC/B;QACF;QAEA,MAAM,EAACC,eAAe,EAAEC,KAAK,EAAC,GAAGV;QACjC,MAAMW,QAAQ,GAAG,2CAA2C;;QAC5D,IAAI,CAACC,GAAG,CAAC7B,eAAe,UAAU2B,OAAO;YAACC;QAAK;QAC/C,8EAA8E;QAC9E,IAAIF,gBAAgBI,MAAM,GAAG,GAAG;YAC9B,MAAMC,QAAQL,gBAAgBM,GAAG,CAAC,CAACC,QAAUA,MAAMxB,IAAI,EAAEyB,IAAI,CAAC;YAC9D,IAAI,CAACL,GAAG,CAAC7B,eAAe,uBAAuB+B,OAAO;gBAACH;YAAK;QAC9D;QACA,IAAI,CAACC,GAAG,CAAC,CAAC,uCAAuC,EAAExB,gBAAgB,CAAC,EAAEsB,OAAO;QAE7E,IAAI,CAACd,OAAO;YACV;QACF;QAEA,IAAIsB;QACJ,IAAI;YACFA,MAAM,MAAMpC,SAASM,iBAAiBsB,OAAO;gBAC3CS,OAAO;gBACPC,aAAa;YACf;QACF,EAAE,OAAOhB,OAAO;YACdnB,kBAAkB,8BAA8BmB;YAChD,IAAI,CAACA,KAAK,CAAC,CAAC,6BAA6B,EAAE1B,gBAAgB0B,QAAQ,EAAE;gBACnEG,MAAMhC,UAAUiC,aAAa;YAC/B;QACF;QAEA,IAAIU,IAAIG,MAAM,KAAK,aAAa;YAC9B,IAAI,CAACjB,KAAK,CAACvB,iBAAiB,WAAWqC,MAAM;gBAACX,MAAMhC,UAAUiC,aAAa;YAAA;QAC7E;IACF;AACF"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
|
+
import { spinner } from '@sanity/cli-core/ux';
|
|
5
|
+
import { isHttpError } from '@sanity/client';
|
|
6
|
+
import { formatJobFailure, watchJob } from '../../../actions/context/watchJob.js';
|
|
7
|
+
import { formatKeyValue } from '../../../actions/debug/output.js';
|
|
8
|
+
import { applyIssues } from '../../../services/context.js';
|
|
9
|
+
const applyIssuesDebug = subdebug('context:issues:apply');
|
|
10
|
+
export class ApplyIssuesCommand extends SanityCommand {
|
|
11
|
+
static args = {
|
|
12
|
+
knowledgeBaseId: Args.string({
|
|
13
|
+
description: 'Knowledge base ID',
|
|
14
|
+
required: true
|
|
15
|
+
}),
|
|
16
|
+
// eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first
|
|
17
|
+
issueId: Args.string({
|
|
18
|
+
description: "ID of an issue to accept and apply (pass several to apply them in one batch). Conflicts can't be applied; resolve them with `sanity context issues resolve`",
|
|
19
|
+
multiple: true,
|
|
20
|
+
required: true
|
|
21
|
+
})
|
|
22
|
+
};
|
|
23
|
+
static description = 'Accept and apply issues to a knowledge base';
|
|
24
|
+
static examples = [
|
|
25
|
+
{
|
|
26
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456 issue.ghi789',
|
|
27
|
+
description: 'Accept and apply two issues in one batch'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456 --watch',
|
|
31
|
+
description: 'Apply an issue and wait for it to finish (non-zero exit on failure)'
|
|
32
|
+
}
|
|
33
|
+
];
|
|
34
|
+
static flags = {
|
|
35
|
+
watch: Flags.boolean({
|
|
36
|
+
default: false,
|
|
37
|
+
description: 'Wait for the apply to finish, exiting non-zero if it fails'
|
|
38
|
+
})
|
|
39
|
+
};
|
|
40
|
+
async run() {
|
|
41
|
+
const { issueId: issueIds, knowledgeBaseId } = this.args;
|
|
42
|
+
const { watch } = this.flags;
|
|
43
|
+
let jobId;
|
|
44
|
+
const spin = spinner('Starting apply').start();
|
|
45
|
+
try {
|
|
46
|
+
const accepted = await applyIssues(knowledgeBaseId, issueIds);
|
|
47
|
+
jobId = accepted.jobId;
|
|
48
|
+
spin.succeed('Apply started');
|
|
49
|
+
} catch (error) {
|
|
50
|
+
spin.fail();
|
|
51
|
+
applyIssuesDebug('Error applying issues', error);
|
|
52
|
+
if (isHttpError(error) && error.statusCode === 404) {
|
|
53
|
+
this.error(`Knowledge base "${knowledgeBaseId}" not found`, {
|
|
54
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
this.error(`Failed to apply issues: ${getErrorMessage(error)}`, {
|
|
58
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
this.log(formatKeyValue('Job ID', jobId));
|
|
62
|
+
this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`);
|
|
63
|
+
if (!watch) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
let job;
|
|
67
|
+
try {
|
|
68
|
+
job = await watchJob(knowledgeBaseId, jobId, {
|
|
69
|
+
label: 'Applying issues',
|
|
70
|
+
successText: 'Issues applied'
|
|
71
|
+
});
|
|
72
|
+
} catch (error) {
|
|
73
|
+
applyIssuesDebug('Error watching apply job', error);
|
|
74
|
+
this.error(`Failed to watch apply job: ${getErrorMessage(error)}`, {
|
|
75
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
if (job.status !== 'succeeded') {
|
|
79
|
+
this.error(formatJobFailure('Apply', job), {
|
|
80
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=apply.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/context/issues/apply.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {spinner} from '@sanity/cli-core/ux'\nimport {isHttpError} from '@sanity/client'\n\nimport {formatJobFailure, watchJob} from '../../../actions/context/watchJob.js'\nimport {formatKeyValue} from '../../../actions/debug/output.js'\nimport {applyIssues} from '../../../services/context.js'\n\nconst applyIssuesDebug = subdebug('context:issues:apply')\n\nexport class ApplyIssuesCommand extends SanityCommand<typeof ApplyIssuesCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first\n issueId: Args.string({\n description:\n \"ID of an issue to accept and apply (pass several to apply them in one batch). Conflicts can't be applied; resolve them with `sanity context issues resolve`\",\n multiple: true,\n required: true,\n }),\n }\n\n static override description = 'Accept and apply issues to a knowledge base'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456 issue.ghi789',\n description: 'Accept and apply two issues in one batch',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456 --watch',\n description: 'Apply an issue and wait for it to finish (non-zero exit on failure)',\n },\n ]\n\n static override flags = {\n watch: Flags.boolean({\n default: false,\n description: 'Wait for the apply to finish, exiting non-zero if it fails',\n }),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {issueId: issueIds, knowledgeBaseId} = this.args\n const {watch} = this.flags\n\n let jobId: string\n const spin = spinner('Starting apply').start()\n try {\n const accepted = await applyIssues(knowledgeBaseId, issueIds)\n jobId = accepted.jobId\n spin.succeed('Apply started')\n } catch (error) {\n spin.fail()\n applyIssuesDebug('Error applying issues', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to apply issues: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n this.log(formatKeyValue('Job ID', jobId))\n this.log(`Track it with: sanity context jobs get ${knowledgeBaseId} ${jobId}`)\n\n if (!watch) {\n return\n }\n\n let job\n try {\n job = await watchJob(knowledgeBaseId, jobId, {\n label: 'Applying issues',\n successText: 'Issues applied',\n })\n } catch (error) {\n applyIssuesDebug('Error watching apply job', error)\n this.error(`Failed to watch apply job: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (job.status !== 'succeeded') {\n this.error(formatJobFailure('Apply', job), {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n }\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","spinner","isHttpError","formatJobFailure","watchJob","formatKeyValue","applyIssues","applyIssuesDebug","ApplyIssuesCommand","args","knowledgeBaseId","string","description","required","issueId","multiple","examples","command","flags","watch","boolean","default","run","issueIds","jobId","spin","start","accepted","succeed","error","fail","statusCode","exit","RUNTIME_ERROR","log","job","label","successText","status"],"mappings":"AAAA,SAAQA,IAAI,EAAEC,KAAK,QAAO,cAAa;AAEvC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,OAAO,QAAO,sBAAqB;AAC3C,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,gBAAgB,EAAEC,QAAQ,QAAO,uCAAsC;AAC/E,SAAQC,cAAc,QAAO,mCAAkC;AAC/D,SAAQC,WAAW,QAAO,+BAA8B;AAExD,MAAMC,mBAAmBR,SAAS;AAElC,OAAO,MAAMS,2BAA2BV;IACtC,OAAgBW,OAAO;QACrBC,iBAAiBf,KAAKgB,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACA,gGAAgG;QAChGC,SAASnB,KAAKgB,MAAM,CAAC;YACnBC,aACE;YACFG,UAAU;YACVF,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,8CAA6C;IAE3E,OAAgBI,WAAW;QACzB;YACEC,SAAS;YACTL,aAAa;QACf;QACA;YACEK,SAAS;YACTL,aAAa;QACf;KACD,CAAA;IAED,OAAgBM,QAAQ;QACtBC,OAAOvB,MAAMwB,OAAO,CAAC;YACnBC,SAAS;YACTT,aAAa;QACf;IACF,EAAqB;IAErB,MAAaU,MAAqB;QAChC,MAAM,EAACR,SAASS,QAAQ,EAAEb,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QACtD,MAAM,EAACU,KAAK,EAAC,GAAG,IAAI,CAACD,KAAK;QAE1B,IAAIM;QACJ,MAAMC,OAAOxB,QAAQ,kBAAkByB,KAAK;QAC5C,IAAI;YACF,MAAMC,WAAW,MAAMrB,YAAYI,iBAAiBa;YACpDC,QAAQG,SAASH,KAAK;YACtBC,KAAKG,OAAO,CAAC;QACf,EAAE,OAAOC,OAAO;YACdJ,KAAKK,IAAI;YACTvB,iBAAiB,yBAAyBsB;YAC1C,IAAI3B,YAAY2B,UAAUA,MAAME,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACF,KAAK,CAAC,CAAC,gBAAgB,EAAEnB,gBAAgB,WAAW,CAAC,EAAE;oBAC1DsB,MAAMnC,UAAUoC,aAAa;gBAC/B;YACF;YACA,IAAI,CAACJ,KAAK,CAAC,CAAC,wBAAwB,EAAE7B,gBAAgB6B,QAAQ,EAAE;gBAC9DG,MAAMnC,UAAUoC,aAAa;YAC/B;QACF;QAEA,IAAI,CAACC,GAAG,CAAC7B,eAAe,UAAUmB;QAClC,IAAI,CAACU,GAAG,CAAC,CAAC,uCAAuC,EAAExB,gBAAgB,CAAC,EAAEc,OAAO;QAE7E,IAAI,CAACL,OAAO;YACV;QACF;QAEA,IAAIgB;QACJ,IAAI;YACFA,MAAM,MAAM/B,SAASM,iBAAiBc,OAAO;gBAC3CY,OAAO;gBACPC,aAAa;YACf;QACF,EAAE,OAAOR,OAAO;YACdtB,iBAAiB,4BAA4BsB;YAC7C,IAAI,CAACA,KAAK,CAAC,CAAC,2BAA2B,EAAE7B,gBAAgB6B,QAAQ,EAAE;gBACjEG,MAAMnC,UAAUoC,aAAa;YAC/B;QACF;QAEA,IAAIE,IAAIG,MAAM,KAAK,aAAa;YAC9B,IAAI,CAACT,KAAK,CAAC1B,iBAAiB,SAASgC,MAAM;gBACzCH,MAAMnC,UAAUoC,aAAa;YAC/B;QACF;IACF;AACF"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
|
+
import { isHttpError } from '@sanity/client';
|
|
5
|
+
import { dismissIssue } from '../../../services/context.js';
|
|
6
|
+
const dismissIssueDebug = subdebug('context:issues:dismiss');
|
|
7
|
+
export class DismissIssueCommand extends SanityCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
knowledgeBaseId: Args.string({
|
|
10
|
+
description: 'Knowledge base ID',
|
|
11
|
+
required: true
|
|
12
|
+
}),
|
|
13
|
+
// eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first
|
|
14
|
+
issueId: Args.string({
|
|
15
|
+
description: 'Issue ID',
|
|
16
|
+
required: true
|
|
17
|
+
})
|
|
18
|
+
};
|
|
19
|
+
static description = "Dismiss an issue\n\nDismissing is permanent: dismissed issues can't be reopened.";
|
|
20
|
+
static examples = [
|
|
21
|
+
{
|
|
22
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456',
|
|
23
|
+
description: 'Dismiss an issue'
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
async run() {
|
|
27
|
+
const { issueId, knowledgeBaseId } = this.args;
|
|
28
|
+
let dismissed;
|
|
29
|
+
try {
|
|
30
|
+
dismissed = await dismissIssue(knowledgeBaseId, issueId);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
dismissIssueDebug('Error dismissing issue', error);
|
|
33
|
+
if (isHttpError(error) && error.statusCode === 404) {
|
|
34
|
+
this.error(`Issue "${issueId}" not found on knowledge base "${knowledgeBaseId}"`, {
|
|
35
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
this.error(`Failed to dismiss issue: ${getErrorMessage(error)}`, {
|
|
39
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// The API returns the issue unchanged when it already left triage
|
|
43
|
+
if (dismissed.status !== 'rejected') {
|
|
44
|
+
this.error(`Issue "${issueId}" is accepted (resolved or applied) and cannot be dismissed`, {
|
|
45
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
this.log('Issue dismissed');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
//# sourceMappingURL=dismiss.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/context/issues/dismiss.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {dismissIssue} from '../../../services/context.js'\n\nconst dismissIssueDebug = subdebug('context:issues:dismiss')\n\nexport class DismissIssueCommand extends SanityCommand<typeof DismissIssueCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first\n issueId: Args.string({\n description: 'Issue ID',\n required: true,\n }),\n }\n\n static override description =\n \"Dismiss an issue\\n\\nDismissing is permanent: dismissed issues can't be reopened.\"\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456',\n description: 'Dismiss an issue',\n },\n ]\n\n public async run(): Promise<void> {\n const {issueId, knowledgeBaseId} = this.args\n\n let dismissed\n try {\n dismissed = await dismissIssue(knowledgeBaseId, issueId)\n } catch (error) {\n dismissIssueDebug('Error dismissing issue', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Issue \"${issueId}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to dismiss issue: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // The API returns the issue unchanged when it already left triage\n if (dismissed.status !== 'rejected') {\n this.error(`Issue \"${issueId}\" is accepted (resolved or applied) and cannot be dismissed`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n this.log('Issue dismissed')\n }\n}\n"],"names":["Args","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","dismissIssue","dismissIssueDebug","DismissIssueCommand","args","knowledgeBaseId","string","description","required","issueId","examples","command","run","dismissed","error","statusCode","exit","RUNTIME_ERROR","status","log"],"mappings":"AAAA,SAAQA,IAAI,QAAO,cAAa;AAChC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,YAAY,QAAO,+BAA8B;AAEzD,MAAMC,oBAAoBJ,SAAS;AAEnC,OAAO,MAAMK,4BAA4BN;IACvC,OAAgBO,OAAO;QACrBC,iBAAiBV,KAAKW,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACA,gGAAgG;QAChGC,SAASd,KAAKW,MAAM,CAAC;YACnBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cACd,mFAAkF;IAEpF,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,MAAaK,MAAqB;QAChC,MAAM,EAACH,OAAO,EAAEJ,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QAE5C,IAAIS;QACJ,IAAI;YACFA,YAAY,MAAMZ,aAAaI,iBAAiBI;QAClD,EAAE,OAAOK,OAAO;YACdZ,kBAAkB,0BAA0BY;YAC5C,IAAId,YAAYc,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CAAC,CAAC,OAAO,EAAEL,QAAQ,+BAA+B,EAAEJ,gBAAgB,CAAC,CAAC,EAAE;oBAChFW,MAAMpB,UAAUqB,aAAa;gBAC/B;YACF;YACA,IAAI,CAACH,KAAK,CAAC,CAAC,yBAAyB,EAAEf,gBAAgBe,QAAQ,EAAE;gBAC/DE,MAAMpB,UAAUqB,aAAa;YAC/B;QACF;QAEA,kEAAkE;QAClE,IAAIJ,UAAUK,MAAM,KAAK,YAAY;YACnC,IAAI,CAACJ,KAAK,CAAC,CAAC,OAAO,EAAEL,QAAQ,2DAA2D,CAAC,EAAE;gBACzFO,MAAMpB,UAAUqB,aAAa;YAC/B;QACF;QAEA,IAAI,CAACE,GAAG,CAAC;IACX;AACF"}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
|
+
import { isHttpError } from '@sanity/client';
|
|
5
|
+
import { formatKeyValue } from '../../../actions/debug/output.js';
|
|
6
|
+
import { getIssue } from '../../../services/context.js';
|
|
7
|
+
const getIssueDebug = subdebug('context:issues:get');
|
|
8
|
+
export class GetIssueCommand extends SanityCommand {
|
|
9
|
+
static args = {
|
|
10
|
+
knowledgeBaseId: Args.string({
|
|
11
|
+
description: 'Knowledge base ID',
|
|
12
|
+
required: true
|
|
13
|
+
}),
|
|
14
|
+
// eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first
|
|
15
|
+
issueId: Args.string({
|
|
16
|
+
description: 'Issue ID',
|
|
17
|
+
required: true
|
|
18
|
+
})
|
|
19
|
+
};
|
|
20
|
+
static description = 'Get details of an issue';
|
|
21
|
+
static enableJsonFlag = true;
|
|
22
|
+
static examples = [
|
|
23
|
+
{
|
|
24
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456',
|
|
25
|
+
description: 'Get details of a specific issue'
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456 --json',
|
|
29
|
+
description: 'Output the issue as JSON'
|
|
30
|
+
}
|
|
31
|
+
];
|
|
32
|
+
async run() {
|
|
33
|
+
const { issueId, knowledgeBaseId } = this.args;
|
|
34
|
+
const { json } = this.flags;
|
|
35
|
+
let issue;
|
|
36
|
+
try {
|
|
37
|
+
issue = await getIssue(knowledgeBaseId, issueId);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
getIssueDebug('Error getting issue', error);
|
|
40
|
+
if (isHttpError(error) && error.statusCode === 404) {
|
|
41
|
+
this.error(`Knowledge base "${knowledgeBaseId}" not found`, {
|
|
42
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
this.error(`Failed to get issue: ${getErrorMessage(error)}`, {
|
|
46
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (!issue) {
|
|
50
|
+
this.error(`Issue "${issueId}" not found on knowledge base "${knowledgeBaseId}"`, {
|
|
51
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (json) {
|
|
55
|
+
this.logJson(issue);
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const { content } = issue;
|
|
59
|
+
const padTo = 13 // "Suggested fix" is the longest key
|
|
60
|
+
;
|
|
61
|
+
this.log(formatKeyValue('ID', issue._id, {
|
|
62
|
+
padTo
|
|
63
|
+
}));
|
|
64
|
+
this.log(formatKeyValue('Kind', content.kind, {
|
|
65
|
+
padTo
|
|
66
|
+
}));
|
|
67
|
+
this.log(formatKeyValue('Severity', content.severity, {
|
|
68
|
+
padTo
|
|
69
|
+
}));
|
|
70
|
+
this.log(formatKeyValue('Status', issue.status, {
|
|
71
|
+
padTo
|
|
72
|
+
}));
|
|
73
|
+
this.log(formatKeyValue('Scope', content.scopePath, {
|
|
74
|
+
padTo
|
|
75
|
+
}));
|
|
76
|
+
this.log(formatKeyValue('Issue', content.issue, {
|
|
77
|
+
padTo
|
|
78
|
+
}));
|
|
79
|
+
this.log(formatKeyValue('Suggested fix', content.suggestedFix, {
|
|
80
|
+
padTo
|
|
81
|
+
}));
|
|
82
|
+
// Sides are labeled with the 0-based index that `issues resolve --side` takes
|
|
83
|
+
if (content.kind === 'conflict') {
|
|
84
|
+
for (const [index, side] of content.sides.entries()){
|
|
85
|
+
const entryPaths = side.entryPaths?.length ? ` (${side.entryPaths.join(', ')})` : '';
|
|
86
|
+
this.log(formatKeyValue(`Side [${index}]`, `${side.claim}${entryPaths}`, {
|
|
87
|
+
padTo
|
|
88
|
+
}));
|
|
89
|
+
}
|
|
90
|
+
if (content.suggested !== undefined) {
|
|
91
|
+
this.log(formatKeyValue('Suggested', `[${content.suggested}]`, {
|
|
92
|
+
padTo
|
|
93
|
+
}));
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
this.log(formatKeyValue('Resolution', issue.resolution === null ? '-' : `[${issue.resolution}]`, {
|
|
97
|
+
padTo
|
|
98
|
+
}));
|
|
99
|
+
this.log(formatKeyValue('Created', issue._createdAt, {
|
|
100
|
+
padTo
|
|
101
|
+
}));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
//# sourceMappingURL=get.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/context/issues/get.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {formatKeyValue} from '../../../actions/debug/output.js'\nimport {getIssue} from '../../../services/context.js'\n\nconst getIssueDebug = subdebug('context:issues:get')\n\nexport class GetIssueCommand extends SanityCommand<typeof GetIssueCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first\n issueId: Args.string({\n description: 'Issue ID',\n required: true,\n }),\n }\n\n static override description = 'Get details of an issue'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456',\n description: 'Get details of a specific issue',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456 --json',\n description: 'Output the issue as JSON',\n },\n ]\n\n public async run(): Promise<void> {\n const {issueId, knowledgeBaseId} = this.args\n const {json} = this.flags\n\n let issue\n try {\n issue = await getIssue(knowledgeBaseId, issueId)\n } catch (error) {\n getIssueDebug('Error getting issue', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to get issue: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (!issue) {\n this.error(`Issue \"${issueId}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n if (json) {\n this.logJson(issue)\n return\n }\n\n const {content} = issue\n const padTo = 13 // \"Suggested fix\" is the longest key\n this.log(formatKeyValue('ID', issue._id, {padTo}))\n this.log(formatKeyValue('Kind', content.kind, {padTo}))\n this.log(formatKeyValue('Severity', content.severity, {padTo}))\n this.log(formatKeyValue('Status', issue.status, {padTo}))\n this.log(formatKeyValue('Scope', content.scopePath, {padTo}))\n this.log(formatKeyValue('Issue', content.issue, {padTo}))\n this.log(formatKeyValue('Suggested fix', content.suggestedFix, {padTo}))\n // Sides are labeled with the 0-based index that `issues resolve --side` takes\n if (content.kind === 'conflict') {\n for (const [index, side] of content.sides.entries()) {\n const entryPaths = side.entryPaths?.length ? ` (${side.entryPaths.join(', ')})` : ''\n this.log(formatKeyValue(`Side [${index}]`, `${side.claim}${entryPaths}`, {padTo}))\n }\n if (content.suggested !== undefined) {\n this.log(formatKeyValue('Suggested', `[${content.suggested}]`, {padTo}))\n }\n }\n this.log(\n formatKeyValue('Resolution', issue.resolution === null ? '-' : `[${issue.resolution}]`, {\n padTo,\n }),\n )\n this.log(formatKeyValue('Created', issue._createdAt, {padTo}))\n }\n}\n"],"names":["Args","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","formatKeyValue","getIssue","getIssueDebug","GetIssueCommand","args","knowledgeBaseId","string","description","required","issueId","enableJsonFlag","examples","command","run","json","flags","issue","error","statusCode","exit","RUNTIME_ERROR","logJson","content","padTo","log","_id","kind","severity","status","scopePath","suggestedFix","index","side","sides","entries","entryPaths","length","join","claim","suggested","undefined","resolution","_createdAt"],"mappings":"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"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
|
+
import { isHttpError } from '@sanity/client';
|
|
5
|
+
import { listIssues } from '../../../services/context.js';
|
|
6
|
+
const listIssuesDebug = subdebug('context:issues:list');
|
|
7
|
+
export class ListIssuesCommand extends SanityCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
knowledgeBaseId: Args.string({
|
|
10
|
+
description: 'Knowledge base ID',
|
|
11
|
+
required: true
|
|
12
|
+
})
|
|
13
|
+
};
|
|
14
|
+
static description = 'List issues found by knowledge base builds';
|
|
15
|
+
static enableJsonFlag = true;
|
|
16
|
+
static examples = [
|
|
17
|
+
{
|
|
18
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123',
|
|
19
|
+
description: 'List all issues for a knowledge base'
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 --status open',
|
|
23
|
+
description: 'List issues awaiting triage'
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 --kind conflict --severity critical',
|
|
27
|
+
description: 'List critical conflicts'
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 --scope billing',
|
|
31
|
+
description: 'List issues about entries under billing/'
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 --json',
|
|
35
|
+
description: 'Output issues as JSON'
|
|
36
|
+
}
|
|
37
|
+
];
|
|
38
|
+
static flags = {
|
|
39
|
+
kind: Flags.custom({
|
|
40
|
+
description: 'Only list issues of this kind',
|
|
41
|
+
// A Record forces every kind the client knows to be listed, so the options can't drift
|
|
42
|
+
options: Object.keys({
|
|
43
|
+
add_entry: true,
|
|
44
|
+
conflict: true,
|
|
45
|
+
gap: true,
|
|
46
|
+
merge_entry: true,
|
|
47
|
+
remove_entry: true,
|
|
48
|
+
split_entry: true,
|
|
49
|
+
update_required: true
|
|
50
|
+
})
|
|
51
|
+
})(),
|
|
52
|
+
scope: Flags.string({
|
|
53
|
+
description: 'Only list issues about this entry path or anything under it (`*` for knowledge-base-wide issues)',
|
|
54
|
+
helpValue: '<path>',
|
|
55
|
+
parse: async (input)=>{
|
|
56
|
+
const trimmed = input.trim().replace(/\/+$/, '');
|
|
57
|
+
if (trimmed === '') {
|
|
58
|
+
throw new Error('`--scope` cannot be empty if provided');
|
|
59
|
+
}
|
|
60
|
+
return trimmed;
|
|
61
|
+
}
|
|
62
|
+
}),
|
|
63
|
+
severity: Flags.custom({
|
|
64
|
+
description: 'Only list issues of this severity',
|
|
65
|
+
options: [
|
|
66
|
+
'critical',
|
|
67
|
+
'suggestion'
|
|
68
|
+
]
|
|
69
|
+
})(),
|
|
70
|
+
status: Flags.custom({
|
|
71
|
+
description: 'Only list issues with this status (rejected = dismissed, accepted = resolved or applied)',
|
|
72
|
+
options: [
|
|
73
|
+
'open',
|
|
74
|
+
'accepted',
|
|
75
|
+
'rejected'
|
|
76
|
+
]
|
|
77
|
+
})()
|
|
78
|
+
};
|
|
79
|
+
async run() {
|
|
80
|
+
const { knowledgeBaseId } = this.args;
|
|
81
|
+
const { json, kind, scope, severity, status } = this.flags;
|
|
82
|
+
let issues;
|
|
83
|
+
try {
|
|
84
|
+
issues = await listIssues(knowledgeBaseId, status);
|
|
85
|
+
} catch (error) {
|
|
86
|
+
listIssuesDebug('Error listing issues', error);
|
|
87
|
+
if (isHttpError(error) && error.statusCode === 404) {
|
|
88
|
+
this.error(`Knowledge base "${knowledgeBaseId}" not found`, {
|
|
89
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
this.error(`Failed to list issues: ${getErrorMessage(error)}`, {
|
|
93
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// The client only filters on status; the rest are applied here
|
|
97
|
+
const matches = issues.filter(({ content })=>(kind === undefined || content.kind === kind) && (severity === undefined || content.severity === severity) && (scope === undefined || content.scopePath === scope || content.scopePath.startsWith(`${scope}/`)));
|
|
98
|
+
if (json) {
|
|
99
|
+
this.logJson(matches);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
if (matches.length === 0) {
|
|
103
|
+
this.log('No issues found');
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
// Two lines per issue so long IDs never wrap: ID and metadata, then the summary cut to fit
|
|
107
|
+
const width = Math.max(process.stdout.columns ?? 100, 40);
|
|
108
|
+
const blocks = matches.map(({ _id, content, status: issueStatus })=>{
|
|
109
|
+
const meta = [
|
|
110
|
+
content.kind,
|
|
111
|
+
content.severity,
|
|
112
|
+
issueStatus,
|
|
113
|
+
content.scopePath
|
|
114
|
+
].join(' · ');
|
|
115
|
+
return `${_id} ${meta}\n ${truncate(content.issue, width - 2)}`;
|
|
116
|
+
});
|
|
117
|
+
this.log(blocks.join('\n\n'));
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function truncate(text, maxLength) {
|
|
121
|
+
// Count characters, not UTF-16 units, so an emoji at the cut point isn't split
|
|
122
|
+
const chars = [
|
|
123
|
+
...text.replaceAll(/\s+/g, ' ').trim()
|
|
124
|
+
];
|
|
125
|
+
return chars.length <= maxLength ? chars.join('') : `${chars.slice(0, maxLength - 1).join('')}…`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/context/issues/list.ts"],"sourcesContent":["import {Args, Flags} from '@oclif/core'\nimport {type FlagInput} from '@oclif/core/interfaces'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {type Context, isHttpError} from '@sanity/client'\n\nimport {listIssues} from '../../../services/context.js'\n\nconst listIssuesDebug = subdebug('context:issues:list')\n\nexport class ListIssuesCommand extends SanityCommand<typeof ListIssuesCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n }\n\n static override description = 'List issues found by knowledge base builds'\n\n static override enableJsonFlag = true\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123',\n description: 'List all issues for a knowledge base',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --status open',\n description: 'List issues awaiting triage',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --kind conflict --severity critical',\n description: 'List critical conflicts',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --scope billing',\n description: 'List issues about entries under billing/',\n },\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 --json',\n description: 'Output issues as JSON',\n },\n ]\n\n static override flags = {\n kind: Flags.custom<IssueKind>({\n description: 'Only list issues of this kind',\n // A Record forces every kind the client knows to be listed, so the options can't drift\n options: Object.keys({\n add_entry: true,\n conflict: true,\n gap: true,\n merge_entry: true,\n remove_entry: true,\n split_entry: true,\n update_required: true,\n } satisfies Record<IssueKind, true>),\n })(),\n scope: Flags.string({\n description:\n 'Only list issues about this entry path or anything under it (`*` for knowledge-base-wide issues)',\n helpValue: '<path>',\n parse: async (input: string) => {\n const trimmed = input.trim().replace(/\\/+$/, '')\n if (trimmed === '') {\n throw new Error('`--scope` cannot be empty if provided')\n }\n return trimmed\n },\n }),\n severity: Flags.custom<Context.IssueDoc['content']['severity']>({\n description: 'Only list issues of this severity',\n options: ['critical', 'suggestion'],\n })(),\n status: Flags.custom<Context.IssueDoc['status']>({\n description:\n 'Only list issues with this status (rejected = dismissed, accepted = resolved or applied)',\n options: ['open', 'accepted', 'rejected'],\n })(),\n } satisfies FlagInput\n\n public async run(): Promise<void> {\n const {knowledgeBaseId} = this.args\n const {json, kind, scope, severity, status} = this.flags\n\n let issues\n try {\n issues = await listIssues(knowledgeBaseId, status)\n } catch (error) {\n listIssuesDebug('Error listing issues', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Knowledge base \"${knowledgeBaseId}\" not found`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to list issues: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // The client only filters on status; the rest are applied here\n const matches = issues.filter(\n ({content}) =>\n (kind === undefined || content.kind === kind) &&\n (severity === undefined || content.severity === severity) &&\n (scope === undefined ||\n content.scopePath === scope ||\n content.scopePath.startsWith(`${scope}/`)),\n )\n\n if (json) {\n this.logJson(matches)\n return\n }\n\n if (matches.length === 0) {\n this.log('No issues found')\n return\n }\n\n // Two lines per issue so long IDs never wrap: ID and metadata, then the summary cut to fit\n const width = Math.max(process.stdout.columns ?? 100, 40)\n const blocks = matches.map(({_id, content, status: issueStatus}) => {\n const meta = [content.kind, content.severity, issueStatus, content.scopePath].join(' · ')\n return `${_id} ${meta}\\n ${truncate(content.issue, width - 2)}`\n })\n this.log(blocks.join('\\n\\n'))\n }\n}\n\ntype IssueKind = Context.IssueDoc['content']['kind']\n\nfunction truncate(text: string, maxLength: number): string {\n // Count characters, not UTF-16 units, so an emoji at the cut point isn't split\n const chars = [...text.replaceAll(/\\s+/g, ' ').trim()]\n return chars.length <= maxLength ? chars.join('') : `${chars.slice(0, maxLength - 1).join('')}…`\n}\n"],"names":["Args","Flags","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","listIssues","listIssuesDebug","ListIssuesCommand","args","knowledgeBaseId","string","description","required","enableJsonFlag","examples","command","flags","kind","custom","options","Object","keys","add_entry","conflict","gap","merge_entry","remove_entry","split_entry","update_required","scope","helpValue","parse","input","trimmed","trim","replace","Error","severity","status","run","json","issues","error","statusCode","exit","RUNTIME_ERROR","matches","filter","content","undefined","scopePath","startsWith","logJson","length","log","width","Math","max","process","stdout","columns","blocks","map","_id","issueStatus","meta","join","truncate","issue","text","maxLength","chars","replaceAll","slice"],"mappings":"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"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { Args } from '@oclif/core';
|
|
2
|
+
import { exitCodes, SanityCommand, subdebug } from '@sanity/cli-core';
|
|
3
|
+
import { getErrorMessage } from '@sanity/cli-core/errors';
|
|
4
|
+
import { isHttpError } from '@sanity/client';
|
|
5
|
+
import { reopenIssue } from '../../../services/context.js';
|
|
6
|
+
const reopenIssueDebug = subdebug('context:issues:reopen');
|
|
7
|
+
export class ReopenIssueCommand extends SanityCommand {
|
|
8
|
+
static args = {
|
|
9
|
+
knowledgeBaseId: Args.string({
|
|
10
|
+
description: 'Knowledge base ID',
|
|
11
|
+
required: true
|
|
12
|
+
}),
|
|
13
|
+
// eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first
|
|
14
|
+
issueId: Args.string({
|
|
15
|
+
description: 'Issue ID',
|
|
16
|
+
required: true
|
|
17
|
+
})
|
|
18
|
+
};
|
|
19
|
+
static description = 'Reopen a resolved conflict issue';
|
|
20
|
+
static examples = [
|
|
21
|
+
{
|
|
22
|
+
command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456',
|
|
23
|
+
description: 'Return a resolved conflict issue to triage'
|
|
24
|
+
}
|
|
25
|
+
];
|
|
26
|
+
async run() {
|
|
27
|
+
const { issueId, knowledgeBaseId } = this.args;
|
|
28
|
+
let reopened;
|
|
29
|
+
try {
|
|
30
|
+
reopened = await reopenIssue(knowledgeBaseId, issueId);
|
|
31
|
+
} catch (error) {
|
|
32
|
+
reopenIssueDebug('Error reopening issue', error);
|
|
33
|
+
if (isHttpError(error) && error.statusCode === 404) {
|
|
34
|
+
this.error(`Issue "${issueId}" not found on knowledge base "${knowledgeBaseId}"`, {
|
|
35
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
this.error(`Failed to reopen issue: ${getErrorMessage(error)}`, {
|
|
39
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
// The API returns the issue unchanged when it cannot be reopened
|
|
43
|
+
if (reopened.status !== 'open') {
|
|
44
|
+
const status = reopened.status === 'rejected' ? 'rejected (dismissed)' : 'accepted (resolved or applied)';
|
|
45
|
+
this.error(`Issue "${issueId}" is ${status} and cannot be reopened.\nOnly resolved conflict issues can be reopened.`, {
|
|
46
|
+
exit: exitCodes.RUNTIME_ERROR
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
this.log('Issue reopened');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
//# sourceMappingURL=reopen.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/commands/context/issues/reopen.ts"],"sourcesContent":["import {Args} from '@oclif/core'\nimport {exitCodes, SanityCommand, subdebug} from '@sanity/cli-core'\nimport {getErrorMessage} from '@sanity/cli-core/errors'\nimport {isHttpError} from '@sanity/client'\n\nimport {reopenIssue} from '../../../services/context.js'\n\nconst reopenIssueDebug = subdebug('context:issues:reopen')\n\nexport class ReopenIssueCommand extends SanityCommand<typeof ReopenIssueCommand> {\n static override args = {\n knowledgeBaseId: Args.string({\n description: 'Knowledge base ID',\n required: true,\n }),\n // eslint-disable-next-line perfectionist/sort-objects -- positional order: knowledge base first\n issueId: Args.string({\n description: 'Issue ID',\n required: true,\n }),\n }\n\n static override description = 'Reopen a resolved conflict issue'\n\n static override examples = [\n {\n command: '<%= config.bin %> <%= command.id %> kb-abc123 issue.def456',\n description: 'Return a resolved conflict issue to triage',\n },\n ]\n\n public async run(): Promise<void> {\n const {issueId, knowledgeBaseId} = this.args\n\n let reopened\n try {\n reopened = await reopenIssue(knowledgeBaseId, issueId)\n } catch (error) {\n reopenIssueDebug('Error reopening issue', error)\n if (isHttpError(error) && error.statusCode === 404) {\n this.error(`Issue \"${issueId}\" not found on knowledge base \"${knowledgeBaseId}\"`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n this.error(`Failed to reopen issue: ${getErrorMessage(error)}`, {\n exit: exitCodes.RUNTIME_ERROR,\n })\n }\n\n // The API returns the issue unchanged when it cannot be reopened\n if (reopened.status !== 'open') {\n const status =\n reopened.status === 'rejected' ? 'rejected (dismissed)' : 'accepted (resolved or applied)'\n this.error(\n `Issue \"${issueId}\" is ${status} and cannot be reopened.\\nOnly resolved conflict issues can be reopened.`,\n {exit: exitCodes.RUNTIME_ERROR},\n )\n }\n\n this.log('Issue reopened')\n }\n}\n"],"names":["Args","exitCodes","SanityCommand","subdebug","getErrorMessage","isHttpError","reopenIssue","reopenIssueDebug","ReopenIssueCommand","args","knowledgeBaseId","string","description","required","issueId","examples","command","run","reopened","error","statusCode","exit","RUNTIME_ERROR","status","log"],"mappings":"AAAA,SAAQA,IAAI,QAAO,cAAa;AAChC,SAAQC,SAAS,EAAEC,aAAa,EAAEC,QAAQ,QAAO,mBAAkB;AACnE,SAAQC,eAAe,QAAO,0BAAyB;AACvD,SAAQC,WAAW,QAAO,iBAAgB;AAE1C,SAAQC,WAAW,QAAO,+BAA8B;AAExD,MAAMC,mBAAmBJ,SAAS;AAElC,OAAO,MAAMK,2BAA2BN;IACtC,OAAgBO,OAAO;QACrBC,iBAAiBV,KAAKW,MAAM,CAAC;YAC3BC,aAAa;YACbC,UAAU;QACZ;QACA,gGAAgG;QAChGC,SAASd,KAAKW,MAAM,CAAC;YACnBC,aAAa;YACbC,UAAU;QACZ;IACF,EAAC;IAED,OAAgBD,cAAc,mCAAkC;IAEhE,OAAgBG,WAAW;QACzB;YACEC,SAAS;YACTJ,aAAa;QACf;KACD,CAAA;IAED,MAAaK,MAAqB;QAChC,MAAM,EAACH,OAAO,EAAEJ,eAAe,EAAC,GAAG,IAAI,CAACD,IAAI;QAE5C,IAAIS;QACJ,IAAI;YACFA,WAAW,MAAMZ,YAAYI,iBAAiBI;QAChD,EAAE,OAAOK,OAAO;YACdZ,iBAAiB,yBAAyBY;YAC1C,IAAId,YAAYc,UAAUA,MAAMC,UAAU,KAAK,KAAK;gBAClD,IAAI,CAACD,KAAK,CAAC,CAAC,OAAO,EAAEL,QAAQ,+BAA+B,EAAEJ,gBAAgB,CAAC,CAAC,EAAE;oBAChFW,MAAMpB,UAAUqB,aAAa;gBAC/B;YACF;YACA,IAAI,CAACH,KAAK,CAAC,CAAC,wBAAwB,EAAEf,gBAAgBe,QAAQ,EAAE;gBAC9DE,MAAMpB,UAAUqB,aAAa;YAC/B;QACF;QAEA,iEAAiE;QACjE,IAAIJ,SAASK,MAAM,KAAK,QAAQ;YAC9B,MAAMA,SACJL,SAASK,MAAM,KAAK,aAAa,yBAAyB;YAC5D,IAAI,CAACJ,KAAK,CACR,CAAC,OAAO,EAAEL,QAAQ,KAAK,EAAES,OAAO,wEAAwE,CAAC,EACzG;gBAACF,MAAMpB,UAAUqB,aAAa;YAAA;QAElC;QAEA,IAAI,CAACE,GAAG,CAAC;IACX;AACF"}
|