@copado/agentia-cli 0.54.0-alpha.0 → 0.57.0-alpha.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/README.md +261 -116
- package/dist/commands/cicd/promotion/run.d.ts +23 -0
- package/dist/commands/cicd/promotion/run.js +137 -0
- package/dist/commands/cicd/promotion/run.js.map +1 -0
- package/dist/commands/cicd/work/commit.d.ts +31 -0
- package/dist/commands/cicd/work/commit.js +254 -0
- package/dist/commands/cicd/work/commit.js.map +1 -0
- package/dist/commands/cicd/work/promote.d.ts +25 -0
- package/dist/commands/cicd/work/promote.js +141 -0
- package/dist/commands/cicd/work/promote.js.map +1 -0
- package/dist/lib/mcp/result.d.ts +4 -0
- package/dist/lib/mcp/result.js +6 -2
- package/dist/lib/mcp/result.js.map +1 -1
- package/dist/lib/mcp/tools.d.ts +64 -0
- package/dist/lib/mcp/tools.js +73 -0
- package/dist/lib/mcp/tools.js.map +1 -1
- package/dist/lib/mcp/work-tools.d.ts +53 -0
- package/dist/lib/mcp/work-tools.js +168 -0
- package/dist/lib/mcp/work-tools.js.map +1 -1
- package/dist/lib/promotion-run.d.ts +105 -0
- package/dist/lib/promotion-run.js +481 -0
- package/dist/lib/promotion-run.js.map +1 -0
- package/dist/lib/setup-templates.d.ts +1 -1
- package/dist/lib/setup-templates.js +17 -6
- package/dist/lib/setup-templates.js.map +1 -1
- package/dist/lib/work-commit.d.ts +118 -0
- package/dist/lib/work-commit.js +348 -0
- package/dist/lib/work-commit.js.map +1 -0
- package/oclif.manifest.json +1332 -954
- package/package.json +1 -1
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
2
|
+
import { type PromotionRunResult } from '../../../lib/promotion-run.js';
|
|
3
|
+
export default class PromotionRun extends AgentiaCommand {
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
static flags: {
|
|
10
|
+
'deployment-step-id': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'ignored-metadata-json': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
operation: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
13
|
+
'recreate-promotion-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
resume: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
15
|
+
wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
16
|
+
'wait-timeout': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
18
|
+
};
|
|
19
|
+
run(): Promise<PromotionRunResult>;
|
|
20
|
+
protected toErrorJson(err: unknown): unknown;
|
|
21
|
+
private execute;
|
|
22
|
+
private hooks;
|
|
23
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
4
|
+
import { formatPromotionRunResult, isPromotionRunExecutionError, parseIgnoredMetadataJson, performPromotionResume, performPromotionRun, PROMOTION_OPERATIONS, PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS, promotionRunErrorJson, PromotionRunValidationError, } from '../../../lib/promotion-run.js';
|
|
5
|
+
export default class PromotionRun extends AgentiaCommand {
|
|
6
|
+
static args = {
|
|
7
|
+
id: Args.string({
|
|
8
|
+
description: '18-character Salesforce Promotion ID',
|
|
9
|
+
required: true,
|
|
10
|
+
}),
|
|
11
|
+
};
|
|
12
|
+
static description = [
|
|
13
|
+
'Preflight, start, and optionally wait for a Copado promotion execution.',
|
|
14
|
+
'Use --resume to continue an existing failed or conflict-resolved execution without starting a duplicate promotion.',
|
|
15
|
+
].join(' ');
|
|
16
|
+
static examples = [
|
|
17
|
+
'<%= config.bin %> <%= command.id %> a0BXXXXXXXXXXXXXXX --operation merge',
|
|
18
|
+
'<%= config.bin %> <%= command.id %> a0BXXXXXXXXXXXXXXX --operation merge_and_deploy --json',
|
|
19
|
+
'<%= config.bin %> <%= command.id %> a0BXXXXXXXXXXXXXXX --resume a4NXXXXXXXXXXXXXXX',
|
|
20
|
+
];
|
|
21
|
+
static flags = {
|
|
22
|
+
'deployment-step-id': Flags.string({
|
|
23
|
+
description: 'Ordered deployment-step Salesforce ID. Can be provided multiple times.',
|
|
24
|
+
multiple: true,
|
|
25
|
+
}),
|
|
26
|
+
'ignored-metadata-json': Flags.string({
|
|
27
|
+
description: 'JSON array to persist through ignored-metadata before starting the promotion.',
|
|
28
|
+
}),
|
|
29
|
+
operation: Flags.string({
|
|
30
|
+
description: 'Promotion operation. Required unless --resume is used.',
|
|
31
|
+
options: [...PROMOTION_OPERATIONS],
|
|
32
|
+
}),
|
|
33
|
+
'recreate-promotion-branch': Flags.boolean({
|
|
34
|
+
description: 'Recreate the promotion branch before execution. Requires confirmation or --yes.',
|
|
35
|
+
}),
|
|
36
|
+
resume: Flags.string({
|
|
37
|
+
description: 'Resume this existing JobExecution ID instead of calling the promotion run endpoint.',
|
|
38
|
+
}),
|
|
39
|
+
wait: Flags.boolean({
|
|
40
|
+
allowNo: true,
|
|
41
|
+
default: true,
|
|
42
|
+
description: 'Poll promotion and deployment executions to terminal status.',
|
|
43
|
+
}),
|
|
44
|
+
'wait-timeout': Flags.integer({
|
|
45
|
+
default: PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS,
|
|
46
|
+
description: 'Maximum total seconds to wait for promotion and deployment executions.',
|
|
47
|
+
}),
|
|
48
|
+
yes: Flags.boolean({
|
|
49
|
+
char: 'y',
|
|
50
|
+
default: false,
|
|
51
|
+
description: 'Confirm promotion branch recreation without prompting.',
|
|
52
|
+
}),
|
|
53
|
+
};
|
|
54
|
+
async run() {
|
|
55
|
+
const { args, flags } = await this.parse(PromotionRun);
|
|
56
|
+
const runFlags = flags;
|
|
57
|
+
if (!Number.isInteger(runFlags['wait-timeout']) || runFlags['wait-timeout'] <= 0) {
|
|
58
|
+
this.error('--wait-timeout must be a positive integer.', { exit: 2 });
|
|
59
|
+
}
|
|
60
|
+
if (runFlags.resume !== undefined && runFlags.operation !== undefined) {
|
|
61
|
+
this.error('Use --resume or --operation, not both.', { exit: 2 });
|
|
62
|
+
}
|
|
63
|
+
if (runFlags.resume === undefined && runFlags.operation === undefined) {
|
|
64
|
+
this.error('--operation is required unless --resume is used.', { exit: 2 });
|
|
65
|
+
}
|
|
66
|
+
if (runFlags.resume !== undefined) {
|
|
67
|
+
if (runFlags['deployment-step-id'] !== undefined ||
|
|
68
|
+
runFlags['ignored-metadata-json'] !== undefined ||
|
|
69
|
+
runFlags['recreate-promotion-branch'] === true) {
|
|
70
|
+
this.error('--resume cannot be combined with run request flags.', { exit: 2 });
|
|
71
|
+
}
|
|
72
|
+
return this.execute(() => performPromotionResume({
|
|
73
|
+
hooks: this.hooks(),
|
|
74
|
+
jobExecutionId: runFlags.resume,
|
|
75
|
+
promotionId: args.id,
|
|
76
|
+
timeoutSeconds: runFlags['wait-timeout'],
|
|
77
|
+
wait: runFlags.wait,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
if (runFlags['recreate-promotion-branch'] === true && !runFlags.yes) {
|
|
81
|
+
if (this.jsonEnabled() || !process.stdin.isTTY) {
|
|
82
|
+
this.error('Promotion branch recreation requires confirmation. Pass --yes for headless or JSON execution.', {
|
|
83
|
+
exit: 2,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
const confirmed = await confirm({
|
|
87
|
+
default: false,
|
|
88
|
+
message: `Recreate the promotion branch for ${args.id}? Existing promotion branch changes may be replaced.`,
|
|
89
|
+
});
|
|
90
|
+
if (!confirmed) {
|
|
91
|
+
this.error('Promotion canceled.', { exit: 1 });
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return this.execute(() => performPromotionRun({
|
|
95
|
+
deploymentStepIds: runFlags['deployment-step-id'],
|
|
96
|
+
hooks: this.hooks(),
|
|
97
|
+
ignoredMetadata: parseIgnoredMetadataJson(runFlags['ignored-metadata-json']),
|
|
98
|
+
operation: runFlags.operation,
|
|
99
|
+
promotionId: args.id,
|
|
100
|
+
recreatePromotionBranch: runFlags['recreate-promotion-branch'],
|
|
101
|
+
timeoutSeconds: runFlags['wait-timeout'],
|
|
102
|
+
wait: runFlags.wait,
|
|
103
|
+
}));
|
|
104
|
+
}
|
|
105
|
+
toErrorJson(err) {
|
|
106
|
+
const base = super.toErrorJson(err);
|
|
107
|
+
return promotionRunErrorJson(base, err);
|
|
108
|
+
}
|
|
109
|
+
async execute(action) {
|
|
110
|
+
try {
|
|
111
|
+
const result = await action();
|
|
112
|
+
this.display(() => this.log(formatPromotionRunResult(result)));
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
if (error instanceof PromotionRunValidationError) {
|
|
117
|
+
this.error(error.message, { exit: 2 });
|
|
118
|
+
}
|
|
119
|
+
if (isPromotionRunExecutionError(error)) {
|
|
120
|
+
this.display(() => {
|
|
121
|
+
if (error.result !== undefined) {
|
|
122
|
+
this.log(formatPromotionRunResult(error.result));
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
error.oclif = { exit: 1 };
|
|
126
|
+
}
|
|
127
|
+
throw error;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
hooks() {
|
|
131
|
+
return {
|
|
132
|
+
log: (message) => this.display(() => this.log(message)),
|
|
133
|
+
withSpinner: (message, action) => this.withSpinner(message, action),
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../../../src/commands/cicd/promotion/run.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
2
|
+
import { type WorkCommitResult } from '../../../lib/work-commit.js';
|
|
3
|
+
export default class WorkCommit extends AgentiaCommand {
|
|
4
|
+
static args: {
|
|
5
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
6
|
+
};
|
|
7
|
+
static description: string;
|
|
8
|
+
static examples: string[];
|
|
9
|
+
static flags: {
|
|
10
|
+
action: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
11
|
+
'base-branch': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
12
|
+
cloud: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
13
|
+
'commit-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
14
|
+
'execute-commit': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
file: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
message: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
'metadata-category': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
'metadata-message': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
19
|
+
'metadata-name': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
20
|
+
'metadata-raw-json': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
'metadata-type': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
22
|
+
'platform-experience': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
|
|
23
|
+
'recreate-feature-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
24
|
+
selection: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
25
|
+
stdin: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
26
|
+
wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
27
|
+
'wait-timeout': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
28
|
+
};
|
|
29
|
+
run(): Promise<WorkCommitResult>;
|
|
30
|
+
protected toErrorJson(err: unknown): unknown;
|
|
31
|
+
}
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
import { Args, Flags } from '@oclif/core';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
4
|
+
import { resolveWorkItemId, WorkActiveResolutionError } from '../../../lib/work-active.js';
|
|
5
|
+
import { buildWorkCommitRequest, formatWorkCommitResult, normalizeWorkCommitInput, performWorkCommit, WORK_COMMIT_ACTIONS, WORK_COMMIT_DEFAULT_TIMEOUT_SECONDS, WORK_COMMIT_PLATFORM_EXPERIENCES, WorkCommitJobFailedError, WorkCommitTimeoutError, WorkCommitValidationError, } from '../../../lib/work-commit.js';
|
|
6
|
+
function readStdin() {
|
|
7
|
+
if (process.stdin.isTTY) {
|
|
8
|
+
throw new WorkCommitValidationError('Cannot read --stdin from an interactive terminal. Pipe JSON input or use --file <path>.');
|
|
9
|
+
}
|
|
10
|
+
return new Promise((resolve, reject) => {
|
|
11
|
+
let data = '';
|
|
12
|
+
process.stdin.setEncoding('utf8');
|
|
13
|
+
process.stdin.on('data', (chunk) => {
|
|
14
|
+
data += chunk;
|
|
15
|
+
});
|
|
16
|
+
process.stdin.on('end', () => resolve(data));
|
|
17
|
+
process.stdin.on('error', reject);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
function readJsonFile(path) {
|
|
21
|
+
try {
|
|
22
|
+
return readFileSync(path, 'utf8');
|
|
23
|
+
}
|
|
24
|
+
catch (error) {
|
|
25
|
+
throw new WorkCommitValidationError(`Cannot read JSON request file ${path}: ${error.message}`);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function parseJsonValue(raw, label) {
|
|
29
|
+
try {
|
|
30
|
+
return JSON.parse(raw);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
throw new WorkCommitValidationError(`${label} must contain valid JSON: ${error.message}`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function hasSimpleChangeFlags(flags) {
|
|
37
|
+
return (flags.action !== undefined ||
|
|
38
|
+
flags['metadata-category'] !== undefined ||
|
|
39
|
+
flags['metadata-message'] !== undefined ||
|
|
40
|
+
flags['metadata-name'] !== undefined ||
|
|
41
|
+
flags['metadata-raw-json'] !== undefined ||
|
|
42
|
+
flags['metadata-type'] !== undefined ||
|
|
43
|
+
flags.selection !== undefined);
|
|
44
|
+
}
|
|
45
|
+
function simpleInputFromFlags(flags) {
|
|
46
|
+
const rawJson = flags['metadata-raw-json'] === undefined
|
|
47
|
+
? undefined
|
|
48
|
+
: parseJsonValue(flags['metadata-raw-json'], '--metadata-raw-json');
|
|
49
|
+
return {
|
|
50
|
+
baseBranch: flags['base-branch'] ?? null,
|
|
51
|
+
changes: [
|
|
52
|
+
{
|
|
53
|
+
...(flags.action === undefined ? {} : { a: flags.action }),
|
|
54
|
+
...(flags['metadata-category'] === undefined ? {} : { c: flags['metadata-category'] }),
|
|
55
|
+
...(rawJson === undefined ? {} : { j: rawJson }),
|
|
56
|
+
...(flags['metadata-message'] === undefined ? {} : { m: flags['metadata-message'] }),
|
|
57
|
+
n: flags['metadata-name'],
|
|
58
|
+
...(flags.selection === undefined ? {} : { selections: flags.selection }),
|
|
59
|
+
t: flags['metadata-type'],
|
|
60
|
+
},
|
|
61
|
+
],
|
|
62
|
+
commitId: flags['commit-id'],
|
|
63
|
+
executeCommit: flags['execute-commit'],
|
|
64
|
+
message: flags.message,
|
|
65
|
+
recreateFeatureBranch: flags['recreate-feature-branch'],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
async function jsonInputFromFlags(flags) {
|
|
69
|
+
const raw = flags.file === undefined ? await readStdin() : readJsonFile(flags.file);
|
|
70
|
+
const input = normalizeWorkCommitInput(parseJsonValue(raw, flags.file === undefined ? 'stdin' : flags.file));
|
|
71
|
+
return {
|
|
72
|
+
...input,
|
|
73
|
+
...(flags['base-branch'] === undefined ? {} : { baseBranch: flags['base-branch'] }),
|
|
74
|
+
...(flags['commit-id'] === undefined ? {} : { commitId: flags['commit-id'] }),
|
|
75
|
+
...(flags['execute-commit'] ? {} : { executeCommit: false }),
|
|
76
|
+
...(flags.message === undefined ? {} : { message: flags.message }),
|
|
77
|
+
...(flags['recreate-feature-branch'] ? { recreateFeatureBranch: true } : {}),
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
async function commitInputFromFlags(flags) {
|
|
81
|
+
const jsonModes = [flags.file !== undefined, flags.stdin].filter(Boolean).length;
|
|
82
|
+
const simpleMode = hasSimpleChangeFlags(flags);
|
|
83
|
+
if (jsonModes > 1) {
|
|
84
|
+
throw new WorkCommitValidationError('Use only one JSON input mode: --file or --stdin.');
|
|
85
|
+
}
|
|
86
|
+
if (jsonModes > 0 && simpleMode) {
|
|
87
|
+
throw new WorkCommitValidationError('Use JSON input or simple metadata flags, not both.');
|
|
88
|
+
}
|
|
89
|
+
if (jsonModes > 0) {
|
|
90
|
+
return jsonInputFromFlags(flags);
|
|
91
|
+
}
|
|
92
|
+
if (!simpleMode) {
|
|
93
|
+
throw new WorkCommitValidationError('Requires simple metadata flags such as --metadata-name and --metadata-type, or JSON input with --file/--stdin.');
|
|
94
|
+
}
|
|
95
|
+
return simpleInputFromFlags(flags);
|
|
96
|
+
}
|
|
97
|
+
export default class WorkCommit extends AgentiaCommand {
|
|
98
|
+
static args = {
|
|
99
|
+
id: Args.string({
|
|
100
|
+
description: 'User story ID (defaults to the active work item from `work set`)',
|
|
101
|
+
required: false,
|
|
102
|
+
}),
|
|
103
|
+
};
|
|
104
|
+
static description = [
|
|
105
|
+
'Create and optionally wait for a Copado cloud commit job for a user story.',
|
|
106
|
+
'Preflights the story, submits POST /release/commit, and polls the job monitor by default.',
|
|
107
|
+
].join(' ');
|
|
108
|
+
static examples = [
|
|
109
|
+
'<%= config.bin %> <%= command.id %> --cloud --message "Commit AccountService" --metadata-name AccountService --metadata-type ApexClass --action Add',
|
|
110
|
+
'<%= config.bin %> <%= command.id %> a07XXXXXXXXXXXXXXX --cloud --message "Update Aura files" --metadata-name accountEditor --metadata-type AuraDefinitionBundle --action SelectiveCommit --selection accountEditor/accountEditor.cmp --selection accountEditor/accountEditorController.js',
|
|
111
|
+
'cat commit-request.json | <%= config.bin %> <%= command.id %> --cloud --stdin --json',
|
|
112
|
+
];
|
|
113
|
+
static flags = {
|
|
114
|
+
action: Flags.string({
|
|
115
|
+
description: 'Metadata action for simple flag input. Defaults to Add.',
|
|
116
|
+
options: [...WORK_COMMIT_ACTIONS],
|
|
117
|
+
}),
|
|
118
|
+
'base-branch': Flags.string({
|
|
119
|
+
description: 'Optional base branch to include in the commit request.',
|
|
120
|
+
}),
|
|
121
|
+
cloud: Flags.boolean({
|
|
122
|
+
default: false,
|
|
123
|
+
description: 'Use the Copado cloud commit API. Required for this command.',
|
|
124
|
+
}),
|
|
125
|
+
'commit-id': Flags.string({
|
|
126
|
+
description: 'Existing local Git commit identifier to register when --no-execute-commit is used.',
|
|
127
|
+
}),
|
|
128
|
+
'execute-commit': Flags.boolean({
|
|
129
|
+
allowNo: true,
|
|
130
|
+
default: true,
|
|
131
|
+
description: 'Execute the Copado commit job. Use --no-execute-commit only with --commit-id.',
|
|
132
|
+
}),
|
|
133
|
+
file: Flags.string({
|
|
134
|
+
char: 'f',
|
|
135
|
+
description: 'Path to a JSON commit request body.',
|
|
136
|
+
}),
|
|
137
|
+
message: Flags.string({
|
|
138
|
+
char: 'm',
|
|
139
|
+
description: 'Commit message. Required unless provided by JSON input.',
|
|
140
|
+
}),
|
|
141
|
+
'metadata-category': Flags.string({
|
|
142
|
+
description: 'Optional metadata category for simple flag input, usually SFDX.',
|
|
143
|
+
}),
|
|
144
|
+
'metadata-message': Flags.string({
|
|
145
|
+
description: 'Optional per-change message for simple flag input.',
|
|
146
|
+
}),
|
|
147
|
+
'metadata-name': Flags.string({
|
|
148
|
+
description: 'Metadata full name for simple flag input.',
|
|
149
|
+
}),
|
|
150
|
+
'metadata-raw-json': Flags.string({
|
|
151
|
+
description: 'Optional raw metadata JSON value for simple flag input.',
|
|
152
|
+
}),
|
|
153
|
+
'metadata-type': Flags.string({
|
|
154
|
+
description: 'Metadata type for simple flag input, for example ApexClass.',
|
|
155
|
+
}),
|
|
156
|
+
'platform-experience': Flags.string({
|
|
157
|
+
default: 'sfdx',
|
|
158
|
+
description: 'Initial platform-experience header for preflight. The preflight response wins for commit.',
|
|
159
|
+
options: [...WORK_COMMIT_PLATFORM_EXPERIENCES],
|
|
160
|
+
}),
|
|
161
|
+
'recreate-feature-branch': Flags.boolean({
|
|
162
|
+
default: false,
|
|
163
|
+
description: 'Ask Copado to recreate the feature branch before committing.',
|
|
164
|
+
}),
|
|
165
|
+
selection: Flags.string({
|
|
166
|
+
description: 'Selected file inside a bundle for SelectiveCommit. Can be provided multiple times.',
|
|
167
|
+
multiple: true,
|
|
168
|
+
}),
|
|
169
|
+
stdin: Flags.boolean({
|
|
170
|
+
default: false,
|
|
171
|
+
description: 'Read a JSON commit request body from stdin.',
|
|
172
|
+
}),
|
|
173
|
+
wait: Flags.boolean({
|
|
174
|
+
allowNo: true,
|
|
175
|
+
default: true,
|
|
176
|
+
description: 'Poll the commit job to a terminal status when a jobExecution Id is returned.',
|
|
177
|
+
}),
|
|
178
|
+
'wait-timeout': Flags.integer({
|
|
179
|
+
default: WORK_COMMIT_DEFAULT_TIMEOUT_SECONDS,
|
|
180
|
+
description: 'Maximum seconds to wait for the commit job.',
|
|
181
|
+
}),
|
|
182
|
+
};
|
|
183
|
+
async run() {
|
|
184
|
+
const { args, flags } = await this.parse(WorkCommit);
|
|
185
|
+
const commitFlags = flags;
|
|
186
|
+
if (!commitFlags.cloud) {
|
|
187
|
+
this.error('Only cloud commit is supported for now. Pass --cloud to use POST /release/commit.', { exit: 2 });
|
|
188
|
+
}
|
|
189
|
+
if (!Number.isInteger(commitFlags['wait-timeout']) || commitFlags['wait-timeout'] <= 0) {
|
|
190
|
+
this.error('--wait-timeout must be a positive integer.', { exit: 2 });
|
|
191
|
+
}
|
|
192
|
+
let workItemId;
|
|
193
|
+
try {
|
|
194
|
+
workItemId = await resolveWorkItemId(args.id);
|
|
195
|
+
}
|
|
196
|
+
catch (error) {
|
|
197
|
+
if (error instanceof WorkActiveResolutionError) {
|
|
198
|
+
this.error(error.message, {
|
|
199
|
+
exit: 1,
|
|
200
|
+
suggestions: [`${this.config.bin} cicd work set <id>`],
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
throw error;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const input = await commitInputFromFlags(commitFlags);
|
|
207
|
+
const request = buildWorkCommitRequest(input, { message: commitFlags.message, userStoryId: workItemId });
|
|
208
|
+
const result = await performWorkCommit({
|
|
209
|
+
hooks: {
|
|
210
|
+
log: (message) => this.display(() => this.log(message)),
|
|
211
|
+
withSpinner: (message, action) => this.withSpinner(message, action),
|
|
212
|
+
},
|
|
213
|
+
initialPlatformExperience: commitFlags['platform-experience'],
|
|
214
|
+
request,
|
|
215
|
+
timeoutSeconds: commitFlags['wait-timeout'],
|
|
216
|
+
wait: commitFlags.wait,
|
|
217
|
+
});
|
|
218
|
+
this.display(() => {
|
|
219
|
+
this.log(formatWorkCommitResult(result));
|
|
220
|
+
});
|
|
221
|
+
return result;
|
|
222
|
+
}
|
|
223
|
+
catch (error) {
|
|
224
|
+
if (error instanceof WorkCommitValidationError) {
|
|
225
|
+
this.error(error.message, { exit: 2 });
|
|
226
|
+
}
|
|
227
|
+
if (error instanceof WorkCommitJobFailedError || error instanceof WorkCommitTimeoutError) {
|
|
228
|
+
this.display(() => {
|
|
229
|
+
if (error.result !== undefined) {
|
|
230
|
+
this.log(formatWorkCommitResult(error.result));
|
|
231
|
+
}
|
|
232
|
+
});
|
|
233
|
+
error.oclif = { exit: 1 };
|
|
234
|
+
throw error;
|
|
235
|
+
}
|
|
236
|
+
throw error;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
toErrorJson(err) {
|
|
240
|
+
const base = super.toErrorJson(err);
|
|
241
|
+
if (err instanceof WorkCommitJobFailedError || err instanceof WorkCommitTimeoutError) {
|
|
242
|
+
return {
|
|
243
|
+
...base,
|
|
244
|
+
error: {
|
|
245
|
+
...(base.error && typeof base.error === 'object' ? base.error : {}),
|
|
246
|
+
...(err.jobMonitor === undefined ? {} : { jobMonitor: err.jobMonitor }),
|
|
247
|
+
...(err.result === undefined ? {} : { result: err.result }),
|
|
248
|
+
},
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
return base;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
//# sourceMappingURL=commit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commit.js","sourceRoot":"","sources":["../../../../src/commands/cicd/work/commit.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
2
|
+
import { type PromotionRunResult } from '../../../lib/promotion-run.js';
|
|
3
|
+
export type WorkPromoteResult = PromotionRunResult & {
|
|
4
|
+
workItemId: string;
|
|
5
|
+
};
|
|
6
|
+
export default class WorkPromote extends AgentiaCommand {
|
|
7
|
+
static args: {
|
|
8
|
+
id: import("@oclif/core/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
9
|
+
};
|
|
10
|
+
static description: string;
|
|
11
|
+
static examples: string[];
|
|
12
|
+
static flags: {
|
|
13
|
+
cloud: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
14
|
+
deploy: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
'deployment-step-id': import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
16
|
+
'ignored-metadata-json': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
17
|
+
'promotion-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
18
|
+
'recreate-promotion-branch': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
19
|
+
wait: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
20
|
+
'wait-timeout': import("@oclif/core/interfaces").OptionFlag<number, import("@oclif/core/interfaces").CustomOptions>;
|
|
21
|
+
yes: import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
22
|
+
};
|
|
23
|
+
run(): Promise<WorkPromoteResult>;
|
|
24
|
+
protected toErrorJson(err: unknown): unknown;
|
|
25
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { confirm } from '@inquirer/prompts';
|
|
2
|
+
import { Args, Flags } from '@oclif/core';
|
|
3
|
+
import { AgentiaCommand } from '../../../lib/agentia-command.js';
|
|
4
|
+
import { formatPromotionRunResult, isPromotionRunExecutionError, parseIgnoredMetadataJson, performPromotionRun, PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS, promotionRunErrorJson, PromotionRunValidationError, resolvePromotionIdForWorkItem, } from '../../../lib/promotion-run.js';
|
|
5
|
+
import { resolveWorkItemId, WorkActiveResolutionError } from '../../../lib/work-active.js';
|
|
6
|
+
export default class WorkPromote extends AgentiaCommand {
|
|
7
|
+
static args = {
|
|
8
|
+
id: Args.string({
|
|
9
|
+
description: 'User Story ID (defaults to the active work item from `work set`)',
|
|
10
|
+
required: false,
|
|
11
|
+
}),
|
|
12
|
+
};
|
|
13
|
+
static description = [
|
|
14
|
+
'Promote the explicit or active User Story through its Copado Promotion.',
|
|
15
|
+
'Requires --cloud and selects promote-only unless --deploy is passed.',
|
|
16
|
+
].join(' ');
|
|
17
|
+
static examples = [
|
|
18
|
+
'<%= config.bin %> <%= command.id %> --cloud',
|
|
19
|
+
'<%= config.bin %> <%= command.id %> a07XXXXXXXXXXXXXXX --cloud --promotion-id a0BXXXXXXXXXXXXXXX',
|
|
20
|
+
'<%= config.bin %> <%= command.id %> --cloud --deploy --json',
|
|
21
|
+
];
|
|
22
|
+
static flags = {
|
|
23
|
+
cloud: Flags.boolean({
|
|
24
|
+
default: false,
|
|
25
|
+
description: 'Use the Copado cloud promotion API. Required for this command.',
|
|
26
|
+
}),
|
|
27
|
+
deploy: Flags.boolean({
|
|
28
|
+
default: false,
|
|
29
|
+
description: 'Use merge_and_deploy instead of promote-only merge.',
|
|
30
|
+
}),
|
|
31
|
+
'deployment-step-id': Flags.string({
|
|
32
|
+
description: 'Ordered deployment-step Salesforce ID. Can be provided multiple times with --deploy.',
|
|
33
|
+
multiple: true,
|
|
34
|
+
}),
|
|
35
|
+
'ignored-metadata-json': Flags.string({
|
|
36
|
+
description: 'JSON array to persist through ignored-metadata before starting the promotion.',
|
|
37
|
+
}),
|
|
38
|
+
'promotion-id': Flags.string({
|
|
39
|
+
description: 'Explicit 18-character Promotion ID when the User Story belongs to multiple promotions.',
|
|
40
|
+
}),
|
|
41
|
+
'recreate-promotion-branch': Flags.boolean({
|
|
42
|
+
description: 'Recreate the promotion branch before execution. Requires confirmation or --yes.',
|
|
43
|
+
}),
|
|
44
|
+
wait: Flags.boolean({
|
|
45
|
+
allowNo: true,
|
|
46
|
+
default: true,
|
|
47
|
+
description: 'Poll promotion and deployment executions to terminal status.',
|
|
48
|
+
}),
|
|
49
|
+
'wait-timeout': Flags.integer({
|
|
50
|
+
default: PROMOTION_RUN_DEFAULT_TIMEOUT_SECONDS,
|
|
51
|
+
description: 'Maximum total seconds to wait for promotion and deployment executions.',
|
|
52
|
+
}),
|
|
53
|
+
yes: Flags.boolean({
|
|
54
|
+
char: 'y',
|
|
55
|
+
default: false,
|
|
56
|
+
description: 'Confirm promotion branch recreation without prompting.',
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
async run() {
|
|
60
|
+
const { args, flags } = await this.parse(WorkPromote);
|
|
61
|
+
const promoteFlags = flags;
|
|
62
|
+
if (!promoteFlags.cloud) {
|
|
63
|
+
this.error('Only cloud promotion is supported for this command. Pass --cloud.', { exit: 2 });
|
|
64
|
+
}
|
|
65
|
+
if (!Number.isInteger(promoteFlags['wait-timeout']) || promoteFlags['wait-timeout'] <= 0) {
|
|
66
|
+
this.error('--wait-timeout must be a positive integer.', { exit: 2 });
|
|
67
|
+
}
|
|
68
|
+
if (!promoteFlags.deploy && promoteFlags['deployment-step-id'] !== undefined) {
|
|
69
|
+
this.error('--deployment-step-id requires --deploy.', { exit: 2 });
|
|
70
|
+
}
|
|
71
|
+
let workItemId;
|
|
72
|
+
try {
|
|
73
|
+
workItemId = await resolveWorkItemId(args.id);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error instanceof WorkActiveResolutionError) {
|
|
77
|
+
this.error(error.message, {
|
|
78
|
+
exit: 1,
|
|
79
|
+
suggestions: [`${this.config.bin} cicd work set <id>`],
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
const promotionId = await this.withSpinner('Resolving User Story promotion', () => resolvePromotionIdForWorkItem(workItemId, promoteFlags['promotion-id']));
|
|
86
|
+
if (promoteFlags['recreate-promotion-branch'] === true && !promoteFlags.yes) {
|
|
87
|
+
if (this.jsonEnabled() || !process.stdin.isTTY) {
|
|
88
|
+
this.error('Promotion branch recreation requires confirmation. Pass --yes for headless or JSON execution.', {
|
|
89
|
+
exit: 2,
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
const confirmed = await confirm({
|
|
93
|
+
default: false,
|
|
94
|
+
message: `Recreate the promotion branch for ${promotionId}? Existing promotion branch changes may be replaced.`,
|
|
95
|
+
});
|
|
96
|
+
if (!confirmed) {
|
|
97
|
+
this.error('Promotion canceled.', { exit: 1 });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
const result = await performPromotionRun({
|
|
101
|
+
deploymentStepIds: promoteFlags['deployment-step-id'],
|
|
102
|
+
hooks: {
|
|
103
|
+
log: (message) => this.display(() => this.log(message)),
|
|
104
|
+
withSpinner: (message, action) => this.withSpinner(message, action),
|
|
105
|
+
},
|
|
106
|
+
ignoredMetadata: parseIgnoredMetadataJson(promoteFlags['ignored-metadata-json']),
|
|
107
|
+
operation: promoteFlags.deploy ? 'merge_and_deploy' : 'merge',
|
|
108
|
+
promotionId,
|
|
109
|
+
recreatePromotionBranch: promoteFlags['recreate-promotion-branch'],
|
|
110
|
+
timeoutSeconds: promoteFlags['wait-timeout'],
|
|
111
|
+
wait: promoteFlags.wait,
|
|
112
|
+
});
|
|
113
|
+
const workResult = { ...result, workItemId };
|
|
114
|
+
this.display(() => {
|
|
115
|
+
this.log(`User Story: ${workItemId}`);
|
|
116
|
+
this.log(formatPromotionRunResult(result));
|
|
117
|
+
});
|
|
118
|
+
return workResult;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error instanceof PromotionRunValidationError) {
|
|
122
|
+
this.error(error.message, { exit: 2 });
|
|
123
|
+
}
|
|
124
|
+
if (isPromotionRunExecutionError(error)) {
|
|
125
|
+
this.display(() => {
|
|
126
|
+
if (error.result !== undefined) {
|
|
127
|
+
this.log(`User Story: ${workItemId}`);
|
|
128
|
+
this.log(formatPromotionRunResult(error.result));
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
error.oclif = { exit: 1 };
|
|
132
|
+
}
|
|
133
|
+
throw error;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
toErrorJson(err) {
|
|
137
|
+
const base = super.toErrorJson(err);
|
|
138
|
+
return promotionRunErrorJson(base, err);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=promote.js.map
|