Skip to content

Commit

Permalink
[Branch-3.0][Feat](GA)automatically cherry-pick (apache#42435)
Browse files Browse the repository at this point in the history
## Proposed changes

This PR helps us automatically cherry-pick commits from one PR to other
branches while preserving the original commit information. The specific
rules are as follows:↳

If a PR submitted to the main branch is merged and the label includes
‘dev/3.0.x’, it will automatically create a new branch, cherry-pick the
commit, and then create a PR. If conflicts arise, the original PR will
be tagged with a label.

## Test

#42

#40

#40

https://github.com/CalvinKirs/incubator-doris/actions/workflows/auto-pick.yml

## todo

(cherry picked from commit bd9d58d)
  • Loading branch information
CalvinKirs committed Oct 24, 2024
1 parent 7d872f9 commit 16b31fd
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
50 changes: 50 additions & 0 deletions .github/workflows/auto-cherry-pick.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# 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.
#
name: Auto Cherry-Pick to Branch

on:
pull_request:
types:
- closed
branches:
- master

jobs:
auto_cherry_pick:
runs-on: ubuntu-latest
if: ${{ contains(github.event.pull_request.labels.*.name, 'dev/3.0.x') && github.event.pull_request.merged == true }}
steps:
- name: Checkout repository
uses: actions/checkout@v3

- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'

- name: Install dependencies
run: |
pip install PyGithub
- name: Auto cherry-pick
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
REPO_NAME: ${{ github.repository }}
CONFLICT_LABEL: cherry-pick-conflict-in-3.0
run: |
python tools/auto-pick-script.py ${{ github.event.pull_request.number }} branch-3.0
105 changes: 105 additions & 0 deletions tools/tools/auto-pick-script.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/usr/bin/env 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.

import os
import sys
from github import Github
import subprocess

# Get GitHub personal access token and other parameters
GITHUB_TOKEN = os.getenv('GITHUB_TOKEN')
REPO_NAME = os.getenv('REPO_NAME', 'apache/doris') # Default repository name
CONFLICT_LABEL = os.getenv('CONFLICT_LABEL', 'cherry-pick-conflict') # Conflict label from environment variable

# Check if the required command-line arguments are provided
if len(sys.argv) != 3:
print("Usage: python script.py <PR_NUMBER> <TARGET_BRANCH>")
sys.exit(1)

pr_number = int(sys.argv[1]) # PR number from command-line argument
TARGET_BRANCH = sys.argv[2] # Target branch from command-line argument

# Create GitHub instance
g = Github(GITHUB_TOKEN)
repo = g.get_repo(REPO_NAME)

# Get the specified PR
pr = repo.get_pull(pr_number)

# Check if the PR has been merged
if not pr.merged:
print(f"PR #{pr_number} has not been merged yet.")
exit(1)

merge_commit_sha = pr.merge_commit_sha

# Get the latest commit from the target branch
base_branch = repo.get_branch(TARGET_BRANCH)

# Create a new branch for cherry-picking the PR
new_branch_name = f'auto-pick-{pr.number}-{TARGET_BRANCH}'
repo.create_git_ref(ref=f'refs/heads/{new_branch_name}', sha=base_branch.commit.sha)
print(f"Created new branch {new_branch_name} from {TARGET_BRANCH}.")
subprocess.run(["git", "config", "--global", "credential.helper", "store"], check=True)

# Clone the repository locally and switch to the new branch
repo_url = f"https://x-access-token:{GITHUB_TOKEN}@github.com/{REPO_NAME}.git"
subprocess.run(["git", "clone", repo_url])
repo_dir = REPO_NAME.split("/")[-1] # Get the directory name
subprocess.run(["git", "checkout", new_branch_name], cwd=repo_dir)

# Set Git user identity for commits
subprocess.run(["git", "config", "user.email", "[email protected]"], cwd=repo_dir)
subprocess.run(["git", "config", "user.name", "Your Name"], cwd=repo_dir)


# Execute the cherry-pick operation
try:
subprocess.run(["git", "cherry-pick", merge_commit_sha], cwd=repo_dir, check=True)
print(f"Successfully cherry-picked commit {merge_commit_sha} into {new_branch_name}.")

# Check if the commit is present in the new branch
commit_check = subprocess.run(
["git", "rev-list", "--count", f"{merge_commit_sha}"],
cwd=repo_dir,
capture_output=True,
text=True
)

if commit_check.returncode == 0 and int(commit_check.stdout.strip()) > 0:
# Push the new branch
subprocess.run(["git", "push", "origin", new_branch_name], cwd=repo_dir, check=True)
print(f"Pushed new branch {new_branch_name} to origin.")

# Create a new PR for the cherry-picked changes
new_pr = repo.create_pull(
title=f"{TARGET_BRANCH}: {pr.title}", # Prefix with branch name
body=pr.body, # Keep the original PR body
head=new_branch_name,
base=TARGET_BRANCH
)

print(f"Created a new PR #{new_pr.number} for cherry-picked changes.")
else:
print(f"Commit {merge_commit_sha} was not found in {new_branch_name} after cherry-picking.")

except subprocess.CalledProcessError:
print(f"Conflict occurred while cherry-picking commit {merge_commit_sha}.")
# Add conflict label
pr.add_to_labels(CONFLICT_LABEL)
print(f"Added label '{CONFLICT_LABEL}' to PR #{pr.number} due to conflict.")

0 comments on commit 16b31fd

Please sign in to comment.