@@ -2,7 +2,9 @@ package main
22
33import (
44 "context"
5+ "errors"
56 "fmt"
7+ "net/url"
68 "os"
79 "path/filepath"
810 "strings"
@@ -11,107 +13,142 @@ import (
1113 "github.com/databrickslabs/sandbox/acceptance/boilerplate"
1214 "github.com/databrickslabs/sandbox/acceptance/ecosystem"
1315 "github.com/databrickslabs/sandbox/acceptance/notify"
16+ "github.com/databrickslabs/sandbox/acceptance/redaction"
1417 "github.com/databrickslabs/sandbox/acceptance/testenv"
1518 "github.com/databrickslabs/sandbox/go-libs/env"
1619 "github.com/databrickslabs/sandbox/go-libs/github"
20+ "github.com/databrickslabs/sandbox/go-libs/slack"
1721 "github.com/sethvargo/go-githubactions"
1822)
1923
24+ func main () {
25+ err := run (context .Background ())
26+ if err != nil {
27+ githubactions .Fatalf ("failed: %s" , err )
28+ }
29+ }
30+
2031func run (ctx context.Context , opts ... githubactions.Option ) error {
21- b , err := boilerplate .New (ctx )
32+ b , err := boilerplate .New (ctx , opts ... )
2233 if err != nil {
2334 return fmt .Errorf ("boilerplate: %w" , err )
2435 }
25- timeoutRaw := b .Action .GetInput ("timeout" )
26- if timeoutRaw == "" {
27- timeoutRaw = "1h"
28- }
29- timeout , err := time .ParseDuration (timeoutRaw )
36+ a := & acceptance {Boilerplate : b }
37+ alert , err := a .trigger (ctx )
3038 if err != nil {
31- return fmt .Errorf ("timeout : %w" , err )
39+ return fmt .Errorf ("trigger : %w" , err )
3240 }
33- ctx , cancel := context .WithTimeout (ctx , timeout )
34- defer cancel ()
35- vaultURI := b .Action .GetInput ("vault_uri" )
36- directory := b .Action .GetInput ("directory" )
37- project := b .Action .GetInput ("project" )
38- if project == "" {
39- abs , err := filepath .Abs (directory )
40- if err != nil {
41- return fmt .Errorf ("absolute path: %w" , err )
42- }
43- project = filepath .Base (abs )
41+ return a .notifyIfNeeded (ctx , alert )
42+ }
43+
44+ type acceptance struct {
45+ * boilerplate.Boilerplate
46+ }
47+
48+ func (a * acceptance ) trigger (ctx context.Context ) (* notify.Notification , error ) {
49+ vaultURI := a .Action .GetInput ("vault_uri" )
50+ directory , project , err := a .getProject ()
51+ if err != nil {
52+ return nil , fmt .Errorf ("project: %w" , err )
4453 }
45- artifactDir , err := b .PrepareArtifacts ()
54+ artifactDir , err := a .PrepareArtifacts ()
4655 if err != nil {
47- return fmt .Errorf ("prepare artifacts: %w" , err )
56+ return nil , fmt .Errorf ("prepare artifacts: %w" , err )
4857 }
4958 defer os .RemoveAll (artifactDir )
50- testEnv := testenv .NewWithGitHubOIDC (b .Action , vaultURI )
59+ testEnv := testenv .NewWithGitHubOIDC (a .Action , vaultURI )
5160 loaded , err := testEnv .Load (ctx )
5261 if err != nil {
53- return fmt .Errorf ("load: %w" , err )
62+ return nil , fmt .Errorf ("load: %w" , err )
5463 }
5564 ctx , stop , err := loaded .Start (ctx )
5665 if err != nil {
57- return fmt .Errorf ("start: %w" , err )
66+ return nil , fmt .Errorf ("start: %w" , err )
5867 }
5968 defer stop ()
6069 // make sure that test logs leave their artifacts somewhere we can pickup
6170 ctx = env .Set (ctx , ecosystem .LogDirEnv , artifactDir )
6271 redact := loaded .Redaction ()
63- // detect and run all tests
64- report , err := ecosystem .RunAll (ctx , redact , directory )
72+ report , err := a .runWithTimeout (ctx , redact , directory )
6573 if err != nil {
66- return fmt .Errorf ("unknown : %w" , err )
74+ return nil , fmt .Errorf ("run : %w" , err )
6775 }
6876 err = report .WriteReport (project , filepath .Join (artifactDir , "test-report.json" ))
6977 if err != nil {
70- return fmt .Errorf ("report: %w" , err )
78+ return nil , fmt .Errorf ("report: %w" , err )
7179 }
7280 // better be redacting twice, right?
7381 summary := redact .ReplaceAll (report .StepSummary ())
74- b .Action .AddStepSummary (summary )
75- err = b .Comment (ctx , summary )
82+ a .Action .AddStepSummary (summary )
83+ err = a .AddOrUpdateComment (ctx , summary )
84+ if err != nil {
85+ return nil , fmt .Errorf ("comment: %w" , err )
86+ }
87+ err = a .Upload (ctx , artifactDir )
88+ if err != nil {
89+ return nil , fmt .Errorf ("upload artifact: %w" , err )
90+ }
91+ runUrl , err := a .RunURL (ctx )
92+ if err != nil {
93+ return nil , fmt .Errorf ("run url: %w" , err )
94+ }
95+ kvStoreURL , err := url .Parse (vaultURI )
7696 if err != nil {
77- return fmt .Errorf ("comment: %w" , err )
97+ return nil , fmt .Errorf ("vault uri: %w" , err )
98+ }
99+ runName := strings .TrimSuffix (kvStoreURL .Host , ".vault.azure.net" )
100+ return & notify.Notification {
101+ Project : project ,
102+ Report : report ,
103+ Cloud : loaded .Cloud (),
104+ RunName : runName ,
105+ RunURL : runUrl ,
106+ }, nil
107+ }
108+
109+ func (a * acceptance ) runWithTimeout (
110+ ctx context.Context , redact redaction.Redaction , directory string ,
111+ ) (ecosystem.TestReport , error ) {
112+ timeoutRaw := a .Action .GetInput ("timeout" )
113+ if timeoutRaw == "" {
114+ timeoutRaw = "50m"
78115 }
79- err = b . Upload ( ctx , artifactDir )
116+ timeout , err := time . ParseDuration ( timeoutRaw )
80117 if err != nil {
81- return fmt .Errorf ("upload artifact : %w" , err )
118+ return nil , fmt .Errorf ("timeout : %w" , err )
82119 }
83- slackWebhook := b .Action .GetInput ("slack_webhook" )
84- createIssues := strings .ToLower (b .Action .GetInput ("create_issues" ))
120+ ctx , cancel := context .WithTimeout (ctx , timeout )
121+ defer cancel ()
122+ // detect and run all tests
123+ report , err := ecosystem .RunAll (ctx , redact , directory )
124+ if err == nil || errors .Is (err , context .DeadlineExceeded ) {
125+ return report , nil
126+ }
127+ return nil , fmt .Errorf ("unknown: %w" , err )
128+ }
129+
130+ func (a * acceptance ) notifyIfNeeded (ctx context.Context , alert * notify.Notification ) error {
131+ slackWebhook := a .Action .GetInput ("slack_webhook" )
132+ createIssues := strings .ToLower (a .Action .GetInput ("create_issues" ))
85133 needsSlack := slackWebhook != ""
86134 needsIssues := createIssues == "true" || createIssues == "yes"
87135 needsNotification := needsSlack || needsIssues
88- if ! report .Pass () && needsNotification {
89- runUrl , err := b .RunURL (ctx )
90- if err != nil {
91- return fmt .Errorf ("run url: %w" , err )
92- }
93- alert := notify.Notification {
94- Project : project ,
95- Report : report ,
96- Cloud : loaded .Cloud (),
97- RunName : b .WorkflowRunName (),
98- WebHook : slackWebhook ,
99- RunURL : runUrl ,
100- }
136+ if ! alert .Report .Pass () && needsNotification {
101137 if needsSlack {
102- err = alert .ToSlack ()
138+ hook := slack .Webhook (slackWebhook )
139+ err := alert .ToSlack (hook )
103140 if err != nil {
104141 return fmt .Errorf ("slack: %w" , err )
105142 }
106143 }
107144 if needsIssues {
108- for _ , v := range report {
145+ for _ , v := range alert . Report {
109146 if ! v .Failed () {
110147 continue
111148 }
112- err = b . CreateIssueIfNotOpen (ctx , github.NewIssue {
113- Title : fmt .Sprintf ("Test failure: `%s`" , v .Name ),
114- Body : v .Summary (),
149+ err := a . CreateOrCommentOnIssue (ctx , github.NewIssue {
150+ Title : fmt .Sprintf ("Test failure: `%s`" , v .Name ),
151+ Body : v .Summary (),
115152 Labels : []string {"bug" },
116153 })
117154 if err != nil {
@@ -120,12 +157,18 @@ func run(ctx context.Context, opts ...githubactions.Option) error {
120157 }
121158 }
122159 }
123- return report .Failed ()
160+ return alert . Report .Failed ()
124161}
125162
126- func main () {
127- err := run (context .Background ())
128- if err != nil {
129- githubactions .Fatalf ("failed: %s" , err )
163+ func (a * acceptance ) getProject () (string , string , error ) {
164+ directory := a .Action .GetInput ("directory" )
165+ project := a .Action .GetInput ("project" )
166+ if project == "" {
167+ abs , err := filepath .Abs (directory )
168+ if err != nil {
169+ return "" , "" , fmt .Errorf ("absolute path: %w" , err )
170+ }
171+ project = filepath .Base (abs )
130172 }
173+ return directory , project , nil
131174}
0 commit comments