1
1
name : Update from Template
2
2
3
3
# 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
5
5
# this repos default branch (which is checked out here)
6
6
# Note that this requires a PAT (Personal Access Token) - at best from a servicing account
7
+ # PAT permissions: read:discussion, read:org, repo, workflow
7
8
# Also note that you should have at least once merged the template repo into the current repo manually
8
9
# otherwise a "refusing to merge unrelated histories" error might occur.
9
10
10
11
on :
11
12
schedule :
12
13
- cron : ' 55 2 * * 1'
13
14
workflow_dispatch :
15
+ inputs :
16
+ no_automatic_merge :
17
+ type : boolean
18
+ description : ' No automatic merge'
19
+ default : false
14
20
15
21
env :
16
22
UPDATE_BRANCH : update-from-template
23
+ UPDATE_BRANCH_MERGED : update-from-template-merged
17
24
REMOTE_URL : https://github.com/xdev-software/standard-maven-template.git
18
25
REMOTE_BRANCH : master
19
26
@@ -36,31 +43,34 @@ jobs:
36
43
37
44
- name : Init Git
38
45
run : |
39
- git config --global user.email "actions@ github.com"
40
- git config --global user.name "GitHub Actions "
46
+ git config --global user.email "111048771+xdev-gh-bot@users.noreply. github.com"
47
+ git config --global user.name "XDEV Bot "
41
48
42
- - name : Main workflow
43
- id : main
49
+ - name : Manage branches
50
+ id : manage-branches
44
51
run : |
45
52
echo "Adding remote template-repo"
46
53
git remote add template ${{ env.REMOTE_URL }}
47
54
48
55
echo "Fetching remote template repo"
49
56
git fetch template
50
57
51
- echo "Deleting local branch that will contain the updates - if present"
58
+ echo "Deleting local branches that will contain the updates - if present"
52
59
git branch -D ${{ env.UPDATE_BRANCH }} || true
60
+ git branch -D ${{ env.UPDATE_BRANCH_MERGED }} || true
53
61
54
62
echo "Checking if the remote template repo has new commits"
55
63
git rev-list ..template/${{ env.REMOTE_BRANCH }}
56
64
57
65
if [ $(git rev-list --count ..template/${{ env.REMOTE_BRANCH }}) -eq 0 ]; then
58
66
echo "There are no commits new commits on the template repo"
59
67
60
- echo "Deleting origin branch that contains the updates - if present"
68
+ echo "Deleting origin branch(es) that contain the updates - if present"
61
69
git push -f origin --delete ${{ env.UPDATE_BRANCH }} || true
70
+ git push -f origin --delete ${{ env.UPDATE_BRANCH_MERGED }} || true
62
71
63
- echo "abort=1" >> $GITHUB_OUTPUT
72
+ echo "create_update_branch_pr=0" >> $GITHUB_OUTPUT
73
+ echo "create_update_branch_merged_pr=0" >> $GITHUB_OUTPUT
64
74
exit 0
65
75
fi
66
76
@@ -73,21 +83,198 @@ jobs:
73
83
echo "Pushing update branch"
74
84
git push -f -u origin ${{ env.UPDATE_BRANCH }}
75
85
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
86
+ echo "Getting base branch"
87
+ base_branch =$(git branch --show-current)
88
+ echo "Base branch is $base_branch "
89
+ echo "base_branch=$base_branch " >> $GITHUB_OUTPUT
80
90
81
- echo "abort=0" >> $GITHUB_OUTPUT
91
+ echo "Trying to create auto-merged branch ${{ env.UPDATE_BRANCH_MERGED }}"
92
+ git branch ${{ env.UPDATE_BRANCH_MERGED }} ${{ env.UPDATE_BRANCH }}
93
+ git checkout ${{ env.UPDATE_BRANCH_MERGED }}
82
94
83
- - name : pull-request
84
- if : steps.main.outputs.abort == 0
95
+ echo "Merging branch $base_branch into ${{ env.UPDATE_BRANCH_MERGED }}"
96
+ git merge $base_branch && merge_exit_code=$? || merge_exit_code=$?
97
+ if [ $merge_exit_code -ne 0 ]; then
98
+ echo "Auto merge failed! Manual merge required"
99
+ echo "::notice ::Auto merge failed - Manual merge required"
100
+
101
+ echo "Cleaning up failed merge"
102
+ git merge --abort
103
+ git checkout $base_branch
104
+ git branch -D ${{ env.UPDATE_BRANCH_MERGED }} || true
105
+
106
+ echo "Deleting auto-merge branch - if present"
107
+ git push -f origin --delete ${{ env.UPDATE_BRANCH_MERGED }} || true
108
+
109
+ echo "create_update_branch_pr=1" >> $GITHUB_OUTPUT
110
+ echo "create_update_branch_merged_pr=0" >> $GITHUB_OUTPUT
111
+ exit 0
112
+ fi
113
+
114
+ echo "Post processing: Trying to automatically fill in template variables"
115
+ find . -type f \
116
+ -not -path "./.git/**" \
117
+ -not -path "./.github/workflows/update-from-template.yml" -print0 \
118
+ | xargs -0 sed -i "s/template-placeholder/${GITHUB_REPOSITORY#*/}/g"
119
+
120
+ git status
121
+ git add --all
122
+
123
+ if [[ "$(git status --porcelain)" != "" ]]; then
124
+ echo "Filled in template; Committing"
125
+
126
+ git commit -m "Fill in template"
127
+ fi
128
+
129
+ echo "Pushing auto-merged branch"
130
+ git push -f -u origin ${{ env.UPDATE_BRANCH_MERGED }}
131
+
132
+ echo "update_branch_merged_commit=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT
133
+
134
+ echo "Restoring base branch $base_branch"
135
+ git checkout $base_branch
136
+
137
+ echo "create_update_branch_pr=0" >> $GITHUB_OUTPUT
138
+ echo "create_update_branch_merged_pr=1" >> $GITHUB_OUTPUT
139
+ echo "try_close_update_branch_pr=1" >> $GITHUB_OUTPUT
140
+
141
+ - name : Create/Update PR update_branch
142
+ if : steps.manage-branches.outputs.create_update_branch_pr == 1
85
143
env :
86
- GH_TOKEN : ${{ secrets.GITHUB_TOKEN }}
144
+ GH_TOKEN : ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
87
145
run : |
88
146
gh_pr_up() {
89
147
gh pr create -H "${{ env.UPDATE_BRANCH }}" "$@" || (git checkout "${{ env.UPDATE_BRANCH }}" && gh pr edit "$@")
90
148
}
91
- gh_pr_up -B "${{ steps.main .outputs.current_branch }}" \
149
+ gh_pr_up -B "${{ steps.manage-branches .outputs.base_branch }}" \
92
150
--title "Update from template" \
93
151
--body "An automated PR to sync changes from the template into this repo"
152
+
153
+ # Ensure that only a single PR is open (otherwise confusion and spam)
154
+ - name : Close PR update_branch
155
+ if : steps.manage-branches.outputs.try_close_update_branch_pr == 1
156
+ env :
157
+ GH_TOKEN : ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
158
+ run : |
159
+ gh pr close "${{ env.UPDATE_BRANCH }}" || true
160
+
161
+ - name : Create/Update PR update_branch_merged
162
+ if : steps.manage-branches.outputs.create_update_branch_merged_pr == 1
163
+ env :
164
+ GH_TOKEN : ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
165
+ run : |
166
+ gh_pr_up() {
167
+ gh pr create -H "${{ env.UPDATE_BRANCH_MERGED }}" "$@" || (git checkout "${{ env.UPDATE_BRANCH_MERGED }}" && gh pr edit "$@")
168
+ }
169
+ gh_pr_up -B "${{ steps.manage-branches.outputs.base_branch }}" \
170
+ --title "Update from template (auto-merged)" \
171
+ --body "An automated PR to sync changes from the template into this repo"
172
+
173
+ - name : Checking if auto-merge for PR update_branch_merged can be done
174
+ id : auto-merge-check
175
+ if : steps.manage-branches.outputs.create_update_branch_merged_pr == 1
176
+ env :
177
+ GH_TOKEN : ${{ secrets.UPDATE_FROM_TEMPLATE_PAT }}
178
+ run : |
179
+ not_failed_conclusion="skipped|neutral|success"
180
+ not_relevant_app_slug="dependabot|github-pages"
181
+
182
+ echo "Waiting for workflows to start..."
183
+ sleep 60s
184
+
185
+ for i in {1..15}; do
186
+ echo "Checking if PR can be auto-merged. Try: $i"
187
+
188
+ echo "Fetching checks"
189
+ cs_response=$(curl -sL \
190
+ --fail-with-body \
191
+ --connect-timeout 60 \
192
+ --max-time 120 \
193
+ -H "Accept: application/vnd.github+json" \
194
+ -H "Authorization: Bearer $GH_TOKEN" \
195
+ -H "X-GitHub-Api-Version: 2022-11-28" \
196
+ https://api.github.com/repos/${{ github.repository }}/commits/${{ steps.manage-branches.outputs.update_branch_merged_commit }}/check-suites)
197
+
198
+ cs_data=$(echo $cs_response | jq '.check_suites[] | { conclusion: .conclusion, slug: .app.slug, check_runs_url: .check_runs_url }')
199
+ echo $cs_data
200
+
201
+ if [[ -z "$cs_data" ]]; then
202
+ echo "No check suite data - Assuming that there are no checks to run"
203
+
204
+ echo "perform=1" >> $GITHUB_OUTPUT
205
+ exit 0
206
+ fi
207
+
208
+ cs_failed=$(echo $cs_data | jq --arg x "$not_failed_conclusion" 'select ((.conclusion == null or (.conclusion | test($x))) | not)')
209
+ if [[ -z "$cs_failed" ]]; then
210
+ echo "No check failed so far; Checking if relevant checks are still running"
211
+
212
+ cs_relevant_still_running=$(echo $cs_data | jq --arg x "$not_relevant_app_slug" 'select (.conclusion == null and (.slug | test($x) | not))')
213
+ if [[ -z $cs_relevant_still_running ]]; then
214
+ echo "All relevant checks finished - PR can be merged"
215
+
216
+ echo "perform=1" >> $GITHUB_OUTPUT
217
+ exit 0
218
+ else
219
+ echo "Relevant checks are still running"
220
+ echo $cs_relevant_still_running
221
+ fi
222
+ else
223
+ echo "Detected failed check"
224
+ echo $cs_failed
225
+
226
+ echo "perform=0" >> $GITHUB_OUTPUT
227
+ exit 0
228
+ fi
229
+
230
+ echo "Waiting before next run..."
231
+ sleep 60s
232
+ done
233
+
234
+ echo "Timed out"
235
+ echo "perform=0" >> $GITHUB_OUTPUT
236
+
237
+ - name : Auto-merge update_branch_merged
238
+ if : steps.auto-merge-check.outputs.perform == 1
239
+ run : |
240
+ base_branch="${{ steps.manage-branches.outputs.base_branch }}"
241
+ echo "Restoring base branch $base_branch"
242
+ git checkout $base_branch
243
+
244
+ echo "Fetching..."
245
+ git fetch
246
+
247
+ expected_commit="${{ steps.manage-branches.outputs.update_branch_merged_commit }}"
248
+ actual_commit=$(git rev-parse origin/${{ env.UPDATE_BRANCH_MERGED }})
249
+ if [[ "$expected_commit" != "$actual_commit" ]]; then
250
+ echo "Branch ${{ env.UPDATE_BRANCH_MERGED }} contains unexpected commit $actual_commit"
251
+ echo "Expected: $expected_commit"
252
+
253
+ exit 0
254
+ fi
255
+
256
+ echo "Ensuring that current branch $base_branch is up-to-date"
257
+ git pull
258
+
259
+ echo "Merging ${{ env.UPDATE_BRANCH_MERGED }} into $base_branch"
260
+ git merge ${{ env.UPDATE_BRANCH_MERGED }} && merge_exit_code=$? || merge_exit_code=$?
261
+ if [ $merge_exit_code -ne 0 ]; then
262
+ echo "Unexpected merge failure $merge_exit_code - Requires manual resolution"
263
+
264
+ exit 0
265
+ fi
266
+
267
+ if [[ "${{ inputs.no_automatic_merge }}" == "true" ]]; then
268
+ echo "Exiting due no_automatic_merge"
269
+
270
+ exit 0
271
+ fi
272
+
273
+ echo "Pushing"
274
+ git push
275
+
276
+ echo "Cleaning up"
277
+ git branch -D ${{ env.UPDATE_BRANCH }} || true
278
+ git branch -D ${{ env.UPDATE_BRANCH_MERGED }} || true
279
+ git push -f origin --delete ${{ env.UPDATE_BRANCH }} || true
280
+ git push -f origin --delete ${{ env.UPDATE_BRANCH_MERGED }} || true
0 commit comments