@@ -34598,9 +34598,64 @@ async function sendDeploymentEvent(apiUrl, apiKey, payload, failOnRejection = fa
3459834598 const data = axiosError.response?.data;
3459934599 // Handle rejection status codes (409, 423, 428)
3460034600 if (status === 409 || status === 423 || status === 428) {
34601- const errorData = data;
34602- const message = errorData?.message || errorData?.error || 'Deployment rejected by Versioner';
34603- const rejectionError = `Deployment rejected: ${message}`;
34601+ const errorResponse = data;
34602+ const detail = errorResponse?.detail;
34603+ const errorCode = detail?.code || 'UNKNOWN';
34604+ const message = detail?.message || 'Deployment rejected by Versioner';
34605+ const ruleName = detail?.details?.rule_name || 'Unknown Rule';
34606+ let rejectionError = '';
34607+ // Format error based on status code
34608+ if (status === 409) {
34609+ // DEPLOYMENT_IN_PROGRESS
34610+ rejectionError = `⚠️ Deployment Conflict\n\n`;
34611+ rejectionError += `${message}\n`;
34612+ rejectionError += `Another deployment is in progress. Please wait and retry.`;
34613+ }
34614+ else if (status === 423) {
34615+ // NO_DEPLOY_WINDOW
34616+ rejectionError = `🔒 Deployment Blocked by Schedule\n\n`;
34617+ rejectionError += `Rule: ${ruleName}\n`;
34618+ rejectionError += `${message}\n`;
34619+ if (detail?.retry_after) {
34620+ rejectionError += `\nRetry after: ${detail.retry_after}`;
34621+ }
34622+ rejectionError += `\n\nTo skip checks (emergency only), add to your workflow:\n`;
34623+ rejectionError += ` skip-preflight-checks: true`;
34624+ }
34625+ else if (status === 428) {
34626+ // Precondition failures (FLOW_VIOLATION, INSUFFICIENT_SOAK_TIME, etc.)
34627+ rejectionError = `❌ Deployment Precondition Failed\n\n`;
34628+ rejectionError += `Error: ${errorCode}\n`;
34629+ rejectionError += `Rule: ${ruleName}\n`;
34630+ rejectionError += `${message}\n`;
34631+ if (detail?.retry_after) {
34632+ rejectionError += `\nRetry after: ${detail.retry_after}`;
34633+ }
34634+ // Add specific guidance based on error code
34635+ if (errorCode === 'FLOW_VIOLATION') {
34636+ rejectionError += `\n\nDeploy to required environments first, then retry.`;
34637+ }
34638+ else if (errorCode === 'INSUFFICIENT_SOAK_TIME') {
34639+ rejectionError += `\n\nWait for soak time to complete, then retry.`;
34640+ rejectionError += `\n\nTo skip checks (emergency only), add to your workflow:\n`;
34641+ rejectionError += ` skip-preflight-checks: true`;
34642+ }
34643+ else if (errorCode === 'QUALITY_APPROVAL_REQUIRED' ||
34644+ errorCode === 'APPROVAL_REQUIRED') {
34645+ rejectionError += `\n\nApproval required before deployment can proceed.`;
34646+ rejectionError += `\nObtain approval via Versioner UI, then retry.`;
34647+ }
34648+ else {
34649+ // Generic handler for unknown/future error codes
34650+ rejectionError += `\n\nResolve the issue described above, then retry.`;
34651+ rejectionError += `\n\nTo skip checks (emergency only), add to your workflow:\n`;
34652+ rejectionError += ` skip-preflight-checks: true`;
34653+ }
34654+ // Always include full details for debugging (all error codes)
34655+ if (detail?.details) {
34656+ rejectionError += `\n\nDetails: ${JSON.stringify(detail.details, null, 2)}`;
34657+ }
34658+ }
3460434659 if (failOnRejection) {
3460534660 throw new Error(rejectionError);
3460634661 }
@@ -35025,6 +35080,7 @@ async function run() {
3502535080 version: inputs.version,
3502635081 environment_name: inputs.environment,
3502735082 status: inputs.status,
35083+ skip_preflight_checks: inputs.skipPreflightChecks,
3502835084 scm_repository: githubMetadata.scm_repository,
3502935085 scm_sha: githubMetadata.scm_sha,
3503035086 source_system: githubMetadata.source_system,
@@ -35124,6 +35180,7 @@ function getInputs() {
3512435180 const status = core.getInput('status', { required: false }) || 'success';
3512535181 const metadataInput = core.getInput('metadata', { required: false }) || '{}';
3512635182 const failOnRejectionInput = core.getInput('fail_on_rejection', { required: false }) || 'true';
35183+ const skipPreflightChecksInput = core.getInput('skip_preflight_checks', { required: false }) || 'false';
3512735184 // Validate API key is provided
3512835185 if (!apiKey) {
3512935186 throw new Error(`api_key is required (provide via input or VERSIONER_API_KEY environment variable)`);
@@ -35159,6 +35216,8 @@ function getInputs() {
3515935216 }
3516035217 // Parse fail_on_rejection boolean
3516135218 const failOnRejection = failOnRejectionInput.toLowerCase() === 'true';
35219+ // Parse skip_preflight_checks boolean
35220+ const skipPreflightChecks = skipPreflightChecksInput.toLowerCase() === 'true';
3516235221 return {
3516335222 apiUrl,
3516435223 apiKey,
@@ -35169,6 +35228,7 @@ function getInputs() {
3516935228 status,
3517035229 metadata,
3517135230 failOnRejection,
35231+ skipPreflightChecks,
3517235232 };
3517335233}
3517435234
0 commit comments