From 3e2f0d6c151f7f8e503d54473606894db1411e84 Mon Sep 17 00:00:00 2001 From: Tugdual Saunier Date: Fri, 9 May 2025 12:29:06 +0200 Subject: [PATCH] ci: add golangci-lint and resorb tech debt --- .github/workflows/test.yaml | 8 +++++++ .golangci.yml | 30 +++++++++++++++++++++++++ block.go | 2 +- formatter.go | 12 +++++----- formatter_test.go | 5 ++++- input.go | 20 +++++++++++------ input_helpers.go | 5 ++++- logging_test.go | 12 +++++++--- output.go | 44 +++++++++++++++++++++++-------------- output_test.go | 27 +++++++++++++++-------- spinner.go | 2 +- 11 files changed, 121 insertions(+), 46 deletions(-) create mode 100644 .golangci.yml diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index e09280f..decbd87 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -5,6 +5,14 @@ on: push: jobs: + lint: + name: Lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: golangci-lint + uses: golangci/golangci-lint-action@v8 + test: runs-on: ubuntu-latest strategy: diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..7638c33 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,30 @@ +version: "2" + +run: + issues-exit-code: 1 + +formatters: + enable: + - gofmt + - gci + +linters: + enable: + - wrapcheck + settings: + wrapcheck: + ignore-package-globs: + # We already make sure your own packages wrap errors properly + - github.com/symfony-cli/* + errcheck: + exclude-functions: + - github.com/symfony-cli/terminal.Printf + - github.com/symfony-cli/terminal.Println + - github.com/symfony-cli/terminal.Printfln + - github.com/symfony-cli/terminal.Eprintf + - github.com/symfony-cli/terminal.Eprintln + - github.com/symfony-cli/terminal.Eprintfln + - github.com/symfony-cli/terminal.Eprint + - fmt.Fprintln + - fmt.Fprintf + - fmt.Fprint diff --git a/block.go b/block.go index 4f8900d..bb61186 100644 --- a/block.go +++ b/block.go @@ -60,7 +60,7 @@ func splitsBlockLines(msg string, width int) ([]string, int) { } for _, line := range strings.Split(msg, "\n") { - line = strings.Replace(line, "\t", " ", -1) + line = strings.ReplaceAll(line, "\t", " ") lastLinePos := 0 inAnOpeningTag := false inAClosingTag := false diff --git a/formatter.go b/formatter.go index cb5211e..3201df3 100644 --- a/formatter.go +++ b/formatter.go @@ -72,9 +72,9 @@ func (s *styleStack) current() *FormatterStyle { const tagRegex = "[a-z][^<>]*" var ( - FormattingRegexp = regexp.MustCompile("(?i)<((" + tagRegex + ")?|/(" + tagRegex + ")?)>") - StyleRegexp = regexp.MustCompile("(?i)([^=]+)=([^;]+)(;|$)") - EscapingRegexp = regexp.MustCompile("([^\\\\]?)<") + FormattingRegexp = regexp.MustCompile(`(?i)<((` + tagRegex + ")?|/(" + tagRegex + ")?)>") + StyleRegexp = regexp.MustCompile(`(?i)([^=]+)=([^;]+)(;|$)`) + EscapingRegexp = regexp.MustCompile(`([^\\]?)<`) ) func Escape(msg []byte) []byte { @@ -231,11 +231,11 @@ func (formatter *Formatter) Format(msg []byte, w io.Writer) (written int, err er msg = output.Bytes() if bytes.Contains(msg, []byte("<<")) { - msg = bytes.Replace(msg, []byte("\\<"), []byte("\\<"), -1) - msg = bytes.Replace(msg, []byte("<<"), []byte("\\"), -1) + msg = bytes.ReplaceAll(msg, []byte("\\<"), []byte("\\<")) + msg = bytes.ReplaceAll(msg, []byte("<<"), []byte("\\")) } - msg = bytes.Replace(msg, []byte("\\<"), []byte("<"), -1) + msg = bytes.ReplaceAll(msg, []byte("\\<"), []byte("<")) _, err = w.Write(msg) return diff --git a/formatter_test.go b/formatter_test.go index d469356..1b5bc5d 100644 --- a/formatter_test.go +++ b/formatter_test.go @@ -23,6 +23,7 @@ import ( "bytes" "strings" + "github.com/rs/zerolog/log" . "gopkg.in/check.v1" ) @@ -104,7 +105,9 @@ var _ = Suite(&OutputFormatterSuite{}) func (formatter *Formatter) formatString(msg string) string { buf := bytes.NewBuffer([]byte(``)) - formatter.Format([]byte(msg), buf) + if _, err := formatter.Format([]byte(msg), buf); err != nil { + log.Err(err) + } return buf.String() } diff --git a/input.go b/input.go index 06d1db0..c18f4ad 100644 --- a/input.go +++ b/input.go @@ -23,6 +23,8 @@ import ( "fmt" "io" "os" + + "github.com/pkg/errors" ) var ( @@ -36,14 +38,16 @@ var ( // space-separated values into successive arguments. Newlines count // as space. It returns the number of items successfully scanned. // If that is less than the number of arguments, err will report why. -func Scan(a ...interface{}) (n int, err error) { - return fmt.Fscan(Stdin, a...) +func Scan(a ...interface{}) (int, error) { + n, err := fmt.Fscan(Stdin, a...) + return n, errors.WithStack(err) } // Scanln is similar to Scan, but stops scanning at a newline and // after the final item there must be a newline or EOF. -func Scanln(a ...interface{}) (n int, err error) { - return fmt.Fscanln(Stdin, a...) +func Scanln(a ...interface{}) (int, error) { + n, err := fmt.Fscanln(Stdin, a...) + return n, errors.WithStack(err) } // Scanf scans text read from standard input, storing successive @@ -53,8 +57,9 @@ func Scanln(a ...interface{}) (n int, err error) { // Newlines in the input must match newlines in the format. // The one exception: the verb %c always scans the next rune in the // input, even if it is a space (or tab etc.) or newline. -func Scanf(format string, a ...interface{}) (n int, err error) { - return fmt.Fscanf(Stdin, format, a...) +func Scanf(format string, a ...interface{}) (int, error) { + n, err := fmt.Fscanf(Stdin, format, a...) + return n, errors.WithStack(err) } type Input struct { @@ -78,7 +83,8 @@ func NewInput(reader io.Reader) *Input { } func (input *Input) Read(p []byte) (int, error) { - return input.reader.Read(p) + n, err := input.reader.Read(p) + return n, errors.WithStack(err) } func (input *Input) IsInteractive() bool { diff --git a/input_helpers.go b/input_helpers.go index c6db5af..cc96434 100644 --- a/input_helpers.go +++ b/input_helpers.go @@ -39,7 +39,10 @@ func AskStringDefault(message, def string, validator func(string) (string, bool) reader := bufio.NewReader(Stdin) for { - Print(message) + if _, err := Print(message); err != nil { + Logger.Err(err).Msg("could not write to terminal") + return def + } answer, readError := reader.ReadString('\n') if readError != nil { continue diff --git a/logging_test.go b/logging_test.go index 0bedca3..8e7d1a6 100644 --- a/logging_test.go +++ b/logging_test.go @@ -29,7 +29,9 @@ type LoggingSuite struct{} var _ = Suite(&LoggingSuite{}) func (ts *LoggingSuite) TestSetLogLevel(c *C) { - defer SetLogLevel(1) + defer func() { + c.Assert(SetLogLevel(1), IsNil) + }() var err error c.Assert(Logger.GetLevel(), Equals, zerolog.ErrorLevel) c.Assert(GetLogLevel(), Equals, 1) @@ -57,7 +59,9 @@ func (ts *LoggingSuite) TestSetLogLevel(c *C) { } func (ts *LoggingSuite) TestIsVerbose(c *C) { - defer SetLogLevel(1) + defer func() { + c.Assert(SetLogLevel(1), IsNil) + }() var err error c.Assert(IsVerbose(), Equals, false) @@ -72,7 +76,9 @@ func (ts *LoggingSuite) TestIsVerbose(c *C) { } func (ts *LoggingSuite) TestIsDebug(c *C) { - defer SetLogLevel(1) + defer func() { + c.Assert(SetLogLevel(1), IsNil) + }() var err error c.Assert(IsDebug(), Equals, false) diff --git a/output.go b/output.go index 9516933..445f924 100644 --- a/output.go +++ b/output.go @@ -23,6 +23,8 @@ import ( "fmt" "io" "os" + + "github.com/pkg/errors" ) func Formatf(msg string, a ...interface{}) string { @@ -36,55 +38,63 @@ func Format(msg string) string { // Print formats using the default formats for its operands and writes to standard output. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Print(a ...interface{}) (n int, err error) { - return fmt.Fprint(Stdout, a...) +func Print(a ...interface{}) (int, error) { + n, err := fmt.Fprint(Stdout, a...) + return n, errors.WithStack(err) } // Printf formats according to a format specifier and writes to standard output. // It returns the number of bytes written and any write error encountered. -func Printf(format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(Stdout, format, a...) +func Printf(format string, a ...interface{}) (int, error) { + n, err := fmt.Fprintf(Stdout, format, a...) + return n, errors.WithStack(err) } // Println formats using the default formats for its operands and writes to standard output. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Println(a ...interface{}) (n int, err error) { - return fmt.Fprintln(Stdout, a...) +func Println(a ...interface{}) (int, error) { + n, err := fmt.Fprintln(Stdout, a...) + return n, errors.WithStack(err) } // Printfln formats according to a format specifier and writes to standard error output. // A newline is appended. // It returns the number of bytes written and any write error encountered. -func Printfln(format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(Stdout, format+"\n", a...) +func Printfln(format string, a ...interface{}) (int, error) { + n, err := fmt.Fprintf(Stdout, format+"\n", a...) + return n, errors.WithStack(err) } // Eprint formats using the default formats for its operands and writes to standard error output. // Spaces are added between operands when neither is a string. // It returns the number of bytes written and any write error encountered. -func Eprint(a ...interface{}) (n int, err error) { - return fmt.Fprint(Stderr, a...) +func Eprint(a ...interface{}) (int, error) { + n, err := fmt.Fprint(Stderr, a...) + return n, errors.WithStack(err) } // Eprintf formats according to a format specifier and writes to standard error output. // It returns the number of bytes written and any write error encountered. -func Eprintf(format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(Stderr, format, a...) +func Eprintf(format string, a ...interface{}) (int, error) { + n, err := fmt.Fprintf(Stderr, format, a...) + return n, errors.WithStack(err) } // Eprintln formats using the default formats for its operands and writes to standard error output. // Spaces are always added between operands and a newline is appended. // It returns the number of bytes written and any write error encountered. -func Eprintln(a ...interface{}) (n int, err error) { - return fmt.Fprintln(Stderr, a...) +func Eprintln(a ...interface{}) (int, error) { + n, err := fmt.Fprintln(Stderr, a...) + return n, errors.WithStack(err) } // Eprintfln formats according to a format specifier and writes to standard error output. // A newline is appended. // It returns the number of bytes written and any write error encountered. -func Eprintfln(format string, a ...interface{}) (n int, err error) { - return fmt.Fprintf(Stderr, format+"\n", a...) +func Eprintfln(format string, a ...interface{}) (int, error) { + n, err := fmt.Fprintf(Stderr, format+"\n", a...) + return n, errors.WithStack(err) } var ( @@ -144,7 +154,7 @@ func (o Output) Write(message []byte) (int, error) { func (o Output) Close() error { if wc, ok := o.writer.(io.WriteCloser); ok { - return wc.Close() + return errors.WithStack(wc.Close()) } return nil diff --git a/output_test.go b/output_test.go index 09c2e96..a013f48 100644 --- a/output_test.go +++ b/output_test.go @@ -46,7 +46,8 @@ func (ts *ConsoleOutputSuite) TestConsoleOutput(c *C) { buffer := new(bytes.Buffer) output := NewBufferedConsoleOutput(buffer, buffer) - output.Write([]byte("test")) + _, err := output.Write([]byte("test")) + c.Assert(err, IsNil) c.Assert(buffer.String(), Equals, "test") formatter := NewFormatter() @@ -82,34 +83,42 @@ func (ts *ConsoleOutputSuite) TestWrappers(c *C) { Stderr = Stdout.Stderr bufferStdout.Reset() - Print("test") + _, err := Print("test") + c.Assert(err, IsNil) c.Check(bufferStdout.String(), Equals, "test") bufferStdout.Reset() - Println("test") + _, err = Println("test") + c.Assert(err, IsNil) c.Check(bufferStdout.String(), Equals, "test\n") bufferStdout.Reset() - Printf("test %d", 2) + _, err = Printf("test %d", 2) + c.Assert(err, IsNil) c.Check(bufferStdout.String(), Equals, "test 2") bufferStdout.Reset() - Printfln("test %d", 3) + _, err = Printfln("test %d", 3) + c.Assert(err, IsNil) c.Check(bufferStdout.String(), Equals, "test 3\n") bufferStderr.Reset() - Eprint("test") + _, err = Eprint("test") + c.Assert(err, IsNil) c.Check(bufferStderr.String(), Equals, "test") bufferStderr.Reset() - Eprintln("test") + _, err = Eprintln("test") + c.Assert(err, IsNil) c.Check(bufferStderr.String(), Equals, "test\n") bufferStderr.Reset() - Eprintf("test %d", 2) + _, err = Eprintf("test %d", 2) + c.Assert(err, IsNil) c.Check(bufferStderr.String(), Equals, "test 2") bufferStderr.Reset() - Eprintfln("test %d", 3) + _, err = Eprintfln("test %d", 3) + c.Assert(err, IsNil) c.Check(bufferStderr.String(), Equals, "test 3\n") } diff --git a/spinner.go b/spinner.go index b5bf229..b07272c 100644 --- a/spinner.go +++ b/spinner.go @@ -101,7 +101,7 @@ func (s *Spinner) Start() { fmt.Fprintf(&b, "%s%s%s %s%s", s.PrefixText, s.PrefixIndicator, s.chars[i], s.SuffixIndicator, s.SuffixText) cursor.ClearLineAfter() cursor.RestorePosition() - b.WriteTo(s.Writer) + _, _ = b.WriteTo(s.Writer) s.lock.Unlock() time.Sleep(s.delay) }