Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add PR auto-approve option #24

Merged
merged 2 commits into from
Oct 17, 2020
Merged
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
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,40 @@ jobs:
head: master
```

## Auto approve

If you use a workflow which does not allow to merge pull requests without a review
("Require pull request reviews before merging" in your [repo settings](https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/configuring-protected-branches))
you can set `auto_approve` to `true`. In that case you'll have to provide a [personal access token](https://docs.github.com/en/free-pro-team@latest/github/authenticating-to-github/creating-a-personal-access-token)
for a user which is allowed to review the pull requests changes. Make sure the token has at least
`public_repo` permissions and store the token inside of the [repository secrets](https://docs.github.com/en/free-pro-team@latest/actions/reference/encrypted-secrets#creating-encrypted-secrets-for-a-repository).

An example workflow would then look like this:

```yml
name: Sync Fork

on:
schedule:
- cron: '*/30 * * * *' # every 30 minutes
workflow_dispatch: # on button click

jobs:
sync:

runs-on: ubuntu-latest

steps:
- uses: tgymnich/[email protected]
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
owner: llvm
base: master
head: master
auto_approve: true
personal_token: ${{ secrets.PERSONAL_TOKEN }}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

shouldn't the already used GITHUB_TOKEN have sufficient permissions to review and approve PRs?

Copy link
Contributor Author

@R0Wi R0Wi Oct 11, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tested it but Github gave me an error message like "you cannot approve your own pull request" which makes sense somehow ;-)

So there have to be two different users then

```

# Parameters

| name | Optional | Default | description |
Expand All @@ -41,5 +75,9 @@ jobs:
| pr_title | ✅ | Fork Sync | Title of the created pull request |
| pr_message | ✅ | | Message of the created pull request |
| ignore_fail | ✅ | | Ignore Exceptions |
| auto_approve | ✅ * | `false` | Automatically approve pull request before merge |
| personal_token| ✅ | | Usertoken for the user to auto approve the pull request |

⚠️ $current_repo_owner is your own username!

⚠️ * if `auto_approve` is set to `true` you must provide the `personal_token`!
7 changes: 7 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@ inputs:
ignore_fail:
description: 'ignore Exceptions'
required: false
auto_approve:
description: 'Automatically approve pull request before merge'
required: false
default: false
personal_token:
description: 'Usertoken for the user to auto approve the pull request'
required: false

runs:
using: 'node12'
Expand Down
19 changes: 16 additions & 3 deletions lib/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,16 +51,29 @@ function run() {
const prTitle = core.getInput('pr_title', { required: false });
const prMessage = core.getInput('pr_message', { required: false });
const ignoreFail = core.getInput('ignore_fail', { required: false });
const autoApprove = core.getInput('auto_approve', { required: false });
const personalToken = core.getInput('personal_token', { required: false });
try {
let pr = yield octokit.pulls.create({ owner: context.repo.owner, repo: context.repo.repo, title: prTitle, head: owner + ':' + head, base: base, body: prMessage, merge_method: mergeMethod, maintainer_can_modify: false });
yield delay(20);
if (autoApprove) {
if (!personalToken) {
console.log('Cannot auto-approve, please set "personal_token"-variable');
}
else {
// Authenticate as current user
const octokitUser = new MyOctokit({ auth: personalToken });
yield octokitUser.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.data.number, event: "COMMENT", body: "Auto approved" });
yield octokitUser.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.data.number, event: "APPROVE" });
}
}
yield octokit.pulls.merge({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.data.number });
}
catch (error) {
if (error.request.request.retryCount) {
console.log(`request failed after ${error.request.request.retryCount} retries with a delay of ${error.request.request.retryAfter}`);
}
if (!!error.errors && error.errors[0].message.startsWith('No commits between')) {
if (!!error.errors && !!error.errors[0] && !!error.errors[0].message && error.errors[0].message.startsWith('No commits between')) {
console.log('No commits between ' + context.repo.owner + ':' + base + ' and ' + owner + ':' + head);
}
else {
Expand All @@ -71,7 +84,7 @@ function run() {
}
});
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms * 1000));
function delay(s) {
return new Promise(resolve => setTimeout(resolve, s * 1000));
}
run();
19 changes: 16 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,31 @@ async function run() {
const prTitle = core.getInput('pr_title', { required: false });
const prMessage = core.getInput('pr_message', { required: false });
const ignoreFail = core.getInput('ignore_fail', { required: false });
const autoApprove = core.getInput('auto_approve', { required: false });
const personalToken = core.getInput('personal_token', { required: false });

try {
let pr = await octokit.pulls.create({ owner: context.repo.owner, repo: context.repo.repo, title: prTitle, head: owner + ':' + head, base: base, body: prMessage, merge_method: mergeMethod, maintainer_can_modify: false });
await delay(20);
if (autoApprove) {
if (!personalToken){
console.log('Cannot auto-approve, please set "personal_token"-variable');
}
else {
// Authenticate as current user
const octokitUser = new MyOctokit({auth: personalToken});
await octokitUser.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.data.number, event: "COMMENT", body: "Auto approved" });
await octokitUser.pulls.createReview({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.data.number, event: "APPROVE" });
}
}
await octokit.pulls.merge({ owner: context.repo.owner, repo: context.repo.repo, pull_number: pr.data.number });
} catch (error) {
if (error.request.request.retryCount) {
console.log(
`request failed after ${error.request.request.retryCount} retries with a delay of ${error.request.request.retryAfter}`
);
}
if (!!error.errors && error.errors[0].message.startsWith('No commits between')) {
if (!!error.errors && !!error.errors[0] && !!error.errors[0].message && error.errors[0].message.startsWith('No commits between')) {
console.log('No commits between ' + context.repo.owner + ':' + base + ' and ' + owner + ':' + head);
} else {
if (!ignoreFail) {
Expand All @@ -42,8 +55,8 @@ async function run() {
}
}

function delay(ms: number) {
return new Promise( resolve => setTimeout(resolve, ms * 1000) );
function delay(s: number) {
return new Promise( resolve => setTimeout(resolve, s * 1000) );
}

run();