1515*/
1616def withDefaultPrComments (closure ) {
1717 catchErrors {
18+ // sendCommentOnError() needs to know if comments are enabled, so lets track it with a global
19+ // isPr() just ensures this functionality is skipped for non-PR builds
20+ buildState. set(' PR_COMMENTS_ENABLED' , isPr())
1821 catchErrors {
1922 closure()
2023 }
24+ sendComment(true )
25+ }
26+ }
2127
22- if (! params. ENABLE_GITHUB_PR_COMMENTS || ! isPr()) {
23- return
24- }
28+ def sendComment (isFinal = false ) {
29+ if (! buildState. get(' PR_COMMENTS_ENABLED' )) {
30+ return
31+ }
2532
26- def status = buildUtils. getBuildStatus()
27- if (status == " ABORTED" ) {
28- return ;
29- }
33+ def status = buildUtils. getBuildStatus()
34+ if (status == " ABORTED" ) {
35+ return
36+ }
3037
31- def lastComment = getLatestBuildComment()
32- def info = getLatestBuildInfo(lastComment) ?: [:]
33- info. builds = (info. builds ?: []). takeRight(5 ) // Rotate out old builds
38+ def lastComment = getLatestBuildComment()
39+ def info = getLatestBuildInfo(lastComment) ?: [:]
40+ info. builds = (info. builds ?: []). takeRight(5 ) // Rotate out old builds
41+
42+ // If two builds are running at the same time, the first one should not post a comment after the second one
43+ if (info. number && info. number. toInteger() > env. BUILD_NUMBER . toInteger()) {
44+ return
45+ }
3446
35- def message = getNextCommentMessage(info)
36- postComment(message)
47+ def shouldUpdateComment = !! info. builds. find { it. number == env. BUILD_NUMBER }
48+
49+ def message = getNextCommentMessage(info, isFinal)
50+
51+ if (shouldUpdateComment) {
52+ updateComment(lastComment. id, message)
53+ } else {
54+ createComment(message)
3755
3856 if (lastComment && lastComment. user. login == ' kibanamachine' ) {
3957 deleteComment(lastComment. id)
4058 }
4159 }
4260}
4361
62+ def sendCommentOnError (Closure closure ) {
63+ try {
64+ closure()
65+ } catch (ex) {
66+ // If this is the first failed step, it's likely that the error hasn't propagated up far enough to mark the build as a failure
67+ currentBuild. result = ' FAILURE'
68+ catchErrors {
69+ sendComment(false )
70+ }
71+ throw ex
72+ }
73+ }
74+
4475// Checks whether or not this currently executing build was triggered via a PR in the elastic/kibana repo
4576def isPr () {
4677 return !! (env. ghprbPullId && env. ghprbPullLink && env. ghprbPullLink =~ / \/ elastic\/ kibana\/ / )
@@ -66,7 +97,7 @@ def getLatestBuildInfo() {
6697}
6798
6899def getLatestBuildInfo (comment ) {
69- return comment ? getBuildInfoFromComment(comment) : null
100+ return comment ? getBuildInfoFromComment(comment. body ) : null
70101}
71102
72103def createBuildInfo () {
@@ -137,14 +168,25 @@ def getTestFailuresMessage() {
137168 return messages. join(" \n " )
138169}
139170
140- def getNextCommentMessage (previousCommentInfo = [:]) {
171+ def getNextCommentMessage (previousCommentInfo = [:], isFinal = false ) {
141172 def info = previousCommentInfo ?: [:]
142173 info. builds = previousCommentInfo. builds ?: []
143174
175+ // When we update an in-progress comment, we need to remove the old version from the history
176+ info. builds = info. builds. findAll { it. number != env. BUILD_NUMBER }
177+
144178 def messages = []
145179 def status = buildUtils. getBuildStatus()
146180
147- if (status == ' SUCCESS' ) {
181+ if (! isFinal) {
182+ def failuresPart = status != ' SUCCESS' ? ' , with failures' : ' '
183+ messages << """
184+ ## :hourglass_flowing_sand: Build in-progress${ failuresPart}
185+ * [continuous-integration/kibana-ci/pull-request](${ env.BUILD_URL} )
186+ * Commit: ${ getCommitHash()}
187+ * This comment will update when the build is complete
188+ """
189+ } else if (status == ' SUCCESS' ) {
148190 messages << """
149191 ## :green_heart: Build Succeeded
150192 * [continuous-integration/kibana-ci/pull-request](${ env.BUILD_URL} )
@@ -172,7 +214,9 @@ def getNextCommentMessage(previousCommentInfo = [:]) {
172214 * [Pipeline Steps](${ env.BUILD_URL} flowGraphTable) (look for red circles / failed steps)
173215 * [Interpreting CI Failures](https://www.elastic.co/guide/en/kibana/current/interpreting-ci-failures.html)
174216 """
217+ }
175218
219+ if (status != ' SUCCESS' && status != ' UNSTABLE' ) {
176220 try {
177221 def steps = getFailedSteps()
178222 if (steps?. size() > 0 ) {
@@ -207,7 +251,7 @@ def getNextCommentMessage(previousCommentInfo = [:]) {
207251 .join(" \n\n " )
208252}
209253
210- def postComment (message ) {
254+ def createComment (message ) {
211255 if (! isPr()) {
212256 error " Trying to post a GitHub PR comment on a non-PR or non-elastic PR build"
213257 }
@@ -223,6 +267,20 @@ def getComments() {
223267 }
224268}
225269
270+ def updateComment (commentId , message ) {
271+ if (! isPr()) {
272+ error " Trying to post a GitHub PR comment on a non-PR or non-elastic PR build"
273+ }
274+
275+ withGithubCredentials {
276+ def path = " repos/elastic/kibana/issues/comments/${ commentId} "
277+ def json = toJSON([ body : message ]). toString()
278+
279+ def resp = githubApi([ path : path ], [ method : " POST" , data : json, headers : [ " X-HTTP-Method-Override" : " PATCH" ] ])
280+ return toJSON(resp)
281+ }
282+ }
283+
226284def deleteComment (commentId ) {
227285 withGithubCredentials {
228286 def path = " repos/elastic/kibana/issues/comments/${ commentId} "
0 commit comments