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

GH Actions: sync PR improvements #5649

Merged
merged 2 commits into from
Jul 28, 2023
Merged
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
101 changes: 64 additions & 37 deletions .github/workflows/branch_sync.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ on:
push:
branches:
- '8.*.x'
schedule:
- cron: '33 04 * * 1-5' # 04:33 UTC Mon-Fri
workflow_dispatch:
inputs:
branch:
head_branch:
description: Branch to merge into master
required: true

Expand All @@ -15,26 +17,53 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 5
env:
BRANCH: ${{ inputs.branch || github.ref_name }}
HEAD_BRANCH: ${{ inputs.head_branch || github.ref_name }}
STATUS_JSON: https://raw.githubusercontent.com/cylc/cylc-admin/master/docs/status/branches.json
steps:
- name: Check branch name
shell: python
run: |
import os
import json
import sys
from urllib.request import urlopen

if os.environ['GITHUB_EVENT_NAME'] == 'schedule':
# Get branch from status page
meta = json.loads(
urlopen(os.environ['STATUS_JSON']).read()
)['meta_releases']
version = min(meta)
branch = meta[version][os.environ['GITHUB_REPOSITORY']]
else:
branch = os.environ['HEAD_BRANCH'].strip()

branch = os.environ['BRANCH'].strip()
if not branch:
sys.exit("::error::Branch name cannot be empty")
if branch.endswith('deconflict'):
sys.exit("::error::Do not run this workflow for already-created deconflict branches")
if branch.endswith('-sync'):
sys.exit("::error::Do not run this workflow for already-created sync branches")

with open(os.environ['GITHUB_ENV'], 'a') as F:
print(f'BRANCH={branch}', file=F)
print(f'DECONFLICT_BRANCH={branch}-deconflict', file=F)
print(f'HEAD_BRANCH={branch}', file=F)
print(f'SYNC_BRANCH={branch}-sync', file=F)

- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: master

- name: Configure git
uses: cylc/release-actions/configure-git@v1

- name: Attempt fast-forward
id: ff
continue-on-error: true
run: |
git merge "origin/${HEAD_BRANCH}" --ff-only
git push origin master

- name: Check for existing PR
id: check-pr
if: steps.ff.outcome == 'failure'
shell: python
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Expand All @@ -44,7 +73,7 @@ jobs:
import subprocess
import sys

for env_var in ('BRANCH', 'DECONFLICT_BRANCH'):
for env_var in ('HEAD_BRANCH', 'SYNC_BRANCH'):
branch = os.environ[env_var]
cmd = f'gh pr list -B master -H {branch} -s open --json url -R ${{ github.repository }}'
ret = subprocess.run(
Expand All @@ -55,66 +84,64 @@ jobs:
print(f"::error::{ret.stderr}")
if ret.returncode:
sys.exit(ret.returncode)
if json.loads(ret.stdout):
print(f"::notice::Found existing PR for {branch}")
results: list = json.loads(ret.stdout)
if results:
print(f"::notice::Found existing PR for {branch} - {results[0]['url']}")
sys.exit(0)

print("No open PRs found")
with open(os.environ['GITHUB_OUTPUT'], 'a') as f:
print('continue=true', file=f)

- name: Checkout
if: steps.check-pr.outputs.continue
uses: actions/checkout@v3
with:
fetch-depth: 0
ref: master

- name: Configure git
if: steps.check-pr.outputs.continue
uses: cylc/release-actions/configure-git@v1

- name: Attempt merge
id: merge
if: steps.check-pr.outputs.continue
continue-on-error: true
run: git merge "origin/${BRANCH}"
run: git merge "origin/${HEAD_BRANCH}"

- name: Abort merge
if: steps.merge.outcome == 'failure'
run: git merge --abort

- name: Diff
id: diff
if: steps.merge.outcome == 'success'
run: |
if [[ "$(git rev-parse HEAD)" == "$(git rev-parse origin/master)" ]]; then
echo "::notice::master is up to date with $BRANCH"
echo "::notice::master is up to date with $HEAD_BRANCH"
exit 0
fi
if git diff HEAD^ --exit-code --stat; then
echo "::notice::No diff between master and $BRANCH"
echo "::notice::No diff between master and $HEAD_BRANCH"
exit 0
fi
echo "continue=true" >> $GITHUB_OUTPUT

- name: Create deconflict branch
if: steps.merge.outcome == 'failure'
- name: Push sync branch
id: push
if: steps.merge.outcome == 'failure' || steps.diff.outputs.continue
run: |
git merge --abort
git checkout -b "$DECONFLICT_BRANCH" "origin/${BRANCH}"
git push origin "$DECONFLICT_BRANCH"
echo "BRANCH=${DECONFLICT_BRANCH}" >> $GITHUB_ENV
git checkout -b "$SYNC_BRANCH" "origin/${HEAD_BRANCH}"
git push origin "$SYNC_BRANCH"
echo "continue=true" >> $GITHUB_OUTPUT

- name: Open PR
if: steps.merge.outcome == 'failure' || steps.diff.outputs.continue
if: steps.push.outputs.continue
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
BODY: |
Please do a **normal merge**, not squash merge
Please do a **normal merge**, not squash merge.
Please fix conflicts if necessary.

---

Triggered by `${{ github.event_name }}`
run: |
gh pr create --head "$BRANCH" \
--title "🤖 Merge ${BRANCH} into master" \
url="$(
gh pr create --head "$SYNC_BRANCH" \
--title "🤖 Merge ${SYNC_BRANCH} into master" \
--body "$BODY"
)"
echo "::notice::PR created at ${url}"

gh pr edit "$BRANCH" --add-label "sync" || true
gh pr edit "$SYNC_BRANCH" --add-label "sync" || true
Loading