From 980eb56fa211a670ba09078ca6f9eff666d7adca Mon Sep 17 00:00:00 2001 From: Kohei Hasegawa Date: Sun, 2 Feb 2020 14:42:41 +0900 Subject: [PATCH 1/7] Update codes to GitHub Actions v2 * Use official toolkit * Remove JasonEtco/actions-toolkit * Fix incompatible things --- src/entrypoint.ts | 264 +++++++++++++++++++++++++++------------------- src/query.ts | 42 +++++--- src/util.ts | 14 ++- 3 files changed, 194 insertions(+), 126 deletions(-) diff --git a/src/entrypoint.ts b/src/entrypoint.ts index 03a31cb..50a65fc 100644 --- a/src/entrypoint.ts +++ b/src/entrypoint.ts @@ -1,129 +1,175 @@ import * as fs from 'fs'; import * as path from 'path'; -import { Toolkit } from 'actions-toolkit'; +import * as util from 'util'; + +import * as core from '@actions/core'; +import * as github from '@actions/github'; +import { graphql } from '@octokit/graphql'; +import Webhooks from '@octokit/webhooks'; +import ignore from 'ignore'; + +import { logger, getLabelIds } from './util'; +import { Label, LabelEdge, LabelName } from './interface'; import { addLabelsToLabelable, removeLabelsFromLabelable, getPullRequestAndLabels, } from './query'; -import { Label, FileEdge, LabelEdge, LabelName } from './interface'; -import { getLabelIds } from './util'; -import * as util from 'util'; -import ignore from 'ignore'; const exec = util.promisify(require('child_process').exec); -const configFile = '.github/auto-label.json'; -const tools = new Toolkit({ - event: ['pull_request.opened', 'pull_request.synchronize'], -}); - -(async () => { - if (!fs.existsSync(path.join(tools.workspace, configFile))) { - tools.exit.neutral('config file does not exist.'); - } - const config = JSON.parse(tools.getFile(configFile)); +async function run() { + try { + const token = process.env['GITHUB_TOKEN']; + if (!token) { + core.setFailed('GITHUB_TOKEN does not exist.'); + return; + } + const graphqlWithAuth = graphql.defaults({ + headers: { authorization: `token ${token}` }, + }); + + const configPath = path.join(__dirname, core.getInput('configPath')); - let result; + if (!fs.existsSync(configPath)) { + core.setFailed(`configFile does not exist in ${configPath}.`); + } - try { - result = await getPullRequestAndLabels(tools, tools.context.issue()); - } catch (error) { - console.error('Request failed: ', error.request, error.message); - tools.exit.failure('getPullRequestAndLabels has been failed.'); - } + const config = JSON.parse(fs.readFileSync(configPath).toString()); - console.log('Result: ', result); - - const allLabels = result.repository.labels.edges.reduce( - (acc: Label, edge: LabelEdge) => { - acc[edge.node.name] = edge.node.id; - return acc; - }, - {}, - ); - - const currentLabelNames = new Set( - result.repository.pullRequest.labels.edges.map( - (edge: LabelEdge) => edge.node.name, - ), - ); - - const { headRefOid, baseRefOid } = result.repository.pullRequest; - - // TODO: handle stderr - const { stdout, stderr } = await exec( - `git merge-base --is-ancestor ${baseRefOid} ${headRefOid} && git diff --name-only ${baseRefOid} || git diff --name-only $(git merge-base ${baseRefOid} ${headRefOid})`, - ); - - const diffFiles = stdout.trim().split('\n'); - - const newLabelNames = new Set( - diffFiles.reduce((acc: LabelName[], file: string) => { - Object.entries(config.rules).forEach(([label, pattern]) => { - if ( - ignore() - .add(pattern as any) - .ignores(file) - ) { - acc.push(label); - } - }); - return acc; - }, []), - ); - - const ruledLabelNames = new Set(Object.keys(config.rules)); - - const labelNamesToAdd = new Set( - ([...newLabelNames] as LabelName[]).filter( - labelName => !currentLabelNames.has(labelName), - ), - ); - - const labelNamesToRemove = new Set( - ([...currentLabelNames] as LabelName[]).filter( - (labelName: string) => - !newLabelNames.has(labelName) && ruledLabelNames.has(labelName), - ), - ); - - console.log(' ---> Current status'); - console.log('allLabels: ', allLabels); - console.log('currentLabelNames: ', currentLabelNames); - console.log('diffFiles: ', diffFiles); - console.log('newLabelNames: ', newLabelNames); - console.log('ruledLabelNames: ', ruledLabelNames); - console.log('labelNamesToAdd: ', labelNamesToAdd); - console.log('labelNamesToRemove: ', labelNamesToRemove); - - const labelableId = result.repository.pullRequest.id; - - if (labelNamesToAdd.size > 0) { - try { - await addLabelsToLabelable(tools, { - labelIds: getLabelIds(allLabels, [...labelNamesToAdd] as LabelName[]), - labelableId, - }); - console.log('Added labels: ', labelNamesToAdd); - } catch (error) { - console.error('Request failed: ', error.request, error.message); - tools.exit.failure('addLabelsToLabelable has been failed. '); + logger.debug('config', config); + logger.debug('github.context.eventName', github.context.eventName); + + if (github.context.eventName !== 'pull_request') { + return; } - } - if (labelNamesToRemove.size > 0) { + const payload = github.context + .payload as Webhooks.WebhookPayloadPullRequest; + + logger.debug('payload.action', payload.action); + + if (payload.action !== 'opened' && payload.action !== 'synchronize') { + return; + } + + const owner = payload.repository.owner.login; + const repo = payload.repository.name; + const number = payload.pull_request.number; + + let result; + try { - await removeLabelsFromLabelable(tools, { - labelIds: getLabelIds(allLabels, [ - ...labelNamesToRemove, - ] as LabelName[]), - labelableId, + result = await getPullRequestAndLabels(graphqlWithAuth, { + owner, + repo, + number, }); - console.log('Removed labels: ', labelNamesToRemove); } catch (error) { - console.error('Request failed: ', error.request, error.message); - tools.exit.failure('removeLabelsFromLabelable has been failed. '); + error(); + core.error(`Request failed: ${JSON.stringify(error.message)}`); + core.setFailed('getPullRequestAndLabels has been failed.'); } + + logger.debug('result', result); + + if (!result) { + return core.setFailed(`result was empty: ${result}`); + } + + const allLabels = result.repository.labels.edges.reduce( + (acc: Label, edge: LabelEdge) => { + acc[edge.node.name] = edge.node.id; + return acc; + }, + {}, + ); + + logger.debug('allLabels', allLabels); + + const currentLabelNames = new Set( + result.repository.pullRequest.labels.edges.map( + (edge: LabelEdge) => edge.node.name, + ), + ); + + logger.debug('currentLabelNames', currentLabelNames); + + const { headRefOid, baseRefOid } = result.repository.pullRequest; + + const { stdout } = await exec( + `git fetch && git merge-base --is-ancestor ${baseRefOid} ${headRefOid} && git diff --name-only ${baseRefOid} || git diff --name-only $(git merge-base ${baseRefOid} ${headRefOid})`, + ); + + const diffFiles = stdout.trim().split('\n'); + + const newLabelNames = new Set( + diffFiles.reduce((acc: LabelName[], file: string) => { + Object.entries(config.rules).forEach(([label, pattern]) => { + if ( + ignore() + .add(pattern as string) + .ignores(file) + ) { + acc.push(label); + } + }); + return acc; + }, []), + ); + + const ruledLabelNames = new Set(Object.keys(config.rules)); + + const labelNamesToAdd = new Set( + ([...newLabelNames] as LabelName[]).filter( + labelName => !currentLabelNames.has(labelName), + ), + ); + + const labelNamesToRemove = new Set( + ([...currentLabelNames] as LabelName[]).filter( + (labelName: string) => + !newLabelNames.has(labelName) && ruledLabelNames.has(labelName), + ), + ); + + logger.debug('labelNamesToAdd', labelNamesToAdd); + logger.debug('labelNamesToRemove', labelNamesToRemove); + + const labelableId = result.repository.pullRequest.id; + + logger.debug('labelableId', labelableId); + + if (labelNamesToAdd.size > 0) { + try { + await addLabelsToLabelable(graphqlWithAuth, { + labelIds: getLabelIds(allLabels, [...labelNamesToAdd] as LabelName[]), + labelableId, + }); + console.log('Added labels: ', labelNamesToAdd); + } catch (error) { + logger.error('Request failed', error.message); + core.setFailed('addLabelsToLabelable has been failed. '); + } + } + + if (labelNamesToRemove.size > 0) { + try { + await removeLabelsFromLabelable(graphqlWithAuth, { + labelIds: getLabelIds(allLabels, [ + ...labelNamesToRemove, + ] as LabelName[]), + labelableId, + }); + console.log('Removed labels: ', labelNamesToRemove); + } catch (error) { + logger.error('Request failed', error.message); + core.setFailed('removeLabelsFromLabelable has been failed. '); + } + } + } catch (error) { + core.setFailed(error.message); } -})(); +} + +run(); diff --git a/src/query.ts b/src/query.ts index 95761f3..74afae1 100644 --- a/src/query.ts +++ b/src/query.ts @@ -1,8 +1,13 @@ -import { Toolkit } from 'actions-toolkit'; -import { LabelName } from './interface'; +import { graphql } from '@octokit/graphql'; +import * as OctokitTypes from '@octokit/types'; + +type Graphql = ( + query: string, + options?: OctokitTypes.RequestParameters, +) => ReturnType; export const getPullRequestAndLabels = ( - tools: Toolkit, + graphqlWithAuth: Graphql, { owner, repo, @@ -13,9 +18,9 @@ export const getPullRequestAndLabels = ( number: number; }, ) => { - const query = `{ - repository(owner: "${owner}", name: "${repo}") { - pullRequest(number: ${number}) { + const query = `query pullRequestAndLabels($owner: String!, $repo: String!, $number: Int!) { + repository(owner:$owner, name:$repo) { + pullRequest(number:$number) { id baseRefOid headRefOid @@ -47,13 +52,16 @@ export const getPullRequestAndLabels = ( } }`; - return tools.github.graphql(query, { + return graphqlWithAuth(query, { + owner, + repo, + number, headers: { Accept: 'application/vnd.github.ocelot-preview+json' }, }); }; export const addLabelsToLabelable = ( - tools: Toolkit, + graphqlWithAuth: Graphql, { labelIds, labelableId, @@ -63,19 +71,21 @@ export const addLabelsToLabelable = ( }, ) => { const query = ` - mutation { - addLabelsToLabelable(input: {labelIds: ${labelIds}, labelableId: "${labelableId}"}) { + mutation addLabelsToLabelable($labelIds: String!, $labelableId: String!) { + addLabelsToLabelable(input: {labelIds:$labelIds, labelableId:$labelableId}) { clientMutationId } }`; - return tools.github.graphql(query, { + return graphqlWithAuth(query, { + labelIds, + labelableId, headers: { Accept: 'application/vnd.github.starfire-preview+json' }, }); }; export const removeLabelsFromLabelable = ( - tools: Toolkit, + graphqlWithAuth: Graphql, { labelIds, labelableId, @@ -85,13 +95,15 @@ export const removeLabelsFromLabelable = ( }, ) => { const query = ` - mutation { - removeLabelsFromLabelable(input: {labelIds: ${labelIds}, labelableId: "${labelableId}"}) { + mutation removeLabelsFromLabelable($labelIds: String!, $labelableId: String!) { + removeLabelsFromLabelable(input: {labelIds:$labelIds, labelableId:$labelableId}) { clientMutationId } }`; - return tools.github.graphql(query, { + return graphqlWithAuth(query, { + labelIds, + labelableId, headers: { Accept: 'application/vnd.github.starfire-preview+json' }, }); }; diff --git a/src/util.ts b/src/util.ts index 4b21f77..35c6a73 100644 --- a/src/util.ts +++ b/src/util.ts @@ -1,7 +1,17 @@ -import { pick } from 'lodash'; -import { Label, LabelName } from './interface'; +import * as core from '@actions/core'; +import pick from 'lodash.pick'; +import { Label, LabelName } from './interface'; export const getLabelIds = ( allLabels: Label[], labelNames: LabelName[], ): string => JSON.stringify(Object.values(pick(allLabels, labelNames))); + +export const logger = { + debug: (message: string, object: {} | null | undefined) => { + return core.debug(`${message}: ${JSON.stringify(object)}`); + }, + error: (message: string, object: {} | null | undefined) => { + return core.error(`${message}: ${JSON.stringify(object)}`); + }, +}; From 250558ea95f689e3c880a10e3639e6d924260873 Mon Sep 17 00:00:00 2001 From: Kohei Hasegawa Date: Sun, 2 Feb 2020 14:48:34 +0900 Subject: [PATCH 2/7] Remove LABEL --- Dockerfile | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 36c54e1..c1b7862 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,4 @@ FROM node:alpine - -LABEL "com.github.actions.name"="autolabel" -LABEL "com.github.actions.description"="Add labels to Pull Request based on matched file patterns" -LABEL "com.github.actions.icon"="flag" -LABEL "com.github.actions.color"="gray-dark" - COPY . . RUN yarn install RUN apk --no-cache add git From 3c0b5e6d208bfa1ee6fb50175e62160334bd71cd Mon Sep 17 00:00:00 2001 From: Kohei Hasegawa Date: Sun, 2 Feb 2020 14:50:33 +0900 Subject: [PATCH 3/7] Update dependencies --- package.json | 16 +++- yarn.lock | 262 +++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 203 insertions(+), 75 deletions(-) diff --git a/package.json b/package.json index 55d0da6..7bf8522 100644 --- a/package.json +++ b/package.json @@ -6,14 +6,19 @@ "build": "node fuse", "build:watch": "node fuse --variant watch", "lint": "eslint --cache --ext .ts src", - "lint:fix": "yarn lint --fix" + "lint:fix": "yarn lint --fix", + "fmt": "prettier --write **/*.ts" }, "dependencies": { - "actions-toolkit": "^1.4.1", - "ignore": "^5.0.5", - "lodash": "^4.17.11" + "@actions/core": "^1.2.2", + "@actions/exec": "^1.0.3", + "@actions/github": "^2.1.0", + "@octokit/graphql": "^4.3.1", + "@types/lodash.pick": "^4.4.6", + "ignore": "^5.0.5" }, "devDependencies": { + "@octokit/webhooks": "^7.0.0", "@types/lodash": "^4.14.120", "@types/node": "^10.12.24", "@typescript-eslint/eslint-plugin": "^1.3.0", @@ -24,6 +29,7 @@ "prettier": "^1.16.4", "tslib": "^1.9.3", "typescript": "^3.3.3", - "yargs": "^12.0.5" + "yargs": "^12.0.5", + "lodash.pick": "^4.4.0" } } diff --git a/yarn.lock b/yarn.lock index b4cad39..ff5facc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,6 +2,39 @@ # yarn lockfile v1 +"@actions/core@^1.2.2": + version "1.2.2" + resolved "https://registry.yarnpkg.com/@actions/core/-/core-1.2.2.tgz#3c4848d50378f9e3bcb67bcf97813382ec7369ee" + integrity sha512-IbCx7oefq+Gi6FWbSs2Fnw8VkEI6Y4gvjrYprY3RV//ksq/KPMlClOerJ4jRosyal6zkUIc8R9fS/cpRMlGClg== + +"@actions/exec@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@actions/exec/-/exec-1.0.3.tgz#b967f8700d6ff011dcc91243b58bafc1bb9ab95f" + integrity sha512-TogJGnueOmM7ntCi0ASTUj4LapRRtDfj57Ja4IhPmg2fls28uVOPbAn8N+JifaOumN2UG3oEO/Ixek2A4NcYSA== + dependencies: + "@actions/io" "^1.0.1" + +"@actions/github@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@actions/github/-/github-2.1.0.tgz#ca36cfb146b4c8955f3d5f88d8dde5f89194de21" + integrity sha512-G4ncMlh4pLLAvNgHUYUtpWQ1zPf/VYqmRH9oshxLabdaOOnp7i1hgSgzr2xne2YUaSND3uqemd3YYTIsm2f/KQ== + dependencies: + "@actions/http-client" "^1.0.3" + "@octokit/graphql" "^4.3.1" + "@octokit/rest" "^16.15.0" + +"@actions/http-client@^1.0.3": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@actions/http-client/-/http-client-1.0.4.tgz#3770b1a978ec731f210d25a490b4f721474ce4c4" + integrity sha512-6EzXhqapKKtYr21ZnFQVBYwfrYPKPCivuSkUN/66/BDakkH2EPjUZH8tZ3MgHdI+gQIdcsY0ybbxw9ZEOmJB6g== + dependencies: + tunnel "0.0.6" + +"@actions/io@^1.0.1": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@actions/io/-/io-1.0.2.tgz#2f614b6e69ce14d191180451eb38e6576a6e6b27" + integrity sha512-J8KuFqVPr3p6U8W93DOXlXW6zFvrQAJANdS+vw0YhusLIq+bszW8zmK2Fh1C2kDPX8FMvwIl1OUcFgvJoXLbAg== + "@babel/code-frame@^7.0.0": version "7.0.0" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8" @@ -18,53 +51,132 @@ esutils "^2.0.2" js-tokens "^4.0.0" -"@octokit/endpoint@^3.1.1": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-3.1.2.tgz#22b5aa8596482fbefc3f1ce22c24ad217aed60fa" - integrity sha512-iRx4kDYybAv9tOrHDBE6HwlgiFi8qmbZl8SHliZWtxbUFuXLZXh2yv8DxGIK9wzD9J0wLDMZneO8vNYJNUSJ9Q== +"@octokit/auth-token@^2.4.0": + version "2.4.0" + resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.4.0.tgz#b64178975218b99e4dfe948253f0673cbbb59d9f" + integrity sha512-eoOVMjILna7FVQf96iWc3+ZtE/ZT6y8ob8ZzcqKY1ibSQCnu4O/B7pJvzMx5cyZ/RjAff6DAdEb0O0Cjcxidkg== dependencies: - deepmerge "3.1.0" - is-plain-object "^2.0.4" - universal-user-agent "^2.0.1" - url-template "^2.0.8" + "@octokit/types" "^2.0.0" -"@octokit/graphql@^2.0.1": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-2.0.1.tgz#0e9d7f41d6ac3305f37767e723183bd0b77af7d2" - integrity sha512-IBNr05yBYqffy9L37Vv3/5xQMw+swmYFtMsuwqUA5vSEUr+s/POf8DOpCaTtS8f7e9k+cEuKLC5AbOoXkdZZOA== +"@octokit/endpoint@^5.5.0": + version "5.5.2" + resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-5.5.2.tgz#ed19d01fe85ac58bc2b774661658f9e5429b8164" + integrity sha512-ICDcRA0C2vtTZZGud1nXRrBLXZqFayodXAKZfo3dkdcLNqcHsgaz3YSTupbURusYeucSVRjjG+RTcQhx6HPPcg== dependencies: - "@octokit/request" "^2.1.2" + "@octokit/types" "^2.0.0" + is-plain-object "^3.0.0" + universal-user-agent "^4.0.0" -"@octokit/request@2.3.0", "@octokit/request@^2.1.2": - version "2.3.0" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-2.3.0.tgz#da2672308bcf0b9376ef66f51bddbe5eb87cc00a" - integrity sha512-5YRqYNZOAaL7+nt7w3Scp6Sz4P2g7wKFP9npx1xdExMomk8/M/ICXVLYVam2wzxeY0cIc6wcKpjC5KI4jiNbGw== +"@octokit/graphql@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.3.1.tgz#9ee840e04ed2906c7d6763807632de84cdecf418" + integrity sha512-hCdTjfvrK+ilU2keAdqNBWOk+gm1kai1ZcdjRfB30oA3/T6n53UVJb7w0L5cR3/rhU91xT3HSqCd+qbvH06yxA== dependencies: - "@octokit/endpoint" "^3.1.1" - is-plain-object "^2.0.4" - node-fetch "^2.3.0" - universal-user-agent "^2.0.1" + "@octokit/request" "^5.3.0" + "@octokit/types" "^2.0.0" + universal-user-agent "^4.0.0" + +"@octokit/plugin-paginate-rest@^1.1.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc" + integrity sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q== + dependencies: + "@octokit/types" "^2.0.1" + +"@octokit/plugin-request-log@^1.0.0": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.0.tgz#eef87a431300f6148c39a7f75f8cfeb218b2547e" + integrity sha512-ywoxP68aOT3zHCLgWZgwUJatiENeHE7xJzYjfz8WI0goynp96wETBF+d95b8g/uL4QmS6owPVlaxiz3wyMAzcw== + +"@octokit/plugin-rest-endpoint-methods@2.2.0": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.2.0.tgz#17778b3b79f6dd978d8854ad81afeb239fae9da2" + integrity sha512-/Es7P4roLJls+4JaUUouZ25dqvXdrLJ80vvRoZzzR0EBCTlaU2ESRjXgH50mUpmR1MKPwJS3Ew5iFj3U3Q8UfQ== + dependencies: + "@octokit/types" "^2.0.1" + deprecation "^2.3.1" + +"@octokit/request-error@^1.0.1", "@octokit/request-error@^1.0.2": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" + integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA== + dependencies: + "@octokit/types" "^2.0.0" + deprecation "^2.0.0" + once "^1.4.0" -"@octokit/rest@^16.13.3": - version "16.15.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.15.0.tgz#648a88d5de055bcf38976709c5b2bdf1227b926f" - integrity sha512-Un+e7rgh38RtPOTe453pT/KPM/p2KZICimBmuZCd2wEo8PacDa4h6RqTPZs+f2DPazTTqdM7QU4LKlUjgiBwWw== +"@octokit/request@^5.2.0", "@octokit/request@^5.3.0": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.3.1.tgz#3a1ace45e6f88b1be4749c5da963b3a3b4a2f120" + integrity sha512-5/X0AL1ZgoU32fAepTfEoggFinO3rxsMLtzhlUX+RctLrusn/CApJuGFCd0v7GMFhF+8UiCsTTfsu7Fh1HnEJg== dependencies: - "@octokit/request" "2.3.0" - before-after-hook "^1.2.0" + "@octokit/endpoint" "^5.5.0" + "@octokit/request-error" "^1.0.1" + "@octokit/types" "^2.0.0" + deprecation "^2.0.0" + is-plain-object "^3.0.0" + node-fetch "^2.3.0" + once "^1.4.0" + universal-user-agent "^4.0.0" + +"@octokit/rest@^16.15.0": + version "16.41.1" + resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.41.1.tgz#885609acbc2d2118eaadf017f92ca503d352a84b" + integrity sha512-C97cb2cwxakAxZ+5oIAhmd9a1lqJ48n9TN3ooRuuifRMVQZGJCIFsb7uQV76YjDsB1agjhhDokAOSKq5F2+HYw== + dependencies: + "@octokit/auth-token" "^2.4.0" + "@octokit/plugin-paginate-rest" "^1.1.1" + "@octokit/plugin-request-log" "^1.0.0" + "@octokit/plugin-rest-endpoint-methods" "2.2.0" + "@octokit/request" "^5.2.0" + "@octokit/request-error" "^1.0.2" + atob-lite "^2.0.0" + before-after-hook "^2.0.0" btoa-lite "^1.0.0" + deprecation "^2.0.0" lodash.get "^4.4.2" lodash.set "^4.3.2" lodash.uniq "^4.5.0" octokit-pagination-methods "^1.1.0" - universal-user-agent "^2.0.0" - url-template "^2.0.8" + once "^1.4.0" + universal-user-agent "^4.0.0" + +"@octokit/types@^2.0.0", "@octokit/types@^2.0.1": + version "2.1.1" + resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.1.1.tgz#77e80d1b663c5f1f829e5377b728fa3c4fe5a97d" + integrity sha512-89LOYH+d/vsbDX785NOfLxTW88GjNd0lWRz1DVPVsZgg9Yett5O+3MOvwo7iHgvUwbFz0mf/yPIjBkUbs4kxoQ== + dependencies: + "@types/node" ">= 8" + +"@octokit/webhooks@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/@octokit/webhooks/-/webhooks-7.0.0.tgz#9e04f7ae097503bcf73b6dca7d6b86bb73608e9f" + integrity sha512-oSZuKc2LDNtt3vW7Iq9XNvIm3i6CxMkrzkuyHinR6IjVRb7EuiMshn3AVDdXdDtAVHvxwxj3ikt3jsTlFE6zEA== + dependencies: + debug "^4.0.0" + +"@types/lodash.pick@^4.4.6": + version "4.4.6" + resolved "https://registry.yarnpkg.com/@types/lodash.pick/-/lodash.pick-4.4.6.tgz#ae4e8f109e982786313bb6aac4b1a73aefa6e9be" + integrity sha512-u8bzA16qQ+8dY280z3aK7PoWb3fzX5ATJ0rJB6F+uqchOX2VYF02Aqa+8aYiHiHgPzQiITqCgeimlyKFy4OA6g== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.149" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.149.tgz#1342d63d948c6062838fbf961012f74d4e638440" + integrity sha512-ijGqzZt/b7BfzcK9vTrS6MFljQRPn5BFWOx8oE0GYxribu6uV+aA9zZuXI1zc/etK9E8nrgdoF2+LgUw7+9tJQ== "@types/lodash@^4.14.120": version "4.14.120" resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.120.tgz#cf265d06f6c7a710db087ed07523ab8c1a24047b" integrity sha512-jQ21kQ120mo+IrDs1nFNVm/AsdFxIx2+vZ347DbogHJPd/JzKNMOqU6HCYin1W6v8l5R9XSO2/e9cxmn7HAnVw== +"@types/node@>= 8": + version "13.7.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-13.7.0.tgz#b417deda18cf8400f278733499ad5547ed1abec4" + integrity sha512-GnZbirvmqZUzMgkFn70c74OQpTTUcCzlhQliTzYjQMqg+hVKcDnxdL19Ne3UdYzdMA/+W3eb646FWn/ZaT1NfQ== + "@types/node@^10.12.24": version "10.12.24" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.24.tgz#b13564af612a22a20b5d95ca40f1bffb3af315cf" @@ -131,18 +243,6 @@ acorn@^6.0.7: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.1.0.tgz#b0a3be31752c97a0f7013c5f4903b71a05db6818" integrity sha512-MW/FjM+IvU9CgBzjO3UIPCE2pyEwUsoFl+VGdczOPEdxfGFjuKny/gN54mOuX7Qxmb9Rg9MCn2oKiSUeW+pjrw== -actions-toolkit@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/actions-toolkit/-/actions-toolkit-1.4.1.tgz#2261c842c97e7b4af7ee1559337366f99c6195e7" - integrity sha512-ZMDDibr8xpoeEJnpCGi/wyJwAdUTN3Yn//wKZ9hqMzFPCFXr8v6G2+O9PvbRnp4U7LPbsdRzV78FZcF9npcqbA== - dependencies: - "@octokit/graphql" "^2.0.1" - "@octokit/rest" "^16.13.3" - execa "^1.0.0" - flat-cache "^2.0.1" - js-yaml "^3.12.0" - minimist "^1.2.0" - ajax-request@^1.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/ajax-request/-/ajax-request-1.2.3.tgz#99fcbec1d6d2792f85fa949535332bd14f5f3790" @@ -300,6 +400,11 @@ asynckit@^0.4.0: resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= +atob-lite@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" + integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= + atob@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" @@ -353,10 +458,10 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" -before-after-hook@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-1.3.2.tgz#7bfbf844ad670aa7a96b5a4e4e15bd74b08ed66b" - integrity sha512-zyPgY5dgbf99c0uGUjhY4w+mxqEGxPKg9RQDl34VvrVh2bM31lFN+mwR1ZHepq/KA3VCPk1gwJZL6IIJqjLy2w== +before-after-hook@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.1.0.tgz#b6c03487f44e24200dd30ca5e6a1979c5d2fb635" + integrity sha512-IWIbu7pMqyw3EAJHzzHbWa85b6oud/yfKYg5rqB5hNE8CeMi3nX+2C2sj0HswfblST86hpVEOAb9x34NZd6P7A== binary-extensions@^1.0.0: version "1.13.0" @@ -647,7 +752,7 @@ debug@2.6.9, debug@^2.1.2, debug@^2.2.0, debug@^2.3.3: dependencies: ms "2.0.0" -debug@^4.0.1: +debug@^4.0.0, debug@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== @@ -674,11 +779,6 @@ deep-is@~0.1.3: resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= -deepmerge@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.1.0.tgz#a612626ce4803da410d77554bfd80361599c034d" - integrity sha512-/TnecbwXEdycfbsM2++O3eGiatEFHjjNciHEwJclM+T5Kd94qD1AP+2elP/Mq0L5b9VZJao5znR01Mz6eX8Seg== - define-property@^0.2.5: version "0.2.5" resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" @@ -716,6 +816,11 @@ depd@~1.1.2: resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= +deprecation@^2.0.0, deprecation@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" + integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -1722,6 +1827,13 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.0.tgz#47bfc5da1b5d50d64110806c199359482e75a928" + integrity sha512-tZIpofR+P05k8Aocp7UI/2UTa9lTJSebCXpFFoR9aibpokDj/uXBsJ8luUu0tTVYKkMU6URDUuOfJZ7koewXvg== + dependencies: + isobject "^4.0.0" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -1774,6 +1886,11 @@ isobject@^3.0.0, isobject@^3.0.1: resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= +isobject@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-4.0.0.tgz#3f1c9155e73b192022a80819bacd0343711697b0" + integrity sha512-S/2fF5wH8SJA/kmwr6HYhK/RI/OkhD84k8ntalo0iJjZikgq1XFvR5M8NPT1x5F7fBwCG3qHfnzeP/Vh/ZxCUA== + isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" @@ -1898,6 +2015,11 @@ lodash.get@^4.4.2: resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= +lodash.pick@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" + integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= + lodash.set@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" @@ -1918,10 +2040,10 @@ lodash@^4.17.11, lodash@^4.3.0: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d" integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg== -macos-release@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.0.0.tgz#7dddf4caf79001a851eb4fba7fb6034f251276ab" - integrity sha512-iCM3ZGeqIzlrH7KxYK+fphlJpCCczyHXc+HhRVbEu9uNTCrzYJjvvtefzeKTCVHd5AP/aD/fzC80JZ4ZP+dQ/A== +macos-release@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.3.0.tgz#eb1930b036c0800adebccd5f17bc4c12de8bb71f" + integrity sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA== map-age-cleaner@^0.1.1: version "0.1.3" @@ -2323,12 +2445,12 @@ os-locale@^3.0.0: lcid "^2.0.0" mem "^4.0.0" -os-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.0.0.tgz#e1434dbfddb8e74b44c98b56797d951b7648a5d9" - integrity sha512-7c74tib2FsdFbQ3W+qj8Tyd1R3Z6tuVRNNxXjJcZ4NgjIEQU9N/prVMqcW29XZPXGACqaXN3jq58/6hoaoXH6g== +os-name@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" + integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== dependencies: - macos-release "^2.0.0" + macos-release "^2.2.0" windows-release "^3.1.0" os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: @@ -3168,6 +3290,11 @@ tunnel-agent@^0.6.0: dependencies: safe-buffer "^5.0.1" +tunnel@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" + integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== + tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" @@ -3231,12 +3358,12 @@ union-value@^1.0.0: is-extendable "^0.1.1" set-value "^0.4.3" -universal-user-agent@^2.0.0, universal-user-agent@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.0.3.tgz#9f6f09f9cc33de867bb720d84c08069b14937c6c" - integrity sha512-eRHEHhChCBHrZsA4WEhdgiOKgdvgrMIHwnwnqD0r5C6AO8kwKcG7qSku3iXdhvHL3YvsS9ZkSGN8h/hIpoFC8g== +universal-user-agent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.0.tgz#27da2ec87e32769619f68a14996465ea1cb9df16" + integrity sha512-eM8knLpev67iBDizr/YtqkJsF3GK8gzDc6st/WKzrTuPtcsOKW/0IdL4cnMBsU69pOx0otavLWBDGTwg+dB0aA== dependencies: - os-name "^3.0.0" + os-name "^3.1.0" universalify@^0.1.0: version "0.1.2" @@ -3268,11 +3395,6 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= -url-template@^2.0.8: - version "2.0.8" - resolved "https://registry.yarnpkg.com/url-template/-/url-template-2.0.8.tgz#fc565a3cccbff7730c775f5641f9555791439f21" - integrity sha1-/FZaPMy/93MMd19WQflVV5FDnyE= - use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" From d6624eaa6e888c4ddbc5de0542dab269eee97a10 Mon Sep 17 00:00:00 2001 From: Kohei Hasegawa Date: Sun, 2 Feb 2020 14:50:44 +0900 Subject: [PATCH 4/7] Add esModuleInterop --- tsconfig.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tsconfig.json b/tsconfig.json index 6105bdb..1c41390 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,6 +5,7 @@ "allowJs": true, "importHelpers": true, "strict": true, - "skipLibCheck": true + "skipLibCheck": true, + "esModuleInterop": true } } From a288b87833f005bb0d7ddd7efca706c1f9edff31 Mon Sep 17 00:00:00 2001 From: Kohei Hasegawa Date: Sun, 2 Feb 2020 14:50:52 +0900 Subject: [PATCH 5/7] Add action.yml --- action.yml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 action.yml diff --git a/action.yml b/action.yml new file mode 100644 index 0000000..e29ab5a --- /dev/null +++ b/action.yml @@ -0,0 +1,14 @@ +name: 'autolabel' +description: 'Add labels to Pull Request based on matched file patterns' +branding: + icon: 'flag' + color: 'gray-dark' +inputs: + configPath: + description: 'A path for config file' + default: '.github/auto-label.json' +runs: + using: 'docker' + image: 'Dockerfile' + args: + - ${{ inputs.configPath }} From ff30e3f6bdad25aab7fa27129ddaf42167aa9736 Mon Sep 17 00:00:00 2001 From: Kohei Hasegawa Date: Sun, 2 Feb 2020 14:52:38 +0900 Subject: [PATCH 6/7] yarn build --- dist/entrypoint.js | 237 +++++++++++++++++++++++++++------------------ 1 file changed, 143 insertions(+), 94 deletions(-) diff --git a/dist/entrypoint.js b/dist/entrypoint.js index fed26da..572b0d0 100644 --- a/dist/entrypoint.js +++ b/dist/entrypoint.js @@ -5,102 +5,152 @@ ___scope___.file("entrypoint.js", function(exports, require, module, __filename, "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -const fs = require("fs"); -const path = require("path"); -const actions_toolkit_1 = require("actions-toolkit"); -const query_1 = require("./query"); +const tslib_1 = require("tslib"); +const fs = tslib_1.__importStar(require("fs")); +const path = tslib_1.__importStar(require("path")); +const util = tslib_1.__importStar(require("util")); +const core = tslib_1.__importStar(require("@actions/core")); +const github = tslib_1.__importStar(require("@actions/github")); +const graphql_1 = require("@octokit/graphql"); +const ignore_1 = tslib_1.__importDefault(require("ignore")); const util_1 = require("./util"); -const util = require("util"); -const ignore_1 = require("ignore"); +const query_1 = require("./query"); const exec = util.promisify(require('child_process').exec); -const configFile = '.github/auto-label.json'; -const tools = new actions_toolkit_1.Toolkit({ - event: ['pull_request.opened', 'pull_request.synchronize'], -}); -(async () => { - if (!fs.existsSync(path.join(tools.workspace, configFile))) { - tools.exit.neutral('config file does not exist.'); - } - const config = JSON.parse(tools.getFile(configFile)); - let result; +async function run() { try { - result = await query_1.getPullRequestAndLabels(tools, tools.context.issue()); - } - catch (error) { - console.error('Request failed: ', error.request, error.message); - tools.exit.failure('getPullRequestAndLabels has been failed.'); - } - console.log('Result: ', result); - const allLabels = result.repository.labels.edges.reduce((acc, edge) => { - acc[edge.node.name] = edge.node.id; - return acc; - }, {}); - const currentLabelNames = new Set(result.repository.pullRequest.labels.edges.map((edge) => edge.node.name)); - const { headRefOid, baseRefOid } = result.repository.pullRequest; - // TODO: handle stderr - const { stdout, stderr } = await exec(`git merge-base --is-ancestor ${baseRefOid} ${headRefOid} && git diff --name-only ${baseRefOid} || git diff --name-only $(git merge-base ${baseRefOid} ${headRefOid})`); - const diffFiles = stdout.trim().split('\n'); - const newLabelNames = new Set(diffFiles.reduce((acc, file) => { - Object.entries(config.rules).forEach(([label, pattern]) => { - if (ignore_1.default() - .add(pattern) - .ignores(file)) { - acc.push(label); - } + const token = process.env['GITHUB_TOKEN']; + if (!token) { + core.setFailed('GITHUB_TOKEN does not exist.'); + return; + } + const graphqlWithAuth = graphql_1.graphql.defaults({ + headers: { authorization: `token ${token}` }, }); - return acc; - }, [])); - const ruledLabelNames = new Set(Object.keys(config.rules)); - const labelNamesToAdd = new Set([...newLabelNames].filter(labelName => !currentLabelNames.has(labelName))); - const labelNamesToRemove = new Set([...currentLabelNames].filter((labelName) => !newLabelNames.has(labelName) && ruledLabelNames.has(labelName))); - console.log(' ---> Current status'); - console.log('allLabels: ', allLabels); - console.log('currentLabelNames: ', currentLabelNames); - console.log('diffFiles: ', diffFiles); - console.log('newLabelNames: ', newLabelNames); - console.log('ruledLabelNames: ', ruledLabelNames); - console.log('labelNamesToAdd: ', labelNamesToAdd); - console.log('labelNamesToRemove: ', labelNamesToRemove); - const labelableId = result.repository.pullRequest.id; - if (labelNamesToAdd.size > 0) { + const configPath = path.join(__dirname, core.getInput('configPath')); + if (!fs.existsSync(configPath)) { + core.setFailed(`configFile does not exist in ${configPath}.`); + } + const config = JSON.parse(fs.readFileSync(configPath).toString()); + util_1.logger.debug('config', config); + util_1.logger.debug('github.context.eventName', github.context.eventName); + if (github.context.eventName !== 'pull_request') { + return; + } + const payload = github.context + .payload; + util_1.logger.debug('payload.action', payload.action); + if (payload.action !== 'opened' && payload.action !== 'synchronize') { + return; + } + const owner = payload.repository.owner.login; + const repo = payload.repository.name; + const number = payload.pull_request.number; + let result; try { - await query_1.addLabelsToLabelable(tools, { - labelIds: util_1.getLabelIds(allLabels, [...labelNamesToAdd]), - labelableId, + result = await query_1.getPullRequestAndLabels(graphqlWithAuth, { + owner, + repo, + number, }); - console.log('Added labels: ', labelNamesToAdd); } catch (error) { - console.error('Request failed: ', error.request, error.message); - tools.exit.failure('addLabelsToLabelable has been failed. '); + error(); + core.error(`Request failed: ${JSON.stringify(error.message)}`); + core.setFailed('getPullRequestAndLabels has been failed.'); } - } - if (labelNamesToRemove.size > 0) { - try { - await query_1.removeLabelsFromLabelable(tools, { - labelIds: util_1.getLabelIds(allLabels, [ - ...labelNamesToRemove, - ]), - labelableId, + util_1.logger.debug('result', result); + if (!result) { + return core.setFailed(`result was empty: ${result}`); + } + const allLabels = result.repository.labels.edges.reduce((acc, edge) => { + acc[edge.node.name] = edge.node.id; + return acc; + }, {}); + util_1.logger.debug('allLabels', allLabels); + const currentLabelNames = new Set(result.repository.pullRequest.labels.edges.map((edge) => edge.node.name)); + util_1.logger.debug('currentLabelNames', currentLabelNames); + const { headRefOid, baseRefOid } = result.repository.pullRequest; + const { stdout } = await exec(`git fetch && git merge-base --is-ancestor ${baseRefOid} ${headRefOid} && git diff --name-only ${baseRefOid} || git diff --name-only $(git merge-base ${baseRefOid} ${headRefOid})`); + const diffFiles = stdout.trim().split('\n'); + const newLabelNames = new Set(diffFiles.reduce((acc, file) => { + Object.entries(config.rules).forEach(([label, pattern]) => { + if (ignore_1.default() + .add(pattern) + .ignores(file)) { + acc.push(label); + } }); - console.log('Removed labels: ', labelNamesToRemove); + return acc; + }, [])); + const ruledLabelNames = new Set(Object.keys(config.rules)); + const labelNamesToAdd = new Set([...newLabelNames].filter(labelName => !currentLabelNames.has(labelName))); + const labelNamesToRemove = new Set([...currentLabelNames].filter((labelName) => !newLabelNames.has(labelName) && ruledLabelNames.has(labelName))); + util_1.logger.debug('labelNamesToAdd', labelNamesToAdd); + util_1.logger.debug('labelNamesToRemove', labelNamesToRemove); + const labelableId = result.repository.pullRequest.id; + util_1.logger.debug('labelableId', labelableId); + if (labelNamesToAdd.size > 0) { + try { + await query_1.addLabelsToLabelable(graphqlWithAuth, { + labelIds: util_1.getLabelIds(allLabels, [...labelNamesToAdd]), + labelableId, + }); + console.log('Added labels: ', labelNamesToAdd); + } + catch (error) { + util_1.logger.error('Request failed', error.message); + core.setFailed('addLabelsToLabelable has been failed. '); + } } - catch (error) { - console.error('Request failed: ', error.request, error.message); - tools.exit.failure('removeLabelsFromLabelable has been failed. '); + if (labelNamesToRemove.size > 0) { + try { + await query_1.removeLabelsFromLabelable(graphqlWithAuth, { + labelIds: util_1.getLabelIds(allLabels, [ + ...labelNamesToRemove, + ]), + labelableId, + }); + console.log('Removed labels: ', labelNamesToRemove); + } + catch (error) { + util_1.logger.error('Request failed', error.message); + core.setFailed('removeLabelsFromLabelable has been failed. '); + } } } -})(); + catch (error) { + core.setFailed(error.message); + } +} +run(); + +}); +___scope___.file("util.js", function(exports, require, module, __filename, __dirname){ + +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const tslib_1 = require("tslib"); +const core = tslib_1.__importStar(require("@actions/core")); +const lodash_pick_1 = tslib_1.__importDefault(require("lodash.pick")); +exports.getLabelIds = (allLabels, labelNames) => JSON.stringify(Object.values(lodash_pick_1.default(allLabels, labelNames))); +exports.logger = { + debug: (message, object) => { + return core.debug(`${message}: ${JSON.stringify(object)}`); + }, + error: (message, object) => { + return core.error(`${message}: ${JSON.stringify(object)}`); + }, +}; }); ___scope___.file("query.js", function(exports, require, module, __filename, __dirname){ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getPullRequestAndLabels = (tools, { owner, repo, number, }) => { - const query = `{ - repository(owner: "${owner}", name: "${repo}") { - pullRequest(number: ${number}) { +exports.getPullRequestAndLabels = (graphqlWithAuth, { owner, repo, number, }) => { + const query = `query pullRequestAndLabels($owner: String!, $repo: String!, $number: Int!) { + repository(owner:$owner, name:$repo) { + pullRequest(number:$number) { id baseRefOid headRefOid @@ -131,41 +181,40 @@ exports.getPullRequestAndLabels = (tools, { owner, repo, number, }) => { resetAt } }`; - return tools.github.graphql(query, { + return graphqlWithAuth(query, { + owner, + repo, + number, headers: { Accept: 'application/vnd.github.ocelot-preview+json' }, }); }; -exports.addLabelsToLabelable = (tools, { labelIds, labelableId, }) => { +exports.addLabelsToLabelable = (graphqlWithAuth, { labelIds, labelableId, }) => { const query = ` - mutation { - addLabelsToLabelable(input: {labelIds: ${labelIds}, labelableId: "${labelableId}"}) { + mutation addLabelsToLabelable($labelIds: String!, $labelableId: String!) { + addLabelsToLabelable(input: {labelIds:$labelIds, labelableId:$labelableId}) { clientMutationId } }`; - return tools.github.graphql(query, { + return graphqlWithAuth(query, { + labelIds, + labelableId, headers: { Accept: 'application/vnd.github.starfire-preview+json' }, }); }; -exports.removeLabelsFromLabelable = (tools, { labelIds, labelableId, }) => { +exports.removeLabelsFromLabelable = (graphqlWithAuth, { labelIds, labelableId, }) => { const query = ` - mutation { - removeLabelsFromLabelable(input: {labelIds: ${labelIds}, labelableId: "${labelableId}"}) { + mutation removeLabelsFromLabelable($labelIds: String!, $labelableId: String!) { + removeLabelsFromLabelable(input: {labelIds:$labelIds, labelableId:$labelableId}) { clientMutationId } }`; - return tools.github.graphql(query, { + return graphqlWithAuth(query, { + labelIds, + labelableId, headers: { Accept: 'application/vnd.github.starfire-preview+json' }, }); }; -}); -___scope___.file("util.js", function(exports, require, module, __filename, __dirname){ - -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -const lodash_1 = require("lodash"); -exports.getLabelIds = (allLabels, labelNames) => JSON.stringify(Object.values(lodash_1.pick(allLabels, labelNames))); - }); return ___scope___.entry = "entrypoint.js"; }); From 1a740c3530c7b3c6489c0aaf438f12f587430c1e Mon Sep 17 00:00:00 2001 From: Kohei Hasegawa Date: Sun, 2 Feb 2020 15:01:29 +0900 Subject: [PATCH 7/7] Update README --- README.md | 31 +++++++++++++++++++------------ 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 68032f2..8adb629 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,21 @@ ## Installation -To configure the action simply add the following lines to your `.github/main.workflow` workflow file: - -``` -workflow "auto-label" { - on = "pull_request" - resolves = ["Auto label"] -} - -action "Auto label" { - uses = "banyan/auto-label@master" - secrets = ["GITHUB_TOKEN"] -} +To configure the action simply add the following lines to your `.github/workflows/auto-label.yml` file: + +```yaml +name: Auto Label +on: pull_request + +jobs: + auto-label: + name: Auto Label + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: banyan/auto-label@master + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ``` And configure by creating `.github/auto-label.json` file. @@ -43,6 +46,10 @@ Pattern matching is following `.gitignore` [spec](https://git-scm.com/docs/gitig * If there's no adding / removing labels, it will only consumes 1 point of rate limit score. * https://developer.github.com/v4/guides/resource-limitations/ +## Tips + +* In case if you want to debug the response quickly, just set `ACTIONS_STEP_DEBUG` as `true` on Secrets from Settings of GitHub. + ### TODO * Handle pagination of label (currently only handles 100)