feat(ql3): fence cluster deployment transitions

This commit is contained in:
whyour
2026-08-17 01:41:10 +08:00
parent abf2d25d63
commit 2e848ef7c0
18 changed files with 1337 additions and 129 deletions
@@ -8,6 +8,9 @@ import {
type LocalComposeReleaseSelectionInput,
type ResolvedLocalComposeReleaseSelection,
} from '../compose/releaseSelection';
import { LocalDeploymentConfigurationError } from './error';
export { LocalDeploymentConfigurationError } from './error';
const MAX_PATH_BYTES = 4_096;
const SAFE_PATH_PATTERN = /^\/[A-Za-z0-9._/@-]+$/;
@@ -364,15 +367,6 @@ export interface LocalDeploymentComposeEvidenceCollectionResult {
}>;
}
export class LocalDeploymentConfigurationError extends TypeError {
readonly code = 'QL3_LOCAL_DEPLOYMENT_CONFIGURATION_INVALID';
constructor(message: string, options?: ErrorOptions) {
super(`Local deployment configuration is invalid: ${message}`, options);
this.name = 'LocalDeploymentConfigurationError';
}
}
function object(value: unknown, label: string): Record<string, unknown> {
if (
!value ||
@@ -0,0 +1,8 @@
export class LocalDeploymentConfigurationError extends TypeError {
readonly code = 'QL3_LOCAL_DEPLOYMENT_CONFIGURATION_INVALID';
constructor(message: string, options?: ErrorOptions) {
super(`Local deployment configuration is invalid: ${message}`, options);
this.name = 'LocalDeploymentConfigurationError';
}
}
@@ -5,7 +5,7 @@ import { spawnSync } from 'node:child_process';
import { readPrivateLocalCommandFile } from '@qinglong/local-command-file';
import { LocalDeploymentConfigurationError } from '../foundation/contract';
import { LocalDeploymentConfigurationError } from '../foundation/error';
import {
normalizeLocalServiceBridgeCommand,
normalizeLocalServiceManagerIntent,
@@ -1,7 +1,7 @@
import crypto from 'node:crypto';
import path from 'node:path';
import { LocalDeploymentConfigurationError } from '../foundation/contract';
import { LocalDeploymentConfigurationError } from '../foundation/error';
const MAX_PATH_BYTES = 4_096;
const SAFE_PATH_PATTERN = /^\/[A-Za-z0-9._/@-]+$/;
@@ -1,7 +1,7 @@
import fs from 'node:fs';
import path from 'node:path';
import { LocalDeploymentConfigurationError } from '../foundation/contract';
import { LocalDeploymentConfigurationError } from '../foundation/error';
const MAX_FILE_BYTES = 1024 * 1024;
@@ -8,10 +8,8 @@ import {
readPrivateLocalJsonFile,
} from '@qinglong/local-command-file';
import {
currentIdentity,
LocalDeploymentConfigurationError,
} from '../foundation/contract';
import { currentIdentity } from '../foundation/contract';
import { LocalDeploymentConfigurationError } from '../foundation/error';
import {
advanceLocalCutoverInstanceHead,
readLocalCutoverInstanceHead,
@@ -3,7 +3,7 @@ import path from 'node:path';
import { readPrivateLocalCommandFile } from '@qinglong/local-command-file';
import { LocalDeploymentConfigurationError } from '../foundation/contract';
import { LocalDeploymentConfigurationError } from '../foundation/error';
import { preflightPublishedFile, publishExactFile } from '../foundation/files';
import { cutoverDigest } from '../cutover/targetEvidence';
import type {
@@ -7,10 +7,8 @@ import {
readPrivateLocalJsonFile,
} from '@qinglong/local-command-file';
import {
currentIdentity,
LocalDeploymentConfigurationError,
} from '../foundation/contract';
import { currentIdentity } from '../foundation/contract';
import { LocalDeploymentConfigurationError } from '../foundation/error';
import {
assertLocalCutoverTargetHead,
localCutoverInstanceHeadPath,
@@ -1,6 +1,6 @@
import crypto from 'node:crypto';
import { LocalDeploymentConfigurationError } from '../foundation/contract';
import { LocalDeploymentConfigurationError } from '../foundation/error';
import type {
LocalServiceManagerAction,
LocalServiceManagerKind,