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