Skip to content

Commit d8299ac

Browse files
committed
sync-upstream: Add automatic GitHub Actions sync script
1 parent daf96bb commit d8299ac

2 files changed

Lines changed: 121 additions & 52 deletions

File tree

.github/workflows/sync.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: Upstream Sync
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 1 * *'
6+
workflow_dispatch:
7+
8+
permissions:
9+
contents: write
10+
pull-requests: write
11+
12+
jobs:
13+
sync-upstream:
14+
runs-on: ubuntu-latest
15+
env:
16+
UPSTREAM: "https://github.com/bitcoin-core/secp256k1.git"
17+
UPSTREAM_BRANCH: "master"
18+
ORIGIN_BRANCH: "master"
19+
MIN_UPSTREAM_MERGES: 1
20+
21+
steps:
22+
- name: Checkout repository
23+
uses: actions/checkout@v6
24+
with:
25+
fetch-depth: 0
26+
27+
- name: Configure Git
28+
run: |
29+
git config user.name "github-actions[bot]"
30+
git config user.email "github-actions[bot]@users.noreply.github.com"
31+
32+
- name: Fetch upstream & generate branch name & check for new commits
33+
id: check_commits
34+
env:
35+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
run: |
37+
gh repo set-default ${{ github.repository }} # Set the default repo to the origin repository
38+
git remote add upstream ${{ env.UPSTREAM }}
39+
git fetch upstream
40+
41+
MERGES=$(git rev-list --count --merges HEAD..upstream/${{ env.UPSTREAM_BRANCH }})
42+
echo "Found $MERGES new merge commits in upstream."
43+
44+
if [ "$MERGES" -lt ${{ env.MIN_UPSTREAM_MERGES }} ]; then
45+
echo "Exiting."
46+
echo "skip=true" >> "$GITHUB_OUTPUT"
47+
else
48+
echo "skip=false" >> "$GITHUB_OUTPUT"
49+
fi
50+
51+
# Generate a sync branch name "sync-UPSTREAM_HEAD", where UPSTREAM_HEAD is a commit ID.
52+
UPSTREAM_HEAD=$(git rev-parse --short upstream/${{ env.UPSTREAM_BRANCH }})
53+
SYNC_BRANCH="sync-$UPSTREAM_HEAD"
54+
echo "Sync branch name: $SYNC_BRANCH"
55+
echo "SYNC_BRANCH=$SYNC_BRANCH" >> "$GITHUB_ENV"
56+
57+
# Check if the sync branch already exists in the origin repository
58+
if git ls-remote --heads origin "$SYNC_BRANCH" | grep -q "$SYNC_BRANCH"; then
59+
echo "Branch $SYNC_BRANCH already exists. Skipping the sync."
60+
echo "skip=true" >> "$GITHUB_OUTPUT"
61+
else
62+
echo "skip=false" >> "$GITHUB_OUTPUT"
63+
fi
64+
65+
- name: Generate PR metadata
66+
id: branch_pr_metadata
67+
if: steps.check_commits.outputs.skip == 'false'
68+
env:
69+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
70+
run: |
71+
# Call the sync script to generate PR title and body
72+
./contrib/sync-upstream.sh -b ${{ env.ORIGIN_BRANCH }} "$SYNC_BRANCH"
73+
74+
- name: Push a sync branch
75+
id: push_branch
76+
if: steps.check_commits.outputs.skip == 'false'
77+
env:
78+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
79+
run: |
80+
echo "Creating sync branch: $SYNC_BRANCH"
81+
git checkout upstream/${{ env.UPSTREAM_BRANCH }}
82+
git checkout -b "$SYNC_BRANCH"
83+
git push -u origin "$SYNC_BRANCH"
84+
85+
- name: Create pull request
86+
id: create_pr
87+
if: steps.check_commits.outputs.skip == 'false'
88+
env:
89+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
90+
run: |
91+
# Execute the generated PR creation script
92+
./contrib/gh-pr-create.sh
93+
94+
- name: Cleanup sync branch on failure
95+
if: steps.push_branch.outcome == 'success' && steps.create_pr.outcome == 'failure'
96+
run: |
97+
echo "PR creation failed but branch was pushed. Deleting: $SYNC_BRANCH"
98+
git push origin --delete "$SYNC_BRANCH"

contrib/sync-upstream.sh

Lines changed: 23 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -6,53 +6,35 @@ help() {
66
echo "Sync merge commits from bitcoin-core/secp256k1 into secp256k1-zkp."
77
echo
88
echo "Usage:"
9-
echo " $0 [-b <branch>] [end]"
10-
echo " Merges every merge commit present in upstream/master and missing in <branch>"
11-
echo " (default: master). If the optional [end] commit is provided, only merges"
12-
echo " up to and including [end]."
9+
echo " $0 [-b <branch>] <pr_branch>"
10+
echo " Find every merge commit present in upstream/master and missing in <branch> (default: master)."
1311
echo
14-
echo "This tool creates a temporary branch and attempts to merge the upstream commits."
15-
echo "If there are merge conflicts, resolve them and run tests, then use the generated"
16-
echo "script contrib/gh-pr-create.sh to create the PR (requires the gh tool)."
12+
echo "This tool prepares the title and body for a sync PR"
13+
echo "and generates a helper script contrib/gh-pr-create.sh."
1714
echo
1815
echo "Setup:"
1916
echo " Requires a remote named 'upstream' pointing to bitcoin-core/secp256k1."
20-
echo " The script will fetch it automatically, and offer to create it if missing."
21-
echo " To add manually: git remote add upstream git@github.com:bitcoin-core/secp256k1.git"
2217
echo
2318
echo "Listing upstream merge commits:"
2419
echo " To list merge commits in upstream/master that are missing from <branch> (oldest first):"
2520
echo " git log --oneline --topo-order --reverse --merges \$(git merge-base upstream/master <branch>)..upstream/master"
26-
echo " These are candidates for [end]."
2721
exit 1
2822
}
2923

3024
REMOTE=upstream
3125
REMOTE_BRANCH="$REMOTE/master"
3226
LOCAL_BRANCH="master"
33-
# Makes sure you have a remote "upstream" that is up-to-date
34-
setup() {
35-
ret=0
36-
git fetch "$REMOTE" &> /dev/null || ret="$?"
37-
if [ ${ret} == 0 ]; then
38-
return
39-
fi
40-
echo "Adding remote \"$REMOTE\" with URL git@github.com:bitcoin-core/secp256k1.git. Continue with y"
41-
read -r yn
42-
case $yn in
43-
[Yy]* ) ;;
44-
* ) exit 1;;
45-
esac
46-
git remote add "$REMOTE" git@github.com:bitcoin-core/secp256k1.git &> /dev/null
47-
git fetch "$REMOTE" &> /dev/null
48-
}
27+
28+
if ! git remote get-url "$REMOTE" &> /dev/null; then
29+
echo "Error: Remote '$REMOTE' not found."
30+
echo "Add it with: git remote add upstream git@github.com:bitcoin-core/secp256k1.git"
31+
echo "Then run: git fetch upstream"
32+
exit 1
33+
fi
4934

5035
range() {
5136
RANGESTART_COMMIT=$(git merge-base "$REMOTE_BRANCH" "$LOCAL_BRANCH")
5237
RANGEEND_COMMIT=$(git rev-parse "$REMOTE_BRANCH")
53-
if [ "$#" = 1 ]; then
54-
RANGEEND_COMMIT=$1
55-
fi
5638
COMMITS=$(git --no-pager log --pretty=format:%H --topo-order --reverse --merges "$RANGESTART_COMMIT".."$RANGEEND_COMMIT")
5739
}
5840

@@ -74,12 +56,19 @@ done
7456

7557
# Shift off the processed options
7658
shift $((OPTIND -1))
59+
if [ "$#" -lt 1 ]; then
60+
echo "Error: <pr_branch> argument is required." >&2
61+
echo
62+
help
63+
exit 1
64+
fi
7765

78-
setup
79-
range "$@"
66+
# Extract the PR branch argument
67+
PR_BRANCH=$1
68+
69+
range
8070

8171
TITLE="Upstream PRs"
82-
REPRODUCE_COMMAND="$0 -b $LOCAL_BRANCH $RANGEEND_COMMIT"
8372
BODY=""
8473
for COMMIT in $COMMITS
8574
do
@@ -93,31 +82,18 @@ TITLE=${TITLE%?}
9382
BODY+=$(cat <<EOF
9483
9584
96-
This PR can be recreated with \`$REPRODUCE_COMMAND\`.
97-
9885
Tips:
9986
* Use \`git show --remerge-diff <pr-branch>\` to show the conflict resolution in the merge commit.
10087
* Use \`git read-tree --reset -u <pr-branch>\` to replay these resolutions during the conflict resolution stage when recreating the PR branch locally.
10188
Be aware that this may discard your index as well as the uncommitted changes and untracked files in your worktree.
10289
EOF
10390
)
10491

105-
echo "Merging $TITLE. Continue with y"
106-
read -r yn
107-
case $yn in
108-
[Yy]* ) ;;
109-
* ) exit 1;;
110-
esac
111-
11292
echo "-----------------------------------"
11393
echo "$TITLE"
11494
echo "-----------------------------------"
11595
echo "$BODY"
11696
echo "-----------------------------------"
117-
# Create branch from PR commit and create PR
118-
git checkout "$LOCAL_BRANCH"
119-
git pull --autostash
120-
git checkout -b temp-merge-"$PRNUM"
12197

12298
# Escape single quote
12399
# ' -> '\''
@@ -132,12 +108,7 @@ BASEDIR=$(dirname "$0")
132108
FNAME="$BASEDIR/gh-pr-create.sh"
133109
cat <<EOT > "$FNAME"
134110
#!/bin/sh
135-
gh pr create -t '$TITLE' -b '$BODY' --web
136-
# Remove temporary branch
137-
git checkout "$LOCAL_BRANCH"
138-
git branch -D temp-merge-"$PRNUM"
111+
gh pr create -t '$TITLE' -b '$BODY' --base '$LOCAL_BRANCH' --head '$PR_BRANCH'
139112
EOT
140113
chmod +x "$FNAME"
141-
echo Run "$FNAME" after solving the merge conflicts
142-
143-
git merge --no-edit -m "Merge upstream '${LAST_COMMIT:0:7}' into temp-merge-$PRNUM" "$LAST_COMMIT"
114+
echo "Generated $FNAME for creating a pull request with the above title and body."

0 commit comments

Comments
 (0)