From c94eaca376481b5723ea200d4ba4fbc66826001f Mon Sep 17 00:00:00 2001 From: Amacado Date: Mon, 7 Oct 2019 23:37:02 +0200 Subject: [PATCH 01/10] Don't apply default config when custom config is provided (solves #12) --- src/action.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/action.js b/src/action.js index e3041b43..056b9854 100644 --- a/src/action.js +++ b/src/action.js @@ -25,10 +25,16 @@ async function action(context = github.context) { ) } - const ref = context.payload.pull_request.head.ref - const config = { - ...defaults, - ...(await getConfig(octokit, CONFIG_FILENAME, repoInfo, ref)) + const ref = context.payload.pull_request.head.ref; + + /** + * load custom config when existing or + * set default config when no custom overwrite exists + */ + var config = defaults; + var customConfig = await getConfig(octokit, CONFIG_FILENAME, repoInfo, ref); + if(customConfig !== null) { + config = customConfig; } const labelsToAdd = Object.entries(config).reduce( From 7edaa414d3d4e4968b67b12945d1c36e46266329 Mon Sep 17 00:00:00 2001 From: Clemens Bastian <8781699+amacado@users.noreply.github.com> Date: Tue, 8 Oct 2019 00:03:30 +0200 Subject: [PATCH 02/10] Add configuration for custom path of .yml configuration file (solves #15) --- src/action.js | 10 ++++++++-- src/utils/config.js | 4 +--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/action.js b/src/action.js index 056b9854..0c29cfe3 100644 --- a/src/action.js +++ b/src/action.js @@ -3,7 +3,6 @@ const github = require('@actions/github') const matcher = require('matcher') const getConfig = require('./utils/config') -const CONFIG_FILENAME = 'pr-labeler.yml' const defaults = { feature: ['feature/*', 'feat/*'], fix: 'fix/*', @@ -12,6 +11,13 @@ const defaults = { async function action(context = github.context) { try { + + var customConfigFile = '.github/pr-labeler.yml'; // default path of config file + // if env variable CONFIG_FILENAME isset use it as the path to a custom pr-labeler config yml + if(process.env.CONFIG_FILENAME !== null) { + customConfigFile = process.env.CONFIG_FILENAME; + } + const GITHUB_TOKEN = process.env.GITHUB_TOKEN const octokit = new github.GitHub(GITHUB_TOKEN) const repoInfo = { @@ -32,7 +38,7 @@ async function action(context = github.context) { * set default config when no custom overwrite exists */ var config = defaults; - var customConfig = await getConfig(octokit, CONFIG_FILENAME, repoInfo, ref); + var customConfig = await getConfig(octokit, customConfigFile, repoInfo, ref); if(customConfig !== null) { config = customConfig; } diff --git a/src/utils/config.js b/src/utils/config.js index 21440d1a..bbf46bf1 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -1,7 +1,5 @@ -const path = require('path') const yaml = require('js-yaml') -const CONFIG_PATH = '.github' /** * @returns {Promise>} @@ -11,7 +9,7 @@ module.exports = async function getConfig(github, fileName, { owner, repo }, ref const response = await github.repos.getContents({ owner, repo, - path: path.posix.join(CONFIG_PATH, fileName), + path: fileName, ref }) From e9ab8f4e579972000e4e35e211e640d2d3b4dbaf Mon Sep 17 00:00:00 2001 From: Amacado Date: Tue, 8 Oct 2019 00:12:22 +0200 Subject: [PATCH 03/10] add example of using custom path for configuration (#15) --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5fa56799..23e492e3 100644 --- a/README.md +++ b/README.md @@ -22,11 +22,13 @@ jobs: - uses: TimonVS/pr-labeler-action@v3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CONFIG_FILENAME: ".github/pr-labeler.yml" # optional, .github/pr-labeler.yml is the default value ``` ## Configuration -Configure by creating a `.github/pr-labeler.yml` file. +Configure by creating a `.github/pr-labeler.yml` file or choose another filename and path with setting `env.CONFIG_FILENAME` to a different value. When you dont +create a filename at the default path (or your custom path) the [default configuration](#default-configuration) will be used. For example: @@ -43,6 +45,16 @@ Then if a pull request is opened with the branch name `feature/218-add-emoji-sup You can use `*` as a wildcard for matching multiple branch names. See https://www.npmjs.com/package/matcher for more information about wildcard options. +### Default configuration + +When no custom configuration is set the following default configuration will be used: + +```yml +feature: ['feature/*', 'feat/*'], +fix: 'fix/*', +chore: 'chore/*' +``` + ## Contributors ✨ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)): From f949943b96c29cd34e48d645cb335b7c1499450a Mon Sep 17 00:00:00 2001 From: Timon van Spronsen Date: Wed, 23 Oct 2019 20:27:02 +0200 Subject: [PATCH 04/10] Formatting --- src/action.js | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/src/action.js b/src/action.js index 0c29cfe3..c02e0b28 100644 --- a/src/action.js +++ b/src/action.js @@ -11,11 +11,10 @@ const defaults = { async function action(context = github.context) { try { - - var customConfigFile = '.github/pr-labeler.yml'; // default path of config file + var customConfigFile = '.github/pr-labeler.yml' // default path of config file // if env variable CONFIG_FILENAME isset use it as the path to a custom pr-labeler config yml - if(process.env.CONFIG_FILENAME !== null) { - customConfigFile = process.env.CONFIG_FILENAME; + if (process.env.CONFIG_FILENAME !== null) { + customConfigFile = process.env.CONFIG_FILENAME } const GITHUB_TOKEN = process.env.GITHUB_TOKEN @@ -31,32 +30,29 @@ async function action(context = github.context) { ) } - const ref = context.payload.pull_request.head.ref; + const ref = context.payload.pull_request.head.ref /** * load custom config when existing or * set default config when no custom overwrite exists */ - var config = defaults; - var customConfig = await getConfig(octokit, customConfigFile, repoInfo, ref); - if(customConfig !== null) { - config = customConfig; + var config = defaults + var customConfig = await getConfig(octokit, customConfigFile, repoInfo, ref) + if (customConfig !== null) { + config = customConfig } - const labelsToAdd = Object.entries(config).reduce( - (labels, [label, patterns]) => { - if ( - Array.isArray(patterns) - ? patterns.some(pattern => matcher.isMatch(ref, pattern)) - : matcher.isMatch(ref, patterns) - ) { - labels.push(label) - } + const labelsToAdd = Object.entries(config).reduce((labels, [label, patterns]) => { + if ( + Array.isArray(patterns) + ? patterns.some(pattern => matcher.isMatch(ref, pattern)) + : matcher.isMatch(ref, patterns) + ) { + labels.push(label) + } - return labels - }, - [] - ) + return labels + }, []) if (labelsToAdd.length > 0) { await octokit.issues.addLabels({ From 6bf0e9222c6f33e473a9c9acf30ae3963cbcb920 Mon Sep 17 00:00:00 2001 From: Timon van Spronsen Date: Wed, 23 Oct 2019 21:12:38 +0200 Subject: [PATCH 05/10] Pass configuration path as parameter instead of env variable and return default config on 404 --- .vscode/settings.json | 6 ++++-- __tests__/action.test.js | 24 ++++++++++++++++++++++++ __tests__/utils/config.test.js | 23 +++++++++++++++++++++++ action.yml | 4 ++++ fixtures/config.yml | 1 + package-lock.json | 6 ++++++ package.json | 1 + src/action.js | 22 +++++----------------- src/utils/config.js | 5 ++--- 9 files changed, 70 insertions(+), 22 deletions(-) create mode 100644 __tests__/utils/config.test.js diff --git a/.vscode/settings.json b/.vscode/settings.json index cac0e10e..eec4fcb7 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,5 @@ { - "editor.formatOnSave": true -} \ No newline at end of file + "editor.formatOnSave": true, + "createTests.defaultLocationForTestFiles": "project root", + "createTests.testDirectoryName": "__tests__" +} diff --git a/__tests__/action.test.js b/__tests__/action.test.js index f3bbb3a9..6c1ff390 100644 --- a/__tests__/action.test.js +++ b/__tests__/action.test.js @@ -5,6 +5,12 @@ const action = require('../src/action') nock.disableNetConnect() describe('pr-labeler-action', () => { + beforeEach(() => { + // configuration-path parameter is required + // parameters are exposed as environment variables: https://help.github.com/en/github/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepswith + process.env['INPUT_CONFIGURATION-PATH'] = '.github/pr-labeler.yml' + }) + it('adds the "fix" label for "fix/510-logging" branch', async () => { nock('https://api.github.com') .get('/repos/Codertocat/Hello-World/contents/.github/pr-labeler.yml?ref=fix%2F510-logging') @@ -41,6 +47,24 @@ describe('pr-labeler-action', () => { expect.assertions(1) }) + it('adds the "release" label for "release/2.0" branch', async () => { + nock('https://api.github.com') + .get('/repos/Codertocat/Hello-World/contents/.github/pr-labeler.yml?ref=release%2F2.0') + .reply(200, configFixture()) + .post('/repos/Codertocat/Hello-World/issues/1/labels', body => { + expect(body).toMatchObject({ + labels: ['release'] + }) + return true + }) + .reply(200) + + await action({ + payload: pullRequestOpenedFixture({ ref: 'release/2.0' }) + }) + expect.assertions(1) + }) + it('uses the default config when no config was provided', async () => { nock('https://api.github.com') .get('/repos/Codertocat/Hello-World/contents/.github/pr-labeler.yml?ref=fix%2F510-logging') diff --git a/__tests__/utils/config.test.js b/__tests__/utils/config.test.js new file mode 100644 index 00000000..c827973c --- /dev/null +++ b/__tests__/utils/config.test.js @@ -0,0 +1,23 @@ +const getConfig = require('../../src/utils/config') + +describe('getConfig', () => { + it('returns default config when GitHub returns a 404 for given path', async () => { + const defaultConfig = { + foo: 'bar' + } + + const githubMock = { + repos: { + getContents() { + const notFoundError = new Error() + notFoundError.code = 404 + throw notFoundError + } + } + } + + const config = await getConfig(githubMock, 'a', { owner: '', repo: '' }, null, defaultConfig) + + expect(config).toBe(defaultConfig) + }) +}) diff --git a/action.yml b/action.yml index ceb0a177..21f7f089 100644 --- a/action.yml +++ b/action.yml @@ -1,6 +1,10 @@ name: 'PR Labeler' description: 'Automatically labels your PRs based on branch name patterns like feature/* or fix/*.' author: 'Timon van Spronsen' +inputs: + configuration-path: + description: 'The path for the label configurations' + default: '.github/pr-labeler.yml' branding: icon: 'tag' color: 'white' diff --git a/fixtures/config.yml b/fixtures/config.yml index 1d506383..7de911e1 100644 --- a/fixtures/config.yml +++ b/fixtures/config.yml @@ -1,3 +1,4 @@ feature: ['feature/*', 'feat/*'] fix: fix/* chore: chore/* +release: release/* diff --git a/package-lock.json b/package-lock.json index 53a69807..4110520b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -493,6 +493,12 @@ "integrity": "sha512-eAtOAFZefEnfJiRFQBGw1eYqa5GTLCZ1y86N0XSI/D6EB+E8z6VPV/UL7Gi5UEclFqoQk+6NRqEDsfmDLXn8sg==", "dev": true }, + "@types/node": { + "version": "12.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.11.5.tgz", + "integrity": "sha512-LC8ALj/24PhByn39nr5jnTvpE7MujK8y7LQmV74kHYF5iQ0odCPkMH4IZNZw+cobKfSXqaC8GgegcbIsQpffdA==", + "dev": true + }, "@types/stack-utils": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", diff --git a/package.json b/package.json index 4199db4a..901c1fc8 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "matcher": "^2.0.0" }, "devDependencies": { + "@types/node": "^12.11.5", "@zeit/ncc": "^0.20.5", "jest": "^24.5.0", "js-yaml": "^3.13.1", diff --git a/src/action.js b/src/action.js index c02e0b28..1b2ebf43 100644 --- a/src/action.js +++ b/src/action.js @@ -1,9 +1,11 @@ +// @ts-check + const core = require('@actions/core') const github = require('@actions/github') const matcher = require('matcher') const getConfig = require('./utils/config') -const defaults = { +const defaultConfig = { feature: ['feature/*', 'feat/*'], fix: 'fix/*', chore: 'chore/*' @@ -11,18 +13,13 @@ const defaults = { async function action(context = github.context) { try { - var customConfigFile = '.github/pr-labeler.yml' // default path of config file - // if env variable CONFIG_FILENAME isset use it as the path to a custom pr-labeler config yml - if (process.env.CONFIG_FILENAME !== null) { - customConfigFile = process.env.CONFIG_FILENAME - } - const GITHUB_TOKEN = process.env.GITHUB_TOKEN const octokit = new github.GitHub(GITHUB_TOKEN) const repoInfo = { owner: context.payload.repository.owner.login, repo: context.payload.repository.name } + const configPath = core.getInput('configuration-path', { required: true }) if (!context.payload.pull_request) { throw new Error( @@ -31,16 +28,7 @@ async function action(context = github.context) { } const ref = context.payload.pull_request.head.ref - - /** - * load custom config when existing or - * set default config when no custom overwrite exists - */ - var config = defaults - var customConfig = await getConfig(octokit, customConfigFile, repoInfo, ref) - if (customConfig !== null) { - config = customConfig - } + const config = await getConfig(octokit, configPath, repoInfo, ref, defaultConfig) const labelsToAdd = Object.entries(config).reduce((labels, [label, patterns]) => { if ( diff --git a/src/utils/config.js b/src/utils/config.js index bbf46bf1..9bd99a1b 100644 --- a/src/utils/config.js +++ b/src/utils/config.js @@ -1,10 +1,9 @@ const yaml = require('js-yaml') - /** * @returns {Promise>} */ -module.exports = async function getConfig(github, fileName, { owner, repo }, ref) { +module.exports = async function getConfig(github, fileName, { owner, repo }, ref, defaultConfig) { try { const response = await github.repos.getContents({ owner, @@ -16,7 +15,7 @@ module.exports = async function getConfig(github, fileName, { owner, repo }, ref return parseConfig(response.data.content) } catch (error) { if (error.code === 404) { - return null + return defaultConfig } throw error From 6408292d9b2dcd226520613129e6ce2f230521d5 Mon Sep 17 00:00:00 2001 From: Timon van Spronsen Date: Wed, 23 Oct 2019 21:28:01 +0200 Subject: [PATCH 06/10] Add test for label with a space --- __tests__/action.test.js | 2 +- fixtures/config.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/action.test.js b/__tests__/action.test.js index 6c1ff390..4599c849 100644 --- a/__tests__/action.test.js +++ b/__tests__/action.test.js @@ -35,7 +35,7 @@ describe('pr-labeler-action', () => { .reply(200, configFixture()) .post('/repos/Codertocat/Hello-World/issues/1/labels', body => { expect(body).toMatchObject({ - labels: ['feature'] + labels: ['🎉 feature'] }) return true }) diff --git a/fixtures/config.yml b/fixtures/config.yml index 7de911e1..04574e6b 100644 --- a/fixtures/config.yml +++ b/fixtures/config.yml @@ -1,4 +1,4 @@ -feature: ['feature/*', 'feat/*'] +'🎉 feature': ['feature/*', 'feat/*'] fix: fix/* chore: chore/* release: release/* From 6da891c219de27870645bce48f8df980bad817fe Mon Sep 17 00:00:00 2001 From: Timon van Spronsen Date: Wed, 23 Oct 2019 21:37:41 +0200 Subject: [PATCH 07/10] Update README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 23e492e3..927ddc70 100644 --- a/README.md +++ b/README.md @@ -20,15 +20,15 @@ jobs: runs-on: ubuntu-latest steps: - uses: TimonVS/pr-labeler-action@v3 + with: + configuration-path: .github/pr-labeler.yml # optional, .github/pr-labeler.yml is the default value env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - CONFIG_FILENAME: ".github/pr-labeler.yml" # optional, .github/pr-labeler.yml is the default value ``` ## Configuration -Configure by creating a `.github/pr-labeler.yml` file or choose another filename and path with setting `env.CONFIG_FILENAME` to a different value. When you dont -create a filename at the default path (or your custom path) the [default configuration](#default-configuration) will be used. +Configure by creating a `.github/pr-labeler.yml` file. For example: @@ -47,7 +47,7 @@ You can use `*` as a wildcard for matching multiple branch names. See https://ww ### Default configuration -When no custom configuration is set the following default configuration will be used: +When no configuration is provided, the following defaults will be used: ```yml feature: ['feature/*', 'feat/*'], From 5df26f9bc688d765094420e2addbaea24f9ab3bb Mon Sep 17 00:00:00 2001 From: Timon van Spronsen Date: Sun, 27 Oct 2019 16:24:30 +0100 Subject: [PATCH 08/10] Fix config test --- __tests__/utils/config.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/__tests__/utils/config.test.js b/__tests__/utils/config.test.js index c827973c..7bb7523e 100644 --- a/__tests__/utils/config.test.js +++ b/__tests__/utils/config.test.js @@ -1,4 +1,4 @@ -const getConfig = require('../../src/utils/config') +const getConfig = require('../../src/utils/config').default describe('getConfig', () => { it('returns default config when GitHub returns a 404 for given path', async () => { @@ -10,7 +10,7 @@ describe('getConfig', () => { repos: { getContents() { const notFoundError = new Error() - notFoundError.code = 404 + notFoundError.status = 404 throw notFoundError } } From c4d11ba5a00c622dcee861abde69224e6059381c Mon Sep 17 00:00:00 2001 From: Timon van Spronsen Date: Sun, 27 Oct 2019 16:27:33 +0100 Subject: [PATCH 09/10] Fix config path --- src/utils/config.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/utils/config.ts b/src/utils/config.ts index bd564f3a..78455af7 100644 --- a/src/utils/config.ts +++ b/src/utils/config.ts @@ -1,7 +1,5 @@ -import path from 'path' import yaml from 'js-yaml' import { GitHub } from '@actions/github' -const CONFIG_PATH = '.github' export interface RepoInfo { owner: string @@ -14,7 +12,7 @@ interface Config { export default async function getConfig( github: GitHub, - fileName: string, + path: string, { owner, repo }: RepoInfo, ref: string, defaultConfig: Config @@ -23,7 +21,7 @@ export default async function getConfig( const response = await github.repos.getContents({ owner, repo, - path: path.posix.join(CONFIG_PATH, fileName), + path, ref }) From ff9b1f1472d5d01e0d5ff929306227f38956fc60 Mon Sep 17 00:00:00 2001 From: Timon van Spronsen Date: Sun, 27 Oct 2019 16:36:36 +0100 Subject: [PATCH 10/10] Convert config test to TS --- __tests__/utils/config.test.js | 23 ----------------------- __tests__/utils/config.test.ts | 31 +++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 23 deletions(-) delete mode 100644 __tests__/utils/config.test.js create mode 100644 __tests__/utils/config.test.ts diff --git a/__tests__/utils/config.test.js b/__tests__/utils/config.test.js deleted file mode 100644 index 7bb7523e..00000000 --- a/__tests__/utils/config.test.js +++ /dev/null @@ -1,23 +0,0 @@ -const getConfig = require('../../src/utils/config').default - -describe('getConfig', () => { - it('returns default config when GitHub returns a 404 for given path', async () => { - const defaultConfig = { - foo: 'bar' - } - - const githubMock = { - repos: { - getContents() { - const notFoundError = new Error() - notFoundError.status = 404 - throw notFoundError - } - } - } - - const config = await getConfig(githubMock, 'a', { owner: '', repo: '' }, null, defaultConfig) - - expect(config).toBe(defaultConfig) - }) -}) diff --git a/__tests__/utils/config.test.ts b/__tests__/utils/config.test.ts new file mode 100644 index 00000000..cd6f2151 --- /dev/null +++ b/__tests__/utils/config.test.ts @@ -0,0 +1,31 @@ +import getConfig from '../../src/utils/config' + +describe('getConfig', () => { + it('returns default config when GitHub returns a 404 for given path', async () => { + const defaultConfig = { + foo: 'bar' + } + + const githubMock = { + repos: { + getContents() { + throw new HTTPError(404) + } + } + } + + const config = await getConfig( + githubMock as any, + 'path/to/config', + { owner: 'repo-owner', repo: 'repo-name' }, + 'ref', + defaultConfig + ) + + expect(config).toBe(defaultConfig) + }) +}) + +class HTTPError { + constructor(public status: number) {} +}