feat : notify new update income
This commit is contained in:
@@ -156,7 +156,25 @@ describe("production deployment contract", () => {
|
||||
expect(notifier).toContain('new EventSource("/api/active")');
|
||||
expect(notifier).toContain("window.location.reload()");
|
||||
expect(notifier).toContain('label: "รีโหลด"');
|
||||
expect(route).toContain('channel.sendNamed("deployment", deploymentId)');
|
||||
expect(notifier).toContain('source.addEventListener("deployment-status"');
|
||||
expect(route).toContain('"deployment-status"');
|
||||
});
|
||||
|
||||
it("announces deployment lifecycle results without blocking releases", async () => {
|
||||
const [workflow, deployment] = await Promise.all([
|
||||
repositoryFile(".gitea/workflows/ci.yml"),
|
||||
repositoryFile("k8s/base/deployment.yaml"),
|
||||
]);
|
||||
|
||||
expect(workflow).toContain("Announce incoming deployment");
|
||||
expect(workflow).toContain("Publish deployment result");
|
||||
expect(workflow).toContain("if: always()");
|
||||
expect(workflow).toContain("continue-on-error: true");
|
||||
expect(workflow).toContain('status\\":\\"deploying');
|
||||
expect(workflow).toContain("DEPLOYMENT_JOB_STATUS");
|
||||
expect(workflow).toContain("/api/deployments/status");
|
||||
expect(deployment).toContain("DEPLOYMENT_WEBHOOK_SECRET");
|
||||
expect(deployment).toContain("optional: true");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -174,6 +192,7 @@ describe("environment template contract", () => {
|
||||
"S3_SECRET_ACCESS_KEY",
|
||||
"NEXT_SERVER_ACTIONS_ENCRYPTION_KEY",
|
||||
"NEXT_DEPLOYMENT_ID",
|
||||
"DEPLOYMENT_WEBHOOK_SECRET",
|
||||
"DISCORD_BOT_TOKEN",
|
||||
"DISCORD_CHANNEL_ID",
|
||||
"DISCORD_LOG_CHANNEL_ID",
|
||||
|
||||
@@ -6,6 +6,7 @@ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
vi.mock("server-only", () => ({}));
|
||||
|
||||
const { closeRedisEventStreams, createRedisEventResponse } = await import("@/lib/events/redis-stream");
|
||||
const { getLatestDeploymentStatus, publishDeploymentStatus } = await import("@/lib/deployment/repository");
|
||||
const { updateVisitorPresence } = await import("@/lib/presence");
|
||||
const { closeRedisClient, redisEventChannel } = await import("@/lib/redis/client");
|
||||
const { consumeRateLimit } = await import("@/lib/security/rate-limit");
|
||||
@@ -102,4 +103,17 @@ describeWithRedis("shared Redis security paths", () => {
|
||||
second.abort();
|
||||
await Promise.all([readerA.cancel(), readerB.cancel()]);
|
||||
});
|
||||
|
||||
it("does not let stale deployment results replace a newer announcement", async () => {
|
||||
const firstId = "a".repeat(40);
|
||||
const secondId = "b".repeat(40);
|
||||
expect((await publishDeploymentStatus(firstId, "deploying")).accepted).toBe(true);
|
||||
expect((await publishDeploymentStatus(secondId, "deploying")).accepted).toBe(true);
|
||||
expect((await publishDeploymentStatus(firstId, "ready")).accepted).toBe(false);
|
||||
expect(await getLatestDeploymentStatus()).toMatchObject({
|
||||
deploymentId: secondId,
|
||||
status: "deploying",
|
||||
});
|
||||
expect((await publishDeploymentStatus(secondId, "failed")).accepted).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user