Skip to content

Commit 979a4aa

Browse files
authored
dev: isolate printer code (#4435)
1 parent b1eed50 commit 979a4aa

10 files changed

+1197
-99
lines changed

pkg/commands/run.go

+14-89
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,6 @@ import (
4444
"github.com/golangci/golangci-lint/pkg/timeutils"
4545
)
4646

47-
const defaultFileMode = 0644
48-
4947
const defaultTimeout = time.Minute
5048

5149
const (
@@ -83,6 +81,8 @@ type runCommand struct {
8381

8482
dbManager *lintersdb.Manager
8583

84+
printer *printers.Printer
85+
8686
log logutils.Log
8787
debugf logutils.DebugFunc
8888
reportData *report.Data
@@ -184,6 +184,13 @@ func (c *runCommand) preRunE(_ *cobra.Command, _ []string) error {
184184

185185
c.dbManager = dbManager
186186

187+
printer, err := printers.NewPrinter(c.log, c.cfg, c.reportData)
188+
if err != nil {
189+
return err
190+
}
191+
192+
c.printer = printer
193+
187194
c.goenv = goutil.NewEnv(c.log.Child(logutils.DebugKeyGoEnv))
188195

189196
c.fileCache = fsutils.NewFileCache()
@@ -320,20 +327,12 @@ func (c *runCommand) runAndPrint(ctx context.Context, args []string) error {
320327

321328
issues, err := c.runAnalysis(ctx, args)
322329
if err != nil {
323-
return err // XXX: don't loose type
330+
return err // XXX: don't lose type
324331
}
325332

326-
formats := strings.Split(c.cfg.Output.Format, ",")
327-
for _, format := range formats {
328-
out := strings.SplitN(format, ":", 2)
329-
if len(out) < 2 {
330-
out = append(out, "")
331-
}
332-
333-
err := c.printReports(issues, out[1], out[0])
334-
if err != nil {
335-
return err
336-
}
333+
err = c.printer.Print(issues)
334+
if err != nil {
335+
return err
337336
}
338337

339338
c.printStats(issues)
@@ -397,80 +396,6 @@ func (c *runCommand) setExitCodeIfIssuesFound(issues []result.Issue) {
397396
}
398397
}
399398

400-
func (c *runCommand) printReports(issues []result.Issue, path, format string) error {
401-
w, shouldClose, err := c.createWriter(path)
402-
if err != nil {
403-
return fmt.Errorf("can't create output for %s: %w", path, err)
404-
}
405-
406-
p, err := c.createPrinter(format, w)
407-
if err != nil {
408-
if file, ok := w.(io.Closer); shouldClose && ok {
409-
_ = file.Close()
410-
}
411-
return err
412-
}
413-
414-
if err = p.Print(issues); err != nil {
415-
if file, ok := w.(io.Closer); shouldClose && ok {
416-
_ = file.Close()
417-
}
418-
return fmt.Errorf("can't print %d issues: %w", len(issues), err)
419-
}
420-
421-
if file, ok := w.(io.Closer); shouldClose && ok {
422-
_ = file.Close()
423-
}
424-
425-
return nil
426-
}
427-
428-
func (c *runCommand) createWriter(path string) (io.Writer, bool, error) {
429-
if path == "" || path == "stdout" {
430-
return logutils.StdOut, false, nil
431-
}
432-
if path == "stderr" {
433-
return logutils.StdErr, false, nil
434-
}
435-
f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, defaultFileMode)
436-
if err != nil {
437-
return nil, false, err
438-
}
439-
return f, true, nil
440-
}
441-
442-
func (c *runCommand) createPrinter(format string, w io.Writer) (printers.Printer, error) {
443-
var p printers.Printer
444-
switch format {
445-
case config.OutFormatJSON:
446-
p = printers.NewJSON(c.reportData, w)
447-
case config.OutFormatColoredLineNumber, config.OutFormatLineNumber:
448-
p = printers.NewText(c.cfg.Output.PrintIssuedLine,
449-
format == config.OutFormatColoredLineNumber, c.cfg.Output.PrintLinterName,
450-
c.log.Child(logutils.DebugKeyTextPrinter), w)
451-
case config.OutFormatTab, config.OutFormatColoredTab:
452-
p = printers.NewTab(c.cfg.Output.PrintLinterName,
453-
format == config.OutFormatColoredTab,
454-
c.log.Child(logutils.DebugKeyTabPrinter), w)
455-
case config.OutFormatCheckstyle:
456-
p = printers.NewCheckstyle(w)
457-
case config.OutFormatCodeClimate:
458-
p = printers.NewCodeClimate(w)
459-
case config.OutFormatHTML:
460-
p = printers.NewHTML(w)
461-
case config.OutFormatJunitXML:
462-
p = printers.NewJunitXML(w)
463-
case config.OutFormatGithubActions:
464-
p = printers.NewGithub(w)
465-
case config.OutFormatTeamCity:
466-
p = printers.NewTeamCity(w)
467-
default:
468-
return nil, fmt.Errorf("unknown output format %s", format)
469-
}
470-
471-
return p, nil
472-
}
473-
474399
func (c *runCommand) printStats(issues []result.Issue) {
475400
if !c.cfg.Run.ShowStats {
476401
return
@@ -688,7 +613,7 @@ func formatMemory(memBytes uint64) string {
688613
return fmt.Sprintf("%dmb", memBytes/Mb)
689614
}
690615

691-
// --- Related to cache.
616+
// Related to cache.
692617

693618
func initHashSalt(version string, cfg *config.Config) error {
694619
binSalt, err := computeBinarySalt(version)

pkg/printers/github.go

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,16 @@ import (
88
"github.com/golangci/golangci-lint/pkg/result"
99
)
1010

11-
type github struct {
11+
type GitHub struct {
1212
w io.Writer
1313
}
1414

1515
const defaultGithubSeverity = "error"
1616

17-
// NewGithub output format outputs issues according to GitHub actions format:
17+
// NewGitHub output format outputs issues according to GitHub actions format:
1818
// https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions#setting-an-error-message
19-
func NewGithub(w io.Writer) Printer {
20-
return &github{w: w}
19+
func NewGitHub(w io.Writer) *GitHub {
20+
return &GitHub{w: w}
2121
}
2222

2323
// print each line as: ::error file=app.js,line=10,col=15::Something went wrong
@@ -41,7 +41,7 @@ func formatIssueAsGithub(issue *result.Issue) string {
4141
return ret
4242
}
4343

44-
func (p *github) Print(issues []result.Issue) error {
44+
func (p *GitHub) Print(issues []result.Issue) error {
4545
for ind := range issues {
4646
_, err := fmt.Fprintln(p.w, formatIssueAsGithub(&issues[ind]))
4747
if err != nil {

pkg/printers/github_test.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import (
1313
"github.com/golangci/golangci-lint/pkg/result"
1414
)
1515

16-
func TestGithub_Print(t *testing.T) {
16+
func TestGitHub_Print(t *testing.T) {
1717
issues := []result.Issue{
1818
{
1919
FromLinter: "linter-a",
@@ -45,7 +45,7 @@ func TestGithub_Print(t *testing.T) {
4545
}
4646

4747
buf := new(bytes.Buffer)
48-
printer := NewGithub(buf)
48+
printer := NewGitHub(buf)
4949

5050
err := printer.Print(issues)
5151
require.NoError(t, err)
@@ -57,7 +57,7 @@ func TestGithub_Print(t *testing.T) {
5757
assert.Equal(t, expected, buf.String())
5858
}
5959

60-
func TestFormatGithubIssue(t *testing.T) {
60+
func Test_formatIssueAsGithub(t *testing.T) {
6161
sampleIssue := result.Issue{
6262
FromLinter: "sample-linter",
6363
Text: "some issue",
@@ -74,7 +74,7 @@ func TestFormatGithubIssue(t *testing.T) {
7474
require.Equal(t, "::error file=path/to/file.go,line=10::some issue (sample-linter)", formatIssueAsGithub(&sampleIssue))
7575
}
7676

77-
func TestFormatGithubIssueWindows(t *testing.T) {
77+
func Test_formatIssueAsGithub_Windows(t *testing.T) {
7878
if runtime.GOOS != "windows" {
7979
t.Skip("Skipping test on non Windows")
8080
}

pkg/printers/printer.go

+133-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,141 @@
11
package printers
22

33
import (
4+
"errors"
5+
"fmt"
6+
"io"
7+
"os"
8+
"strings"
9+
10+
"github.com/golangci/golangci-lint/pkg/config"
11+
"github.com/golangci/golangci-lint/pkg/logutils"
12+
"github.com/golangci/golangci-lint/pkg/report"
413
"github.com/golangci/golangci-lint/pkg/result"
514
)
615

7-
type Printer interface {
16+
const defaultFileMode = 0644
17+
18+
type issuePrinter interface {
819
Print(issues []result.Issue) error
920
}
21+
22+
// Printer prints issues
23+
type Printer struct {
24+
cfg *config.Config
25+
reportData *report.Data
26+
27+
log logutils.Log
28+
29+
stdOut io.Writer
30+
stdErr io.Writer
31+
}
32+
33+
// NewPrinter creates a new Printer.
34+
func NewPrinter(log logutils.Log, cfg *config.Config, reportData *report.Data) (*Printer, error) {
35+
if log == nil {
36+
return nil, errors.New("missing log argument in constructor")
37+
}
38+
if cfg == nil {
39+
return nil, errors.New("missing config argument in constructor")
40+
}
41+
if reportData == nil {
42+
return nil, errors.New("missing reportData argument in constructor")
43+
}
44+
45+
return &Printer{
46+
cfg: cfg,
47+
reportData: reportData,
48+
log: log,
49+
stdOut: logutils.StdOut,
50+
stdErr: logutils.StdErr,
51+
}, nil
52+
}
53+
54+
// Print prints issues based on the formats defined
55+
func (c *Printer) Print(issues []result.Issue) error {
56+
formats := strings.Split(c.cfg.Output.Format, ",")
57+
58+
for _, item := range formats {
59+
format, path, _ := strings.Cut(item, ":")
60+
err := c.printReports(issues, path, format)
61+
if err != nil {
62+
return err
63+
}
64+
}
65+
66+
return nil
67+
}
68+
69+
func (c *Printer) printReports(issues []result.Issue, path, format string) error {
70+
w, shouldClose, err := c.createWriter(path)
71+
if err != nil {
72+
return fmt.Errorf("can't create output for %s: %w", path, err)
73+
}
74+
75+
defer func() {
76+
if file, ok := w.(io.Closer); shouldClose && ok {
77+
_ = file.Close()
78+
}
79+
}()
80+
81+
p, err := c.createPrinter(format, w)
82+
if err != nil {
83+
return err
84+
}
85+
86+
if err = p.Print(issues); err != nil {
87+
return fmt.Errorf("can't print %d issues: %w", len(issues), err)
88+
}
89+
90+
return nil
91+
}
92+
93+
func (c *Printer) createWriter(path string) (io.Writer, bool, error) {
94+
if path == "" || path == "stdout" {
95+
return c.stdOut, false, nil
96+
}
97+
98+
if path == "stderr" {
99+
return c.stdErr, false, nil
100+
}
101+
102+
f, err := os.OpenFile(path, os.O_CREATE|os.O_TRUNC|os.O_WRONLY, defaultFileMode)
103+
if err != nil {
104+
return nil, false, err
105+
}
106+
107+
return f, true, nil
108+
}
109+
110+
func (c *Printer) createPrinter(format string, w io.Writer) (issuePrinter, error) {
111+
var p issuePrinter
112+
113+
switch format {
114+
case config.OutFormatJSON:
115+
p = NewJSON(c.reportData, w)
116+
case config.OutFormatColoredLineNumber, config.OutFormatLineNumber:
117+
p = NewText(c.cfg.Output.PrintIssuedLine,
118+
format == config.OutFormatColoredLineNumber, c.cfg.Output.PrintLinterName,
119+
c.log.Child(logutils.DebugKeyTextPrinter), w)
120+
case config.OutFormatTab, config.OutFormatColoredTab:
121+
p = NewTab(c.cfg.Output.PrintLinterName,
122+
format == config.OutFormatColoredTab,
123+
c.log.Child(logutils.DebugKeyTabPrinter), w)
124+
case config.OutFormatCheckstyle:
125+
p = NewCheckstyle(w)
126+
case config.OutFormatCodeClimate:
127+
p = NewCodeClimate(w)
128+
case config.OutFormatHTML:
129+
p = NewHTML(w)
130+
case config.OutFormatJunitXML:
131+
p = NewJunitXML(w)
132+
case config.OutFormatGithubActions:
133+
p = NewGitHub(w)
134+
case config.OutFormatTeamCity:
135+
p = NewTeamCity(w)
136+
default:
137+
return nil, fmt.Errorf("unknown output format %s", format)
138+
}
139+
140+
return p, nil
141+
}

0 commit comments

Comments
 (0)