Skip to content

Commit 70ccc92

Browse files
committed
Added workflow to perform scheduled auto merge from upstream envoy
This commit copies the workflow file and associated script from the previous default branch to the new default branch, because Github only executes workflows from the default branch. Signed-off-by: Ted Poole <[email protected]>
1 parent aaaa646 commit 70ccc92

File tree

3 files changed

+201
-0
lines changed

3 files changed

+201
-0
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Sync from Upstream (Scheduled)
2+
3+
permissions:
4+
contents: read
5+
6+
on:
7+
schedule:
8+
- cron: "0 1 * * *"
9+
workflow_dispatch:
10+
11+
concurrency:
12+
group: ${{ github.workflow }}
13+
14+
jobs:
15+
sync:
16+
if: github.repository == 'envoyproxy/envoy-openssl'
17+
runs-on: ubuntu-22.04
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
branch_name:
22+
- release/v1.32
23+
- release/v1.28
24+
steps:
25+
- id: appauth
26+
uses: envoyproxy/toolshed/gh-actions/[email protected]
27+
with:
28+
key: ${{ secrets.ENVOY_CI_UPDATE_BOT_KEY }}
29+
app_id: ${{ secrets.ENVOY_CI_UPDATE_APP_ID }}
30+
31+
# Checkout the branch we're merging into
32+
- name: "Checkout ${{ github.repository }}[${{ matrix.branch_name }}]"
33+
uses: actions/checkout@v4
34+
with:
35+
token: ${{ steps.appauth.outputs.token }}
36+
ref: ${{ matrix.branch_name }}
37+
fetch-depth: 0
38+
39+
# Configure the git user info on the repository
40+
- run: git config user.name "${{ github.actor }}"
41+
- run: git config user.email "${{ github.actor_id }}+${{ github.actor }}@users.noreply.github.com"
42+
43+
# Checkout & run the script from the default branch
44+
- name: 'Checkout ci/envoy-sync-receive.sh'
45+
uses: actions/checkout@v4
46+
with:
47+
ref: ${{ github.event.repository.default_branch }}
48+
sparse-checkout: 'ci/envoy-sync-receive.sh'
49+
sparse-checkout-cone-mode: false
50+
path: '.script'
51+
- run: .script/ci/envoy-sync-receive.sh ${{ matrix.branch_name }}
52+
env:
53+
GH_TOKEN: ${{ steps.appauth.outputs.token }}

README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,30 @@ repository, with the addition of:
3131
Note that the initial `release/v1.26` branch is *not* intended for production.
3232
It is anticipated that `release/v1.28` will be the first branch to reach production.
3333

34+
## Synchronizing
35+
36+
Since this repository is primarily a copy of the [envoyproxy/envoy](https://github.com/envoyproxy/envoy) repository,
37+
the process of keeping this repository in sync with the regular envoy repository is automated.
38+
39+
This automation is implemented by the
40+
[envoy-sync-scheduled.yaml](.github/workflows/envoy-sync-scheduled.yaml)
41+
workflow which executes on a daily schedule. For each of the branches listed in
42+
the workflow's strategy matrix, a merge is attempted from the [envoyproxy/envoy](https://github.com/envoyproxy/envoy)
43+
repository into the identically named branch in this repository.
44+
45+
- If the merge is successful, it:
46+
- pushes the feature branch to the repository
47+
- creates the associated pull request if it doesn't already exist
48+
- closes the associated issue if it already exists
49+
- If the merge is unsuccessful, it:
50+
- leaves the associated pull request untouched if it already exists
51+
- creates the associated issue issue if it doesn't already exist
52+
- adds a comment on the associated issue to describe the merge fail
53+
54+
Note that the feature branches created by this automation are named
55+
`auto-merge-<branch-name>`. These repeatable names allow the workflow to reuse &
56+
update existing branches and pull requests, rather than creating new ones each time.
57+
3458
## Building
3559

3660
The process for building envoy-openssl is very similar to building regular envoy, wherever possible

ci/envoy-sync-receive.sh

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
#!/usr/bin/env bash
2+
#
3+
# Copyright Red Hat
4+
#
5+
# This script is invoked from .github/workflow/envoy-sync-*.yaml workflows.
6+
#
7+
# It merges the specified branch from the upstream envoyproxy/envoy repository
8+
# into the current branch in the current working directory. It is assumed that
9+
# the calling workflow has already checked out the destination repository and
10+
# switched to the destination branch, in the current working directory before
11+
# invoking us.
12+
#
13+
# - If the merge is successful, it:
14+
# - pushes the feature branch to the repository
15+
# - creates the associated pull request if it doesn't already exist
16+
# - closes the associated issue if it already exists
17+
#
18+
# -If the merge is unsuccessful, it:
19+
# - leaves the associated pull request untouched if it already exists
20+
# - creates the associated issue issue if it doesn't already exist
21+
# - adds a comment on the associated issue to describe the merge fail
22+
#
23+
24+
set -euo pipefail
25+
26+
notice() { printf "::notice:: %s\n" "$1"; }
27+
28+
SCRATCH="$(mktemp -d)"
29+
cleanup() {
30+
local savexit=$?
31+
rm -rf -- "${SCRATCH}"
32+
exit "${savexit}"
33+
}
34+
trap 'cleanup' EXIT
35+
36+
SRC_REPO_URL="https://github.com/envoyproxy/envoy.git"
37+
SRC_REPO_PATH="${SRC_REPO_URL/#*github.com?/}"
38+
SRC_REPO_PATH="${SRC_REPO_PATH/%.git/}"
39+
SRC_BRANCH_NAME="$1"
40+
SRC_HEAD_SHA="$(git ls-remote "${SRC_REPO_URL}" | awk "/\srefs\/heads\/${SRC_BRANCH_NAME/\//\\\/}$/{print \$1}")"
41+
42+
DST_REPO_URL=$(git remote get-url origin)
43+
DST_REPO_PATH="${DST_REPO_URL/#*github.com?/}"
44+
DST_REPO_PATH="${DST_REPO_PATH/%.git/}"
45+
DST_BRANCH_NAME=$(git branch --show-current)
46+
DST_HEAD_SHA=$(git rev-parse HEAD)
47+
48+
# Add the remote upstream repo and fetch the specified branch
49+
git remote remove upstream &> /dev/null || true
50+
git remote add -f -t "${SRC_BRANCH_NAME}" upstream "${SRC_REPO_URL}"
51+
52+
# Compose text for pull request or issue title
53+
TITLE="auto-merge ${SRC_REPO_PATH}[${SRC_BRANCH_NAME}] "
54+
TITLE+="into ${DST_REPO_PATH}[${DST_BRANCH_NAME}]"
55+
56+
# Create a new branch name for the merge. Deliberately don't include
57+
# any commit hash or timestamp in the name to ensure it is repeatable.
58+
# This ensures that each time we get invoked, due to an upstream change,
59+
# we accumulate the changes in the same branch and pull request, rather
60+
# than creating new ones that superceed the old one(s) each time.
61+
DST_NEW_BRANCH_NAME="auto-merge-$(echo "${SRC_BRANCH_NAME}" | tr /. -)"
62+
63+
# Set the default remote for the gh command
64+
gh repo set-default "${DST_REPO_PATH}"
65+
66+
# Perform the merge using --no-ff option to force creating a merge commit
67+
if git merge --no-ff --log=10000 --signoff -m "${TITLE}" \
68+
"upstream/${SRC_BRANCH_NAME}" > "${SCRATCH}/mergeout"; then
69+
DST_NEW_HEAD_SHA="$(git rev-parse HEAD)"
70+
if [[ "${DST_NEW_HEAD_SHA}" != "${DST_HEAD_SHA}" ]]; then
71+
git push --force origin "HEAD:${DST_NEW_BRANCH_NAME}"
72+
PR_COUNT=$(gh pr list --head "${DST_NEW_BRANCH_NAME}" \
73+
--base "${DST_BRANCH_NAME}" \
74+
--state open | wc -l)
75+
if [[ "${PR_COUNT}" == "0" ]]; then
76+
PR_URL=$(gh pr create --head "${DST_NEW_BRANCH_NAME}" \
77+
--base "${DST_BRANCH_NAME}" \
78+
--title "${TITLE}" \
79+
--body "Generated by $(basename "$0")")
80+
MERGE_OUTCOME="Created ${PR_URL}"
81+
else
82+
PR_ID=$(gh pr list --head "${DST_NEW_BRANCH_NAME}" \
83+
--base "${DST_BRANCH_NAME}" \
84+
--state open | head -1 | cut -f1)
85+
PR_URL="https://github.com/${DST_REPO_PATH}/pull/${PR_ID}"
86+
MERGE_OUTCOME="Updated ${PR_URL}"
87+
fi
88+
else
89+
MERGE_OUTCOME="No changes"
90+
fi
91+
notice "${TITLE} successful (${MERGE_OUTCOME})"
92+
# Close any related issues with a comment describing why
93+
for ISSUE_ID in $(gh issue list -S "${TITLE} failed" | cut -f1); do
94+
ISSUE_URL="https://github.com/${DST_REPO_PATH}/issues/${ISSUE_ID}"
95+
gh issue close "${ISSUE_URL}" --comment "Successful ${TITLE} (${MERGE_OUTCOME})"
96+
notice "Closed ${ISSUE_URL}"
97+
done
98+
else # merge fail
99+
notice "${TITLE} failed"
100+
ISSUE_COUNT=$(gh issue list -S "${TITLE} failed" | wc -l)
101+
if [[ "${ISSUE_COUNT}" == "0" ]]; then
102+
ISSUE_URL=$(gh issue create --title "${TITLE} failed" --body "${TITLE} failed")
103+
ISSUE_ID="$(basename "${ISSUE_URL}")"
104+
ISSUE_OUTCOME="Created"
105+
else
106+
ISSUE_ID="$(gh issue list -S "${TITLE} failed sort:created-asc" | tail -1 | cut -f1)"
107+
ISSUE_URL="https://github.com/${DST_REPO_PATH}/issues/${ISSUE_ID}"
108+
ISSUE_OUTCOME="Updated"
109+
fi
110+
COMMENT_URL=$(\
111+
gh issue comment "${ISSUE_URL}" --body-file - <<-EOF
112+
Failed to ${TITLE}
113+
114+
Upstream : [${SRC_HEAD_SHA}](https://github.com/${SRC_REPO_PATH}/commit/${SRC_HEAD_SHA})
115+
Downstream : [${DST_HEAD_SHA}](https://github.com/${DST_REPO_PATH}/commit/${DST_HEAD_SHA})
116+
117+
\`\`\`
118+
$(cat "${SCRATCH}/mergeout" || true)
119+
\`\`\`
120+
EOF
121+
)
122+
notice "${ISSUE_OUTCOME} ISSUE#${ISSUE_ID} (${COMMENT_URL})"
123+
exit 1
124+
fi

0 commit comments

Comments
 (0)