mirror of
https://github.com/actions/labeler.git
synced 2025-12-11 20:24:51 +00:00
Added output (#60)
* Added output * removed formatting changes * more formatting changes * Fix merge conflicts * Small test refactoring * tests are passing * Add a test * Add a small jest mock for addLabels. Not used. * Add tests for more cases * get rid of an unused jest mock * fix review points * rebuild + minor README fix * fix review points * update tests * fix formatting * add tests, fix bug * cleanup --------- Co-authored-by: Daniel Shteremberg <dshteremberg@labelbox.com> Co-authored-by: Daniel Shteremberg <Daniel@Daniel-Shterembergs-MacBook-Pro.local> Co-authored-by: Patrick Ellis <patrick.j.ellis@gmail.com> Co-authored-by: Andrey Lobanovich <andrei.lobanovich@akvelon.com>
This commit is contained in:
committed by
GitHub
parent
375538a703
commit
0967ca812e
50
README.md
50
README.md
@@ -109,12 +109,12 @@ jobs:
|
|||||||
|
|
||||||
Various inputs are defined in [`action.yml`](action.yml) to let you configure the labeler:
|
Various inputs are defined in [`action.yml`](action.yml) to let you configure the labeler:
|
||||||
|
|
||||||
| Name | Description | Default |
|
| Name | Description | Default |
|
||||||
| - | - | - |
|
|----------------------|-------------------------------------------------------------------------------------------------|-----------------------|
|
||||||
| `repo-token` | Token to use to authorize label changes. Typically the `GITHUB_TOKEN` secret, with `contents:read` and `pull-requests:write` access | `github.token` |
|
| `repo-token` | Token to use to authorize label changes. Typically the GITHUB_TOKEN secret | N/A |
|
||||||
| `configuration-path` | The path to the label configuration file | `.github/labeler.yml` |
|
| `configuration-path` | The path to the label configuration file | `.github/labeler.yml` |
|
||||||
| `sync-labels` | Whether or not to remove labels when matching files are reverted or no longer changed by the PR | `false` |
|
| `sync-labels` | Whether or not to remove labels when matching files are reverted or no longer changed by the PR | `false` |
|
||||||
| `dot` | Whether or not to auto-include paths starting with dot (e.g. `.github`) | `false` |
|
| `dot` | Whether or not to auto-include paths starting with dot (e.g. `.github`) | `false` |
|
||||||
|
|
||||||
When `dot` is disabled and you want to include _all_ files in a folder:
|
When `dot` is disabled and you want to include _all_ files in a folder:
|
||||||
|
|
||||||
@@ -131,6 +131,44 @@ label1:
|
|||||||
- path/to/folder/**
|
- path/to/folder/**
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### Outputs
|
||||||
|
|
||||||
|
Labeler provides the following outputs:
|
||||||
|
|
||||||
|
| Name | Description |
|
||||||
|
|--------------|-----------------------------------------------------------|
|
||||||
|
| `new-labels` | A comma-separated list of all new labels |
|
||||||
|
| `all-labels` | A comma-separated list of all labels that the PR contains |
|
||||||
|
|
||||||
|
The following example performs steps based on the output of labeler:
|
||||||
|
```yml
|
||||||
|
name: "My workflow"
|
||||||
|
on:
|
||||||
|
- pull_request_target
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
triage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- id: label-the-PR
|
||||||
|
uses: actions/labeler@v3
|
||||||
|
|
||||||
|
- id: run-frontend-tests
|
||||||
|
if: contains(fromJson(steps.label-the-PR.outputs.all-labels), 'frontend')
|
||||||
|
run: |
|
||||||
|
echo "Running frontend tests..."
|
||||||
|
# Put your commands for running frontend tests here
|
||||||
|
|
||||||
|
- id: run-backend-tests
|
||||||
|
if: contains(fromJson(steps.label-the-PR.outputs.all-labels), 'backend')
|
||||||
|
run: |
|
||||||
|
echo "Running backend tests..."
|
||||||
|
# Put your commands for running backend tests here
|
||||||
|
```
|
||||||
|
|
||||||
## Permissions
|
## Permissions
|
||||||
|
|
||||||
In order to add labels to pull requests, the GitHub labeler action requires
|
In order to add labels to pull requests, the GitHub labeler action requires
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ const reposMock = jest.spyOn(gh.rest.repos, 'getContent');
|
|||||||
const paginateMock = jest.spyOn(gh, 'paginate');
|
const paginateMock = jest.spyOn(gh, 'paginate');
|
||||||
const getPullMock = jest.spyOn(gh.rest.pulls, 'get');
|
const getPullMock = jest.spyOn(gh.rest.pulls, 'get');
|
||||||
const coreWarningMock = jest.spyOn(core, 'warning');
|
const coreWarningMock = jest.spyOn(core, 'warning');
|
||||||
|
const setOutputSpy = jest.spyOn(core, 'setOutput');
|
||||||
|
|
||||||
const yamlFixtures = {
|
const yamlFixtures = {
|
||||||
'only_pdfs.yml': fs.readFileSync('__tests__/fixtures/only_pdfs.yml')
|
'only_pdfs.yml': fs.readFileSync('__tests__/fixtures/only_pdfs.yml')
|
||||||
@@ -50,12 +51,21 @@ describe('run', () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(setLabelsMock).toHaveBeenCalledTimes(1);
|
expect(setLabelsMock).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
expect(setLabelsMock).toHaveBeenCalledWith({
|
expect(setLabelsMock).toHaveBeenCalledWith({
|
||||||
owner: 'monalisa',
|
owner: 'monalisa',
|
||||||
repo: 'helloworld',
|
repo: 'helloworld',
|
||||||
issue_number: 123,
|
issue_number: 123,
|
||||||
labels: ['touched-a-pdf-file']
|
labels: ['touched-a-pdf-file']
|
||||||
});
|
});
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'new-labels',
|
||||||
|
'touched-a-pdf-file'
|
||||||
|
);
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'all-labels',
|
||||||
|
'touched-a-pdf-file'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('(with dot: true) adds labels to PRs that match our glob patterns', async () => {
|
it('(with dot: true) adds labels to PRs that match our glob patterns', async () => {
|
||||||
@@ -77,6 +87,14 @@ describe('run', () => {
|
|||||||
issue_number: 123,
|
issue_number: 123,
|
||||||
labels: ['touched-a-pdf-file']
|
labels: ['touched-a-pdf-file']
|
||||||
});
|
});
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'new-labels',
|
||||||
|
'touched-a-pdf-file'
|
||||||
|
);
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'all-labels',
|
||||||
|
'touched-a-pdf-file'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('(with dot: false) does not add labels to PRs that do not match our glob patterns', async () => {
|
it('(with dot: false) does not add labels to PRs that do not match our glob patterns', async () => {
|
||||||
@@ -92,6 +110,8 @@ describe('run', () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(setLabelsMock).toHaveBeenCalledTimes(0);
|
expect(setLabelsMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('new-labels', '');
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('all-labels', '');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('(with dot: true) does not add labels to PRs that do not match our glob patterns', async () => {
|
it('(with dot: true) does not add labels to PRs that do not match our glob patterns', async () => {
|
||||||
@@ -128,6 +148,8 @@ describe('run', () => {
|
|||||||
issue_number: 123,
|
issue_number: 123,
|
||||||
labels: ['manually-added']
|
labels: ['manually-added']
|
||||||
});
|
});
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('new-labels', '');
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('all-labels', 'manually-added');
|
||||||
});
|
});
|
||||||
|
|
||||||
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 () => {
|
||||||
@@ -148,6 +170,11 @@ describe('run', () => {
|
|||||||
await run();
|
await run();
|
||||||
|
|
||||||
expect(setLabelsMock).toHaveBeenCalledTimes(0);
|
expect(setLabelsMock).toHaveBeenCalledTimes(0);
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('new-labels', '');
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith(
|
||||||
|
'all-labels',
|
||||||
|
'touched-a-pdf-file,manually-added'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('(with sync-labels: false) it only logs the excess labels', async () => {
|
it('(with sync-labels: false) it only logs the excess labels', async () => {
|
||||||
@@ -178,6 +205,9 @@ describe('run', () => {
|
|||||||
'Maximum of 100 labels allowed. Excess labels: touched-a-pdf-file',
|
'Maximum of 100 labels allowed. Excess labels: touched-a-pdf-file',
|
||||||
{title: 'Label limit for a PR exceeded'}
|
{title: 'Label limit for a PR exceeded'}
|
||||||
);
|
);
|
||||||
|
const allLabels: string = existingLabels.map(i => i.name).join(',');
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('new-labels', '');
|
||||||
|
expect(setOutputSpy).toHaveBeenCalledWith('all-labels', allLabels);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,11 @@ inputs:
|
|||||||
default: false
|
default: false
|
||||||
required: false
|
required: false
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
new-labels:
|
||||||
|
description: 'A comma-separated list of all new labels'
|
||||||
|
all-labels:
|
||||||
|
description: 'A comma-separated list of all labels that the PR contains'
|
||||||
runs:
|
runs:
|
||||||
using: 'node16'
|
using: 'node16'
|
||||||
main: 'dist/index.js'
|
main: 'dist/index.js'
|
||||||
|
|||||||
14
dist/index.js
vendored
14
dist/index.js
vendored
@@ -68,8 +68,8 @@ function run() {
|
|||||||
core.debug(`fetching changed files for pr #${prNumber}`);
|
core.debug(`fetching changed files for pr #${prNumber}`);
|
||||||
const changedFiles = yield getChangedFiles(client, prNumber);
|
const changedFiles = yield getChangedFiles(client, prNumber);
|
||||||
const labelGlobs = yield getLabelGlobs(client, configPath);
|
const labelGlobs = yield getLabelGlobs(client, configPath);
|
||||||
const prLabels = pullRequest.labels.map(label => label.name);
|
const preexistingLabels = pullRequest.labels.map(l => l.name);
|
||||||
const allLabels = new Set(prLabels);
|
const allLabels = new Set(preexistingLabels);
|
||||||
for (const [label, globs] of labelGlobs.entries()) {
|
for (const [label, globs] of labelGlobs.entries()) {
|
||||||
core.debug(`processing ${label}`);
|
core.debug(`processing ${label}`);
|
||||||
if (checkGlobs(changedFiles, globs, dot)) {
|
if (checkGlobs(changedFiles, globs, dot)) {
|
||||||
@@ -79,12 +79,16 @@ function run() {
|
|||||||
allLabels.delete(label);
|
allLabels.delete(label);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const labels = [...allLabels].slice(0, GITHUB_MAX_LABELS);
|
const labelsToAdd = [...allLabels].slice(0, GITHUB_MAX_LABELS);
|
||||||
const excessLabels = [...allLabels].slice(GITHUB_MAX_LABELS);
|
const excessLabels = [...allLabels].slice(GITHUB_MAX_LABELS);
|
||||||
try {
|
try {
|
||||||
if (!isListEqual(prLabels, labels)) {
|
let newLabels = [];
|
||||||
yield setLabels(client, prNumber, labels);
|
if (!isListEqual(labelsToAdd, preexistingLabels)) {
|
||||||
|
yield setLabels(client, prNumber, labelsToAdd);
|
||||||
|
newLabels = labelsToAdd.filter(l => !preexistingLabels.includes(l));
|
||||||
}
|
}
|
||||||
|
core.setOutput('new-labels', newLabels.join(','));
|
||||||
|
core.setOutput('all-labels', labelsToAdd.join(','));
|
||||||
if (excessLabels.length) {
|
if (excessLabels.length) {
|
||||||
core.warning(`Maximum of ${GITHUB_MAX_LABELS} labels allowed. Excess labels: ${excessLabels.join(', ')}`, { title: 'Label limit for a PR exceeded' });
|
core.warning(`Maximum of ${GITHUB_MAX_LABELS} labels allowed. Excess labels: ${excessLabels.join(', ')}`, { title: 'Label limit for a PR exceeded' });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,8 @@ export async function run() {
|
|||||||
configPath
|
configPath
|
||||||
);
|
);
|
||||||
|
|
||||||
const prLabels: string[] = pullRequest.labels.map(label => label.name);
|
const preexistingLabels = pullRequest.labels.map(l => l.name);
|
||||||
const allLabels: Set<string> = new Set(prLabels);
|
const allLabels: Set<string> = new Set<string>(preexistingLabels);
|
||||||
|
|
||||||
for (const [label, globs] of labelGlobs.entries()) {
|
for (const [label, globs] of labelGlobs.entries()) {
|
||||||
core.debug(`processing ${label}`);
|
core.debug(`processing ${label}`);
|
||||||
@@ -55,14 +55,20 @@ export async function run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const labels = [...allLabels].slice(0, GITHUB_MAX_LABELS);
|
const labelsToAdd = [...allLabels].slice(0, GITHUB_MAX_LABELS);
|
||||||
const excessLabels = [...allLabels].slice(GITHUB_MAX_LABELS);
|
const excessLabels = [...allLabels].slice(GITHUB_MAX_LABELS);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (!isListEqual(prLabels, labels)) {
|
let newLabels: string[] = [];
|
||||||
await setLabels(client, prNumber, labels);
|
|
||||||
|
if (!isListEqual(labelsToAdd, preexistingLabels)) {
|
||||||
|
await setLabels(client, prNumber, labelsToAdd);
|
||||||
|
newLabels = labelsToAdd.filter(l => !preexistingLabels.includes(l));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
core.setOutput('new-labels', newLabels.join(','));
|
||||||
|
core.setOutput('all-labels', labelsToAdd.join(','));
|
||||||
|
|
||||||
if (excessLabels.length) {
|
if (excessLabels.length) {
|
||||||
core.warning(
|
core.warning(
|
||||||
`Maximum of ${GITHUB_MAX_LABELS} labels allowed. Excess labels: ${excessLabels.join(
|
`Maximum of ${GITHUB_MAX_LABELS} labels allowed. Excess labels: ${excessLabels.join(
|
||||||
|
|||||||
Reference in New Issue
Block a user