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

DRIVERS-2956 Add Script to Cherry-Pick PRs #470

Merged
merged 2 commits into from
Aug 22, 2024
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
23 changes: 20 additions & 3 deletions .evergreen/github_app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

## create_or_modify_comment

Uses `mongodb-drivers-comment-bot` to create/update comments on PRs
Uses `mongodb-drivers-pr-bot` to create/update comments on PRs
with the results of an EVG task. We offer a convenience script to install node,
fetch secrets and run the app:

Expand All @@ -14,7 +14,7 @@ Note: this script be run on a Linux EVG Host or locally. It will self-manage th

## apply-labels

Uses `mongodb-drivers-comment-bot` to apply labels according to [labeler](https://github.com/actions/labeler) config,
Uses `mongodb-drivers-pr-bot` to apply labels according to [labeler](https://github.com/actions/labeler) config,
without the need for a `pull_request_target` trigger. Note: only the `changed-files: > any-glob-to-any-file:` config
is currently implemented.

Expand All @@ -29,7 +29,7 @@ Note: this script can be run on a Linux EVG Host or locally. It will self-manag

## add-reviewer

Uses `mongodb-drivers-comment-bot` to apply add a random reviewer based on a text file.
Uses `mongodb-drivers-pr-bot` to apply add a random reviewer based on a text file.

We offer a convenience script to install node,
fetch secrets and run the app:
Expand All @@ -39,3 +39,20 @@ bash assign-reviewer.sh -o "<repo-owner>" -n "<repo-name>" -h "<head-commit-sha>
```

Note: this script can be run on a Linux EVG Host or locally. It will self-manage the credentials it needs.

## backport-pr

Uses `mongodb-drivers-pr-bot` to backport a PR from one branch to another. It is triggered by the magic
comment "drivers-pr-bot please backport to {target_branch}". The script should be run in an EVG task on a merge.
If the matching comment is found, it will attempt to create a new branch and cherry-pick the commit, and then
create a PR with the change. If the cherry-pick fails, it will create a comment on the PR with the instructions
to make the cherry-pick manually.

If the PR is merged and the task has already run before the magic comment is made, you can make the magic comment
and then manually restart the task to pick up the backport.

The script is called as:

```bash
bash backport-pr.sh {owner} {repo} {target_sha}
```
19 changes: 3 additions & 16 deletions .evergreen/github_app/apply-labels.mjs
Original file line number Diff line number Diff line change
@@ -1,20 +1,13 @@
/**
* Apply default GitHub PR labels using the mongodb-drivers-comment-bot.
* Apply default GitHub PR labels using the mongodb-drivers-pr-bot.
*/
import * as fs from "fs";
import { parse } from 'yaml';
import * as process from "process";
import { program } from 'commander';
import { App } from "octokit";
import { getOctokit } from './utils.mjs';
import { minimatch } from 'minimatch';

const appId = process.env.GITHUB_APP_ID;
const privateKey = process.env.GITHUB_SECRET_KEY.replace(/\\n/g, '\n');
if (appId == '' || privateKey == '') {
console.error("Missing GitHub App auth information");
process.exit(1)
}

// Handle cli.
program
.version('1.0.0', '-v, --version')
Expand All @@ -34,13 +27,7 @@ const {
} = options;

// Set up the app.
const installId = process.env['GITHUB_APP_INSTALL_ID_' + owner.toUpperCase()];
if (installId == '') {
console.error(`Missing install id for ${owner}`)
process.exit(1)
}
const app = new App({ appId, privateKey });
const octokit = await app.getInstallationOctokit(installId);
const octokit = await getOctokit(owner);
const headers = {
"x-github-api-version": "2022-11-28",
};
Expand Down
14 changes: 5 additions & 9 deletions .evergreen/github_app/apply-labels.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]})
. $SCRIPT_DIR/../handle-paths.sh
pushd $SCRIPT_DIR

# Bootstrap the secrets.
. ../secrets_handling/setup-secrets.sh drivers/comment-bot
# Bootstrap the app.
source utils.sh
bootstrap

# Install node and activate it.
bash ../install-node.sh
source ../init-node-and-npm-env.sh

# Install and run the app.
npm install
node apply-labels.mjs "$@"
# Run the app.
node assign-reviewer.mjs "$@"
popd
19 changes: 3 additions & 16 deletions .evergreen/github_app/assign-reviewer.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
/**
* Create or modify a GitHub comment using the mongodb-drivers-comment-bot.
* Create or modify a GitHub comment using the mongodb-drivers-pr-bot.
*/
import * as fs from "fs";
import * as process from "process";
import { program } from 'commander';
import { App } from "octokit";

const appId = process.env.GITHUB_APP_ID;
const privateKey = process.env.GITHUB_SECRET_KEY.replace(/\\n/g, '\n');
if (appId == '' || privateKey == '') {
console.error("Missing GitHub App auth information");
process.exit(1)
}
import { getOctokit } from './utils.mjs';

// Handle cli.
program
Expand All @@ -32,13 +25,7 @@ const {
} = options;

// Set up the app.
const installId = process.env['GITHUB_APP_INSTALL_ID_' + owner.toUpperCase()];
if (installId == '') {
console.error(`Missing install id for ${owner}`)
process.exit(1)
}
const app = new App({ appId, privateKey });
const octokit = await app.getInstallationOctokit(installId);
const octokit = await getOctokit(owner);
const headers = {
"x-github-api-version": "2022-11-28",
};
Expand Down
12 changes: 4 additions & 8 deletions .evergreen/github_app/assign-reviewer.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]})
. $SCRIPT_DIR/../handle-paths.sh
pushd $SCRIPT_DIR

# Bootstrap the secrets.
. ../secrets_handling/setup-secrets.sh drivers/comment-bot
# Bootstrap the app.
source utils.sh
bootstrap

# Install node and activate it.
bash ../install-node.sh
source ../init-node-and-npm-env.sh

# Install and run the app.
npm install
# Run the app.
node assign-reviewer.mjs "$@"
popd
120 changes: 120 additions & 0 deletions .evergreen/github_app/backport-pr.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#!/usr/bin/env bash
set -eu

SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]})
. $SCRIPT_DIR/../handle-paths.sh
pushd $SCRIPT_DIR

owner=$1
repo=$2
target_sha=$3

# Ensure that all variables required to run are given, otherwise throw
# an error.
for VARNAME in owner repo target_sha; do
[[ -z "${!VARNAME:-}" ]] && echo "ERROR: $VARNAME not set" && exit 1;
done

# Bootstrap the app.
source utils.sh
bootstrap

# Run the app.

# First find the target branch.
echo "Getting target branch..."
target_branch=$(node get_backport_target.mjs -o $owner -n $repo -h $target_sha)
if [ -z "${target_branch}" ]; then
echo "No matching cherry-pick comment!"
popd
exit 0
fi
echo "Target branch: $target_branch"
echo "Getting target branch... done."

# Get a github access token for the git checkout.
echo "Getting github token..."
token=$(bash ./get-access-token.sh $repo $owner)
if [ -z "${token}" ]; then
echo "Failed to get github access token!"
popd
exit 1
fi
echo "Getting github token... done."

# Make the git checkout and create a new branch.
echo "Creating the git checkout..."
dirname=$(mktemp -d)
branch="cherry-pick-$target_branch-$target_sha"
git clone https://github.com/$owner/$repo.git $dirname

pushd $dirname
git config user.email "167856002+mongodb-dbx-release-bot[bot]@users.noreply.github.com"
git config user.name "mongodb-dbx-release-bot[bot]"
git remote set-url origin https://x-access-token:${token}@github.com/$owner/$repo.git
git checkout -b $branch "origin/$target_branch"
echo "Creating the git checkout... done."

# Attempt to make the cherry-pick.
echo "Creating the cherry-pick..."
old_title=$(git --no-pager log $target_sha --pretty=%B | head -n 1)
title="${old_title} [${target_branch}]"
body="Cherry-pick of $target_sha to $target_branch"
if git cherry-pick -x -m1 $target_sha; then
# If the cherry-pick succeeds, push the branch and make a PR.
echo "Creating the cherry-pick..."
echo "Creating the PR..."
git push origin $branch
resp=$(curl -L \
-X POST \
-H "Accept: application/vnd.github+json" \
-H "Authorization: Bearer $token" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-d "{\"title\":\"${title}\",\"body\":\"${body}\",\"head\":\"${branch}\",\"base\":\"${target_branch}\"}" \
--url https://api.github.com/repos/$owner/$repo/pulls)
echo $resp | jq '.html_url'
echo "Creating the PR... done."
else
# If the cherry-pick fails, make a comment.
echo "Creating the cherry-pick... failed!"
echo "Creating the PR comment..."
message="Sorry, unable to cherry-pick to $target_branch"
cat << EOF >> comment.txt
$message, please backport manually. Here are approximate instructions:

1. Checkout backport branch and update it.

```
git checkout ${target_branch}
git pull
```

2. Cherry pick the first parent branch of the this PR on top of the older branch:
```
git cherry-pick -x -m1 ${target_sha}
```

3. You will likely have some merge/cherry-pick conflicts here, fix them and commit:

```
git commit -am {message}
```

4. Push to a named branch:

```
git push origin ${target_branch}:{remote_submit_branch}
```

5. Create a PR against branch ${target_branch}. I would have named this PR:

> "$title"
EOF
node create_or_modify_comment.sh -o $owner -n $repo -m $message -c comment.txt -h $target_sha
rm comment.txt
echo "Creating the PR comment... done."
fi

popd
rm -rf $dirname
popd
42 changes: 5 additions & 37 deletions .evergreen/github_app/create_or_modify_comment.mjs
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
/**
* Create or modify a GitHub comment using the mongodb-drivers-comment-bot.
* Create or modify a GitHub comment using the mongodb-drivers-pr-bot.
*/
import * as fs from "fs";
import * as process from "process";
import { program } from 'commander';
import { App } from "octokit";

const appId = process.env.GITHUB_APP_ID;
const privateKey = process.env.GITHUB_SECRET_KEY.replace(/\\n/g, '\n');
if (appId == '' || privateKey == '') {
console.error("Missing GitHub App auth information");
process.exit(1)
}
import { getOctokit, findComment } from './utils.mjs';

// Handle cli.
program
Expand All @@ -35,38 +28,13 @@ const {
const bodyText = fs.readFileSync(commentPath, { encoding: 'utf8' });

// Set up the app.
const installId = process.env['GITHUB_APP_INSTALL_ID_' + owner.toUpperCase()];
if (installId == '') {
console.error(`Missing install id for ${owner}`)
process.exit(1)
}
const app = new App({ appId, privateKey });
const octokit = await app.getInstallationOctokit(installId);
const octokit = await getOctokit(owner);
const headers = {
"x-github-api-version": "2022-11-28",
};

// Find the matching pull request.
let resp = await octokit.request("GET /repos/{owner}/{repo}/pulls?state=open&per_page=100", {
owner,
repo,
headers
});
const issue = resp.data.find(pr => pr.head.sha === targetSha);
if (issue == null) {
console.error(`ERROR: Could not find matching pull request for sha ${targetSha}`)
process.exit(1)
}
const { number: issueNumber } = issue

// Find a matching comment if it exists, and update it.
resp = await octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}/comments", {
owner,
repo,
issue_number: issueNumber,
headers
});
const comment = resp.data.find(comment => comment.body.includes(bodyMatch));
// Find a matching comment.
const comment = await findComment(octokit, owner, repo, targetSha, bodyMatch, "open");
if (!comment) {
// create comment.
await octokit.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", {
Expand Down
12 changes: 4 additions & 8 deletions .evergreen/github_app/create_or_modify_comment.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,10 @@ SCRIPT_DIR=$(dirname ${BASH_SOURCE[0]})
. $SCRIPT_DIR/../handle-paths.sh
pushd $SCRIPT_DIR

# Bootstrap the secrets.
. ../secrets_handling/setup-secrets.sh drivers/comment-bot
# Bootstrap the app.
source utils.sh
bootstrap

# Install node and activate it.
bash ../install-node.sh
source ../init-node-and-npm-env.sh

# Install and run the app.
npm install
# Run the app.
node create_or_modify_comment.mjs "$@"
popd
Loading
Loading