Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion communicate-on-pull-request-merged/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ steps:
- uses: fastlane/github-action/communicate-on-pull-request-merged@latest
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
pr-comment: "Hey @${{ github.event.pull_request.user.login }} :wave: Thank you for your contribution!"
pr-comment: "Hey :wave: Thank you for your contribution!"
```

# License
Expand Down

This file was deleted.

7 changes: 0 additions & 7 deletions communicate-on-pull-request-merged/__tests__/issue.json

This file was deleted.

102 changes: 62 additions & 40 deletions communicate-on-pull-request-merged/__tests__/main.test.ts
Original file line number Diff line number Diff line change
@@ -1,72 +1,94 @@
const path = require('path');
const nock = require('nock');

const validScenarios = [
{
response: 'pull-request-closed.json'
}
];

const invalidScenarios = [
{
response: 'issue.json'
scenario_name: 'no-push-event',
event_name: 'pull_request',
sha: '',
commits: '',
pulls: ''
},
{
response: 'action-opened.json'
scenario_name: 'no-commit-sha',
event_name: 'push',
sha: '',
commits: '',
pulls: ''
},
{
response: 'pull-request-closed-but-not-merged'
scenario_name: 'no-merge-changes',
event_name: 'push',
sha: '123abc',
commits: '',
pulls: ''
},
{
scenario_name: 'no-pull-request-for-a-given-commit',
event_name: 'push',
sha: '123abc',
commits: JSON.parse(
'{"parents": [{"url": "0", "sha": "0"}, {"url": "1", "sha": "1"}]}'
),
pulls: ''
}
];

describe('action test suite', () => {
for (const scenario of validScenarios) {
it(`It posts a comment on a merged issue for (${scenario.response})`, async () => {
process.env['INPUT_REPO-TOKEN'] = 'token';
process.env['INPUT_PR-COMMENT'] = 'message';
process.env['INPUT_PR-LABEL-TO-ADD'] = 'label-to-add';
process.env['INPUT_PR-LABEL-TO-REMOVE'] = 'label-to-remove';
it(`It posts a comment on a merged pull request, adds and removes the labels`, async () => {
process.env['INPUT_REPO-TOKEN'] = 'token';
process.env['INPUT_PR-COMMENT'] = 'message';
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'] = 'push';
process.env['GITHUB_REPOSITORY'] = 'foo/bar';
process.env['GITHUB_SHA'] = 'abc123';

const api = nock('https://api.github.com')
.persist()
.post(
'/repos/foo/bar/pulls/10/reviews',
'{"body":"message","event":"COMMENT"}'
const api = nock('https://api.github.com')
.persist()
.get('/repos/foo/bar/git/commits/abc123')
.reply(
200,
JSON.parse(
'{"parents": [{"url": "hello-0", "sha": "1acc"}, {"url": "hello-1", "sha": "2acc"}]}'
)
.reply(200)
.get('/repos/foo/bar/issues/10/labels')
.reply(200, JSON.parse('[]'))
.post('/repos/foo/bar/issues/10/labels', '{"labels":["label-to-add"]}')
.reply(200);
)
.get('/repos/foo/bar/commits/abc123/pulls')
.reply(200, JSON.parse('[{"number": 10, "state": "closed"}]'))
.post(
'/repos/foo/bar/pulls/10/reviews',
'{"body":"message","event":"COMMENT"}'
)
.reply(200)
.get('/repos/foo/bar/issues/10/labels')
.reply(200, JSON.parse('[]'))
.post('/repos/foo/bar/issues/10/labels', '{"labels":["label-to-add"]}')
.reply(200);

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

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

for (const scenario of invalidScenarios) {
it(`It does not post a comment on a closed pull request for (${scenario.response})`, async () => {
it(`It does not post a comment on a closed pull request for (${scenario.scenario_name})`, async () => {
process.env['INPUT_REPO-TOKEN'] = 'token';
process.env['INPUT_PR-COMMENT'] = 'message';
process.env['INPUT_PR-LABEL-TO-ADD'] = 'label-to-add';
process.env['INPUT_PR-LABEL-TO-REMOVE'] = 'label-to-remove';

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

const api = nock('https://api.github.com')
.persist()
.get(`/repos/foo/bar/git/commits/${scenario.sha}`)
.reply(200, `${scenario.commits}`)
.get(`/repos/foo/bar/commits/${scenario.sha}/pulls`)
.reply(200, `${scenario.pulls}`)
.post(
'/repos/foo/bar/pulls/10/reviews',
'{"body":"message","event":"COMMENT"}'
Expand Down

This file was deleted.

This file was deleted.

7 changes: 4 additions & 3 deletions communicate-on-pull-request-merged/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,14 @@ inputs:
required: true
pr-comment:
description: 'A comment to post on a pull request when code changes are merged'
required: true
required: false
# The default value is taken (see the source code of the action) when no `pr-comment` is provided
pr-label-to-add:
description: 'The label to apply when a pull request is merged'
default: 'status: included-in-next-release'
pr-label-to-remove:
description: 'The label to remove when a pull request is merged'
default: 'status: needs-attention'
description: 'The label to remove when a pull request is merged'
default: 'status: needs-attention'
runs:
using: 'docker'
image: 'Dockerfile'
60 changes: 48 additions & 12 deletions communicate-on-pull-request-merged/lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,22 @@ const github = __importStar(require("@actions/github"));
function run() {
return __awaiter(this, void 0, void 0, function* () {
try {
const isPullRequest = !!github.context.payload.pull_request;
if (!isPullRequest) {
console.log('The event that triggered this action was not a pull request, exiting');
return;
}
if (github.context.payload.action !== 'closed') {
console.log('No pull request was closed, exiting');
if (github.context.eventName !== 'push') {
console.log('The event that triggered this action was not a push, exiting');
return;
}
const repoToken = core.getInput('repo-token', { required: true });
const client = new github.GitHub(repoToken);
const prNumber = github.context.payload.pull_request.number;
const merged = github.context.payload.pull_request['merged'];
if (!merged) {
console.log('No pull request was merged, exiting');
const commit = yield getCommit(client, github.context.sha);
if (!isMergeCommit(commit)) {
console.log('No merge commit, exiting');
return;
}
const { data: [pullRequest] } = yield getPullRequests(client, github.context.sha);
const prNumber = pullRequest.number;
const closed = pullRequest.state == 'closed';
if (!closed) {
console.log('No pull request was closed, exiting');
return;
}
const labelToRemove = core.getInput('pr-label-to-remove');
Expand All @@ -43,14 +44,39 @@ function run() {
yield removeLabel(client, prNumber, labelToRemove);
}
yield addLabels(client, prNumber, [core.getInput('pr-label-to-add')]);
yield addComment(client, prNumber, core.getInput('pr-comment', { required: true }));
var comment = core.getInput('pr-comment', { required: false });
if (comment.length == 0) {
comment = defaultPrComment(pullRequest.user.login);
}
yield addComment(client, prNumber, comment);
}
catch (error) {
core.setFailed(error.message);
}
});
}
exports.run = run;
function getCommit(client, commit_sha) {
return __awaiter(this, void 0, void 0, function* () {
return yield client.git.getCommit({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
commit_sha: commit_sha
});
});
}
function isMergeCommit(commit) {
return commit.data.parents.length > 1;
}
function getPullRequests(client, commit_sha) {
return __awaiter(this, void 0, void 0, function* () {
return yield client.repos.listPullRequestsAssociatedWithCommit({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
commit_sha: commit_sha
});
});
}
function addComment(client, prNumber, comment) {
return __awaiter(this, void 0, void 0, function* () {
yield client.pulls.createReview({
Expand Down Expand Up @@ -98,4 +124,14 @@ function removeLabel(client, prNumber, label) {
});
});
}
function defaultPrComment(prAuthor) {
return `Hey @${prAuthor} :wave:

Thank you for your contribution to _fastlane_ and congrats on getting this pull request merged :tada:
The code change now lives in the \`master\` branch, however it wasn't released to [RubyGems](https://rubygems.org/gems/fastlane) yet.
We usually ship about once a week, and your PR will be included in the next one.

Please let us know if this change requires an immediate release by adding a comment here :+1:
We'll notify you once we shipped a new release with your changes :rocket:`;
}
run();
69 changes: 52 additions & 17 deletions communicate-on-pull-request-merged/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,29 @@ import * as github from '@actions/github';

export async function run() {
try {
const isPullRequest: boolean = !!github.context.payload.pull_request;
if (!isPullRequest) {
if (github.context.eventName !== 'push') {
console.log(
'The event that triggered this action was not a pull request, exiting'
'The event that triggered this action was not a push, exiting'
);
return;
}

if (github.context.payload.action !== 'closed') {
console.log('No pull request was closed, exiting');
return;
}

const repoToken = core.getInput('repo-token', {required: true});
const client: github.GitHub = new github.GitHub(repoToken);
const prNumber = github.context.payload.pull_request!.number;

const merged = github.context.payload.pull_request!['merged'];
if (!merged) {
console.log('No pull request was merged, exiting');
const commit = await getCommit(client, github.context.sha);
if (!isMergeCommit(commit)) {
console.log('No merge commit, exiting');
return;
}

const {
data: [pullRequest]
} = await getPullRequests(client, github.context.sha);
const prNumber = pullRequest.number;
const closed = pullRequest.state == 'closed';
if (!closed) {
console.log('No pull request was closed, exiting');
return;
}

Expand All @@ -37,16 +40,37 @@ export async function run() {
}

await addLabels(client, prNumber, [core.getInput('pr-label-to-add')]);
await addComment(
client,
prNumber,
core.getInput('pr-comment', {required: true})
);

var comment = core.getInput('pr-comment', {required: false});
if (comment.length == 0) {
comment = defaultPrComment(pullRequest.user.login);
}
await addComment(client, prNumber, comment);
} catch (error) {
core.setFailed(error.message);
}
}

async function getCommit(client: github.GitHub, commit_sha: string) {
return await client.git.getCommit({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
commit_sha: commit_sha
});
}

function isMergeCommit(commit): boolean {
return commit.data.parents.length > 1;
}

async function getPullRequests(client: github.GitHub, commit_sha: string) {
return await client.repos.listPullRequestsAssociatedWithCommit({
owner: github.context.repo.owner,
repo: github.context.repo.repo,
commit_sha: commit_sha
});
}

async function addComment(
client: github.GitHub,
prNumber: number,
Expand Down Expand Up @@ -107,4 +131,15 @@ async function removeLabel(
});
}

function defaultPrComment(prAuthor: string): string {
return `Hey @${prAuthor} :wave:

Thank you for your contribution to _fastlane_ and congrats on getting this pull request merged :tada:
The code change now lives in the \`master\` branch, however it wasn't released to [RubyGems](https://rubygems.org/gems/fastlane) yet.
We usually ship about once a week, and your PR will be included in the next one.

Please let us know if this change requires an immediate release by adding a comment here :+1:
We'll notify you once we shipped a new release with your changes :rocket:`;
}

run();