diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..ca09262 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,12 @@ +{ + "printWidth": 80, + "tabWidth": 2, + "useTabs": false, + "semi": true, + "singleQuote": true, + "trailingComma": "none", + "bracketSpacing": false, + "arrowParens": "avoid", + "parser": "typescript", + "endOfLine": "auto" + } \ No newline at end of file diff --git a/__mocks__/@actions/github.ts b/__mocks__/@actions/github.ts index d423a29..ea8319f 100644 --- a/__mocks__/@actions/github.ts +++ b/__mocks__/@actions/github.ts @@ -1,34 +1,34 @@ export const context = { payload: { pull_request: { - number: 123, - }, + number: 123 + } }, repo: { - owner: "monalisa", - repo: "helloworld", - }, + owner: 'monalisa', + repo: 'helloworld' + } }; const mockApi = { rest: { issues: { addLabels: jest.fn(), - removeLabel: jest.fn(), + removeLabel: jest.fn() }, pulls: { get: jest.fn().mockResolvedValue({}), listFiles: { endpoint: { - merge: jest.fn().mockReturnValue({}), - }, - }, + merge: jest.fn().mockReturnValue({}) + } + } }, repos: { - getContent: jest.fn(), - }, + getContent: jest.fn() + } }, - paginate: jest.fn(), + paginate: jest.fn() }; export const getOctokit = jest.fn().mockImplementation(() => mockApi); diff --git a/__tests__/labeler.test.ts b/__tests__/labeler.test.ts index 082ed67..d684d28 100644 --- a/__tests__/labeler.test.ts +++ b/__tests__/labeler.test.ts @@ -1,27 +1,27 @@ -import { checkGlobs } from "../src/labeler"; +import {checkGlobs} from '../src/labeler'; -import * as core from "@actions/core"; +import * as core from '@actions/core'; -jest.mock("@actions/core"); +jest.mock('@actions/core'); beforeAll(() => { - jest.spyOn(core, "getInput").mockImplementation((name, options) => { - return jest.requireActual("@actions/core").getInput(name, options); + jest.spyOn(core, 'getInput').mockImplementation((name, options) => { + return jest.requireActual('@actions/core').getInput(name, options); }); }); -const matchConfig = [{ any: ["*.txt"] }]; +const matchConfig = [{any: ['*.txt']}]; -describe("checkGlobs", () => { - it("returns true when our pattern does match changed files", () => { - const changedFiles = ["foo.txt", "bar.txt"]; +describe('checkGlobs', () => { + it('returns true when our pattern does match changed files', () => { + const changedFiles = ['foo.txt', 'bar.txt']; const result = checkGlobs(changedFiles, matchConfig); expect(result).toBeTruthy(); }); - it("returns false when our pattern does not match changed files", () => { - const changedFiles = ["foo.docx"]; + it('returns false when our pattern does not match changed files', () => { + const changedFiles = ['foo.docx']; const result = checkGlobs(changedFiles, matchConfig); expect(result).toBeFalsy(); diff --git a/__tests__/main.test.ts b/__tests__/main.test.ts index de14559..e886a02 100644 --- a/__tests__/main.test.ts +++ b/__tests__/main.test.ts @@ -1,45 +1,45 @@ -import { run } from "../src/labeler"; -import * as github from "@actions/github"; -import * as core from "@actions/core"; +import {run} from '../src/labeler'; +import * as github from '@actions/github'; +import * as core from '@actions/core'; -const fs = jest.requireActual("fs"); +const fs = jest.requireActual('fs'); -jest.mock("@actions/core"); -jest.mock("@actions/github"); +jest.mock('@actions/core'); +jest.mock('@actions/github'); -const gh = github.getOctokit("_"); -const addLabelsMock = jest.spyOn(gh.rest.issues, "addLabels"); -const removeLabelMock = jest.spyOn(gh.rest.issues, "removeLabel"); -const reposMock = jest.spyOn(gh.rest.repos, "getContent"); -const paginateMock = jest.spyOn(gh, "paginate"); -const getPullMock = jest.spyOn(gh.rest.pulls, "get"); +const gh = github.getOctokit('_'); +const addLabelsMock = jest.spyOn(gh.rest.issues, 'addLabels'); +const removeLabelMock = jest.spyOn(gh.rest.issues, 'removeLabel'); +const reposMock = jest.spyOn(gh.rest.repos, 'getContent'); +const paginateMock = jest.spyOn(gh, 'paginate'); +const getPullMock = jest.spyOn(gh.rest.pulls, 'get'); const yamlFixtures = { - "only_pdfs.yml": fs.readFileSync("__tests__/fixtures/only_pdfs.yml"), + 'only_pdfs.yml': fs.readFileSync('__tests__/fixtures/only_pdfs.yml') }; afterAll(() => jest.restoreAllMocks()); -describe("run", () => { - it("adds labels to PRs that match our glob patterns", async () => { - usingLabelerConfigYaml("only_pdfs.yml"); - mockGitHubResponseChangedFiles("foo.pdf"); +describe('run', () => { + it('adds labels to PRs that match our glob patterns', async () => { + usingLabelerConfigYaml('only_pdfs.yml'); + mockGitHubResponseChangedFiles('foo.pdf'); await run(); expect(removeLabelMock).toHaveBeenCalledTimes(0); expect(addLabelsMock).toHaveBeenCalledTimes(1); expect(addLabelsMock).toHaveBeenCalledWith({ - owner: "monalisa", - repo: "helloworld", + owner: 'monalisa', + repo: 'helloworld', issue_number: 123, - labels: ["touched-a-pdf-file"], + labels: ['touched-a-pdf-file'] }); }); - it("does not add labels to PRs that do not match our glob patterns", async () => { - usingLabelerConfigYaml("only_pdfs.yml"); - mockGitHubResponseChangedFiles("foo.txt"); + it('does not add labels to PRs that do not match our glob patterns', async () => { + usingLabelerConfigYaml('only_pdfs.yml'); + mockGitHubResponseChangedFiles('foo.txt'); await run(); @@ -47,23 +47,23 @@ describe("run", () => { expect(addLabelsMock).toHaveBeenCalledTimes(0); }); - it("(with sync-labels: true) it deletes preexisting PR labels that no longer match the glob pattern", async () => { + it('(with sync-labels: true) it deletes preexisting PR labels that no longer match the glob pattern', async () => { let mockInput = { - "repo-token": "foo", - "configuration-path": "bar", - "sync-labels": true, + 'repo-token': 'foo', + 'configuration-path': 'bar', + 'sync-labels': true }; jest - .spyOn(core, "getInput") + .spyOn(core, 'getInput') .mockImplementation((name: string, ...opts) => mockInput[name]); - usingLabelerConfigYaml("only_pdfs.yml"); - mockGitHubResponseChangedFiles("foo.txt"); + usingLabelerConfigYaml('only_pdfs.yml'); + mockGitHubResponseChangedFiles('foo.txt'); getPullMock.mockResolvedValue({ data: { - labels: [{ name: "touched-a-pdf-file" }], - }, + labels: [{name: 'touched-a-pdf-file'}] + } }); await run(); @@ -71,30 +71,30 @@ describe("run", () => { expect(addLabelsMock).toHaveBeenCalledTimes(0); expect(removeLabelMock).toHaveBeenCalledTimes(1); expect(removeLabelMock).toHaveBeenCalledWith({ - owner: "monalisa", - repo: "helloworld", + owner: 'monalisa', + repo: 'helloworld', issue_number: 123, - name: "touched-a-pdf-file", + name: 'touched-a-pdf-file' }); }); - it("(with sync-labels: false) it issues no delete calls even when there are preexisting PR labels that no longer match the glob pattern", async () => { + it('(with sync-labels: false) it issues no delete calls even when there are preexisting PR labels that no longer match the glob pattern', async () => { let mockInput = { - "repo-token": "foo", - "configuration-path": "bar", - "sync-labels": false, + 'repo-token': 'foo', + 'configuration-path': 'bar', + 'sync-labels': false }; jest - .spyOn(core, "getInput") + .spyOn(core, 'getInput') .mockImplementation((name: string, ...opts) => mockInput[name]); - usingLabelerConfigYaml("only_pdfs.yml"); - mockGitHubResponseChangedFiles("foo.txt"); + usingLabelerConfigYaml('only_pdfs.yml'); + mockGitHubResponseChangedFiles('foo.txt'); getPullMock.mockResolvedValue({ data: { - labels: [{ name: "touched-a-pdf-file" }], - }, + labels: [{name: 'touched-a-pdf-file'}] + } }); await run(); @@ -106,11 +106,11 @@ describe("run", () => { function usingLabelerConfigYaml(fixtureName: keyof typeof yamlFixtures): void { reposMock.mockResolvedValue({ - data: { content: yamlFixtures[fixtureName], encoding: "utf8" }, + data: {content: yamlFixtures[fixtureName], encoding: 'utf8'} }); } function mockGitHubResponseChangedFiles(...files: string[]): void { - const returnValue = files.map((f) => ({ filename: f })); + const returnValue = files.map(f => ({filename: f})); paginateMock.mockReturnValue(returnValue); } diff --git a/src/labeler.ts b/src/labeler.ts index 59cf23f..b33073a 100644 --- a/src/labeler.ts +++ b/src/labeler.ts @@ -1,7 +1,7 @@ -import * as core from "@actions/core"; -import * as github from "@actions/github"; -import * as yaml from "js-yaml"; -import { Minimatch, IMinimatch } from "minimatch"; +import * as core from '@actions/core'; +import * as github from '@actions/github'; +import * as yaml from 'js-yaml'; +import {Minimatch, IMinimatch} from 'minimatch'; interface MatchConfig { all?: string[]; @@ -13,22 +13,22 @@ type ClientType = ReturnType; export async function run() { try { - const token = core.getInput("repo-token", { required: true }); - const configPath = core.getInput("configuration-path", { required: true }); - const syncLabels = !!core.getInput("sync-labels", { required: false }); + const token = core.getInput('repo-token', {required: true}); + const configPath = core.getInput('configuration-path', {required: true}); + const syncLabels = !!core.getInput('sync-labels', {required: false}); const prNumber = getPrNumber(); if (!prNumber) { - console.log("Could not get pull request number from context, exiting"); + console.log('Could not get pull request number from context, exiting'); return; } const client: ClientType = github.getOctokit(token); - const { data: pullRequest } = await client.rest.pulls.get({ + const {data: pullRequest} = await client.rest.pulls.get({ owner: github.context.repo.owner, repo: github.context.repo.repo, - pull_number: prNumber, + pull_number: prNumber }); core.debug(`fetching changed files for pr #${prNumber}`); @@ -44,7 +44,7 @@ export async function run() { core.debug(`processing ${label}`); if (checkGlobs(changedFiles, globs)) { labels.push(label); - } else if (pullRequest.labels.find((l) => l.name === label)) { + } else if (pullRequest.labels.find(l => l.name === label)) { labelsToRemove.push(label); } } @@ -78,15 +78,15 @@ async function getChangedFiles( const listFilesOptions = client.rest.pulls.listFiles.endpoint.merge({ owner: github.context.repo.owner, repo: github.context.repo.repo, - pull_number: prNumber, + pull_number: prNumber }); const listFilesResponse = await client.paginate(listFilesOptions); const changedFiles = listFilesResponse.map((f: any) => f.filename); - core.debug("found changed files:"); + core.debug('found changed files:'); for (const file of changedFiles) { - core.debug(" " + file); + core.debug(' ' + file); } return changedFiles; @@ -116,7 +116,7 @@ async function fetchContent( owner: github.context.repo.owner, repo: github.context.repo.repo, path: repoPath, - ref: github.context.sha, + ref: github.context.sha }); return Buffer.from(response.data.content, response.data.encoding).toString(); @@ -127,7 +127,7 @@ function getLabelGlobMapFromObject( ): Map { const labelGlobs: Map = new Map(); for (const label in configObject) { - if (typeof configObject[label] === "string") { + if (typeof configObject[label] === 'string') { labelGlobs.set(label, [configObject[label]]); } else if (configObject[label] instanceof Array) { labelGlobs.set(label, configObject[label]); @@ -142,9 +142,9 @@ function getLabelGlobMapFromObject( } function toMatchConfig(config: StringOrMatchConfig): MatchConfig { - if (typeof config === "string") { + if (typeof config === 'string') { return { - any: [config], + any: [config] }; } @@ -152,7 +152,7 @@ function toMatchConfig(config: StringOrMatchConfig): MatchConfig { } function printPattern(matcher: IMinimatch): string { - return (matcher.negate ? "!" : "") + matcher.pattern; + return (matcher.negate ? '!' : '') + matcher.pattern; } export function checkGlobs( @@ -185,7 +185,7 @@ function isMatch(changedFile: string, matchers: IMinimatch[]): boolean { // equivalent to "Array.some()" but expanded for debugging and clarity function checkAny(changedFiles: string[], globs: string[]): boolean { - const matchers = globs.map((g) => new Minimatch(g)); + const matchers = globs.map(g => new Minimatch(g)); core.debug(` checking "any" patterns`); for (const changedFile of changedFiles) { if (isMatch(changedFile, matchers)) { @@ -200,7 +200,7 @@ function checkAny(changedFiles: string[], globs: string[]): boolean { // equivalent to "Array.every()" but expanded for debugging and clarity function checkAll(changedFiles: string[], globs: string[]): boolean { - const matchers = globs.map((g) => new Minimatch(g)); + const matchers = globs.map(g => new Minimatch(g)); core.debug(` checking "all" patterns`); for (const changedFile of changedFiles) { if (!isMatch(changedFile, matchers)) { @@ -238,7 +238,7 @@ async function addLabels( owner: github.context.repo.owner, repo: github.context.repo.repo, issue_number: prNumber, - labels: labels, + labels: labels }); } @@ -248,12 +248,12 @@ async function removeLabels( labels: string[] ) { await Promise.all( - labels.map((label) => + labels.map(label => client.rest.issues.removeLabel({ owner: github.context.repo.owner, repo: github.context.repo.repo, issue_number: prNumber, - name: label, + name: label }) ) ); diff --git a/src/main.ts b/src/main.ts index d9d6212..60377ad 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,3 +1,3 @@ -import { run } from "./labeler"; +import {run} from './labeler'; run();