Skip to content

Commit

Permalink
Automatic cherry-pick script (#339)
Browse files Browse the repository at this point in the history
* Automatic cherry-pick script

* switch from alamb to apache

* autopep8

* flake8

* add rat

* tweaks

* Add some docs to the README
  • Loading branch information
alamb authored Jun 3, 2021
1 parent 7ec3158 commit 239558b
Show file tree
Hide file tree
Showing 2 changed files with 175 additions and 0 deletions.
28 changes: 28 additions & 0 deletions dev/release/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,3 +234,31 @@ following commands
(cd parquet && cargo publish)
(cd parquet_derive && cargo publish)
```

# Backporting

As of now, the plan for backporting to `active_release` is to do so semi-manually.

Step 1: Pick the commit to cherry-pick

Step 2: Create cherry-pick PR to active_release

Step 3a: If CI passes, merge cherry-pick PR

Step 3b: If CI doesn't pass or some other changes are needed, the PR should be reviewed / approved as normal prior to merge



For example, to backport `b2de5446cc1e45a0559fb39039d0545df1ac0d26` to active_release use the folliwing

```shell
git clone [email protected]:apache/arrow-rs.git /tmp/arrow-rs

ARROW_GITHUB_API_TOKEN=$ARROW_GITHUB_API_TOKEN CHECKOUT_ROOT=/tmp/arrow-rs CHERRY_PICK_SHA=b2de5446cc1e45a0559fb39039d0545df1ac0d26 python3 dev/release/cherry-pick-pr.py
```

## Rationale for creating PRs:
1. PRs are a natural place to run the CI tests to make sure there are no logical conflicts
2. PRs offer a place for the original author / committers to comment and say it should/should not be backported.
3. PRs offer a way to make cleanups / fixups and approve (if needed) for non cherry pick PRs
4. There is an additional control / review when the candidate release is created
147 changes: 147 additions & 0 deletions dev/release/cherry-pick-pr.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
#!/usr/bin/python3
##############################################################################
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
##############################################################################

# This script is designed to create a cherry pick PR to a target branch
#
# Usage: python3 cherry_pick_pr.py
#
# To test locally:
#
# git clone [email protected]:apache/arrow-rs.git /tmp/arrow-rs
#
# pip3 install PyGithub
# ARROW_GITHUB_API_TOKEN=<..>
# CHECKOUT_ROOT=<path>
# CHERRY_PICK_SHA=<sha> python3 cherry-pick-pr.py
#
import os
import sys
import six
import subprocess

from pathlib import Path

TARGET_BRANCH = 'active_release'
TARGET_REPO = 'apache/arrow-rs'

p = Path(__file__)

# Use github workspace if specified
repo_root = os.environ.get("CHECKOUT_ROOT")
if repo_root is None:
print("arrow-rs checkout must be supplied in CHECKOUT_ROOT environment")
sys.exit(1)

print("Using checkout in {}".format(repo_root))

token = os.environ.get('ARROW_GITHUB_API_TOKEN', None)
if token is None:
print("GITHUB token must be supplied in ARROW_GITHUB_API_TOKEN environmet")
sys.exit(1)

new_sha = os.environ.get('CHERRY_PICK_SHA', None)
if new_sha is None:
print("SHA to cherry pick must be supplied in CHERRY_PICK_SHA environment")
sys.exit(1)


# from merge_pr.py from arrow repo
def run_cmd(cmd):
if isinstance(cmd, six.string_types):
cmd = cmd.split(' ')
try:
output = subprocess.check_output(cmd)
except subprocess.CalledProcessError as e:
# this avoids hiding the stdout / stderr of failed processes
print('Command failed: %s' % cmd)
print('With output:')
print('--------------')
print(e.output)
print('--------------')
raise e

if isinstance(output, six.binary_type):
output = output.decode('utf-8')

return output


os.chdir(repo_root)
new_sha_short = run_cmd("git rev-parse --short {}".format(new_sha)).strip()
new_branch = 'cherry_pick_{}'.format(new_sha_short)


def make_cherry_pick():
if os.environ.get('GITHUB_SHA', None) is not None:
print("Running on github runner, setting email/username")
run_cmd(['git', 'config', 'user.email', '[email protected]'])
run_cmd(['git', 'config', 'user.name', 'Arrow-RS Automation'])

#
# Create a new branch from active_release
# and cherry pick to there.
#

print("Creating cherry pick from {} to {}".format(
new_sha_short, new_branch
))

# The following tortured dance is required due to how the github
# actions/checkout works (it doesn't pull other branches and pulls
# only one commit back)

# pull 10 commits back so we can get the proper cherry pick
# (probably only need 2 but 10 must be better, right?)
run_cmd(['git', 'fetch', '--depth', '10', 'origin', 'master'])
run_cmd(['git', 'fetch', 'origin', 'active_release'])
run_cmd(['git', 'checkout', '-b', new_branch])
run_cmd(['git', 'reset', '--hard', 'origin/active_release'])
run_cmd(['git', 'cherry-pick', new_sha])
run_cmd(['git', 'push', '-u', 'origin', new_branch])


def make_cherry_pick_pr():
from github import Github
g = Github(token)
repo = g.get_repo(TARGET_REPO)

# Default titles
new_title = 'Cherry pick {} to active_release'.format(new_sha)
new_commit_message = 'Automatic cherry-pick of {}\n'.format(new_sha)

# try and get info from github api
commit = repo.get_commit(new_sha)
for orig_pull in commit.get_pulls():
new_commit_message += '* Originally appeared in {}: {}\n'.format(
orig_pull.html_url, orig_pull.title)
new_title = 'Cherry pick {} to active_release'.format(orig_pull.title)

pr = repo.create_pull(title=new_title,
body=new_commit_message,
base='refs/heads/active_release',
head='refs/heads/{}'.format(new_branch),
maintainer_can_modify=True
)

print('Created PR {}'.format(pr.html_url))


make_cherry_pick()
make_cherry_pick_pr()

0 comments on commit 239558b

Please sign in to comment.