Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 18 additions & 12 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -1,26 +1,31 @@
name: CI

on:
push:
branches: [master]
pull_request:
on: [push, pull_request]

# Default to 'contents: read', which grants actions to read commits. Any
# permission not included is implicitly set to "none".
#
# see https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions
permissions:
contents: read

jobs:
test:
name: Test
runs-on: ubuntu-latest
timeout-minutes: 20 # guardrails timeout

strategy:
fail-fast: false
matrix:
go: ["1.12", "1.21", "1.22", "1.23"]
go: ["1.12", "1.21", "1.22", "1.23", "oldstable", "stable"]

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: ${{ matrix.go }}

Expand All @@ -32,17 +37,18 @@ jobs:
lint:
name: Lint
runs-on: ubuntu-latest
timeout-minutes: 20 # guardrails timeout

steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Set up Go
uses: actions/setup-go@3041bf56c941b39c61721a86cd11f3bb1338122a # v5.2.0
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5.5.0
with:
go-version: "1.23"
go-version: "stable"

- name: Lint
uses: golangci/golangci-lint-action@971e284b6050e8a5849b72094c50ab08da042db8 # v6.1.1
uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 # v8.0.0
with:
version: v1.63.4
version: v2.4
26 changes: 25 additions & 1 deletion .golangci.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,28 @@
version: "2"

linters:
disable-all: true
enable:
- errorlint
- nolintlint
- revive
- unconvert
- unparam
exclusions:
generated: disable
presets:
- comments
- std-error-handling
Comment on lines +5 to +14
Copy link
Collaborator

@tomasaschan tomasaschan Sep 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why this specific set of linters and presets? Is it based on what the repo is currently configured with, or on some listed standard set somewhere, or just your personal preference?

I personally don't mind being very specific with what code should look like - I think standardizing formatting from the get-go was one of the best things of Go when it launched - so if there's a way to just say "enable everything" I think it'd be fine to use that instead of listing specific linters or rulesets.

settings:
staticcheck:
# Enable all options, with some exceptions.
# For defaults, see https://golangci-lint.run/usage/linters/#staticcheck
checks:
- all
- -QF1008 # Omit embedded fields from selector expression; https://staticcheck.dev/docs/checks/#QF1008
- -ST1003 # Poorly chosen identifier; https://staticcheck.dev/docs/checks/#ST1003

formatters:
enable:
- gofmt
exclusions:
generated: disable
4 changes: 2 additions & 2 deletions bool_func_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestBoolFuncUsage(t *testing.T) {
// regular boolfunc flag:
// expect to see '--flag1' followed by the usageMessage, and no mention of a default value
fset := NewFlagSet("unittest", ContinueOnError)
fset.BoolFunc("flag1", "usage message", func(s string) error { return nil })
fset.BoolFunc("flag1", "usage message", func(string) error { return nil })
usage := fset.FlagUsagesWrapped(80)

usage = strings.TrimSpace(usage)
Expand All @@ -64,7 +64,7 @@ func TestBoolFuncUsage(t *testing.T) {
// func flag, with a placeholder name:
// if usageMesage contains a placeholder, expect '--flag2 {placeholder}'; still expect no mention of a default value
fset := NewFlagSet("unittest", ContinueOnError)
fset.BoolFunc("flag2", "usage message with `name` placeholder", func(s string) error { return nil })
fset.BoolFunc("flag2", "usage message with `name` placeholder", func(string) error { return nil })
usage := fset.FlagUsagesWrapped(80)

usage = strings.TrimSpace(usage)
Expand Down
4 changes: 1 addition & 3 deletions bool_slice.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,12 @@ func newBoolSliceValue(val []bool, p *[]bool) *boolSliceValue {
// Set converts, and assigns, the comma-separated boolean argument string representation as the []bool value of this flag.
// If Set is called on a flag that already has a []bool assigned, the newly converted values will be appended.
func (s *boolSliceValue) Set(val string) error {

// remove all quote characters
rmQuote := strings.NewReplacer(`"`, "", `'`, "", "`", "")

// read flag arguments with CSV parser
boolStrSlice, err := readAsCSV(rmQuote.Replace(val))
if err != nil && err != io.EOF {
if err != nil && err != io.EOF { //nolint:errorlint // not using errors.Is for compatibility with go1.12
return err
}

Expand Down Expand Up @@ -60,7 +59,6 @@ func (s *boolSliceValue) Type() string {

// String defines a "native" format for this boolean slice flag value.
func (s *boolSliceValue) String() string {

boolStrSlice := make([]string, len(*s.value))
for i, b := range *s.value {
boolStrSlice[i] = strconv.FormatBool(b)
Expand Down
1 change: 0 additions & 1 deletion bool_slice_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,6 @@ func TestBSAsSliceValue(t *testing.T) {
}

func TestBSBadQuoting(t *testing.T) {

tests := []struct {
Want []bool
FlagArg []string
Expand Down
2 changes: 1 addition & 1 deletion bool_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func (v *triStateValue) IsBoolFlag() bool {
}

func (v *triStateValue) Get() interface{} {
return triStateValue(*v)
return *v
}

func (v *triStateValue) Set(s string) error {
Expand Down
10 changes: 2 additions & 8 deletions bytes.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ func (bytesHex bytesHexValue) String() string {
// Set implements pflag.Value.Set.
func (bytesHex *bytesHexValue) Set(value string) error {
bin, err := hex.DecodeString(strings.TrimSpace(value))

if err != nil {
return err
}
Expand All @@ -39,20 +38,18 @@ func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue {
}

func bytesHexConv(sval string) (interface{}, error) {

bin, err := hex.DecodeString(sval)

if err == nil {
return bin, nil
}

return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err.Error())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is %w also a not-in-1.12 thing?

}

// GetBytesHex return the []byte value of a flag with the given name
func (f *FlagSet) GetBytesHex(name string) ([]byte, error) {
val, err := f.getFlagType(name, "bytesHex", bytesHexConv)

if err != nil {
return []byte{}, err
}
Expand Down Expand Up @@ -119,7 +116,6 @@ func (bytesBase64 bytesBase64Value) String() string {
// Set implements pflag.Value.Set.
func (bytesBase64 *bytesBase64Value) Set(value string) error {
bin, err := base64.StdEncoding.DecodeString(strings.TrimSpace(value))

if err != nil {
return err
}
Expand All @@ -140,19 +136,17 @@ func newBytesBase64Value(val []byte, p *[]byte) *bytesBase64Value {
}

func bytesBase64ValueConv(sval string) (interface{}, error) {

bin, err := base64.StdEncoding.DecodeString(sval)
if err == nil {
return bin, nil
}

return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err.Error())
}

// GetBytesBase64 return the []byte value of a flag with the given name
func (f *FlagSet) GetBytesBase64(name string) ([]byte, error) {
val, err := f.getFlagType(name, "bytesBase64", bytesBase64ValueConv)

if err != nil {
return []byte{}, err
}
Expand Down
2 changes: 1 addition & 1 deletion count.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ func newCountValue(val int, p *int) *countValue {
func (i *countValue) Set(s string) error {
// "+1" means that no specific value was passed, so increment
if s == "+1" {
*i = countValue(*i + 1)
*i = *i + 1
return nil
}
v, err := strconv.ParseInt(s, 0, 0)
Expand Down
5 changes: 2 additions & 3 deletions duration_slice.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package pflag

import (
"fmt"
"strings"
"time"
)
Expand Down Expand Up @@ -46,7 +45,7 @@ func (s *durationSliceValue) Type() string {
func (s *durationSliceValue) String() string {
out := make([]string, len(*s.value))
for i, d := range *s.value {
out[i] = fmt.Sprintf("%s", d)
out[i] = d.String()
}
return "[" + strings.Join(out, ",") + "]"
}
Expand All @@ -56,7 +55,7 @@ func (s *durationSliceValue) fromString(val string) (time.Duration, error) {
}

func (s *durationSliceValue) toString(val time.Duration) string {
return fmt.Sprintf("%s", val)
return val.String()
}

func (s *durationSliceValue) Append(val string) error {
Expand Down
4 changes: 2 additions & 2 deletions errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func TestInvalidValueError(t *testing.T) {
if err.GetValue() != "foo" {
t.Errorf("Expected GetValue to return %q, got %q", "foo", err.GetValue())
}
if err.Unwrap() != expectedCause {
t.Errorf("Expected Unwrwap to return %q, got %q", expectedCause, err.Unwrap())
if actual := err.Unwrap(); actual != expectedCause { //nolint:errorlint // not using errors.Is for compatibility with go1.12
t.Errorf("Expected Unwrwap to return %q, got %q", expectedCause, actual)
}
}

Expand Down
Loading