Skip to content

Commit 21e923d

Browse files
authored
[BIVS-2846] Accept build trigger responses with multiple results (#207)
* BIVS-2846 accept build trigger responses with multiple results * lint
1 parent 51b044e commit 21e923d

File tree

3 files changed

+306
-18
lines changed

3 files changed

+306
-18
lines changed

bitriseapi/bitriseapi.go

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,14 +105,30 @@ type TriggerAPIParamsModel struct {
105105

106106
// TriggerAPIResponseModel ...
107107
type TriggerAPIResponseModel struct {
108+
Status string `json:"status"`
109+
Message string `json:"message"`
110+
Service string `json:"service"`
111+
AppSlug string `json:"slug"`
112+
// Deprecated
113+
BuildSlug string `json:"build_slug"`
114+
// Deprecated
115+
BuildNumber int `json:"build_number"`
116+
// Deprecated
117+
BuildURL string `json:"build_url"`
118+
// Deprecated
119+
TriggeredWorkflow string `json:"triggered_workflow"`
120+
Results []BuildTriggerRespItemModel `json:"results"`
121+
}
122+
123+
// BuildTriggerRespItemModel ...
124+
type BuildTriggerRespItemModel struct {
108125
Status string `json:"status"`
109126
Message string `json:"message"`
110-
Service string `json:"service"`
111-
AppSlug string `json:"slug"`
112127
BuildSlug string `json:"build_slug"`
113128
BuildNumber int `json:"build_number"`
114129
BuildURL string `json:"build_url"`
115130
TriggeredWorkflow string `json:"triggered_workflow"`
131+
TriggeredPipeline string `json:"triggered_pipeline"`
116132
}
117133

118134
// Validate ...

service/hook/slack/slack.go

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -193,12 +193,43 @@ type RespModel struct {
193193
Attachments []AttachmentItemModel `json:"attachments,omitempty"`
194194
}
195195

196-
func messageForSuccessfulBuildTrigger(apiResponse bitriseapi.TriggerAPIResponseModel) string {
197-
return fmt.Sprintf("Triggered build #%d (%s), with workflow: %s - url: %s",
198-
apiResponse.BuildNumber,
199-
apiResponse.BuildSlug,
200-
apiResponse.TriggeredWorkflow,
201-
apiResponse.BuildURL)
196+
func messageForBuildTrigger(apiResponse bitriseapi.TriggerAPIResponseModel) string {
197+
if len(apiResponse.Results) < 2 {
198+
// Single successful build
199+
return fmt.Sprintf("Triggered build #%d (%s), with workflow: %s - url: %s",
200+
apiResponse.BuildNumber,
201+
apiResponse.BuildSlug,
202+
apiResponse.TriggeredWorkflow,
203+
apiResponse.BuildURL)
204+
}
205+
206+
// Multiple builds, maybe failing
207+
msg := fmt.Sprintf("Triggered %d builds:", len(apiResponse.Results))
208+
for _, result := range apiResponse.Results {
209+
var targetType, targetName string
210+
if result.TriggeredPipeline == "" {
211+
targetType = "workflow"
212+
targetName = result.TriggeredWorkflow
213+
} else {
214+
targetType = "pipeline"
215+
targetName = result.TriggeredPipeline
216+
}
217+
218+
if result.Status == "ok" {
219+
msg += fmt.Sprintf("\nbuild #%d (%s), with %s: %s - url: %s",
220+
result.BuildNumber,
221+
result.BuildSlug,
222+
targetType,
223+
targetName,
224+
result.BuildURL)
225+
} else {
226+
msg += fmt.Sprintf("\nbuild with %s: %s - failed: %s",
227+
targetType,
228+
targetName,
229+
result.Message)
230+
}
231+
}
232+
return msg
202233
}
203234

204235
// TransformResponse ...
@@ -212,11 +243,17 @@ func (hp HookProvider) TransformResponse(input hookCommon.TransformResponseInput
212243
}
213244
if len(input.FailedTriggerResponses) > 0 {
214245
for _, aFailedTrigResp := range input.FailedTriggerResponses {
215-
errMsg := aFailedTrigResp.Message
216-
if errMsg == "" {
217-
errMsg = fmt.Sprintf("%+v", aFailedTrigResp)
246+
if len(aFailedTrigResp.Results) > 1 {
247+
// New behaviour: multiple builds, some have failed
248+
slackAttachments = append(slackAttachments, createAttachmentItemModel(messageForBuildTrigger(aFailedTrigResp), slackColorDanger))
249+
} else {
250+
// Compatibility behaviour: for a project-level error or a single build, report errors as before
251+
errMsg := aFailedTrigResp.Message
252+
if errMsg == "" {
253+
errMsg = fmt.Sprintf("%+v", aFailedTrigResp)
254+
}
255+
slackAttachments = append(slackAttachments, createAttachmentItemModel(errMsg, slackColorDanger))
218256
}
219-
slackAttachments = append(slackAttachments, createAttachmentItemModel(errMsg, slackColorDanger))
220257
}
221258
}
222259
if len(input.SkippedTriggerResponses) > 0 {
@@ -230,7 +267,7 @@ func (hp HookProvider) TransformResponse(input hookCommon.TransformResponseInput
230267
}
231268
if len(input.SuccessTriggerResponses) > 0 {
232269
for _, aSuccessTrigResp := range input.SuccessTriggerResponses {
233-
slackAttachments = append(slackAttachments, createAttachmentItemModel(messageForSuccessfulBuildTrigger(aSuccessTrigResp), slackColorGood))
270+
slackAttachments = append(slackAttachments, createAttachmentItemModel(messageForBuildTrigger(aSuccessTrigResp), slackColorGood))
234271
}
235272
}
236273

service/hook/slack/slack_test.go

Lines changed: 240 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,7 @@ func Test_HookProvider_TransformRequest(t *testing.T) {
477477

478478
func Test_messageForSuccessfulBuildTrigger(t *testing.T) {
479479
require.Equal(t, "Triggered build #23 (build-slug), with workflow: test-wf - url: bitrise.io/...",
480-
messageForSuccessfulBuildTrigger(bitriseapi.TriggerAPIResponseModel{
480+
messageForBuildTrigger(bitriseapi.TriggerAPIResponseModel{
481481
Status: "ok",
482482
Message: "some msg from the server",
483483
Service: "bitrise",
@@ -492,7 +492,7 @@ func Test_messageForSuccessfulBuildTrigger(t *testing.T) {
492492
func Test_HookProvider_TransformResponse(t *testing.T) {
493493
provider := HookProvider{}
494494

495-
t.Log("Single success")
495+
t.Log("Single response: legacy single success")
496496
{
497497
baseRespModel := hookCommon.TransformResponseInputModel{
498498
SuccessTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
@@ -527,7 +527,7 @@ func Test_HookProvider_TransformResponse(t *testing.T) {
527527
}, resp)
528528
}
529529

530-
t.Log("Single failed trigger - with defined 'message'")
530+
t.Log("Single response: legacy single failed trigger - with defined 'message'")
531531
{
532532
baseRespModel := hookCommon.TransformResponseInputModel{
533533
FailedTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
@@ -560,7 +560,7 @@ func Test_HookProvider_TransformResponse(t *testing.T) {
560560
}, resp)
561561
}
562562

563-
t.Log("Single failed trigger - empty 'message'")
563+
t.Log("Single response: legacy single failed trigger - empty 'message'")
564564
{
565565
baseRespModel := hookCommon.TransformResponseInputModel{
566566
FailedTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
@@ -576,7 +576,242 @@ func Test_HookProvider_TransformResponse(t *testing.T) {
576576
}
577577

578578
resp := provider.TransformResponse(baseRespModel)
579-
expectedText := `{Status:error Message: Service:bitrise AppSlug:app-slug BuildSlug:build-slug BuildNumber:23 BuildURL: TriggeredWorkflow:}`
579+
expectedText := `{Status:error Message: Service:bitrise AppSlug:app-slug BuildSlug:build-slug BuildNumber:23 BuildURL: TriggeredWorkflow: Results:[]}`
580+
require.Equal(t, hookCommon.TransformResponseModel{
581+
Data: RespModel{
582+
ResponseType: "in_channel",
583+
Text: "",
584+
Attachments: []AttachmentItemModel{
585+
{
586+
Text: expectedText,
587+
Fallback: expectedText,
588+
Color: slackColorDanger,
589+
},
590+
},
591+
},
592+
HTTPStatusCode: 200,
593+
}, resp)
594+
}
595+
596+
t.Log("Single response: single success")
597+
{
598+
baseRespModel := hookCommon.TransformResponseInputModel{
599+
SuccessTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
600+
{
601+
Status: "ok",
602+
Message: "triggered build",
603+
Service: "bitrise",
604+
AppSlug: "app-slug",
605+
BuildSlug: "build-slug",
606+
BuildNumber: 23,
607+
BuildURL: "bitrise.io/...",
608+
TriggeredWorkflow: "wf-one",
609+
Results: []bitriseapi.BuildTriggerRespItemModel{
610+
{
611+
Status: "ok",
612+
BuildSlug: "build-slug",
613+
BuildNumber: 23,
614+
BuildURL: "bitrise.io/...",
615+
TriggeredWorkflow: "wf-one",
616+
TriggeredPipeline: "",
617+
},
618+
},
619+
},
620+
},
621+
}
622+
623+
resp := provider.TransformResponse(baseRespModel)
624+
expectedText := `Triggered build #23 (build-slug), with workflow: wf-one - url: bitrise.io/...`
625+
require.Equal(t, hookCommon.TransformResponseModel{
626+
Data: RespModel{
627+
ResponseType: "in_channel",
628+
Text: "",
629+
Attachments: []AttachmentItemModel{
630+
{
631+
Text: expectedText,
632+
Fallback: expectedText,
633+
Color: slackColorGood,
634+
},
635+
},
636+
},
637+
HTTPStatusCode: 200,
638+
}, resp)
639+
}
640+
641+
t.Log("Single response: single failed build")
642+
{
643+
baseRespModel := hookCommon.TransformResponseInputModel{
644+
FailedTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
645+
{
646+
Status: "error",
647+
Message: "failed build",
648+
Service: "bitrise",
649+
AppSlug: "app-slug",
650+
Results: []bitriseapi.BuildTriggerRespItemModel{
651+
{
652+
Status: "error",
653+
Message: "failed build",
654+
TriggeredWorkflow: "wf-one",
655+
TriggeredPipeline: "",
656+
},
657+
},
658+
},
659+
},
660+
}
661+
662+
resp := provider.TransformResponse(baseRespModel)
663+
expectedText := "failed build"
664+
require.Equal(t, hookCommon.TransformResponseModel{
665+
Data: RespModel{
666+
ResponseType: "in_channel",
667+
Text: "",
668+
Attachments: []AttachmentItemModel{
669+
{
670+
Text: expectedText,
671+
Fallback: expectedText,
672+
Color: slackColorDanger,
673+
},
674+
},
675+
},
676+
HTTPStatusCode: 200,
677+
}, resp)
678+
}
679+
680+
t.Log("Single response: multiple successful builds")
681+
{
682+
baseRespModel := hookCommon.TransformResponseInputModel{
683+
SuccessTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
684+
{
685+
Status: "ok",
686+
Message: "triggered build",
687+
Service: "bitrise",
688+
AppSlug: "app-slug",
689+
BuildSlug: "build-slug",
690+
BuildNumber: 23,
691+
BuildURL: "bitrise.io/...",
692+
TriggeredWorkflow: "wf-one",
693+
Results: []bitriseapi.BuildTriggerRespItemModel{
694+
{
695+
Status: "ok",
696+
BuildSlug: "build-slug",
697+
BuildNumber: 23,
698+
BuildURL: "bitrise.io/...",
699+
TriggeredWorkflow: "wf-one",
700+
TriggeredPipeline: "",
701+
},
702+
{
703+
Status: "ok",
704+
BuildSlug: "second-build",
705+
BuildNumber: 46,
706+
BuildURL: "bitrise.io/....",
707+
TriggeredWorkflow: "",
708+
TriggeredPipeline: "pipeline-one",
709+
},
710+
},
711+
},
712+
},
713+
}
714+
715+
resp := provider.TransformResponse(baseRespModel)
716+
expectedText := "Triggered 2 builds:\nbuild #23 (build-slug), with workflow: wf-one - url: bitrise.io/...\nbuild #46 (second-build), with pipeline: pipeline-one - url: bitrise.io/...."
717+
require.Equal(t, hookCommon.TransformResponseModel{
718+
Data: RespModel{
719+
ResponseType: "in_channel",
720+
Text: "",
721+
Attachments: []AttachmentItemModel{
722+
{
723+
Text: expectedText,
724+
Fallback: expectedText,
725+
Color: slackColorGood,
726+
},
727+
},
728+
},
729+
HTTPStatusCode: 200,
730+
}, resp)
731+
}
732+
733+
t.Log("Single response: multiple failed builds")
734+
{
735+
baseRespModel := hookCommon.TransformResponseInputModel{
736+
FailedTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
737+
{
738+
Status: "error",
739+
Message: "failed build",
740+
Service: "bitrise",
741+
AppSlug: "app-slug",
742+
Results: []bitriseapi.BuildTriggerRespItemModel{
743+
{
744+
Status: "error",
745+
Message: "failed build",
746+
TriggeredWorkflow: "wf-one",
747+
TriggeredPipeline: "",
748+
},
749+
{
750+
Status: "error",
751+
Message: "this failed too",
752+
TriggeredWorkflow: "",
753+
TriggeredPipeline: "pipeline-one",
754+
},
755+
},
756+
},
757+
},
758+
}
759+
760+
resp := provider.TransformResponse(baseRespModel)
761+
expectedText := "Triggered 2 builds:\nbuild with workflow: wf-one - failed: failed build\nbuild with pipeline: pipeline-one - failed: this failed too"
762+
require.Equal(t, hookCommon.TransformResponseModel{
763+
Data: RespModel{
764+
ResponseType: "in_channel",
765+
Text: "",
766+
Attachments: []AttachmentItemModel{
767+
{
768+
Text: expectedText,
769+
Fallback: expectedText,
770+
Color: slackColorDanger,
771+
},
772+
},
773+
},
774+
HTTPStatusCode: 200,
775+
}, resp)
776+
}
777+
778+
t.Log("Single response: multiple builds with mixed status")
779+
{
780+
baseRespModel := hookCommon.TransformResponseInputModel{
781+
FailedTriggerResponses: []bitriseapi.TriggerAPIResponseModel{
782+
{
783+
Status: "error",
784+
Message: "failed build",
785+
Service: "bitrise",
786+
AppSlug: "app-slug",
787+
Results: []bitriseapi.BuildTriggerRespItemModel{
788+
{
789+
Status: "error",
790+
Message: "failed build",
791+
TriggeredWorkflow: "wf-one",
792+
TriggeredPipeline: "",
793+
},
794+
{
795+
Status: "ok",
796+
BuildSlug: "build-slug",
797+
BuildNumber: 23,
798+
BuildURL: "bitrise.io/...",
799+
TriggeredWorkflow: "wf-one",
800+
TriggeredPipeline: "",
801+
},
802+
{
803+
Status: "error",
804+
Message: "this failed too",
805+
TriggeredWorkflow: "",
806+
TriggeredPipeline: "pipeline-one",
807+
},
808+
},
809+
},
810+
},
811+
}
812+
813+
resp := provider.TransformResponse(baseRespModel)
814+
expectedText := "Triggered 3 builds:\nbuild with workflow: wf-one - failed: failed build\nbuild #23 (build-slug), with workflow: wf-one - url: bitrise.io/...\nbuild with pipeline: pipeline-one - failed: this failed too"
580815
require.Equal(t, hookCommon.TransformResponseModel{
581816
Data: RespModel{
582817
ResponseType: "in_channel",

0 commit comments

Comments
 (0)