@straiffi/archon 1.7.8 → 1.7.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/client/assets/{ActivityView-DwfDSF4q.js → ActivityView-IUWr92uj.js} +1 -1
- package/dist/client/assets/{GitHubActionsDialog-3dMCYCSZ.js → GitHubActionsDialog-0YtWvbFk.js} +1 -1
- package/dist/client/assets/VerificationDialog-B4Pyz1LV.js +4 -0
- package/dist/client/assets/{architectureDiagram-3BPJPVTR-Bdnc97XK.js → architectureDiagram-3BPJPVTR-LLMyOR-6.js} +1 -1
- package/dist/client/assets/{blockDiagram-GPEHLZMM-boxM3She.js → blockDiagram-GPEHLZMM-aa1HitBJ.js} +1 -1
- package/dist/client/assets/{c4Diagram-AAUBKEIU-CJDdF7xd.js → c4Diagram-AAUBKEIU-BpSt5sdj.js} +1 -1
- package/dist/client/assets/channel-DWPRC-jg.js +1 -0
- package/dist/client/assets/{chunk-2J33WTMH-ClpcO-Om.js → chunk-2J33WTMH-D8pf3RNr.js} +1 -1
- package/dist/client/assets/{chunk-3OPIFGDE-CcuL_65J.js → chunk-3OPIFGDE-_yx1N2iT.js} +1 -1
- package/dist/client/assets/{chunk-5ZQYHXKU-CUGYZXkH.js → chunk-5ZQYHXKU-CYURGSbL.js} +1 -1
- package/dist/client/assets/{chunk-727SXJPM-CApeLDyK.js → chunk-727SXJPM-Ci2Mu1zz.js} +1 -1
- package/dist/client/assets/{chunk-AQP2D5EJ-8FdSvF2D.js → chunk-AQP2D5EJ-CqVgrKze.js} +1 -1
- package/dist/client/assets/{chunk-CSCIHK7Q-CZoIOF3a.js → chunk-CSCIHK7Q-CT8aPk-o.js} +1 -1
- package/dist/client/assets/{chunk-KSCS5N6A-BigFQI5y.js → chunk-KSCS5N6A-yM1i0J-p.js} +1 -1
- package/dist/client/assets/{chunk-L5ZTLDWV-DIi3SHaT.js → chunk-L5ZTLDWV-BKMGr31Z.js} +1 -1
- package/dist/client/assets/{chunk-LZXEDZCA-B-Z0BcQy.js → chunk-LZXEDZCA-A7oUDETP.js} +2 -2
- package/dist/client/assets/{chunk-ND2GUHAM-EBeba0mg.js → chunk-ND2GUHAM-Cagc-XAG.js} +1 -1
- package/dist/client/assets/{chunk-NZK2D7GU-DJBI2y53.js → chunk-NZK2D7GU-pe8tKLWI.js} +1 -1
- package/dist/client/assets/{chunk-O5CBEL6O-BqxdXhMd.js → chunk-O5CBEL6O-BahwghWW.js} +1 -1
- package/dist/client/assets/{chunk-WU5MYG2G-Coe1_Cbb.js → chunk-WU5MYG2G-BfSAFufr.js} +1 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-DBZaZLLc.js +1 -0
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B7HsVFoJ.js +1 -0
- package/dist/client/assets/{dagre-BM42HDAG-tuTmeA0Y.js → dagre-BM42HDAG-DCma6-hS.js} +1 -1
- package/dist/client/assets/{diagram-2AECGRRQ-ILGCpG2F.js → diagram-2AECGRRQ-DUeggZrO.js} +1 -1
- package/dist/client/assets/{diagram-5GNKFQAL-C8qBZsgK.js → diagram-5GNKFQAL-CdjOKGtl.js} +1 -1
- package/dist/client/assets/{diagram-KO2AKTUF-BXlcm_Zo.js → diagram-KO2AKTUF-CYjXhgh_.js} +1 -1
- package/dist/client/assets/{diagram-LMA3HP47-B8V5EVbD.js → diagram-LMA3HP47-DYBCh4cm.js} +1 -1
- package/dist/client/assets/{diagram-OG6HWLK6-CWsdOqcP.js → diagram-OG6HWLK6-D3HPQt3z.js} +1 -1
- package/dist/client/assets/{erDiagram-TEJ5UH35-DW8pgly2.js → erDiagram-TEJ5UH35-mG8Yztg-.js} +1 -1
- package/dist/client/assets/{flowDiagram-I6XJVG4X-Djn7fOVR.js → flowDiagram-I6XJVG4X-4FvjuoSZ.js} +1 -1
- package/dist/client/assets/{ganttDiagram-6RSMTGT7-DZ421MEy.js → ganttDiagram-6RSMTGT7-ByCQI8ft.js} +1 -1
- package/dist/client/assets/{gitGraphDiagram-PVQCEYII-CCNzLPuP.js → gitGraphDiagram-PVQCEYII-CzEUA7nB.js} +1 -1
- package/dist/client/assets/index-D-miHTTb.js +273 -0
- package/dist/client/assets/index-TAQIlNdJ.css +2 -0
- package/dist/client/assets/{infoDiagram-5YYISTIA-Bd1gYgMp.js → infoDiagram-5YYISTIA-Q9CqnXO1.js} +1 -1
- package/dist/client/assets/{ishikawaDiagram-YF4QCWOH-txyMoatJ.js → ishikawaDiagram-YF4QCWOH-CO8BToGf.js} +1 -1
- package/dist/client/assets/{journeyDiagram-JHISSGLW-DhT3bmX6.js → journeyDiagram-JHISSGLW-DtOyWvDJ.js} +1 -1
- package/dist/client/assets/{kanban-definition-UN3LZRKU-BBHt2hfC.js → kanban-definition-UN3LZRKU-DIn9bYpk.js} +1 -1
- package/dist/client/assets/{line-KGRcT7Qz.js → line-H-k0M9_s.js} +1 -1
- package/dist/client/assets/{mermaid-parser.core-CDzt4_zR.js → mermaid-parser.core-CZOUS5zK.js} +1 -1
- package/dist/client/assets/{mermaid.core-DD_-k1aB.js → mermaid.core-Ck71Qr7h.js} +3 -3
- package/dist/client/assets/{mindmap-definition-RKZ34NQL-DoctVTDl.js → mindmap-definition-RKZ34NQL-BRFEcJw_.js} +1 -1
- package/dist/client/assets/{pieDiagram-4H26LBE5-DFlLEi70.js → pieDiagram-4H26LBE5-CwihXXcJ.js} +1 -1
- package/dist/client/assets/{quadrantDiagram-W4KKPZXB-3YHOQgl7.js → quadrantDiagram-W4KKPZXB-moiRw4Cm.js} +1 -1
- package/dist/client/assets/{requirementDiagram-4Y6WPE33-X4fZVL9M.js → requirementDiagram-4Y6WPE33-tshvM_vV.js} +1 -1
- package/dist/client/assets/{sankeyDiagram-5OEKKPKP-BUPnMXeG.js → sankeyDiagram-5OEKKPKP-rtKIuBEp.js} +1 -1
- package/dist/client/assets/{sequenceDiagram-3UESZ5HK-D6QU3M64.js → sequenceDiagram-3UESZ5HK-lkTCo4wE.js} +1 -1
- package/dist/client/assets/{stateDiagram-AJRCARHV-c35bu4qZ.js → stateDiagram-AJRCARHV-CFQhVUSd.js} +1 -1
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-rrN4DgWp.js +1 -0
- package/dist/client/assets/{timeline-definition-PNZ67QCA-CX2y6e_b.js → timeline-definition-PNZ67QCA-BmlQ7Wiy.js} +1 -1
- package/dist/client/assets/{vennDiagram-CIIHVFJN-BDaWltjF.js → vennDiagram-CIIHVFJN-CZyZepcT.js} +1 -1
- package/dist/client/assets/{wardleyDiagram-YWT4CUSO-BpBRL2sb.js → wardleyDiagram-YWT4CUSO-C2b52gni.js} +1 -1
- package/dist/client/assets/{xychartDiagram-2RQKCTM6-Bqw7X0UT.js → xychartDiagram-2RQKCTM6-FqnROUHq.js} +1 -1
- package/dist/client/index.html +2 -2
- package/dist/server/db.js +23 -10
- package/dist/server/db.js.map +1 -1
- package/dist/server/index.js +330 -25
- package/dist/server/index.js.map +1 -1
- package/dist/server/lib/agent.js +5 -4
- package/dist/server/lib/agent.js.map +1 -1
- package/dist/server/lib/automationCheckGate.js +114 -20
- package/dist/server/lib/automationCheckGate.js.map +1 -1
- package/dist/server/lib/automationProgression.js +2 -1
- package/dist/server/lib/automationProgression.js.map +1 -1
- package/dist/server/lib/automationReconciliation.js +19 -0
- package/dist/server/lib/automationReconciliation.js.map +1 -1
- package/dist/server/lib/automationResumeDecision.js +82 -0
- package/dist/server/lib/automationResumeDecision.js.map +1 -1
- package/dist/server/lib/automationReviewGate.js +142 -0
- package/dist/server/lib/automationReviewGate.js.map +1 -0
- package/dist/server/lib/automationStageDetails.js +98 -5
- package/dist/server/lib/automationStageDetails.js.map +1 -1
- package/dist/server/lib/buildCompletionContinuation.js +109 -0
- package/dist/server/lib/buildCompletionContinuation.js.map +1 -0
- package/dist/server/lib/buildSequences.js +81 -0
- package/dist/server/lib/buildSequences.js.map +1 -1
- package/dist/server/lib/buildTicketCommit.js +219 -0
- package/dist/server/lib/buildTicketCommit.js.map +1 -0
- package/dist/server/lib/bundleAutomationReadiness.js +7 -0
- package/dist/server/lib/bundleAutomationReadiness.js.map +1 -0
- package/dist/server/lib/bundleReviewOperations.js +17 -5
- package/dist/server/lib/bundleReviewOperations.js.map +1 -1
- package/dist/server/lib/chatOperations.js +2 -2
- package/dist/server/lib/chatOperations.js.map +1 -1
- package/dist/server/lib/checkDefinitions.js +11 -0
- package/dist/server/lib/checkDefinitions.js.map +1 -1
- package/dist/server/lib/checkGateEvaluations.js +4 -3
- package/dist/server/lib/checkGateEvaluations.js.map +1 -1
- package/dist/server/lib/checkRunner.js +27 -4
- package/dist/server/lib/checkRunner.js.map +1 -1
- package/dist/server/lib/checkRuns.js +38 -6
- package/dist/server/lib/checkRuns.js.map +1 -1
- package/dist/server/lib/git.js +5 -1
- package/dist/server/lib/git.js.map +1 -1
- package/dist/server/lib/lightweightPrompt.js +2 -1
- package/dist/server/lib/lightweightPrompt.js.map +1 -1
- package/dist/server/lib/projectAutoConfig.js +2 -1
- package/dist/server/lib/projectAutoConfig.js.map +1 -1
- package/dist/server/lib/projects.js +95 -10
- package/dist/server/lib/projects.js.map +1 -1
- package/dist/server/lib/requiredCheckPolicy.js +150 -19
- package/dist/server/lib/requiredCheckPolicy.js.map +1 -1
- package/dist/server/lib/run.js +3 -2
- package/dist/server/lib/run.js.map +1 -1
- package/dist/server/lib/terminal.js +5 -7
- package/dist/server/lib/terminal.js.map +1 -1
- package/dist/server/lib/testSessions.js +2 -2
- package/dist/server/lib/testSessions.js.map +1 -1
- package/dist/server/lib/ticketAutomationCommit.js +251 -160
- package/dist/server/lib/ticketAutomationCommit.js.map +1 -1
- package/dist/server/lib/tickets.js +45 -4
- package/dist/server/lib/tickets.js.map +1 -1
- package/dist/server/lib/types.js.map +1 -1
- package/dist/server/lib/workspaceProcessEnvironment.js +21 -0
- package/dist/server/lib/workspaceProcessEnvironment.js.map +1 -0
- package/dist/server/workers/build.js +57 -97
- package/dist/server/workers/build.js.map +1 -1
- package/dist/server/workers/chat.js +13 -6
- package/dist/server/workers/chat.js.map +1 -1
- package/dist/server/workers/followUp.js +92 -116
- package/dist/server/workers/followUp.js.map +1 -1
- package/dist/server/workers/plan.js +4 -1
- package/dist/server/workers/plan.js.map +1 -1
- package/package.json +1 -1
- package/dist/client/assets/VerificationDialog-CoTfXMyb.js +0 -4
- package/dist/client/assets/channel-BGqdAcIT.js +0 -1
- package/dist/client/assets/classDiagram-4FO5ZUOK-D5VuKRcj.js +0 -1
- package/dist/client/assets/classDiagram-v2-Q7XG4LA2-B9GNqpRr.js +0 -1
- package/dist/client/assets/index-BRc02lbW.js +0 -273
- package/dist/client/assets/index-CZO9HL1Z.css +0 -2
- package/dist/client/assets/stateDiagram-v2-BHNVJYJU-Ymy1_EHr.js +0 -1
|
@@ -12,7 +12,7 @@ import { getGitHubConnectionConfig } from './integrations/index.js';
|
|
|
12
12
|
import { upsertBundlePullRequestFromGitHub, } from './bundlePullRequests.js';
|
|
13
13
|
import { depthAtLeast, getBundleAutomationState, resolveAutomationConfig, } from './ticketAutomation.js';
|
|
14
14
|
import { completeAutomationProgressionInTransaction, completeAutomationProgression, getAutomationProgression, waitAutomationProgressionInTransaction, waitAutomationProgression, } from './automationProgression.js';
|
|
15
|
-
import { assertAutomationAuthorizationCurrent, authorizeAutomationBoundary, AutomationCheckGateError, } from './automationCheckGate.js';
|
|
15
|
+
import { assertAutomationBoundaryNotRequired, assertAutomationAuthorizationCurrent, authorizeAutomationBoundary, AutomationCheckGateError, } from './automationCheckGate.js';
|
|
16
16
|
import { AUTOMATION_STAGE_DETAILS_SCHEMA_VERSION, createAutomationStageDetails, ensureAutomationStageResult, getAutomationStageDetails, } from './automationStageDetails.js';
|
|
17
17
|
import { getProjectById } from './projects.js';
|
|
18
18
|
import { getExecutionRun, withExecutionRunTransaction } from './executionRuns.js';
|
|
@@ -160,7 +160,38 @@ const loadLiveState = (projectId, bundleId) => {
|
|
|
160
160
|
}
|
|
161
161
|
return { project, bundle, automationConfig: resolveAutomationConfig(bundle, project) };
|
|
162
162
|
};
|
|
163
|
-
const
|
|
163
|
+
const toStageCheckAuthorization = (authorization) => authorization.requirement === 'required'
|
|
164
|
+
? {
|
|
165
|
+
kind: 'required',
|
|
166
|
+
gateEvaluationId: authorization.evaluation.id,
|
|
167
|
+
policyFingerprint: authorization.policyFingerprint,
|
|
168
|
+
workspaceFingerprint: authorization.workspaceIdentity.fingerprint,
|
|
169
|
+
}
|
|
170
|
+
: {
|
|
171
|
+
kind: 'not_required',
|
|
172
|
+
policyFingerprint: authorization.policyFingerprint,
|
|
173
|
+
};
|
|
174
|
+
const assertBoundaryAuthorizationCurrent = async ({ authorization, project, bundle, progressionRunId, cwd, boundaryKind, }) => {
|
|
175
|
+
if (authorization.requirement === 'required') {
|
|
176
|
+
await assertAutomationAuthorizationCurrent({
|
|
177
|
+
project,
|
|
178
|
+
bundle,
|
|
179
|
+
progressionRunId,
|
|
180
|
+
cwd,
|
|
181
|
+
evaluationId: authorization.evaluation.id,
|
|
182
|
+
boundaryKind,
|
|
183
|
+
});
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
assertAutomationBoundaryNotRequired({
|
|
187
|
+
project,
|
|
188
|
+
bundle,
|
|
189
|
+
progressionRunId,
|
|
190
|
+
policyFingerprint: authorization.policyFingerprint,
|
|
191
|
+
boundaryKind,
|
|
192
|
+
});
|
|
193
|
+
};
|
|
194
|
+
const assertStageCanMutateWithPolicy = (projectId, bundleId, progressionRunId, ticket, mutationLabel, canMutateLive) => {
|
|
164
195
|
const live = loadLiveState(projectId, bundleId);
|
|
165
196
|
const progression = getAutomationProgression(projectId, bundleId);
|
|
166
197
|
const state = getBundleAutomationState(projectId, bundleId);
|
|
@@ -169,12 +200,12 @@ const assertStageCanMutate = (projectId, bundleId, progressionRunId, requiredDep
|
|
|
169
200
|
|| progression.status !== 'running'
|
|
170
201
|
|| state?.automation_progression_run_id !== progressionRunId
|
|
171
202
|
|| state.automation_paused_reason !== null
|
|
172
|
-
|| !
|
|
173
|
-
|
|
174
|
-
throw new Error(`automation no longer permits ${mutation} mutation`);
|
|
203
|
+
|| !canMutateLive(live, { ticket, progressionRunId })) {
|
|
204
|
+
throw new Error(`automation no longer permits ${mutationLabel} mutation`);
|
|
175
205
|
}
|
|
176
206
|
return live;
|
|
177
207
|
};
|
|
208
|
+
const assertStageCanMutate = (projectId, bundleId, progressionRunId, ticket, requiredDepth) => assertStageCanMutateWithPolicy(projectId, bundleId, progressionRunId, ticket, requiredDepth === 'auto_commit' ? 'commit' : requiredDepth === 'auto_push' ? 'push' : 'pull-request', live => depthAtLeast(live.automationConfig.depth, requiredDepth));
|
|
178
209
|
const githubConfigMatchesIntent = (githubConfig, intent) => (githubConfig.host.toLowerCase() === intent.repoHost.toLowerCase()
|
|
179
210
|
&& githubConfig.repo_owner.toLowerCase() === intent.repoOwner.toLowerCase()
|
|
180
211
|
&& githubConfig.repo_name.toLowerCase() === intent.repoName.toLowerCase()
|
|
@@ -322,6 +353,181 @@ const pauseBeforeStage = ({ projectId, bundleId, progressionRunId, pauseCode, re
|
|
|
322
353
|
pausedStageRunId: null,
|
|
323
354
|
broadcaster,
|
|
324
355
|
});
|
|
356
|
+
export const runAutomationCommitOperation = async ({ ticket, io, progressionRunId, allowedActiveChildRunId, retryOfRunId, mutationLabel, canCommitLive, shouldCompleteProgression, failureMode = 'return', requiredProgressionPurpose, }) => {
|
|
357
|
+
if (!ticket.project_id || !ticket.worktree_bundle_id) {
|
|
358
|
+
return null;
|
|
359
|
+
}
|
|
360
|
+
const projectId = ticket.project_id;
|
|
361
|
+
const bundleId = ticket.worktree_bundle_id;
|
|
362
|
+
const progression = getAutomationProgression(projectId, bundleId);
|
|
363
|
+
if (!progression || progression.id !== progressionRunId) {
|
|
364
|
+
return null;
|
|
365
|
+
}
|
|
366
|
+
const broadcaster = asBroadcaster(io);
|
|
367
|
+
let live = loadLiveState(projectId, bundleId);
|
|
368
|
+
if (!canCommitLive(live, { ticket, progressionRunId })) {
|
|
369
|
+
completeAutomationProgression({ projectId, bundleId, progressionRunId, broadcaster });
|
|
370
|
+
emitUpdated(io, ticket.id);
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
const branch = live.bundle.branch;
|
|
374
|
+
const cwd = live.bundle.kind === 'project_root'
|
|
375
|
+
? live.project.repo_path
|
|
376
|
+
: resolveWorktreePath(branch, live.project);
|
|
377
|
+
let commitRunId = null;
|
|
378
|
+
try {
|
|
379
|
+
const status = getGitStatus(cwd, branch, live.project);
|
|
380
|
+
const precondition = evaluateCommitPrecondition(status);
|
|
381
|
+
if (!precondition.ok) {
|
|
382
|
+
throw new Error(precondition.reason);
|
|
383
|
+
}
|
|
384
|
+
if (status.files.length === 0) {
|
|
385
|
+
const authorization = await authorizeAutomationBoundary({
|
|
386
|
+
project: live.project,
|
|
387
|
+
bundle: live.bundle,
|
|
388
|
+
progressionRunId,
|
|
389
|
+
cwd,
|
|
390
|
+
boundaryKind: 'automation_commit',
|
|
391
|
+
requiredProgressionPurpose,
|
|
392
|
+
broadcaster,
|
|
393
|
+
prepare: () => {
|
|
394
|
+
const head = getGitHeadIdentity(cwd);
|
|
395
|
+
return { head, indexTreeSha: getGitIndexTreeSha(cwd) };
|
|
396
|
+
},
|
|
397
|
+
resolveIntendedIdentity: (_value, workspaceIdentity) => ({
|
|
398
|
+
kind: 'workspace', fingerprint: workspaceIdentity.fingerprint,
|
|
399
|
+
}),
|
|
400
|
+
});
|
|
401
|
+
const { head, indexTreeSha } = authorization.value;
|
|
402
|
+
const intent = {
|
|
403
|
+
branch,
|
|
404
|
+
preActionHeadSha: head.headSha,
|
|
405
|
+
preActionIndexTreeSha: indexTreeSha,
|
|
406
|
+
intendedTreeSha: head.treeSha,
|
|
407
|
+
commitMessageDigest: EMPTY_MESSAGE_DIGEST,
|
|
408
|
+
selectedContentDigest: computeGitTreeDeltaDigest(cwd, head.headSha, head.treeSha),
|
|
409
|
+
checkAuthorization: toStageCheckAuthorization(authorization),
|
|
410
|
+
};
|
|
411
|
+
commitRunId = startStage({
|
|
412
|
+
projectId,
|
|
413
|
+
bundleId,
|
|
414
|
+
ticketId: ticket.id,
|
|
415
|
+
ticketTitle: ticket.title,
|
|
416
|
+
progressionRunId,
|
|
417
|
+
allowedActiveChildRunId,
|
|
418
|
+
stageKind: 'automation_commit',
|
|
419
|
+
intent,
|
|
420
|
+
broadcaster,
|
|
421
|
+
retryOfRunId,
|
|
422
|
+
});
|
|
423
|
+
await assertBoundaryAuthorizationCurrent({ authorization, project: live.project, bundle: live.bundle, progressionRunId, cwd, boundaryKind: 'automation_commit' });
|
|
424
|
+
live = loadLiveState(projectId, bundleId);
|
|
425
|
+
const result = {
|
|
426
|
+
outcome: 'no_changes',
|
|
427
|
+
headSha: head.headSha,
|
|
428
|
+
treeSha: head.treeSha,
|
|
429
|
+
};
|
|
430
|
+
finishStage({
|
|
431
|
+
projectId,
|
|
432
|
+
bundleId,
|
|
433
|
+
progressionRunId,
|
|
434
|
+
runId: commitRunId,
|
|
435
|
+
stageKind: 'automation_commit',
|
|
436
|
+
result,
|
|
437
|
+
outcome: 'no_changes',
|
|
438
|
+
completeProgression: shouldCompleteProgression(live, result),
|
|
439
|
+
broadcaster,
|
|
440
|
+
});
|
|
441
|
+
return { runId: commitRunId, ...result };
|
|
442
|
+
}
|
|
443
|
+
const selectedPaths = getAutomationCommitPaths(status.files);
|
|
444
|
+
const message = await generateCommitMessage(cwd, live.project, selectedPaths);
|
|
445
|
+
live = loadLiveState(projectId, bundleId);
|
|
446
|
+
if (!message) {
|
|
447
|
+
throw new Error('commit message generation produced an empty result');
|
|
448
|
+
}
|
|
449
|
+
if (!canCommitLive(live, { ticket, progressionRunId })) {
|
|
450
|
+
completeAutomationProgression({ projectId, bundleId, progressionRunId, broadcaster });
|
|
451
|
+
emitUpdated(io, ticket.id);
|
|
452
|
+
return null;
|
|
453
|
+
}
|
|
454
|
+
const authorization = await authorizeAutomationBoundary({
|
|
455
|
+
project: live.project,
|
|
456
|
+
bundle: live.bundle,
|
|
457
|
+
progressionRunId,
|
|
458
|
+
cwd,
|
|
459
|
+
boundaryKind: 'automation_commit',
|
|
460
|
+
requiredProgressionPurpose,
|
|
461
|
+
broadcaster,
|
|
462
|
+
prepare: () => prepareAutomationCommit(cwd, branch, live.project, selectedPaths),
|
|
463
|
+
resolveIntendedIdentity: (_value, workspaceIdentity) => ({
|
|
464
|
+
kind: 'workspace', fingerprint: workspaceIdentity.fingerprint,
|
|
465
|
+
}),
|
|
466
|
+
});
|
|
467
|
+
const prepared = authorization.value;
|
|
468
|
+
const intent = {
|
|
469
|
+
branch,
|
|
470
|
+
preActionHeadSha: prepared.preActionHeadSha,
|
|
471
|
+
preActionIndexTreeSha: prepared.preActionIndexTreeSha,
|
|
472
|
+
intendedTreeSha: prepared.intendedTreeSha,
|
|
473
|
+
commitMessageDigest: digestCommitMessage(message),
|
|
474
|
+
selectedContentDigest: prepared.selectedContentDigest,
|
|
475
|
+
checkAuthorization: toStageCheckAuthorization(authorization),
|
|
476
|
+
};
|
|
477
|
+
commitRunId = startStage({
|
|
478
|
+
projectId,
|
|
479
|
+
bundleId,
|
|
480
|
+
ticketId: ticket.id,
|
|
481
|
+
ticketTitle: ticket.title,
|
|
482
|
+
progressionRunId,
|
|
483
|
+
allowedActiveChildRunId,
|
|
484
|
+
stageKind: 'automation_commit',
|
|
485
|
+
intent,
|
|
486
|
+
broadcaster,
|
|
487
|
+
retryOfRunId,
|
|
488
|
+
});
|
|
489
|
+
await assertBoundaryAuthorizationCurrent({ authorization, project: live.project, bundle: live.bundle, progressionRunId, cwd, boundaryKind: 'automation_commit' });
|
|
490
|
+
live = assertStageCanMutateWithPolicy(projectId, bundleId, progressionRunId, ticket, mutationLabel, canCommitLive);
|
|
491
|
+
const result = await commitPreparedAutomationChanges(cwd, branch, live.project, message, prepared);
|
|
492
|
+
live = loadLiveState(projectId, bundleId);
|
|
493
|
+
finishStage({
|
|
494
|
+
projectId,
|
|
495
|
+
bundleId,
|
|
496
|
+
progressionRunId,
|
|
497
|
+
runId: commitRunId,
|
|
498
|
+
stageKind: 'automation_commit',
|
|
499
|
+
result,
|
|
500
|
+
outcome: 'committed',
|
|
501
|
+
completeProgression: shouldCompleteProgression(live, result),
|
|
502
|
+
broadcaster,
|
|
503
|
+
});
|
|
504
|
+
return { outcome: 'committed', runId: commitRunId, ...result };
|
|
505
|
+
}
|
|
506
|
+
catch (error) {
|
|
507
|
+
if (error instanceof AutomationCheckGateError) {
|
|
508
|
+
if (commitRunId) {
|
|
509
|
+
failStageAuthorization({ projectId, bundleId, progressionRunId, runId: commitRunId, stageKind: 'automation_commit', error, broadcaster });
|
|
510
|
+
}
|
|
511
|
+
emitBundleUpdated(io, ticket);
|
|
512
|
+
if (failureMode === 'throw') {
|
|
513
|
+
throw error;
|
|
514
|
+
}
|
|
515
|
+
return null;
|
|
516
|
+
}
|
|
517
|
+
const reason = `commit failed: ${getErrorMessage(error)}`;
|
|
518
|
+
if (commitRunId) {
|
|
519
|
+
failStage({ projectId, bundleId, progressionRunId, runId: commitRunId, stageKind: 'automation_commit', pauseCode: 'commit', reason, ambiguous: true, broadcaster });
|
|
520
|
+
}
|
|
521
|
+
else {
|
|
522
|
+
pauseBeforeStage({ projectId, bundleId, progressionRunId, pauseCode: 'commit', reason, broadcaster });
|
|
523
|
+
}
|
|
524
|
+
emitUpdated(io, ticket.id);
|
|
525
|
+
if (failureMode === 'throw') {
|
|
526
|
+
throw error;
|
|
527
|
+
}
|
|
528
|
+
return null;
|
|
529
|
+
}
|
|
530
|
+
};
|
|
325
531
|
const remoteStatesEqual = (left, right) => (left.state === right.state && (left.state === 'absent' || (right.state === 'observed' && left.sha === right.sha)));
|
|
326
532
|
export const runAutomationCommitChain = async (ticket, _project, _bundle, _automationConfig, io, progressionRunId, resumeFrom, triggeringReviewRunId) => {
|
|
327
533
|
if (!ticket.project_id || !ticket.worktree_bundle_id) {
|
|
@@ -342,143 +548,30 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
342
548
|
|| (resumeFrom.stageKind === 'automation_push' && !isRetry)));
|
|
343
549
|
let expectedHeadSha = resumeFrom?.expectedHeadSha ?? null;
|
|
344
550
|
let live = loadLiveState(projectId, bundleId);
|
|
345
|
-
if (!depthAtLeast(live.automationConfig.depth, 'auto_commit')) {
|
|
346
|
-
completeAutomationProgression({ projectId, bundleId, progressionRunId, broadcaster });
|
|
347
|
-
emitUpdated(io, ticket.id);
|
|
348
|
-
return;
|
|
349
|
-
}
|
|
350
551
|
const branch = live.bundle.branch;
|
|
351
552
|
const cwd = live.bundle.kind === 'project_root'
|
|
352
553
|
? live.project.repo_path
|
|
353
554
|
: resolveWorktreePath(branch, live.project);
|
|
354
|
-
let commitRunId = null;
|
|
355
555
|
if (!skipCommit) {
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
cwd,
|
|
368
|
-
boundaryKind: 'automation_commit',
|
|
369
|
-
broadcaster,
|
|
370
|
-
resolveIntendedIdentity: workspaceIdentity => {
|
|
371
|
-
const head = getGitHeadIdentity(cwd);
|
|
372
|
-
return {
|
|
373
|
-
intendedIdentity: { kind: 'git_tree', treeSha: head.treeSha, workspaceFingerprint: workspaceIdentity.fingerprint },
|
|
374
|
-
value: { head, indexTreeSha: getGitIndexTreeSha(cwd) },
|
|
375
|
-
};
|
|
376
|
-
},
|
|
377
|
-
});
|
|
378
|
-
const { head, indexTreeSha } = authorization.value;
|
|
379
|
-
const intent = {
|
|
380
|
-
branch,
|
|
381
|
-
preActionHeadSha: head.headSha,
|
|
382
|
-
preActionIndexTreeSha: indexTreeSha,
|
|
383
|
-
intendedTreeSha: head.treeSha,
|
|
384
|
-
commitMessageDigest: EMPTY_MESSAGE_DIGEST,
|
|
385
|
-
selectedContentDigest: computeGitTreeDeltaDigest(cwd, head.headSha, head.treeSha),
|
|
386
|
-
gateEvaluationId: authorization.evaluation.id,
|
|
387
|
-
policyFingerprint: authorization.policyFingerprint,
|
|
388
|
-
workspaceFingerprint: authorization.workspaceIdentity.fingerprint,
|
|
389
|
-
};
|
|
390
|
-
commitRunId = startStage({ projectId, bundleId, ticketId: ticket.id, ticketTitle: ticket.title, progressionRunId, allowedActiveChildRunId: triggeringReviewRunId, stageKind: 'automation_commit', intent, broadcaster, retryOfRunId: resumeFrom?.stageKind === 'automation_commit' ? resumeFrom.retryOfRunId : undefined });
|
|
391
|
-
await assertAutomationAuthorizationCurrent({ project: live.project, bundle: live.bundle, progressionRunId, cwd, evaluationId: authorization.evaluation.id, boundaryKind: 'automation_commit' });
|
|
392
|
-
live = loadLiveState(projectId, bundleId);
|
|
393
|
-
finishStage({
|
|
394
|
-
projectId,
|
|
395
|
-
bundleId,
|
|
396
|
-
progressionRunId,
|
|
397
|
-
runId: commitRunId,
|
|
398
|
-
stageKind: 'automation_commit',
|
|
399
|
-
result: { outcome: 'no_changes', headSha: head.headSha, treeSha: head.treeSha },
|
|
400
|
-
outcome: 'no_changes',
|
|
401
|
-
completeProgression: !depthAtLeast(live.automationConfig.depth, 'auto_push'),
|
|
402
|
-
broadcaster,
|
|
403
|
-
});
|
|
404
|
-
expectedHeadSha = head.headSha;
|
|
405
|
-
}
|
|
406
|
-
else {
|
|
407
|
-
const selectedPaths = getAutomationCommitPaths(status.files);
|
|
408
|
-
const message = await generateCommitMessage(cwd, live.project, selectedPaths);
|
|
409
|
-
live = loadLiveState(projectId, bundleId);
|
|
410
|
-
if (!message) {
|
|
411
|
-
throw new Error('commit message generation produced an empty result');
|
|
412
|
-
}
|
|
413
|
-
if (!depthAtLeast(live.automationConfig.depth, 'auto_commit')) {
|
|
414
|
-
completeAutomationProgression({ projectId, bundleId, progressionRunId, broadcaster });
|
|
415
|
-
emitUpdated(io, ticket.id);
|
|
416
|
-
return;
|
|
417
|
-
}
|
|
418
|
-
const authorization = await authorizeAutomationBoundary({
|
|
419
|
-
project: live.project,
|
|
420
|
-
bundle: live.bundle,
|
|
421
|
-
progressionRunId,
|
|
422
|
-
cwd,
|
|
423
|
-
boundaryKind: 'automation_commit',
|
|
424
|
-
broadcaster,
|
|
425
|
-
resolveIntendedIdentity: workspaceIdentity => {
|
|
426
|
-
const prepared = prepareAutomationCommit(cwd, branch, live.project, selectedPaths);
|
|
427
|
-
return {
|
|
428
|
-
intendedIdentity: { kind: 'git_tree', treeSha: prepared.intendedTreeSha, workspaceFingerprint: workspaceIdentity.fingerprint },
|
|
429
|
-
value: prepared,
|
|
430
|
-
};
|
|
431
|
-
},
|
|
432
|
-
});
|
|
433
|
-
const prepared = authorization.value;
|
|
434
|
-
const intent = {
|
|
435
|
-
branch,
|
|
436
|
-
preActionHeadSha: prepared.preActionHeadSha,
|
|
437
|
-
preActionIndexTreeSha: prepared.preActionIndexTreeSha,
|
|
438
|
-
intendedTreeSha: prepared.intendedTreeSha,
|
|
439
|
-
commitMessageDigest: digestCommitMessage(message),
|
|
440
|
-
selectedContentDigest: prepared.selectedContentDigest,
|
|
441
|
-
gateEvaluationId: authorization.evaluation.id,
|
|
442
|
-
policyFingerprint: authorization.policyFingerprint,
|
|
443
|
-
workspaceFingerprint: authorization.workspaceIdentity.fingerprint,
|
|
444
|
-
};
|
|
445
|
-
commitRunId = startStage({ projectId, bundleId, ticketId: ticket.id, ticketTitle: ticket.title, progressionRunId, allowedActiveChildRunId: triggeringReviewRunId, stageKind: 'automation_commit', intent, broadcaster, retryOfRunId: resumeFrom?.stageKind === 'automation_commit' ? resumeFrom.retryOfRunId : undefined });
|
|
446
|
-
await assertAutomationAuthorizationCurrent({ project: live.project, bundle: live.bundle, progressionRunId, cwd, evaluationId: authorization.evaluation.id, boundaryKind: 'automation_commit' });
|
|
447
|
-
live = assertStageCanMutate(projectId, bundleId, progressionRunId, 'auto_commit');
|
|
448
|
-
const result = await commitPreparedAutomationChanges(cwd, branch, live.project, message, prepared);
|
|
449
|
-
live = loadLiveState(projectId, bundleId);
|
|
450
|
-
finishStage({
|
|
451
|
-
projectId,
|
|
452
|
-
bundleId,
|
|
453
|
-
progressionRunId,
|
|
454
|
-
runId: commitRunId,
|
|
455
|
-
stageKind: 'automation_commit',
|
|
456
|
-
result,
|
|
457
|
-
outcome: 'committed',
|
|
458
|
-
completeProgression: !depthAtLeast(live.automationConfig.depth, 'auto_push'),
|
|
459
|
-
broadcaster,
|
|
460
|
-
});
|
|
461
|
-
expectedHeadSha = result.commitSha;
|
|
462
|
-
}
|
|
463
|
-
}
|
|
464
|
-
catch (error) {
|
|
465
|
-
if (error instanceof AutomationCheckGateError) {
|
|
466
|
-
if (commitRunId) {
|
|
467
|
-
failStageAuthorization({ projectId, bundleId, progressionRunId, runId: commitRunId, stageKind: 'automation_commit', error, broadcaster });
|
|
468
|
-
}
|
|
469
|
-
emitBundleUpdated(io, ticket);
|
|
470
|
-
return;
|
|
471
|
-
}
|
|
472
|
-
const reason = `commit failed: ${getErrorMessage(error)}`;
|
|
473
|
-
if (commitRunId) {
|
|
474
|
-
failStage({ projectId, bundleId, progressionRunId, runId: commitRunId, stageKind: 'automation_commit', pauseCode: 'commit', reason, ambiguous: true, broadcaster });
|
|
475
|
-
}
|
|
476
|
-
else {
|
|
477
|
-
pauseBeforeStage({ projectId, bundleId, progressionRunId, pauseCode: 'commit', reason, broadcaster });
|
|
478
|
-
}
|
|
479
|
-
emitUpdated(io, ticket.id);
|
|
556
|
+
const commitResult = await runAutomationCommitOperation({
|
|
557
|
+
ticket,
|
|
558
|
+
io,
|
|
559
|
+
progressionRunId,
|
|
560
|
+
allowedActiveChildRunId: triggeringReviewRunId,
|
|
561
|
+
retryOfRunId: resumeFrom?.stageKind === 'automation_commit' ? resumeFrom.retryOfRunId : undefined,
|
|
562
|
+
mutationLabel: 'commit',
|
|
563
|
+
canCommitLive: current => depthAtLeast(current.automationConfig.depth, 'auto_commit'),
|
|
564
|
+
shouldCompleteProgression: current => !depthAtLeast(current.automationConfig.depth, 'auto_push'),
|
|
565
|
+
});
|
|
566
|
+
if (!commitResult) {
|
|
480
567
|
return;
|
|
481
568
|
}
|
|
569
|
+
if (commitResult.outcome === 'committed') {
|
|
570
|
+
expectedHeadSha = commitResult.commitSha;
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
expectedHeadSha = commitResult.headSha;
|
|
574
|
+
}
|
|
482
575
|
}
|
|
483
576
|
live = loadLiveState(projectId, bundleId);
|
|
484
577
|
if (getAutomationProgression(projectId, bundleId)?.id !== progressionRunId) {
|
|
@@ -515,24 +608,23 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
515
608
|
cwd,
|
|
516
609
|
boundaryKind: 'automation_push',
|
|
517
610
|
broadcaster,
|
|
518
|
-
|
|
611
|
+
prepare: () => {
|
|
519
612
|
const head = getGitHeadIdentity(cwd);
|
|
520
613
|
if (head.headSha !== target) {
|
|
521
614
|
throw new Error('HEAD changed while required checks were evaluated for push');
|
|
522
615
|
}
|
|
523
|
-
return
|
|
524
|
-
intendedIdentity: { kind: 'commit', commitSha: target, workspaceFingerprint: workspaceIdentity.fingerprint },
|
|
525
|
-
value: head,
|
|
526
|
-
};
|
|
616
|
+
return head;
|
|
527
617
|
},
|
|
618
|
+
resolveIntendedIdentity: (_value, workspaceIdentity) => ({
|
|
619
|
+
kind: 'commit', commitSha: target, workspaceFingerprint: workspaceIdentity.fingerprint,
|
|
620
|
+
}),
|
|
528
621
|
});
|
|
529
622
|
const intent = {
|
|
530
623
|
branch,
|
|
531
624
|
originIdentity,
|
|
532
625
|
targetLocalSha: target,
|
|
533
626
|
preActionRemote,
|
|
534
|
-
|
|
535
|
-
policyFingerprint: authorization.policyFingerprint,
|
|
627
|
+
checkAuthorization: toStageCheckAuthorization(authorization),
|
|
536
628
|
intendedTreeSha: authorization.value.treeSha,
|
|
537
629
|
resultingCommitSha: target,
|
|
538
630
|
};
|
|
@@ -540,14 +632,14 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
540
632
|
const current = await fetchRemoteBranchState(cwd, branch, originIdentity);
|
|
541
633
|
live = loadLiveState(projectId, bundleId);
|
|
542
634
|
if (current.state === 'observed' && current.sha === target) {
|
|
543
|
-
await
|
|
544
|
-
live = assertStageCanMutate(projectId, bundleId, progressionRunId, 'auto_push');
|
|
635
|
+
await assertBoundaryAuthorizationCurrent({ authorization, project: live.project, bundle: live.bundle, progressionRunId, cwd, boundaryKind: 'automation_push' });
|
|
636
|
+
live = assertStageCanMutate(projectId, bundleId, progressionRunId, ticket, 'auto_push');
|
|
545
637
|
finishStage({ projectId, bundleId, progressionRunId, runId: pushRunId, stageKind: 'automation_push', result: { remoteSha: target }, outcome: 'already_current', completeProgression: !depthAtLeast(live.automationConfig.depth, 'auto_pr'), broadcaster });
|
|
546
638
|
expectedHeadSha = target;
|
|
547
639
|
}
|
|
548
640
|
else if (remoteStatesEqual(current, preActionRemote)) {
|
|
549
|
-
await
|
|
550
|
-
live = assertStageCanMutate(projectId, bundleId, progressionRunId, 'auto_push');
|
|
641
|
+
await assertBoundaryAuthorizationCurrent({ authorization, project: live.project, bundle: live.bundle, progressionRunId, cwd, boundaryKind: 'automation_push' });
|
|
642
|
+
live = assertStageCanMutate(projectId, bundleId, progressionRunId, ticket, 'auto_push');
|
|
551
643
|
await pushAutomationTarget(cwd, branch, target, originIdentity);
|
|
552
644
|
live = loadLiveState(projectId, bundleId);
|
|
553
645
|
const observed = await fetchRemoteBranchState(cwd, branch, originIdentity);
|
|
@@ -613,16 +705,16 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
613
705
|
cwd,
|
|
614
706
|
boundaryKind: 'automation_pull_request',
|
|
615
707
|
broadcaster,
|
|
616
|
-
|
|
708
|
+
prepare: () => {
|
|
617
709
|
const head = getGitHeadIdentity(cwd);
|
|
618
710
|
if (head.headSha !== headSha) {
|
|
619
711
|
throw new Error('HEAD changed while required checks were evaluated for pull request');
|
|
620
712
|
}
|
|
621
|
-
return
|
|
622
|
-
intendedIdentity: { kind: 'commit', commitSha: headSha, workspaceFingerprint: workspaceIdentity.fingerprint },
|
|
623
|
-
value: head,
|
|
624
|
-
};
|
|
713
|
+
return head;
|
|
625
714
|
},
|
|
715
|
+
resolveIntendedIdentity: (_value, workspaceIdentity) => ({
|
|
716
|
+
kind: 'commit', commitSha: headSha, workspaceFingerprint: workspaceIdentity.fingerprint,
|
|
717
|
+
}),
|
|
626
718
|
});
|
|
627
719
|
const intent = {
|
|
628
720
|
provider: 'github',
|
|
@@ -632,8 +724,7 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
632
724
|
baseBranch: githubConfig.default_base_branch,
|
|
633
725
|
headBranch: branch,
|
|
634
726
|
headSha,
|
|
635
|
-
|
|
636
|
-
policyFingerprint: authorization.policyFingerprint,
|
|
727
|
+
checkAuthorization: toStageCheckAuthorization(authorization),
|
|
637
728
|
intendedTreeSha: authorization.value.treeSha,
|
|
638
729
|
resultingCommitSha: headSha,
|
|
639
730
|
};
|
|
@@ -643,8 +734,8 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
643
734
|
let pullRequest;
|
|
644
735
|
let outcome;
|
|
645
736
|
if (observation.outcome === 'exact') {
|
|
646
|
-
await
|
|
647
|
-
live = assertStageCanMutate(projectId, bundleId, progressionRunId, 'auto_pr');
|
|
737
|
+
await assertBoundaryAuthorizationCurrent({ authorization, project: live.project, bundle: live.bundle, progressionRunId, cwd, boundaryKind: 'automation_pull_request' });
|
|
738
|
+
live = assertStageCanMutate(projectId, bundleId, progressionRunId, ticket, 'auto_pr');
|
|
648
739
|
pullRequest = observation.pullRequest;
|
|
649
740
|
outcome = 'already_exists';
|
|
650
741
|
}
|
|
@@ -655,8 +746,8 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
655
746
|
if (!currentConfig || !githubConfigMatchesIntent(currentConfig, intent)) {
|
|
656
747
|
throw new Error('GitHub configuration changed while the pull-request stage was active');
|
|
657
748
|
}
|
|
658
|
-
live = assertStageCanMutate(projectId, bundleId, progressionRunId, 'auto_pr');
|
|
659
|
-
await
|
|
749
|
+
live = assertStageCanMutate(projectId, bundleId, progressionRunId, ticket, 'auto_pr');
|
|
750
|
+
await assertBoundaryAuthorizationCurrent({ authorization, project: live.project, bundle: live.bundle, progressionRunId, cwd, boundaryKind: 'automation_pull_request' });
|
|
660
751
|
if (getGitHeadIdentity(cwd).headSha !== intent.headSha) {
|
|
661
752
|
throw new Error('HEAD changed while the pull-request stage was active');
|
|
662
753
|
}
|
|
@@ -668,12 +759,12 @@ export const runAutomationCommitChain = async (ticket, _project, _bundle, _autom
|
|
|
668
759
|
if (!mutationConfig || !githubConfigMatchesIntent(mutationConfig, intent)) {
|
|
669
760
|
throw new Error('GitHub configuration changed while the pull-request stage was active');
|
|
670
761
|
}
|
|
671
|
-
live = assertStageCanMutate(projectId, bundleId, progressionRunId, 'auto_pr');
|
|
762
|
+
live = assertStageCanMutate(projectId, bundleId, progressionRunId, ticket, 'auto_pr');
|
|
672
763
|
if (getGitHeadIdentity(cwd).headSha !== intent.headSha) {
|
|
673
764
|
throw new Error('HEAD changed before pull-request creation');
|
|
674
765
|
}
|
|
675
|
-
await
|
|
676
|
-
live = assertStageCanMutate(projectId, bundleId, progressionRunId, 'auto_pr');
|
|
766
|
+
await assertBoundaryAuthorizationCurrent({ authorization, project: live.project, bundle: live.bundle, progressionRunId, cwd, boundaryKind: 'automation_pull_request' });
|
|
767
|
+
live = assertStageCanMutate(projectId, bundleId, progressionRunId, ticket, 'auto_pr');
|
|
677
768
|
pullRequest = await createGitHubPullRequest(mutationConfig, {
|
|
678
769
|
title: content.title,
|
|
679
770
|
body: content.body,
|