Skip to content

Commit c639c60

Browse files
authored
Merge pull request #3 from alexwilson/read-merge-method
feat: Specify merge-method
2 parents 1c929cb + 18bbe90 commit c639c60

File tree

9 files changed

+901
-59
lines changed

9 files changed

+901
-59
lines changed

README.md

Lines changed: 51 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,55 @@
11
# Enable Github Auto-Merge Action
22

3-
⚠️**WIP: Please wait until version 1.0.0 before using this.** ⚠️
3+
Name: `alexwilson/enable-github-automerge-action`
44

5-
## What is this?
5+
## 1) What is this?
66

7-
A Github action for enabling [Github Auto-Merge](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/automatically-merging-a-pull-request) in a workflow for a pull-request.
8-
You might want to use this for automatically merging Dependabot pull-requests.
7+
To speed up some of your workflows, this action allows you to automatically enable [Auto-Merge](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/automatically-merging-a-pull-request) in your Github pull-requests.
8+
9+
When enabled, Auto-Merge will merge pull-requests automatically _as soon as all requirements are met_ (approvals, passing tests).
10+
11+
_You can use this, for example, to automatically merge Dependabot pull-requests_.
12+
13+
This action pairs well with [`hmarr/auto-approve-action`](https://github.com/hmarr/auto-approve-action)
14+
15+
## 2) Usage
16+
17+
Add as a step inside a GitHub workflow, e.g. `.github/workflows/auto-merge.yml`. [You can see an example of this in this repository](./.github/workflows/auto-merge-dependabot.yml).
18+
19+
```yaml
20+
name: Auto-Merge
21+
on: pull_request
22+
23+
jobs:
24+
build:
25+
runs-on: ubuntu-latest
26+
steps:
27+
- uses: alexwilson/enable-github-automerge-action@main
28+
github-token: "${{ secrets.GITHUB_TOKEN }}"
29+
```
30+
31+
*Note*: You will probably want to add some restrictions so this doesn't auto-merge every PR: these are handled fairly well by GitHub Workflow syntax, [you can read more about this here](https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsif).
32+
33+
### 2.1) Additional Options
34+
35+
```yaml
36+
- uses: alexwilson/enable-github-automerge-action@1.0.0
37+
with:
38+
github-token: "${{ secrets.GITHUB_TOKEN }}"
39+
merge-method: "SQUASH"
40+
```
41+
42+
- **github-token**: The Github Token to use for this action. By default this variable is set to run as `github-actions`, however you can replace this with another user/actor's Github Token (make sure it has, _at minimum_, `repo` scope).
43+
- **merge-method**: Override the merge method. By default this action attempts to select your repository's default merge method, and falls back to merge. One of `MERGE`, `SQUASH` or `REBASE`. [Read more here](https://docs.github.com/en/graphql/reference/enums#pullrequestmergemethod).
44+
45+
## 3) Developing Locally
46+
47+
Github Action developer-experience isn't fantastic, so for now we mimic the Github Action environment in `./src/local.ts`.
48+
49+
This file sets environment variables locally to enable action inputs, and points to a sample pull-request webhook event in `./stub/example-pull-request.json`.
50+
51+
1. Make sure you're running a recent version of Node (the correct version will always be in `.nvmrc` and `action.yml`)
52+
2. Set `GITHUB_TOKEN` locally. (You can do this via `$ export GITHUB_TOKEN=blah`)
53+
3. Optionally(!) set `MERGE_METHOD` locally. (You can do this via `$ export MERGE_METHOD=MERGE`)
54+
4. Run with `npm run local`.
55+
5. **Important**: Avoid committing anything to `dist/*` — this is automatically regenerated and manually adjusting this will make rebasing harder!

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ inputs:
77
github-token:
88
description: 'The GITHUB_TOKEN secret'
99
required: true
10+
merge-method:
11+
description: 'Preferred merge method for automatic merges.'
12+
required: false
1013
runs:
1114
using: 'node12'
1215
main: 'dist/index.js'

dist/index.js

Lines changed: 137 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
1515
return result;
1616
};
1717
Object.defineProperty(exports, "__esModule", ({ value: true }));
18-
const os = __importStar(__nccwpck_require__(87));
18+
const os = __importStar(__nccwpck_require__(365));
1919
const utils_1 = __nccwpck_require__(278);
2020
/**
2121
* Commands
@@ -113,7 +113,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
113113
const command_1 = __nccwpck_require__(351);
114114
const file_command_1 = __nccwpck_require__(717);
115115
const utils_1 = __nccwpck_require__(278);
116-
const os = __importStar(__nccwpck_require__(87));
116+
const os = __importStar(__nccwpck_require__(365));
117117
const path = __importStar(__nccwpck_require__(622));
118118
/**
119119
* The code to exit an action
@@ -350,7 +350,7 @@ Object.defineProperty(exports, "__esModule", ({ value: true }));
350350
// We use any as a valid input type
351351
/* eslint-disable @typescript-eslint/no-explicit-any */
352352
const fs = __importStar(__nccwpck_require__(747));
353-
const os = __importStar(__nccwpck_require__(87));
353+
const os = __importStar(__nccwpck_require__(365));
354354
const utils_1 = __nccwpck_require__(278);
355355
function issueCommand(command, message) {
356356
const filePath = process.env[`GITHUB_${command}`];
@@ -395,15 +395,15 @@ exports.toCommandValue = toCommandValue;
395395

396396
/***/ }),
397397

398-
/***/ 53:
398+
/***/ 87:
399399
/***/ ((__unused_webpack_module, exports, __nccwpck_require__) => {
400400

401401
"use strict";
402402

403403
Object.defineProperty(exports, "__esModule", ({ value: true }));
404404
exports.Context = void 0;
405405
const fs_1 = __nccwpck_require__(747);
406-
const os_1 = __nccwpck_require__(87);
406+
const os_1 = __nccwpck_require__(365);
407407
class Context {
408408
/**
409409
* Hydrate the context from the environment
@@ -478,7 +478,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
478478
};
479479
Object.defineProperty(exports, "__esModule", ({ value: true }));
480480
exports.getOctokit = exports.context = void 0;
481-
const Context = __importStar(__nccwpck_require__(53));
481+
const Context = __importStar(__nccwpck_require__(87));
482482
const utils_1 = __nccwpck_require__(30);
483483
exports.context = new Context.Context();
484484
/**
@@ -571,7 +571,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
571571
};
572572
Object.defineProperty(exports, "__esModule", ({ value: true }));
573573
exports.getOctokitOptions = exports.GitHub = exports.context = void 0;
574-
const Context = __importStar(__nccwpck_require__(53));
574+
const Context = __importStar(__nccwpck_require__(87));
575575
const Utils = __importStar(__nccwpck_require__(914));
576576
// octokit + plugins
577577
const core_1 = __nccwpck_require__(762);
@@ -5781,6 +5781,122 @@ function wrappy (fn, cb) {
57815781
}
57825782

57835783

5784+
/***/ }),
5785+
5786+
/***/ 20:
5787+
/***/ (function(__unused_webpack_module, exports, __nccwpck_require__) {
5788+
5789+
"use strict";
5790+
5791+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
5792+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
5793+
return new (P || (P = Promise))(function (resolve, reject) {
5794+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5795+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
5796+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
5797+
step((generator = generator.apply(thisArg, _arguments || [])).next());
5798+
});
5799+
};
5800+
Object.defineProperty(exports, "__esModule", ({ value: true }));
5801+
exports.EnableGithubAutomergeAction = void 0;
5802+
const core_1 = __nccwpck_require__(186);
5803+
class EnableGithubAutomergeAction {
5804+
constructor(client, context, options) {
5805+
this.client = client;
5806+
this.context = context;
5807+
this.options = options;
5808+
}
5809+
run() {
5810+
return __awaiter(this, void 0, void 0, function* () {
5811+
// Find out where we are!
5812+
const { repo } = this.context;
5813+
if (!repo) {
5814+
throw new Error("Could not find repository!");
5815+
}
5816+
// Make sure this is actually a pull-request!
5817+
// We need this to retrieve the pull-request node ID.
5818+
const { pull_request: pullRequest } = this.context.payload;
5819+
if (!pullRequest) {
5820+
throw new Error("Event payload missing `pull_request`, is this a pull-request?");
5821+
}
5822+
const pullRequestId = pullRequest.node_id;
5823+
//
5824+
// Step 1. Retrieve the merge method!
5825+
core_1.debug(`Retrieving merge-method...`);
5826+
const mergeMethod = yield this.getMergeMethod(repo);
5827+
core_1.debug(`Successfully retrieved merge-method as: ${mergeMethod}`);
5828+
//
5829+
// Step 2. Enable auto-merge.
5830+
core_1.debug(`Enabling auto-merge for pull-request #${pullRequest.number}`);
5831+
yield this.enableAutoMerge(pullRequestId, mergeMethod);
5832+
core_1.debug(`Successfully enabled auto-merge for pull-request #${pullRequest.number}`);
5833+
});
5834+
}
5835+
getMergeMethod(repo) {
5836+
var _a;
5837+
return __awaiter(this, void 0, void 0, function* () {
5838+
const { preferredMergeMethod } = this.options;
5839+
// Allow users to specify a merge method.
5840+
if (preferredMergeMethod && preferredMergeMethod.length > 0) {
5841+
return preferredMergeMethod;
5842+
}
5843+
//
5844+
// Otherwise try and discover one.
5845+
//
5846+
// Merge is the default behaviour.
5847+
let mergeMethod = `MERGE`;
5848+
// Try to discover the repository's default merge method.
5849+
try {
5850+
const repositorySettings = (yield this.client.graphql(`
5851+
query($repository: String!, $owner: String!) {
5852+
repository(name:$repository, owner:$owner) {
5853+
viewerDefaultMergeMethod
5854+
}
5855+
}
5856+
`, {
5857+
repository: repo.repo,
5858+
owner: repo.owner,
5859+
}));
5860+
const viewerDefaultMergeMethod = ((_a = repositorySettings === null || repositorySettings === void 0 ? void 0 : repositorySettings.repository) === null || _a === void 0 ? void 0 : _a.viewerDefaultMergeMethod) || undefined;
5861+
if (viewerDefaultMergeMethod && viewerDefaultMergeMethod.length > 0) {
5862+
mergeMethod = viewerDefaultMergeMethod;
5863+
}
5864+
}
5865+
catch (err) {
5866+
core_1.error(`Failed to read default merge method: ${err.message}`);
5867+
}
5868+
return mergeMethod;
5869+
});
5870+
}
5871+
enableAutoMerge(pullRequestId, mergeMethod) {
5872+
return __awaiter(this, void 0, void 0, function* () {
5873+
return yield this.client.graphql(`
5874+
mutation(
5875+
$pullRequestId: ID!,
5876+
$mergeMethod: PullRequestMergeMethod!
5877+
) {
5878+
enablePullRequestAutoMerge(input: {
5879+
pullRequestId: $pullRequestId,
5880+
mergeMethod: $mergeMethod
5881+
}) {
5882+
clientMutationId
5883+
pullRequest {
5884+
id
5885+
state
5886+
}
5887+
}
5888+
}
5889+
`, {
5890+
pullRequestId,
5891+
mergeMethod,
5892+
});
5893+
});
5894+
}
5895+
}
5896+
exports.EnableGithubAutomergeAction = EnableGithubAutomergeAction;
5897+
exports.default = EnableGithubAutomergeAction;
5898+
5899+
57845900
/***/ }),
57855901

57865902
/***/ 399:
@@ -5817,38 +5933,30 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
58175933
});
58185934
};
58195935
Object.defineProperty(exports, "__esModule", ({ value: true }));
5820-
const core = __importStar(__nccwpck_require__(186));
5936+
exports.run = void 0;
58215937
const github = __importStar(__nccwpck_require__(438));
5938+
const core_1 = __nccwpck_require__(186);
5939+
const enable_github_automerge_action_1 = __nccwpck_require__(20);
58225940
function run() {
58235941
return __awaiter(this, void 0, void 0, function* () {
58245942
try {
5825-
const token = core.getInput("github-token", { required: true });
5943+
const { context } = github;
5944+
const options = Object.create(null);
5945+
const token = core_1.getInput("github-token", { required: true });
58265946
const client = github.getOctokit(token);
5827-
const { pull_request: pullRequest } = github.context.payload;
5828-
if (!pullRequest) {
5829-
throw new Error("Event payload missing `pull_request`");
5947+
const preferredMergeMethod = core_1.getInput("merge-method", { required: false });
5948+
if (preferredMergeMethod) {
5949+
options.preferredMergeMethod = preferredMergeMethod;
58305950
}
5831-
core.debug(`Enabling auto-merge for pull-request #${pullRequest.number}`);
5832-
client.graphql(`
5833-
mutation {
5834-
enablePullRequestAutoMerge(input:{
5835-
pullRequestId: "${pullRequest.node_id}"
5836-
}) {
5837-
clientMutationId
5838-
pullRequest {
5839-
id
5840-
state
5841-
}
5842-
}
5843-
}
5844-
`);
5845-
core.debug(`Successfully enabled auto-merge for pull-request #${pullRequest.number}`);
5951+
const automergeAction = new enable_github_automerge_action_1.EnableGithubAutomergeAction(client, context, options);
5952+
yield automergeAction.run();
58465953
}
58475954
catch (error) {
5848-
core.setFailed(error.message);
5955+
core_1.setFailed(error.message);
58495956
}
58505957
});
58515958
}
5959+
exports.run = run;
58525960
run();
58535961

58545962

@@ -5910,7 +6018,7 @@ module.exports = require("net");;
59106018

59116019
/***/ }),
59126020

5913-
/***/ 87:
6021+
/***/ 365:
59146022
/***/ ((module) => {
59156023

59166024
"use strict";

0 commit comments

Comments
 (0)