ci: deploy website from Forgejo Actions #54
2 changed files with 97 additions and 0 deletions
|
|
@ -326,6 +326,60 @@ describe("workspace boundaries", () => {
|
||||||
expect(result.log.match(/^stop dimensionlab-website$/gm)).toHaveLength(2);
|
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", () => {
|
test("refuses stop-based deploys unless the container belongs to the expected unit", () => {
|
||||||
const result = runDeployScriptWithFakes(
|
const result = runDeployScriptWithFakes(
|
||||||
{
|
{
|
||||||
|
|
@ -349,6 +403,30 @@ describe("workspace boundaries", () => {
|
||||||
expect(result.log).not.toContain("build ");
|
expect(result.log).not.toContain("build ");
|
||||||
expect(result.log).not.toContain("stop dimensionlab-website");
|
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 =
|
type WorkspacePackageExport =
|
||||||
|
|
@ -448,3 +526,21 @@ if [ "$*" = *'/api/dashboard/tiles'* ]; then
|
||||||
printf '{"state":"ready","tiles":[]}'
|
printf '{"state":"ready","tiles":[]}'
|
||||||
fi
|
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
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
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"
|
run systemctl --user restart "$SERVICE_NAME"
|
||||||
else
|
else
|
||||||
|
require_container_managed_by_service
|
||||||
run "$container_cli" stop "$CONTAINER_NAME"
|
run "$container_cli" stop "$CONTAINER_NAME"
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue