Skip to content
This repository has been archived by the owner on Jul 2, 2024. It is now read-only.

EVG-20677 & EVG-20868: Make type.ts validation more robust #2038

Merged
merged 5 commits into from
Sep 18, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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
25 changes: 6 additions & 19 deletions scripts/check-schema-and-codegen/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import fs from "fs";
import { checkSchemaAndCodegenCore } from ".";
import {
canResolveDNS,
checkIsAncestor,
getLatestCommitFromRemote,
} from "./utils";
import { checkIsAncestor, getLatestCommitFromRemote } from "./utils";

jest.mock("fs", () => ({
readFileSync: jest.fn().mockReturnValue(Buffer.from("file-contents")),
Expand All @@ -20,23 +16,22 @@ jest.mock("./utils.ts", () => ({
}));

describe("checkSchemaAndCodegen", () => {
let consoleInfoSpy;
let consoleErrorSpy;
beforeEach(() => {
consoleInfoSpy = jest.spyOn(console, "info").mockImplementation(() => {});
consoleErrorSpy = jest.spyOn(console, "error").mockImplementation(() => {});
(canResolveDNS as jest.Mock).mockResolvedValue(true);
(checkIsAncestor as jest.Mock).mockResolvedValue(true);
(getLatestCommitFromRemote as jest.Mock).mockResolvedValue(
"{getLatestCommitFromRemote()}"
);
});

it("returns 0 when offline", async () => {
(canResolveDNS as jest.Mock).mockResolvedValue(false);
(getLatestCommitFromRemote as jest.Mock).mockRejectedValueOnce(
new Error("TypeError: fetch failed")
);
await expect(checkSchemaAndCodegenCore()).resolves.toBe(0);
expect(consoleInfoSpy).toHaveBeenCalledWith(
"Skipping GQL codegen validation because I can't connect to github.com."
expect(consoleErrorSpy).toHaveBeenCalledWith(
"An error occured during GQL types validation: Error: TypeError: fetch failed"
);
});

Expand Down Expand Up @@ -72,12 +67,4 @@ describe("checkSchemaAndCodegen", () => {
"GQL types validation failed: Your GQL types file ({path.resolve()}) is outdated. Run 'yarn codegen'."
);
});

it("handle error and exit with 0", async () => {
(canResolveDNS as jest.Mock).mockRejectedValue(new Error("Test Error"));
await expect(checkSchemaAndCodegenCore()).resolves.toBe(0);
expect(consoleErrorSpy).toHaveBeenCalledWith(
"An error occured during GQL types validation: Error: Test Error"
);
});
});
9 changes: 0 additions & 9 deletions scripts/check-schema-and-codegen/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import fs from "fs";
import process from "process";
import { generatedFileName as existingTypesFileName } from "../../codegen";
import {
canResolveDNS,
checkIsAncestor,
generateTypes,
getLatestCommitFromRemote,
Expand All @@ -16,14 +15,6 @@ const failCopy = "GQL types validation failed:";
*/
export const checkSchemaAndCodegenCore = async (): Promise<number> => {
try {
// First check to see if all remote GQL commits exist locally.
const hasInternetAccess = await canResolveDNS("github.com");
if (!hasInternetAccess) {
console.info(
"Skipping GQL codegen validation because I can't connect to github.com."
);
return 0;
}
const commit = await getLatestCommitFromRemote();
const hasLatestCommit = await checkIsAncestor(commit);
if (!hasLatestCommit) {
Expand Down
22 changes: 3 additions & 19 deletions scripts/check-schema-and-codegen/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,12 @@ const GQL_DIR = "graphql/schema";
const LOCAL_SCHEMA = "sdlschema";
const REPO = "/repos/evergreen-ci/evergreen";

/**
* Checks if a given domain can be resolved.
* @async
* @param domain - The domain name to check.
* @returns - Resolves to `true` if the domain can be resolved, `false` otherwise.
*/
export const canResolveDNS = (domain: string) =>
new Promise((resolve) => {
dns.lookup(domain, (err) => {
if (err) {
resolve(false);
} else {
resolve(true);
}
});
});

/**
* Get the latest commit that was made to the GQL folder of the remote Evergreen repository.
* @returns A Promise that resolves to the SHA of the latest commit.
* @throws {Error} When failed to fetch commits.
*/
export async function getLatestCommitFromRemote(): Promise<string> {
export const getLatestCommitFromRemote = async (): Promise<string> => {
const url = `${GITHUB_API}${REPO}/commits?path=${GQL_DIR}&sha=main`;
const response = await fetch(url);
if (!response.ok) {
Expand All @@ -46,7 +29,7 @@ export async function getLatestCommitFromRemote(): Promise<string> {
return commits[0].sha;
}
throw new Error(`No commits found for this path: ${url}`);
}
};

/**
* Check if the local Evergreen repo contains a given commit.
Expand All @@ -64,6 +47,7 @@ export const checkIsAncestor = async (commit: string): Promise<boolean> => {
return true;
} catch (error) {
process.chdir(originalDir);
// Error status 1 and 128 means that the commit is not an anecestor and the user must fetch.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I discussed this offline but would love to see a reference to this here. Just so its easy to differentiate between what 1 and 128 means.

if (error.status === 1 || error.status === 128) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be helpful to comment on what these statuses represent or extract them into named constants.

return false;
}
Expand Down