From 0d7f3bf00a8cef9f915e3abd4fe7b29d59858d5b Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 01:23:36 -0300 Subject: [PATCH 01/10] move inputs to the configuration file --- action.yml | 9 - src/constants.ts | 6 - src/core.ts | 115 +++++------ src/main.ts | 6 +- src/types.ts | 7 + src/validation.ts | 6 + test/batch/configuration.ts | 153 ++++----------- test/batch/rules.ts | 371 +++++++++++++----------------------- test/constants.ts | 6 + 9 files changed, 234 insertions(+), 445 deletions(-) diff --git a/action.yml b/action.yml index 4ee376a..f977f35 100644 --- a/action.yml +++ b/action.yml @@ -8,15 +8,6 @@ inputs: token: required: true description: 'Repository token' - locks-review-team: - required: true - description: 'The team which will be asked for review if locks are touched' - team-leads-team: - required: true - description: 'The team leads which will be asked for review if locks are touched' - action-review-team: - required: true - description: "The team which will be asked for review if the action's files are changed" runs: using: 'node16' main: 'dist/index.js' diff --git a/src/constants.ts b/src/constants.ts index f492d0e..ecd4405 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -32,9 +32,3 @@ export const rulesConfigurations: RulesConfigurations = { invalidFields: ["min_approvals", "teams", "users", "all", "any"], }, } - -export const variableNameToActionInputName = { - teamLeadsTeam: "team-leads-team", - locksReviewTeam: "locks-review-team", - actionReviewTeam: "action-review-team", -} diff --git a/src/core.ts b/src/core.ts index b48e476..69c5bde 100644 --- a/src/core.ts +++ b/src/core.ts @@ -9,7 +9,6 @@ import { configFilePath, maxGithubApiFilesPerPage, maxGithubApiTeamMembersPerPage, - variableNameToActionInputName, } from "./constants" import { LoggerInterface } from "./logger" import { @@ -95,35 +94,66 @@ export const runChecks = async function ( pr: PR, octokit: Octokit, logger: LoggerInterface, - { - actionReviewTeam, - locksReviewTeam, - teamLeadsTeam, - }: { - actionReviewTeam: string - locksReviewTeam: string - teamLeadsTeam: string - }, ) { - if (locksReviewTeam.length === 0) { + const configFileResponse = await octokit.rest.repos.getContent({ + owner: pr.base.repo.owner.login, + repo: pr.base.repo.name, + path: configFilePath, + }) + if (configFileResponse.status !== 200) { logger.failure( - `Locks Review Team (action input: ${variableNameToActionInputName.locksReviewTeam}) should be provided`, + `Failed to get the contents of ${configFilePath} (code ${configFileResponse.status})`, ) + logger.log(configFileResponse.data) return commitStateFailure } - if (teamLeadsTeam.length === 0) { + const { data } = configFileResponse + if (typeof data !== "object" || data === null) { logger.failure( - `Team Leads Team (action input: ${variableNameToActionInputName.teamLeadsTeam}) should be provided`, + `Data response for ${configFilePath} had unexpected type (expected object)`, ) + logger.log(configFileResponse.data) return commitStateFailure } - if (actionReviewTeam.length === 0) { + if (!("content" in data)) { logger.failure( - `Action Review Team (action input: ${variableNameToActionInputName.actionReviewTeam}) should be provided`, + `Did not find "content" key in the response for ${configFilePath}`, ) + logger.log(configFileResponse.data) + return commitStateFailure + } + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment + const { content: configFileContentsEnconded } = data + if (typeof configFileContentsEnconded !== "string") { + logger.failure( + `Content response for ${configFilePath} had unexpected type (expected string)`, + ) + logger.log(configFileResponse.data) + return commitStateFailure + } + + const configFileContents = Buffer.from( + configFileContentsEnconded, + "base64", + ).toString("utf-8") + const configValidationResult = configurationSchema.validate( + YAML.parse(configFileContents), + ) + if (configValidationResult.error) { + logger.failure("Configuration file is invalid") + logger.log(configValidationResult.error) return commitStateFailure } + const { + inputs: { + "locks-review-team": locksReviewTeam, + "team-leads-team": teamLeadsTeam, + "action-review-team": actionReviewTeam, + }, + rules, + } = configValidationResult.value + // Set up a teams cache so that teams used multiple times don't have to be // requested more than once const teamsCache: TeamsCache = new Map() @@ -218,57 +248,6 @@ export const runChecks = async function ( } } - const configFileResponse = await octokit.rest.repos.getContent({ - owner: pr.base.repo.owner.login, - repo: pr.base.repo.name, - path: configFilePath, - }) - if (configFileResponse.status !== 200) { - logger.failure( - `Failed to get the contents of ${configFilePath} (code ${configFileResponse.status})`, - ) - logger.log(configFileResponse.data) - return commitStateFailure - } - const { data } = configFileResponse - if (typeof data !== "object" || data === null) { - logger.failure( - `Data response for ${configFilePath} had unexpected type (expected object)`, - ) - logger.log(configFileResponse.data) - return commitStateFailure - } - if (!("content" in data)) { - logger.failure( - `Did not find "content" key in the response for ${configFilePath}`, - ) - logger.log(configFileResponse.data) - return commitStateFailure - } - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { content: configFileContentsEnconded } = data - if (typeof configFileContentsEnconded !== "string") { - logger.failure( - `Content response for ${configFilePath} had unexpected type (expected string)`, - ) - logger.log(configFileResponse.data) - return commitStateFailure - } - - const configFileContents = Buffer.from( - configFileContentsEnconded, - "base64", - ).toString("utf-8") - const validationResult = configurationSchema.validate( - YAML.parse(configFileContents), - ) - if (validationResult.error) { - logger.failure("Configuration file is invalid") - logger.log(validationResult.error) - return commitStateFailure - } - const config = validationResult.value - const processComplexRule = async function ( id: MatchedRule["id"], name: string, @@ -327,7 +306,7 @@ export const runChecks = async function ( } } - for (const rule of config.rules) { + for (const rule of rules) { const includeCondition = (function () { switch (typeof rule.condition) { case "string": { diff --git a/src/main.ts b/src/main.ts index 5c3de31..561b0ab 100644 --- a/src/main.ts +++ b/src/main.ts @@ -103,11 +103,7 @@ const main = function () { process.exit(0) } - runChecks(pr, octokit, logger, { - locksReviewTeam: getInput("locks-review-team"), - teamLeadsTeam: getInput("team-leads-team"), - actionReviewTeam: getInput("action-review-team"), - }) + runChecks(pr, octokit, logger) .then(function (state) { finish(state) }) diff --git a/src/types.ts b/src/types.ts index 207d689..b5399d6 100644 --- a/src/types.ts +++ b/src/types.ts @@ -84,6 +84,7 @@ export type RulesConfigurations = { export type Configuration = { rules: Rule[] + inputs: Inputs } export type RuleUserInfo = { @@ -117,3 +118,9 @@ export class RuleFailure { public usersToAskForReview: Map, ) {} } + +export type Inputs = { + "locks-review-team": string + "team-leads-team": string + "action-review-team": string +} diff --git a/src/validation.ts b/src/validation.ts index c838d1e..2150e39 100644 --- a/src/validation.ts +++ b/src/validation.ts @@ -5,6 +5,7 @@ import { AndRule, BasicRule, Configuration, + Inputs, OrRule, RuleCriteria, } from "./types" @@ -77,5 +78,10 @@ const ruleSchema = Joi.alternatives([ ]) export const configurationSchema = Joi.object().keys({ + inputs: Joi.object().keys({ + "locks-review-team": Joi.string().required(), + "team-leads-team": Joi.string().required(), + "action-review-team": Joi.string().required(), + }), rules: Joi.array().items(ruleSchema).required(), }) diff --git a/test/batch/configuration.ts b/test/batch/configuration.ts index 4ecbddb..f4f6725 100644 --- a/test/batch/configuration.ts +++ b/test/batch/configuration.ts @@ -8,6 +8,7 @@ import { condition, configFileContentsApiPath, githubApi, + inputs, prApiPath, rulesExamples, team, @@ -16,11 +17,19 @@ import { } from "test/constants" import Logger from "test/logger" -import { - rulesConfigurations, - variableNameToActionInputName, -} from "src/constants" +import { rulesConfigurations } from "src/constants" import { runChecks } from "src/core" +import { Rule } from "src/types" + +const setup = function ({ rules }: { rules?: Array> }) { + nock(githubApi) + .get(configFileContentsApiPath) + .reply(200, { + content: Buffer.from(YAML.stringify({ inputs, rules })).toString( + "base64", + ), + }) +} describe("Configuration", function () { let logger: Logger @@ -41,80 +50,6 @@ describe("Configuration", function () { .reply(200, [{ filename: condition }]) }) - for (const missingField of [ - "name", - "condition", - "check_type", - "min_approvals", - ]) { - it(`Configuration is invalid if ${missingField} is missing`, async function () { - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - ${missingField === "name" ? "" : `name: condition`} - ${missingField === "condition" ? "" : `condition: condition`} - ${missingField === "check_type" ? "" : `check_type: diff`} - ${missingField === "min_approvals" ? "" : `min_approvals: 1`} - `, - ).toString("base64"), - }) - - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe("failure") - - expect(logHistory).toMatchSnapshot() - }) - } - - it("Configuration is invalid if min_approvals is less than 1", async function () { - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: diff - min_approvals: 0 - `, - ).toString("base64"), - }) - - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe("failure") - - expect(logHistory).toMatchSnapshot() - }) - - for (const name in variableNameToActionInputName) { - it(`Configuration is invalid if ${name} is empty or missing`, async function () { - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - [name]: "", - }), - ).toBe("failure") - - expect(logHistory).toMatchSnapshot() - }) - } - for (const { kind, invalidFields } of Object.values(rulesConfigurations)) { const goodRule = rulesExamples[kind] @@ -143,21 +78,9 @@ describe("Configuration", function () { it(`Rule kind ${kind} does not allow invalid field ${invalidField}`, async function () { const badRule = { ...goodRule, [invalidField]: invalidFieldValidValue } - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from(YAML.stringify({ rules: [badRule] })).toString( - "base64", - ), - }) + setup({ rules: [badRule] }) - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe("failure") + expect(await runChecks(basePR, octokit, logger)).toBe("failure") expect(logHistory).toMatchSnapshot() }) @@ -170,36 +93,24 @@ describe("Configuration", function () { [null, "null"], ]) { it(`min_approvals is invalid for ${kind} if it is ${description}`, async function () { - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - YAML.stringify({ - rules: [ - { - ...exampleRule, - ...("min_approvals" in exampleRule - ? { min_approvals: invalidValue } - : "all" in exampleRule - ? { all: [{ min_approvals: invalidValue }] } - : "any" in exampleRule - ? { any: [{ min_approvals: invalidValue }] } - : "all_distinct" in exampleRule - ? { all_distinct: [{ min_approvals: invalidValue }] } - : {}), - }, - ], - }), - ).toString("base64"), - }) + setup({ + rules: [ + { + ...exampleRule, + ...("min_approvals" in exampleRule + ? { min_approvals: invalidValue } + : "all" in exampleRule + ? { all: [{ min_approvals: invalidValue }] } + : "any" in exampleRule + ? { any: [{ min_approvals: invalidValue }] } + : "all_distinct" in exampleRule + ? { all_distinct: [{ min_approvals: invalidValue }] } + : {}), + }, + ], + }) - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe("failure") + expect(await runChecks(basePR, octokit, logger)).toBe("failure") expect(logHistory).toMatchSnapshot() }) diff --git a/test/batch/rules.ts b/test/batch/rules.ts index 2cba1fb..f718497 100644 --- a/test/batch/rules.ts +++ b/test/batch/rules.ts @@ -9,6 +9,7 @@ import { configFileContentsApiPath, coworkers, githubApi, + inputs, org, prApiPath, requestedReviewersApiPath, @@ -25,7 +26,7 @@ import { maxGithubApiTeamMembersPerPage, } from "src/constants" import { runChecks } from "src/core" -import { Rule } from "src/types" +import { AndRule, OrRule, Rule } from "src/types" describe("Rules", function () { let logger: Logger @@ -63,6 +64,7 @@ describe("Rules", function () { diff ??= condition teams ??= [{ name: team, members: users }] changedFiles ??= [condition] + rules ??= [] nock(githubApi) .get(reviewsApiPath) @@ -111,35 +113,28 @@ describe("Rules", function () { .matchHeader("accept", "application/vnd.github.v3.diff") .reply(200, diff) - if (rules !== undefined) { - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from(YAML.stringify({ rules })).toString("base64"), - }) - } + nock(githubApi) + .get(configFileContentsApiPath) + .reply(200, { + content: Buffer.from(YAML.stringify({ inputs, rules })).toString( + "base64", + ), + }) } for (const checkType of ["diff", "changed_files"] as const) { it(`${scenario} on rule including only users for ${checkType}`, async function () { - setup() - - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: ${checkType} - min_approvals: ${coworkers.length} - users: - - ${coworkers[0]} - - ${coworkers[1]} - `, - ).toString("base64"), - }) + setup({ + rules: [ + { + name: condition, + condition, + check_type: checkType, + min_approvals: coworkers.length, + users: [coworkers[0], coworkers[1]], + }, + ], + }) switch (scenario) { case "Has no approval": { @@ -168,35 +163,25 @@ describe("Rules", function () { } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) it(`${scenario} on rule including only teams for ${checkType}`, async function () { - setup() - - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: ${checkType} - min_approvals: ${coworkers.length} - teams: - - ${team} - `, - ).toString("base64"), - }) + setup({ + rules: [ + { + name: condition, + condition, + check_type: checkType, + min_approvals: coworkers.length, + teams: [team], + }, + ], + }) if (scenario !== "Approved") { nock(githubApi) @@ -210,43 +195,31 @@ describe("Rules", function () { .reply(201) } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) it(`${scenario} on rule including both teams and users for ${checkType}`, async function () { - setup( - scenario === "Is missing approval" - ? { users: coworkers.concat(userCoworker3) } - : undefined, - ) - const userAskedIndividually = coworkers[1] - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: ${checkType} - min_approvals: ${coworkers.length} - users: - - ${userAskedIndividually} - teams: - - ${team} - `, - ).toString("base64"), - }) + setup({ + rules: [ + { + name: condition, + condition, + check_type: checkType, + min_approvals: coworkers.length, + users: [userAskedIndividually], + teams: [team], + }, + ], + ...(scenario === "Is missing approval" + ? { users: coworkers.concat(userCoworker3) } + : {}), + }) if (scenario !== "Approved") { nock(githubApi) @@ -268,37 +241,27 @@ describe("Rules", function () { .reply(201) } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) it(`${scenario} on rule not specifying users or teams`, async function () { - setup( - scenario === "Is missing approval" + setup({ + rules: [ + { + name: condition, + condition, + check_type: checkType, + min_approvals: coworkers.length, + }, + ], + ...(scenario === "Is missing approval" ? { users: coworkers.concat(userCoworker3) } - : undefined, - ) - - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: ${checkType} - min_approvals: ${coworkers.length} - `, - ).toString("base64"), - }) + : {}), + }) if (scenario !== "Approved") { nock(githubApi) @@ -312,46 +275,36 @@ describe("Rules", function () { .reply(201) } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) for (const [ruleKind, ruleField] of [ ["AndRule", "all"], + ["AndDistinctRule", "all_distinct"], ["OrRule", "any"], - ]) { + ] as const) { it(`Rule kind ${ruleKind}: ${scenario} specifying only users for ${checkType}`, async function () { - setup() - - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: ${checkType} - ${ruleField}: - - min_approvals: 1 - users: - - ${coworkers[0]} - - min_approvals: 1 - users: - - ${coworkers[1]} - `, - ).toString("base64"), - }) + setup({ + rules: [ + { + name: condition, + condition, + check_type: checkType, + [ruleField]: [ + { min_approvals: 1, users: [coworkers[0]] }, + { min_approvals: 1, users: [coworkers[1]] }, + ], + } as Rule, + ], + }) let expected: "success" | "failure" switch (ruleKind) { + case "AndDistinctRule": case "AndRule": { if (scenario !== "Approved") { nock(githubApi) @@ -386,17 +339,12 @@ describe("Rules", function () { break } default: { + const exhaustivenessCheck: never = ruleKind throw new Error(`Unhandled rule kind ${ruleKind}`) } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(expected) + expect(await runChecks(basePR, octokit, logger)).toBe(expected) expect(logHistory).toMatchSnapshot() }) @@ -416,30 +364,22 @@ describe("Rules", function () { }, { name: team2, members: [coworkers[1]] }, ], + rules: [ + { + name: condition, + condition, + check_type: checkType, + [ruleField]: [ + { min_approvals: 1, teams: [team1] }, + { min_approvals: 1, teams: [team2] }, + ], + } as Rule, + ], }) - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: ${checkType} - ${ruleField}: - - min_approvals: 1 - teams: - - ${team1} - - min_approvals: 1 - teams: - - ${team2} - `, - ).toString("base64"), - }) - let expectedCheckOutcome: "success" | "failure" switch (ruleKind) { + case "AndDistinctRule": case "AndRule": { if (scenario !== "Approved") { nock(githubApi) @@ -479,17 +419,14 @@ describe("Rules", function () { break } default: { + const exhaustivenessCheck: never = ruleKind throw new Error(`Unhandled rule kind ${ruleKind}`) } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(expectedCheckOutcome) + expect(await runChecks(basePR, octokit, logger)).toBe( + expectedCheckOutcome, + ) expect(logHistory).toMatchSnapshot() }) @@ -510,33 +447,23 @@ describe("Rules", function () { }, { name: team2, members: [coworkers[1]] }, ], + rules: [ + { + name: condition, + condition, + check_type: checkType, + [ruleField]: [ + { min_approvals: 1, teams: [team1] }, + { min_approvals: 1, teams: [team2] }, + { min_approvals: 1, users: [userCoworker3] }, + ], + } as Rule, + ], }) - nock(githubApi) - .get(configFileContentsApiPath) - .reply(200, { - content: Buffer.from( - ` - rules: - - name: ${condition} - condition: ${condition} - check_type: ${checkType} - ${ruleField}: - - min_approvals: 1 - teams: - - ${team1} - - min_approvals: 1 - teams: - - ${team2} - - min_approvals: 1 - users: - - ${userCoworker3} - `, - ).toString("base64"), - }) - let expectedCheckOutcome: "success" | "failure" switch (ruleKind) { + case "AndDistinctRule": case "AndRule": { if (scenario !== "Approved") { nock(githubApi) @@ -576,17 +503,14 @@ describe("Rules", function () { break } default: { + const exhaustivenessCheck: never = ruleKind throw new Error(`Unhandled rule kind ${ruleKind}`) } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(expectedCheckOutcome) + expect(await runChecks(basePR, octokit, logger)).toBe( + expectedCheckOutcome, + ) expect(logHistory).toMatchSnapshot() }) @@ -627,13 +551,7 @@ describe("Rules", function () { } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe( + expect(await runChecks(basePR, octokit, logger)).toBe( scenario === "Approved" || description === "condition: exclude" || description === "condition: include & exclude" @@ -654,7 +572,6 @@ describe("Rules", function () { { name: team, members: [coworkers[0]] }, { name: team2, members: [coworkers[1]] }, ], - rules: [], }) switch (scenario) { @@ -674,13 +591,9 @@ describe("Rules", function () { } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) @@ -692,7 +605,6 @@ describe("Rules", function () { { name: team, members: [coworkers[0]] }, { name: team2, members: [coworkers[1]] }, ], - rules: [], }) switch (scenario) { @@ -712,13 +624,9 @@ describe("Rules", function () { } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) @@ -727,7 +635,6 @@ describe("Rules", function () { for (const actionReviewFile of actionReviewTeamFiles) { it(`${scenario} when ${actionReviewFile} is changed`, async function () { setup({ - rules: [], changedFiles: [actionReviewFile], teams: [{ name: team3, members: [coworkers[1]] }], }) @@ -748,13 +655,9 @@ describe("Rules", function () { } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) @@ -796,13 +699,9 @@ describe("Rules", function () { } } - expect( - await runChecks(basePR, octokit, logger, { - locksReviewTeam: team, - teamLeadsTeam: team2, - actionReviewTeam: team3, - }), - ).toBe(scenario === "Approved" ? "success" : "failure") + expect(await runChecks(basePR, octokit, logger)).toBe( + scenario === "Approved" ? "success" : "failure", + ) expect(logHistory).toMatchSnapshot() }) diff --git a/test/constants.ts b/test/constants.ts index 00235a4..033315d 100644 --- a/test/constants.ts +++ b/test/constants.ts @@ -8,6 +8,12 @@ export const user = "user" export const team = "team" export const team2 = "team2" export const team3 = "team3" +export const inputs = { + "locks-review-team": team, + "team-leads-team": team2, + "action-review-team": team3, +} + export const userCoworker = "userCoworker" export const userCoworker2 = "userCoworker2" export const userCoworker3 = "userCoworker3" From 8d176b585ed20eeaf2730270366c0ff2a341b370 Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 01:24:02 -0300 Subject: [PATCH 02/10] update snapshots --- test/batch/configuration.ts.snap | 368 +++++++++++++++++-------------- test/batch/rules.ts.snap | 230 +++++++++++++++++++ 2 files changed, 438 insertions(+), 160 deletions(-) diff --git a/test/batch/configuration.ts.snap b/test/batch/configuration.ts.snap index 4286434..3519050 100644 --- a/test/batch/configuration.ts.snap +++ b/test/batch/configuration.ts.snap @@ -1,119 +1,17 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`Configuration Configuration is invalid if actionReviewTeam is empty or missing 1`] = ` -Array [ - "ERROR: Action Review Team (action input: action-review-team) should be provided", -] -`; - -exports[`Configuration Configuration is invalid if check_type is missing 1`] = ` -Array [ - "Changed files Set(1) { 'condition' }", - "ERROR: Configuration file is invalid", - "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, - details: [ - { - message: '\\"rules[0]\\" does not match any of the allowed types', - path: [Array], - type: 'alternatives.match', - context: [Object] - } - ] -}", -] -`; - -exports[`Configuration Configuration is invalid if condition is missing 1`] = ` -Array [ - "Changed files Set(1) { 'condition' }", - "ERROR: Configuration file is invalid", - "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, - details: [ - { - message: '\\"rules[0]\\" does not match any of the allowed types', - path: [Array], - type: 'alternatives.match', - context: [Object] - } - ] -}", -] -`; - -exports[`Configuration Configuration is invalid if locksReviewTeam is empty or missing 1`] = ` -Array [ - "ERROR: Locks Review Team (action input: locks-review-team) should be provided", -] -`; - -exports[`Configuration Configuration is invalid if min_approvals is less than 1 1`] = ` -Array [ - "Changed files Set(1) { 'condition' }", - "ERROR: Configuration file is invalid", - "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, - details: [ - { - message: '\\"rules[0]\\" does not match any of the allowed types', - path: [Array], - type: 'alternatives.match', - context: [Object] - } - ] -}", -] -`; - -exports[`Configuration Configuration is invalid if min_approvals is missing 1`] = ` -Array [ - "Changed files Set(1) { 'condition' }", - "ERROR: Configuration file is invalid", - "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, - details: [ - { - message: '\\"rules[0]\\" does not match any of the allowed types', - path: [Array], - type: 'alternatives.match', - context: [Object] - } - ] -}", -] -`; - -exports[`Configuration Configuration is invalid if name is missing 1`] = ` -Array [ - "Changed files Set(1) { 'condition' }", - "ERROR: Configuration file is invalid", - "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, - details: [ - { - message: '\\"rules[0]\\" does not match any of the allowed types', - path: [Array], - type: 'alternatives.match', - context: [Object] - } - ] -}", -] -`; - -exports[`Configuration Configuration is invalid if teamLeadsTeam is empty or missing 1`] = ` -Array [ - "ERROR: Team Leads Team (action input: team-leads-team) should be provided", -] -`; - exports[`Configuration Rule kind AndDistinctRule does not allow invalid field all 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -128,10 +26,16 @@ Array [ exports[`Configuration Rule kind AndDistinctRule does not allow invalid field any 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -146,10 +50,16 @@ Array [ exports[`Configuration Rule kind AndDistinctRule does not allow invalid field min_approvals 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -164,10 +74,16 @@ Array [ exports[`Configuration Rule kind AndDistinctRule does not allow invalid field teams 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -182,10 +98,16 @@ Array [ exports[`Configuration Rule kind AndDistinctRule does not allow invalid field users 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -200,10 +122,16 @@ Array [ exports[`Configuration Rule kind AndRule does not allow invalid field all_distinct 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -218,10 +146,16 @@ Array [ exports[`Configuration Rule kind AndRule does not allow invalid field any 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -236,10 +170,16 @@ Array [ exports[`Configuration Rule kind AndRule does not allow invalid field min_approvals 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -254,10 +194,16 @@ Array [ exports[`Configuration Rule kind AndRule does not allow invalid field teams 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -272,10 +218,16 @@ Array [ exports[`Configuration Rule kind AndRule does not allow invalid field users 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -290,10 +242,16 @@ Array [ exports[`Configuration Rule kind BasicRule does not allow invalid field all 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -308,10 +266,16 @@ Array [ exports[`Configuration Rule kind BasicRule does not allow invalid field all_distinct 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -326,10 +290,16 @@ Array [ exports[`Configuration Rule kind BasicRule does not allow invalid field any 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -344,10 +314,16 @@ Array [ exports[`Configuration Rule kind OrRule does not allow invalid field all 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -362,10 +338,16 @@ Array [ exports[`Configuration Rule kind OrRule does not allow invalid field all_distinct 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -380,10 +362,16 @@ Array [ exports[`Configuration Rule kind OrRule does not allow invalid field min_approvals 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -398,10 +386,16 @@ Array [ exports[`Configuration Rule kind OrRule does not allow invalid field teams 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -416,10 +410,16 @@ Array [ exports[`Configuration Rule kind OrRule does not allow invalid field users 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -434,10 +434,16 @@ Array [ exports[`Configuration min_approvals is invalid for AndDistinctRule if it is less than 1 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -452,10 +458,16 @@ Array [ exports[`Configuration min_approvals is invalid for AndDistinctRule if it is null 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -470,10 +482,16 @@ Array [ exports[`Configuration min_approvals is invalid for AndRule if it is less than 1 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -488,10 +506,16 @@ Array [ exports[`Configuration min_approvals is invalid for AndRule if it is null 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -506,10 +530,16 @@ Array [ exports[`Configuration min_approvals is invalid for BasicRule if it is less than 1 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -524,10 +554,16 @@ Array [ exports[`Configuration min_approvals is invalid for BasicRule if it is null 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -542,10 +578,16 @@ Array [ exports[`Configuration min_approvals is invalid for OrRule if it is less than 1 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', @@ -560,10 +602,16 @@ Array [ exports[`Configuration min_approvals is invalid for OrRule if it is null 1`] = ` Array [ - "Changed files Set(1) { 'condition' }", "ERROR: Configuration file is invalid", "[Error [ValidationError]: \\"rules[0]\\" does not match any of the allowed types] { - _original: { rules: [ [Object] ] }, + _original: { + inputs: { + 'locks-review-team': 'team', + 'team-leads-team': 'team2', + 'action-review-team': 'team3' + }, + rules: [ [Object] ] + }, details: [ { message: '\\"rules[0]\\" does not match any of the allowed types', diff --git a/test/batch/rules.ts.snap b/test/batch/rules.ts.snap index 3ec979f..c87fd4c 100644 --- a/test/batch/rules.ts.snap +++ b/test/batch/rules.ts.snap @@ -692,6 +692,236 @@ Array [ ] `; +exports[`Rules Rule kind AndDistinctRule: Approved specifying both teams and users for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { + { id: 0, user: 'userCoworker', isApproval: true }, + { id: 1, user: 'userCoworker2', isApproval: true }, + { id: 2, user: 'userCoworker3', isApproval: true } +}", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Approved specifying both teams and users for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { + { id: 0, user: 'userCoworker', isApproval: true }, + { id: 1, user: 'userCoworker2', isApproval: true }, + { id: 2, user: 'userCoworker3', isApproval: true } +}", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Approved specifying only teams for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { + { id: 0, user: 'userCoworker', isApproval: true }, + { id: 1, user: 'userCoworker2', isApproval: true } +}", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Approved specifying only teams for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { + { id: 0, user: 'userCoworker', isApproval: true }, + { id: 1, user: 'userCoworker2', isApproval: true } +}", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Approved specifying only users for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { + { id: 0, user: 'userCoworker', isApproval: true }, + { id: 1, user: 'userCoworker2', isApproval: true } +}", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Approved specifying only users for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { + { id: 0, user: 'userCoworker', isApproval: true }, + { id: 1, user: 'userCoworker2', isApproval: true } +}", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Has no approval specifying both teams and users for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { }", + "usersToAskForReview Map(2) { + 'userCoworker3' => { teams: null }, + 'userCoworker2' => { teams: Set(2) { 'team1', 'team2' } } +}", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 3 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 0 and at index 1 and at index 2 failed. The following users have not approved yet: userCoworker3, userCoworker2 (teams: team1,team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Has no approval specifying both teams and users for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { }", + "usersToAskForReview Map(2) { + 'userCoworker3' => { teams: null }, + 'userCoworker2' => { teams: Set(2) { 'team1', 'team2' } } +}", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 3 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 0 and at index 1 and at index 2 failed. The following users have not approved yet: userCoworker3, userCoworker2 (teams: team1,team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Has no approval specifying only teams for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { }", + "usersToAskForReview Map(1) { 'userCoworker2' => { teams: Set(2) { 'team1', 'team2' } } }", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 0 and at index 1 failed. The following users have not approved yet: userCoworker2 (teams: team1,team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Has no approval specifying only teams for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { }", + "usersToAskForReview Map(1) { 'userCoworker2' => { teams: Set(2) { 'team1', 'team2' } } }", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 0 and at index 1 failed. The following users have not approved yet: userCoworker2 (teams: team1,team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Has no approval specifying only users for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { }", + "usersToAskForReview Map(2) { + 'userCoworker' => { teams: null }, + 'userCoworker2' => { teams: null } +}", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 0 and at index 1 failed. The following users have not approved yet: userCoworker, userCoworker2.", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Has no approval specifying only users for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { }", + "usersToAskForReview Map(2) { + 'userCoworker' => { teams: null }, + 'userCoworker2' => { teams: null } +}", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 0 and at index 1 failed. The following users have not approved yet: userCoworker, userCoworker2.", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Is missing approval specifying both teams and users for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { { id: 1, user: 'userCoworker', isApproval: true } }", + "usersToAskForReview Map(2) { + 'userCoworker3' => { teams: null }, + 'userCoworker2' => { teams: Set(1) { 'team2' } } +}", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 3 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 1 and at index 2 failed. The following users have not approved yet: userCoworker3, userCoworker2 (team: team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Is missing approval specifying both teams and users for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { { id: 1, user: 'userCoworker', isApproval: true } }", + "usersToAskForReview Map(2) { + 'userCoworker3' => { teams: null }, + 'userCoworker2' => { teams: Set(1) { 'team2' } } +}", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 3 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subconditions at index 1 and at index 2 failed. The following users have not approved yet: userCoworker3, userCoworker2 (team: team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Is missing approval specifying only teams for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { { id: 1, user: 'userCoworker', isApproval: true } }", + "usersToAskForReview Map(1) { 'userCoworker2' => { teams: Set(1) { 'team2' } } }", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subcondition at index 1 failed. The following users have not approved yet: userCoworker2 (team: team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Is missing approval specifying only teams for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { { id: 1, user: 'userCoworker', isApproval: true } }", + "usersToAskForReview Map(1) { 'userCoworker2' => { teams: Set(1) { 'team2' } } }", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subcondition at index 1 failed. The following users have not approved yet: userCoworker2 (team: team2).", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Is missing approval specifying only users for changed_files 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" for the file condition", + "latestReviews [Map Iterator] { { id: 1, user: 'userCoworker', isApproval: true } }", + "usersToAskForReview Map(1) { 'userCoworker2' => { teams: null } }", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subcondition at index 1 failed. The following users have not approved yet: userCoworker2.", + "", +] +`; + +exports[`Rules Rule kind AndDistinctRule: Is missing approval specifying only users for diff 1`] = ` +Array [ + "Changed files Set(1) { 'condition' }", + "Matched expression \\"condition\\" of rule \\"condition\\" on diff", + "latestReviews [Map Iterator] { { id: 1, user: 'userCoworker', isApproval: true } }", + "usersToAskForReview Map(1) { 'userCoworker2' => { teams: null } }", + "ERROR: The following problems were found:", + "Rule \\"condition\\" needs in total 2 DISTINCT approvals, meaning users whose approvals counted towards one criterion are excluded from other criteria. For example: even if a user belongs multiple teams, their approval will only count towards one of them; or even if a user is referenced in multiple subconditions, their approval will only count towards one subcondition. Subcondition at index 1 failed. The following users have not approved yet: userCoworker2.", + "", +] +`; + exports[`Rules Rule kind AndRule: Approved specifying both teams and users for changed_files 1`] = ` Array [ "Changed files Set(1) { 'condition' }", From f5e1d23cca167b3ee84e7587f95395eae47e1766 Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 01:24:17 -0300 Subject: [PATCH 03/10] update README --- README.md | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/README.md b/README.md index e8002fe..ee3dba4 100644 --- a/README.md +++ b/README.md @@ -49,7 +49,6 @@ This action has the following non-configurable built-in checks: - If the action's files are changed, 1 approval from [action-review-team](#workflow-configuration) is required - - `.github/workflows/pr-custom-review.yml` - `.github/pr-custom-review.yml` Customizable rules should be enabled through [configuration](#action-configuration). @@ -225,9 +224,7 @@ field. ### Workflow configuration -The workflow configuration should be placed in -`.github/workflows/pr-custom-review.yml` (related to -[built-in checks](#built-in-checks)). +The workflow configuration should be placed in `.github/workflows`. ```yaml name: PR Custom Review Status # The PR status will be created with this name. @@ -256,19 +253,6 @@ jobs: # - `workflow` for being able to request the workflow's job # information; used to track lines in the job's output token: ${{ secrets.REVIEWS_TOKEN }} - - # locks-review-team defines the team which will handle the "locks - # touched" built-in rule. We recommend protecting this input with - # "🔒" so that it won't be changed unless someone from - # locks-review-team approves it. - # 🔒 PROTECTED: Changes to locks-review-team should be approved by custom-locks-team - locks-review-team: custom-locks-team - - # The second team which will handle the "locks touched" built-in rule. - team-leads-team: my-custom-leads-team - - # The team which will handle the changes to the action's configuration. - action-review-team: my-action-review-team ``` ### GitHub repository configuration @@ -389,7 +373,6 @@ installed. 5. Add the [workflow configuration](#workflow-configuration), as demonstrated in - - Team inputs should use the teams created on Step 1 - `token` input should use the Personal Access Token generated on Step 2 6. Trigger one of the events defined in the From f58a361001f676a4af5a660a891c0f1ec73c24bd Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 01:27:21 -0300 Subject: [PATCH 04/10] fix lints --- test/batch/configuration.ts | 4 ---- test/batch/rules.ts | 8 ++++---- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/test/batch/configuration.ts b/test/batch/configuration.ts index f4f6725..ff04160 100644 --- a/test/batch/configuration.ts +++ b/test/batch/configuration.ts @@ -11,15 +11,11 @@ import { inputs, prApiPath, rulesExamples, - team, - team2, - team3, } from "test/constants" import Logger from "test/logger" import { rulesConfigurations } from "src/constants" import { runChecks } from "src/core" -import { Rule } from "src/types" const setup = function ({ rules }: { rules?: Array> }) { nock(githubApi) diff --git a/test/batch/rules.ts b/test/batch/rules.ts index f718497..d748d19 100644 --- a/test/batch/rules.ts +++ b/test/batch/rules.ts @@ -26,7 +26,7 @@ import { maxGithubApiTeamMembersPerPage, } from "src/constants" import { runChecks } from "src/core" -import { AndRule, OrRule, Rule } from "src/types" +import { Rule } from "src/types" describe("Rules", function () { let logger: Logger @@ -340,7 +340,7 @@ describe("Rules", function () { } default: { const exhaustivenessCheck: never = ruleKind - throw new Error(`Unhandled rule kind ${ruleKind}`) + throw new Error(`Unhandled rule kind ${exhaustivenessCheck}`) } } @@ -420,7 +420,7 @@ describe("Rules", function () { } default: { const exhaustivenessCheck: never = ruleKind - throw new Error(`Unhandled rule kind ${ruleKind}`) + throw new Error(`Unhandled rule kind ${exhaustivenessCheck}`) } } @@ -504,7 +504,7 @@ describe("Rules", function () { } default: { const exhaustivenessCheck: never = ruleKind - throw new Error(`Unhandled rule kind ${ruleKind}`) + throw new Error(`Unhandled rule kind ${exhaustivenessCheck}`) } } From 0deae17166eb0ba0ac5fdd3b3fa144d2a58c682c Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 02:05:00 -0300 Subject: [PATCH 05/10] clean up workflowFilePath --- src/constants.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/constants.ts b/src/constants.ts index ecd4405..6cc2936 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -1,8 +1,7 @@ import { CommitState, RulesConfigurations } from "./types" export const configFilePath = ".github/pr-custom-review.yml" -export const workflowFilePath = ".github/workflows/pr-custom-review.yml" -export const actionReviewTeamFiles = [configFilePath, workflowFilePath] +export const actionReviewTeamFiles = [configFilePath] export const commitStateSuccess: CommitState = "success" export const commitStateFailure: CommitState = "failure" From cb0f9b405afaf882cd4adf0b13eaab01932c9e53 Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 02:06:58 -0300 Subject: [PATCH 06/10] exemplify configuration syntax --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index ee3dba4..f3cbcfd 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ This is a GitHub Action created for complex pull request approval scenarios whic - [Built-in checks](#built-in-checks) - [Configuration](#configuration) - [Configuration file](#configuration-file) + - [Configuration syntax](#configuration-syntax) - [Rules syntax](#rules-syntax) - [Basic Rule syntax](#basic-rule-syntax) - [AND Rule syntax](#and-rule-syntax) @@ -66,6 +67,29 @@ action's workflow file is added, otherwise the action will fail with `RequestError [HttpError]: Not Found` because the configuration does not yet exist in the default branch. +### Configuration syntax + +```yaml +inputs: + # locks-review-team defines the team which will handle the "locks touched" + # built-in rule. We recommend protecting this input with "🔒" so that it + # won't be changed unless someone from locks-review-team approves it. + # 🔒 PROTECTED: Changes to locks-review-team should be approved by custom-locks-team + locks-review-team: custom-locks-team + + # The second team which will handle the "locks touched" built-in rule. + team-leads-team: my-custom-leads-team + + # The team which will handle the changes to the action's configuration. + action-review-team: my-action-review-team + +# This is an example of a basic rule which enforces one approval from anyone +# More complex rule types are explained in-depth in the "Rules syntax" section +rules: + - name: A single approval + min_approvals: 1 +``` + ### Rules syntax Three kinds of rules are available: From 9b8b73a4501d1658fe350f5d6d36502ebd2b1f0a Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 02:08:34 -0300 Subject: [PATCH 07/10] update docs --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e8002fe..3de2f0d 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,7 @@ exist in the default branch. ### Rules syntax -Three kinds of rules are available: +Four kinds of rules are available: - Basic Rule, through which you specify **top-level** `users` and `teams` for reaching `min_approvals` @@ -78,6 +78,9 @@ Three kinds of rules are available: with its own `min_approvals`, and **all** of them (logical `AND`) should reach their respective `min_approvals` +- AND DISTINCT Rule, which works like AND Rule except that each approval needs + to come from a different user + - OR Rule, through which you specify subconditions of `users` and `teams`, each with its own `min_approvals`, and **any** of them (logical `OR`) should reach their respective `min_approvals` @@ -163,7 +166,7 @@ field. #### AND DISTINCT Rule syntax -AND DISTINCT Rules work like [AND Rules](#and-rule-syntax) in the sense that all +AND DISTINCT Rules works like [AND Rules](#and-rule-syntax) in the sense that all subconditions have to be fulfilled, except that each approval contributes at most **once** for a single subcondition, i.e. all approvals throughout all subconditions have to come from different users (hence the name DISTINCT). From 90ca11f31857c3895a8c45ffc065a48013ebda0d Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 05:29:54 -0300 Subject: [PATCH 08/10] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 8610135..6a8163b 100644 --- a/README.md +++ b/README.md @@ -189,7 +189,7 @@ field. #### AND DISTINCT Rule syntax -AND DISTINCT Rules works like [AND Rules](#and-rule-syntax) in the sense that all +AND DISTINCT Rules work like [AND Rules](#and-rule-syntax) in the sense that all subconditions have to be fulfilled, except that each approval contributes at most **once** for a single subcondition, i.e. all approvals throughout all subconditions have to come from different users (hence the name DISTINCT). From 5286e2adbdb6e6304484093310c9a6ac27d3242b Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 05:35:45 -0300 Subject: [PATCH 09/10] simplify request handling --- src/core.ts | 35 +++-------------------------- src/main.ts | 63 ++++++++++++++++++++++++----------------------------- 2 files changed, 31 insertions(+), 67 deletions(-) diff --git a/src/core.ts b/src/core.ts index 69c5bde..663b37a 100644 --- a/src/core.ts +++ b/src/core.ts @@ -100,30 +100,15 @@ export const runChecks = async function ( repo: pr.base.repo.name, path: configFilePath, }) - if (configFileResponse.status !== 200) { - logger.failure( - `Failed to get the contents of ${configFilePath} (code ${configFileResponse.status})`, - ) - logger.log(configFileResponse.data) - return commitStateFailure - } - const { data } = configFileResponse - if (typeof data !== "object" || data === null) { - logger.failure( - `Data response for ${configFilePath} had unexpected type (expected object)`, - ) - logger.log(configFileResponse.data) - return commitStateFailure - } - if (!("content" in data)) { + if (!("content" in configFileResponse.data)) { logger.failure( `Did not find "content" key in the response for ${configFilePath}`, ) logger.log(configFileResponse.data) return commitStateFailure } - // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment - const { content: configFileContentsEnconded } = data + + const { content: configFileContentsEnconded } = configFileResponse.data if (typeof configFileContentsEnconded !== "string") { logger.failure( `Content response for ${configFilePath} had unexpected type (expected string)`, @@ -164,13 +149,6 @@ export const runChecks = async function ( pull_number: pr.number, mediaType: { format: "diff" }, })) /* Octokit doesn't inform the right return type for mediaType: { format: "diff" } */ as unknown as OctokitResponse - if (diffResponse.status !== 200) { - logger.failure( - `Failed to get the diff from ${pr.html_url} (code ${diffResponse.status})`, - ) - logger.log(diffResponse.data) - return commitStateFailure - } const { data: diff } = diffResponse const matchedRules: MatchedRule[] = [] @@ -435,13 +413,6 @@ export const runChecks = async function ( repo: pr.base.repo.name, pull_number: pr.number, }) - if (reviewsResponse.status !== 200) { - logger.failure( - `Failed to fetch reviews from ${pr.html_url} (code ${reviewsResponse.status})`, - ) - logger.log(reviewsResponse.data) - return commitStateFailure - } const { data: reviews } = reviewsResponse const latestReviews: Map< diff --git a/src/main.ts b/src/main.ts index 561b0ab..dd15b10 100644 --- a/src/main.ts +++ b/src/main.ts @@ -32,55 +32,48 @@ const main = function () { } else { // Fetch the jobs so that we'll be able to detect this step and provide a // more accurate logging location - const jobsResponse = await octokit.rest.actions.listJobsForWorkflowRun({ + const { + data: { jobs }, + } = await octokit.rest.actions.listJobsForWorkflowRun({ owner: pr.base.repo.owner.login, repo: pr.base.repo.name, run_id: context.runId, }) - if (jobsResponse.status === 200) { - const { - data: { jobs }, - } = jobsResponse - for (const job of jobs) { - if (job.name === jobName) { - let stepNumber: number | undefined = undefined - const actionRepository = process.env.GITHUB_ACTION_REPOSITORY - if (actionRepository === undefined) { + for (const job of jobs) { + if (job.name === jobName) { + let stepNumber: number | undefined = undefined + const actionRepository = process.env.GITHUB_ACTION_REPOSITORY + if (actionRepository === undefined) { + logger.warning( + "Action repository was not found in the environment", + ) + } else { + const actionRepositoryMatch = actionRepository.match(/[^/]*$/) + if (actionRepositoryMatch === null) { logger.warning( - "Action repository was not found in the environment", + `Action repository name could not be extracted from ${actionRepository}`, ) } else { - const actionRepositoryMatch = actionRepository.match(/[^/]*$/) - if (actionRepositoryMatch === null) { + const actionStep = job.steps?.find(function ({ name }) { + return name === actionRepositoryMatch[0] + }) + if (actionStep === undefined) { logger.warning( - `Action repository name could not be extracted from ${actionRepository}`, + `Failed to find ${actionRepositoryMatch[0]} in the job's steps`, + job.steps, ) } else { - const actionStep = job.steps?.find(function ({ name }) { - return name === actionRepositoryMatch[0] - }) - if (actionStep === undefined) { - logger.warning( - `Failed to find ${actionRepositoryMatch[0]} in the job's steps`, - job.steps, - ) - } else { - stepNumber = actionStep.number - } + stepNumber = actionStep.number } } - detailsUrl = `${job.html_url}${ - stepNumber - ? `#step:${stepNumber}:${logger.relevantStartingLine}` - : "" - }` - break } + detailsUrl = `${job.html_url}${ + stepNumber + ? `#step:${stepNumber}:${logger.relevantStartingLine}` + : "" + }` + break } - } else { - logger.failure( - `Failed to fetch jobs for workflow run ${context.runId} (code ${jobsResponse.status})`, - ) } } } From 5a65ac2a73829fce9dc905f6cfde63717c132827 Mon Sep 17 00:00:00 2001 From: joao-paulo-parity Date: Mon, 4 Apr 2022 05:36:14 -0300 Subject: [PATCH 10/10] clean obsolete snaps --- test/batch/rules.ts.snap | 32 -------------------------------- 1 file changed, 32 deletions(-) diff --git a/test/batch/rules.ts.snap b/test/batch/rules.ts.snap index c87fd4c..5a58505 100644 --- a/test/batch/rules.ts.snap +++ b/test/batch/rules.ts.snap @@ -109,16 +109,6 @@ Array [ ] `; -exports[`Rules Approved when .github/workflows/pr-custom-review.yml is changed 1`] = ` -Array [ - "Changed files Set(1) { '.github/workflows/pr-custom-review.yml' }", - "latestReviews [Map Iterator] { - { id: 0, user: 'userCoworker', isApproval: true }, - { id: 1, user: 'userCoworker2', isApproval: true } -}", -] -`; - exports[`Rules Approved when line after lock is modified (+) 1`] = ` Array [ "Diff has changes to 🔒 lines or lines following 🔒", @@ -347,17 +337,6 @@ Array [ ] `; -exports[`Rules Has no approval when .github/workflows/pr-custom-review.yml is changed 1`] = ` -Array [ - "Changed files Set(1) { '.github/workflows/pr-custom-review.yml' }", - "latestReviews [Map Iterator] { }", - "usersToAskForReview Map(1) { 'userCoworker2' => { teams: Set(1) { 'team3' } } }", - "ERROR: The following problems were found:", - "Rule \\"Action files changed\\" needs at least 1 approvals, but 0 were matched. The following users have not approved yet: userCoworker2 (team: team3).", - "", -] -`; - exports[`Rules Has no approval when line after lock is modified (+) 1`] = ` Array [ "Diff has changes to 🔒 lines or lines following 🔒", @@ -587,17 +566,6 @@ Array [ ] `; -exports[`Rules Is missing approval when .github/workflows/pr-custom-review.yml is changed 1`] = ` -Array [ - "Changed files Set(1) { '.github/workflows/pr-custom-review.yml' }", - "latestReviews [Map Iterator] { { id: 1, user: 'userCoworker', isApproval: true } }", - "usersToAskForReview Map(1) { 'userCoworker2' => { teams: Set(1) { 'team3' } } }", - "ERROR: The following problems were found:", - "Rule \\"Action files changed\\" needs at least 1 approvals, but 0 were matched. The following users have not approved yet: userCoworker2 (team: team3).", - "", -] -`; - exports[`Rules Is missing approval when line after lock is modified (+) 1`] = ` Array [ "Diff has changes to 🔒 lines or lines following 🔒",