From 0d48769556db3ed313434c7e824339924c8df792 Mon Sep 17 00:00:00 2001 From: Kevin J Hoerr Date: Thu, 16 Sep 2021 16:52:14 -0400 Subject: Add format to head commit info --- src/metadata.ts | 29 +++++++++---- src/routes.test.ts | 53 +++++++++++++++++++++-- src/routes.ts | 121 +++++++---------------------------------------------- 3 files changed, 87 insertions(+), 116 deletions(-) (limited to 'src') diff --git a/src/metadata.ts b/src/metadata.ts index b7dbf19..6a0addc 100644 --- a/src/metadata.ts +++ b/src/metadata.ts @@ -5,8 +5,19 @@ import loggerConfig from "./util/logger"; import { BranchNotFoundError } from "./errors"; import { GradientStyle } from "./formats"; +interface HeadContext { + commit: string; + format: string; +} + +export const isError = ( + obj: HeadContext | BranchNotFoundError +): obj is BranchNotFoundError => { + return Object.keys(obj).includes("name"); +}; + interface Branch { - head: string; + head: HeadContext | string; } interface BranchList { @@ -17,7 +28,7 @@ export interface HeadIdentity { organization: string; repository: string; branch: string; - head: string; + head: HeadContext; } export interface Repository { @@ -73,7 +84,7 @@ class Metadata { organization: string, repository: string, branch: string - ): Promise { + ): Promise { const result = await this.database .collection("repository") .findOne({ @@ -84,14 +95,18 @@ class Metadata { if (result !== null && Object.keys(result.branches).includes(branch)) { const limb = result.branches[branch]; + const head = typeof limb.head === "string" ? limb.head : limb.head.commit; + const format = + typeof limb.head === "string" ? "tarpaulin" : limb.head.format; logger.debug( - "Found commit %s for ORB %s/%s/%s", - limb.head, + "Found commit %s for ORB %s/%s/%s (format %s)", + head, organization, repository, - branch + branch, + format ); - return limb.head; + return { commit: head, format }; } else { return new BranchNotFoundError(); } diff --git a/src/routes.test.ts b/src/routes.test.ts index f8bcfcd..5ffd289 100644 --- a/src/routes.test.ts +++ b/src/routes.test.ts @@ -55,7 +55,8 @@ const config = { }; const mock = ( headCommit: jest.Mock = jest.fn( - () => new Promise(solv => solv("testcommit")) + () => + new Promise(solv => solv({ commit: "testcommit", format: "tarpaulin" })) ), updateBranch: jest.Mock = jest.fn(() => new Promise(solv => solv(true))) ): MetadataMockType => ({ @@ -255,6 +256,25 @@ describe("Badges and reports", () => { expect(res.text).toEqual(buffer.toString("utf-8")); }); + it("should retrieve the marked format as stored in metadata", async () => { + const head = jest.fn( + () => + new Promise(solv => + solv({ commit: "testcommit", format: "cobertura" }) + ) + ); + const mockMeta = mock(head); + // request HTML, get XML + const res = await (await request(mockMeta)) + .get("/v1/testorg/testrepo/testbranch.html") + .expect("Content-Type", /xml/) + .expect(200); + const buffer = await fs.promises.readFile(coberturaReport); + + expect(mockMeta.getHeadCommit).toHaveBeenCalledTimes(1); + expect(res.text).toEqual(buffer.toString("utf-8")); + }); + it("should return 404 if file does not exist", async () => { await (await request()).get("/v1/neorg/nerepo/nebranch.html").expect(404); }); @@ -278,7 +298,13 @@ describe("Badges and reports", () => { describe("GET /v1/:org/:repo/:branch.xml", () => { it("should retrieve the stored report file with the associated head commit", async () => { - const mockMeta = mock(); + const head = jest.fn( + () => + new Promise(solv => + solv({ commit: "testcommit", format: "cobertura" }) + ) + ); + const mockMeta = mock(head); const res = await (await request(mockMeta)) .get("/v1/testorg/testrepo/testbranch.xml") .expect("Content-Type", /xml/) @@ -289,6 +315,25 @@ describe("Badges and reports", () => { expect(res.text).toEqual(buffer.toString("utf-8")); }); + it("should retrieve the marked format as stored in metadata", async () => { + const head = jest.fn( + () => + new Promise(solv => + solv({ commit: "testcommit", format: "tarpaulin" }) + ) + ); + const mockMeta = mock(head); + // request XML, get HTML + const res = await (await request(mockMeta)) + .get("/v1/testorg/testrepo/testbranch.xml") + .expect("Content-Type", /html/) + .expect(200); + const buffer = await fs.promises.readFile(tarpaulinReport); + + expect(mockMeta.getHeadCommit).toHaveBeenCalledTimes(1); + expect(res.text).toEqual(buffer.toString("utf-8")); + }); + it("should return 404 if file does not exist", async () => { await (await request()).get("/v1/neorg/nerepo/nebranch.xml").expect(404); }); @@ -396,7 +441,7 @@ describe("Uploads", () => { organization: "testorg", repository: "testrepo", branch: "newthis", - head: "newthat" + head: { commit: "newthat", format: "tarpaulin" } }); expect(mockMeta.updateBranch).toHaveBeenCalledTimes(1); await fs.promises.access( @@ -489,7 +534,7 @@ describe("Uploads", () => { organization: "testorg", repository: "testrepo", branch: "newthis", - head: "newthat" + head: { commit: "newthat", format: "cobertura" } }); expect(mockMeta.updateBranch).toHaveBeenCalledTimes(1); await fs.promises.access( diff --git a/src/routes.ts b/src/routes.ts index df23a54..d242902 100644 --- a/src/routes.ts +++ b/src/routes.ts @@ -5,7 +5,7 @@ import path from "path"; import fs from "fs"; import formats, { Format } from "./formats"; -import Metadata, { HeadIdentity } from "./metadata"; +import Metadata, { HeadIdentity, isError } from "./metadata"; import loggerConfig from "./util/logger"; import { InvalidReportDocumentError, Messages } from "./errors"; @@ -24,7 +24,7 @@ export default (metadata: Metadata): Router => { identity.organization, identity.repository, identity.branch, - identity.head + identity.head.commit ); const coverage = await formatter.parseCoverage(contents); if (typeof coverage !== "number") { @@ -76,8 +76,8 @@ export default (metadata: Metadata): Router => { express.static(path.join(metadata.getPublicDir(), "static")) ); - // Upload HTML file - router.post("/v1/:org/:repo/:branch/:commit.html", (req, res) => { + // Upload file + router.post("/v1/:org/:repo/:branch/:commit.(ht)?x?ml", (req, res) => { const { org, repo, branch, commit } = req.params; const { token, format } = req.query; @@ -111,69 +111,7 @@ export default (metadata: Metadata): Router => { organization: org, repository: repo, branch, - head: commit - }; - - try { - const result = await commitFormatDocs(contents, identity, formatter); - - if (typeof result === "boolean") { - if (result) { - return res.status(200).send(); - } else { - logger.error( - "Unknown error while attempting to commit branch update" - ); - return res.status(500).send(Messages.UnknownError); - } - } else { - return res.status(400).send(Messages.InvalidFormat); - } - } catch (err) { - logger.error( - err ?? "Unknown error occurred while processing POST request" - ); - return res.status(500).send(Messages.UnknownError); - } - }); - }); - - // Upload XML file - router.post("/v1/:org/:repo/:branch/:commit.xml", (req, res) => { - const { org, repo, branch, commit } = req.params; - - const { token, format } = req.query; - if (token != metadata.getToken()) { - return res.status(401).send(Messages.InvalidToken); - } - - if (typeof format !== "string" || !formats.listFormats().includes(format)) { - return res.status(406).send(Messages.InvalidFormat); - } - - const limit = metadata.getUploadLimit(); - if (Number(req.headers["content-length"] ?? 0) > limit) { - return res.status(413).send(Messages.FileTooLarge); - } - - let contents = ""; - req.on("data", raw => { - if (contents.length <= limit) { - contents += raw; - } - }); - req.on("end", async () => { - // Ignore large requests - if (contents.length > limit) { - return res.status(413).send(Messages.FileTooLarge); - } - - const formatter = formats.getFormat(format); - const identity = { - organization: org, - repository: repo, - branch, - head: commit + head: { commit, format } }; try { @@ -212,7 +150,7 @@ export default (metadata: Metadata): Router => { org, repo, branch, - head, + head.commit, file ); fs.access(pathname, fs.constants.R_OK, err => @@ -227,12 +165,12 @@ export default (metadata: Metadata): Router => { metadata.getHeadCommit(org, repo, branch).then( result => { - if (typeof result === "string") { + if (!isError(result)) { const identity = { organization: org, repository: repo, branch, - head: result.toString() + head: result }; retrieveFile(res, identity, "badge.svg"); } else { @@ -248,47 +186,20 @@ export default (metadata: Metadata): Router => { ); }); - router.get("/v1/:org/:repo/:branch.html", (req, res) => { + router.get("/v1/:org/:repo/:branch.(ht)?x?ml", (req, res) => { const { org, repo, branch } = req.params; - const format = formats.formats.tarpaulin; - - metadata.getHeadCommit(org, repo, branch).then( - result => { - if (typeof result === "string") { - const identity = { - organization: org, - repository: repo, - branch, - head: result.toString() - }; - retrieveFile(res, identity, format.fileName); - } else { - res.status(404).send(result.message); - } - }, - err => { - logger.error( - err ?? "Error occurred while fetching commit for GET request" - ); - res.status(500).send(Messages.UnknownError); - } - ); - }); - - router.get("/v1/:org/:repo/:branch.xml", (req, res) => { - const { org, repo, branch } = req.params; - const format = formats.formats.cobertura; metadata.getHeadCommit(org, repo, branch).then( result => { - if (typeof result === "string") { + if (!isError(result)) { const identity = { organization: org, repository: repo, branch, - head: result.toString() + head: result }; - retrieveFile(res, identity, format.fileName); + const { fileName } = formats.getFormat(result.format); + retrieveFile(res, identity, fileName); } else { res.status(404).send(result.message); } @@ -309,7 +220,7 @@ export default (metadata: Metadata): Router => { organization: org, repository: repo, branch, - head: commit + head: { commit, format: "_" } }; retrieveFile(res, identity, "badge.svg"); }); @@ -322,7 +233,7 @@ export default (metadata: Metadata): Router => { organization: org, repository: repo, branch, - head: commit + head: { commit, format: "tarpaulin" } }; retrieveFile(res, identity, format.fileName); }); @@ -334,7 +245,7 @@ export default (metadata: Metadata): Router => { organization: org, repository: repo, branch, - head: commit + head: { commit, format: "cobertura" } }; retrieveFile(res, identity, format.fileName); }); -- cgit