fix(compose): remove stale labels for disabled domains

This commit is contained in:
Vyacheslav Scherbinin 2026-08-11 10:45:33 +07:00
parent 63144e6855
commit 37c8d6477e
2 changed files with 92 additions and 2 deletions

View File

@ -6,11 +6,12 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
// addDomainToCompose reads the compose file from disk through loadDockerCompose
// (existsSync + readFileSync). Mock node:fs so the function runs its real
// label-generation logic against an in-memory compose spec.
const composeYaml = `
const baseComposeYaml = `
services:
frigate:
image: frigate
`;
let composeYaml = baseComposeYaml;
vi.mock("node:fs", async (importOriginal) => {
const actual = await importOriginal<typeof import("node:fs")>();
@ -62,6 +63,7 @@ const serviceLabels = (
describe("addDomainToCompose enabled filtering", () => {
beforeEach(() => {
vi.clearAllMocks();
composeYaml = baseComposeYaml;
});
it("generates traefik labels for an enabled domain", async () => {
@ -88,6 +90,55 @@ describe("addDomainToCompose enabled filtering", () => {
);
});
it.each([
[
"docker-compose",
`services:
frigate:
image: frigate
labels:
- traefik.enable=true
- traefik.http.routers.test-app-1-web.rule=Host(\`frigate.example.com\`)
- traefik.http.services.test-app-1-web.loadbalancer.server.port=8971
- traefik.http.middlewares.stripprefix-test-app-1.stripprefix.prefixes=/api
- custom.label=preserved
`,
],
[
"stack",
`services:
frigate:
image: frigate
deploy:
labels:
- traefik.enable=true
- traefik.http.routers.test-app-1-web.rule=Host(\`frigate.example.com\`)
- traefik.http.services.test-app-1-web.loadbalancer.server.port=8971
- traefik.http.middlewares.stripprefix-test-app-1.stripprefix.prefixes=/api
- custom.label=preserved
`,
],
] as const)(
"removes stale labels for a disabled domain from %s rebuilds",
async (composeType, staleComposeYaml) => {
composeYaml = staleComposeYaml;
const result = await addDomainToCompose({ ...baseCompose, composeType }, [
{ ...baseDomain, enabled: false },
]);
const service = result?.services?.frigate;
const labels =
composeType === "docker-compose"
? service?.labels
: service?.deploy?.labels;
expect(labels).toContain("custom.label=preserved");
expect(
(labels as string[]).some((label) => label.includes("test-app-1")),
).toBe(false);
},
);
it("emits labels only for the enabled domain when both are present", async () => {
const result = await addDomainToCompose(baseCompose, [
{ ...baseDomain, host: "enabled.example.com", enabled: true },

View File

@ -166,6 +166,25 @@ export const applyComposeFilePatch = async (
}
};
const removeDomainLabels = (
labels: DefinitionsService["labels"],
appName: string,
uniqueConfigKey: number,
) => {
if (!Array.isArray(labels)) return labels;
const prefixes = [
`traefik.http.routers.${appName}-${uniqueConfigKey}-`,
`traefik.http.services.${appName}-${uniqueConfigKey}-`,
`traefik.http.middlewares.stripprefix-${appName}-${uniqueConfigKey}.`,
`traefik.http.middlewares.addprefix-${appName}-${uniqueConfigKey}.`,
];
return labels.filter(
(label) => !prefixes.some((prefix) => label.startsWith(prefix)),
);
};
export const addDomainToCompose = async (
compose: Compose,
domains: Domain[],
@ -198,7 +217,27 @@ export const addDomainToCompose = async (
result = randomized;
}
// Disabled domains keep their config but must not produce any traefik labels.
for (const domain of domains.filter((d) => !d.enabled)) {
if (!domain.serviceName) continue;
const service = result.services?.[domain.serviceName];
if (!service) continue;
if (compose.composeType === "docker-compose") {
service.labels = removeDomainLabels(
service.labels,
appName,
domain.uniqueConfigKey,
);
} else if (service.deploy) {
service.deploy.labels = removeDomainLabels(
service.deploy.labels,
appName,
domain.uniqueConfigKey,
);
}
}
for (const domain of domains.filter((d) => d.enabled)) {
const { serviceName, https } = domain;
if (!serviceName) {