@copado/agentia-cli 0.115.0-alpha.0 → 0.117.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 +370 -357
- package/dist/commands/cicd/work/commit.d.ts +0 -5
- package/dist/commands/cicd/work/commit.js +18 -33
- package/dist/commands/cicd/work/commit.js.map +1 -1
- package/dist/commands/cicd/work/publish.d.ts +12 -0
- package/dist/commands/cicd/work/publish.js +20 -0
- package/dist/commands/cicd/work/publish.js.map +1 -0
- package/dist/commands/cicd/work/push.d.ts +4 -0
- package/dist/commands/cicd/work/push.js +11 -81
- package/dist/commands/cicd/work/push.js.map +1 -1
- package/dist/commands/cicd/work/set.d.ts +2 -2
- package/dist/commands/cicd/work/set.js +6 -2
- package/dist/commands/cicd/work/set.js.map +1 -1
- package/dist/commands/cicd/work/status.js +14 -13
- package/dist/commands/cicd/work/status.js.map +1 -1
- package/dist/commands/cicd/work/submit.d.ts +2 -0
- package/dist/commands/cicd/work/submit.js +11 -3
- package/dist/commands/cicd/work/submit.js.map +1 -1
- package/dist/commands/cicd/work/test/apex.d.ts +11 -0
- package/dist/commands/cicd/work/test/apex.js +57 -0
- package/dist/commands/cicd/work/test/apex.js.map +1 -0
- package/dist/commands/cicd/work/test.js +12 -4
- package/dist/commands/cicd/work/test.js.map +1 -1
- package/dist/lib/cicd-gateway.d.ts +3 -0
- package/dist/lib/cicd-gateway.js +35 -2
- package/dist/lib/cicd-gateway.js.map +1 -1
- package/dist/lib/defaults-store.d.ts +1 -1
- package/dist/lib/defaults-store.js +1 -1
- package/dist/lib/git-worktree.d.ts +13 -5
- package/dist/lib/git-worktree.js +49 -11
- package/dist/lib/git-worktree.js.map +1 -1
- package/dist/lib/local-quality-gates.d.ts +4 -0
- package/dist/lib/local-quality-gates.js +1 -1
- package/dist/lib/local-quality-gates.js.map +1 -1
- package/dist/lib/mcp/tools.d.ts +12 -2
- package/dist/lib/mcp/tools.js +10 -8
- package/dist/lib/mcp/tools.js.map +1 -1
- package/dist/lib/mcp/work-tools.d.ts +18 -6
- package/dist/lib/mcp/work-tools.js +75 -50
- package/dist/lib/mcp/work-tools.js.map +1 -1
- package/dist/lib/nested-metadata-changes.d.ts +4 -4
- package/dist/lib/setup-templates.d.ts +3 -3
- package/dist/lib/setup-templates.js +34 -29
- package/dist/lib/setup-templates.js.map +1 -1
- package/dist/lib/setup-wizard.js +1 -1
- package/dist/lib/setup-wizard.js.map +1 -1
- package/dist/lib/stock-quality-gates.d.ts +12 -0
- package/dist/lib/stock-quality-gates.js +67 -0
- package/dist/lib/stock-quality-gates.js.map +1 -0
- package/dist/lib/work-apex-test.d.ts +56 -0
- package/dist/lib/work-apex-test.js +265 -0
- package/dist/lib/work-apex-test.js.map +1 -0
- package/dist/lib/work-branch-metadata.d.ts +2 -0
- package/dist/lib/work-branch-metadata.js +9 -0
- package/dist/lib/work-branch-metadata.js.map +1 -1
- package/dist/lib/work-local-commit.d.ts +1 -1
- package/dist/lib/work-local-commit.js +1 -1
- package/dist/lib/work-publish-command.d.ts +26 -0
- package/dist/lib/work-publish-command.js +88 -0
- package/dist/lib/work-publish-command.js.map +1 -0
- package/dist/lib/work-push.d.ts +6 -5
- package/dist/lib/work-push.js +30 -22
- package/dist/lib/work-push.js.map +1 -1
- package/dist/lib/work-set-selection.d.ts +3 -1
- package/dist/lib/work-set-selection.js +19 -1
- package/dist/lib/work-set-selection.js.map +1 -1
- package/dist/lib/work-types.d.ts +12 -1
- package/dist/lib/work-types.js.map +1 -1
- package/oclif.manifest.json +2231 -2151
- package/package.json +4 -1
- package/templates/AGENTS.md +2 -2
- package/templates/skills/agentia-cicd/SKILL.md +4 -3
- package/templates/skills/agentia-cicd/references/work.md +25 -23
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { getMcpRequestSignal } from './mcp/request-context.js';
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
export const DEFAULT_APEX_TEST_WAIT_MINUTES = 60;
|
|
6
|
+
const APEX_TEST_MAX_BUFFER_BYTES = 32 * 1024 * 1024;
|
|
7
|
+
const APEX_TEST_TIMEOUT_BUFFER_MS = 60_000;
|
|
8
|
+
const APEX_CLASS_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_]*(\.[A-Za-z][A-Za-z0-9_]*)?$/;
|
|
9
|
+
const ORG_ID_PATTERN = /\b00D[A-Za-z0-9]{12,15}\b/g;
|
|
10
|
+
const USER_ID_PATTERN = /\b005[A-Za-z0-9]{12,15}\b/g;
|
|
11
|
+
const FAILED_OUTCOMES = new Set(['compilefail', 'fail']);
|
|
12
|
+
export class WorkApexTestError extends Error {
|
|
13
|
+
result;
|
|
14
|
+
constructor(result) {
|
|
15
|
+
const failing = result.summary.failing ?? result.tests.filter((test) => isFailedOutcome(test.outcome)).length;
|
|
16
|
+
super(`Apex tests failed (${failing} failing).`);
|
|
17
|
+
this.name = 'WorkApexTestError';
|
|
18
|
+
this.result = result;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
let sfApexTestExecFn = defaultSfApexTestExec;
|
|
22
|
+
export function buildSfApexTestArgs(classNames, waitMinutes) {
|
|
23
|
+
return ['apex', 'run', 'test', '--class-names', ...classNames, '-c', '--json', '--wait', String(waitMinutes)];
|
|
24
|
+
}
|
|
25
|
+
export function parseApexTestClassNames(value) {
|
|
26
|
+
const names = value
|
|
27
|
+
.split(/[,\s]+/)
|
|
28
|
+
.map((name) => name.trim())
|
|
29
|
+
.filter((name) => name.length > 0);
|
|
30
|
+
if (names.length === 0) {
|
|
31
|
+
throw new Error('Requires `--apex-test-classes`.');
|
|
32
|
+
}
|
|
33
|
+
const unique = [];
|
|
34
|
+
const seen = new Set();
|
|
35
|
+
for (const name of names) {
|
|
36
|
+
if (!APEX_CLASS_NAME_PATTERN.test(name)) {
|
|
37
|
+
throw new Error(`Invalid Apex test class name '${name}'. Use identifiers such as MyTest or Namespace.MyTest.`);
|
|
38
|
+
}
|
|
39
|
+
if (seen.has(name)) {
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
seen.add(name);
|
|
43
|
+
unique.push(name);
|
|
44
|
+
}
|
|
45
|
+
return unique;
|
|
46
|
+
}
|
|
47
|
+
export function validateApexTestWaitMinutes(waitMinutes) {
|
|
48
|
+
if (!Number.isInteger(waitMinutes) || waitMinutes < 1) {
|
|
49
|
+
throw new Error('`--wait` must be a positive integer number of minutes.');
|
|
50
|
+
}
|
|
51
|
+
return waitMinutes;
|
|
52
|
+
}
|
|
53
|
+
export function formatWorkApexTestHuman(result) {
|
|
54
|
+
const failedTests = result.tests.filter((test) => isFailedOutcome(test.outcome));
|
|
55
|
+
const lines = [
|
|
56
|
+
`Apex tests: ${result.summary.outcome ?? (failedTests.length === 0 ? 'Passed' : 'Failed')}`,
|
|
57
|
+
...summaryLines(result.summary),
|
|
58
|
+
];
|
|
59
|
+
if (failedTests.length === 0) {
|
|
60
|
+
return lines.join('\n');
|
|
61
|
+
}
|
|
62
|
+
return [
|
|
63
|
+
...lines,
|
|
64
|
+
'',
|
|
65
|
+
'Failed tests:',
|
|
66
|
+
...failedTests.flatMap((test) => [
|
|
67
|
+
'',
|
|
68
|
+
testLabel(test),
|
|
69
|
+
...(test.outcome === undefined ? [] : [` Outcome: ${test.outcome}`]),
|
|
70
|
+
...(test.message === undefined ? [] : [` Message: ${test.message}`]),
|
|
71
|
+
...(test.stackTrace === undefined ? [] : [` StackTrace: ${test.stackTrace}`]),
|
|
72
|
+
]),
|
|
73
|
+
].join('\n');
|
|
74
|
+
}
|
|
75
|
+
export async function runWorkApexTests({ classNames, waitMinutes: requestedWaitMinutes, }) {
|
|
76
|
+
const waitMinutes = validateApexTestWaitMinutes(requestedWaitMinutes);
|
|
77
|
+
const args = buildSfApexTestArgs(classNames, waitMinutes);
|
|
78
|
+
let stdout;
|
|
79
|
+
try {
|
|
80
|
+
const executed = await sfApexTestExecFn(args, {
|
|
81
|
+
maxBuffer: APEX_TEST_MAX_BUFFER_BYTES,
|
|
82
|
+
signal: getMcpRequestSignal(),
|
|
83
|
+
timeout: waitMinutes * 60 * 1000 + APEX_TEST_TIMEOUT_BUFFER_MS,
|
|
84
|
+
});
|
|
85
|
+
stdout = executed.stdout;
|
|
86
|
+
}
|
|
87
|
+
catch (error) {
|
|
88
|
+
throw new Error(sanitizeApexTestError(error));
|
|
89
|
+
}
|
|
90
|
+
const parsed = extractJsonObject(stdout);
|
|
91
|
+
if (parsed.result === undefined) {
|
|
92
|
+
throw new Error(sanitizeApexTestError(parsed.message ?? parsed.name ?? 'Salesforce CLI Apex test run failed.'));
|
|
93
|
+
}
|
|
94
|
+
const result = parseSfApexTestJson(stdout, classNames, waitMinutes);
|
|
95
|
+
if (isTestRunFailed(result)) {
|
|
96
|
+
throw new WorkApexTestError(result);
|
|
97
|
+
}
|
|
98
|
+
if (typeof parsed.status === 'number' && parsed.status !== 0) {
|
|
99
|
+
throw new Error(sanitizeApexTestError(parsed.message ?? parsed.name ?? 'Salesforce CLI Apex test run failed.'));
|
|
100
|
+
}
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
export function parseSfApexTestJson(raw, classNames, waitMinutes) {
|
|
104
|
+
const parsed = extractJsonObject(raw);
|
|
105
|
+
if (parsed.result === undefined) {
|
|
106
|
+
throw new Error(sanitizeApexTestError(parsed.message ?? parsed.name ?? 'Salesforce CLI Apex test run failed.'));
|
|
107
|
+
}
|
|
108
|
+
const tests = (parsed.result.tests ?? []).flatMap((item) => {
|
|
109
|
+
const mapped = mapTestMethod(item);
|
|
110
|
+
return mapped === undefined ? [] : [mapped];
|
|
111
|
+
});
|
|
112
|
+
const summary = mapSummary(parsed.result.summary ?? {});
|
|
113
|
+
return {
|
|
114
|
+
classNames,
|
|
115
|
+
summary,
|
|
116
|
+
tests,
|
|
117
|
+
waitMinutes,
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
export function setSfApexTestExecForTests(fn) {
|
|
121
|
+
sfApexTestExecFn = fn;
|
|
122
|
+
}
|
|
123
|
+
export function resetSfApexTestExecForTests() {
|
|
124
|
+
sfApexTestExecFn = defaultSfApexTestExec;
|
|
125
|
+
}
|
|
126
|
+
async function defaultSfApexTestExec(args, options) {
|
|
127
|
+
try {
|
|
128
|
+
const { stderr, stdout } = await execFileAsync('sf', args, {
|
|
129
|
+
encoding: 'utf8',
|
|
130
|
+
maxBuffer: options.maxBuffer,
|
|
131
|
+
signal: options.signal,
|
|
132
|
+
timeout: options.timeout,
|
|
133
|
+
});
|
|
134
|
+
return { stderr: stderr.toString(), stdout: stdout.toString() };
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
if (isExecFileError(error) && typeof error.stdout === 'string' && error.stdout.trim().length > 0) {
|
|
138
|
+
return {
|
|
139
|
+
stderr: typeof error.stderr === 'string' ? error.stderr : '',
|
|
140
|
+
stdout: error.stdout,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
throw error;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function extractJsonObject(raw) {
|
|
147
|
+
const start = raw.indexOf('{');
|
|
148
|
+
if (start === -1) {
|
|
149
|
+
throw new Error('Salesforce CLI returned non-JSON output.');
|
|
150
|
+
}
|
|
151
|
+
return JSON.parse(raw.slice(start));
|
|
152
|
+
}
|
|
153
|
+
function mapSummary(summary) {
|
|
154
|
+
return {
|
|
155
|
+
...(optionalString(summary.commandTime) === undefined ? {} : { commandTime: optionalString(summary.commandTime) }),
|
|
156
|
+
...(optionalString(summary.failRate) === undefined ? {} : { failRate: optionalString(summary.failRate) }),
|
|
157
|
+
...(optionalNumber(summary.failing) === undefined ? {} : { failing: optionalNumber(summary.failing) }),
|
|
158
|
+
...(optionalString(summary.orgWideCoverage) === undefined
|
|
159
|
+
? {}
|
|
160
|
+
: { orgWideCoverage: optionalString(summary.orgWideCoverage) }),
|
|
161
|
+
...(optionalString(summary.outcome) === undefined ? {} : { outcome: optionalString(summary.outcome) }),
|
|
162
|
+
...(optionalString(summary.passRate) === undefined ? {} : { passRate: optionalString(summary.passRate) }),
|
|
163
|
+
...(optionalNumber(summary.passing) === undefined ? {} : { passing: optionalNumber(summary.passing) }),
|
|
164
|
+
...(optionalNumber(summary.skipped) === undefined ? {} : { skipped: optionalNumber(summary.skipped) }),
|
|
165
|
+
...(optionalString(summary.testExecutionTime) === undefined
|
|
166
|
+
? {}
|
|
167
|
+
: { testExecutionTime: optionalString(summary.testExecutionTime) }),
|
|
168
|
+
...(optionalString(summary.testRunCoverage) === undefined
|
|
169
|
+
? {}
|
|
170
|
+
: { testRunCoverage: optionalString(summary.testRunCoverage) }),
|
|
171
|
+
...(optionalString(summary.testRunId) === undefined ? {} : { testRunId: optionalString(summary.testRunId) }),
|
|
172
|
+
...(optionalString(summary.testStartTime) === undefined
|
|
173
|
+
? {}
|
|
174
|
+
: { testStartTime: optionalString(summary.testStartTime) }),
|
|
175
|
+
...(optionalString(summary.testTotalTime) === undefined ? {} : { testTotalTime: optionalString(summary.testTotalTime) }),
|
|
176
|
+
...(optionalNumber(summary.testsRan) === undefined ? {} : { testsRan: optionalNumber(summary.testsRan) }),
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
function mapTestMethod(value) {
|
|
180
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
181
|
+
return undefined;
|
|
182
|
+
}
|
|
183
|
+
const record = value;
|
|
184
|
+
const apexClass = record.ApexClass !== null && typeof record.ApexClass === 'object' && !Array.isArray(record.ApexClass)
|
|
185
|
+
? record.ApexClass
|
|
186
|
+
: undefined;
|
|
187
|
+
const mapped = {
|
|
188
|
+
...(optionalString(apexClass?.Name) === undefined ? {} : { className: optionalString(apexClass?.Name) }),
|
|
189
|
+
...(optionalString(record.FullName) === undefined ? {} : { fullName: optionalString(record.FullName) }),
|
|
190
|
+
...(optionalString(record.Message) === undefined ? {} : { message: optionalString(record.Message) }),
|
|
191
|
+
...(optionalString(record.MethodName) === undefined ? {} : { methodName: optionalString(record.MethodName) }),
|
|
192
|
+
...(optionalString(record.Outcome) === undefined ? {} : { outcome: optionalString(record.Outcome) }),
|
|
193
|
+
...(optionalString(record.StackTrace) === undefined ? {} : { stackTrace: optionalString(record.StackTrace) }),
|
|
194
|
+
};
|
|
195
|
+
return Object.keys(mapped).length === 0 ? undefined : mapped;
|
|
196
|
+
}
|
|
197
|
+
function isTestRunFailed(result) {
|
|
198
|
+
if (result.tests.some((test) => isFailedOutcome(test.outcome))) {
|
|
199
|
+
return true;
|
|
200
|
+
}
|
|
201
|
+
const outcome = result.summary.outcome?.trim().toLowerCase();
|
|
202
|
+
return outcome === 'failed' || (result.summary.failing ?? 0) > 0;
|
|
203
|
+
}
|
|
204
|
+
function isFailedOutcome(outcome) {
|
|
205
|
+
return outcome !== undefined && FAILED_OUTCOMES.has(outcome.trim().toLowerCase());
|
|
206
|
+
}
|
|
207
|
+
function testLabel(test) {
|
|
208
|
+
if (test.fullName !== undefined && test.fullName.length > 0) {
|
|
209
|
+
return test.fullName;
|
|
210
|
+
}
|
|
211
|
+
const joined = [test.className, test.methodName]
|
|
212
|
+
.filter((part) => part !== undefined && part.length > 0)
|
|
213
|
+
.join('.');
|
|
214
|
+
return joined.length > 0 ? joined : 'unknown test';
|
|
215
|
+
}
|
|
216
|
+
function summaryLines(summary) {
|
|
217
|
+
const lines = [];
|
|
218
|
+
pushLine(lines, 'Tests ran', summary.testsRan);
|
|
219
|
+
pushLine(lines, 'Passing', summary.passing);
|
|
220
|
+
pushLine(lines, 'Failing', summary.failing);
|
|
221
|
+
pushLine(lines, 'Skipped', summary.skipped);
|
|
222
|
+
pushLine(lines, 'Pass rate', summary.passRate);
|
|
223
|
+
pushLine(lines, 'Fail rate', summary.failRate);
|
|
224
|
+
pushLine(lines, 'Test run coverage', summary.testRunCoverage);
|
|
225
|
+
pushLine(lines, 'Org-wide coverage', summary.orgWideCoverage);
|
|
226
|
+
pushLine(lines, 'Test execution time', summary.testExecutionTime);
|
|
227
|
+
return lines;
|
|
228
|
+
}
|
|
229
|
+
function pushLine(lines, label, value) {
|
|
230
|
+
if (value === undefined || value === '') {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
lines.push(`${label}: ${value}`);
|
|
234
|
+
}
|
|
235
|
+
function optionalString(value) {
|
|
236
|
+
if (typeof value !== 'string') {
|
|
237
|
+
return undefined;
|
|
238
|
+
}
|
|
239
|
+
const sanitized = sanitizeIdentity(value).trim();
|
|
240
|
+
return sanitized.length === 0 ? undefined : sanitized;
|
|
241
|
+
}
|
|
242
|
+
function optionalNumber(value) {
|
|
243
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
|
|
244
|
+
}
|
|
245
|
+
function sanitizeApexTestError(error) {
|
|
246
|
+
if (isExecFileError(error) && error.code === 'ENOENT') {
|
|
247
|
+
return 'Salesforce CLI (`sf`) is not installed or is not on PATH.';
|
|
248
|
+
}
|
|
249
|
+
if (error instanceof Error && error.name === 'AbortError') {
|
|
250
|
+
return 'Apex test run was cancelled.';
|
|
251
|
+
}
|
|
252
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
253
|
+
const cleaned = sanitizeIdentity(message).trim();
|
|
254
|
+
if (cleaned.length === 0) {
|
|
255
|
+
return 'Salesforce CLI Apex test run failed.';
|
|
256
|
+
}
|
|
257
|
+
return `Salesforce CLI Apex test run failed: ${cleaned}`;
|
|
258
|
+
}
|
|
259
|
+
function sanitizeIdentity(value) {
|
|
260
|
+
return value.replaceAll(ORG_ID_PATTERN, '<org-id>').replaceAll(USER_ID_PATTERN, '<user-id>');
|
|
261
|
+
}
|
|
262
|
+
function isExecFileError(error) {
|
|
263
|
+
return error instanceof Error;
|
|
264
|
+
}
|
|
265
|
+
//# sourceMappingURL=work-apex-test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-apex-test.js","sourceRoot":"","sources":["../../src/lib/work-apex-test.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,3 +9,5 @@ export type WorkBranchMetadataResult = {
|
|
|
9
9
|
metadataList: WorkBranchMetadataItem[];
|
|
10
10
|
};
|
|
11
11
|
export declare function resolveWorkBranchMetadata(baseRef: string, moduleType?: ModuleType): Promise<WorkBranchMetadataResult>;
|
|
12
|
+
/** Local branch metadata when `work set` recorded lastBaseBranch; otherwise undefined. */
|
|
13
|
+
export declare function resolveRecordedWorkBranchMetadata(moduleType?: ModuleType): Promise<undefined | WorkBranchMetadataResult>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { readLastBaseBranch } from './defaults-store.js';
|
|
1
2
|
import { resolvedSelectionsFromChangedFiles } from './dependency-from-changes.js';
|
|
2
3
|
const NO_METADATA_MESSAGES = [
|
|
3
4
|
'No changed files were found',
|
|
@@ -28,4 +29,12 @@ export async function resolveWorkBranchMetadata(baseRef, moduleType) {
|
|
|
28
29
|
return { baseRef, metadataList: [] };
|
|
29
30
|
}
|
|
30
31
|
}
|
|
32
|
+
/** Local branch metadata when `work set` recorded lastBaseBranch; otherwise undefined. */
|
|
33
|
+
export async function resolveRecordedWorkBranchMetadata(moduleType) {
|
|
34
|
+
const baseRef = (await readLastBaseBranch())?.trim();
|
|
35
|
+
if (!baseRef) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return resolveWorkBranchMetadata(baseRef, moduleType);
|
|
39
|
+
}
|
|
31
40
|
//# sourceMappingURL=work-branch-metadata.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"work-branch-metadata.js","sourceRoot":"","sources":["../../src/lib/work-branch-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kCAAkC,EAAC,MAAM,8BAA8B,CAAA;AAc/E,MAAM,oBAAoB,GAAG;IAC3B,6BAA6B;IAC7B,8CAA8C;CAC/C,CAAA;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAe,EACf,UAAuB;IAEvB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,kCAAkC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAEhF,OAAO;YACL,OAAO;YACP,YAAY,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,EAAC,UAAU,EAAE,SAAS,EAAC,EAAE,EAAE,CAAC,CAAC;gBACzD,UAAU;gBACV,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,IAAI,EAAE,SAAS,CAAC,IAAI;aACrB,CAAC,CAAC;SACJ,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,KAAK,CAAA;QACb,CAAC;QAED,OAAO,EAAC,OAAO,EAAE,YAAY,EAAE,EAAE,EAAC,CAAA;IACpC,CAAC;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"work-branch-metadata.js","sourceRoot":"","sources":["../../src/lib/work-branch-metadata.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,kBAAkB,EAAC,MAAM,qBAAqB,CAAA;AACtD,OAAO,EAAC,kCAAkC,EAAC,MAAM,8BAA8B,CAAA;AAc/E,MAAM,oBAAoB,GAAG;IAC3B,6BAA6B;IAC7B,8CAA8C;CAC/C,CAAA;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,CAAC,KAAK,YAAY,KAAK,CAAC,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAA;IACd,CAAC;IAED,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAC7C,OAAe,EACf,UAAuB;IAEvB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,MAAM,kCAAkC,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;QAEhF,OAAO;YACL,OAAO;YACP,YAAY,EAAE,UAAU,CAAC,GAAG,CAAC,CAAC,EAAC,UAAU,EAAE,SAAS,EAAC,EAAE,EAAE,CAAC,CAAC;gBACzD,UAAU;gBACV,IAAI,EAAE,SAAS,CAAC,IAAI;gBACpB,IAAI,EAAE,SAAS,CAAC,IAAI;aACrB,CAAC,CAAC;SACJ,CAAA;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;YAC9B,MAAM,KAAK,CAAA;QACb,CAAC;QAED,OAAO,EAAC,OAAO,EAAE,YAAY,EAAE,EAAE,EAAC,CAAA;IACpC,CAAC;AACH,CAAC;AAED,0FAA0F;AAC1F,MAAM,CAAC,KAAK,UAAU,iCAAiC,CACrD,UAAuB;IAEvB,MAAM,OAAO,GAAG,CAAC,MAAM,kBAAkB,EAAE,CAAC,EAAE,IAAI,EAAE,CAAA;IACpD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAA;IAClB,CAAC;IAED,OAAO,yBAAyB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;AACvD,CAAC"}
|
|
@@ -35,7 +35,7 @@ export declare function resolveWorkLocalCommitMessage(explicitMessage?: string):
|
|
|
35
35
|
workItem?: string;
|
|
36
36
|
}>;
|
|
37
37
|
/**
|
|
38
|
-
* Runs a plain `git commit` and records the Copado selections consumed later by `cicd work
|
|
38
|
+
* Runs a plain `git commit` and records the Copado selections consumed later by `cicd work publish`.
|
|
39
39
|
* No gateway call is made.
|
|
40
40
|
*/
|
|
41
41
|
export declare function performWorkLocalCommit(input: WorkLocalCommitInput): Promise<WorkLocalCommitResult>;
|
|
@@ -83,7 +83,7 @@ function gitFailureMessage(error) {
|
|
|
83
83
|
return detail.length > 0 ? detail : error instanceof Error ? error.message : String(error);
|
|
84
84
|
}
|
|
85
85
|
/**
|
|
86
|
-
* Runs a plain `git commit` and records the Copado selections consumed later by `cicd work
|
|
86
|
+
* Runs a plain `git commit` and records the Copado selections consumed later by `cicd work publish`.
|
|
87
87
|
* No gateway call is made.
|
|
88
88
|
*/
|
|
89
89
|
export async function performWorkLocalCommit(input) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type WorkPushResult } from './work-types.js';
|
|
2
|
+
export declare const WORK_PUBLISH_DESCRIPTION: string;
|
|
3
|
+
export declare const workPublishFlags: {
|
|
4
|
+
readonly 'full-metadata': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
5
|
+
readonly permissions: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
|
|
6
|
+
readonly 'skip-nested-metadata-detection': import("@oclif/core/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
};
|
|
8
|
+
export type WorkPublishFlagValues = {
|
|
9
|
+
'full-metadata'?: string;
|
|
10
|
+
permissions?: string;
|
|
11
|
+
'skip-nested-metadata-detection'?: boolean;
|
|
12
|
+
};
|
|
13
|
+
export type WorkPublishHost = {
|
|
14
|
+
config: {
|
|
15
|
+
bin: string;
|
|
16
|
+
};
|
|
17
|
+
display(render: () => void): void;
|
|
18
|
+
error(input: Error | string, options?: {
|
|
19
|
+
exit?: false | number;
|
|
20
|
+
suggestions?: string[];
|
|
21
|
+
}): never;
|
|
22
|
+
log(message?: string, ...args: string[]): void;
|
|
23
|
+
logElapsed(startedAtMs: number): void;
|
|
24
|
+
withSpinner<T>(message: string, action: () => Promise<T>): Promise<T>;
|
|
25
|
+
};
|
|
26
|
+
export declare function runWorkPublish(command: WorkPublishHost, flags: WorkPublishFlagValues): Promise<WorkPushResult>;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Flags } from '@oclif/core';
|
|
2
|
+
import { listPendingChanges } from './git-worktree.js';
|
|
3
|
+
import { performWorkPush, resolveWorkPushContext, WorkPushValidationError } from './work-push.js';
|
|
4
|
+
export const WORK_PUBLISH_DESCRIPTION = [
|
|
5
|
+
'Publish the current feature/<lastWorkItem> branch and register commits with Copado.',
|
|
6
|
+
'Requires a clean working tree, base branch, and dev org branch from `.agentia/config.user.json`.',
|
|
7
|
+
'Fetches origin/<lastBaseBranch>, then registers only commits in origin/<lastBaseBranch>..HEAD and diffs nested parent XML at merge-base(origin/<lastBaseBranch>, HEAD) versus HEAD, so origin/base-only history is ignored.',
|
|
8
|
+
'When there are no commits since origin/<lastBaseBranch>, or origin already has HEAD, fails with "No changes to publish" unless `--permissions` and/or `--full-metadata` is set, in which case it creates an empty commit so a tip commit id exists.',
|
|
9
|
+
'Applies Copado environment-variable then yaml replacements when needed, commits both as a single follow-up commit, locks the tip commit, runs `git push origin <branch>`,',
|
|
10
|
+
'reports the nested metadata changed across the branch, such as the CustomField behind a profile field-permission edit, plus the parent components it would ignore,',
|
|
11
|
+
'calls headless work/push with one changeListUpdate list of Action:MetadataType:MetadataName corrections: lastPermissionSelected and --permissions plus the nested metadata of the changed profiles and permission sets as RetrieveOnly, lastFullMetadataSelected and --full-metadata plus brand-new nested parent files as fullMetadata, the ignored parents as unchanged, the nested metadata deleted on the branch as Del, and the remaining nested metadata as Add, then merges the feature branch into the recorded dev org branch.',
|
|
12
|
+
'The changed profiles and permission sets themselves are never sent as corrections, so they stay in the change list and deploy only the permissions their RetrieveOnly entries select. Brand-new nested parent files are an exception: they are sent as fullMetadata so the complete file travels.',
|
|
13
|
+
'`cicd work push` is a compatibility alias of this command.',
|
|
14
|
+
].join(' ');
|
|
15
|
+
export const workPublishFlags = {
|
|
16
|
+
'full-metadata': Flags.string({
|
|
17
|
+
description: 'Comma-separated type-prefixed metadata such as Profile:Sales_User,PermissionSet:Sales_Onboarding, added for this publish and sent as headless push fullMetadata corrections. The named metadata is committed as a complete file, so it is never decomposed into nested metadata. Not stored.',
|
|
18
|
+
}),
|
|
19
|
+
permissions: Flags.string({
|
|
20
|
+
description: 'Comma-separated type-prefixed metadata such as CustomField:Account.SLA__c,ApexClass:AccountService, added for this publish and sent as headless push RetrieveOnly corrections. Not stored.',
|
|
21
|
+
}),
|
|
22
|
+
'skip-nested-metadata-detection': Flags.boolean({
|
|
23
|
+
default: false,
|
|
24
|
+
description: 'Do not detect the nested metadata changed across the branch (also configurable via skipNestedMetadataDetection in .agentia/config.json or .agentia/config.user.json)',
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
export async function runWorkPublish(command, flags) {
|
|
28
|
+
const startedAt = Date.now();
|
|
29
|
+
let context;
|
|
30
|
+
try {
|
|
31
|
+
context = await resolveWorkPushContext();
|
|
32
|
+
}
|
|
33
|
+
catch (error) {
|
|
34
|
+
if (error instanceof WorkPushValidationError) {
|
|
35
|
+
command.error(error.message, {
|
|
36
|
+
exit: error.exit,
|
|
37
|
+
suggestions: error.suggestions,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
throw error;
|
|
41
|
+
}
|
|
42
|
+
const { baseBranch, branch, devOrgBranch, workItem, workItemId } = context;
|
|
43
|
+
const pendingFiles = await listPendingChanges();
|
|
44
|
+
if (pendingFiles.length > 0) {
|
|
45
|
+
command.error([
|
|
46
|
+
'Uncommitted tracked changes present. Commit them, then try again:',
|
|
47
|
+
...pendingFiles.map((file) => ` ${file}`),
|
|
48
|
+
].join('\n'), {
|
|
49
|
+
exit: 2,
|
|
50
|
+
suggestions: ['git add -A && git commit', `${command.config.bin} cicd work publish`],
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
command.display(() => {
|
|
54
|
+
command.log(`Branch: ${branch}`);
|
|
55
|
+
command.log(`Work item: ${workItem}`);
|
|
56
|
+
command.log(`Base branch: ${baseBranch}`);
|
|
57
|
+
command.log(`Dev org branch: ${devOrgBranch}`);
|
|
58
|
+
});
|
|
59
|
+
try {
|
|
60
|
+
const result = await performWorkPush({
|
|
61
|
+
baseBranch,
|
|
62
|
+
branch,
|
|
63
|
+
devOrgBranch,
|
|
64
|
+
...(flags['full-metadata'] === undefined ? {} : { fullMetadata: flags['full-metadata'] }),
|
|
65
|
+
hooks: {
|
|
66
|
+
display: (render) => command.display(render),
|
|
67
|
+
log: (message) => command.log(message),
|
|
68
|
+
withSpinner: (message, action) => command.withSpinner(message, action),
|
|
69
|
+
},
|
|
70
|
+
...(flags.permissions === undefined ? {} : { permissions: flags.permissions }),
|
|
71
|
+
skipNestedMetadataDetection: flags['skip-nested-metadata-detection'],
|
|
72
|
+
workItem,
|
|
73
|
+
workItemId,
|
|
74
|
+
});
|
|
75
|
+
command.logElapsed(startedAt);
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof WorkPushValidationError) {
|
|
80
|
+
command.error(error.message, {
|
|
81
|
+
exit: error.exit,
|
|
82
|
+
suggestions: error.suggestions,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
throw error;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=work-publish-command.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"work-publish-command.js","sourceRoot":"","sources":["../../src/lib/work-publish-command.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/work-push.d.ts
CHANGED
|
@@ -35,11 +35,12 @@ export type WorkPushNeed = {
|
|
|
35
35
|
* Decide whether done/submit should push.
|
|
36
36
|
*
|
|
37
37
|
* Salesforce Data Set / Data Template steps only waive the empty-history error.
|
|
38
|
-
* When HEAD has commits beyond
|
|
39
|
-
* or any other git validation.
|
|
38
|
+
* When HEAD has commits beyond origin/<lastBaseBranch>, those steps must not skip
|
|
39
|
+
* push or any other git validation. The local base ref is ignored: a stale local
|
|
40
|
+
* main must not count origin/base history as feature work.
|
|
40
41
|
*/
|
|
41
42
|
export declare function resolveWorkPushNeed(branch: string): Promise<WorkPushNeed>;
|
|
42
|
-
/** Resolve lastWorkItem / branch / lastBaseBranch / lastDevOrgBranch for work
|
|
43
|
+
/** Resolve lastWorkItem / branch / lastBaseBranch / lastDevOrgBranch for work publish. */
|
|
43
44
|
export declare function resolveWorkPushContext(): Promise<ResolvedWorkPushContext>;
|
|
44
45
|
export type SleepFn = (ms: number) => Promise<void>;
|
|
45
46
|
export declare function setSleepForTests(nextSleep: SleepFn): void;
|
|
@@ -56,8 +57,8 @@ export declare function readWorkPushRetrieveOnly(): Promise<string[]>;
|
|
|
56
57
|
/** Metadata recorded by `cicd work commit --full-metadata`, pushed as `fullMetadata` corrections. */
|
|
57
58
|
export declare function readWorkPushFullMetadata(): Promise<string[]>;
|
|
58
59
|
/**
|
|
59
|
-
* Selections recorded at commit time plus the ones passed to this
|
|
60
|
-
* duplicates. `cicd work
|
|
60
|
+
* Selections recorded at commit time plus the ones passed to this publish, in that order and without
|
|
61
|
+
* duplicates. `cicd work publish` never stores its own flag values, so a flag adds to the recorded
|
|
61
62
|
* selection for the current invocation only.
|
|
62
63
|
*/
|
|
63
64
|
export declare function mergeWorkPushSelections(storedSelections: readonly string[], requestedSelections: readonly string[]): string[];
|
package/dist/lib/work-push.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { CicdGateway, CicdGatewayError } from './cicd-gateway.js';
|
|
2
2
|
import { DEFAULT_WORK_PUSH_RETRY_TIMEOUT_SECONDS, readLastBaseBranch, readLastDevOrgBranch, readLastFullMetadataSelected, readLastPermissionSelected, readLastWorkItem, readSkipNestedMetadataDetection, readWorkPushRetryTimeoutSeconds, } from './defaults-store.js';
|
|
3
3
|
import { hasSalesforceDataDeploymentStep, normalizeDeploymentSteps, userStoryDeploymentStepsEndpoint, } from './deployment-step-types.js';
|
|
4
|
-
import { checkoutBranch, commitAllowEmpty, commitAllTrackedChanges, countCommitsSince, getCommitsNameStatus, getCurrentBranch, getFileAtRef, getGitRepoRoot, getMergeBase, hasUnpushedCommits, listPendingChanges, mergeTheirsIgnoreSpaceChange, pullOriginBranch, pushOriginBranch, restoreFeatureBranch, } from './git-worktree.js';
|
|
4
|
+
import { checkoutBranch, commitAllowEmpty, commitAllTrackedChanges, countCommitsSince, fetchOriginBranch, getCommitsNameStatus, getCurrentBranch, getFileAtRef, getGitRepoRoot, getMergeBase, hasUnpushedCommits, listPendingChanges, mergeTheirsIgnoreSpaceChange, originBranchRef, pullOriginBranch, pushOriginBranch, restoreFeatureBranch, } from './git-worktree.js';
|
|
5
5
|
import { detectNestedMetadataChanges, formatNestedMetadataSelection, listDeletableNestedChildren, listNestedParentCandidates, } from './nested-metadata-changes.js';
|
|
6
6
|
import { buildVarReplacementEntries, runVarReplacement } from './var-replacement.js';
|
|
7
7
|
import { resolveWorkItemId, WorkActiveResolutionError } from './work-active.js';
|
|
@@ -41,16 +41,23 @@ export async function resolveRecordedBaseBranch() {
|
|
|
41
41
|
}
|
|
42
42
|
return baseBranch;
|
|
43
43
|
}
|
|
44
|
+
/** Fetch `origin/<baseBranch>` and return that remote-tracking ref. */
|
|
45
|
+
async function fetchOriginBaseRef(baseBranch) {
|
|
46
|
+
await fetchOriginBranch(baseBranch);
|
|
47
|
+
return originBranchRef(baseBranch);
|
|
48
|
+
}
|
|
44
49
|
/**
|
|
45
50
|
* Decide whether done/submit should push.
|
|
46
51
|
*
|
|
47
52
|
* Salesforce Data Set / Data Template steps only waive the empty-history error.
|
|
48
|
-
* When HEAD has commits beyond
|
|
49
|
-
* or any other git validation.
|
|
53
|
+
* When HEAD has commits beyond origin/<lastBaseBranch>, those steps must not skip
|
|
54
|
+
* push or any other git validation. The local base ref is ignored: a stale local
|
|
55
|
+
* main must not count origin/base history as feature work.
|
|
50
56
|
*/
|
|
51
57
|
export async function resolveWorkPushNeed(branch) {
|
|
52
58
|
const baseBranch = await resolveRecordedBaseBranch();
|
|
53
|
-
const
|
|
59
|
+
const originBase = await fetchOriginBaseRef(baseBranch);
|
|
60
|
+
const count = await countCommitsSince(originBase);
|
|
54
61
|
if (count > 0) {
|
|
55
62
|
return {
|
|
56
63
|
needsPush: await hasUnpushedCommits(branch),
|
|
@@ -74,18 +81,18 @@ export async function resolveWorkPushNeed(branch) {
|
|
|
74
81
|
if (hasSalesforceDataDeploymentStep(steps)) {
|
|
75
82
|
return { needsPush: false, skippedForDataSteps: true };
|
|
76
83
|
}
|
|
77
|
-
throw new WorkPushValidationError(`No commits found between ${
|
|
84
|
+
throw new WorkPushValidationError(`No commits found between ${originBase} and HEAD.`, {
|
|
78
85
|
exit: 1,
|
|
79
86
|
suggestions: ['Make at least one commit on the feature branch.'],
|
|
80
87
|
});
|
|
81
88
|
}
|
|
82
|
-
/** Resolve lastWorkItem / branch / lastBaseBranch / lastDevOrgBranch for work
|
|
89
|
+
/** Resolve lastWorkItem / branch / lastBaseBranch / lastDevOrgBranch for work publish. */
|
|
83
90
|
export async function resolveWorkPushContext() {
|
|
84
91
|
const { branch, workItem } = await resolveActiveFeatureWorkItem();
|
|
85
92
|
const baseBranch = await resolveRecordedBaseBranch();
|
|
86
93
|
const devOrgBranch = (await readLastDevOrgBranch())?.trim();
|
|
87
94
|
if (devOrgBranch === undefined || devOrgBranch.length === 0) {
|
|
88
|
-
throw new WorkPushValidationError('No lastDevOrgBranch recorded in `.agentia/config.user.json`. Set it before
|
|
95
|
+
throw new WorkPushValidationError('No lastDevOrgBranch recorded in `.agentia/config.user.json`. Set it before publishing.');
|
|
89
96
|
}
|
|
90
97
|
let workItemId;
|
|
91
98
|
try {
|
|
@@ -176,7 +183,7 @@ export async function registerHeadlessPush(pushBody, hooks, timeoutSeconds = DEF
|
|
|
176
183
|
}
|
|
177
184
|
const delaySeconds = resolveWorkPushRetryDelaySeconds(retryAfterSeconds, waitedSeconds);
|
|
178
185
|
if (waitedSeconds + delaySeconds > timeoutSeconds) {
|
|
179
|
-
throw new CicdGatewayError(`CICD Gateway rate limited the work
|
|
186
|
+
throw new CicdGatewayError(`CICD Gateway rate limited the work publish request and the retry timeout of ${timeoutSeconds}s was exceeded.`, {
|
|
180
187
|
categories: error.categories,
|
|
181
188
|
code: error.code,
|
|
182
189
|
jobId: error.jobId,
|
|
@@ -190,9 +197,9 @@ export async function registerHeadlessPush(pushBody, hooks, timeoutSeconds = DEF
|
|
|
190
197
|
}
|
|
191
198
|
hooks.display(() => {
|
|
192
199
|
hooks.log(error.jobId === undefined
|
|
193
|
-
? `Rate limited (429). Retrying work
|
|
200
|
+
? `Rate limited (429). Retrying work publish in ${delaySeconds}s` +
|
|
194
201
|
` (${waitedSeconds + delaySeconds}s / ${timeoutSeconds}s waited).`
|
|
195
|
-
: `waiting for job id ${error.jobId}, Retrying work
|
|
202
|
+
: `waiting for job id ${error.jobId}, Retrying work publish in ${delaySeconds}s` +
|
|
196
203
|
` (${waitedSeconds + delaySeconds}s / ${timeoutSeconds}s waited).`);
|
|
197
204
|
});
|
|
198
205
|
// eslint-disable-next-line no-await-in-loop -- wait before the next retry
|
|
@@ -212,8 +219,8 @@ export async function readWorkPushFullMetadata() {
|
|
|
212
219
|
return stored === undefined ? [] : parseCommaSeparatedList(stored);
|
|
213
220
|
}
|
|
214
221
|
/**
|
|
215
|
-
* Selections recorded at commit time plus the ones passed to this
|
|
216
|
-
* duplicates. `cicd work
|
|
222
|
+
* Selections recorded at commit time plus the ones passed to this publish, in that order and without
|
|
223
|
+
* duplicates. `cicd work publish` never stores its own flag values, so a flag adds to the recorded
|
|
217
224
|
* selection for the current invocation only.
|
|
218
225
|
*/
|
|
219
226
|
export function mergeWorkPushSelections(storedSelections, requestedSelections) {
|
|
@@ -364,7 +371,7 @@ async function applyCopadoReplacements(options) {
|
|
|
364
371
|
export const SKIP_NESTED_METADATA_DETECTION_CONFIG_MESSAGE = 'Nested metadata detection skipped (skipNestedMetadataDetection in .agentia/config.json or .agentia/config.user.json).';
|
|
365
372
|
export const SKIP_NESTED_METADATA_DETECTION_REQUEST_MESSAGE = 'Nested metadata detection skipped by request.';
|
|
366
373
|
/**
|
|
367
|
-
* Nested metadata changed across every commit not in
|
|
374
|
+
* Nested metadata changed across every commit not in origin/<base>: the parent components whose
|
|
368
375
|
* XML changed only in nested blocks, and the child components carrying the real change.
|
|
369
376
|
*
|
|
370
377
|
* Children of a Profile or PermissionSet parent are sent as `RetrieveOnly` and the parent itself is
|
|
@@ -469,23 +476,24 @@ function logSelectionEntries(log, header, entries) {
|
|
|
469
476
|
export async function performWorkPush(options) {
|
|
470
477
|
const { baseBranch, branch, devOrgBranch, hooks, workItem } = options;
|
|
471
478
|
const { display, log, withSpinner } = hooks;
|
|
472
|
-
|
|
479
|
+
const originBase = await withSpinner(`Fetching origin/${baseBranch}`, () => fetchOriginBaseRef(baseBranch));
|
|
480
|
+
let logStdout = await withSpinner(`Collecting commits since origin/${baseBranch}`, () => getCommitsNameStatus(originBase));
|
|
473
481
|
let commits = parseNameStatusLog(logStdout, workItem);
|
|
474
482
|
const hasSelectionFlags = options.fullMetadata !== undefined || options.permissions !== undefined;
|
|
475
483
|
const needsEmptyCommit = commits.length === 0 || !(await hasUnpushedCommits(branch));
|
|
476
484
|
if (needsEmptyCommit) {
|
|
477
485
|
if (!hasSelectionFlags) {
|
|
478
|
-
throw new WorkPushValidationError('No changes to
|
|
486
|
+
throw new WorkPushValidationError('No changes to publish.', {
|
|
479
487
|
exit: 1,
|
|
480
488
|
suggestions: [
|
|
481
|
-
'Make at least one commit on the feature branch before
|
|
482
|
-
'Or pass --permissions and/or --full-metadata to
|
|
489
|
+
'Make at least one commit on the feature branch before publishing.',
|
|
490
|
+
'Or pass --permissions and/or --full-metadata to publish selection corrections with an empty commit.',
|
|
483
491
|
],
|
|
484
492
|
});
|
|
485
493
|
}
|
|
486
|
-
const emptyCommitMessage = `${workItem}: empty commit for work
|
|
487
|
-
await withSpinner('Creating empty commit for selection
|
|
488
|
-
logStdout = await withSpinner(`Collecting commits since
|
|
494
|
+
const emptyCommitMessage = `${workItem}: empty commit for work publish selections`;
|
|
495
|
+
await withSpinner('Creating empty commit for selection publish', () => commitAllowEmpty(emptyCommitMessage));
|
|
496
|
+
logStdout = await withSpinner(`Collecting commits since origin/${baseBranch}`, () => getCommitsNameStatus(originBase));
|
|
489
497
|
commits = parseNameStatusLog(logStdout, workItem);
|
|
490
498
|
if (commits.length === 0) {
|
|
491
499
|
throw new WorkPushValidationError('Unable to determine tip commit id after empty commit.', {
|
|
@@ -512,7 +520,7 @@ export async function performWorkPush(options) {
|
|
|
512
520
|
let tipCommitToLock = tipCommitId;
|
|
513
521
|
try {
|
|
514
522
|
const replacementResult = await applyCopadoReplacements({
|
|
515
|
-
baseBranch,
|
|
523
|
+
baseBranch: originBase,
|
|
516
524
|
changedFiles,
|
|
517
525
|
commits,
|
|
518
526
|
devOrgBranch,
|
|
@@ -530,7 +538,7 @@ export async function performWorkPush(options) {
|
|
|
530
538
|
const selectedPermissions = mergeWorkPushSelections(storedRetrieveOnly, options.permissions === undefined ? [] : parseCommaSeparatedList(options.permissions));
|
|
531
539
|
const selectedFullMetadata = mergeWorkPushSelections(storedFullMetadata, options.fullMetadata === undefined ? [] : parseCommaSeparatedList(options.fullMetadata));
|
|
532
540
|
const nestedMetadata = await reportNestedMetadataChanges({
|
|
533
|
-
baseBranch,
|
|
541
|
+
baseBranch: originBase,
|
|
534
542
|
commits: commitsToRegister,
|
|
535
543
|
fullMetadata: selectedFullMetadata,
|
|
536
544
|
hooks: { display, log, withSpinner },
|