@vypdev/copilot 3.5.2 → 3.5.4
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/build/cli/index.js
CHANGED
|
@@ -38159,6 +38159,27 @@ function runAtApplicationErrorBoundary(operation) {
|
|
|
38159
38159
|
}
|
|
38160
38160
|
|
|
38161
38161
|
|
|
38162
|
+
/***/ }),
|
|
38163
|
+
|
|
38164
|
+
/***/ 72594:
|
|
38165
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
38166
|
+
|
|
38167
|
+
"use strict";
|
|
38168
|
+
|
|
38169
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
38170
|
+
exports.DeploymentMergeEffectError = void 0;
|
|
38171
|
+
const application_error_1 = __nccwpck_require__(75999);
|
|
38172
|
+
/** Semantic effect failure. Only a confirmed readiness rejection permits one new inspection. */
|
|
38173
|
+
class DeploymentMergeEffectError extends application_error_1.ApplicationError {
|
|
38174
|
+
constructor(action, readinessChanged, code, message, cause) {
|
|
38175
|
+
super(code, message, { cause });
|
|
38176
|
+
this.action = action;
|
|
38177
|
+
this.readinessChanged = readinessChanged;
|
|
38178
|
+
}
|
|
38179
|
+
}
|
|
38180
|
+
exports.DeploymentMergeEffectError = DeploymentMergeEffectError;
|
|
38181
|
+
|
|
38182
|
+
|
|
38162
38183
|
/***/ }),
|
|
38163
38184
|
|
|
38164
38185
|
/***/ 38313:
|
|
@@ -51843,6 +51864,91 @@ function bindSddEvidenceReadPorts(ports) {
|
|
|
51843
51864
|
}
|
|
51844
51865
|
|
|
51845
51866
|
|
|
51867
|
+
/***/ }),
|
|
51868
|
+
|
|
51869
|
+
/***/ 84387:
|
|
51870
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
51871
|
+
|
|
51872
|
+
"use strict";
|
|
51873
|
+
|
|
51874
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
51875
|
+
exports.DeploymentMergeEffects = void 0;
|
|
51876
|
+
const application_error_1 = __nccwpck_require__(75999);
|
|
51877
|
+
const deployment_merge_effect_error_1 = __nccwpck_require__(72594);
|
|
51878
|
+
const managed_pull_request_1 = __nccwpck_require__(95914);
|
|
51879
|
+
/** Applies current policy, with one bounded re-observation after a typed readiness rejection. */
|
|
51880
|
+
class DeploymentMergeEffects {
|
|
51881
|
+
constructor(pullRequests) {
|
|
51882
|
+
this.pullRequests = pullRequests;
|
|
51883
|
+
}
|
|
51884
|
+
async configure(operation, pullRequest, inspection, inspect, beforeApply) {
|
|
51885
|
+
await beforeApply(inspection.decision.mode);
|
|
51886
|
+
const action = selectAction(operation, inspection);
|
|
51887
|
+
try {
|
|
51888
|
+
await this.apply(action, pullRequest);
|
|
51889
|
+
return inspection.decision.mode;
|
|
51890
|
+
}
|
|
51891
|
+
catch (error) {
|
|
51892
|
+
if (!(error instanceof deployment_merge_effect_error_1.DeploymentMergeEffectError) || !error.readinessChanged || operation.prMode !== "auto")
|
|
51893
|
+
throw error;
|
|
51894
|
+
const current = await this.pullRequests.getPullRequest(pullRequest.number);
|
|
51895
|
+
assertSamePullRequest(pullRequest, current);
|
|
51896
|
+
if (current.merged)
|
|
51897
|
+
return inspection.decision.mode;
|
|
51898
|
+
if (current.state !== "open")
|
|
51899
|
+
throw new application_error_1.ApplicationError("provider.conflict", "The managed PR was closed without merging.");
|
|
51900
|
+
const refreshed = await inspect(current);
|
|
51901
|
+
if (refreshed.kind === "blocked")
|
|
51902
|
+
throw new application_error_1.ApplicationError("provider.conflict", refreshed.reason);
|
|
51903
|
+
const nextAction = selectAction(operation, refreshed);
|
|
51904
|
+
if (nextAction === action) {
|
|
51905
|
+
if (action === "enable-auto-merge" && current.autoMergeEnabled)
|
|
51906
|
+
return refreshed.decision.mode;
|
|
51907
|
+
throw error;
|
|
51908
|
+
}
|
|
51909
|
+
await beforeApply(refreshed.decision.mode);
|
|
51910
|
+
await this.apply(nextAction, current);
|
|
51911
|
+
return refreshed.decision.mode;
|
|
51912
|
+
}
|
|
51913
|
+
}
|
|
51914
|
+
async apply(action, pullRequest) {
|
|
51915
|
+
try {
|
|
51916
|
+
if (action === "merge") {
|
|
51917
|
+
await this.pullRequests.mergePullRequest(pullRequest.number, pullRequest.headSha);
|
|
51918
|
+
}
|
|
51919
|
+
else if (action === "enable-auto-merge" && !pullRequest.autoMergeEnabled) {
|
|
51920
|
+
await this.pullRequests.enableAutoMerge(pullRequest.nodeId, pullRequest.headSha);
|
|
51921
|
+
}
|
|
51922
|
+
else if (action === "merge-queue" && !await this.pullRequests.isPullRequestQueued(pullRequest.nodeId)) {
|
|
51923
|
+
await this.pullRequests.enqueuePullRequest(pullRequest.nodeId, pullRequest.headSha);
|
|
51924
|
+
}
|
|
51925
|
+
}
|
|
51926
|
+
catch (cause) {
|
|
51927
|
+
if (cause instanceof application_error_1.ApplicationError)
|
|
51928
|
+
throw cause;
|
|
51929
|
+
throw new application_error_1.ApplicationError("workflow.failed", `Automatic merge action ${action} failed with an unclassified provider rejection.`, { cause, retryable: true });
|
|
51930
|
+
}
|
|
51931
|
+
}
|
|
51932
|
+
}
|
|
51933
|
+
exports.DeploymentMergeEffects = DeploymentMergeEffects;
|
|
51934
|
+
function selectAction(operation, inspection) {
|
|
51935
|
+
if (inspection.decision.mode !== "auto-merge")
|
|
51936
|
+
return inspection.decision.mode;
|
|
51937
|
+
return operation.prMode === "auto" && inspection.capabilities.immediatelyMergeable ? "merge" : "enable-auto-merge";
|
|
51938
|
+
}
|
|
51939
|
+
function assertSamePullRequest(expected, current) {
|
|
51940
|
+
const marker = (0, managed_pull_request_1.parseManagedPullRequestMarker)(expected.body);
|
|
51941
|
+
const currentMarker = (0, managed_pull_request_1.parseManagedPullRequestMarker)(current.body);
|
|
51942
|
+
if (expected.number !== current.number || expected.nodeId !== current.nodeId
|
|
51943
|
+
|| expected.repositoryFullName !== current.repositoryFullName || expected.baseBranch !== current.baseBranch
|
|
51944
|
+
|| expected.headBranch !== current.headBranch || expected.headSha !== current.headSha
|
|
51945
|
+
|| !marker || !currentMarker || marker.operationId !== currentMarker.operationId
|
|
51946
|
+
|| marker.phase !== currentMarker.phase || marker.issue !== currentMarker.issue) {
|
|
51947
|
+
throw new application_error_1.ApplicationError("provider.conflict", "The managed PR identity or frozen head changed during merge setup.", { retryable: false });
|
|
51948
|
+
}
|
|
51949
|
+
}
|
|
51950
|
+
|
|
51951
|
+
|
|
51846
51952
|
/***/ }),
|
|
51847
51953
|
|
|
51848
51954
|
/***/ 77658:
|
|
@@ -51867,6 +51973,7 @@ const deployment_message_catalog_1 = __nccwpck_require__(79364);
|
|
|
51867
51973
|
const deployment_operation_1 = __nccwpck_require__(92730);
|
|
51868
51974
|
const merge_queue_readiness_1 = __nccwpck_require__(12515);
|
|
51869
51975
|
const result_1 = __nccwpck_require__(73817);
|
|
51976
|
+
const deployment_merge_effects_1 = __nccwpck_require__(84387);
|
|
51870
51977
|
exports.DEPLOYMENT_ORCHESTRATION_TASK_ID = "DeploymentOrchestrationUseCase";
|
|
51871
51978
|
class DeploymentOrchestrationRuntime {
|
|
51872
51979
|
constructor(dependencies, stateBoundary) {
|
|
@@ -51941,12 +52048,19 @@ class DeploymentOrchestrationRuntime {
|
|
|
51941
52048
|
result: await this.block(context, operation, category, inspection.reason, true),
|
|
51942
52049
|
};
|
|
51943
52050
|
}
|
|
51944
|
-
|
|
51945
|
-
|
|
51946
|
-
|
|
51947
|
-
|
|
51948
|
-
|
|
51949
|
-
|
|
52051
|
+
let managed = operation;
|
|
52052
|
+
try {
|
|
52053
|
+
await new deployment_merge_effects_1.DeploymentMergeEffects(this.dependencies.pullRequests).configure(operation, pullRequest, inspection, (current) => this.inspectMergeBehavior(context, operation, current.baseBranch, targetRole, current.headSha, current.number), async (mode) => {
|
|
52054
|
+
managed = { ...operation, selectedPrMode: mode };
|
|
52055
|
+
await this.persist(context, managed);
|
|
52056
|
+
});
|
|
52057
|
+
}
|
|
52058
|
+
catch (cause) {
|
|
52059
|
+
const diagnostic = (0, application_error_1.toApplicationError)(cause, "workflow.failed", "Automatic merge setup failed with an unclassified provider rejection.", { retryable: true });
|
|
52060
|
+
const message = `GitHub could not configure automatic merge for PR #${pullRequest.number}. ${diagnostic.message} Check the PR and retry the stored ${category} phase.`;
|
|
52061
|
+
const error = new application_error_1.ApplicationError(diagnostic.code, message, { cause, retryable: diagnostic.retryable });
|
|
52062
|
+
return { kind: "blocked", result: await this.block(context, managed, category, message, error.retryable, error) };
|
|
52063
|
+
}
|
|
51950
52064
|
await this.publishDashboard(context, managed);
|
|
51951
52065
|
return { kind: "configured", operation: managed };
|
|
51952
52066
|
}
|
|
@@ -52000,27 +52114,6 @@ class DeploymentOrchestrationRuntime {
|
|
|
52000
52114
|
// Preserve the original provider failure returned by the coordinator.
|
|
52001
52115
|
}
|
|
52002
52116
|
}
|
|
52003
|
-
async applyMergeBehavior(context, operation, pullRequest, inspection) {
|
|
52004
|
-
if (inspection.decision.mode === "auto-merge") {
|
|
52005
|
-
await this.applyAutoMerge(context, operation, pullRequest, inspection.capabilities);
|
|
52006
|
-
return;
|
|
52007
|
-
}
|
|
52008
|
-
if (inspection.decision.mode === "merge-queue") {
|
|
52009
|
-
const queued = await this.dependencies.pullRequests.isPullRequestQueued(pullRequest.nodeId);
|
|
52010
|
-
if (!queued) {
|
|
52011
|
-
await this.dependencies.pullRequests.enqueuePullRequest(pullRequest.nodeId, pullRequest.headSha);
|
|
52012
|
-
}
|
|
52013
|
-
}
|
|
52014
|
-
}
|
|
52015
|
-
async applyAutoMerge(context, operation, pullRequest, capabilities) {
|
|
52016
|
-
if (operation.prMode === "auto" && capabilities.immediatelyMergeable) {
|
|
52017
|
-
await this.dependencies.pullRequests.mergePullRequest(pullRequest.number, pullRequest.headSha);
|
|
52018
|
-
return;
|
|
52019
|
-
}
|
|
52020
|
-
if (!pullRequest.autoMergeEnabled) {
|
|
52021
|
-
await this.dependencies.pullRequests.enableAutoMerge(pullRequest.nodeId);
|
|
52022
|
-
}
|
|
52023
|
-
}
|
|
52024
52117
|
async unsupportedMergeBehavior(context, operation, targetRole, targetBranch, capabilities, decision) {
|
|
52025
52118
|
const catalog = await this.presentationCatalog('issue', context, operation);
|
|
52026
52119
|
if (capabilities.mergeQueueObservationProblems.length === 0) {
|
|
@@ -52876,22 +52969,19 @@ const application_error_1 = __nccwpck_require__(75999);
|
|
|
52876
52969
|
const deployment_plan_policy_1 = __nccwpck_require__(8352);
|
|
52877
52970
|
const deployment_operation_1 = __nccwpck_require__(92730);
|
|
52878
52971
|
const deployment_orchestration_runtime_1 = __nccwpck_require__(77658);
|
|
52972
|
+
const deployment_continuation_guard_1 = __nccwpck_require__(1779);
|
|
52879
52973
|
class ConfirmPublicationHandler {
|
|
52880
52974
|
constructor(runtime, reconciliation) {
|
|
52881
52975
|
this.runtime = runtime;
|
|
52882
52976
|
this.reconciliation = reconciliation;
|
|
52883
52977
|
}
|
|
52884
52978
|
async invoke(context) {
|
|
52885
|
-
const
|
|
52886
|
-
|
|
52887
|
-
|
|
52888
|
-
|
|
52889
|
-
|
|
52890
|
-
|
|
52891
|
-
await this.runtime.publishDashboard(context, operation);
|
|
52892
|
-
return (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Publication for ${operation.tag} was already verified; duplicate notification ignored.`);
|
|
52893
|
-
}
|
|
52894
|
-
assertPublicationPhase(operation);
|
|
52979
|
+
const current = (0, deployment_orchestration_runtime_1.requireDeploymentOperation)(context);
|
|
52980
|
+
const invalid = (0, deployment_continuation_guard_1.validateDeploymentContinuation)(current, context.singleAction.operationId, ["published", "publishing", "promoted", "reconciliation_pending", "completed"], context.singleAction.version);
|
|
52981
|
+
if (invalid)
|
|
52982
|
+
throw new application_error_1.ApplicationError("workflow.stale", invalid);
|
|
52983
|
+
// Verify external receipts before clearing a block or retrying any merge/cleanup effect.
|
|
52984
|
+
const operation = current;
|
|
52895
52985
|
const productionSha = requireProductionSha(operation);
|
|
52896
52986
|
const publication = await this.runtime.dependencies.publication.inspect({
|
|
52897
52987
|
tag: operation.tag,
|
|
@@ -52908,8 +52998,18 @@ class ConfirmPublicationHandler {
|
|
|
52908
52998
|
if (!reachable) {
|
|
52909
52999
|
return await this.runtime.block(context, operation, "publication", "Published SHA is not reachable from the stored production branch.", false);
|
|
52910
53000
|
}
|
|
53001
|
+
const resumed = await this.resumeRetryableBlock(context, operation);
|
|
53002
|
+
if (resumed.phase === "reconciliation_pending" && resumed.publicationVerified) {
|
|
53003
|
+
return await this.reconciliation.plan(context, resumed)
|
|
53004
|
+
?? (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Publication for ${resumed.tag} was already verified; reconciliation state was recovered.`);
|
|
53005
|
+
}
|
|
53006
|
+
if (resumed.phase === "completed" && resumed.publicationVerified) {
|
|
53007
|
+
await this.runtime.publishDashboard(context, resumed);
|
|
53008
|
+
return (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Publication for ${resumed.tag} was already verified; duplicate notification ignored.`);
|
|
53009
|
+
}
|
|
53010
|
+
assertPublicationPhase(resumed);
|
|
52911
53011
|
const published = {
|
|
52912
|
-
...
|
|
53012
|
+
...resumed,
|
|
52913
53013
|
phase: "published",
|
|
52914
53014
|
publicationVerified: true,
|
|
52915
53015
|
publicationReceipt: publication.receipt,
|
|
@@ -53228,6 +53328,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
53228
53328
|
exports.ReconciliationHandler = void 0;
|
|
53229
53329
|
const deployment_plan_policy_1 = __nccwpck_require__(8352);
|
|
53230
53330
|
const deployment_operation_1 = __nccwpck_require__(92730);
|
|
53331
|
+
const managed_pull_request_1 = __nccwpck_require__(95914);
|
|
53231
53332
|
const deployment_orchestration_runtime_1 = __nccwpck_require__(77658);
|
|
53232
53333
|
class ReconciliationHandler {
|
|
53233
53334
|
constructor(runtime) {
|
|
@@ -53264,10 +53365,12 @@ class ReconciliationHandler {
|
|
|
53264
53365
|
return await this.complete(context, updated, ` after reconciliation PR #${pullRequest.number}`);
|
|
53265
53366
|
}
|
|
53266
53367
|
async plan(context, operation) {
|
|
53267
|
-
const index = operation.reconciliationTargets.findIndex((target) => target.status === "pending"
|
|
53368
|
+
const index = operation.reconciliationTargets.findIndex((target) => target.status === "pending");
|
|
53268
53369
|
if (index < 0)
|
|
53269
53370
|
return await this.finishOrPresent(context, operation);
|
|
53270
53371
|
let target = operation.reconciliationTargets[index];
|
|
53372
|
+
if (target.pullRequest !== undefined)
|
|
53373
|
+
return await this.resumePullRequest(context, operation, target);
|
|
53271
53374
|
const targetRole = (0, deployment_orchestration_runtime_1.reconciliationTargetRole)(operation, target.targetBranch);
|
|
53272
53375
|
const preflight = await this.runtime.inspectMergeBehavior(context, operation, target.targetBranch, targetRole, target.sourceSha);
|
|
53273
53376
|
if (preflight.kind === "blocked") {
|
|
@@ -53324,6 +53427,26 @@ class ReconciliationHandler {
|
|
|
53324
53427
|
await this.runtime.publishMilestone(context, completed, { kind: "orchestration-complete", tag: completed.tag });
|
|
53325
53428
|
return (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Deployment ${completed.tag} completed${completionContext}.`);
|
|
53326
53429
|
}
|
|
53430
|
+
async resumePullRequest(context, operation, target) {
|
|
53431
|
+
const pullRequest = await this.runtime.dependencies.pullRequests.getPullRequest(target.pullRequest);
|
|
53432
|
+
const identity = (0, managed_pull_request_1.parseManagedPullRequestMarker)(pullRequest.body);
|
|
53433
|
+
const expectedHead = target.syncBranch ? target.syncSha : target.sourceSha;
|
|
53434
|
+
if (!identity || identity.operationId !== operation.operationId || identity.phase !== "reconciliation"
|
|
53435
|
+
|| identity.issue !== context.singleAction.issue || pullRequest.number !== target.pullRequest
|
|
53436
|
+
|| pullRequest.repositoryFullName.toLowerCase() !== `${context.owner}/${context.repo}`.toLowerCase()
|
|
53437
|
+
|| pullRequest.baseBranch !== target.targetBranch
|
|
53438
|
+
|| pullRequest.headBranch !== (target.syncBranch ?? target.sourceBranch)
|
|
53439
|
+
|| !expectedHead || pullRequest.headSha !== expectedHead) {
|
|
53440
|
+
return await this.runtime.block(context, operation, "reconciliation", "The recorded reconciliation PR no longer matches its durable identity and head SHA.", false);
|
|
53441
|
+
}
|
|
53442
|
+
if (pullRequest.merged)
|
|
53443
|
+
return await this.accept(context, operation, pullRequest);
|
|
53444
|
+
if (pullRequest.state === "closed") {
|
|
53445
|
+
return await this.runtime.block(context, operation, "reconciliation", `Reconciliation PR #${pullRequest.number} was closed without merge.`, true);
|
|
53446
|
+
}
|
|
53447
|
+
const configured = await this.runtime.configureMergeBehavior(context, operation, pullRequest, "reconciliation", (0, deployment_orchestration_runtime_1.reconciliationTargetRole)(operation, target.targetBranch));
|
|
53448
|
+
return configured.kind === "blocked" ? configured.result : undefined;
|
|
53449
|
+
}
|
|
53327
53450
|
async finishOrPresent(context, operation) {
|
|
53328
53451
|
if (operation.reconciliationTargets.length > 0
|
|
53329
53452
|
&& operation.reconciliationTargets.every((target) => target.status === "completed")) {
|
|
@@ -79302,6 +79425,47 @@ function isNotFound(error) {
|
|
|
79302
79425
|
}
|
|
79303
79426
|
|
|
79304
79427
|
|
|
79428
|
+
/***/ }),
|
|
79429
|
+
|
|
79430
|
+
/***/ 30873:
|
|
79431
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
79432
|
+
|
|
79433
|
+
"use strict";
|
|
79434
|
+
|
|
79435
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
79436
|
+
exports.githubDeploymentMergeError = githubDeploymentMergeError;
|
|
79437
|
+
const deployment_merge_effect_error_1 = __nccwpck_require__(72594);
|
|
79438
|
+
/** Never copy provider messages, request objects, headers, or arbitrary error types into public state. */
|
|
79439
|
+
function githubDeploymentMergeError(action, cause) {
|
|
79440
|
+
const value = isRecord(cause) ? cause : {};
|
|
79441
|
+
const status = typeof value.status === "number" && Number.isInteger(value.status)
|
|
79442
|
+
&& value.status >= 100 && value.status <= 599 ? value.status : undefined;
|
|
79443
|
+
const rawErrors = Array.isArray(value.errors) ? value.errors : [];
|
|
79444
|
+
const errors = rawErrors.filter(isRecord);
|
|
79445
|
+
const types = errors.map((error) => error.type);
|
|
79446
|
+
const denied = status === 401 || status === 403 || types.includes("FORBIDDEN") || types.includes("UNAUTHORIZED");
|
|
79447
|
+
const limited = status === 429 || types.includes("RATE_LIMITED");
|
|
79448
|
+
const unavailable = (status !== undefined && status >= 500) || types.includes("INTERNAL") || types.includes("SERVICE_UNAVAILABLE");
|
|
79449
|
+
const cleanRejection = rawErrors.length === 1 && errors.length === 1 && errors[0].type === "UNPROCESSABLE"
|
|
79450
|
+
&& typeof errors[0].message === "string"
|
|
79451
|
+
&& ["Pull request is in clean status", "Pull request Pull request is in clean status",
|
|
79452
|
+
"Pull request is in unstable status", "Pull request Pull request is in unstable status"].includes(errors[0].message);
|
|
79453
|
+
const readinessChanged = !denied && !limited && !unavailable
|
|
79454
|
+
&& ((action === "merge" && status === 405) || (action === "enable-auto-merge" && (status === undefined || status === 200) && cleanRejection));
|
|
79455
|
+
const code = denied ? "authorization.denied"
|
|
79456
|
+
: limited ? "provider.rate-limited"
|
|
79457
|
+
: unavailable ? "provider.unavailable"
|
|
79458
|
+
: status === 404 || types.includes("NOT_FOUND") ? "provider.not-found"
|
|
79459
|
+
: status !== undefined || types.length > 0 ? "provider.conflict" : "workflow.failed";
|
|
79460
|
+
const reason = readinessChanged ? "readiness-changed" : code;
|
|
79461
|
+
const http = status === undefined ? "" : `; HTTP ${status}`;
|
|
79462
|
+
return new deployment_merge_effect_error_1.DeploymentMergeEffectError(action, readinessChanged, code, `GitHub rejected ${action} (${reason}${http}).`, cause);
|
|
79463
|
+
}
|
|
79464
|
+
function isRecord(value) {
|
|
79465
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
79466
|
+
}
|
|
79467
|
+
|
|
79468
|
+
|
|
79305
79469
|
/***/ }),
|
|
79306
79470
|
|
|
79307
79471
|
/***/ 96483:
|
|
@@ -79312,6 +79476,8 @@ function isNotFound(error) {
|
|
|
79312
79476
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
79313
79477
|
exports.GithubManagedPullRequestRepository = void 0;
|
|
79314
79478
|
const managed_pull_request_1 = __nccwpck_require__(95914);
|
|
79479
|
+
const github_deployment_merge_error_1 = __nccwpck_require__(30873);
|
|
79480
|
+
const deployment_merge_effect_error_1 = __nccwpck_require__(72594);
|
|
79315
79481
|
class GithubManagedPullRequestRepository {
|
|
79316
79482
|
constructor(clientProvider) {
|
|
79317
79483
|
this.clientProvider = clientProvider;
|
|
@@ -79355,12 +79521,21 @@ class GithubManagedPullRequestRepository {
|
|
|
79355
79521
|
});
|
|
79356
79522
|
return mapPullRequest(data, owner, repository);
|
|
79357
79523
|
}
|
|
79358
|
-
async enableAutoMerge(
|
|
79359
|
-
|
|
79360
|
-
|
|
79361
|
-
|
|
79524
|
+
async enableAutoMerge(_owner, _repository, pullRequestNodeId, expectedHeadSha, token) {
|
|
79525
|
+
let response;
|
|
79526
|
+
try {
|
|
79527
|
+
response = await this.clientProvider.getClient(token).graphql(`mutation EnableDeploymentAutoMerge($pullRequestId: ID!, $expectedHeadOid: GitObjectID!) {
|
|
79528
|
+
enablePullRequestAutoMerge(input: {pullRequestId: $pullRequestId, expectedHeadOid: $expectedHeadOid, mergeMethod: MERGE}) {
|
|
79529
|
+
pullRequest { id }
|
|
79530
|
+
}
|
|
79531
|
+
}`, { pullRequestId: pullRequestNodeId, expectedHeadOid: expectedHeadSha });
|
|
79532
|
+
}
|
|
79533
|
+
catch (cause) {
|
|
79534
|
+
throw (0, github_deployment_merge_error_1.githubDeploymentMergeError)("enable-auto-merge", cause);
|
|
79535
|
+
}
|
|
79536
|
+
if (response?.enablePullRequestAutoMerge?.pullRequest?.id !== pullRequestNodeId) {
|
|
79537
|
+
throw new deployment_merge_effect_error_1.DeploymentMergeEffectError("enable-auto-merge", false, "provider.contract-invalid", "GitHub did not confirm native auto-merge for the expected PR.");
|
|
79362
79538
|
}
|
|
79363
|
-
}`, { pullRequestId: pullRequestNodeId, owner, repository });
|
|
79364
79539
|
}
|
|
79365
79540
|
async isPullRequestQueued(owner, repository, pullRequestNodeId, token) {
|
|
79366
79541
|
const response = await this.clientProvider.getClient(token).graphql(`query DeploymentPullRequestQueue($pullRequestId: ID!) {
|
|
@@ -79384,15 +79559,18 @@ class GithubManagedPullRequestRepository {
|
|
|
79384
79559
|
}
|
|
79385
79560
|
}
|
|
79386
79561
|
async mergePullRequest(owner, repository, pullRequest, expectedHeadSha, token) {
|
|
79387
|
-
|
|
79388
|
-
|
|
79389
|
-
|
|
79390
|
-
|
|
79391
|
-
|
|
79392
|
-
|
|
79393
|
-
|
|
79394
|
-
|
|
79395
|
-
|
|
79562
|
+
let data;
|
|
79563
|
+
try {
|
|
79564
|
+
({ data } = await this.clientProvider.getClient(token).rest.pulls.merge({
|
|
79565
|
+
owner, repo: repository, pull_number: pullRequest, merge_method: "merge", sha: expectedHeadSha,
|
|
79566
|
+
}));
|
|
79567
|
+
}
|
|
79568
|
+
catch (cause) {
|
|
79569
|
+
throw (0, github_deployment_merge_error_1.githubDeploymentMergeError)("merge", cause);
|
|
79570
|
+
}
|
|
79571
|
+
if (!data?.merged || typeof data.sha !== "string" || !/^[a-f0-9]{40}$/i.test(data.sha)) {
|
|
79572
|
+
throw new deployment_merge_effect_error_1.DeploymentMergeEffectError("merge", false, "provider.contract-invalid", "GitHub did not confirm a completed merge with a valid commit SHA.");
|
|
79573
|
+
}
|
|
79396
79574
|
return data.sha;
|
|
79397
79575
|
}
|
|
79398
79576
|
}
|
|
@@ -92436,7 +92614,7 @@ function bindManagedPullRequests(port, binding) {
|
|
|
92436
92614
|
findManagedPullRequests: (query) => port.findManagedPullRequests({ ...query, owner: binding.owner, repository: binding.repository, token: binding.token }),
|
|
92437
92615
|
createManagedPullRequest: (command) => port.createManagedPullRequest({ ...command, owner: binding.owner, repository: binding.repository, token: binding.token }),
|
|
92438
92616
|
getPullRequest: (pullRequest) => port.getPullRequest(binding.owner, binding.repository, pullRequest, binding.token),
|
|
92439
|
-
enableAutoMerge: (pullRequestNodeId) => port.enableAutoMerge(binding.owner, binding.repository, pullRequestNodeId, binding.token),
|
|
92617
|
+
enableAutoMerge: (pullRequestNodeId, expectedHeadSha) => port.enableAutoMerge(binding.owner, binding.repository, pullRequestNodeId, expectedHeadSha, binding.token),
|
|
92440
92618
|
isPullRequestQueued: (pullRequestNodeId) => port.isPullRequestQueued(binding.owner, binding.repository, pullRequestNodeId, binding.token),
|
|
92441
92619
|
enqueuePullRequest: (pullRequestNodeId, expectedHeadSha) => port.enqueuePullRequest(binding.owner, binding.repository, pullRequestNodeId, expectedHeadSha, binding.token),
|
|
92442
92620
|
mergePullRequest: (pullRequest, expectedHeadSha) => port.mergePullRequest(binding.owner, binding.repository, pullRequest, expectedHeadSha, binding.token),
|
|
@@ -38816,6 +38816,27 @@ function runAtApplicationErrorBoundary(operation) {
|
|
|
38816
38816
|
}
|
|
38817
38817
|
|
|
38818
38818
|
|
|
38819
|
+
/***/ }),
|
|
38820
|
+
|
|
38821
|
+
/***/ 72594:
|
|
38822
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
38823
|
+
|
|
38824
|
+
"use strict";
|
|
38825
|
+
|
|
38826
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
38827
|
+
exports.DeploymentMergeEffectError = void 0;
|
|
38828
|
+
const application_error_1 = __nccwpck_require__(75999);
|
|
38829
|
+
/** Semantic effect failure. Only a confirmed readiness rejection permits one new inspection. */
|
|
38830
|
+
class DeploymentMergeEffectError extends application_error_1.ApplicationError {
|
|
38831
|
+
constructor(action, readinessChanged, code, message, cause) {
|
|
38832
|
+
super(code, message, { cause });
|
|
38833
|
+
this.action = action;
|
|
38834
|
+
this.readinessChanged = readinessChanged;
|
|
38835
|
+
}
|
|
38836
|
+
}
|
|
38837
|
+
exports.DeploymentMergeEffectError = DeploymentMergeEffectError;
|
|
38838
|
+
|
|
38839
|
+
|
|
38819
38840
|
/***/ }),
|
|
38820
38841
|
|
|
38821
38842
|
/***/ 61544:
|
|
@@ -50157,6 +50178,91 @@ function bindSddEvidenceReadPorts(ports) {
|
|
|
50157
50178
|
}
|
|
50158
50179
|
|
|
50159
50180
|
|
|
50181
|
+
/***/ }),
|
|
50182
|
+
|
|
50183
|
+
/***/ 84387:
|
|
50184
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
50185
|
+
|
|
50186
|
+
"use strict";
|
|
50187
|
+
|
|
50188
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
50189
|
+
exports.DeploymentMergeEffects = void 0;
|
|
50190
|
+
const application_error_1 = __nccwpck_require__(75999);
|
|
50191
|
+
const deployment_merge_effect_error_1 = __nccwpck_require__(72594);
|
|
50192
|
+
const managed_pull_request_1 = __nccwpck_require__(95914);
|
|
50193
|
+
/** Applies current policy, with one bounded re-observation after a typed readiness rejection. */
|
|
50194
|
+
class DeploymentMergeEffects {
|
|
50195
|
+
constructor(pullRequests) {
|
|
50196
|
+
this.pullRequests = pullRequests;
|
|
50197
|
+
}
|
|
50198
|
+
async configure(operation, pullRequest, inspection, inspect, beforeApply) {
|
|
50199
|
+
await beforeApply(inspection.decision.mode);
|
|
50200
|
+
const action = selectAction(operation, inspection);
|
|
50201
|
+
try {
|
|
50202
|
+
await this.apply(action, pullRequest);
|
|
50203
|
+
return inspection.decision.mode;
|
|
50204
|
+
}
|
|
50205
|
+
catch (error) {
|
|
50206
|
+
if (!(error instanceof deployment_merge_effect_error_1.DeploymentMergeEffectError) || !error.readinessChanged || operation.prMode !== "auto")
|
|
50207
|
+
throw error;
|
|
50208
|
+
const current = await this.pullRequests.getPullRequest(pullRequest.number);
|
|
50209
|
+
assertSamePullRequest(pullRequest, current);
|
|
50210
|
+
if (current.merged)
|
|
50211
|
+
return inspection.decision.mode;
|
|
50212
|
+
if (current.state !== "open")
|
|
50213
|
+
throw new application_error_1.ApplicationError("provider.conflict", "The managed PR was closed without merging.");
|
|
50214
|
+
const refreshed = await inspect(current);
|
|
50215
|
+
if (refreshed.kind === "blocked")
|
|
50216
|
+
throw new application_error_1.ApplicationError("provider.conflict", refreshed.reason);
|
|
50217
|
+
const nextAction = selectAction(operation, refreshed);
|
|
50218
|
+
if (nextAction === action) {
|
|
50219
|
+
if (action === "enable-auto-merge" && current.autoMergeEnabled)
|
|
50220
|
+
return refreshed.decision.mode;
|
|
50221
|
+
throw error;
|
|
50222
|
+
}
|
|
50223
|
+
await beforeApply(refreshed.decision.mode);
|
|
50224
|
+
await this.apply(nextAction, current);
|
|
50225
|
+
return refreshed.decision.mode;
|
|
50226
|
+
}
|
|
50227
|
+
}
|
|
50228
|
+
async apply(action, pullRequest) {
|
|
50229
|
+
try {
|
|
50230
|
+
if (action === "merge") {
|
|
50231
|
+
await this.pullRequests.mergePullRequest(pullRequest.number, pullRequest.headSha);
|
|
50232
|
+
}
|
|
50233
|
+
else if (action === "enable-auto-merge" && !pullRequest.autoMergeEnabled) {
|
|
50234
|
+
await this.pullRequests.enableAutoMerge(pullRequest.nodeId, pullRequest.headSha);
|
|
50235
|
+
}
|
|
50236
|
+
else if (action === "merge-queue" && !await this.pullRequests.isPullRequestQueued(pullRequest.nodeId)) {
|
|
50237
|
+
await this.pullRequests.enqueuePullRequest(pullRequest.nodeId, pullRequest.headSha);
|
|
50238
|
+
}
|
|
50239
|
+
}
|
|
50240
|
+
catch (cause) {
|
|
50241
|
+
if (cause instanceof application_error_1.ApplicationError)
|
|
50242
|
+
throw cause;
|
|
50243
|
+
throw new application_error_1.ApplicationError("workflow.failed", `Automatic merge action ${action} failed with an unclassified provider rejection.`, { cause, retryable: true });
|
|
50244
|
+
}
|
|
50245
|
+
}
|
|
50246
|
+
}
|
|
50247
|
+
exports.DeploymentMergeEffects = DeploymentMergeEffects;
|
|
50248
|
+
function selectAction(operation, inspection) {
|
|
50249
|
+
if (inspection.decision.mode !== "auto-merge")
|
|
50250
|
+
return inspection.decision.mode;
|
|
50251
|
+
return operation.prMode === "auto" && inspection.capabilities.immediatelyMergeable ? "merge" : "enable-auto-merge";
|
|
50252
|
+
}
|
|
50253
|
+
function assertSamePullRequest(expected, current) {
|
|
50254
|
+
const marker = (0, managed_pull_request_1.parseManagedPullRequestMarker)(expected.body);
|
|
50255
|
+
const currentMarker = (0, managed_pull_request_1.parseManagedPullRequestMarker)(current.body);
|
|
50256
|
+
if (expected.number !== current.number || expected.nodeId !== current.nodeId
|
|
50257
|
+
|| expected.repositoryFullName !== current.repositoryFullName || expected.baseBranch !== current.baseBranch
|
|
50258
|
+
|| expected.headBranch !== current.headBranch || expected.headSha !== current.headSha
|
|
50259
|
+
|| !marker || !currentMarker || marker.operationId !== currentMarker.operationId
|
|
50260
|
+
|| marker.phase !== currentMarker.phase || marker.issue !== currentMarker.issue) {
|
|
50261
|
+
throw new application_error_1.ApplicationError("provider.conflict", "The managed PR identity or frozen head changed during merge setup.", { retryable: false });
|
|
50262
|
+
}
|
|
50263
|
+
}
|
|
50264
|
+
|
|
50265
|
+
|
|
50160
50266
|
/***/ }),
|
|
50161
50267
|
|
|
50162
50268
|
/***/ 77658:
|
|
@@ -50181,6 +50287,7 @@ const deployment_message_catalog_1 = __nccwpck_require__(79364);
|
|
|
50181
50287
|
const deployment_operation_1 = __nccwpck_require__(92730);
|
|
50182
50288
|
const merge_queue_readiness_1 = __nccwpck_require__(12515);
|
|
50183
50289
|
const result_1 = __nccwpck_require__(73817);
|
|
50290
|
+
const deployment_merge_effects_1 = __nccwpck_require__(84387);
|
|
50184
50291
|
exports.DEPLOYMENT_ORCHESTRATION_TASK_ID = "DeploymentOrchestrationUseCase";
|
|
50185
50292
|
class DeploymentOrchestrationRuntime {
|
|
50186
50293
|
constructor(dependencies, stateBoundary) {
|
|
@@ -50255,12 +50362,19 @@ class DeploymentOrchestrationRuntime {
|
|
|
50255
50362
|
result: await this.block(context, operation, category, inspection.reason, true),
|
|
50256
50363
|
};
|
|
50257
50364
|
}
|
|
50258
|
-
|
|
50259
|
-
|
|
50260
|
-
|
|
50261
|
-
|
|
50262
|
-
|
|
50263
|
-
|
|
50365
|
+
let managed = operation;
|
|
50366
|
+
try {
|
|
50367
|
+
await new deployment_merge_effects_1.DeploymentMergeEffects(this.dependencies.pullRequests).configure(operation, pullRequest, inspection, (current) => this.inspectMergeBehavior(context, operation, current.baseBranch, targetRole, current.headSha, current.number), async (mode) => {
|
|
50368
|
+
managed = { ...operation, selectedPrMode: mode };
|
|
50369
|
+
await this.persist(context, managed);
|
|
50370
|
+
});
|
|
50371
|
+
}
|
|
50372
|
+
catch (cause) {
|
|
50373
|
+
const diagnostic = (0, application_error_1.toApplicationError)(cause, "workflow.failed", "Automatic merge setup failed with an unclassified provider rejection.", { retryable: true });
|
|
50374
|
+
const message = `GitHub could not configure automatic merge for PR #${pullRequest.number}. ${diagnostic.message} Check the PR and retry the stored ${category} phase.`;
|
|
50375
|
+
const error = new application_error_1.ApplicationError(diagnostic.code, message, { cause, retryable: diagnostic.retryable });
|
|
50376
|
+
return { kind: "blocked", result: await this.block(context, managed, category, message, error.retryable, error) };
|
|
50377
|
+
}
|
|
50264
50378
|
await this.publishDashboard(context, managed);
|
|
50265
50379
|
return { kind: "configured", operation: managed };
|
|
50266
50380
|
}
|
|
@@ -50314,27 +50428,6 @@ class DeploymentOrchestrationRuntime {
|
|
|
50314
50428
|
// Preserve the original provider failure returned by the coordinator.
|
|
50315
50429
|
}
|
|
50316
50430
|
}
|
|
50317
|
-
async applyMergeBehavior(context, operation, pullRequest, inspection) {
|
|
50318
|
-
if (inspection.decision.mode === "auto-merge") {
|
|
50319
|
-
await this.applyAutoMerge(context, operation, pullRequest, inspection.capabilities);
|
|
50320
|
-
return;
|
|
50321
|
-
}
|
|
50322
|
-
if (inspection.decision.mode === "merge-queue") {
|
|
50323
|
-
const queued = await this.dependencies.pullRequests.isPullRequestQueued(pullRequest.nodeId);
|
|
50324
|
-
if (!queued) {
|
|
50325
|
-
await this.dependencies.pullRequests.enqueuePullRequest(pullRequest.nodeId, pullRequest.headSha);
|
|
50326
|
-
}
|
|
50327
|
-
}
|
|
50328
|
-
}
|
|
50329
|
-
async applyAutoMerge(context, operation, pullRequest, capabilities) {
|
|
50330
|
-
if (operation.prMode === "auto" && capabilities.immediatelyMergeable) {
|
|
50331
|
-
await this.dependencies.pullRequests.mergePullRequest(pullRequest.number, pullRequest.headSha);
|
|
50332
|
-
return;
|
|
50333
|
-
}
|
|
50334
|
-
if (!pullRequest.autoMergeEnabled) {
|
|
50335
|
-
await this.dependencies.pullRequests.enableAutoMerge(pullRequest.nodeId);
|
|
50336
|
-
}
|
|
50337
|
-
}
|
|
50338
50431
|
async unsupportedMergeBehavior(context, operation, targetRole, targetBranch, capabilities, decision) {
|
|
50339
50432
|
const catalog = await this.presentationCatalog('issue', context, operation);
|
|
50340
50433
|
if (capabilities.mergeQueueObservationProblems.length === 0) {
|
|
@@ -51190,22 +51283,19 @@ const application_error_1 = __nccwpck_require__(75999);
|
|
|
51190
51283
|
const deployment_plan_policy_1 = __nccwpck_require__(8352);
|
|
51191
51284
|
const deployment_operation_1 = __nccwpck_require__(92730);
|
|
51192
51285
|
const deployment_orchestration_runtime_1 = __nccwpck_require__(77658);
|
|
51286
|
+
const deployment_continuation_guard_1 = __nccwpck_require__(1779);
|
|
51193
51287
|
class ConfirmPublicationHandler {
|
|
51194
51288
|
constructor(runtime, reconciliation) {
|
|
51195
51289
|
this.runtime = runtime;
|
|
51196
51290
|
this.reconciliation = reconciliation;
|
|
51197
51291
|
}
|
|
51198
51292
|
async invoke(context) {
|
|
51199
|
-
const
|
|
51200
|
-
|
|
51201
|
-
|
|
51202
|
-
|
|
51203
|
-
|
|
51204
|
-
|
|
51205
|
-
await this.runtime.publishDashboard(context, operation);
|
|
51206
|
-
return (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Publication for ${operation.tag} was already verified; duplicate notification ignored.`);
|
|
51207
|
-
}
|
|
51208
|
-
assertPublicationPhase(operation);
|
|
51293
|
+
const current = (0, deployment_orchestration_runtime_1.requireDeploymentOperation)(context);
|
|
51294
|
+
const invalid = (0, deployment_continuation_guard_1.validateDeploymentContinuation)(current, context.singleAction.operationId, ["published", "publishing", "promoted", "reconciliation_pending", "completed"], context.singleAction.version);
|
|
51295
|
+
if (invalid)
|
|
51296
|
+
throw new application_error_1.ApplicationError("workflow.stale", invalid);
|
|
51297
|
+
// Verify external receipts before clearing a block or retrying any merge/cleanup effect.
|
|
51298
|
+
const operation = current;
|
|
51209
51299
|
const productionSha = requireProductionSha(operation);
|
|
51210
51300
|
const publication = await this.runtime.dependencies.publication.inspect({
|
|
51211
51301
|
tag: operation.tag,
|
|
@@ -51222,8 +51312,18 @@ class ConfirmPublicationHandler {
|
|
|
51222
51312
|
if (!reachable) {
|
|
51223
51313
|
return await this.runtime.block(context, operation, "publication", "Published SHA is not reachable from the stored production branch.", false);
|
|
51224
51314
|
}
|
|
51315
|
+
const resumed = await this.resumeRetryableBlock(context, operation);
|
|
51316
|
+
if (resumed.phase === "reconciliation_pending" && resumed.publicationVerified) {
|
|
51317
|
+
return await this.reconciliation.plan(context, resumed)
|
|
51318
|
+
?? (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Publication for ${resumed.tag} was already verified; reconciliation state was recovered.`);
|
|
51319
|
+
}
|
|
51320
|
+
if (resumed.phase === "completed" && resumed.publicationVerified) {
|
|
51321
|
+
await this.runtime.publishDashboard(context, resumed);
|
|
51322
|
+
return (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Publication for ${resumed.tag} was already verified; duplicate notification ignored.`);
|
|
51323
|
+
}
|
|
51324
|
+
assertPublicationPhase(resumed);
|
|
51225
51325
|
const published = {
|
|
51226
|
-
...
|
|
51326
|
+
...resumed,
|
|
51227
51327
|
phase: "published",
|
|
51228
51328
|
publicationVerified: true,
|
|
51229
51329
|
publicationReceipt: publication.receipt,
|
|
@@ -51542,6 +51642,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
|
51542
51642
|
exports.ReconciliationHandler = void 0;
|
|
51543
51643
|
const deployment_plan_policy_1 = __nccwpck_require__(8352);
|
|
51544
51644
|
const deployment_operation_1 = __nccwpck_require__(92730);
|
|
51645
|
+
const managed_pull_request_1 = __nccwpck_require__(95914);
|
|
51545
51646
|
const deployment_orchestration_runtime_1 = __nccwpck_require__(77658);
|
|
51546
51647
|
class ReconciliationHandler {
|
|
51547
51648
|
constructor(runtime) {
|
|
@@ -51578,10 +51679,12 @@ class ReconciliationHandler {
|
|
|
51578
51679
|
return await this.complete(context, updated, ` after reconciliation PR #${pullRequest.number}`);
|
|
51579
51680
|
}
|
|
51580
51681
|
async plan(context, operation) {
|
|
51581
|
-
const index = operation.reconciliationTargets.findIndex((target) => target.status === "pending"
|
|
51682
|
+
const index = operation.reconciliationTargets.findIndex((target) => target.status === "pending");
|
|
51582
51683
|
if (index < 0)
|
|
51583
51684
|
return await this.finishOrPresent(context, operation);
|
|
51584
51685
|
let target = operation.reconciliationTargets[index];
|
|
51686
|
+
if (target.pullRequest !== undefined)
|
|
51687
|
+
return await this.resumePullRequest(context, operation, target);
|
|
51585
51688
|
const targetRole = (0, deployment_orchestration_runtime_1.reconciliationTargetRole)(operation, target.targetBranch);
|
|
51586
51689
|
const preflight = await this.runtime.inspectMergeBehavior(context, operation, target.targetBranch, targetRole, target.sourceSha);
|
|
51587
51690
|
if (preflight.kind === "blocked") {
|
|
@@ -51638,6 +51741,26 @@ class ReconciliationHandler {
|
|
|
51638
51741
|
await this.runtime.publishMilestone(context, completed, { kind: "orchestration-complete", tag: completed.tag });
|
|
51639
51742
|
return (0, deployment_orchestration_runtime_1.deploymentSuccess)(`Deployment ${completed.tag} completed${completionContext}.`);
|
|
51640
51743
|
}
|
|
51744
|
+
async resumePullRequest(context, operation, target) {
|
|
51745
|
+
const pullRequest = await this.runtime.dependencies.pullRequests.getPullRequest(target.pullRequest);
|
|
51746
|
+
const identity = (0, managed_pull_request_1.parseManagedPullRequestMarker)(pullRequest.body);
|
|
51747
|
+
const expectedHead = target.syncBranch ? target.syncSha : target.sourceSha;
|
|
51748
|
+
if (!identity || identity.operationId !== operation.operationId || identity.phase !== "reconciliation"
|
|
51749
|
+
|| identity.issue !== context.singleAction.issue || pullRequest.number !== target.pullRequest
|
|
51750
|
+
|| pullRequest.repositoryFullName.toLowerCase() !== `${context.owner}/${context.repo}`.toLowerCase()
|
|
51751
|
+
|| pullRequest.baseBranch !== target.targetBranch
|
|
51752
|
+
|| pullRequest.headBranch !== (target.syncBranch ?? target.sourceBranch)
|
|
51753
|
+
|| !expectedHead || pullRequest.headSha !== expectedHead) {
|
|
51754
|
+
return await this.runtime.block(context, operation, "reconciliation", "The recorded reconciliation PR no longer matches its durable identity and head SHA.", false);
|
|
51755
|
+
}
|
|
51756
|
+
if (pullRequest.merged)
|
|
51757
|
+
return await this.accept(context, operation, pullRequest);
|
|
51758
|
+
if (pullRequest.state === "closed") {
|
|
51759
|
+
return await this.runtime.block(context, operation, "reconciliation", `Reconciliation PR #${pullRequest.number} was closed without merge.`, true);
|
|
51760
|
+
}
|
|
51761
|
+
const configured = await this.runtime.configureMergeBehavior(context, operation, pullRequest, "reconciliation", (0, deployment_orchestration_runtime_1.reconciliationTargetRole)(operation, target.targetBranch));
|
|
51762
|
+
return configured.kind === "blocked" ? configured.result : undefined;
|
|
51763
|
+
}
|
|
51641
51764
|
async finishOrPresent(context, operation) {
|
|
51642
51765
|
if (operation.reconciliationTargets.length > 0
|
|
51643
51766
|
&& operation.reconciliationTargets.every((target) => target.status === "completed")) {
|
|
@@ -71570,6 +71693,47 @@ function isNotFound(error) {
|
|
|
71570
71693
|
}
|
|
71571
71694
|
|
|
71572
71695
|
|
|
71696
|
+
/***/ }),
|
|
71697
|
+
|
|
71698
|
+
/***/ 30873:
|
|
71699
|
+
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
|
|
71700
|
+
|
|
71701
|
+
"use strict";
|
|
71702
|
+
|
|
71703
|
+
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
71704
|
+
exports.githubDeploymentMergeError = githubDeploymentMergeError;
|
|
71705
|
+
const deployment_merge_effect_error_1 = __nccwpck_require__(72594);
|
|
71706
|
+
/** Never copy provider messages, request objects, headers, or arbitrary error types into public state. */
|
|
71707
|
+
function githubDeploymentMergeError(action, cause) {
|
|
71708
|
+
const value = isRecord(cause) ? cause : {};
|
|
71709
|
+
const status = typeof value.status === "number" && Number.isInteger(value.status)
|
|
71710
|
+
&& value.status >= 100 && value.status <= 599 ? value.status : undefined;
|
|
71711
|
+
const rawErrors = Array.isArray(value.errors) ? value.errors : [];
|
|
71712
|
+
const errors = rawErrors.filter(isRecord);
|
|
71713
|
+
const types = errors.map((error) => error.type);
|
|
71714
|
+
const denied = status === 401 || status === 403 || types.includes("FORBIDDEN") || types.includes("UNAUTHORIZED");
|
|
71715
|
+
const limited = status === 429 || types.includes("RATE_LIMITED");
|
|
71716
|
+
const unavailable = (status !== undefined && status >= 500) || types.includes("INTERNAL") || types.includes("SERVICE_UNAVAILABLE");
|
|
71717
|
+
const cleanRejection = rawErrors.length === 1 && errors.length === 1 && errors[0].type === "UNPROCESSABLE"
|
|
71718
|
+
&& typeof errors[0].message === "string"
|
|
71719
|
+
&& ["Pull request is in clean status", "Pull request Pull request is in clean status",
|
|
71720
|
+
"Pull request is in unstable status", "Pull request Pull request is in unstable status"].includes(errors[0].message);
|
|
71721
|
+
const readinessChanged = !denied && !limited && !unavailable
|
|
71722
|
+
&& ((action === "merge" && status === 405) || (action === "enable-auto-merge" && (status === undefined || status === 200) && cleanRejection));
|
|
71723
|
+
const code = denied ? "authorization.denied"
|
|
71724
|
+
: limited ? "provider.rate-limited"
|
|
71725
|
+
: unavailable ? "provider.unavailable"
|
|
71726
|
+
: status === 404 || types.includes("NOT_FOUND") ? "provider.not-found"
|
|
71727
|
+
: status !== undefined || types.length > 0 ? "provider.conflict" : "workflow.failed";
|
|
71728
|
+
const reason = readinessChanged ? "readiness-changed" : code;
|
|
71729
|
+
const http = status === undefined ? "" : `; HTTP ${status}`;
|
|
71730
|
+
return new deployment_merge_effect_error_1.DeploymentMergeEffectError(action, readinessChanged, code, `GitHub rejected ${action} (${reason}${http}).`, cause);
|
|
71731
|
+
}
|
|
71732
|
+
function isRecord(value) {
|
|
71733
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
71734
|
+
}
|
|
71735
|
+
|
|
71736
|
+
|
|
71573
71737
|
/***/ }),
|
|
71574
71738
|
|
|
71575
71739
|
/***/ 96483:
|
|
@@ -71580,6 +71744,8 @@ function isNotFound(error) {
|
|
|
71580
71744
|
Object.defineProperty(exports, "__esModule", ({ value: true }));
|
|
71581
71745
|
exports.GithubManagedPullRequestRepository = void 0;
|
|
71582
71746
|
const managed_pull_request_1 = __nccwpck_require__(95914);
|
|
71747
|
+
const github_deployment_merge_error_1 = __nccwpck_require__(30873);
|
|
71748
|
+
const deployment_merge_effect_error_1 = __nccwpck_require__(72594);
|
|
71583
71749
|
class GithubManagedPullRequestRepository {
|
|
71584
71750
|
constructor(clientProvider) {
|
|
71585
71751
|
this.clientProvider = clientProvider;
|
|
@@ -71623,12 +71789,21 @@ class GithubManagedPullRequestRepository {
|
|
|
71623
71789
|
});
|
|
71624
71790
|
return mapPullRequest(data, owner, repository);
|
|
71625
71791
|
}
|
|
71626
|
-
async enableAutoMerge(
|
|
71627
|
-
|
|
71628
|
-
|
|
71629
|
-
|
|
71792
|
+
async enableAutoMerge(_owner, _repository, pullRequestNodeId, expectedHeadSha, token) {
|
|
71793
|
+
let response;
|
|
71794
|
+
try {
|
|
71795
|
+
response = await this.clientProvider.getClient(token).graphql(`mutation EnableDeploymentAutoMerge($pullRequestId: ID!, $expectedHeadOid: GitObjectID!) {
|
|
71796
|
+
enablePullRequestAutoMerge(input: {pullRequestId: $pullRequestId, expectedHeadOid: $expectedHeadOid, mergeMethod: MERGE}) {
|
|
71797
|
+
pullRequest { id }
|
|
71798
|
+
}
|
|
71799
|
+
}`, { pullRequestId: pullRequestNodeId, expectedHeadOid: expectedHeadSha });
|
|
71800
|
+
}
|
|
71801
|
+
catch (cause) {
|
|
71802
|
+
throw (0, github_deployment_merge_error_1.githubDeploymentMergeError)("enable-auto-merge", cause);
|
|
71803
|
+
}
|
|
71804
|
+
if (response?.enablePullRequestAutoMerge?.pullRequest?.id !== pullRequestNodeId) {
|
|
71805
|
+
throw new deployment_merge_effect_error_1.DeploymentMergeEffectError("enable-auto-merge", false, "provider.contract-invalid", "GitHub did not confirm native auto-merge for the expected PR.");
|
|
71630
71806
|
}
|
|
71631
|
-
}`, { pullRequestId: pullRequestNodeId, owner, repository });
|
|
71632
71807
|
}
|
|
71633
71808
|
async isPullRequestQueued(owner, repository, pullRequestNodeId, token) {
|
|
71634
71809
|
const response = await this.clientProvider.getClient(token).graphql(`query DeploymentPullRequestQueue($pullRequestId: ID!) {
|
|
@@ -71652,15 +71827,18 @@ class GithubManagedPullRequestRepository {
|
|
|
71652
71827
|
}
|
|
71653
71828
|
}
|
|
71654
71829
|
async mergePullRequest(owner, repository, pullRequest, expectedHeadSha, token) {
|
|
71655
|
-
|
|
71656
|
-
|
|
71657
|
-
|
|
71658
|
-
|
|
71659
|
-
|
|
71660
|
-
|
|
71661
|
-
|
|
71662
|
-
|
|
71663
|
-
|
|
71830
|
+
let data;
|
|
71831
|
+
try {
|
|
71832
|
+
({ data } = await this.clientProvider.getClient(token).rest.pulls.merge({
|
|
71833
|
+
owner, repo: repository, pull_number: pullRequest, merge_method: "merge", sha: expectedHeadSha,
|
|
71834
|
+
}));
|
|
71835
|
+
}
|
|
71836
|
+
catch (cause) {
|
|
71837
|
+
throw (0, github_deployment_merge_error_1.githubDeploymentMergeError)("merge", cause);
|
|
71838
|
+
}
|
|
71839
|
+
if (!data?.merged || typeof data.sha !== "string" || !/^[a-f0-9]{40}$/i.test(data.sha)) {
|
|
71840
|
+
throw new deployment_merge_effect_error_1.DeploymentMergeEffectError("merge", false, "provider.contract-invalid", "GitHub did not confirm a completed merge with a valid commit SHA.");
|
|
71841
|
+
}
|
|
71664
71842
|
return data.sha;
|
|
71665
71843
|
}
|
|
71666
71844
|
}
|
|
@@ -84870,7 +85048,7 @@ function bindManagedPullRequests(port, binding) {
|
|
|
84870
85048
|
findManagedPullRequests: (query) => port.findManagedPullRequests({ ...query, owner: binding.owner, repository: binding.repository, token: binding.token }),
|
|
84871
85049
|
createManagedPullRequest: (command) => port.createManagedPullRequest({ ...command, owner: binding.owner, repository: binding.repository, token: binding.token }),
|
|
84872
85050
|
getPullRequest: (pullRequest) => port.getPullRequest(binding.owner, binding.repository, pullRequest, binding.token),
|
|
84873
|
-
enableAutoMerge: (pullRequestNodeId) => port.enableAutoMerge(binding.owner, binding.repository, pullRequestNodeId, binding.token),
|
|
85051
|
+
enableAutoMerge: (pullRequestNodeId, expectedHeadSha) => port.enableAutoMerge(binding.owner, binding.repository, pullRequestNodeId, expectedHeadSha, binding.token),
|
|
84874
85052
|
isPullRequestQueued: (pullRequestNodeId) => port.isPullRequestQueued(binding.owner, binding.repository, pullRequestNodeId, binding.token),
|
|
84875
85053
|
enqueuePullRequest: (pullRequestNodeId, expectedHeadSha) => port.enqueuePullRequest(binding.owner, binding.repository, pullRequestNodeId, expectedHeadSha, binding.token),
|
|
84876
85054
|
mergePullRequest: (pullRequest, expectedHeadSha) => port.mergePullRequest(binding.owner, binding.repository, pullRequest, expectedHeadSha, binding.token),
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@ on:
|
|
|
8
8
|
required: true
|
|
9
9
|
default: prepare
|
|
10
10
|
type: choice
|
|
11
|
-
options: [prepare, publish]
|
|
11
|
+
options: [prepare, publish, resume]
|
|
12
12
|
operation-id:
|
|
13
13
|
description: 'Internal durable operation identifier'
|
|
14
14
|
required: false
|
|
@@ -66,10 +66,10 @@ jobs:
|
|
|
66
66
|
if (operationId) errors.push('Operation ID must be empty in prepare mode.');
|
|
67
67
|
if (!title || title.length > 1000) errors.push('Title must contain 1-1000 characters.');
|
|
68
68
|
if (!changelog || changelog.length > 50000) errors.push('Changelog must contain 1-50000 characters.');
|
|
69
|
-
} else if (mode === 'publish') {
|
|
69
|
+
} else if (mode === 'publish' || mode === 'resume') {
|
|
70
70
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{7,127}$/.test(operationId)) errors.push('Operation ID is invalid.');
|
|
71
|
-
if (title || changelog) errors.push('Title and changelog must be empty in publish mode.');
|
|
72
|
-
} else errors.push('Mode must be prepare or
|
|
71
|
+
if (title || changelog) errors.push('Title and changelog must be empty in publish or resume mode.');
|
|
72
|
+
} else errors.push('Mode must be prepare, publish, or resume.');
|
|
73
73
|
if (errors.length) core.setFailed(errors.join(' '));
|
|
74
74
|
|
|
75
75
|
prepare-version-files:
|
|
@@ -185,17 +185,66 @@ jobs:
|
|
|
185
185
|
single-action-version: ${{ inputs.version }}
|
|
186
186
|
token: ${{ secrets.PAT }}
|
|
187
187
|
|
|
188
|
+
resume-reconciliation:
|
|
189
|
+
name: Resume published deployment
|
|
190
|
+
if: ${{ inputs.mode == 'resume' }}
|
|
191
|
+
runs-on: ubuntu-latest
|
|
192
|
+
needs: validate
|
|
193
|
+
timeout-minutes: 15
|
|
194
|
+
permissions:
|
|
195
|
+
issues: write
|
|
196
|
+
pull-requests: write
|
|
197
|
+
steps:
|
|
198
|
+
- name: Verify published operation before recovery
|
|
199
|
+
uses: actions/github-script@v9
|
|
200
|
+
env:
|
|
201
|
+
ISSUE: ${{ inputs.issue }}
|
|
202
|
+
OPERATION_ID: ${{ inputs.operation-id }}
|
|
203
|
+
VERSION: ${{ inputs.version }}
|
|
204
|
+
with:
|
|
205
|
+
script: |
|
|
206
|
+
const response = await github.rest.issues.get({ ...context.repo, issue_number: Number(process.env.ISSUE) });
|
|
207
|
+
if (response.data.pull_request) throw new Error('The launcher must be an issue.');
|
|
208
|
+
const body = response.data.body || '';
|
|
209
|
+
const start = '<!-- copilot-configuration-start';
|
|
210
|
+
const end = 'copilot-configuration-end -->';
|
|
211
|
+
const first = body.indexOf(start);
|
|
212
|
+
const last = body.indexOf(end, first + start.length);
|
|
213
|
+
if (first < 0 || last < 0 || body.indexOf(start, first + start.length) >= 0) throw new Error('A unique durable configuration is required.');
|
|
214
|
+
const payload = JSON.parse(body.slice(first + start.length, last));
|
|
215
|
+
const state = payload?.deploymentOrchestration;
|
|
216
|
+
const receipt = state?.publicationReceipt;
|
|
217
|
+
const phase = state?.phase === 'blocked' && state?.lastFailure?.retryable === true
|
|
218
|
+
? state.lastFailure.previousPhase : state?.phase;
|
|
219
|
+
if (payload?.schemaVersion !== 3 || state?.stateVersion !== 1
|
|
220
|
+
|| !Number.isSafeInteger(state?.revision) || state.revision < 1
|
|
221
|
+
|| state.operationId !== process.env.OPERATION_ID || state.version !== process.env.VERSION
|
|
222
|
+
|| !['reconciliation_pending', 'completed'].includes(phase) || state.publicationVerified !== true
|
|
223
|
+
|| !/^[a-f0-9]{40}$/i.test(state.productionSha || '') || state.tag !== `v${process.env.VERSION}`
|
|
224
|
+
|| receipt?.operationId !== state.operationId || receipt?.productionSha !== state.productionSha
|
|
225
|
+
|| receipt?.tag !== state.tag) throw new Error('Recovery requires the matching, already verified publication and reconciliation state.');
|
|
226
|
+
- name: Resume reconciliation from verified receipts
|
|
227
|
+
uses: vypdev/copilot@v3
|
|
228
|
+
with:
|
|
229
|
+
single-action: published_deployment_action
|
|
230
|
+
single-action-issue: ${{ inputs.issue }}
|
|
231
|
+
issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }}
|
|
232
|
+
single-action-operation-id: ${{ inputs.operation-id }}
|
|
233
|
+
single-action-version: ${{ inputs.version }}
|
|
234
|
+
merge-queue-check-attestations: ${{ vars.MERGE_QUEUE_CHECK_ATTESTATIONS || '[]' }}
|
|
235
|
+
token: ${{ secrets.PAT }}
|
|
236
|
+
|
|
188
237
|
report-failure:
|
|
189
238
|
name: Report orchestration failure
|
|
190
239
|
runs-on: ubuntu-latest
|
|
191
240
|
timeout-minutes: 5
|
|
192
|
-
needs: [validate, prepare-version-files, promote, publish]
|
|
241
|
+
needs: [validate, prepare-version-files, promote, publish, resume-reconciliation]
|
|
193
242
|
if: ${{ failure() && needs.validate.result == 'success' }}
|
|
194
243
|
permissions:
|
|
195
244
|
issues: write
|
|
196
245
|
steps:
|
|
197
246
|
- name: Persist publication failure
|
|
198
|
-
if: ${{ inputs.mode == 'publish' }}
|
|
247
|
+
if: ${{ inputs.mode == 'publish' || inputs.mode == 'resume' }}
|
|
199
248
|
uses: vypdev/copilot@v3
|
|
200
249
|
with:
|
|
201
250
|
single-action: failed_deployment_action
|
|
@@ -8,7 +8,7 @@ on:
|
|
|
8
8
|
required: true
|
|
9
9
|
default: prepare
|
|
10
10
|
type: choice
|
|
11
|
-
options: [prepare, publish]
|
|
11
|
+
options: [prepare, publish, resume]
|
|
12
12
|
operation-id:
|
|
13
13
|
description: 'Internal durable operation identifier'
|
|
14
14
|
required: false
|
|
@@ -66,10 +66,10 @@ jobs:
|
|
|
66
66
|
if (operationId) errors.push('Operation ID must be empty in prepare mode.');
|
|
67
67
|
if (!title || title.length > 1000) errors.push('Title must contain 1-1000 characters.');
|
|
68
68
|
if (!changelog || changelog.length > 50000) errors.push('Changelog must contain 1-50000 characters.');
|
|
69
|
-
} else if (mode === 'publish') {
|
|
69
|
+
} else if (mode === 'publish' || mode === 'resume') {
|
|
70
70
|
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{7,127}$/.test(operationId)) errors.push('Operation ID is invalid.');
|
|
71
|
-
if (title || changelog) errors.push('Title and changelog must be empty in publish mode.');
|
|
72
|
-
} else errors.push('Mode must be prepare or
|
|
71
|
+
if (title || changelog) errors.push('Title and changelog must be empty in publish or resume mode.');
|
|
72
|
+
} else errors.push('Mode must be prepare, publish, or resume.');
|
|
73
73
|
if (errors.length) core.setFailed(errors.join(' '));
|
|
74
74
|
|
|
75
75
|
prepare-version-files:
|
|
@@ -185,17 +185,66 @@ jobs:
|
|
|
185
185
|
single-action-version: ${{ inputs.version }}
|
|
186
186
|
token: ${{ secrets.PAT }}
|
|
187
187
|
|
|
188
|
+
resume-reconciliation:
|
|
189
|
+
name: Resume published deployment
|
|
190
|
+
if: ${{ inputs.mode == 'resume' }}
|
|
191
|
+
runs-on: ubuntu-latest
|
|
192
|
+
needs: validate
|
|
193
|
+
timeout-minutes: 15
|
|
194
|
+
permissions:
|
|
195
|
+
issues: write
|
|
196
|
+
pull-requests: write
|
|
197
|
+
steps:
|
|
198
|
+
- name: Verify published operation before recovery
|
|
199
|
+
uses: actions/github-script@v9
|
|
200
|
+
env:
|
|
201
|
+
ISSUE: ${{ inputs.issue }}
|
|
202
|
+
OPERATION_ID: ${{ inputs.operation-id }}
|
|
203
|
+
VERSION: ${{ inputs.version }}
|
|
204
|
+
with:
|
|
205
|
+
script: |
|
|
206
|
+
const response = await github.rest.issues.get({ ...context.repo, issue_number: Number(process.env.ISSUE) });
|
|
207
|
+
if (response.data.pull_request) throw new Error('The launcher must be an issue.');
|
|
208
|
+
const body = response.data.body || '';
|
|
209
|
+
const start = '<!-- copilot-configuration-start';
|
|
210
|
+
const end = 'copilot-configuration-end -->';
|
|
211
|
+
const first = body.indexOf(start);
|
|
212
|
+
const last = body.indexOf(end, first + start.length);
|
|
213
|
+
if (first < 0 || last < 0 || body.indexOf(start, first + start.length) >= 0) throw new Error('A unique durable configuration is required.');
|
|
214
|
+
const payload = JSON.parse(body.slice(first + start.length, last));
|
|
215
|
+
const state = payload?.deploymentOrchestration;
|
|
216
|
+
const receipt = state?.publicationReceipt;
|
|
217
|
+
const phase = state?.phase === 'blocked' && state?.lastFailure?.retryable === true
|
|
218
|
+
? state.lastFailure.previousPhase : state?.phase;
|
|
219
|
+
if (payload?.schemaVersion !== 3 || state?.stateVersion !== 1
|
|
220
|
+
|| !Number.isSafeInteger(state?.revision) || state.revision < 1
|
|
221
|
+
|| state.operationId !== process.env.OPERATION_ID || state.version !== process.env.VERSION
|
|
222
|
+
|| !['reconciliation_pending', 'completed'].includes(phase) || state.publicationVerified !== true
|
|
223
|
+
|| !/^[a-f0-9]{40}$/i.test(state.productionSha || '') || state.tag !== `v${process.env.VERSION}`
|
|
224
|
+
|| receipt?.operationId !== state.operationId || receipt?.productionSha !== state.productionSha
|
|
225
|
+
|| receipt?.tag !== state.tag) throw new Error('Recovery requires the matching, already verified publication and reconciliation state.');
|
|
226
|
+
- name: Resume reconciliation from verified receipts
|
|
227
|
+
uses: vypdev/copilot@v3
|
|
228
|
+
with:
|
|
229
|
+
single-action: published_deployment_action
|
|
230
|
+
single-action-issue: ${{ inputs.issue }}
|
|
231
|
+
issue-workflow-profile: ${{ vars.COPILOT_ISSUE_WORKFLOW_PROFILE || '' }}
|
|
232
|
+
single-action-operation-id: ${{ inputs.operation-id }}
|
|
233
|
+
single-action-version: ${{ inputs.version }}
|
|
234
|
+
merge-queue-check-attestations: ${{ vars.MERGE_QUEUE_CHECK_ATTESTATIONS || '[]' }}
|
|
235
|
+
token: ${{ secrets.PAT }}
|
|
236
|
+
|
|
188
237
|
report-failure:
|
|
189
238
|
name: Report orchestration failure
|
|
190
239
|
runs-on: ubuntu-latest
|
|
191
240
|
timeout-minutes: 5
|
|
192
|
-
needs: [validate, prepare-version-files, promote, publish]
|
|
241
|
+
needs: [validate, prepare-version-files, promote, publish, resume-reconciliation]
|
|
193
242
|
if: ${{ failure() && needs.validate.result == 'success' }}
|
|
194
243
|
permissions:
|
|
195
244
|
issues: write
|
|
196
245
|
steps:
|
|
197
246
|
- name: Persist publication failure
|
|
198
|
-
if: ${{ inputs.mode == 'publish' }}
|
|
247
|
+
if: ${{ inputs.mode == 'publish' || inputs.mode == 'resume' }}
|
|
199
248
|
uses: vypdev/copilot@v3
|
|
200
249
|
with:
|
|
201
250
|
single-action: failed_deployment_action
|