fix: format dev cd lease timestamps

This commit is contained in:
Code Queue Review
2026-05-23 09:13:18 +00:00
parent fd07465923
commit 5f11ec389a
3 changed files with 30 additions and 8 deletions
+14 -4
View File
@@ -154,6 +154,16 @@ function nowIso() {
return new Date().toISOString();
}
function kubernetesMicroTime(value) {
const date = value instanceof Date ? value : new Date(value);
if (!Number.isFinite(date.getTime())) {
throw new DevCdApplyError("invalid Kubernetes Lease timestamp", {
code: "invalid-lease-timestamp"
});
}
return date.toISOString().replace(/\.(\d{3})Z$/u, ".$1000Z");
}
function parseJsonMaybe(value) {
try {
return JSON.parse(value);
@@ -580,7 +590,7 @@ function mergeLease(lease, patch, { resetLockAnnotations = false } = {}) {
}
async function acquireDeployLock({ ctx, args, kubectlContext, target, deployBefore, transactionId, ownerTaskId, liveBefore, now }) {
const startedAt = now.toISOString();
const startedAt = kubernetesMicroTime(now);
const get = await kubectl(ctx, kubectlContext, ["-n", args.targetNamespace, "get", "lease", args.lockName, "-o", "json"]);
if (get.code === 0) {
const lease = JSON.parse(get.stdout);
@@ -698,7 +708,7 @@ async function patchOwnedLease({ ctx, args, kubectlContext, lockState, transacti
}
async function updateDeployLockPhase({ ctx, args, kubectlContext, transactionId, lockState, phase, status = "running" }) {
const updatedAt = ctx.now().toISOString();
const updatedAt = kubernetesMicroTime(ctx.now());
const patch = {
metadata: {
annotations: {
@@ -724,7 +734,7 @@ async function updateDeployLockPhase({ ctx, args, kubectlContext, transactionId,
}
async function updateDeployLockLiveBefore({ ctx, args, kubectlContext, transactionId, lockState, liveBefore }) {
const updatedAt = ctx.now().toISOString();
const updatedAt = kubernetesMicroTime(ctx.now());
const patch = {
metadata: {
annotations: {
@@ -767,7 +777,7 @@ async function releaseDeployLock({ ctx, args, kubectlContext, transactionId, sta
phase: current.phase
};
}
const releasedAt = ctx.now().toISOString();
const releasedAt = kubernetesMicroTime(ctx.now());
const patch = {
metadata: {
annotations: {
+7
View File
@@ -100,6 +100,9 @@ function makeHttpGetJson() {
function makeRunCommand({ heldLock = null, commandLog = [] } = {}) {
let lease = heldLock ? leaseFromLock(heldLock) : null;
const assertLeaseMicroTime = (value) => {
assert.match(value, /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}Z$/u);
};
return async (command, args, options = {}) => {
commandLog.push({ command, args, env: options.env ?? {}, input: options.input ?? "" });
if (command === "git" && args[0] === "rev-parse" && args.includes("origin/main^{commit}")) {
@@ -117,12 +120,16 @@ function makeRunCommand({ heldLock = null, commandLog = [] } = {}) {
}
if (command.includes("kubectl") && args.includes("create")) {
lease = JSON.parse(options.input);
assertLeaseMicroTime(lease.spec.acquireTime);
assertLeaseMicroTime(lease.spec.renewTime);
lease.metadata.resourceVersion = "2";
return { code: 0, stdout: `${JSON.stringify(lease)}\n`, stderr: "" };
}
if (command.includes("kubectl") && args.includes("replace")) {
const nextLease = JSON.parse(options.input);
assert.equal(nextLease.metadata?.resourceVersion, lease?.metadata?.resourceVersion);
if (nextLease.spec?.acquireTime) assertLeaseMicroTime(nextLease.spec.acquireTime);
if (nextLease.spec?.renewTime) assertLeaseMicroTime(nextLease.spec.renewTime);
lease = nextLease;
lease.metadata.resourceVersion = String(Number(lease.metadata.resourceVersion ?? "2") + 1);
return { code: 0, stdout: `${JSON.stringify(lease)}\n`, stderr: "" };
+9 -4
View File
@@ -1015,10 +1015,6 @@ function assertDevCdApplyReport(report, label) {
assertString(report.transaction.ownerTaskId, `${label}.transaction.ownerTaskId`);
assert.ok(Number.isInteger(report.transaction.ttlSeconds), `${label}.transaction.ttlSeconds`);
assertArray(report.transaction.phases, `${label}.transaction.phases`);
assert.ok(
report.transaction.phases.some((phase) => phase.phase === "publishing"),
`${label}.transaction.phases must include publishing`
);
assertObject(report.devCdApply, `${label}.devCdApply`);
for (const field of ["mode", "target", "deployJson", "lock", "steps", "liveBefore", "liveVerify", "reportPaths", "safety"]) {
@@ -1042,6 +1038,15 @@ function assertDevCdApplyReport(report, label) {
assertObject(report.devCdApply.lock, `${label}.devCdApply.lock`);
assert.equal(typeof report.devCdApply.lock.acquired, "boolean", `${label}.devCdApply.lock.acquired`);
if (report.devCdApply.lock.acquired) {
assert.ok(
report.transaction.phases.some((phase) => phase.phase === "publishing"),
`${label}.transaction.phases must include publishing after lock acquisition`
);
} else {
assert.equal(report.status, "blocked", `${label}.status must be blocked when lock was not acquired`);
assert.equal(report.devCdApply.safety.mutationAttempted, false, `${label}.devCdApply.safety.mutationAttempted`);
}
assertArray(report.devCdApply.steps, `${label}.devCdApply.steps`);
for (const [index, step] of report.devCdApply.steps.entries()) {