a073f92da3
Deploy / deploy (push) Successful in 7m31s
Numbering was scoped to the project, so the day's first delivery of
episode 102 was named _02 purely because episode 101 had already gone out
that morning. The count is meant to distinguish repeat deliveries of the
same content, and packageDir already separates episodes — three episodes
delivering today each land in their own folder and each are that folder's
first delivery. Adding `episode` to the lookup makes the suffix mean what
the folder layout already implies: only a second delivery of the *same*
episode becomes _02. The [projectId, episode] index already exists, so
the extra filter costs nothing.
packageNameTemplate also moves from {yymmdd} to {yyyymmdd}. The AE panel
has always built its local delivery folders with a four-digit year, so
this is the server matching the connector rather than a new convention.
The {yymmdd} token stays in TokenValues: a project carrying its own
template in deliveryConfig is unaffected either way.
Existing packages are untouched — buildDeliveryJobManifest reads rootPath
off the record. On the day of the changeover an episode that already
delivered as 260903_Delivery starts again at the bare 20260903_Delivery,
which is a different name and a different folder, so nothing merges.
Producer reviews keep their per-project numbering: a review can span
several episodes and stores episode as "", so scoping it the same way
would put every such review in one bucket.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
99 lines
3.4 KiB
TypeScript
99 lines
3.4 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { DELIVERY_CONFIG_DEFAULT, applyTokens, dateTokens, nextPackageName, tidyPath } from "./deliveries";
|
|
|
|
const BASE = "20260901_Delivery";
|
|
|
|
describe("nextPackageName", () => {
|
|
it("uses the bare base for the first package of the day", () => {
|
|
expect(nextPackageName(BASE, [])).toBe(BASE);
|
|
});
|
|
|
|
it("suffixes later packages sharing the base", () => {
|
|
expect(nextPackageName(BASE, [BASE])).toBe(`${BASE}_02`);
|
|
expect(nextPackageName(BASE, [BASE, `${BASE}_02`])).toBe(`${BASE}_03`);
|
|
});
|
|
|
|
it("never reuses a number after a gap", () => {
|
|
expect(nextPackageName(BASE, [BASE, `${BASE}_02`, `${BASE}_04`])).toBe(`${BASE}_05`);
|
|
});
|
|
|
|
it("ignores names that only share a prefix", () => {
|
|
expect(nextPackageName(BASE, [`${BASE}_final`, "20260902_Delivery"])).toBe(BASE);
|
|
});
|
|
});
|
|
|
|
describe("delivery layout", () => {
|
|
const tokens = {
|
|
deliveryRoot: "//SAN/DELIVERY",
|
|
showId: "ACME",
|
|
episode: "101",
|
|
packageName: BASE,
|
|
};
|
|
|
|
it("separates shows so two shows' episode 101 cannot collide", () => {
|
|
const acme = applyTokens(DELIVERY_CONFIG_DEFAULT.layout.packageDir, tokens);
|
|
const other = applyTokens(DELIVERY_CONFIG_DEFAULT.layout.packageDir, { ...tokens, showId: "BRAVO" });
|
|
expect(acme).toBe("//SAN/DELIVERY/ACME/101/20260901_Delivery");
|
|
expect(other).not.toBe(acme);
|
|
});
|
|
|
|
it("puts producer reviews under the show too", () => {
|
|
expect(applyTokens(DELIVERY_CONFIG_DEFAULT.layout.reviewDir, tokens)).toBe(
|
|
"//SAN/DELIVERY/ACME/PRODUCER_REVIEWS/20260901_Delivery"
|
|
);
|
|
});
|
|
});
|
|
|
|
describe("tidyPath", () => {
|
|
it("drops the empty segment a non-episodic show leaves behind", () => {
|
|
const raw = applyTokens(DELIVERY_CONFIG_DEFAULT.layout.packageDir, {
|
|
deliveryRoot: "//SAN/DELIVERY",
|
|
showId: "ACME",
|
|
episode: "",
|
|
packageName: BASE,
|
|
});
|
|
expect(tidyPath(raw)).toBe("//SAN/DELIVERY/ACME/20260901_Delivery");
|
|
});
|
|
|
|
it("keeps the UNC root intact", () => {
|
|
expect(tidyPath("//SAN/DELIVERY/ACME")).toBe("//SAN/DELIVERY/ACME");
|
|
});
|
|
|
|
it("leaves a well-formed path alone", () => {
|
|
expect(tidyPath("V:/DELIVERY/ACME/101/x")).toBe("V:/DELIVERY/ACME/101/x");
|
|
});
|
|
});
|
|
|
|
describe("per-episode numbering", () => {
|
|
// The scoping itself lives in createDeliveryPackage's query, which passes
|
|
// only the names already used by *this* episode. These pin the contract that
|
|
// depends on: another episode's delivery must not push this one to _02.
|
|
it("gives each episode's first delivery of the day the bare name", () => {
|
|
const ep101 = nextPackageName(BASE, [BASE]);
|
|
const ep102 = nextPackageName(BASE, []);
|
|
expect(ep101).toBe(`${BASE}_02`);
|
|
expect(ep102).toBe(BASE);
|
|
});
|
|
|
|
it("keeps two episodes' same-named packages in separate folders", () => {
|
|
const dirFor = (episode: string, packageName: string) =>
|
|
tidyPath(
|
|
applyTokens(DELIVERY_CONFIG_DEFAULT.layout.packageDir, {
|
|
deliveryRoot: "//SAN/DELIVERY",
|
|
showId: "ACME",
|
|
episode,
|
|
packageName,
|
|
})
|
|
);
|
|
expect(dirFor("101", BASE)).toBe("//SAN/DELIVERY/ACME/101/20260901_Delivery");
|
|
expect(dirFor("102", BASE)).toBe("//SAN/DELIVERY/ACME/102/20260901_Delivery");
|
|
});
|
|
});
|
|
|
|
describe("package name template", () => {
|
|
it("names the day with a four-digit year", () => {
|
|
const name = applyTokens(DELIVERY_CONFIG_DEFAULT.packageNameTemplate, dateTokens(new Date(2026, 8, 1)));
|
|
expect(name).toBe("20260901_Delivery");
|
|
});
|
|
});
|