@@ -16,6 +16,11 @@ import (
1616 "github.com/ovh/cds/sdk/log"
1717)
1818
19+ type VCSEventMessenger struct {
20+ commitsStatuses map [string ][]sdk.VCSCommitStatus
21+ vcsClient sdk.VCSAuthorizedClient
22+ }
23+
1924// ResyncCommitStatus resync commit status for a workflow run
2025func ResyncCommitStatus (ctx context.Context , db gorp.SqlExecutor , store cache.Store , proj sdk.Project , wr * sdk.WorkflowRun ) error {
2126 _ , end := observability .Span (ctx , "workflow.resyncCommitStatus" ,
@@ -24,91 +29,108 @@ func ResyncCommitStatus(ctx context.Context, db gorp.SqlExecutor, store cache.St
2429 )
2530 defer end ()
2631
27- for nodeID , nodeRuns := range wr .WorkflowNodeRuns {
32+ eventMessenger := & VCSEventMessenger {commitsStatuses : make (map [string ][]sdk.VCSCommitStatus )}
33+ for _ , nodeRuns := range wr .WorkflowNodeRuns {
2834 sort .Slice (nodeRuns , func (i , j int ) bool {
2935 return nodeRuns [i ].SubNumber >= nodeRuns [j ].SubNumber
3036 })
3137 nodeRun := nodeRuns [0 ]
3238
33- if ! sdk . StatusIsTerminated ( nodeRun . Status ) {
34- continue
39+ if err := eventMessenger . SendVCSEvent ( ctx , db , store , proj , * wr , nodeRun ); err != nil {
40+ log . Error ( ctx , "resyncCommitStatus > unable to send vcs event: %v" , err )
3541 }
42+ }
43+
44+ return nil
45+ }
46+
47+ func (e * VCSEventMessenger ) SendVCSEvent (ctx context.Context , db gorp.SqlExecutor , store cache.Store , proj sdk.Project , wr sdk.WorkflowRun , nodeRun sdk.WorkflowNodeRun ) error {
48+ if nodeRun .Status == sdk .StatusWaiting {
49+ return nil
50+ }
51+
52+ if e .commitsStatuses == nil {
53+ e .commitsStatuses = make (map [string ][]sdk.VCSCommitStatus )
54+ }
3655
37- node := wr .Workflow .WorkflowData .NodeByID (nodeID )
38- if ! node .IsLinkedToRepo (& wr .Workflow ) {
56+ node := wr .Workflow .WorkflowData .NodeByID (nodeRun .WorkflowNodeID )
57+ if ! node .IsLinkedToRepo (& wr .Workflow ) {
58+ return nil
59+ }
60+
61+ var notif * sdk.WorkflowNotification
62+ // browse notification to find vcs one
63+ loopNotif:
64+ for _ , n := range wr .Workflow .Notifications {
65+ if n .Type != sdk .VCSUserNotification {
3966 continue
4067 }
41-
42- var notif * sdk.WorkflowNotification
43- // browse notification to find vcs one
44- loopNotif:
45- for _ , n := range wr .Workflow .Notifications {
46- if n .Type != sdk .VCSUserNotification {
47- continue
48- }
49- // If list of node is nill, send notification to all of them
50- if len (n .NodeIDs ) == 0 {
68+ // If list of node is nill, send notification to all of them
69+ if len (n .NodeIDs ) == 0 {
70+ notif = & n
71+ break
72+ }
73+ // browser source node id
74+ for _ , src := range n .NodeIDs {
75+ if src == node .ID {
5176 notif = & n
52- break
53- }
54- // browser source node id
55- for _ , src := range n .NodeIDs {
56- if src == node .ID {
57- notif = & n
58- break loopNotif
59- }
77+ break loopNotif
6078 }
6179 }
80+ }
6281
63- vcsServerName := wr .Workflow .Applications [node .Context .ApplicationID ].VCSServer
64- repoFullName := wr .Workflow .Applications [node .Context .ApplicationID ].RepositoryFullname
82+ if notif == nil {
83+ return nil
84+ }
6585
66- vcsServer := repositoriesmanager .GetProjectVCSServer (proj , vcsServerName )
67- if vcsServer == nil {
68- return nil
69- }
86+ vcsServerName := wr .Workflow .Applications [node .Context .ApplicationID ].VCSServer
87+ repoFullName := wr .Workflow .Applications [node .Context .ApplicationID ].RepositoryFullname
7088
71- details := fmt .Sprintf ("on project:%s workflow:%s node:%s num:%d sub:%d vcs:%s" , proj .Name , wr .Workflow .Name , nodeRun .WorkflowNodeName , nodeRun .Number , nodeRun .SubNumber , vcsServer .Name )
89+ vcsServer := repositoriesmanager .GetProjectVCSServer (proj , vcsServerName )
90+ if vcsServer == nil {
91+ return nil
92+ }
7293
73- //Get the RepositoriesManager Client
74- client , errClient := repositoriesmanager .AuthorizedClient (ctx , db , store , proj .Key , vcsServer )
75- if errClient != nil {
76- return sdk .WrapError (errClient , "resyncCommitStatus> Cannot get client %s" , details )
94+ //Get the RepositoriesManager Client
95+ if e .vcsClient == nil {
96+ var err error
97+ e .vcsClient , err = repositoriesmanager .AuthorizedClient (ctx , db , store , proj .Key , vcsServer )
98+ if err != nil {
99+ return err
77100 }
101+ }
78102
79- ref := nodeRun .VCSHash
80- if nodeRun .VCSTag != "" {
81- ref = nodeRun .VCSTag
82- }
103+ ref := nodeRun .VCSHash
104+ if nodeRun .VCSTag != "" {
105+ ref = nodeRun .VCSTag
106+ }
83107
84- statuses , errStatuses := client .ListStatuses (ctx , repoFullName , ref )
85- if errStatuses != nil {
86- return sdk .WrapError (errStatuses , "resyncCommitStatus> Cannot get statuses %s" , details )
108+ statuses , ok := e .commitsStatuses [ref ]
109+ if ! ok {
110+ var err error
111+ statuses , err = e .vcsClient .ListStatuses (ctx , repoFullName , ref )
112+ if err != nil {
113+ return err
87114 }
88-
89- var statusFound * sdk. VCSCommitStatus
90- expected := sdk .VCSCommitStatusDescription (proj .Key , wr .Workflow .Name , sdk.EventRunWorkflowNode {
91- NodeName : nodeRun .WorkflowNodeName ,
92- })
93-
94- for i , status := range statuses {
95- if status . Decription == expected {
96- statusFound = & statuses [ i ]
97- break
98- }
115+ e . commitsStatuses [ ref ] = statuses
116+ }
117+ expected := sdk .VCSCommitStatusDescription (proj .Key , wr .Workflow .Name , sdk.EventRunWorkflowNode {
118+ NodeName : nodeRun .WorkflowNodeName ,
119+ })
120+
121+ var statusFound * sdk. VCSCommitStatus
122+ for i , status := range statuses {
123+ if status . Decription == expected {
124+ statusFound = & statuses [ i ]
125+ break
99126 }
127+ }
100128
101- if statusFound == nil || statusFound .State == "" {
102- if err := sendVCSEventStatus (ctx , db , store , proj , wr , & nodeRun , notif ); err != nil {
103- log .Error (ctx , "resyncCommitStatus> Error sending status %s err: %v" , details , err )
104- }
105-
106- if err := sendVCSPullRequestComment (ctx , db , store , proj , wr , & nodeRun , notif ); err != nil {
107- log .Error (ctx , "resyncCommitStatus> Error sending pr comments %s %s err:%v" , statusFound .State , details , err )
108- }
109- continue
129+ if statusFound == nil || statusFound .State == "" {
130+ if err := e .sendVCSEventStatus (ctx , db , store , proj .Key , wr , & nodeRun , notif , vcsServer .Name ); err != nil {
131+ return err
110132 }
111-
133+ } else {
112134 skipStatus := false
113135 switch statusFound .State {
114136 case sdk .StatusSuccess :
@@ -130,21 +152,20 @@ func ResyncCommitStatus(ctx context.Context, db gorp.SqlExecutor, store cache.St
130152 }
131153
132154 if ! skipStatus {
133- if err := sendVCSEventStatus (ctx , db , store , proj , wr , & nodeRun , notif ); err != nil {
134- log . Error ( ctx , "resyncCommitStatus> Error sending status %s %s err:%v" , statusFound . State , details , err )
155+ if err := e . sendVCSEventStatus (ctx , db , store , proj . Key , wr , & nodeRun , notif , vcsServer . Name ); err != nil {
156+ return err
135157 }
136158 }
159+ }
137160
138- if err := sendVCSPullRequestComment (ctx , db , store , proj , wr , & nodeRun , notif ); err != nil {
139- log .Error (ctx , "resyncCommitStatus> Error sending pr comments %s %s err:%v" , statusFound .State , details , err )
140- }
141-
161+ if err := e .sendVCSPullRequestComment (ctx , db , wr , & nodeRun , notif , vcsServer .Name ); err != nil {
162+ return err
142163 }
143164 return nil
144165}
145166
146167// sendVCSEventStatus send status
147- func sendVCSEventStatus (ctx context.Context , db gorp.SqlExecutor , store cache.Store , proj sdk. Project , wr * sdk.WorkflowRun , nodeRun * sdk.WorkflowNodeRun , notif * sdk.WorkflowNotification ) error {
168+ func ( e * VCSEventMessenger ) sendVCSEventStatus (ctx context.Context , db gorp.SqlExecutor , store cache.Store , projectKey string , wr sdk.WorkflowRun , nodeRun * sdk.WorkflowNodeRun , notif * sdk.WorkflowNotification , vcsServerName string ) error {
148169 if notif == nil || notif .Settings .Template == nil || (notif .Settings .Template .DisableStatus != nil && * notif .Settings .Template .DisableStatus ) {
149170 return nil
150171 }
@@ -166,17 +187,6 @@ func sendVCSEventStatus(ctx context.Context, db gorp.SqlExecutor, store cache.St
166187 env = wr .Workflow .Environments [node .Context .EnvironmentID ]
167188 }
168189
169- vcsServer := repositoriesmanager .GetProjectVCSServer (proj , app .VCSServer )
170- if vcsServer == nil {
171- return nil
172- }
173-
174- //Get the RepositoriesManager Client
175- client , errClient := repositoriesmanager .AuthorizedClient (ctx , db , store , proj .Key , vcsServer )
176- if errClient != nil {
177- return sdk .WrapError (errClient , "sendVCSEventStatus> Cannot get client" )
178- }
179-
180190 var eventWNR = sdk.EventRunWorkflowNode {
181191 ID : nodeRun .ID ,
182192 Number : nodeRun .Number ,
@@ -214,12 +224,11 @@ func sendVCSEventStatus(ctx context.Context, db gorp.SqlExecutor, store cache.St
214224
215225 report , err := nodeRun .Report ()
216226 if err != nil {
217- log .Error (ctx , "sendVCSEventStatus> unable to compute node run report%v" , err )
218- return nil
227+ return err
219228 }
220229
221230 // Check if it's a gerrit or not
222- vcsConf , err := repositoriesmanager .LoadByName (ctx , db , vcsServer . Name )
231+ vcsConf , err := repositoriesmanager .LoadByName (ctx , db , vcsServerName )
223232 if err != nil {
224233 return err
225234 }
@@ -266,24 +275,24 @@ func sendVCSEventStatus(ctx context.Context, db gorp.SqlExecutor, store cache.St
266275 EventType : fmt .Sprintf ("%T" , eventWNR ),
267276 Payload : payload ,
268277 Timestamp : time .Now (),
269- ProjectKey : proj . Key ,
278+ ProjectKey : projectKey ,
270279 WorkflowName : wr .Workflow .Name ,
271280 PipelineName : pipName ,
272281 ApplicationName : appName ,
273282 EnvironmentName : envName ,
274283 }
275284
276- if err := client .SetStatus (ctx , evt ); err != nil {
285+ if err := e . vcsClient .SetStatus (ctx , evt ); err != nil {
277286 if err2 := repositoriesmanager .RetryEvent (& evt , err , store ); err2 != nil {
278- log . Error ( ctx , "sendEvent>processEvent> err while retry event: %v" , err2 )
287+ return err2
279288 }
280- log . Error ( ctx , "sendEvent> err:%v" , err )
289+ return err
281290 }
282291
283292 return nil
284293}
285294
286- func sendVCSPullRequestComment (ctx context.Context , db gorp.SqlExecutor , store cache. Store , proj sdk. Project , wr * sdk.WorkflowRun , nodeRun * sdk.WorkflowNodeRun , notif * sdk.WorkflowNotification ) error {
295+ func ( e * VCSEventMessenger ) sendVCSPullRequestComment (ctx context.Context , db gorp.SqlExecutor , wr sdk.WorkflowRun , nodeRun * sdk.WorkflowNodeRun , notif * sdk.WorkflowNotification , vcsServerName string ) error {
287296 if notif == nil || notif .Settings .Template == nil || (notif .Settings .Template .DisableComment != nil && * notif .Settings .Template .DisableComment ) {
288297 return nil
289298 }
@@ -308,23 +317,11 @@ func sendVCSPullRequestComment(ctx context.Context, db gorp.SqlExecutor, store c
308317
309318 report , err := nodeRun .Report ()
310319 if err != nil {
311- log .Error (ctx , "sendVCSPullRequestComment> unable to compute node run report%v" , err )
312- return nil
313- }
314-
315- vcsServer := repositoriesmanager .GetProjectVCSServer (proj , app .VCSServer )
316- if vcsServer == nil {
317- return nil
318- }
319-
320- //Get the RepositoriesManager Client
321- client , errClient := repositoriesmanager .AuthorizedClient (ctx , db , store , proj .Key , vcsServer )
322- if errClient != nil {
323- return errClient
320+ return err
324321 }
325322
326323 // Check if it's a gerrit or not
327- vcsConf , err := repositoriesmanager .LoadByName (ctx , db , vcsServer . Name )
324+ vcsConf , err := repositoriesmanager .LoadByName (ctx , db , vcsServerName )
328325 if err != nil {
329326 return err
330327 }
@@ -347,31 +344,26 @@ func sendVCSPullRequestComment(ctx context.Context, db gorp.SqlExecutor, store c
347344 // If we are on Gerrit
348345 if changeID != "" && vcsConf .Type == "gerrit" {
349346 reqComment .ChangeID = changeID
350- if err := client .PullRequestComment (ctx , app .RepositoryFullname , reqComment ); err != nil {
351- log .Error (ctx , "sendVCSPullRequestComment> unable to send PR report:%v" , err )
352- return nil
347+ if err := e .vcsClient .PullRequestComment (ctx , app .RepositoryFullname , reqComment ); err != nil {
348+ return err
353349 }
354350 } else if vcsConf .Type != "gerrit" {
355351 //Check if this branch and this commit is a pullrequest
356- prs , err := client .PullRequests (ctx , app .RepositoryFullname )
352+ prs , err := e . vcsClient .PullRequests (ctx , app .RepositoryFullname )
357353 if err != nil {
358- log .Error (ctx , "sendVCSPullRequestComment> unable to get pull requests on repo %s: %v" , app .RepositoryFullname , err )
359- return nil
354+ return err
360355 }
361356
362357 //Send comment on pull request
363358 for _ , pr := range prs {
364359 if pr .Head .Branch .DisplayID == nodeRun .VCSBranch && pr .Head .Branch .LatestCommit == nodeRun .VCSHash && ! pr .Merged && ! pr .Closed {
365360 reqComment .ID = pr .ID
366- if err := client .PullRequestComment (ctx , app .RepositoryFullname , reqComment ); err != nil {
367- log .Error (ctx , "sendVCSPullRequestComment> unable to send PR report:%v" , err )
368- return nil
361+ if err := e .vcsClient .PullRequestComment (ctx , app .RepositoryFullname , reqComment ); err != nil {
362+ return err
369363 }
370- // if we found the pull request for head branch we can break (only one PR for the branch should exist)
371364 break
372365 }
373366 }
374367 }
375-
376368 return nil
377369}
0 commit comments