fix: format dev cd lease timestamps
This commit is contained in:
@@ -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: {
|
||||
|
||||
@@ -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: "" };
|
||||
|
||||
@@ -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()) {
|
||||
|
||||
Reference in New Issue
Block a user