Skip to content

Commit

Permalink
Separately implement filter and mapping predicates
Browse files Browse the repository at this point in the history
The predicates are for filtering or mapping repository nodes.
  • Loading branch information
igwejk committed Mar 8, 2024
1 parent e85852e commit 55deda2
Show file tree
Hide file tree
Showing 5 changed files with 229 additions and 6 deletions.
4 changes: 3 additions & 1 deletion src/getRepos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import { collectRepos } from "./utils/collectRepos";

import { getRepositoriesQuery } from "./utils/graphql";

import { Func } from "../types/common";

async function start() {
try {
await collectRepos(paginateQuery, getRepositoriesQuery);
await collectRepos(paginateQuery as Func, getRepositoriesQuery);
} catch (err) {
error(err);
return err;
Expand Down
16 changes: 12 additions & 4 deletions src/utils/collectRepos.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,15 @@ import {
GetGraphQLQueryFunction,
orgsInEnterpriseArray,
response,
usersWriteAdminReposArray,
} from "../../types/common";

import { GraphQlQueryResponseData } from "@octokit/graphql";

import {
whereRepositoryViewerPermissionIsAdmin,
toRepositoryDesiredConfig,
} from "./predicates";

import { getOrganizationFromLocalFile } from "./getOrganizationFromLocalFile";

export const collectRepos = async (
Expand Down Expand Up @@ -38,13 +44,15 @@ export const collectRepos = async (
const repositoriesInOrg = (await func(
res[index].login,
graphQuery,
)) as usersWriteAdminReposArray;
res[index].repos = repositoriesInOrg;
)) as GraphQlQueryResponseData;
res[index].repos = repositoriesInOrg
.filter(whereRepositoryViewerPermissionIsAdmin)
.map(toRepositoryDesiredConfig);
}
inform(`All repos collected. Writing them to file: ${reposFileLocation}`);
await createFile(res, reposFileLocation);

return { status: 200, message: "sucess" };
return { status: 200, message: "success" };
} catch (err) {
error(err);
throw err;
Expand Down
61 changes: 61 additions & 0 deletions src/utils/predicates.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import {
RepositoryDesiredConfig,
GraphQLQueryResponseGetRepos,
} from "../../types/common";

import { getcodeQLLanguage } from "./getcodeQLLanguage";

export function whereRepositoryViewerPermissionIsAdmin(
repositoryNode: GraphQLQueryResponseGetRepos,
): boolean {
return (
repositoryNode.viewerPermission === "ADMIN" ||
// This is the case when viewer is a GitHub App
repositoryNode.viewerPermission === null
);
}

export function whereRepositoryLanguageToCheckIsMatched(
repositoryNode: GraphQLQueryResponseGetRepos,
languageToCheck: string = process.env.LANGUAGE_TO_CHECK as string,
): boolean {
const repositoryPrimaryLanguage =
repositoryNode.primaryLanguage?.name || "no-language";
if (!languageToCheck) {
return true;
}

return (
repositoryPrimaryLanguage.toLowerCase() === languageToCheck.toLowerCase()
);
}

export function whereRepositoryVisibilityIsNotPublic(
{ visibility }: GraphQLQueryResponseGetRepos,
isGHES: boolean = process.env.GHES === "true",
): boolean {
return isGHES || visibility !== "PUBLIC";
}

export function toRepositoryDesiredConfig(
repositoryNode: GraphQLQueryResponseGetRepos,
featureToEnable: string = process.env.ENABLE_ON as string,
isRequireCreateIssue: boolean = process.env.CREATE_ISSUE === "true",
): RepositoryDesiredConfig {
return {
enableDependabot: featureToEnable.includes("dependabot") as boolean,
enableDependabotUpdates: featureToEnable.includes(
"dependabotupdates",
) as boolean,
enableSecretScanning: featureToEnable.includes("secretscanning") as boolean,
enableCodeScanning: featureToEnable.includes("codescanning") as boolean,
enablePushProtection: featureToEnable.includes("pushprotection") as boolean,
enableActions: featureToEnable.includes("actions") as boolean,
primaryLanguage: getcodeQLLanguage(
repositoryNode.primaryLanguage?.name || "",
),
createIssue: isRequireCreateIssue,
repo: repositoryNode.nameWithOwner,
repositoryNode: repositoryNode,
};
}
139 changes: 139 additions & 0 deletions tests/predicates.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import {
toRepositoryDesiredConfig,
whereRepositoryViewerPermissionIsAdmin,
whereRepositoryLanguageToCheckIsMatched,
whereRepositoryVisibilityIsNotPublic,
} from "../src/utils/predicates";
import {
GraphQLQueryResponseGetRepos,
RepositoryDesiredConfig,
} from "../types/common";

describe("whereRepositoryViewerPermissionIsAdmin", () => {
const mockRepositoryNode = Object.create(null, {
nameWithOwner: { value: "TestOwner/TestRepo", enumerable: true },
viewerPermission: { value: "ADMIN", enumerable: true },
primaryLanguage: {
value: Object.create(null, {
name: { value: "JavaScript", enumerable: true },
}),
enumerable: true,
},
}) as GraphQLQueryResponseGetRepos;

it("should return true when viewerPermission is ADMIN", () => {
const result = whereRepositoryViewerPermissionIsAdmin(mockRepositoryNode);
expect(result).toBe(true);
});

it("should return false when viewerPermission is not ADMIN", () => {
const result = whereRepositoryViewerPermissionIsAdmin({
...mockRepositoryNode,
viewerPermission: "READ",
});
expect(result).toBe(false);
});
});

describe("whereRepositoryLanguageToCheckIsMatched", () => {
const mockRepositoryNode = {
nameWithOwner: "TestOwner/TestRepo",
primaryLanguage: { name: "JavaScript" },
} as GraphQLQueryResponseGetRepos;

it("should return true when primary language matches", () => {
process.env.LANGUAGES_TO_CHECK = "JavaScript";
const result = whereRepositoryLanguageToCheckIsMatched(mockRepositoryNode);
expect(result).toBe(true);
});

it("should return false when primary language does not match", () => {
process.env.LANGUAGES_TO_CHECK = "Python";
const result = whereRepositoryLanguageToCheckIsMatched(mockRepositoryNode);
expect(result).toBe(false);
});
});

describe("whereRepositoryVisibilityIsNotPublic", () => {
const mockRepositoryNode = {
nameWithOwner: "TestOwner/TestRepo",
isPrivate: true,
};

it("should return true when repository is private", () => {
const result = whereRepositoryVisibilityIsNotPublic(mockRepositoryNode);
expect(result).toBe(true);
});

it("should return false when repository is public", () => {
const result = whereRepositoryVisibilityIsNotPublic({
...mockRepositoryNode,
isPrivate: false,
});
expect(result).toBe(false);
});
});

describe("toRepositoryDesiredConfig", () => {
const mockRepositoryNode = Object.create(null, {
nameWithOwner: { value: "TestOwner/TestRepo", enumerable: true },
primaryLanguage: {
value: Object.create(null, {
name: { value: "JavaScript", enumerable: true },
}),
enumerable: true,
},
}) as GraphQLQueryResponseGetRepos;

it("should return correct config when all features are enabled", () => {
process.env.ENABLE_ON =
"dependabot,dependabotupdates,secretscanning,codescanning,pushprotection,actions";
process.env.CREATE_ISSUE = "true";

const result: RepositoryDesiredConfig =
toRepositoryDesiredConfig(mockRepositoryNode);
expect(result).toEqual({
enableDependabot: true,
enableDependabotUpdates: true,
enableSecretScanning: true,
enableCodeScanning: true,
enablePushProtection: true,
enableActions: true,
primaryLanguage: "javascript",
createIssue: true,
repo: "TestOwner/TestRepo",
repositoryNode: mockRepositoryNode,
});
});

it("should return correct config when no features are enabled", () => {
process.env.ENABLE_ON = "";
process.env.CREATE_ISSUE = "false";

const result: RepositoryDesiredConfig =
toRepositoryDesiredConfig(mockRepositoryNode);
expect(result).toEqual({
enableDependabot: false,
enableDependabotUpdates: false,
enableSecretScanning: false,
enableCodeScanning: false,
enablePushProtection: false,
enableActions: false,
primaryLanguage: "javascript",
createIssue: false,
repo: "TestOwner/TestRepo",
repositoryNode: mockRepositoryNode,
});
});

it("should handle null primary language", () => {
process.env.ENABLE_ON = "dependabot";
process.env.CREATE_ISSUE = "true";

const result: RepositoryDesiredConfig = toRepositoryDesiredConfig({
...mockRepositoryNode,
primaryLanguage: null,
});
expect(result.primaryLanguage).toEqual("");
});
});
15 changes: 14 additions & 1 deletion types/common/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,20 @@ export type GraphQLQueryResponseGetRepos = {
visibility: string;
primaryLanguage: {
name: string;
};
} | null;
};

export type RepositoryDesiredConfig = {
enableDependabot: boolean;
enableDependabotUpdates: boolean;
enableSecretScanning: boolean;
enableCodeScanning: boolean;
enablePushProtection: boolean;
enableActions: boolean;
primaryLanguage: string;
createIssue: boolean;
repo: string;
repositoryNode: GraphQLQueryResponseGetRepos;
};

export type GraphQLQueryResponseData = GraphQLQueryResponseGetRepos[];
Expand Down

0 comments on commit 55deda2

Please sign in to comment.