Merge pull request #2738 from pikasTech/fix/2745-tasktree-schema-deadlock

fix(cicd): 吸收语义 code hash 漂移
This commit is contained in:
Lyon
2026-07-21 18:51:43 +08:00
committed by GitHub
2 changed files with 23 additions and 2 deletions
+7
View File
@@ -1178,6 +1178,12 @@ test("planner ignores package scripts-only changes even when package is a compon
await git(repo, ["add", "deploy/deploy.yaml", "package.json"]);
await git(repo, ["commit", "-m", "seed package scripts"]);
await refreshFixtureCatalogForHead(repo);
const catalogPath = path.join(repo, "deploy/artifact-catalog.v02.json");
const catalog = JSON.parse(await readFile(catalogPath, "utf8"));
for (const service of catalog.services) service.codeInputHash = "legacy-package-script-hash";
await writeFile(catalogPath, JSON.stringify(catalog, null, 2));
await git(repo, ["add", "deploy/artifact-catalog.v02.json"]);
await git(repo, ["commit", "-m", "seed legacy code input hashes"]);
await writeFile(path.join(repo, "package.json"), JSON.stringify({
type: "module",
@@ -1197,6 +1203,7 @@ test("planner ignores package scripts-only changes even when package is a compon
assert.deepEqual(plan.affectedServices, []);
assert.deepEqual(plan.buildServices, []);
assert.equal(plan.services.every((service) => !service.changedPaths.includes("package.json")), true);
assert.equal(plan.services.every((service) => service.codeMetadataHashDrift === true), true);
assert.equal(plan.imageBuildRequired, false);
assert.equal(plan.buildSkippedCount, 2);
});
+16 -2
View File
@@ -161,6 +161,7 @@ export async function createCiPlan(options = {}) {
...buildSystemMatches
].filter((item) => !isTestOnlyPath(item) && !isDocsOnlyPath(item)));
const catalogRecord = catalogByServiceId.get(model.serviceId) ?? null;
const catalogEnvironmentSourceCommitId = envReuse ? text(catalogRecord?.sourceCommitId) : "";
const environmentInputHash = envReuse ? await hashEnvReuseInputs(repoRoot, targetRef, envInputPaths, serviceEnvReuseRecipe, {
skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath),
semanticPackageJson: true
@@ -169,10 +170,15 @@ export async function createCiPlan(options = {}) {
skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath),
semanticPackageJson: true
}) : null;
const catalogCodeInputHashAtSource = envReuse && catalogEnvironmentSourceCommitId
? await hashGitPathsIfCommitExists(repoRoot, catalogEnvironmentSourceCommitId, codeInputPaths, {
skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath),
semanticPackageJson: true
})
: null;
const currentEnvironmentImage = envReuse ? envReuseImageRef(registryPrefix, model.serviceId, environmentInputHash, envArtifactGroup) : null;
const catalogEnvironmentImage = envReuse ? environmentImageFromCatalog(model.serviceId, catalogRecord) : null;
const catalogEnvironmentDigest = envReuse ? environmentDigestFromCatalog(catalogRecord) : null;
const catalogEnvironmentSourceCommitId = envReuse ? text(catalogRecord?.sourceCommitId) : "";
const catalogEnvironmentInputHashAtSource = envReuse && catalogEnvironmentSourceCommitId
? await hashEnvReuseInputsIfCommitExists(repoRoot, catalogEnvironmentSourceCommitId, envInputPaths, serviceEnvReuseRecipe, {
skipPath: (filePath) => isTestOnlyPath(filePath) || isDocsOnlyPath(filePath),
@@ -224,7 +230,12 @@ export async function createCiPlan(options = {}) {
const effectiveEnvironmentInputChanged = environmentInputChanged === true && !environmentMetadataHashDrift;
const environmentReady = envReuse && Boolean(environmentImage) && (reuseRegistryProbe ? reuseRegistry?.status === "present" && digestReady : !effectiveEnvironmentInputChanged && digestReady);
const envChanged = envReuse ? Boolean(relevantEnvMatches.length > 0 || !environmentReady || reuseRegistryUnavailable) : null;
const codeChanged = envReuse ? relevantCodeMatches.length > 0 || catalogRecord?.codeInputHash !== codeInputHash : null;
const codeInputChanged = envReuse ? catalogRecord?.codeInputHash !== codeInputHash : null;
const codeMetadataHashDrift = envReuse
&& codeInputChanged === true
&& Boolean(catalogCodeInputHashAtSource)
&& catalogCodeInputHashAtSource === codeInputHash;
const codeChanged = envReuse ? relevantCodeMatches.length > 0 || (codeInputChanged === true && !codeMetadataHashDrift) : null;
const componentInputPaths = uniqueSorted([
...model.componentPaths,
...model.sharedPaths,
@@ -338,6 +349,9 @@ export async function createCiPlan(options = {}) {
catalogEnvironmentInputHashAtSource,
environmentSourceUnchanged,
codeChanged,
codeInputChanged,
codeMetadataHashDrift,
catalogCodeInputHashAtSource,
reuseRegistry,
environmentInputHash,
codeInputHash,