@waron97/prbot 3.3.0 → 3.4.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/package.json +5 -1
- package/src/agrippa/commands/clone.js +10 -9
- package/src/agrippa/commands/cloneLrp.js +9 -9
- package/src/agrippa/commands/clonePb.js +10 -10
- package/src/agrippa/commands/diff.js +9 -8
- package/src/agrippa/commands/init.js +14 -13
- package/src/agrippa/commands/initPhase.js +10 -11
- package/src/agrippa/commands/pb.js +25 -26
- package/src/agrippa/commands/pull.js +67 -48
- package/src/agrippa/commands/pullLrp.js +2 -3
- package/src/agrippa/commands/pullPb.js +2 -3
- package/src/agrippa/commands/push.js +33 -24
- package/src/agrippa/commands/repair.js +4 -3
- package/src/agrippa/index.js +20 -11
- package/src/agrippa/lib/pbLayout.js +8 -1
- package/src/agrippa/lib/pbModel.js +1 -0
- package/src/agrippa/lib/pbPreview.js +6 -2
- package/src/agrippa/lib/pbProject.js +71 -3
- package/src/commands/autopr.js +20 -21
- package/src/commands/changelog.js +4 -3
- package/src/commands/commit.js +11 -10
- package/src/commands/export.js +2 -1
- package/src/commands/exportPb.js +19 -2
- package/src/commands/init.js +2 -1
- package/src/commands/routine.js +19 -8
- package/src/index.js +137 -112
- package/src/lib/auth.js +19 -1
- package/src/lib/logger.js +12 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { dirname } from 'path';
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import { getToken } from '../../lib/auth.js';
|
|
4
|
+
import { log, warn } from '../../lib/logger.js';
|
|
4
5
|
import { describeWorkflow, getPhasesByIds, getPhasesByWorkflow, listMfas } from '../lib/api.js';
|
|
5
6
|
import { computeChecksum } from '../lib/checksum.js';
|
|
6
7
|
import { loadEffectiveEnv, readConfig, writeConfig } from '../lib/config.js';
|
|
@@ -18,7 +19,7 @@ import {
|
|
|
18
19
|
import { pullLrpEntry } from './pullLrp.js';
|
|
19
20
|
import { pullPbEntry } from './pullPb.js';
|
|
20
21
|
|
|
21
|
-
async function pull() {
|
|
22
|
+
async function pull(opts = {}) {
|
|
22
23
|
const config = readConfig();
|
|
23
24
|
loadEffectiveEnv(config);
|
|
24
25
|
|
|
@@ -29,19 +30,23 @@ async function pull() {
|
|
|
29
30
|
// Stale-file check
|
|
30
31
|
const stale = config.workspace.filter((e) => !fileExists(e.path));
|
|
31
32
|
if (stale.length) {
|
|
32
|
-
|
|
33
|
-
stale.forEach((e) =>
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
log('\nThe following tracked files no longer exist on disk:');
|
|
34
|
+
stale.forEach((e) => log(` - ${e.path} (${e.name})`));
|
|
35
|
+
if (opts.nonInteractive) {
|
|
36
|
+
log(' (non-interactive: leaving them tracked; run interactively to clean up)');
|
|
37
|
+
} else {
|
|
38
|
+
const { cleanup } = await inquirer.prompt([
|
|
39
|
+
{
|
|
40
|
+
type: 'confirm',
|
|
41
|
+
name: 'cleanup',
|
|
42
|
+
message: 'Remove these entries from the workspace config?',
|
|
43
|
+
default: true,
|
|
44
|
+
},
|
|
45
|
+
]);
|
|
46
|
+
if (cleanup) {
|
|
47
|
+
config.workspace = config.workspace.filter((e) => fileExists(e.path));
|
|
48
|
+
writeConfig(config);
|
|
49
|
+
}
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
|
|
@@ -58,7 +63,7 @@ async function pull() {
|
|
|
58
63
|
(e) => e.object_type !== 'process_builder' && e.object_type !== 'long_running_process'
|
|
59
64
|
);
|
|
60
65
|
if (pullable.length) {
|
|
61
|
-
|
|
66
|
+
log('Fetching remote code...');
|
|
62
67
|
const remoteCodeMap = await fetchRemoteCode(token, ripUrl, pullable);
|
|
63
68
|
|
|
64
69
|
const classified = pullable.map((entry) => {
|
|
@@ -85,12 +90,12 @@ async function pull() {
|
|
|
85
90
|
const changed = classified.filter((e) => e.status !== 'unchanged');
|
|
86
91
|
|
|
87
92
|
if (!changed.length) {
|
|
88
|
-
|
|
93
|
+
log('Everything is up to date.');
|
|
89
94
|
} else {
|
|
90
|
-
const selected = await selectEntries(changed, 'pull (overwrites local files)');
|
|
95
|
+
const selected = await selectEntries(changed, 'pull (overwrites local files)', opts);
|
|
91
96
|
|
|
92
97
|
if (!selected.length) {
|
|
93
|
-
|
|
98
|
+
log('Nothing selected. No changes made.');
|
|
94
99
|
} else {
|
|
95
100
|
for (const entry of selected) {
|
|
96
101
|
writeCodeFile(entry.path, entry.remoteCode);
|
|
@@ -105,18 +110,18 @@ async function pull() {
|
|
|
105
110
|
}
|
|
106
111
|
}
|
|
107
112
|
writeConfig(config);
|
|
108
|
-
|
|
113
|
+
log(`\nPulled ${selected.length} record(s).`);
|
|
109
114
|
}
|
|
110
115
|
}
|
|
111
116
|
} else {
|
|
112
|
-
|
|
117
|
+
log('No tracked resources. Run `agrippa clone` first.');
|
|
113
118
|
}
|
|
114
119
|
|
|
115
120
|
// ── refresh tracked process-builder wizards ───────────────────────────────
|
|
116
|
-
await pullPbEntries(token, config);
|
|
121
|
+
await pullPbEntries(token, config, opts);
|
|
117
122
|
|
|
118
123
|
// ── refresh tracked long-running processes ────────────────────────────────
|
|
119
|
-
await pullLrpEntries(token, config);
|
|
124
|
+
await pullLrpEntries(token, config, opts);
|
|
120
125
|
|
|
121
126
|
// ── discover new phases on tracked workflows ──────────────────────────────
|
|
122
127
|
await discoverNewPhases(token, ripUrl, config, changedWorkflowIds);
|
|
@@ -127,13 +132,13 @@ async function pull() {
|
|
|
127
132
|
// unchanged local === remote semantically → nothing to do
|
|
128
133
|
// fast-forward remote changed, local untouched since pull → safe overwrite
|
|
129
134
|
// conflict local diverged from checksum_at_pull → overwrite loses local work
|
|
130
|
-
async function pullPbEntries(token, config) {
|
|
135
|
+
async function pullPbEntries(token, config, opts = {}) {
|
|
131
136
|
const entries = config.workspace.filter((e) => e.object_type === 'process_builder');
|
|
132
137
|
if (!entries.length) return;
|
|
133
138
|
if (!process.env.PB_URL)
|
|
134
139
|
throw new Error('PB_URL is not configured. Run `prbot init` or set it in agrippa.yaml.');
|
|
135
140
|
|
|
136
|
-
|
|
141
|
+
log('Checking process-builder wizards...');
|
|
137
142
|
const classified = [];
|
|
138
143
|
for (const entry of entries) {
|
|
139
144
|
let upstream = null;
|
|
@@ -143,7 +148,7 @@ async function pullPbEntries(token, config) {
|
|
|
143
148
|
upstream = null;
|
|
144
149
|
}
|
|
145
150
|
if (!upstream) {
|
|
146
|
-
|
|
151
|
+
warn(` ${entry.name}: could not fetch upstream, skipping`);
|
|
147
152
|
continue;
|
|
148
153
|
}
|
|
149
154
|
const localSemantic = localChecksum(projectReader(entry.path));
|
|
@@ -158,13 +163,13 @@ async function pullPbEntries(token, config) {
|
|
|
158
163
|
|
|
159
164
|
const changed = classified.filter((e) => e.status !== 'unchanged');
|
|
160
165
|
if (!changed.length) {
|
|
161
|
-
|
|
166
|
+
log('Wizards are up to date.');
|
|
162
167
|
return;
|
|
163
168
|
}
|
|
164
169
|
|
|
165
|
-
const selected = await selectEntries(changed, 'pull (overwrites local wizard files)');
|
|
170
|
+
const selected = await selectEntries(changed, 'pull (overwrites local wizard files)', opts);
|
|
166
171
|
if (!selected.length) {
|
|
167
|
-
|
|
172
|
+
log('No wizards selected.');
|
|
168
173
|
return;
|
|
169
174
|
}
|
|
170
175
|
|
|
@@ -180,16 +185,16 @@ async function pullPbEntries(token, config) {
|
|
|
180
185
|
if (res.newStatus) config.workspace[idx].status = res.newStatus;
|
|
181
186
|
}
|
|
182
187
|
const note = res.diffs.length ? ` (WARNING: ${res.diffs.length} round-trip diff(s))` : '';
|
|
183
|
-
|
|
188
|
+
log(` ${entry.name} → refreshed${note}`);
|
|
184
189
|
}
|
|
185
190
|
writeConfig(config);
|
|
186
|
-
|
|
191
|
+
log(`\nPulled ${selected.length} wizard(s). Local backups in .backup/${backupTs}/`);
|
|
187
192
|
}
|
|
188
193
|
|
|
189
194
|
// Refresh tracked long-running processes from upstream. Same classification
|
|
190
195
|
// concern as pullPbEntries, but entries are located by NAME (the tabulator id
|
|
191
196
|
// changes on every save/version — never a stable key).
|
|
192
|
-
async function pullLrpEntries(token, config) {
|
|
197
|
+
async function pullLrpEntries(token, config, opts = {}) {
|
|
193
198
|
const entries = config.workspace.filter((e) => e.object_type === 'long_running_process');
|
|
194
199
|
if (!entries.length) return;
|
|
195
200
|
if (!process.env.IMPORTEXPORT_URL)
|
|
@@ -197,7 +202,7 @@ async function pullLrpEntries(token, config) {
|
|
|
197
202
|
'IMPORTEXPORT_URL is not configured. Run `prbot init` or set it in agrippa.yaml.'
|
|
198
203
|
);
|
|
199
204
|
|
|
200
|
-
|
|
205
|
+
log('Checking long-running processes...');
|
|
201
206
|
const classified = [];
|
|
202
207
|
for (const entry of entries) {
|
|
203
208
|
let upstream = null;
|
|
@@ -207,7 +212,7 @@ async function pullLrpEntries(token, config) {
|
|
|
207
212
|
upstream = null;
|
|
208
213
|
}
|
|
209
214
|
if (!upstream) {
|
|
210
|
-
|
|
215
|
+
warn(` ${entry.name}: could not fetch upstream, skipping`);
|
|
211
216
|
continue;
|
|
212
217
|
}
|
|
213
218
|
const localSemantic = localChecksum(projectReader(entry.path));
|
|
@@ -222,13 +227,13 @@ async function pullLrpEntries(token, config) {
|
|
|
222
227
|
|
|
223
228
|
const changed = classified.filter((e) => e.status !== 'unchanged');
|
|
224
229
|
if (!changed.length) {
|
|
225
|
-
|
|
230
|
+
log('Long-running processes are up to date.');
|
|
226
231
|
return;
|
|
227
232
|
}
|
|
228
233
|
|
|
229
|
-
const selected = await selectEntries(changed, 'pull (overwrites local LRP files)');
|
|
234
|
+
const selected = await selectEntries(changed, 'pull (overwrites local LRP files)', opts);
|
|
230
235
|
if (!selected.length) {
|
|
231
|
-
|
|
236
|
+
log('No long-running processes selected.');
|
|
232
237
|
return;
|
|
233
238
|
}
|
|
234
239
|
|
|
@@ -247,10 +252,10 @@ async function pullLrpEntries(token, config) {
|
|
|
247
252
|
config.workspace[idx].status = res.newRow.status;
|
|
248
253
|
}
|
|
249
254
|
const note = res.diffs.length ? ` (WARNING: ${res.diffs.length} round-trip diff(s))` : '';
|
|
250
|
-
|
|
255
|
+
log(` ${entry.name} → refreshed${note}`);
|
|
251
256
|
}
|
|
252
257
|
writeConfig(config);
|
|
253
|
-
|
|
258
|
+
log(
|
|
254
259
|
`\nPulled ${selected.length} long-running process(es). Local backups in .backup/${backupTs}/`
|
|
255
260
|
);
|
|
256
261
|
}
|
|
@@ -294,7 +299,7 @@ async function discoverNewPhases(token, ripUrl, config, changedWorkflowIds = new
|
|
|
294
299
|
checksum_at_pull: computeChecksum(phase.code),
|
|
295
300
|
name: `${wfName} / ${phase.name}`,
|
|
296
301
|
});
|
|
297
|
-
|
|
302
|
+
log(` new phase: ${filePath}`);
|
|
298
303
|
newCount++;
|
|
299
304
|
wfChanged = true;
|
|
300
305
|
}
|
|
@@ -307,14 +312,14 @@ async function discoverNewPhases(token, ripUrl, config, changedWorkflowIds = new
|
|
|
307
312
|
const structure = await describeWorkflow(token, ripUrl, wfId);
|
|
308
313
|
writeWorkflowDoc(basePath, structure);
|
|
309
314
|
} catch (err) {
|
|
310
|
-
|
|
315
|
+
warn(` could not refresh workflow.yml for ${wfName}: ${err.message}`);
|
|
311
316
|
}
|
|
312
317
|
}
|
|
313
318
|
}
|
|
314
319
|
|
|
315
320
|
if (newCount) {
|
|
316
321
|
writeConfig(config);
|
|
317
|
-
|
|
322
|
+
log(`Added ${newCount} new phase(s) from tracked workflows.`);
|
|
318
323
|
}
|
|
319
324
|
}
|
|
320
325
|
|
|
@@ -343,18 +348,32 @@ async function fetchRemoteCode(token, ripUrl, workspace) {
|
|
|
343
348
|
return map;
|
|
344
349
|
}
|
|
345
350
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
351
|
+
// `changed` only ever contains `fast-forward` and `conflict` entries (the
|
|
352
|
+
// caller already filtered out `unchanged`). `conflict` means local and remote
|
|
353
|
+
// have both diverged from the last-known-good baseline — applying it blindly
|
|
354
|
+
// can silently lose either side's work, so it is never preselected and is
|
|
355
|
+
// refused outright in `--non-interactive` mode instead of being silently
|
|
356
|
+
// skipped or applied.
|
|
357
|
+
async function selectEntries(changed, verb, opts = {}) {
|
|
358
|
+
const conflicts = changed.filter((e) => e.status === 'conflict');
|
|
359
|
+
|
|
360
|
+
if (opts.nonInteractive) {
|
|
361
|
+
if (conflicts.length) {
|
|
362
|
+
throw new Error(
|
|
363
|
+
`CONFLICT: refusing to ${verb} non-interactively — ${conflicts.length} resource(s) ` +
|
|
364
|
+
`in conflict: ${conflicts.map((e) => e.name).join(', ')}. Resolve interactively ` +
|
|
365
|
+
`or re-run once the conflicting side is reconciled.`
|
|
366
|
+
);
|
|
350
367
|
}
|
|
351
|
-
return
|
|
352
|
-
}
|
|
368
|
+
return changed;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
const badgeFor = (status) => (status === 'fast-forward' ? '↑ safe' : '⚠ conflict');
|
|
353
372
|
|
|
354
373
|
const choices = changed.map((e) => ({
|
|
355
374
|
name: `${e.name} [${badgeFor(e.status)}]`,
|
|
356
375
|
value: e,
|
|
357
|
-
checked:
|
|
376
|
+
checked: e.status !== 'conflict',
|
|
358
377
|
}));
|
|
359
378
|
|
|
360
379
|
const { selected } = await inquirer.prompt([
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from 'fs';
|
|
2
2
|
import { dirname, join } from 'path';
|
|
3
|
-
import { computeChecksum } from '../lib/checksum.js';
|
|
4
3
|
import { fetchUpstream } from '../lib/lrpApi.js';
|
|
5
|
-
import { comparePayload, decompose, recompose
|
|
4
|
+
import { checksumOfPayload, comparePayload, decompose, recompose } from '../lib/pbProject.js';
|
|
6
5
|
import { projectReader, writeProject } from '../lib/pbWorkspace.js';
|
|
7
6
|
|
|
8
7
|
// Delete files under <baseDir>/scripts that are not in the fresh decompose
|
|
@@ -46,7 +45,7 @@ async function pullLrpEntry(token, entry, backupDir, backupTs) {
|
|
|
46
45
|
const diffs = comparePayload(upstream.payload, rebuilt).filter((d) => !d.startsWith('pages:'));
|
|
47
46
|
|
|
48
47
|
return {
|
|
49
|
-
newChecksum:
|
|
48
|
+
newChecksum: checksumOfPayload(rebuilt),
|
|
50
49
|
newRow: upstream.row,
|
|
51
50
|
diffs,
|
|
52
51
|
};
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, readdirSync, rmSync, writeFileSync } from 'fs';
|
|
2
2
|
import { dirname, join } from 'path';
|
|
3
|
-
import { computeChecksum } from '../lib/checksum.js';
|
|
4
3
|
import { getProcess } from '../lib/pbApi.js';
|
|
5
|
-
import { comparePayload, decompose, recompose
|
|
4
|
+
import { checksumOfPayload, comparePayload, decompose, recompose } from '../lib/pbProject.js';
|
|
6
5
|
import { projectReader, writeProject } from '../lib/pbWorkspace.js';
|
|
7
6
|
|
|
8
7
|
// Delete files under <baseDir>/<sub> that are not in the fresh decompose map, so
|
|
@@ -44,7 +43,7 @@ async function pullPbEntry(token, entry, backupDir, backupTs) {
|
|
|
44
43
|
const diffs = comparePayload(upstream, rebuilt);
|
|
45
44
|
|
|
46
45
|
return {
|
|
47
|
-
newChecksum:
|
|
46
|
+
newChecksum: checksumOfPayload(rebuilt),
|
|
48
47
|
newUpdatedDate: upstream.updated_date,
|
|
49
48
|
newStatus: upstream.status,
|
|
50
49
|
diffs,
|
|
@@ -2,6 +2,7 @@ import { mkdirSync, writeFileSync } from 'fs';
|
|
|
2
2
|
import { dirname, join } from 'path';
|
|
3
3
|
import inquirer from 'inquirer';
|
|
4
4
|
import { getToken } from '../../lib/auth.js';
|
|
5
|
+
import { log } from '../../lib/logger.js';
|
|
5
6
|
import { updateMfa, updatePhase } from '../lib/api.js';
|
|
6
7
|
import { computeChecksum } from '../lib/checksum.js';
|
|
7
8
|
import { loadEffectiveEnv, readConfig, writeConfig } from '../lib/config.js';
|
|
@@ -23,24 +24,28 @@ async function push(opts = {}) {
|
|
|
23
24
|
// Stale-entry check (a path may be a file for phase/mfa or a dir for pb).
|
|
24
25
|
const stale = config.workspace.filter((e) => !fileExists(e.path));
|
|
25
26
|
if (stale.length) {
|
|
26
|
-
|
|
27
|
-
stale.forEach((e) =>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
log('\nThe following tracked resources no longer exist on disk:');
|
|
28
|
+
stale.forEach((e) => log(` - ${e.path} (${e.name})`));
|
|
29
|
+
if (opts.nonInteractive) {
|
|
30
|
+
log(' (non-interactive: leaving them tracked; run interactively to clean up)');
|
|
31
|
+
} else {
|
|
32
|
+
const { cleanup } = await inquirer.prompt([
|
|
33
|
+
{
|
|
34
|
+
type: 'confirm',
|
|
35
|
+
name: 'cleanup',
|
|
36
|
+
message: 'Remove these entries from the workspace config?',
|
|
37
|
+
default: true,
|
|
38
|
+
},
|
|
39
|
+
]);
|
|
40
|
+
if (cleanup) {
|
|
41
|
+
config.workspace = config.workspace.filter((e) => fileExists(e.path));
|
|
42
|
+
writeConfig(config);
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
45
|
}
|
|
41
46
|
|
|
42
47
|
if (!config.workspace.length) {
|
|
43
|
-
|
|
48
|
+
log('No tracked resources. Run `agrippa clone` first.');
|
|
44
49
|
return;
|
|
45
50
|
}
|
|
46
51
|
|
|
@@ -59,7 +64,7 @@ async function push(opts = {}) {
|
|
|
59
64
|
'IMPORTEXPORT_URL is not configured. Run `prbot init` or set it in agrippa.yaml.'
|
|
60
65
|
);
|
|
61
66
|
|
|
62
|
-
|
|
67
|
+
log('Fetching remote state...');
|
|
63
68
|
const token = await getToken();
|
|
64
69
|
|
|
65
70
|
const remoteCodeMap = hasCode
|
|
@@ -123,13 +128,13 @@ async function push(opts = {}) {
|
|
|
123
128
|
|
|
124
129
|
const changed = classified.filter((e) => e.status !== 'unchanged');
|
|
125
130
|
if (!changed.length) {
|
|
126
|
-
|
|
131
|
+
log('Nothing to push — everything matches the last-pulled state.');
|
|
127
132
|
return;
|
|
128
133
|
}
|
|
129
134
|
|
|
130
|
-
const selected = await selectEntries(changed, 'push (overwrites remote)',
|
|
135
|
+
const selected = await selectEntries(changed, 'push (overwrites remote)', opts);
|
|
131
136
|
if (!selected.length) {
|
|
132
|
-
|
|
137
|
+
log('Nothing selected. No changes made.');
|
|
133
138
|
return;
|
|
134
139
|
}
|
|
135
140
|
|
|
@@ -168,7 +173,7 @@ async function push(opts = {}) {
|
|
|
168
173
|
]
|
|
169
174
|
.filter(Boolean)
|
|
170
175
|
.join(', ');
|
|
171
|
-
|
|
176
|
+
log(` ${entry.name} → saved (draft)${note ? ` [${note}]` : ''}`);
|
|
172
177
|
if (idx !== -1) {
|
|
173
178
|
config.workspace[idx].checksum_at_pull = res.newChecksum;
|
|
174
179
|
if (res.newUpdatedDate) config.workspace[idx].updated_date = res.newUpdatedDate;
|
|
@@ -177,7 +182,7 @@ async function push(opts = {}) {
|
|
|
177
182
|
pushedPb.push({ entry, idx });
|
|
178
183
|
} else if (entry.object_type === 'long_running_process') {
|
|
179
184
|
const res = await pushLrpEntry(token, entry, BACKUP_DIR, backupTs);
|
|
180
|
-
|
|
185
|
+
log(` ${entry.name} → saved`);
|
|
181
186
|
if (idx !== -1) {
|
|
182
187
|
config.workspace[idx].checksum_at_pull = res.newChecksum;
|
|
183
188
|
config.workspace[idx].tenant_id = res.newRow.tenantId;
|
|
@@ -197,7 +202,7 @@ async function push(opts = {}) {
|
|
|
197
202
|
pushed++;
|
|
198
203
|
}
|
|
199
204
|
|
|
200
|
-
|
|
205
|
+
log(`\nRemote backups written to ${BACKUP_DIR}/${backupTs}/`);
|
|
201
206
|
|
|
202
207
|
// Publish/deploy step for pushed wizards and LRPs.
|
|
203
208
|
if (pushedPb.length) {
|
|
@@ -208,7 +213,7 @@ async function push(opts = {}) {
|
|
|
208
213
|
}
|
|
209
214
|
|
|
210
215
|
writeConfig(config);
|
|
211
|
-
|
|
216
|
+
log(`\nPushed ${pushed} record(s).`);
|
|
212
217
|
}
|
|
213
218
|
|
|
214
219
|
async function handlePublish(token, pushedPb, config, opts) {
|
|
@@ -216,6 +221,8 @@ async function handlePublish(token, pushedPb, config, opts) {
|
|
|
216
221
|
let doPublish;
|
|
217
222
|
if (opts.skipPublish) doPublish = false;
|
|
218
223
|
else if (opts.publish) doPublish = true;
|
|
224
|
+
else if (opts.nonInteractive)
|
|
225
|
+
doPublish = false; // no stdin to prompt on; default to safe
|
|
219
226
|
else {
|
|
220
227
|
({ doPublish } = await inquirer.prompt([
|
|
221
228
|
{
|
|
@@ -229,7 +236,7 @@ async function handlePublish(token, pushedPb, config, opts) {
|
|
|
229
236
|
if (doPublish) {
|
|
230
237
|
await publish(token, entry.guid);
|
|
231
238
|
if (idx !== -1) config.workspace[idx].status = 'published';
|
|
232
|
-
|
|
239
|
+
log(` published ${entry.name}`);
|
|
233
240
|
}
|
|
234
241
|
}
|
|
235
242
|
}
|
|
@@ -239,6 +246,8 @@ async function handleDeploy(token, pushedLrp, config, opts) {
|
|
|
239
246
|
let doDeploy;
|
|
240
247
|
if (opts.skipPublish) doDeploy = false;
|
|
241
248
|
else if (opts.publish) doDeploy = true;
|
|
249
|
+
else if (opts.nonInteractive)
|
|
250
|
+
doDeploy = false; // no stdin to prompt on; default to safe
|
|
242
251
|
else {
|
|
243
252
|
({ doDeploy } = await inquirer.prompt([
|
|
244
253
|
{
|
|
@@ -252,7 +261,7 @@ async function handleDeploy(token, pushedLrp, config, opts) {
|
|
|
252
261
|
if (doDeploy) {
|
|
253
262
|
await deploy(token, deployId);
|
|
254
263
|
if (idx !== -1) config.workspace[idx].status = 'deployed';
|
|
255
|
-
|
|
264
|
+
log(` deployed ${entry.name}`);
|
|
256
265
|
}
|
|
257
266
|
}
|
|
258
267
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { log } from '../../lib/logger.js';
|
|
1
2
|
import { readConfig, writeConfig } from '../lib/config.js';
|
|
2
3
|
import { fileExists } from '../lib/workspace.js';
|
|
3
4
|
|
|
@@ -9,16 +10,16 @@ async function repair() {
|
|
|
9
10
|
config.workspace = config.workspace.filter((entry) => fileExists(entry.path));
|
|
10
11
|
|
|
11
12
|
if (!stale.length) {
|
|
12
|
-
|
|
13
|
+
log('No stale entries found.');
|
|
13
14
|
return;
|
|
14
15
|
}
|
|
15
16
|
|
|
16
17
|
for (const entry of stale) {
|
|
17
|
-
|
|
18
|
+
log(` removed: ${entry.path} (${entry.name})`);
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
writeConfig(config);
|
|
21
|
-
|
|
22
|
+
log(
|
|
22
23
|
`Removed ${stale.length} stale entr${stale.length === 1 ? 'y' : 'ies'} (${before} → ${config.workspace.length}).`
|
|
23
24
|
);
|
|
24
25
|
}
|
package/src/agrippa/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { createRequire } from 'module';
|
|
3
3
|
import { program } from 'commander';
|
|
4
|
+
import { error } from '../lib/logger.js';
|
|
4
5
|
import { clone } from './commands/clone.js';
|
|
5
6
|
import { diff } from './commands/diff.js';
|
|
6
7
|
import { init } from './commands/init.js';
|
|
@@ -24,7 +25,7 @@ const require = createRequire(import.meta.url);
|
|
|
24
25
|
const { version } = require('../../package.json');
|
|
25
26
|
|
|
26
27
|
process.on('unhandledRejection', (err) => {
|
|
27
|
-
|
|
28
|
+
error(`Error: ${err.message}`);
|
|
28
29
|
process.exit(1);
|
|
29
30
|
});
|
|
30
31
|
|
|
@@ -35,7 +36,7 @@ program
|
|
|
35
36
|
.description('Create agrippa.yaml workspace config in the current directory')
|
|
36
37
|
.action(() =>
|
|
37
38
|
init().catch((err) => {
|
|
38
|
-
|
|
39
|
+
error(`Error: ${err.message}`);
|
|
39
40
|
process.exit(1);
|
|
40
41
|
})
|
|
41
42
|
);
|
|
@@ -54,7 +55,7 @@ program
|
|
|
54
55
|
.option('--path <path>', 'Destination path (file for MFA, base dir for workflow/pb/lrp)')
|
|
55
56
|
.action((opts) =>
|
|
56
57
|
clone(opts).catch((err) => {
|
|
57
|
-
|
|
58
|
+
error(`Error: ${err.message}`);
|
|
58
59
|
process.exit(1);
|
|
59
60
|
})
|
|
60
61
|
);
|
|
@@ -62,9 +63,13 @@ program
|
|
|
62
63
|
program
|
|
63
64
|
.command('pull')
|
|
64
65
|
.description('Pull remote changes into local files')
|
|
65
|
-
.
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
.option(
|
|
67
|
+
'--non-interactive',
|
|
68
|
+
'No prompts; auto-select safe (fast-forward) entries and fail if any is in conflict'
|
|
69
|
+
)
|
|
70
|
+
.action((opts) =>
|
|
71
|
+
pull(opts).catch((err) => {
|
|
72
|
+
error(`Error: ${err.message}`);
|
|
68
73
|
process.exit(1);
|
|
69
74
|
})
|
|
70
75
|
);
|
|
@@ -74,9 +79,13 @@ program
|
|
|
74
79
|
.description('Push local changes to RIP / Process Builder / LRP (backs up remote first)')
|
|
75
80
|
.option('--publish', 'Auto-publish pushed wizards and auto-deploy pushed LRPs')
|
|
76
81
|
.option('--skip-publish', 'Skip publishing/deploying pushed wizards and LRPs (no prompt)')
|
|
82
|
+
.option(
|
|
83
|
+
'--non-interactive',
|
|
84
|
+
'No prompts; auto-select safe (fast-forward) entries and fail if any is in conflict'
|
|
85
|
+
)
|
|
77
86
|
.action((opts) =>
|
|
78
87
|
push(opts).catch((err) => {
|
|
79
|
-
|
|
88
|
+
error(`Error: ${err.message}`);
|
|
80
89
|
process.exit(1);
|
|
81
90
|
})
|
|
82
91
|
);
|
|
@@ -86,7 +95,7 @@ program
|
|
|
86
95
|
.description('Show differences between local files and remote code')
|
|
87
96
|
.action((path) =>
|
|
88
97
|
diff(path).catch((err) => {
|
|
89
|
-
|
|
98
|
+
error(`Error: ${err.message}`);
|
|
90
99
|
process.exit(1);
|
|
91
100
|
})
|
|
92
101
|
);
|
|
@@ -96,7 +105,7 @@ program
|
|
|
96
105
|
.description('Initialize a phase with default code template and result vars')
|
|
97
106
|
.action(() =>
|
|
98
107
|
initPhase().catch((err) => {
|
|
99
|
-
|
|
108
|
+
error(`Error: ${err.message}`);
|
|
100
109
|
process.exit(1);
|
|
101
110
|
})
|
|
102
111
|
);
|
|
@@ -106,14 +115,14 @@ program
|
|
|
106
115
|
.description('Remove stale workspace entries where local file no longer exists')
|
|
107
116
|
.action(() =>
|
|
108
117
|
repair().catch((err) => {
|
|
109
|
-
|
|
118
|
+
error(`Error: ${err.message}`);
|
|
110
119
|
process.exit(1);
|
|
111
120
|
})
|
|
112
121
|
);
|
|
113
122
|
|
|
114
123
|
// ---- pb: local editing helpers for a cloned process-builder wizard or LRP ----
|
|
115
124
|
const die = (err) => {
|
|
116
|
-
|
|
125
|
+
error(`Error: ${err.message}`);
|
|
117
126
|
process.exit(1);
|
|
118
127
|
};
|
|
119
128
|
const pb = program
|
|
@@ -154,7 +154,14 @@ async function autoLayout(structure) {
|
|
|
154
154
|
targets: [e.target],
|
|
155
155
|
sourcePort,
|
|
156
156
|
labels: e.name
|
|
157
|
-
? [
|
|
157
|
+
? [
|
|
158
|
+
{
|
|
159
|
+
id: `${e.id}__lbl`,
|
|
160
|
+
text: e.name,
|
|
161
|
+
width: Math.min(e.name.length * 6, 140),
|
|
162
|
+
height: 14,
|
|
163
|
+
},
|
|
164
|
+
]
|
|
158
165
|
: [],
|
|
159
166
|
layoutOptions: {
|
|
160
167
|
'elk.layered.priority.straightness': isHappy ? '10' : 1,
|
|
@@ -92,8 +92,12 @@ function toSvg(structure) {
|
|
|
92
92
|
);
|
|
93
93
|
if (e.name) {
|
|
94
94
|
const lp = e.labelPos;
|
|
95
|
-
const lx = lp
|
|
96
|
-
|
|
95
|
+
const lx = lp
|
|
96
|
+
? lp.x + lp.width / 2
|
|
97
|
+
: e.waypoints[Math.floor(e.waypoints.length / 2)][0];
|
|
98
|
+
const ly = lp
|
|
99
|
+
? lp.y + lp.height / 2
|
|
100
|
+
: e.waypoints[Math.floor(e.waypoints.length / 2)][1] - 4;
|
|
97
101
|
out.push(
|
|
98
102
|
`<text x="${lx + ox}" y="${ly + oy}" text-anchor="middle" fill="#666" font-size="9">${esc(e.name)}</text>`
|
|
99
103
|
);
|