Skip to content

Commit

Permalink
feat(GH-8): Add client for GitHub checks
Browse files Browse the repository at this point in the history
  • Loading branch information
gavanlamb committed Jun 14, 2024
1 parent 0b5e089 commit bd27f93
Show file tree
Hide file tree
Showing 2 changed files with 160 additions and 0 deletions.
102 changes: 102 additions & 0 deletions __tests__/client/githubChecksClient.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { CheckRunStatus } from "../../src/types/checkRunStatus";
import { CheckConclusion } from "../../src/types/checkConclusion";

describe("createCheck", () => {
beforeEach(() => {
jest.clearAllMocks();
jest.resetModules();
});

it("should not suppress exceptions if client code throws", async () => {
const errorMessage = "Error encountered when calling octokit client";
const createOctokitClientMock = jest.fn(() => {
throw new Error(errorMessage);
});
jest.doMock("../../src/clients/octokit", () => ({ createOctokitClient: createOctokitClientMock }));

const { createCheck } = await import("../../src/clients/githubChecksClient");
const exec = createCheck(
"owner",
"repo",
"check-name",
"headSha",
CheckRunStatus.Completed,
CheckConclusion.Success,
"Check Title",
"Check Body"
);

await expect(exec).rejects.toThrow(errorMessage);
expect(createOctokitClientMock).toHaveBeenCalledTimes(1);
});

it("should throw an error if the check run creation fails", async () => {
const debugMock = jest.fn();
jest.doMock("@actions/core", () => ({debug: debugMock}));

const createOctokitClientMock = jest.fn(() => ({rest:{ checks:{ create:jest.fn(() => ({ status: 500 }))}}}));
jest.doMock("../../src/clients/octokit", () => ({createOctokitClient: createOctokitClientMock}));

const owner = "owner";
const repo = "repo";
const headSha = "headSha";

const { createCheck } = await import("../../src/clients/githubChecksClient");
const exec = createCheck(
owner,
repo,
"check-name",
headSha,
CheckRunStatus.Completed,
CheckConclusion.Success,
"Check Title",
"Check Body"
);

await expect(exec).rejects.toThrow(`Failed to create the check run for:\n\towner: ${owner}\n\trepo: ${repo}\n\theadSha: ${headSha}`);
expect(createOctokitClientMock).toHaveBeenCalledTimes(1);
expect(debugMock).toHaveBeenCalledWith("Going to call the rest endpoint to delete an issue comment with the following details:\n" +
"\towner: owner\n" +
"\trepo: repo\n" +
"\tname: check-name\n" +
"\theadSha: headSha\n" +
"\tstatus: completed\n" +
"\tconclusion: success\n" +
"\ttitle: Check Title\n" +
"\tbody: Check Body");
expect(debugMock).toHaveBeenCalledWith("Called the rest endpoint to create check run");
});

it("should create a check run successfully", async () => {
const debugMock = jest.fn();
jest.doMock("@actions/core", () => ({debug: debugMock}));

const createOctokitClientMock = jest.fn(() => ({ rest:{ checks:{ create: jest.fn(() => ({ status: 201 })) }}}));
jest.doMock("../../src/clients/octokit", () => ({createOctokitClient: createOctokitClientMock}));

const { createCheck } = await import("../../src/clients/githubChecksClient");
await createCheck(
"owner",
"repo",
"check-name",
"headSha",
CheckRunStatus.Completed,
CheckConclusion.Success,
"Check Title",
"Check Body"
);

expect(createOctokitClientMock).toHaveBeenCalledTimes(1);
expect(debugMock).toHaveBeenCalledWith("Going to call the rest endpoint to delete an issue comment with the following details:\n" +
"\towner: owner\n" +
"\trepo: repo\n" +
"\tname: check-name\n" +
"\theadSha: headSha\n" +
"\tstatus: completed\n" +
"\tconclusion: success\n" +
"\ttitle: Check Title\n" +
"\tbody: Check Body");
expect(debugMock).toHaveBeenCalledWith("Called the rest endpoint to create check run");
expect(debugMock).toHaveBeenCalledWith("Check run created successfully.");
});
});
58 changes: 58 additions & 0 deletions src/clients/githubChecksClient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { debug } from "@actions/core";
import { CheckRunStatus } from "../types/checkRunStatus";
import { CheckConclusion } from "../types/checkConclusion";
import { createOctokitClient } from "./octokit";
/**
* Create an issue comment on a PR
* @param owner owner of the repo
* @param repo repo name
* @param name the name of the check run
* @param headSha headSha
* @param status the status of the check
* @param conclusion status of the conclusion
* @param title title of the check run
* @param body the body of the check run
* @returns {Promise<void>} Resolves when the action is complete
* @throws Error when the response indicates the request was unsuccessful.
*/
async function createCheck(
owner: string,
repo: string,
name: string,
headSha: string,
status: CheckRunStatus,
conclusion: CheckConclusion,
title: string,
body: string): Promise<void>
{
const client = await createOctokitClient();

debug(`Going to call the rest endpoint to delete an issue comment with the following details:\n\towner: ${owner}\n\trepo: ${repo}\n\tname: ${name}\n\theadSha: ${headSha}\n\tstatus: ${status}\n\tconclusion: ${conclusion}\n\ttitle: ${title}\n\tbody: ${body}`);
const response = await client.rest.checks.create({
owner,
repo,
name,
head_sha: headSha,
details_url: undefined,
external_id: undefined,
status,
started_at: Date.now(),
conclusion,
completed_at: Date.now(),
output: {
title,
summary: body,
text: body
}
});
debug('Called the rest endpoint to create check run');

if(response.status === 201)
debug('Check run created successfully.');
else
throw new Error(`Failed to create the check run for:\n\towner: ${owner}\n\trepo: ${repo}\n\theadSha: ${headSha}`);
}

export {
createCheck
};

0 comments on commit bd27f93

Please sign in to comment.