Skip to content

Commit 90f80fa

Browse files
committed
roachtest: add github issue posting dry run mode
We already have the functionality in datadriven tests to render github issue post requests as clickable links. This change extends that functionality to roachtests in the form of a --dry-run-issue-posting flag. This allows for viewing what the output of a failed roachtest would look like even if github posting is disabled.
1 parent 755545b commit 90f80fa

File tree

6 files changed

+92
-49
lines changed

6 files changed

+92
-49
lines changed

pkg/cmd/roachtest/github.go

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ package main
88
import (
99
"context"
1010
"fmt"
11+
"net/url"
1112
"os"
13+
"strings"
1214
"time"
1315

1416
"github.com/cockroachdb/cockroach/pkg/cmd/bazci/githubpost/issues"
@@ -35,6 +37,7 @@ type GithubPoster interface {
3537
// githubIssues struct implements GithubPoster
3638
type githubIssues struct {
3739
disable bool
40+
dryRun bool
3841
issuePoster func(context.Context, issues.Logger, issues.IssueFormatter, issues.PostRequest,
3942
*issues.Options) (*issues.TestFailureIssue, error)
4043
teamLoader func() (team.Map, error)
@@ -327,6 +330,10 @@ func (g *githubIssues) MaybePost(
327330
message string,
328331
params map[string]string,
329332
) (*issues.TestFailureIssue, error) {
333+
if g.dryRun {
334+
return nil, g.dryRunPost(t, issueInfo, l, message, params)
335+
}
336+
330337
skipReason := g.shouldPost(t)
331338
if skipReason != "" {
332339
l.Printf("skipping GitHub issue posting (%s)", skipReason)
@@ -352,3 +359,75 @@ func (g *githubIssues) MaybePost(
352359
opts,
353360
)
354361
}
362+
363+
// dryRunPost simulates posting an issue to GitHub by rendering
364+
// the issue and logging a clickable link.
365+
func (g *githubIssues) dryRunPost(
366+
t *testImpl,
367+
issueInfo *githubIssueInfo,
368+
l *logger.Logger,
369+
message string,
370+
params map[string]string,
371+
) error {
372+
postRequest, err := g.createPostRequest(
373+
t.Name(), t.start, t.end, t.spec, t.failures(),
374+
message,
375+
roachtestutil.UsingRuntimeAssertions(t), t.goCoverEnabled, params, issueInfo,
376+
)
377+
if err != nil {
378+
return err
379+
}
380+
_, url, err := formatPostRequest(postRequest)
381+
if err != nil {
382+
return err
383+
}
384+
l.Printf("GitHub issue posting in dry-run mode:\n%s", url)
385+
return nil
386+
}
387+
388+
// formatPostRequest returns a string representation of the rendered PostRequest
389+
// as well as a link that can be followed to open the issue in Github. The rendered
390+
// PostRequest also includes the labels that would be applied to the issue as part
391+
// of the body.
392+
func formatPostRequest(req issues.PostRequest) (string, string, error) {
393+
data := issues.TemplateData{
394+
PostRequest: req,
395+
Parameters: req.ExtraParams,
396+
CondensedMessage: issues.CondensedMessage(req.Message),
397+
Branch: "test_branch",
398+
Commit: "test_SHA",
399+
PackageNameShort: strings.TrimPrefix(req.PackageName, issues.CockroachPkgPrefix),
400+
}
401+
402+
formatter := issues.UnitTestFormatter
403+
r := &issues.Renderer{}
404+
if err := formatter.Body(r, data); err != nil {
405+
return "", "", err
406+
}
407+
408+
var post strings.Builder
409+
post.WriteString(r.String())
410+
411+
// Github labels are normally not part of the rendered issue body, but we want to
412+
// still test that they are correctly set so append them here.
413+
post.WriteString("\n------\nLabels:\n")
414+
for _, label := range req.Labels {
415+
post.WriteString(fmt.Sprintf("- <code>%s</code>\n", label))
416+
}
417+
418+
u, err := url.Parse("https://github.com/cockroachdb/cockroach/issues/new")
419+
if err != nil {
420+
return "", "", err
421+
}
422+
q := u.Query()
423+
q.Add("title", formatter.Title(data))
424+
q.Add("body", post.String())
425+
// Adding a template parameter is required to be able to view the rendered
426+
// template on GitHub, otherwise it just takes you to the template selection
427+
// page.
428+
q.Add("template", "none")
429+
u.RawQuery = q.Encode()
430+
post.WriteString(fmt.Sprintf("Rendered:\n%s", u.String()))
431+
432+
return post.String(), u.String(), nil
433+
}

pkg/cmd/roachtest/github_test.go

Lines changed: 2 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ package main
77
import (
88
"context"
99
"fmt"
10-
"net/url"
1110
"path/filepath"
1211
"strings"
1312
"testing"
@@ -90,7 +89,7 @@ func TestShouldPost(t *testing.T) {
9089

9190
ti := &testImpl{spec: testSpec}
9291
ti.mu.failures = c.failures
93-
github := &githubIssues{disable: c.disableIssues}
92+
github := &githubIssues{disable: c.disableIssues, dryRun: false}
9493

9594
skipReason := github.shouldPost(ti)
9695
require.Equal(t, c.expectedReason, skipReason)
@@ -184,7 +183,7 @@ func TestCreatePostRequest(t *testing.T) {
184183
}
185184
require.NoError(t, err)
186185

187-
post, err := formatPostRequest(req)
186+
post, _, err := formatPostRequest(req)
188187
require.NoError(t, err)
189188

190189
return post
@@ -258,49 +257,3 @@ F250826 19:49:07.194443 3106 sql/sem/builtins/builtins.go:6063 ⋮ [T1,Vsystem,n
258257
})
259258
})
260259
}
261-
262-
// formatPostRequest returns a string representation of the rendered PostRequest.
263-
// Additionally, it also includes labels, as well as a link that can be followed
264-
// to open the issue in Github.
265-
func formatPostRequest(req issues.PostRequest) (string, error) {
266-
data := issues.TemplateData{
267-
PostRequest: req,
268-
Parameters: req.ExtraParams,
269-
CondensedMessage: issues.CondensedMessage(req.Message),
270-
Branch: "test_branch",
271-
Commit: "test_SHA",
272-
PackageNameShort: strings.TrimPrefix(req.PackageName, issues.CockroachPkgPrefix),
273-
}
274-
275-
formatter := issues.UnitTestFormatter
276-
r := &issues.Renderer{}
277-
if err := formatter.Body(r, data); err != nil {
278-
return "", err
279-
}
280-
281-
var post strings.Builder
282-
post.WriteString(r.String())
283-
284-
// Github labels are normally not part of the rendered issue body, but we want to
285-
// still test that they are correctly set so append them here.
286-
post.WriteString("\n------\nLabels:\n")
287-
for _, label := range req.Labels {
288-
post.WriteString(fmt.Sprintf("- <code>%s</code>\n", label))
289-
}
290-
291-
u, err := url.Parse("https://github.com/cockroachdb/cockroach/issues/new")
292-
if err != nil {
293-
return "", err
294-
}
295-
q := u.Query()
296-
q.Add("title", formatter.Title(data))
297-
q.Add("body", post.String())
298-
// Adding a template parameter is required to be able to view the rendered
299-
// template on GitHub, otherwise it just takes you to the template selection
300-
// page.
301-
q.Add("template", "none")
302-
u.RawQuery = q.Encode()
303-
post.WriteString(fmt.Sprintf("Rendered:\n%s", u.String()))
304-
305-
return post.String(), nil
306-
}

pkg/cmd/roachtest/roachtestflags/flags.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,12 @@ var (
446446
Usage: `Disable posting GitHub issue for failures`,
447447
})
448448

449+
DryRunIssuePosting bool
450+
_ = registerRunFlag(&DryRunIssuePosting, FlagInfo{
451+
Name: "dry-run-issue-posting",
452+
Usage: `Enable dry-run mode for GitHub issue posting (formats issues but doesn't post them)`,
453+
})
454+
449455
PromPort int = 2113
450456
_ = registerRunFlag(&PromPort, FlagInfo{
451457
Name: "prom-port",

pkg/cmd/roachtest/run.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,7 @@ func runTests(register func(registry.Registry), filter *registry.TestFilter) err
143143

144144
github := &githubIssues{
145145
disable: runner.config.disableIssue,
146+
dryRun: runner.config.dryRunIssuePosting,
146147
issuePoster: issues.Post,
147148
teamLoader: team.DefaultLoadTeams,
148149
}

pkg/cmd/roachtest/test_runner.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ type testRunner struct {
148148
skipClusterWipeOnAttach bool
149149
// disableIssue disables posting GitHub issues for test failures.
150150
disableIssue bool
151+
// dryRunIssuePosting enables dry-run mode for GitHub issue posting.
152+
dryRunIssuePosting bool
151153
// overrideShutdownPromScrapeInterval overrides the default time a test runner waits to
152154
// shut down, normally used to ensure a remote prometheus server has scraped the roachtest
153155
// endpoint.
@@ -215,6 +217,7 @@ func newTestRunner(cr *clusterRegistry, stopper *stop.Stopper) *testRunner {
215217
}
216218
r.config.skipClusterWipeOnAttach = !roachtestflags.ClusterWipe
217219
r.config.disableIssue = roachtestflags.DisableIssue
220+
r.config.dryRunIssuePosting = roachtestflags.DryRunIssuePosting
218221
r.workersMu.workers = make(map[string]*workerStatus)
219222
return r
220223
}

pkg/cmd/roachtest/test_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ func defaultLoggingOpt(buf *syncedBuffer) loggingOpt {
103103
func defaultGithub(disable bool) GithubPoster {
104104
return &githubIssues{
105105
disable: disable,
106+
dryRun: false,
106107
// issuePoster isn't mocked because an env var check exits MaybePost when
107108
// the GitHub API isn't present, so technically setting it here doesn't
108109
// matter

0 commit comments

Comments
 (0)