@@ -102,69 +102,98 @@ if (breakEarly) { return } // thanks Jenkins...
102102
103103// new data to be added to the past-jobs.json
104104// { lastTime: unixTimestamp, url: "" }
105- def buildCompletionData = [:]
105+ buildCompletionData = [:]
106106
107- for (buildObj in queue ) {
108- stage (buildObj .identifier ) {
109- // def json = writeJSON(json: buildObj, returnText: true)
110- // echo(json) // for debugging/data purposes
107+ // list of closures that we can use to wait for the jobs on.
108+ def waitQueue = [:]
109+ def addToWait (identifier , buildId , externalizableId ) {
110+ return {
111+ // "catchError" to set "stageResult" :(
112+ catchError (message : ' Build of "' + identifier + ' " failed' , buildResult : ' UNSTABLE' , stageResult : ' FAILURE' ) {
113+ stage (identifier ) {
114+ def res = waitForBuild (
115+ runId : externalizableId ,
116+ propagateAbort : true , // allow cancelling this job to cancel all the triggered jobs
117+ )
118+ buildCompletionData [buildId ] = [
119+ lastTime : (res .startTimeInMillis + res .duration ) / 1000 , // convert to seconds
120+ url : res .absoluteUrl ,
121+ ]
122+ if (res .result != ' SUCCESS' ) {
123+ // set stage result via catchError
124+ error (res .result )
125+ }
126+ }
127+ }
128+ }
129+ }
130+
131+ // stage to wrap up all the build job triggers that get waited on later
132+ stage (' trigger' ) {
133+ for (int i = 0 ; i < queue .size (); i ++ ) {
134+ def buildObj = queue [i ]
111135
112136 // "catchError" to set "stageResult" :(
113137 catchError (message : ' Build of "' + buildObj .identifier + ' " failed' , buildResult : ' UNSTABLE' , stageResult : ' FAILURE' ) {
114138 if (buildObj .gha_payload ) {
115- node {
116- withEnv ([
117- ' payload=' + buildObj .gha_payload ,
118- ]) {
119- withCredentials ([
120- string (
121- variable : ' GH_TOKEN' ,
122- credentialsId : ' github-access-token-docker-library-bot-meta' ,
123- ),
139+ stage (buildObj .identifier ) {
140+ node {
141+ withEnv ([
142+ ' payload=' + buildObj .gha_payload ,
124143 ]) {
125- sh ' ' '
126- set -u +x
127-
128- # https :// docs.github.com/en/free-pro-team@latest/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event
129- curl - fL \
130- - X POST \
131- - H ' Accept: application/vnd.github+json' \
132- - H "Authorization : Bearer $GH_TOKEN " \
133- - H ' X-GitHub-Api-Version: 2022-11-28' \
134- https :// api.github.com/repos/docker-library/meta/actions/workflows/build.yml/dispatches \
135- - d "$payload "
136- ' ' '
144+ withCredentials ([
145+ string (
146+ variable : ' GH_TOKEN' ,
147+ credentialsId : ' github-access-token-docker-library-bot-meta' ,
148+ ),
149+ ]) {
150+ sh ' ' '
151+ set -u +x
152+
153+ # https :// docs.github.com/en/free-pro-team@latest/rest/actions/workflows?apiVersion=2022-11-28#create-a-workflow-dispatch-event
154+ curl - fL \
155+ - X POST \
156+ - H ' Accept: application/vnd.github+json' \
157+ - H "Authorization : Bearer $GH_TOKEN " \
158+ - H ' X-GitHub-Api-Version: 2022-11-28' \
159+ https :// api.github.com/repos/docker-library/meta/actions/workflows/build.yml/dispatches \
160+ - d "$payload "
161+ ' ' '
162+ }
137163 }
164+ // record that GHA was triggered (for tracking continued triggers that fail to push an image)
165+ buildCompletionData [buildObj .buildId ] = [
166+ lastTime : System .currentTimeMillis () / 1000 , // convert to seconds
167+ url : currentBuild .absoluteUrl ,
168+ ]
138169 }
139- // record that GHA was triggered (for tracking continued triggers that fail to push an image)
140- buildCompletionData [buildObj .buildId ] = [
141- lastTime : System .currentTimeMillis () / 1000 , // convert to seconds
142- url : currentBuild .absoluteUrl ,
143- ]
144170 }
145171 } else {
172+ // why not parallel these build() invocations?
173+ // jenkins parallel closures get started in a randomish order, ruining our sorted queue
146174 def res = build (
147175 job : ' build' ,
148176 parameters : [
177+ string (name : ' identifier' , value : buildObj .identifier ),
149178 string (name : ' buildId' , value : buildObj .buildId ),
150179 ],
151180 propagate : false ,
152- quietPeriod : 5 , // seconds
181+ // trigger these quickly so they all get added to Jenkins queue in "queue" order
182+ quietPeriod : 0 , // seconds
183+ // we'll wait on them after they are all queued
184+ waitForStart : true ,
153185 )
154- // record the job failure
155- buildCompletionData [buildObj .buildId ] = [
156- lastTime : (res .startTimeInMillis + res .duration ) / 1000 , // convert to seconds
157- url : res .absoluteUrl ,
158- ]
159- if (res .result != ' SUCCESS' ) {
160- // set stage result via catchError
161- error (res .result )
162- }
186+ waitQueue [buildObj .identifier ] = addToWait (buildObj .identifier , buildObj .buildId , res .externalizableId )
163187 }
164188 }
165189 }
166190}
167191
192+ // wait on all the 'build' jobs that were queued
193+ if (waitQueue .size () > 0 ) {
194+ parallel waitQueue
195+ }
196+
168197// save currentJobs so we can use it next run as pastJobs
169198node {
170199 def buildCompletionDataJson = writeJSON (json : buildCompletionData , returnText : true )
0 commit comments