fix(ci): guard deploy auto fallback
All checks were successful
Dimension Lab website / ci (pull_request) Successful in 17s
Dimension Lab website / deploy (pull_request) Has been skipped

This commit is contained in:
vince 2026-06-20 16:59:36 +02:00
parent a010520a94
commit 006c7e041f
2 changed files with 97 additions and 0 deletions

View file

@ -326,6 +326,60 @@ describe("workspace boundaries", () => {
expect(result.log.match(/^stop dimensionlab-website$/gm)).toHaveLength(2);
});
test("rolls back the latest image when the container fails to restart", () => {
const result = runDeployScriptWithFakes(
{
curl: passingCurlCommand,
git: fakeGitCommand,
podman: fakePodmanCommand("dimensionlab-website.service"),
},
{
DEPLOY_CONTAINER_CLI: "podman",
DEPLOY_CONTAINER_START_TIMEOUT_SECONDS: "0",
DEPLOY_EVENT_NAME: "push",
DEPLOY_REF: "refs/heads/main",
DEPLOY_RESTART_STRATEGY: "quadlet-container",
DEPLOY_SHA: "1234567890abcdef",
},
);
expect(result.status).toBe(1);
expect(result.stderr).toContain("did not restart on localhost/dimensionlab-website:latest");
expect(result.stderr).toContain("rolling back to localhost/dimensionlab-website:rollback-");
expect(result.log).toMatch(
/tag localhost\/dimensionlab-website:rollback-\d{14} localhost\/dimensionlab-website:latest/,
);
expect(result.log.match(/^stop dimensionlab-website$/gm)).toHaveLength(2);
});
test.each([
{
env: { DEPLOY_EVENT_NAME: "pull_request", DEPLOY_REF: "refs/heads/main" },
message: "production deploys only run for push",
},
{
env: { DEPLOY_EVENT_NAME: "push", DEPLOY_REF: "refs/heads/codex/test" },
message: "expected refs/heads/main",
},
])("refuses guarded deploy contexts before host mutations", ({ env, message }) => {
const result = runDeployScriptWithFakes(
{
curl: passingCurlCommand,
git: fakeGitCommand,
podman: fakePodmanCommand("dimensionlab-website.service"),
},
{
DEPLOY_CONTAINER_CLI: "podman",
DEPLOY_SHA: "1234567890abcdef",
...env,
},
);
expect(result.status).toBe(1);
expect(result.stderr).toContain(message);
expect(result.log).toBe("");
});
test("refuses stop-based deploys unless the container belongs to the expected unit", () => {
const result = runDeployScriptWithFakes(
{
@ -349,6 +403,30 @@ describe("workspace boundaries", () => {
expect(result.log).not.toContain("build ");
expect(result.log).not.toContain("stop dimensionlab-website");
});
test("checks the expected unit before auto falls back to stopping the container", () => {
const result = runDeployScriptWithFakes(
{
curl: passingCurlCommand,
git: fakeGitCommand,
podman: fakePodmanCommand("other.service"),
systemctl: fakeSystemctlCommand({ active: false, show: true }),
},
{
DEPLOY_CONTAINER_CLI: "podman",
DEPLOY_EVENT_NAME: "push",
DEPLOY_REF: "refs/heads/main",
DEPLOY_RESTART_STRATEGY: "auto",
DEPLOY_SHA: "1234567890abcdef",
},
);
expect(result.status).toBe(1);
expect(result.stderr).toContain(
"refusing to stop dimensionlab-website; expected PODMAN_SYSTEMD_UNIT=dimensionlab-website.service",
);
expect(result.log).not.toContain("stop dimensionlab-website");
});
});
type WorkspacePackageExport =
@ -448,3 +526,21 @@ if [ "$*" = *'/api/dashboard/tiles'* ]; then
printf '{"state":"ready","tiles":[]}'
fi
`;
function fakeSystemctlCommand(options: { active: boolean; show: boolean }): string {
const activeStatus = options.active ? 0 : 3;
const showStatus = options.show ? 0 : 1;
return `#!/usr/bin/env bash
printf 'systemctl %s\\n' "$*" >> "$DEPLOY_TEST_LOG"
if [ "$1" = "--user" ] && [ "$2" = "is-active" ]; then
exit ${activeStatus}
fi
if [ "$1" = "--user" ] && [ "$2" = "show" ]; then
exit ${showStatus}
fi
if [ "$1" = "--user" ] && [ "$2" = "restart" ]; then
exit 0
fi
`;
}

View file

@ -215,6 +215,7 @@ restart_service() {
if command -v systemctl >/dev/null 2>&1 && systemctl --user is-active "$SERVICE_NAME" >/dev/null 2>&1; then
run systemctl --user restart "$SERVICE_NAME"
else
require_container_managed_by_service
run "$container_cli" stop "$CONTAINER_NAME"
fi
;;