Skip to content

Commit 159ac27

Browse files
committed
Add retry logic and error propagation to automerge workflow
1 parent 57c31b3 commit 159ac27

1 file changed

Lines changed: 63 additions & 48 deletions

File tree

.github/workflows/automerge.yml

Lines changed: 63 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -46,54 +46,69 @@ jobs:
4646
julia <<'JL'
4747
using Dates, Base64
4848
49-
sh(cmd) = chomp(read(cmd, String))
50-
repo = ENV["REPO"]
51-
pr = parse(Int, ENV["PR_NUMBER"])
52-
53-
min_age = Minute(parse(Int, get(ENV,"MIN_AGE_MINUTES","10")))
54-
allowed = filter(!isempty, strip.(split(get(ENV,"ALLOWED_AUTHORS",""), ',')))
55-
head_prefix = get(ENV,"HEAD_PREFIX","")
56-
title_re = Regex(get(ENV,"TITLE_REGEX","^New version:"))
57-
commit_re = Regex(get(ENV,"COMMIT_REGEX","(?m)^Commit:"))
58-
method = get(ENV,"MERGE_METHOD","squash")
59-
del_branch = get(ENV,"DELETE_BRANCH","true") == "true"
60-
61-
jq = "[.state, (.draft|tostring), .title, .user.login, .base.ref, .head.ref, .head.repo.full_name, .created_at, .head.sha, (.body // \"\" | @base64)] | @tsv"
62-
63-
function meta()
64-
f = split(sh(`gh api repos/$repo/pulls/$pr --jq $jq`), '\t'; keepempty=true)
65-
state,draft,title,author,base,head,head_repo,created,sha,body64 = f
66-
body = String(base64decode(body64))
67-
return (; state,draft,title,author,base,head,head_repo,created,sha,body)
49+
function main()
50+
sh(cmd) = chomp(read(cmd, String))
51+
repo = ENV["REPO"]
52+
pr = parse(Int, ENV["PR_NUMBER"])
53+
54+
min_age = Minute(parse(Int, get(ENV,"MIN_AGE_MINUTES","10")))
55+
allowed = filter(!isempty, strip.(split(get(ENV,"ALLOWED_AUTHORS",""), ',')))
56+
head_prefix = get(ENV,"HEAD_PREFIX","")
57+
title_re = Regex(get(ENV,"TITLE_REGEX","^New version:"))
58+
commit_re = Regex(get(ENV,"COMMIT_REGEX","(?m)^Commit:"))
59+
method = get(ENV,"MERGE_METHOD","squash")
60+
del_branch = get(ENV,"DELETE_BRANCH","true") == "true"
61+
62+
jq = "[.state, (.draft|tostring), .title, .user.login, .base.ref, .head.ref, .head.repo.full_name, .created_at, .head.sha, (.body // \"\" | @base64)] | @tsv"
63+
64+
function meta(; retries=3, delay=5)
65+
for attempt in 1:retries
66+
try
67+
f = split(sh(`gh api repos/$repo/pulls/$pr --jq $jq`), '\t'; keepempty=true)
68+
state,draft,title,author,base,head,head_repo,created,sha,body64 = f
69+
body = String(base64decode(body64))
70+
return (; state,draft,title,author,base,head,head_repo,created,sha,body)
71+
catch e
72+
if attempt < retries
73+
@warn "Failed to fetch PR metadata (attempt $attempt/$retries), retrying in $(delay)s..." exception=e
74+
sleep(delay)
75+
else
76+
rethrow()
77+
end
78+
end
79+
end
80+
end
81+
82+
function eligible(m)
83+
m.state == "open" || return false
84+
m.draft == "false" || return false
85+
m.base == "main" || return false
86+
m.head_repo == repo || return false
87+
isempty(allowed) || (m.author in allowed) || return false
88+
isempty(head_prefix) || startswith(m.head, head_prefix) || return false
89+
occursin(title_re, m.title) || return false
90+
occursin(commit_re, m.body) || return false
91+
return true
92+
end
93+
94+
m = meta()
95+
eligible(m) || (println("PR #$pr not eligible; exiting."); return)
96+
97+
created = split(replace(m.created, "Z"=>""), ".")[1]
98+
created_dt = DateTime(created, dateformat"yyyy-mm-ddTHH:MM:SS")
99+
wait_ms = Dates.value((created_dt + min_age) - now())
100+
wait_ms > 0 && sleep(ceil(Int, wait_ms/1000))
101+
102+
m = meta()
103+
eligible(m) || (println("PR #$pr no longer eligible; exiting."); return)
104+
105+
run(`gh api -X PUT repos/$repo/pulls/$pr/merge -f merge_method=$method -f sha=$(m.sha)`)
106+
107+
if del_branch
108+
enc = replace(m.head, "/" => "%2F")
109+
try run(`gh api -X DELETE repos/$repo/git/refs/heads/$enc`) catch; end
110+
end
68111
end
69112
70-
function eligible(m)
71-
m.state == "open" || return false
72-
m.draft == "false" || return false
73-
m.base == "main" || return false
74-
m.head_repo == repo || return false
75-
isempty(allowed) || (m.author in allowed) || return false
76-
isempty(head_prefix) || startswith(m.head, head_prefix) || return false
77-
occursin(title_re, m.title) || return false
78-
occursin(commit_re, m.body) || return false
79-
return true
80-
end
81-
82-
m = meta()
83-
eligible(m) || (println("PR #$pr not eligible; exiting."); exit(0))
84-
85-
created = split(replace(m.created, "Z"=>""), ".")[1]
86-
created_dt = DateTime(created, dateformat"yyyy-mm-ddTHH:MM:SS")
87-
wait_ms = Dates.value((created_dt + min_age) - now())
88-
wait_ms > 0 && sleep(ceil(Int, wait_ms/1000))
89-
90-
m = meta()
91-
eligible(m) || (println("PR #$pr no longer eligible; exiting."); exit(0))
92-
93-
run(`gh api -X PUT repos/$repo/pulls/$pr/merge -f merge_method=$method -f sha=$(m.sha)`)
94-
95-
if del_branch
96-
enc = replace(m.head, "/" => "%2F")
97-
try run(`gh api -X DELETE repos/$repo/git/refs/heads/$enc`) catch; end
98-
end
113+
main()
99114
JL

0 commit comments

Comments
 (0)