Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/release-sync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ async function listSyncedVersions(prisma: PrismaClient, type: ReleaseType): Prom
return new Set(releases.map(release => release.version));
}

async function releaseExists(
export async function releaseExists(
prisma: PrismaClient,
type: ReleaseType,
version: string,
Expand Down
14 changes: 10 additions & 4 deletions src/releases.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Request, Response } from "express";
import { prisma } from "./db";
import { BadRequestError, ConflictError, InternalServerError, NotFoundError } from "./errors";
import type { ReleaseSyncRunner } from "./release-sync";
import { releaseExists, type ReleaseSyncRunner } from "./release-sync";
import semver from "semver";

import { GetObjectCommand, ListObjectsV2Command } from "@aws-sdk/client-s3";
Expand Down Expand Up @@ -734,8 +734,10 @@ const syncBodySchema = z
/**
* POST /releases/sync: register every stable R2 version missing from the DB
* and answer with the per-outcome counts. With `{ type, version }` in the
* body, that one version skips the settle window: the caller vouches its
* last object is written. Every other version keeps it.
* body, that one version skips the settle window (the caller vouches its
* last object is written) and the answer adds `registered`: whether a row
* for it exists once the run is over, whichever run created it. The counts
* alone cannot say that, since they cover every version scanned.
*/
export function Sync(runner: ReleaseSyncRunner) {
return async (req: Request, res: Response) => {
Expand All @@ -744,6 +746,10 @@ export function Sync(runner: ReleaseSyncRunner) {
if (stats === "busy") {
throw new ConflictError("A release sync is already in progress");
}
return res.json(stats);
if (!settled) {
return res.json(stats);
}
const registered = await releaseExists(prisma, settled.type, settled.version);
return res.json({ ...stats, registered });
};
}
14 changes: 13 additions & 1 deletion test/sync-releases.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,7 +546,9 @@ describe("Sync handler", () => {

await Sync(newRunner())(request({ type: "app", version: FRESH_VERSION }), res);

expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ created: 1, uploading: 1 }));
expect(res.json).toHaveBeenCalledWith(
expect.objectContaining({ created: 1, uploading: 1, registered: true }),
);
expect(
await testPrisma.release.findUnique({
where: { version_type: { version: FRESH_VERSION, type: "app" } },
Expand All @@ -566,6 +568,16 @@ describe("Sync handler", () => {
await Sync(newRunner())(request(), res);

expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ created: 0, uploading: 2 }));
expect(res.json).not.toHaveBeenCalledWith(expect.objectContaining({ registered: expect.anything() }));
});

it("answers registered: false when the named version is not on R2", async () => {
mockS3ListVersions("app", []);
const res = response();

await Sync(newRunner())(request({ type: "app", version: "9.9.99" }), res);

expect(res.json).toHaveBeenCalledWith(expect.objectContaining({ created: 0, registered: false }));
});

it.each([
Expand Down
Loading