Skip to content

Commit

Permalink
Add communicate-on-pull-request-released GitHub Action (#24)
Browse files Browse the repository at this point in the history
* Create a skeleton of `communicate-on-pull-request-released` GitHub Action.
Implement adding a comment to referenced issue, removing label from a pr and adding a label to a pr.

* Create release parser

* Fix a message posted on a referenced issue.
Add a comment to a referenced pull request.
Intagrate the main logic.

* Check if a label can be removed from a pull request before removing it

* Fix parsing a labels response

* Add debug logs

* Add more debug logs

* Fix getting a pull request metadata

* Remove debugging console logs

* Add integration tests

* Restore communicate-on-pull-reuqest-merged tests

* Update README.md
  • Loading branch information
mollyIV authored Nov 25, 2019
1 parent dd8bb80 commit d0c340c
Show file tree
Hide file tree
Showing 22 changed files with 927 additions and 0 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ The Fastlane GitHub Actions provide a set of GitHub Actions to make maintaining

Adds a comment and a label to a pull request when it is merged. Read more [here](communicate-on-pull-request-merged).

- 🚀 [@github-actions/communicate-on-pull-request-released](communicate-on-pull-request-released)

Adds a comment and a label to a pull request and referenced issue when it is released. Read more [here](communicate-on-pull-request-released).

## Versioning

All the actions are released in one batch. We do not support semantic versioning (yet). Reference a `latest` branch in your workflow:
Expand Down
3 changes: 3 additions & 0 deletions communicate-on-pull-request-released/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package-lock.json
node_modules
__tests__/runner/*
11 changes: 11 additions & 0 deletions communicate-on-pull-request-released/.prettierrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"printWidth": 80,
"tabWidth": 2,
"useTabs": false,
"semi": true,
"singleQuote": true,
"trailingComma": "none",
"bracketSpacing": false,
"arrowParens": "avoid",
"parser": "typescript"
}
7 changes: 7 additions & 0 deletions communicate-on-pull-request-released/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
FROM node:slim

COPY . .

RUN npm install --production

ENTRYPOINT ["node", "/lib/main.js"]
18 changes: 18 additions & 0 deletions communicate-on-pull-request-released/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Communicate on pull request merged

An action for adding comments and labels to a pull request and referenced issue when the pull request is released.

# Usage

See [action.yml](action.yml)

```yaml
steps:
- uses: fastlane/github-action/communicate-on-pull-request-released@latest
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
```
# License
The scripts and documentation in this project are released under the [MIT License](LICENSE)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"release": {
"tag_name": "2.134.1",
"body": "This is a release description."
},
"action": "created"
}
90 changes: 90 additions & 0 deletions communicate-on-pull-request-released/__tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
const path = require('path');
const nock = require('nock');

const validScenarios = [
{
response: 'release.json',
event_name: 'release'
}
];

const invalidScenarios = [
{
response: 'pull-request-closed.json'
},
{
response: 'action-created.json'
},
{
response: 'release-missing-pr-numbers.json',
event_name: 'release'
}
];

describe('action test suite', () => {
for (const scenario of validScenarios) {
it(`It posts a comment on pull requests, referenced issues and update labels for (${scenario.response})`, async () => {
process.env['INPUT_REPO-TOKEN'] = 'token';
process.env['INPUT_PR-LABEL-TO-ADD'] = 'label-to-add';
process.env['INPUT_PR-LABEL-TO-REMOVE'] = 'label-to-remove';

process.env['GITHUB_REPOSITORY'] = 'foo/bar';
process.env['GITHUB_EVENT_NAME'] = scenario.event_name;
process.env['GITHUB_EVENT_PATH'] = path.join(
__dirname,
scenario.response
);

const api = nock('https://api.github.com')
.persist()
.post(
'/repos/foo/bar/pulls/999/reviews',
'{"body":"Congratulations! :tada: This was released as part of [_fastlane_ 2.134.1](https://github.com/Codertocat/Hello-World/runs/128620228) :rocket:","event":"COMMENT"}'
)
.reply(200)
.get('/repos/foo/bar/issues/999/labels')
.reply(200, JSON.parse('[]'))
.post('/repos/foo/bar/issues/999/labels', '{"labels":["label-to-add"]}')
.reply(200)
.get('/repos/foo/bar/pulls/999')
.reply(200, JSON.parse('{"body":"closes #10"}'))
.post(
'/repos/foo/bar/issues/10/comments',
'{"body":"The pull request #999 that closed this issue was merged and released as part of [_fastlane_ 2.134.1](https://github.com/Codertocat/Hello-World/runs/128620228) :rocket:\\nPlease let us know if the functionality works as expected as a reply here. If it does not, please open a new issue. Thanks!"}'
)
.reply(200);

const main = require('../src/main');
await main.run();

expect(api.isDone()).toBeTruthy();
});
}
});

describe('action test suite', () => {
for (const scenario of invalidScenarios) {
it(`It does not post a comment on pull requests, referenced issues and does not update labels for (${scenario.response})`, async () => {
process.env['INPUT_REPO-TOKEN'] = 'token';
process.env['INPUT_PR-LABEL-TO-ADD'] = 'label-to-add';
process.env['INPUT_PR-LABEL-TO-REMOVE'] = 'label-to-remove';

process.env['GITHUB_REPOSITORY'] = 'foo/bar';
process.env['GITHUB_EVENT_PATH'] = path.join(
__dirname,
scenario.response
);
process.env['GITHUB_EVENT_NAME'] = scenario.event_name;

const api = nock('https://api.github.com')
.persist()
.post('/repos/foo/bar/issues/10/labels', '{"labels":["label-to-add"]}')
.reply(200);

const main = require('../src/main');
await main.run();

expect(api.isDone()).not.toBeTruthy();
});
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"pull_request": {
"number": 10,
"body": "This is a pr description.",
"merged": true
},
"action": "closed"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
const validScenarios = [
{
prBody: 'The description. Close #444.',
issueNumber: 444,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'closed #444',
issueNumber: 444,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'Fix #444.',
issueNumber: 444,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'This pull request fixes #444',
issueNumber: 444,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'This PR fixed #1234',
issueNumber: 1234,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'This pull request resolve #444.',
issueNumber: 444,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'It resolves #1.',
issueNumber: 1,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'resolved #33.',
issueNumber: 33,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'This pull request closes #1234.',
issueNumber: 1234,
owner: 'foo',
repo: 'bar'
},
{
prBody: 'This pull request closes https://github.com/foo/bar/issues/10',
issueNumber: 10,
owner: 'foo',
repo: 'bar'
}
];

const invalidScenarios = [
{
prBody: 'This description does not contain referenced issue.',
owner: 'foo',
repo: 'bar'
},
{
prBody: 'unsupported closing keyword #4444',
owner: 'foo',
repo: 'bar'
},
{
prBody: '#4444',
owner: 'foo',
repo: 'bar'
},
{
prBody: 'closes # 4444',
owner: 'foo',
repo: 'bar'
},
{
prBody: 'fixes #abc',
owner: 'foo',
repo: 'bar'
},
{
prBody: 'resolve 1234',
owner: 'foo',
repo: 'bar'
},
{
prBody: 'This pull request closes http://github.com/foo/bar/issues/10',
owner: 'foo',
repo: 'bar'
},
{
prBody: 'This pull request closes https://github.com/foo/bar/issues/10',
owner: 'foo',
repo: 'foo'
}
];

describe('pull request parser test suite', () => {
for (const scenario of validScenarios) {
it(`It detects referenced issue for (${scenario.prBody})`, async () => {
const parser = require('../src/pull-request-parser');
expect(
parser.getReferencedIssue(
scenario.owner,
scenario.repo,
scenario.prBody
)
).toEqual(scenario.issueNumber);
});
}

for (const scenario of invalidScenarios) {
it(`It does not detect referenced issue for (${scenario.prBody})`, async () => {
const parser = require('../src/pull-request-parser');
expect(
parser.getReferencedIssue(
scenario.owner,
scenario.repo,
scenario.prBody
)
).toBeUndefined();
});
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"release": {
"tag_name": "2.134.1",
"body": "Could not find pull request numbers included in the release."
},
"action": "published"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
const validScenarios = [
{
releaseBody:
'[action] cocoapods changes (#15490) via XYZ\n[fastlane] revert (#15399, #15407) via ZYX',
issues: [15490, 15399, 15407]
},
{
releaseBody: '[action] title (#1) via XYZ\n[action] title (#2) via XYZ',
issues: [1, 2]
},
{
releaseBody: '[action] title (#999) via XYZ',
issues: [999]
}
];

const invalidScenarios = [
{
releaseBody: 'The description does not contain pull requests references'
},
{
releaseBody: ''
},
{
releaseBody: 'Incorrect syntax reference: # 999, 1100'
}
];

describe('release parser test suite', () => {
for (const scenario of validScenarios) {
it(`It detects the list of pull requests for (${scenario.releaseBody})`, async () => {
const parser = require('../src/release-parser');
let pullRequests = parser.getReferencedPullRequests(scenario.releaseBody);
expect(pullRequests).toEqual(scenario.issues);
});
}

for (const scenario of invalidScenarios) {
it(`It does not detect the list of pull requests for (${scenario.releaseBody})`, async () => {
const parser = require('../src/release-parser');
let pullRequests = parser.getReferencedPullRequests(scenario.releaseBody);
expect(pullRequests.length).toBe(0);
});
}
});
8 changes: 8 additions & 0 deletions communicate-on-pull-request-released/__tests__/release.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"release": {
"tag_name": "2.134.1",
"body": "* [action] title (#999) via XYZ",
"html_url": "https://github.com/Codertocat/Hello-World/runs/128620228"
},
"action": "published"
}
16 changes: 16 additions & 0 deletions communicate-on-pull-request-released/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
name: 'Communicate on pull request released'
description: 'An action for adding comments and labels to a pull request and referenced issue when the pull request is released'
author: 'fastlane'
inputs:
repo-token:
description: 'Token for the repo. Can be passed in using {{ secrets.GITHUB_TOKEN }}'
required: true
pr-label-to-add:
description: 'The label to apply when a pull request is released'
default: 'status: released'
pr-label-to-remove:
description: 'The label to remove when a pull request is released'
default: 'status: included-in-next-release'
runs:
using: 'docker'
image: 'Dockerfile'
11 changes: 11 additions & 0 deletions communicate-on-pull-request-released/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module.exports = {
clearMocks: true,
moduleFileExtensions: ['js', 'ts'],
testEnvironment: 'node',
testMatch: ['**/*.test.ts'],
testRunner: 'jest-circus/runner',
transform: {
'^.+\\.ts$': 'ts-jest'
},
verbose: true
}
Loading

0 comments on commit d0c340c

Please sign in to comment.