1package base
2
3// This file contains gerrithub related definitions etc
4
5import (
6 "encoding/json"
7 "strings"
8
9 "cue.dev/x/githubactions"
10)
11
12// trybotWorkflows is a template for trybot-based repos
13trybotWorkflows: {
14 (trybot.key): githubactions.#Workflow & {
15 name: trybot.name
16 on: {
17 // Run nightly at 2am UTC without a cache to catch flakes.
18 schedule: [{cron: "0 2 * * *"}]
19 // Triggering a trybot job via a workflow_dispatch can be a useful way
20 // to manually or automatically start a job without needing to git push.
21 workflow_dispatch: {}
22 }
23 }
24 "\(trybot.key)_dispatch": trybotDispatchWorkflow
25 "push_tip_to_\(trybot.key)": pushTipToTrybotWorkflow
26}
27
28#dispatch: {
29 type: string
30 CL: int
31 patchset: int
32 targetBranch: *defaultBranch | string
33
34 let p = strings.Split("\(CL)", "")
35 let rightMostTwo = p[len(p)-2] + p[len(p)-1]
36 ref: *"refs/changes/\(rightMostTwo)/\(CL)/\(patchset)" | string
37}
38
39trybotDispatchWorkflow: bashWorkflow & {
40 #dummyDispatch?: #dispatch
41 name: "Dispatch \(trybot.key)"
42 on: {
43 repository_dispatch: {}
44 push: {
45 // To enable testing of the dispatch itself
46 branches: [testDefaultBranch]
47 }
48 }
49 jobs: {
50 (trybot.key): {
51 "runs-on": linuxSmallMachine + overrideCacheTagDispatch
52
53 let goodDummyData = [if json.Marshal(#dummyDispatch) != _|_ {true}, false][0]
54
55 // We set the "on" conditions above, but this would otherwise mean we
56 // run for all dispatch events.
57 if: "${{ (\(isTestDefaultBranch) && \(goodDummyData)) || github.event.client_payload.type == '\(trybot.key)' }}"
58
59 // See the comment below about the need for cases
60 let cases = [
61 {
62 condition: "!="
63 expr: "fromJSON(steps.payload.outputs.value)"
64 nameSuffix: "fake data"
65 },
66 {
67 condition: "=="
68 expr: "github.event.client_payload"
69 nameSuffix: "repository_dispatch payload"
70 },
71 ]
72
73 steps: [
74 writeNetrcFile,
75
76 {
77 name: "Write fake payload"
78 id: "payload"
79 if: "github.repository == '\(githubRepositoryPath)' && \(isTestDefaultBranch)"
80
81 // Use bash heredocs so that JSON's use of double quotes does
82 // not get interpreted as shell. Both in the running of the
83 // command itself, which itself is the echo-ing of a command to
84 // $GITHUB_OUTPUT.
85 run: #"""
86 cat <<EOD >> $GITHUB_OUTPUT
87 value<<DOE
88 \#(*json.Marshal(#dummyDispatch) | "null")
89 DOE
90 EOD
91 """#
92 },
93
94 // GitHub does not allow steps with the same ID, even if (by virtue
95 // of runtime 'if' expressions) both would not actually run. So
96 // we have to duplciate the steps that follow with those same
97 // runtime expressions
98 //
99 // Hence we have to create two steps, one to trigger if the
100 // repository_dispatch payload is set, and one if not (i.e. we use
101 // the fake payload).
102 for v in cases {
103 let localBranchExpr = "local_${{ \(v.expr).targetBranch }}"
104 let targetBranchExpr = "${{ \(v.expr).targetBranch }}"
105 {
106 name: "Trigger \(trybot.name) (\(v.nameSuffix))"
107 if: "github.event.client_payload.type \(v.condition) '\(trybot.key)'"
108 run: """
109 mkdir tmpgit
110 cd tmpgit
111 git init -b initialbranch
112 git config user.name \(botGitHubUser)
113 git config user.email \(botGitHubUserEmail)
114 git config http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n \(botGitHubUser):${{ secrets.\(botGitHubUserTokenSecretsKey) }} | base64)"
115 git remote add origin \(gerritHubRepositoryURL)
116
117 git fetch origin ${{ \(v.expr).ref }}
118 git checkout -b \(localBranchExpr) FETCH_HEAD
119
120 # Error if we already have dispatchTrailer according to git log logic.
121 # See earlier check for GitHub expression logic check.
122 x="$(git log -1 --pretty='%(trailers:key=\(dispatchTrailer),valueonly)')"
123 if [[ "$x" != "" ]]
124 then
125 echo "Ref ${{ \(v.expr).ref }} already has a \(dispatchTrailer)"
126 exit 1
127 fi
128
129 # Add the trailer because we don't have it yet. GitHub expressions do not have a
130 # substitute or quote capability. So we do that in shell. We also strip out the
131 # indenting added by toJSON. We ensure that the type field is first in order
132 # that we can safely check for specific types of dispatch trailer.
133 #
134 # Use bash heredoc so that JSON's use of double quotes does
135 # not get interpreted as shell.
136 trailer="$(cat <<EOD | jq -r -c '{type} + .'
137 ${{ toJSON(\(v.expr)) }}
138 EOD
139 )"
140 # --no-divider prevents a "---" line from marking the end of the commit message.
141 # Here, we know that the input is exactly one commit message,
142 # so don't do weird things if the commit message has a "---" line.
143 git log -1 --format=%B | git interpret-trailers --no-divider --trailer "\(dispatchTrailer): $trailer" | git commit --amend -F -
144 git log -1
145
146 success=false
147 for try in {1..20}; do
148 echo "Push to trybot try $try"
149 if git push -f \(trybotRepositoryURL) \(localBranchExpr):\(targetBranchExpr); then
150 success=true
151 break
152 fi
153 sleep 1
154 done
155 if ! $success; then
156 echo "Giving up"
157 exit 1
158 fi
159 """
160 }
161 },
162 ]
163 }
164 }
165}
166
167pushTipToTrybotWorkflow: bashWorkflow & {
168 on: {
169 push: branches: protectedBranchPatterns
170 }
171 name: "Push tip to \(trybot.key)"
172 concurrency: "push_tip_to_trybot"
173
174 jobs: push: {
175 "runs-on": linuxSmallMachine + overrideCacheTagDispatch
176 if: "${{github.repository == '\(githubRepositoryPath)'}}"
177 steps: [
178 writeNetrcFile,
179 {
180 name: "Push tip to trybot"
181 run: """
182 mkdir tmpgit
183 cd tmpgit
184 git init -b initialbranch
185 git config user.name \(botGitHubUser)
186 git config user.email \(botGitHubUserEmail)
187 git config http.https://github.com/.extraheader "AUTHORIZATION: basic $(echo -n \(botGitHubUser):${{ secrets.\(botGitHubUserTokenSecretsKey) }} | base64)"
188 git remote add origin \(gerritHubRepositoryURL)
189 git remote add trybot \(trybotRepositoryURL)
190
191 git fetch origin "${{ github.ref }}"
192
193 success=false
194 for try in {1..20}; do
195 echo "Push to trybot try $try"
196 if git push -f trybot "FETCH_HEAD:${{ github.ref }}"; then
197 success=true
198 break
199 fi
200 sleep 1
201 done
202 if ! $success; then
203 echo "Giving up"
204 exit 1
205 fi
206 """
207 },
208 ]
209 }
210
211}
212
213writeNetrcFile: githubactions.#Step & {
214 name: "Write netrc file for \(botGerritHubUser) Gerrithub"
215 run: """
216 cat <<EOD > ~/.netrc
217 machine \(gerritHubHostname)
218 login \(botGerritHubUser)
219 password ${{ secrets.\(botGerritHubUserPasswordSecretsKey) }}
220 EOD
221 chmod 600 ~/.netrc
222 """
223}