Skip to content

Commit

Permalink
Implement the ability to auto-merge an arbitrary pull request (#149)
Browse files Browse the repository at this point in the history
Implement support for arbitrary pull requests

Co-authored-by: Pascal
  • Loading branch information
roryabraham committed May 11, 2021
1 parent ebf03a4 commit 042e737
Show file tree
Hide file tree
Showing 5 changed files with 278 additions and 9 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,8 @@ Also, the following general options are supported:
so make sure to add it as secret, not as environment variable, in the GitHub
workflow file!

- `PULL_REQUEST`: If provided, this action will attempt to merge the specified pull request. By default, it will attempt to use the pull request specified in the GitHub context. If a pull request number is provided via this input, this action will search in the current repo for the provided pull request number. If you want to merge a pull request in another repo, just provide the repo slug before the pull request number, like `Some-Org/Some-Repo/1234`

You can configure the environment variables in the workflow file like this:

```yaml
Expand All @@ -209,6 +211,7 @@ You can configure the environment variables in the workflow file like this:
MERGE_RETRY_SLEEP: "10000"
UPDATE_LABELS: ""
UPDATE_METHOD: "rebase"
PULL_REQUEST: "1234"
```

## Supported Events
Expand Down
84 changes: 80 additions & 4 deletions dist/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,9 @@ async function executeGitHubAction(context, eventName, eventData) {
logger.info("Event name:", eventName);
logger.trace("Event data:", eventData);

if (["push"].includes(eventName)) {
if (context.config.pullRequest != null) {
await handleArbitraryPullRequestUpdate(context, eventData);
} else if (["push"].includes(eventName)) {
await handleBaseBranchUpdate(context, eventName, eventData);
} else if (["status"].includes(eventName)) {
await handleStatusUpdate(context, eventName, eventData);
Expand Down Expand Up @@ -233,6 +235,34 @@ async function handlePullRequestUpdate(context, eventName, event) {
await merge(context, pullRequest);
}

async function handleArbitraryPullRequestUpdate(context, eventData) {
const { config, octokit } = context;

const repoOwner =
config.pullRequest.repoOwner || eventData.repository.owner.login;
const repoName = config.pullRequest.repoName || eventData.repository.name;
const { pullRequestNumber } = config.pullRequest;

logger.info(`Looking for pull request #${pullRequestNumber}...`);

try {
const { data: pullRequest } = await octokit.pulls.get({
owner: repoOwner,
repo: repoName,
pull_number: pullRequestNumber
});
logger.trace("Full PR:", pullRequest);

await update(context, pullRequest);
await merge(context, pullRequest);
} catch (e) {
logger.error(
`Error fetching pull request: ${repoOwner}/${repoName}/${pullRequestNumber}`
);
throw e;
}
}

async function handleCheckUpdate(context, eventName, event) {
const { action } = event;
if (action !== "completed") {
Expand Down Expand Up @@ -517,7 +547,6 @@ module.exports = { executeLocally, executeGitHubAction };

const util = __webpack_require__(1669);
const process = __webpack_require__(1765);

const fse = __webpack_require__(5630);
const tmp = __webpack_require__(8517);

Expand Down Expand Up @@ -611,7 +640,7 @@ function createConfig(env = {}) {
if (val == null || val === "") {
return defaultValue;
} else {
const number = parseInt(val);
const number = parseInt(val, 10);
if (isNaN(number) || number < 0) {
throw new ClientError(`Not a positive integer: ${val}`);
} else {
Expand All @@ -620,6 +649,50 @@ function createConfig(env = {}) {
}
}

function parsePullRequest(pullRequest) {
if (!pullRequest) {
return null;
}

logger.info(`Parsing PULL_REQUEST input: ${pullRequest}`);

const error = new ClientError(
`Invalid value provided for input PULL_REQUEST: ${pullRequest}. Must be a positive integer, optionally prefixed by a repo slug.`
);

if (typeof pullRequest === "string") {
let repoOwner;
let repoName;
let pullRequestNumber;

const destructuredPullRequest = pullRequest.split("/");
if (destructuredPullRequest.length === 3) {
[repoOwner, repoName, pullRequestNumber] = destructuredPullRequest;
} else if (destructuredPullRequest.length === 1) {
[pullRequestNumber] = destructuredPullRequest;
} else {
throw error;
}

pullRequestNumber = parseInt(pullRequestNumber, 10);
if (isNaN(pullRequestNumber) || pullRequestNumber <= 0) {
throw error;
}

return {
repoOwner,
repoName,
pullRequestNumber
};
}

if (typeof pullRequest === "number" && pullRequest > 0) {
return { pullRequestNumber: pullRequest };
}

throw error;
}

const mergeLabels = parseMergeLabels(env.MERGE_LABELS, "automerge");
const mergeRemoveLabels = parseMergeRemoveLabels(env.MERGE_REMOVE_LABELS, "");
const mergeMethod = env.MERGE_METHOD || "merge";
Expand All @@ -638,6 +711,8 @@ function createConfig(env = {}) {
const updateRetries = parsePositiveInt("UPDATE_RETRIES", 1);
const updateRetrySleep = parsePositiveInt("UPDATE_RETRY_SLEEP", 5000);

const pullRequest = parsePullRequest(env.PULL_REQUEST);

return {
mergeLabels,
mergeRemoveLabels,
Expand All @@ -654,7 +729,8 @@ function createConfig(env = {}) {
updateLabels,
updateMethod,
updateRetries,
updateRetrySleep
updateRetrySleep,
pullRequest
};
}

Expand Down
32 changes: 31 additions & 1 deletion lib/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,9 @@ async function executeGitHubAction(context, eventName, eventData) {
logger.info("Event name:", eventName);
logger.trace("Event data:", eventData);

if (["push"].includes(eventName)) {
if (context.config.pullRequest != null) {
await handleArbitraryPullRequestUpdate(context, eventData);
} else if (["push"].includes(eventName)) {
await handleBaseBranchUpdate(context, eventName, eventData);
} else if (["status"].includes(eventName)) {
await handleStatusUpdate(context, eventName, eventData);
Expand Down Expand Up @@ -98,6 +100,34 @@ async function handlePullRequestUpdate(context, eventName, event) {
await merge(context, pullRequest);
}

async function handleArbitraryPullRequestUpdate(context, eventData) {
const { config, octokit } = context;

const repoOwner =
config.pullRequest.repoOwner || eventData.repository.owner.login;
const repoName = config.pullRequest.repoName || eventData.repository.name;
const { pullRequestNumber } = config.pullRequest;

logger.info(`Looking for pull request #${pullRequestNumber}...`);

try {
const { data: pullRequest } = await octokit.pulls.get({
owner: repoOwner,
repo: repoName,
pull_number: pullRequestNumber
});
logger.trace("Full PR:", pullRequest);

await update(context, pullRequest);
await merge(context, pullRequest);
} catch (e) {
logger.error(
`Error fetching pull request: ${repoOwner}/${repoName}/${pullRequestNumber}`
);
throw e;
}
}

async function handleCheckUpdate(context, eventName, event) {
const { action } = event;
if (action !== "completed") {
Expand Down
52 changes: 49 additions & 3 deletions lib/common.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const util = require("util");
const process = require("process");

const fse = require("fs-extra");
const tmp = require("tmp");

Expand Down Expand Up @@ -94,7 +93,7 @@ function createConfig(env = {}) {
if (val == null || val === "") {
return defaultValue;
} else {
const number = parseInt(val);
const number = parseInt(val, 10);
if (isNaN(number) || number < 0) {
throw new ClientError(`Not a positive integer: ${val}`);
} else {
Expand All @@ -103,6 +102,50 @@ function createConfig(env = {}) {
}
}

function parsePullRequest(pullRequest) {
if (!pullRequest) {
return null;
}

logger.info(`Parsing PULL_REQUEST input: ${pullRequest}`);

const error = new ClientError(
`Invalid value provided for input PULL_REQUEST: ${pullRequest}. Must be a positive integer, optionally prefixed by a repo slug.`
);

if (typeof pullRequest === "string") {
let repoOwner;
let repoName;
let pullRequestNumber;

const destructuredPullRequest = pullRequest.split("/");
if (destructuredPullRequest.length === 3) {
[repoOwner, repoName, pullRequestNumber] = destructuredPullRequest;
} else if (destructuredPullRequest.length === 1) {
[pullRequestNumber] = destructuredPullRequest;
} else {
throw error;
}

pullRequestNumber = parseInt(pullRequestNumber, 10);
if (isNaN(pullRequestNumber) || pullRequestNumber <= 0) {
throw error;
}

return {
repoOwner,
repoName,
pullRequestNumber
};
}

if (typeof pullRequest === "number" && pullRequest > 0) {
return { pullRequestNumber: pullRequest };
}

throw error;
}

const mergeLabels = parseMergeLabels(env.MERGE_LABELS, "automerge");
const mergeRemoveLabels = parseMergeRemoveLabels(env.MERGE_REMOVE_LABELS, "");
const mergeMethod = env.MERGE_METHOD || "merge";
Expand All @@ -121,6 +164,8 @@ function createConfig(env = {}) {
const updateRetries = parsePositiveInt("UPDATE_RETRIES", 1);
const updateRetrySleep = parsePositiveInt("UPDATE_RETRY_SLEEP", 5000);

const pullRequest = parsePullRequest(env.PULL_REQUEST);

return {
mergeLabels,
mergeRemoveLabels,
Expand All @@ -137,7 +182,8 @@ function createConfig(env = {}) {
updateLabels,
updateMethod,
updateRetries,
updateRetrySleep
updateRetrySleep,
pullRequest
};
}

Expand Down
Loading

0 comments on commit 042e737

Please sign in to comment.