Skip to content

Commit ce8bef4

Browse files
authored
Merge pull request #111 from xdev-software/update-from-template
Update from template
2 parents 56c2bed + eba545f commit ce8bef4

File tree

3 files changed

+241
-20
lines changed

3 files changed

+241
-20
lines changed
Lines changed: 239 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
name: Update from Template
22

33
# This workflow keeps the repo up to date with changes from the template repo (REMOTE_URL)
4-
# It duplicates the REMOTE_BRANCH (into UPDATE_BRANCH) and tries to merge it into the
4+
# It duplicates the REMOTE_BRANCH (into UPDATE_BRANCH) and tries to merge it into
55
# this repos default branch (which is checked out here)
66
# Note that this requires a PAT (Personal Access Token) - at best from a servicing account
7+
# PAT permissions: read:discussion, read:org, repo, workflow
78
# Also note that you should have at least once merged the template repo into the current repo manually
89
# otherwise a "refusing to merge unrelated histories" error might occur.
910

1011
on:
1112
schedule:
1213
- cron: '55 2 * * 1'
1314
workflow_dispatch:
15+
inputs:
16+
no_automatic_merge:
17+
type: boolean
18+
description: 'No automatic merge'
19+
default: false
1420

1521
env:
1622
UPDATE_BRANCH: update-from-template
23+
UPDATE_BRANCH_MERGED: update-from-template-merged
1724
REMOTE_URL: https://github.com/xdev-software/intellij-plugin-template.git
1825
REMOTE_BRANCH: master
1926

@@ -24,7 +31,9 @@ permissions:
2431
jobs:
2532
update:
2633
runs-on: ubuntu-latest
27-
34+
outputs:
35+
update_branch_merged_commit: ${{ steps.manage-branches.outputs.update_branch_merged_commit }}
36+
create_update_branch_merged_pr: ${{ steps.manage-branches.outputs.create_update_branch_merged_pr }}
2837
steps:
2938
- uses: actions/checkout@v4
3039
with:
@@ -36,31 +45,34 @@ jobs:
3645

3746
- name: Init Git
3847
run: |
39-
git config --global user.email "actions@github.com"
40-
git config --global user.name "GitHub Actions"
48+
git config --global user.email "[email protected].github.com"
49+
git config --global user.name "XDEV Bot"
4150
42-
- name: Main workflow
43-
id: main
51+
- name: Manage branches
52+
id: manage-branches
4453
run: |
4554
echo "Adding remote template-repo"
4655
git remote add template ${{ env.REMOTE_URL }}
4756
4857
echo "Fetching remote template repo"
4958
git fetch template
5059
51-
echo "Deleting local branch that will contain the updates - if present"
60+
echo "Deleting local branches that will contain the updates - if present"
5261
git branch -D ${{ env.UPDATE_BRANCH }} || true
62+
git branch -D ${{ env.UPDATE_BRANCH_MERGED }} || true
5363
5464
echo "Checking if the remote template repo has new commits"
5565
git rev-list ..template/${{ env.REMOTE_BRANCH }}
5666
5767
if [ $(git rev-list --count ..template/${{ env.REMOTE_BRANCH }}) -eq 0 ]; then
5868
echo "There are no commits new commits on the template repo"
5969
60-
echo "Deleting origin branch that contains the updates - if present"
70+
echo "Deleting origin branch(es) that contain the updates - if present"
6171
git push -f origin --delete ${{ env.UPDATE_BRANCH }} || true
72+
git push -f origin --delete ${{ env.UPDATE_BRANCH_MERGED }} || true
6273
63-
echo "abort=1" >> $GITHUB_OUTPUT
74+
echo "create_update_branch_pr=0" >> $GITHUB_OUTPUT
75+
echo "create_update_branch_merged_pr=0" >> $GITHUB_OUTPUT
6476
exit 0
6577
fi
6678
@@ -73,21 +85,230 @@ jobs:
7385
echo "Pushing update branch"
7486
git push -f -u origin ${{ env.UPDATE_BRANCH }}
7587
76-
echo "Getting current branch"
77-
current_branch=$(git branch --show-current)
78-
echo "Current branch is $current_branch"
79-
echo "current_branch=$current_branch" >> $GITHUB_OUTPUT
88+
echo "Getting base branch"
89+
base_branch=$(git branch --show-current)
90+
echo "Base branch is $base_branch"
91+
echo "base_branch=$base_branch" >> $GITHUB_OUTPUT
8092
81-
echo "abort=0" >> $GITHUB_OUTPUT
93+
echo "Trying to create auto-merged branch ${{ env.UPDATE_BRANCH_MERGED }}"
94+
git branch ${{ env.UPDATE_BRANCH_MERGED }} ${{ env.UPDATE_BRANCH }}
95+
git checkout ${{ env.UPDATE_BRANCH_MERGED }}
8296
83-
- name: pull-request
84-
if: steps.main.outputs.abort == 0
97+
echo "Merging branch $base_branch into ${{ env.UPDATE_BRANCH_MERGED }}"
98+
git merge $base_branch && merge_exit_code=$? || merge_exit_code=$?
99+
if [ $merge_exit_code -ne 0 ]; then
100+
echo "Auto merge failed! Manual merge required"
101+
echo "::notice ::Auto merge failed - Manual merge required"
102+
103+
echo "Cleaning up failed merge"
104+
git merge --abort
105+
git checkout $base_branch
106+
git branch -D ${{ env.UPDATE_BRANCH_MERGED }} || true
107+
108+
echo "Deleting auto-merge branch - if present"
109+
git push -f origin --delete ${{ env.UPDATE_BRANCH_MERGED }} || true
110+
111+
echo "create_update_branch_pr=1" >> $GITHUB_OUTPUT
112+
echo "create_update_branch_merged_pr=0" >> $GITHUB_OUTPUT
113+
exit 0
114+
fi
115+
116+
echo "Post processing: Trying to automatically fill in template variables"
117+
find . -type f \
118+
-not -path "./.git/**" \
119+
-not -path "./.github/workflows/update-from-template.yml" -print0 \
120+
| xargs -0 sed -i "s/template-placeholder/${GITHUB_REPOSITORY#*/}/g"
121+
122+
git status
123+
git add --all
124+
125+
if [[ "$(git status --porcelain)" != "" ]]; then
126+
echo "Filled in template; Committing"
127+
128+
git commit -m "Fill in template"
129+
fi
130+
131+
echo "Pushing auto-merged branch"
132+
git push -f -u origin ${{ env.UPDATE_BRANCH_MERGED }}
133+
134+
echo "update_branch_merged_commit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
135+
136+
echo "Restoring base branch $base_branch"
137+
git checkout $base_branch
138+
139+
echo "create_update_branch_pr=0" >> $GITHUB_OUTPUT
140+
echo "create_update_branch_merged_pr=1" >> $GITHUB_OUTPUT
141+
echo "try_close_update_branch_pr=1" >> $GITHUB_OUTPUT
142+
143+
- name: Create/Update PR update_branch
144+
if: steps.manage-branches.outputs.create_update_branch_pr == 1
85145
env:
86-
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
146+
GH_TOKEN: ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
87147
run: |
88148
gh_pr_up() {
89149
gh pr create -H "${{ env.UPDATE_BRANCH }}" "$@" || (git checkout "${{ env.UPDATE_BRANCH }}" && gh pr edit "$@")
90150
}
91-
gh_pr_up -B "${{ steps.main.outputs.current_branch }}" \
151+
gh_pr_up -B "${{ steps.manage-branches.outputs.base_branch }}" \
92152
--title "Update from template" \
93153
--body "An automated PR to sync changes from the template into this repo"
154+
155+
# Ensure that only a single PR is open (otherwise confusion and spam)
156+
- name: Close PR update_branch
157+
if: steps.manage-branches.outputs.try_close_update_branch_pr == 1
158+
env:
159+
GH_TOKEN: ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
160+
run: |
161+
gh pr close "${{ env.UPDATE_BRANCH }}" || true
162+
163+
- name: Create/Update PR update_branch_merged
164+
if: steps.manage-branches.outputs.create_update_branch_merged_pr == 1
165+
env:
166+
GH_TOKEN: ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
167+
run: |
168+
gh_pr_up() {
169+
gh pr create -H "${{ env.UPDATE_BRANCH_MERGED }}" "$@" || (git checkout "${{ env.UPDATE_BRANCH_MERGED }}" && gh pr edit "$@")
170+
}
171+
gh_pr_up -B "${{ steps.manage-branches.outputs.base_branch }}" \
172+
--title "Update from template (auto-merged)" \
173+
--body "An automated PR to sync changes from the template into this repo"
174+
175+
# Wait a moment so that checks of PR have higher prio than following job
176+
sleep 3
177+
178+
# Split into two jobs to help with executor starvation
179+
auto-merge:
180+
needs: [update]
181+
if: needs.update.outputs.create_update_branch_merged_pr == 1
182+
runs-on: ubuntu-latest
183+
steps:
184+
- uses: actions/checkout@v4
185+
with:
186+
# Required because otherwise there are always changes detected when executing diff/rev-list
187+
fetch-depth: 0
188+
# If no PAT is used the following error occurs on a push:
189+
# refusing to allow a GitHub App to create or update workflow `.github/workflows/xxx.yml` without `workflows` permission
190+
token: ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
191+
192+
- name: Init Git
193+
run: |
194+
git config --global user.email "[email protected]"
195+
git config --global user.name "XDEV Bot"
196+
197+
- name: Checking if auto-merge for PR update_branch_merged can be done
198+
id: auto-merge-check
199+
env:
200+
GH_TOKEN: ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
201+
run: |
202+
not_failed_conclusion="skipped|neutral|success"
203+
not_relevant_app_slug="dependabot|github-pages|sonarcloud"
204+
205+
echo "Waiting for checks to start..."
206+
sleep 40s
207+
208+
for i in {1..20}; do
209+
echo "Checking if PR can be auto-merged. Try: $i"
210+
211+
echo "Checking if update-branch-merged exists"
212+
git fetch
213+
if [[ $(git rev-parse origin/${{ env.UPDATE_BRANCH_MERGED }}) ]]; then
214+
echo "Branch origin/${{ env.UPDATE_BRANCH_MERGED }} is missing"
215+
exit 0
216+
fi
217+
218+
echo "Fetching checks"
219+
cs_response=$(curl -sL \
220+
--fail-with-body \
221+
--connect-timeout 60 \
222+
--max-time 120 \
223+
-H "Accept: application/vnd.github+json" \
224+
-H "Authorization: Bearer $GH_TOKEN" \
225+
-H "X-GitHub-Api-Version: 2022-11-28" \
226+
https://api.github.com/repos/${{ github.repository }}/commits/${{ needs.update.outputs.update_branch_merged_commit }}/check-suites)
227+
228+
cs_data=$(echo $cs_response | jq '.check_suites[] | { conclusion: .conclusion, slug: .app.slug, check_runs_url: .check_runs_url }')
229+
echo $cs_data
230+
231+
if [[ -z "$cs_data" ]]; then
232+
echo "No check suite data - Assuming that there are no checks to run"
233+
234+
echo "perform=1" >> $GITHUB_OUTPUT
235+
exit 0
236+
fi
237+
238+
cs_failed=$(echo $cs_data | jq --arg x "$not_failed_conclusion" 'select ((.conclusion == null or (.conclusion | test($x))) | not)')
239+
if [[ -z "$cs_failed" ]]; then
240+
echo "No check failed so far; Checking if relevant checks are still running"
241+
242+
cs_relevant_still_running=$(echo $cs_data | jq --arg x "$not_relevant_app_slug" 'select (.conclusion == null and (.slug | test($x) | not))')
243+
if [[ -z $cs_relevant_still_running ]]; then
244+
echo "All relevant checks finished - PR can be merged"
245+
246+
echo "perform=1" >> $GITHUB_OUTPUT
247+
exit 0
248+
else
249+
echo "Relevant checks are still running"
250+
echo $cs_relevant_still_running
251+
fi
252+
else
253+
echo "Detected failed check"
254+
echo $cs_failed
255+
256+
echo "perform=0" >> $GITHUB_OUTPUT
257+
exit 0
258+
fi
259+
260+
echo "Waiting before next run..."
261+
sleep 30s
262+
done
263+
264+
echo "Timed out - Assuming executor starvation - Forcing merge"
265+
echo "perform=1" >> $GITHUB_OUTPUT
266+
267+
- name: Auto-merge update_branch_merged
268+
if: steps.auto-merge-check.outputs.perform == 1
269+
run: |
270+
echo "Getting base branch"
271+
base_branch=$(git branch --show-current)
272+
echo "Base branch is $base_branch"
273+
274+
echo "Fetching..."
275+
git fetch
276+
if [[ $(git rev-parse origin/${{ env.UPDATE_BRANCH_MERGED }}) ]]; then
277+
echo "Branch origin/${{ env.UPDATE_BRANCH_MERGED }} is missing"
278+
exit 0
279+
fi
280+
281+
expected_commit="${{ needs.update.outputs.update_branch_merged_commit }}"
282+
actual_commit=$(git rev-parse origin/${{ env.UPDATE_BRANCH_MERGED }})
283+
if [[ "$expected_commit" != "$actual_commit" ]]; then
284+
echo "Branch ${{ env.UPDATE_BRANCH_MERGED }} contains unexpected commit $actual_commit"
285+
echo "Expected: $expected_commit"
286+
287+
exit 0
288+
fi
289+
290+
echo "Ensuring that current branch $base_branch is up-to-date"
291+
git pull
292+
293+
echo "Merging origin/${{ env.UPDATE_BRANCH_MERGED }} into $base_branch"
294+
git merge origin/${{ env.UPDATE_BRANCH_MERGED }} && merge_exit_code=$? || merge_exit_code=$?
295+
if [ $merge_exit_code -ne 0 ]; then
296+
echo "Unexpected merge failure $merge_exit_code - Requires manual resolution"
297+
298+
exit 0
299+
fi
300+
301+
if [[ "${{ inputs.no_automatic_merge }}" == "true" ]]; then
302+
echo "Exiting due no_automatic_merge"
303+
304+
exit 0
305+
fi
306+
307+
echo "Pushing"
308+
git push
309+
310+
echo "Cleaning up"
311+
git branch -D ${{ env.UPDATE_BRANCH }} || true
312+
git branch -D ${{ env.UPDATE_BRANCH_MERGED }} || true
313+
git push -f origin --delete ${{ env.UPDATE_BRANCH }} || true
314+
git push -f origin --delete ${{ env.UPDATE_BRANCH_MERGED }} || true

gradle/wrapper/gradle-wrapper.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
distributionBase=GRADLE_USER_HOME
22
distributionPath=wrapper/dists
3-
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
3+
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
44
networkTimeout=10000
55
validateDistributionUrl=true
66
zipStoreBase=GRADLE_USER_HOME

gradlew

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@
5555
# Darwin, MinGW, and NonStop.
5656
#
5757
# (3) This script is generated from the Groovy template
58-
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
58+
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
5959
# within the Gradle project.
6060
#
6161
# You can find Gradle at https://github.com/gradle/gradle/.

0 commit comments

Comments
 (0)