Skip to content

Commit 0c0bdd1

Browse files
committed
Create issues on failures of integration tests
1 parent d7f855c commit 0c0bdd1

File tree

11 files changed

+143
-14
lines changed

11 files changed

+143
-14
lines changed

.github/workflows/build.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
app=$1
44

55
# Define platforms and architectures
6-
platforms=("windows" "linux" "darwin")
7-
architectures=("amd64" "arm64")
6+
platforms=("linux")
7+
architectures=("amd64")
88
mkdir -p dist
99

1010
# Build binaries for each platform and architecture combination

.github/workflows/nightly-go-libs.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
name: acceptance
2+
3+
on:
4+
workflow_dispatch:
5+
# ...
6+
7+
permissions:
8+
id-token: write
9+
contents: read
10+
pull-requests: write
11+
issues: write
12+
13+
jobs:
14+
acceptance:
15+
environment: tool
16+
runs-on: larger
17+
steps:
18+
- name: Checkout
19+
uses: actions/checkout@v4
20+
21+
- name: Setup Go
22+
uses: actions/setup-go@v5
23+
with:
24+
go-version: 1.21
25+
26+
- name: Acceptance
27+
uses: databrickslabs/sandbox/acceptance@acceptance/v0.2.0
28+
with:
29+
directory: go-libs
30+
vault_uri: ${{ secrets.VAULT_URI }}
31+
create_issues: true
32+
env:
33+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34+
ARM_CLIENT_ID: ${{ secrets.ARM_CLIENT_ID }}
35+
ARM_TENANT_ID: ${{ secrets.ARM_TENANT_ID }}
36+

acceptance/action.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ inputs:
2020
description: 'Maximum suite execution time. Defaults to 1h'
2121
required: false
2222
default: 1h
23+
create_issues:
24+
description: 'Create issues in the repository for failed tests'
25+
required: false
26+
default: false
2327
outputs:
2428
sample:
2529
description: 'Sample output'

acceptance/boilerplate/actions.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,40 @@ func (a *boilerplate) RunURL(ctx context.Context) (string, error) {
9292
return "", fmt.Errorf("id not found for current run: %s", a.context.Job)
9393
}
9494

95+
func (a *boilerplate) CreateIssueIfNotOpen(ctx context.Context, newIssue github.NewIssue) error {
96+
org, repo := a.context.Repo()
97+
it := a.GitHub.ListRepositoryIssues(ctx, org, repo, &github.ListIssues{
98+
State: "open",
99+
})
100+
created := map[string]bool{}
101+
for it.HasNext(ctx) {
102+
issue, err := it.Next(ctx)
103+
if err != nil {
104+
return fmt.Errorf("issue: %w", err)
105+
}
106+
created[issue.Title] = true
107+
}
108+
if created[newIssue.Title] {
109+
return nil
110+
}
111+
body, err := a.taggedComment(ctx, newIssue.Body)
112+
if err != nil {
113+
return fmt.Errorf("tagged comment: %w", err)
114+
}
115+
// with the tagged comment, which has the workflow ref, we can link to the run
116+
issue, err := a.GitHub.CreateIssue(ctx, org, repo, github.NewIssue{
117+
Title: newIssue.Title,
118+
Assignees: newIssue.Assignees,
119+
Labels: newIssue.Labels,
120+
Body: body,
121+
})
122+
if err != nil {
123+
return fmt.Errorf("new issue: %w", err)
124+
}
125+
logger.Infof(ctx, "Created issue: https://github.com/%s/%s/issues/%d", issue.Number)
126+
return nil
127+
}
128+
95129
func (a *boilerplate) tag() string {
96130
// The ref path to the workflow. For example,
97131
// octocat/hello-world/.github/workflows/my-workflow.yml@refs/heads/my_branch.

acceptance/ecosystem/report.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,19 @@ func (tr TestResult) Duration() time.Duration {
2525
return time.Duration(tr.Elapsed * float64(time.Second))
2626
}
2727

28+
func (tr TestResult) Failed() bool {
29+
return !tr.Pass && !tr.Skip
30+
}
31+
32+
func (tr TestResult) Summary() string {
33+
res := []string{}
34+
res = append(res, "<details>")
35+
res = append(res, fmt.Sprintf("<summary>%s</summary>", tr))
36+
res = append(res, fmt.Sprintf("\n```\n%s\n```\n", tr.Output))
37+
res = append(res, "</details>")
38+
return strings.Join(res, "\n")
39+
}
40+
2841
func (tr TestResult) String() string {
2942
summary := ""
3043
if !tr.Pass {
@@ -138,13 +151,10 @@ func (r TestReport) String() string {
138151
func (r TestReport) StepSummary() string {
139152
res := []string{r.String()}
140153
for _, v := range r {
141-
if v.Pass || v.Skip {
154+
if !v.Failed() {
142155
continue
143156
}
144-
res = append(res, "<details>")
145-
res = append(res, fmt.Sprintf("<summary>%s</summary>", v))
146-
res = append(res, fmt.Sprintf("\n```\n%s\n```\n", v.Output))
147-
res = append(res, "</details>")
157+
res = append(res, v.Summary())
148158
}
149159
if r.Flaky() {
150160
res = append(res, "\nFlaky tests:\n")

acceptance/main.go

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,15 @@ import (
55
"fmt"
66
"os"
77
"path/filepath"
8+
"strings"
89
"time"
910

1011
"github.com/databrickslabs/sandbox/acceptance/boilerplate"
1112
"github.com/databrickslabs/sandbox/acceptance/ecosystem"
1213
"github.com/databrickslabs/sandbox/acceptance/notify"
1314
"github.com/databrickslabs/sandbox/acceptance/testenv"
1415
"github.com/databrickslabs/sandbox/go-libs/env"
16+
"github.com/databrickslabs/sandbox/go-libs/github"
1517
"github.com/sethvargo/go-githubactions"
1618
)
1719

@@ -79,21 +81,43 @@ func run(ctx context.Context, opts ...githubactions.Option) error {
7981
return fmt.Errorf("upload artifact: %w", err)
8082
}
8183
slackWebhook := b.Action.GetInput("slack_webhook")
82-
if !report.Pass() && slackWebhook != "" {
84+
createIssues := strings.ToLower(b.Action.GetInput("create_issues"))
85+
needsSlack := slackWebhook != ""
86+
needsIssues := createIssues == "true" || createIssues == "yes"
87+
needsNotification := needsSlack || needsIssues
88+
if !report.Pass() && needsNotification {
8389
runUrl, err := b.RunURL(ctx)
8490
if err != nil {
8591
return fmt.Errorf("run url: %w", err)
8692
}
87-
err = notify.Notification{
93+
alert := notify.Notification{
8894
Project: project,
8995
Report: report,
9096
Cloud: loaded.Cloud(),
9197
RunName: b.WorkflowRunName(),
9298
WebHook: slackWebhook,
9399
RunURL: runUrl,
94-
}.ToSlack()
95-
if err != nil {
96-
return fmt.Errorf("slack: %w", err)
100+
}
101+
if needsSlack {
102+
err = alert.ToSlack()
103+
if err != nil {
104+
return fmt.Errorf("slack: %w", err)
105+
}
106+
}
107+
if needsIssues {
108+
for _, v := range report {
109+
if !v.Failed() {
110+
continue
111+
}
112+
err = b.CreateIssueIfNotOpen(ctx, github.NewIssue{
113+
Title: fmt.Sprintf("Test failure: `%s`", v.Name),
114+
Body: v.Summary(),
115+
Labels: []string{"bug"},
116+
})
117+
if err != nil {
118+
return fmt.Errorf("create issue: %w", err)
119+
}
120+
}
97121
}
98122
}
99123
return report.Failed()

acceptance/shim.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
const version = 'v0.1.4';
1+
const version = 'v0.2.0';
22

33
const { createWriteStream, chmodSync } = require('fs');
44
const { createGunzip } = require('zlib');

go-libs/github/github.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,18 @@ func (c *GitHubClient) GetIssueComments(ctx context.Context, org, repo string, n
292292
})
293293
}
294294

295+
func (c *GitHubClient) CreateIssue(ctx context.Context, org, repo string, body NewIssue) (*Issue, error) {
296+
path := fmt.Sprintf("%s/repos/%s/%s/issues", gitHubAPI, org, repo)
297+
var res Issue
298+
err := c.api.Do(ctx, "POST", path,
299+
httpclient.WithRequestData(body),
300+
httpclient.WithResponseUnmarshal(&res))
301+
if err != nil {
302+
return nil, err
303+
}
304+
return &res, nil
305+
}
306+
295307
func (c *GitHubClient) CreateIssueComment(ctx context.Context, org, repo string, number int, body string) (*IssueComment, error) {
296308
path := fmt.Sprintf("%s/repos/%s/%s/issues/%d/comments", gitHubAPI, org, repo, number)
297309
var res IssueComment

go-libs/github/issues.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ type ListIssues struct {
1515
PageOptions
1616
}
1717

18+
type NewIssue struct {
19+
Title string `json:"title,omitempty"`
20+
Body string `json:"body,omitempty"`
21+
Assignees []string `json:"assignees,omitempty"`
22+
Labels []string `json:"labels,omitempty"`
23+
}
24+
1825
type Issue struct {
1926
ID int64 `json:"id,omitempty"`
2027
Number int `json:"number,omitempty"`

go-libs/sqlexec/sqlexec_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func TestAccQueryTypes(t *testing.T) {
8282
require.NoError(t, result.Err())
8383

8484
require.Equal(t, []int{1, 2}, arrayType)
85-
require.Equal(t, []byte("a"), binaryType)
85+
require.Equal(t, []byte("a..."), binaryType)
8686
require.Equal(t, true, booleanType)
8787
require.Equal(t, time.Now().UTC().Truncate(24*time.Hour), dateType)
8888
require.InDelta(t, 3, decimalType, 0.01)

go.work.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,7 @@ github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg
445445
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
446446
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
447447
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
448+
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
448449
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
449450
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
450451
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
@@ -615,6 +616,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240205150955-31a09d347014/go.
615616
google.golang.org/genproto/googleapis/bytestream v0.0.0-20231127180814-3a041ad873d4/go.mod h1:o8b+u5ZiOSKuCwaZNjqXDJtJ0CmB9NtUPgCfO4rbakw=
616617
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:ZSvZ8l+AWJwXw91DoTjWjaVLpWU6o0eZ4YLYpH8aLeQ=
617618
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240213162025-012b6fc9bca9/go.mod h1:om8Bj876Z0v9ei+RD1LnEWig7vpHQ371PUqsgjmLQEA=
619+
google.golang.org/genproto/googleapis/bytestream v0.0.0-20240304161311-37d4d3c04a78/go.mod h1:vh/N7795ftP0AkN1w8XKqN4w1OdUKXW5Eummda+ofv8=
618620
google.golang.org/genproto/googleapis/rpc v0.0.0-20230822172742-b8732ec3820d/go.mod h1:+Bk1OCOj40wS2hwAMA+aCW9ypzm63QTBBHp6lQ3p+9M=
619621
google.golang.org/genproto/googleapis/rpc v0.0.0-20231002182017-d307bd883b97/go.mod h1:v7nGkzlmW8P3n/bKmWBn2WpBjpOEx8Q6gMueudAmKfY=
620622
google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc=

0 commit comments

Comments
 (0)