From 0e0bf8b4b4298240be1225193701f0abc5f6646b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 10:31:55 +0200 Subject: [PATCH 01/11] initial effort --- action.yml | 6 ++++++ go.mod | 4 ++++ go.sum | 15 +++++++++++++++ main.go | 6 ++++++ pkg/testcoverage/check.go | 20 +++++++++++++++++++- pkg/testcoverage/config.go | 1 + pkg/testcoverage/coverage/module.go | 8 ++++---- pkg/testcoverage/logger/logger.go | 18 ++++++++++++++++++ 8 files changed, 73 insertions(+), 5 deletions(-) create mode 100644 pkg/testcoverage/logger/logger.go diff --git a/action.yml b/action.yml index e4220848..009157f7 100644 --- a/action.yml +++ b/action.yml @@ -13,6 +13,11 @@ inputs: required: false default: "" type: string + debug: + description: Prints additional debugging output when running action. + required: false + default: false + type: boolean # Individual properties profile: @@ -138,6 +143,7 @@ runs: - --config=${{ inputs.config || '''''' }} - --profile=${{ inputs.profile || '''''' }} - --source-dir=${{ inputs.source-dir || '''''' }} + - --debug=${{ inputs.debug }} - --github-action-output=true - --threshold-file=${{ inputs.threshold-file }} - --threshold-package=${{ inputs.threshold-package }} diff --git a/go.mod b/go.mod index 48cfb8e1..6ff56e68 100644 --- a/go.mod +++ b/go.mod @@ -22,11 +22,15 @@ require ( github.com/google/go-querystring v1.1.0 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect github.com/kr/pretty v0.3.1 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.19 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/rs/zerolog v1.34.0 // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect golang.org/x/image v0.18.0 // indirect + golang.org/x/sys v0.26.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index 5b576e21..9e062d3b 100644 --- a/go.sum +++ b/go.sum @@ -5,10 +5,12 @@ github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oy github.com/aws/aws-sdk-go v1.44.256/go.mod h1:aVsgQcEevwlmQ7qHE9I3h+dtQgpqhFB+i8Phjh7fkwI= github.com/aws/aws-sdk-go v1.49.4 h1:qiXsqEeLLhdLgUIyfr5ot+N/dGPWALmtM1SetRmbUlY= github.com/aws/aws-sdk-go v1.49.4/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk= +github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= @@ -31,6 +33,11 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA= +github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/narqo/go-badge v0.0.0-20230821190521-c9a75c019a59 h1:kbREB9muGo4sHLoZJD/E/IV8yK3Y15eEA9mYi/ztRsk= github.com/narqo/go-badge v0.0.0-20230821190521-c9a75c019a59/go.mod h1:m9BzkaxwU4IfPQi9ko23cmuFltayFe8iS0dlRlnEWiM= github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= @@ -40,6 +47,9 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= +github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= +github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8= github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8= github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 h1:WnNuhiq+FOY3jNj6JXFT+eLN3CQ/oPIsDPRanvwsmbI= @@ -77,9 +87,14 @@ golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= diff --git a/main.go b/main.go index 2d3d918f..8c791278 100644 --- a/main.go +++ b/main.go @@ -26,6 +26,7 @@ const ( type args struct { ConfigPath string `arg:"-c,--config"` Profile string `arg:"-p,--profile" help:"path to coverage profile"` + Debug bool `arg:"-d,--debug"` LocalPrefix string `arg:"-l,--local-prefix"` // deprecated SourceDir string `arg:"-s,--source-dir"` GithubActionOutput bool `arg:"-o,--github-action-output"` @@ -56,6 +57,7 @@ func newArgs() args { return args{ ConfigPath: ciDefaultString, Profile: ciDefaultString, + Debug: false, LocalPrefix: ciDefaultString, SourceDir: ciDefaultString, GithubActionOutput: false, @@ -96,6 +98,10 @@ func (a *args) overrideConfig(cfg testcoverage.Config) (testcoverage.Config, err cfg.Profile = a.Profile } + if a.Debug { + cfg.Debug = true + } + if a.GithubActionOutput { cfg.GithubActionOutput = true } diff --git a/pkg/testcoverage/check.go b/pkg/testcoverage/check.go index c563a2b2..917e234a 100644 --- a/pkg/testcoverage/check.go +++ b/pkg/testcoverage/check.go @@ -9,9 +9,27 @@ import ( "strings" "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/coverage" + "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/logger" ) -func Check(w io.Writer, cfg Config) bool { +//nolint:maintidx // relax +func Check(wout io.Writer, cfg Config) bool { + buffer := &bytes.Buffer{} + w := bufio.NewWriter(buffer) + //nolint:errcheck // relax + defer func() { + if cfg.Debug { + wout.Write(logger.Buffer.Bytes()) + wout.Write([]byte("-------------------------\n\n")) + } + + w.Flush() + wout.Write(buffer.Bytes()) + }() + + logger.L.Debug().Msg("running check...") + logger.L.Debug().Any("config", cfg).Msg("using configuration") + currentStats, err := GenerateCoverageStats(cfg) if err != nil { fmt.Fprintf(w, "failed to generate coverage statistics: %v\n", err) diff --git a/pkg/testcoverage/config.go b/pkg/testcoverage/config.go index ae8b09a5..7a89fc99 100644 --- a/pkg/testcoverage/config.go +++ b/pkg/testcoverage/config.go @@ -23,6 +23,7 @@ var ( type Config struct { Profile string `yaml:"profile"` + Debug bool `yaml:"-"` LocalPrefixDeprecated string `yaml:"-"` SourceDir string `yaml:"-"` Threshold Threshold `yaml:"threshold"` diff --git a/pkg/testcoverage/coverage/module.go b/pkg/testcoverage/coverage/module.go index 2d4ec8c8..b0817a56 100644 --- a/pkg/testcoverage/coverage/module.go +++ b/pkg/testcoverage/coverage/module.go @@ -2,23 +2,23 @@ package coverage import ( "bufio" - "fmt" "os" "path/filepath" "strings" + + "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/logger" ) -//nolint:forbidigo // relax func findModuleDirective(rootDir string) string { goModFile := findGoModFile(rootDir) if goModFile == "" { - fmt.Printf("could not find go.mod file in root dir: %s\n", rootDir) + logger.L.Debug().Str("dir", rootDir).Msg("could not find go.mod file in root dir") return "" } module := readModuleDirective(goModFile) if module == "" { // coverage-ignore - fmt.Println("`module` directive not found") + logger.L.Debug().Msg("`module` directive not found") } return module diff --git a/pkg/testcoverage/logger/logger.go b/pkg/testcoverage/logger/logger.go new file mode 100644 index 00000000..c070aada --- /dev/null +++ b/pkg/testcoverage/logger/logger.go @@ -0,0 +1,18 @@ +package logger + +import ( + "bytes" + + "github.com/rs/zerolog" +) + +//nolint:gochecknoglobals // relax +var ( + Buffer bytes.Buffer + L zerolog.Logger +) + +//nolint:gochecknoinits // relax +func init() { + L = zerolog.New(&Buffer).With().Logger() +} From a36419d68ab585a79a20cdd03d6287190451fcb7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 10:33:52 +0200 Subject: [PATCH 02/11] mod tidy --- go.mod | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 6ff56e68..935470a7 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/google/go-github/v56 v56.0.0 github.com/johannesboyne/gofakes3 v0.0.0-20230914150226-f005f5cc03aa github.com/narqo/go-badge v0.0.0-20230821190521-c9a75c019a59 + github.com/rs/zerolog v1.34.0 github.com/stretchr/testify v1.10.0 golang.org/x/tools v0.26.0 gopkg.in/yaml.v3 v3.0.1 @@ -26,7 +27,6 @@ require ( github.com/mattn/go-isatty v0.0.19 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect - github.com/rs/zerolog v1.34.0 // indirect github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 // indirect github.com/shabbyrobe/gocovmerge v0.0.0-20190829150210-3e036491d500 // indirect golang.org/x/image v0.18.0 // indirect From 01321cd800d7bcdb75f9fdde533c826bdf5ddc86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 10:51:35 +0200 Subject: [PATCH 03/11] more effort --- .github/.testcoverage-local.yml | 3 +- .github/.testcoverage.yml | 3 +- Makefile | 2 +- main.go | 198 +---------------------------- main_config.go | 202 ++++++++++++++++++++++++++++++ pkg/testcoverage/check.go | 2 +- pkg/testcoverage/check_test.go | 14 +++ pkg/testcoverage/logger/logger.go | 21 +++- 8 files changed, 241 insertions(+), 204 deletions(-) create mode 100644 main_config.go diff --git a/.github/.testcoverage-local.yml b/.github/.testcoverage-local.yml index 8ce01510..02326843 100644 --- a/.github/.testcoverage-local.yml +++ b/.github/.testcoverage-local.yml @@ -11,4 +11,5 @@ override: threshold: 66 exclude: paths: - - main\.go$ \ No newline at end of file + - main\.go$ + - main_config\.go$ \ No newline at end of file diff --git a/.github/.testcoverage.yml b/.github/.testcoverage.yml index a5115313..b78e2846 100644 --- a/.github/.testcoverage.yml +++ b/.github/.testcoverage.yml @@ -6,4 +6,5 @@ threshold: total: 100 exclude: paths: - - main\.go$ \ No newline at end of file + - main\.go$ + - main_config\.go$ \ No newline at end of file diff --git a/Makefile b/Makefile index 53ad7f31..9c49640e 100644 --- a/Makefile +++ b/Makefile @@ -27,7 +27,7 @@ test: # Runs test coverage check .PHONY: check-coverage check-coverage: test - go run ./main.go --config=./.github/.testcoverage-local.yml + go run ./ --config=./.github/.testcoverage-local.yml # View coverage profile .PHONY: view-coverage diff --git a/main.go b/main.go index 8c791278..dabec6a8 100644 --- a/main.go +++ b/main.go @@ -1,14 +1,11 @@ package main import ( - "errors" "fmt" "os" - "strings" - - "github.com/alexflint/go-arg" "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage" + "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/logger" ) const ( @@ -16,158 +13,6 @@ const ( Name = "go-test-coverage" ) -const ( - // default value of string variables passed by CI - ciDefaultString = `''` - // default value of int variables passed by CI - ciDefaultInt = -1 -) - -type args struct { - ConfigPath string `arg:"-c,--config"` - Profile string `arg:"-p,--profile" help:"path to coverage profile"` - Debug bool `arg:"-d,--debug"` - LocalPrefix string `arg:"-l,--local-prefix"` // deprecated - SourceDir string `arg:"-s,--source-dir"` - GithubActionOutput bool `arg:"-o,--github-action-output"` - ThresholdFile int `arg:"-f,--threshold-file"` - ThresholdPackage int `arg:"-k,--threshold-package"` - ThresholdTotal int `arg:"-t,--threshold-total"` - - BreakdownFileName string `arg:"--breakdown-file-name"` - DiffBaseBreakdownFileName string `arg:"--diff-base-breakdown-file-name"` - - BadgeFileName string `arg:"-b,--badge-file-name"` - - CDNKey string `arg:"--cdn-key"` - CDNSecret string `arg:"--cdn-secret"` - CDNRegion string `arg:"--cdn-region"` - CDNEndpoint string `arg:"--cdn-endpoint"` - CDNFileName string `arg:"--cdn-file-name"` - CDNBucketName string `arg:"--cdn-bucket-name"` - CDNForcePathStyle bool `arg:"--cdn-force-path-style"` - - GitToken string `arg:"--git-token"` - GitRepository string `arg:"--git-repository"` - GitBranch string `arg:"--git-branch"` - GitFileName string `arg:"--git-file-name"` -} - -func newArgs() args { - return args{ - ConfigPath: ciDefaultString, - Profile: ciDefaultString, - Debug: false, - LocalPrefix: ciDefaultString, - SourceDir: ciDefaultString, - GithubActionOutput: false, - ThresholdFile: ciDefaultInt, - ThresholdPackage: ciDefaultInt, - ThresholdTotal: ciDefaultInt, - - BreakdownFileName: ciDefaultString, - DiffBaseBreakdownFileName: ciDefaultString, - - // Badge - BadgeFileName: ciDefaultString, - - // CDN - CDNKey: ciDefaultString, - CDNSecret: ciDefaultString, - CDNRegion: ciDefaultString, - CDNEndpoint: ciDefaultString, - CDNFileName: ciDefaultString, - CDNBucketName: ciDefaultString, - CDNForcePathStyle: false, - - // Git - GitToken: ciDefaultString, - GitRepository: ciDefaultString, - GitBranch: ciDefaultString, - GitFileName: ciDefaultString, - } -} - -func (*args) Version() string { - return Name + " " + Version -} - -//nolint:cyclop,maintidx,mnd,funlen // relax -func (a *args) overrideConfig(cfg testcoverage.Config) (testcoverage.Config, error) { - if !isCIDefaultString(a.Profile) { - cfg.Profile = a.Profile - } - - if a.Debug { - cfg.Debug = true - } - - if a.GithubActionOutput { - cfg.GithubActionOutput = true - } - - if !isCIDefaultString(a.LocalPrefix) { - cfg.LocalPrefixDeprecated = a.LocalPrefix - } - - if !isCIDefaultString(a.SourceDir) { - cfg.SourceDir = a.SourceDir - } - - if !isCIDefaultInt(a.ThresholdFile) { - cfg.Threshold.File = a.ThresholdFile - } - - if !isCIDefaultInt(a.ThresholdPackage) { - cfg.Threshold.Package = a.ThresholdPackage - } - - if !isCIDefaultInt(a.ThresholdTotal) { - cfg.Threshold.Total = a.ThresholdTotal - } - - if !isCIDefaultString(a.BreakdownFileName) { - cfg.BreakdownFileName = a.BreakdownFileName - } - - if !isCIDefaultString(a.DiffBaseBreakdownFileName) { - cfg.Diff.BaseBreakdownFileName = a.DiffBaseBreakdownFileName - } - - if !isCIDefaultString(a.BadgeFileName) { - cfg.Badge.FileName = a.BadgeFileName - } - - if !isCIDefaultString(a.CDNSecret) { - cfg.Badge.CDN.Secret = a.CDNSecret - cfg.Badge.CDN.Key = escapeCiDefaultString(a.CDNKey) - cfg.Badge.CDN.Region = escapeCiDefaultString(a.CDNRegion) - cfg.Badge.CDN.FileName = escapeCiDefaultString(a.CDNFileName) - cfg.Badge.CDN.BucketName = escapeCiDefaultString(a.CDNBucketName) - cfg.Badge.CDN.ForcePathStyle = a.CDNForcePathStyle - - if !isCIDefaultString(a.CDNEndpoint) { - cfg.Badge.CDN.Endpoint = a.CDNEndpoint - } - } - - if !isCIDefaultString(a.GitToken) { - cfg.Badge.Git.Token = a.GitToken - cfg.Badge.Git.Branch = escapeCiDefaultString(a.GitBranch) - cfg.Badge.Git.FileName = escapeCiDefaultString(a.GitFileName) - - parts := strings.Split(escapeCiDefaultString(a.GitRepository), "/") - if len(parts) != 2 { - return cfg, errors.New("--git-repository flag should have format {owner}/{repository}") - } - - cfg.Badge.Git.Owner = parts[0] - cfg.Badge.Git.Repository = parts[1] - } - - return cfg, nil -} - //nolint:forbidigo // relax func main() { cfg, err := readConfig() @@ -176,48 +21,9 @@ func main() { os.Exit(1) } + logger.Init() pass := testcoverage.Check(os.Stdout, cfg) if !pass { os.Exit(1) } } - -func readConfig() (testcoverage.Config, error) { - cmdArgs := newArgs() - arg.MustParse(&cmdArgs) - - cfg := testcoverage.Config{} - - // Load config from file - if !isCIDefaultString(cmdArgs.ConfigPath) { - err := testcoverage.ConfigFromFile(&cfg, cmdArgs.ConfigPath) - if err != nil { - return testcoverage.Config{}, fmt.Errorf("failed loading config from file: %w", err) - } - } - - // Override config with values from args - cfg, err := cmdArgs.overrideConfig(cfg) - if err != nil { - return testcoverage.Config{}, fmt.Errorf("argument is not valid: %w", err) - } - - // Validate config - if err := cfg.Validate(); err != nil { - return testcoverage.Config{}, fmt.Errorf("config file is not valid: %w", err) - } - - return cfg, nil -} - -func isCIDefaultString(v string) bool { return v == ciDefaultString } - -func isCIDefaultInt(v int) bool { return v == ciDefaultInt } - -func escapeCiDefaultString(v string) string { - if v == ciDefaultString { - return "" - } - - return v -} diff --git a/main_config.go b/main_config.go new file mode 100644 index 00000000..3551f784 --- /dev/null +++ b/main_config.go @@ -0,0 +1,202 @@ +package main + +import ( + "errors" + "fmt" + "strings" + + "github.com/alexflint/go-arg" + "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage" +) + +const ( + // default value of string variables passed by CI + ciDefaultString = `''` + // default value of int variables passed by CI + ciDefaultInt = -1 +) + +type args struct { + ConfigPath string `arg:"-c,--config"` + Profile string `arg:"-p,--profile" help:"path to coverage profile"` + Debug bool `arg:"-d,--debug"` + LocalPrefix string `arg:"-l,--local-prefix"` // deprecated + SourceDir string `arg:"-s,--source-dir"` + GithubActionOutput bool `arg:"-o,--github-action-output"` + ThresholdFile int `arg:"-f,--threshold-file"` + ThresholdPackage int `arg:"-k,--threshold-package"` + ThresholdTotal int `arg:"-t,--threshold-total"` + + BreakdownFileName string `arg:"--breakdown-file-name"` + DiffBaseBreakdownFileName string `arg:"--diff-base-breakdown-file-name"` + + BadgeFileName string `arg:"-b,--badge-file-name"` + + CDNKey string `arg:"--cdn-key"` + CDNSecret string `arg:"--cdn-secret"` + CDNRegion string `arg:"--cdn-region"` + CDNEndpoint string `arg:"--cdn-endpoint"` + CDNFileName string `arg:"--cdn-file-name"` + CDNBucketName string `arg:"--cdn-bucket-name"` + CDNForcePathStyle bool `arg:"--cdn-force-path-style"` + + GitToken string `arg:"--git-token"` + GitRepository string `arg:"--git-repository"` + GitBranch string `arg:"--git-branch"` + GitFileName string `arg:"--git-file-name"` +} + +func newArgs() args { + return args{ + ConfigPath: ciDefaultString, + Profile: ciDefaultString, + Debug: false, + LocalPrefix: ciDefaultString, + SourceDir: ciDefaultString, + GithubActionOutput: false, + ThresholdFile: ciDefaultInt, + ThresholdPackage: ciDefaultInt, + ThresholdTotal: ciDefaultInt, + + BreakdownFileName: ciDefaultString, + DiffBaseBreakdownFileName: ciDefaultString, + + // Badge + BadgeFileName: ciDefaultString, + + // CDN + CDNKey: ciDefaultString, + CDNSecret: ciDefaultString, + CDNRegion: ciDefaultString, + CDNEndpoint: ciDefaultString, + CDNFileName: ciDefaultString, + CDNBucketName: ciDefaultString, + CDNForcePathStyle: false, + + // Git + GitToken: ciDefaultString, + GitRepository: ciDefaultString, + GitBranch: ciDefaultString, + GitFileName: ciDefaultString, + } +} + +func (*args) Version() string { + return Name + " " + Version +} + +//nolint:cyclop,maintidx,mnd,funlen // relax +func (a *args) overrideConfig(cfg testcoverage.Config) (testcoverage.Config, error) { + if !isCIDefaultString(a.Profile) { + cfg.Profile = a.Profile + } + + if a.Debug { + cfg.Debug = true + } + + if a.GithubActionOutput { + cfg.GithubActionOutput = true + } + + if !isCIDefaultString(a.LocalPrefix) { + cfg.LocalPrefixDeprecated = a.LocalPrefix + } + + if !isCIDefaultString(a.SourceDir) { + cfg.SourceDir = a.SourceDir + } + + if !isCIDefaultInt(a.ThresholdFile) { + cfg.Threshold.File = a.ThresholdFile + } + + if !isCIDefaultInt(a.ThresholdPackage) { + cfg.Threshold.Package = a.ThresholdPackage + } + + if !isCIDefaultInt(a.ThresholdTotal) { + cfg.Threshold.Total = a.ThresholdTotal + } + + if !isCIDefaultString(a.BreakdownFileName) { + cfg.BreakdownFileName = a.BreakdownFileName + } + + if !isCIDefaultString(a.DiffBaseBreakdownFileName) { + cfg.Diff.BaseBreakdownFileName = a.DiffBaseBreakdownFileName + } + + if !isCIDefaultString(a.BadgeFileName) { + cfg.Badge.FileName = a.BadgeFileName + } + + if !isCIDefaultString(a.CDNSecret) { + cfg.Badge.CDN.Secret = a.CDNSecret + cfg.Badge.CDN.Key = escapeCiDefaultString(a.CDNKey) + cfg.Badge.CDN.Region = escapeCiDefaultString(a.CDNRegion) + cfg.Badge.CDN.FileName = escapeCiDefaultString(a.CDNFileName) + cfg.Badge.CDN.BucketName = escapeCiDefaultString(a.CDNBucketName) + cfg.Badge.CDN.ForcePathStyle = a.CDNForcePathStyle + + if !isCIDefaultString(a.CDNEndpoint) { + cfg.Badge.CDN.Endpoint = a.CDNEndpoint + } + } + + if !isCIDefaultString(a.GitToken) { + cfg.Badge.Git.Token = a.GitToken + cfg.Badge.Git.Branch = escapeCiDefaultString(a.GitBranch) + cfg.Badge.Git.FileName = escapeCiDefaultString(a.GitFileName) + + parts := strings.Split(escapeCiDefaultString(a.GitRepository), "/") + if len(parts) != 2 { + return cfg, errors.New("--git-repository flag should have format {owner}/{repository}") + } + + cfg.Badge.Git.Owner = parts[0] + cfg.Badge.Git.Repository = parts[1] + } + + return cfg, nil +} + +func readConfig() (testcoverage.Config, error) { + cmdArgs := newArgs() + arg.MustParse(&cmdArgs) + + cfg := testcoverage.Config{} + + // Load config from file + if !isCIDefaultString(cmdArgs.ConfigPath) { + err := testcoverage.ConfigFromFile(&cfg, cmdArgs.ConfigPath) + if err != nil { + return testcoverage.Config{}, fmt.Errorf("failed loading config from file: %w", err) + } + } + + // Override config with values from args + cfg, err := cmdArgs.overrideConfig(cfg) + if err != nil { + return testcoverage.Config{}, fmt.Errorf("argument is not valid: %w", err) + } + + // Validate config + if err := cfg.Validate(); err != nil { + return testcoverage.Config{}, fmt.Errorf("config file is not valid: %w", err) + } + + return cfg, nil +} + +func isCIDefaultString(v string) bool { return v == ciDefaultString } + +func isCIDefaultInt(v int) bool { return v == ciDefaultInt } + +func escapeCiDefaultString(v string) string { + if v == ciDefaultString { + return "" + } + + return v +} diff --git a/pkg/testcoverage/check.go b/pkg/testcoverage/check.go index 917e234a..7083cd05 100644 --- a/pkg/testcoverage/check.go +++ b/pkg/testcoverage/check.go @@ -19,7 +19,7 @@ func Check(wout io.Writer, cfg Config) bool { //nolint:errcheck // relax defer func() { if cfg.Debug { - wout.Write(logger.Buffer.Bytes()) + wout.Write(logger.Bytes()) wout.Write([]byte("-------------------------\n\n")) } diff --git a/pkg/testcoverage/check_test.go b/pkg/testcoverage/check_test.go index 3a099a80..f6c67500 100644 --- a/pkg/testcoverage/check_test.go +++ b/pkg/testcoverage/check_test.go @@ -10,6 +10,7 @@ import ( . "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage" "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/coverage" + "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/logger" "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/path" "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/testdata" ) @@ -310,6 +311,19 @@ func TestCheckNoParallel(t *testing.T) { assertGithubOutputValues(t, testFile) assertHasUncoveredLinesInfo(t, buf.String(), []string{}) }) + + t.Run("logger has output", func(t *testing.T) { + logger.Init() + defer logger.Destruct() + + buf := &bytes.Buffer{} + cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 65}, SourceDir: sourceDir, Debug: true} + pass := Check(buf, cfg) + assert.True(t, pass) + + assert.NotEmpty(t, logger.Bytes()) + assert.Contains(t, buf.String(), string(logger.Bytes())) + }) } func Test_Analyze(t *testing.T) { diff --git a/pkg/testcoverage/logger/logger.go b/pkg/testcoverage/logger/logger.go index c070aada..03f6dc83 100644 --- a/pkg/testcoverage/logger/logger.go +++ b/pkg/testcoverage/logger/logger.go @@ -2,17 +2,30 @@ package logger import ( "bytes" + "sync" "github.com/rs/zerolog" ) //nolint:gochecknoglobals // relax var ( - Buffer bytes.Buffer + buffer bytes.Buffer + lock sync.Mutex L zerolog.Logger ) -//nolint:gochecknoinits // relax -func init() { - L = zerolog.New(&Buffer).With().Logger() +func Init() { // coverage-ignore + L = zerolog.New(&buffer).With().Logger() +} + +func Destruct() { + L = zerolog.Logger{} + buffer = bytes.Buffer{} +} + +func Bytes() []byte { + lock.Lock() + defer lock.Unlock() + + return buffer.Bytes() } From 8f6c45d2c2e1d3a47213558b861b64f5dfc2a7cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 10:53:47 +0200 Subject: [PATCH 04/11] lint fixes --- main.go | 1 + main_config.go | 1 + pkg/testcoverage/check_test.go | 9 +++++++-- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/main.go b/main.go index dabec6a8..536af2a4 100644 --- a/main.go +++ b/main.go @@ -22,6 +22,7 @@ func main() { } logger.Init() + pass := testcoverage.Check(os.Stdout, cfg) if !pass { os.Exit(1) diff --git a/main_config.go b/main_config.go index 3551f784..c1b5707d 100644 --- a/main_config.go +++ b/main_config.go @@ -6,6 +6,7 @@ import ( "strings" "github.com/alexflint/go-arg" + "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage" ) diff --git a/pkg/testcoverage/check_test.go b/pkg/testcoverage/check_test.go index f6c67500..a3bbfe55 100644 --- a/pkg/testcoverage/check_test.go +++ b/pkg/testcoverage/check_test.go @@ -254,7 +254,7 @@ func TestCheck(t *testing.T) { }) } -// must not be parallel because it uses env +//nolint:paralleltest // must not be parallel because it uses env func TestCheckNoParallel(t *testing.T) { if testing.Short() { return @@ -317,7 +317,12 @@ func TestCheckNoParallel(t *testing.T) { defer logger.Destruct() buf := &bytes.Buffer{} - cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 65}, SourceDir: sourceDir, Debug: true} + cfg := Config{ + Profile: profileOK, + Threshold: Threshold{Total: 65}, + SourceDir: sourceDir, + Debug: true, + } pass := Check(buf, cfg) assert.True(t, pass) From 126c398660c15ff478f349a6843a8faea7aaccd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 11:09:29 +0200 Subject: [PATCH 05/11] more effort --- main.go | 9 ++++-- pkg/testcoverage/check.go | 26 ++++++++-------- pkg/testcoverage/check_test.go | 54 +++++++++++++++++++++------------- 3 files changed, 53 insertions(+), 36 deletions(-) diff --git a/main.go b/main.go index 536af2a4..9b5c17c2 100644 --- a/main.go +++ b/main.go @@ -13,7 +13,7 @@ const ( Name = "go-test-coverage" ) -//nolint:forbidigo // relax +//nolint:forbidigo,wsl // relax func main() { cfg, err := readConfig() if err != nil { @@ -23,8 +23,11 @@ func main() { logger.Init() - pass := testcoverage.Check(os.Stdout, cfg) - if !pass { + pass, haderr := testcoverage.Check(os.Stdout, cfg) + if haderr { + fmt.Println("\nRunning coverage check failed. Please use --debug=true flag to see detailed output.") + } + if !pass || haderr { os.Exit(1) } } diff --git a/pkg/testcoverage/check.go b/pkg/testcoverage/check.go index 7083cd05..54b87d0b 100644 --- a/pkg/testcoverage/check.go +++ b/pkg/testcoverage/check.go @@ -12,8 +12,8 @@ import ( "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/logger" ) -//nolint:maintidx // relax -func Check(wout io.Writer, cfg Config) bool { +//nolint:maintidx, nonamedreturns // relax +func Check(wout io.Writer, cfg Config) (passed bool, haderr bool) { buffer := &bytes.Buffer{} w := bufio.NewWriter(buffer) //nolint:errcheck // relax @@ -32,20 +32,20 @@ func Check(wout io.Writer, cfg Config) bool { currentStats, err := GenerateCoverageStats(cfg) if err != nil { - fmt.Fprintf(w, "failed to generate coverage statistics: %v\n", err) - return false + logger.L.Error().Err(err).Msg("failed to generate coverage statistics") + return false, true } err = saveCoverageBreakdown(cfg, currentStats) if err != nil { - fmt.Fprintf(w, "failed to save coverage breakdown: %v\n", err) - return false + logger.L.Error().Err(err).Msg("failed to save coverage breakdown") + return false, true } baseStats, err := loadBaseCoverageBreakdown(cfg) if err != nil { - fmt.Fprintf(w, "failed to load base coverage breakdown: %v\n", err) - return false + logger.L.Error().Err(err).Msg("failed to load base coverage breakdown") + return false, true } result := Analyze(cfg, currentStats, baseStats) @@ -57,8 +57,8 @@ func Check(wout io.Writer, cfg Config) bool { err = SetGithubActionOutput(result, report) if err != nil { - fmt.Fprintf(w, "failed setting github action output: %v\n", err) - return false + logger.L.Error().Err(err).Msg("failed setting github action output") + return false, true } if cfg.LocalPrefixDeprecated != "" { // coverage-ignore @@ -69,11 +69,11 @@ func Check(wout io.Writer, cfg Config) bool { err = generateAndSaveBadge(w, cfg, result.TotalStats.CoveredPercentage()) if err != nil { - fmt.Fprintf(w, "failed to generate and save badge: %v\n", err) - return false + logger.L.Error().Err(err).Msg("failed to generate and save badge") + return false, true } - return result.Pass() + return result.Pass(), false } func reportForHuman(w io.Writer, result AnalyzeResult) string { diff --git a/pkg/testcoverage/check_test.go b/pkg/testcoverage/check_test.go index a3bbfe55..585748fe 100644 --- a/pkg/testcoverage/check_test.go +++ b/pkg/testcoverage/check_test.go @@ -37,8 +37,9 @@ func TestCheck(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} - pass := Check(buf, Config{}) + pass, haderr := Check(buf, Config{}) assert.False(t, pass) + assert.True(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 0) assertNoUncoveredLinesInfo(t, buf.String()) @@ -49,8 +50,9 @@ func TestCheck(t *testing.T) { buf := &bytes.Buffer{} cfg := Config{Profile: profileNOK, Threshold: Threshold{Total: 65}} - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) + assert.True(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 0) assertNoUncoveredLinesInfo(t, buf.String()) @@ -61,8 +63,9 @@ func TestCheck(t *testing.T) { buf := &bytes.Buffer{} cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 65}, SourceDir: sourceDir} - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.True(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertNoFileNames(t, buf.String(), prefix) @@ -81,8 +84,9 @@ func TestCheck(t *testing.T) { }, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.True(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertNoUncoveredLinesInfo(t, buf.String()) @@ -93,8 +97,9 @@ func TestCheck(t *testing.T) { buf := &bytes.Buffer{} cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 100}, SourceDir: sourceDir} - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 1) assertHasUncoveredLinesInfo(t, buf.String(), []string{ @@ -115,8 +120,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 10, Path: "^pkg"}}, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.True(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 2, 0) assertNoFileNames(t, buf.String(), prefix) @@ -133,8 +139,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 100, Path: "^pkg"}}, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 2) assertHasUncoveredLinesInfo(t, buf.String(), []string{ @@ -155,8 +162,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 60, Path: "pkg/testcoverage/badgestorer/github.go"}}, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.True(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertNoFileNames(t, buf.String(), prefix) @@ -173,8 +181,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 80, Path: "pkg/testcoverage/badgestorer/github.go"}}, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 1) assert.GreaterOrEqual(t, strings.Count(buf.String(), prefix), 0) @@ -197,9 +206,9 @@ func TestCheck(t *testing.T) { }, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) - assertFailedToSaveBadge(t, buf.String()) + assert.True(t, haderr) }) t.Run("valid profile - fail invalid breakdown file", func(t *testing.T) { @@ -211,9 +220,9 @@ func TestCheck(t *testing.T) { BreakdownFileName: t.TempDir(), // should failed because this is dir SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) - assert.Contains(t, buf.String(), "failed to save coverage breakdown") + assert.True(t, haderr) }) t.Run("valid profile - valid breakdown file", func(t *testing.T) { @@ -225,8 +234,9 @@ func TestCheck(t *testing.T) { BreakdownFileName: t.TempDir() + "/breakdown.testcoverage", SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.True(t, pass) + assert.False(t, haderr) contentBytes, err := os.ReadFile(cfg.BreakdownFileName) assert.NoError(t, err) @@ -248,9 +258,9 @@ func TestCheck(t *testing.T) { }, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) - assert.Contains(t, buf.String(), "failed to load base coverage breakdown") + assert.True(t, haderr) }) } @@ -270,8 +280,9 @@ func TestCheckNoParallel(t *testing.T) { Threshold: Threshold{Total: 100}, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) + assert.True(t, haderr) }) t.Run("ok pass; with github output file", func(t *testing.T) { @@ -285,8 +296,9 @@ func TestCheckNoParallel(t *testing.T) { Threshold: Threshold{Total: 10}, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.True(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertGithubOutputValues(t, testFile) @@ -304,8 +316,9 @@ func TestCheckNoParallel(t *testing.T) { Threshold: Threshold{Total: 100}, SourceDir: sourceDir, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.False(t, pass) + assert.False(t, haderr) assertGithubActionErrorsCount(t, buf.String(), 1) assertHumanReport(t, buf.String(), 0, 1) assertGithubOutputValues(t, testFile) @@ -323,8 +336,9 @@ func TestCheckNoParallel(t *testing.T) { SourceDir: sourceDir, Debug: true, } - pass := Check(buf, cfg) + pass, haderr := Check(buf, cfg) assert.True(t, pass) + assert.False(t, haderr) assert.NotEmpty(t, logger.Bytes()) assert.Contains(t, buf.String(), string(logger.Bytes())) From df96061ef33cc13f849bd555ef3800ba5b8b959d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 11:18:31 +0200 Subject: [PATCH 06/11] message update --- main.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/main.go b/main.go index 9b5c17c2..2e66f5ff 100644 --- a/main.go +++ b/main.go @@ -25,7 +25,12 @@ func main() { pass, haderr := testcoverage.Check(os.Stdout, cfg) if haderr { - fmt.Println("\nRunning coverage check failed. Please use --debug=true flag to see detailed output.") + fmt.Println("Running coverage check failed.") + if cfg.GithubActionOutput { + fmt.Printf("Please set `debug: true` input to see detailed output.") + } else { + fmt.Println("Please use `--debug=true` flag to see detailed output.") + } } if !pass || haderr { os.Exit(1) From 16982fc7be08d797bccda4bdb39cbee20dd686af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 11:20:22 +0200 Subject: [PATCH 07/11] update --- pkg/testcoverage/logger/logger.go | 5 ----- 1 file changed, 5 deletions(-) diff --git a/pkg/testcoverage/logger/logger.go b/pkg/testcoverage/logger/logger.go index 03f6dc83..5d14e872 100644 --- a/pkg/testcoverage/logger/logger.go +++ b/pkg/testcoverage/logger/logger.go @@ -2,7 +2,6 @@ package logger import ( "bytes" - "sync" "github.com/rs/zerolog" ) @@ -10,7 +9,6 @@ import ( //nolint:gochecknoglobals // relax var ( buffer bytes.Buffer - lock sync.Mutex L zerolog.Logger ) @@ -24,8 +22,5 @@ func Destruct() { } func Bytes() []byte { - lock.Lock() - defer lock.Unlock() - return buffer.Bytes() } From eefde5c4db6dd6541a3882304dcf6d2688479cbe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 11:23:51 +0200 Subject: [PATCH 08/11] lint fix --- pkg/testcoverage/helpers_test.go | 6 ------ 1 file changed, 6 deletions(-) diff --git a/pkg/testcoverage/helpers_test.go b/pkg/testcoverage/helpers_test.go index 2d50c25d..206682a1 100644 --- a/pkg/testcoverage/helpers_test.go +++ b/pkg/testcoverage/helpers_test.go @@ -195,12 +195,6 @@ func assertGithubActionErrorsCount(t *testing.T, content string, count int) { assert.Equal(t, count, strings.Count(content, "::error")) } -func assertFailedToSaveBadge(t *testing.T, content string) { - t.Helper() - - assert.Contains(t, content, "failed to generate and save badge") -} - func assertPrefix(t *testing.T, result AnalyzeResult, prefix string, has bool) { t.Helper() From 1e96d0b58528a9654e960a2525707b5e2447032b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 11:26:44 +0200 Subject: [PATCH 09/11] add action test --- .github/workflows/action-test.yml | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/workflows/action-test.yml b/.github/workflows/action-test.yml index e1055379..3ee892df 100644 --- a/.github/workflows/action-test.yml +++ b/.github/workflows/action-test.yml @@ -125,4 +125,22 @@ jobs: config: ./.github/workflows/testdata/total100.yml threshold-file: 0 threshold-package: 0 - threshold-total: 0 \ No newline at end of file + threshold-total: 0 + + ## Test 6 + + - name: "test: debug output" + uses: ./ + id: test-6 + continue-on-error: true + with: + profile: unexistant-profile.out + debug: true + threshold-file: 0 + threshold-package: 0 + threshold-total: 100 + + - name: "check: test should have failed" + if: steps.test-4.outcome != 'failure' + shell: bash + run: echo "Previous step should have failed" && exit 1 \ No newline at end of file From 5da23cd0e4a0f0005ff1fbf0d4c11bcbe1ac0770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 11:40:57 +0200 Subject: [PATCH 10/11] more effort --- main.go | 6 +-- pkg/testcoverage/check.go | 26 ++++++------- pkg/testcoverage/check_test.go | 71 ++++++++++++++++++---------------- 3 files changed, 53 insertions(+), 50 deletions(-) diff --git a/main.go b/main.go index 2e66f5ff..8ce8f3b3 100644 --- a/main.go +++ b/main.go @@ -23,8 +23,8 @@ func main() { logger.Init() - pass, haderr := testcoverage.Check(os.Stdout, cfg) - if haderr { + pass, err := testcoverage.Check(os.Stdout, cfg) + if err != nil { fmt.Println("Running coverage check failed.") if cfg.GithubActionOutput { fmt.Printf("Please set `debug: true` input to see detailed output.") @@ -32,7 +32,7 @@ func main() { fmt.Println("Please use `--debug=true` flag to see detailed output.") } } - if !pass || haderr { + if !pass || err != nil { os.Exit(1) } } diff --git a/pkg/testcoverage/check.go b/pkg/testcoverage/check.go index 54b87d0b..dd3b6691 100644 --- a/pkg/testcoverage/check.go +++ b/pkg/testcoverage/check.go @@ -12,8 +12,8 @@ import ( "github.com/vladopajic/go-test-coverage/v2/pkg/testcoverage/logger" ) -//nolint:maintidx, nonamedreturns // relax -func Check(wout io.Writer, cfg Config) (passed bool, haderr bool) { +//nolint:maintidx // relax +func Check(wout io.Writer, cfg Config) (bool, error) { buffer := &bytes.Buffer{} w := bufio.NewWriter(buffer) //nolint:errcheck // relax @@ -27,25 +27,27 @@ func Check(wout io.Writer, cfg Config) (passed bool, haderr bool) { wout.Write(buffer.Bytes()) }() + handleErr := func(err error, msg string) (bool, error) { + logger.L.Error().Err(err).Msg(msg) + return false, fmt.Errorf("%s: %w", msg, err) + } + logger.L.Debug().Msg("running check...") logger.L.Debug().Any("config", cfg).Msg("using configuration") currentStats, err := GenerateCoverageStats(cfg) if err != nil { - logger.L.Error().Err(err).Msg("failed to generate coverage statistics") - return false, true + return handleErr(err, "failed to generate coverage statistics") } err = saveCoverageBreakdown(cfg, currentStats) if err != nil { - logger.L.Error().Err(err).Msg("failed to save coverage breakdown") - return false, true + return handleErr(err, "failed to save coverage breakdown") } baseStats, err := loadBaseCoverageBreakdown(cfg) if err != nil { - logger.L.Error().Err(err).Msg("failed to load base coverage breakdown") - return false, true + return handleErr(err, "failed to load base coverage breakdown") } result := Analyze(cfg, currentStats, baseStats) @@ -57,8 +59,7 @@ func Check(wout io.Writer, cfg Config) (passed bool, haderr bool) { err = SetGithubActionOutput(result, report) if err != nil { - logger.L.Error().Err(err).Msg("failed setting github action output") - return false, true + return handleErr(err, "failed setting github action output") } if cfg.LocalPrefixDeprecated != "" { // coverage-ignore @@ -69,11 +70,10 @@ func Check(wout io.Writer, cfg Config) (passed bool, haderr bool) { err = generateAndSaveBadge(w, cfg, result.TotalStats.CoveredPercentage()) if err != nil { - logger.L.Error().Err(err).Msg("failed to generate and save badge") - return false, true + return handleErr(err, "failed to generate and save badge") } - return result.Pass(), false + return result.Pass(), nil } func reportForHuman(w io.Writer, result AnalyzeResult) string { diff --git a/pkg/testcoverage/check_test.go b/pkg/testcoverage/check_test.go index 585748fe..1d39758c 100644 --- a/pkg/testcoverage/check_test.go +++ b/pkg/testcoverage/check_test.go @@ -37,9 +37,9 @@ func TestCheck(t *testing.T) { t.Parallel() buf := &bytes.Buffer{} - pass, haderr := Check(buf, Config{}) + pass, err := Check(buf, Config{}) assert.False(t, pass) - assert.True(t, haderr) + assert.Error(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 0) assertNoUncoveredLinesInfo(t, buf.String()) @@ -50,9 +50,9 @@ func TestCheck(t *testing.T) { buf := &bytes.Buffer{} cfg := Config{Profile: profileNOK, Threshold: Threshold{Total: 65}} - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.True(t, haderr) + assert.Error(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 0) assertNoUncoveredLinesInfo(t, buf.String()) @@ -63,9 +63,9 @@ func TestCheck(t *testing.T) { buf := &bytes.Buffer{} cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 65}, SourceDir: sourceDir} - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.True(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertNoFileNames(t, buf.String(), prefix) @@ -84,9 +84,9 @@ func TestCheck(t *testing.T) { }, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.True(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertNoUncoveredLinesInfo(t, buf.String()) @@ -97,9 +97,9 @@ func TestCheck(t *testing.T) { buf := &bytes.Buffer{} cfg := Config{Profile: profileOK, Threshold: Threshold{Total: 100}, SourceDir: sourceDir} - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 1) assertHasUncoveredLinesInfo(t, buf.String(), []string{ @@ -120,9 +120,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 10, Path: "^pkg"}}, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.True(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 2, 0) assertNoFileNames(t, buf.String(), prefix) @@ -139,9 +139,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 100, Path: "^pkg"}}, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 2) assertHasUncoveredLinesInfo(t, buf.String(), []string{ @@ -162,9 +162,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 60, Path: "pkg/testcoverage/badgestorer/github.go"}}, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.True(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertNoFileNames(t, buf.String(), prefix) @@ -181,9 +181,9 @@ func TestCheck(t *testing.T) { Override: []Override{{Threshold: 80, Path: "pkg/testcoverage/badgestorer/github.go"}}, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 0, 1) assert.GreaterOrEqual(t, strings.Count(buf.String(), prefix), 0) @@ -206,9 +206,10 @@ func TestCheck(t *testing.T) { }, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.True(t, haderr) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to generate and save badge") }) t.Run("valid profile - fail invalid breakdown file", func(t *testing.T) { @@ -220,9 +221,10 @@ func TestCheck(t *testing.T) { BreakdownFileName: t.TempDir(), // should failed because this is dir SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.True(t, haderr) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to save coverage breakdown") }) t.Run("valid profile - valid breakdown file", func(t *testing.T) { @@ -234,9 +236,9 @@ func TestCheck(t *testing.T) { BreakdownFileName: t.TempDir() + "/breakdown.testcoverage", SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.True(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) contentBytes, err := os.ReadFile(cfg.BreakdownFileName) assert.NoError(t, err) @@ -258,9 +260,10 @@ func TestCheck(t *testing.T) { }, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.True(t, haderr) + assert.Error(t, err) + assert.Contains(t, err.Error(), "failed to load base coverage breakdown") }) } @@ -280,9 +283,9 @@ func TestCheckNoParallel(t *testing.T) { Threshold: Threshold{Total: 100}, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.True(t, haderr) + assert.Error(t, err) }) t.Run("ok pass; with github output file", func(t *testing.T) { @@ -296,9 +299,9 @@ func TestCheckNoParallel(t *testing.T) { Threshold: Threshold{Total: 10}, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.True(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 0) assertHumanReport(t, buf.String(), 1, 0) assertGithubOutputValues(t, testFile) @@ -316,9 +319,9 @@ func TestCheckNoParallel(t *testing.T) { Threshold: Threshold{Total: 100}, SourceDir: sourceDir, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.False(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assertGithubActionErrorsCount(t, buf.String(), 1) assertHumanReport(t, buf.String(), 0, 1) assertGithubOutputValues(t, testFile) @@ -336,9 +339,9 @@ func TestCheckNoParallel(t *testing.T) { SourceDir: sourceDir, Debug: true, } - pass, haderr := Check(buf, cfg) + pass, err := Check(buf, cfg) assert.True(t, pass) - assert.False(t, haderr) + assert.NoError(t, err) assert.NotEmpty(t, logger.Bytes()) assert.Contains(t, buf.String(), string(logger.Bytes())) From b4931c6fc43a6a22139b434ad27580057a580b2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vlado=20Paji=C4=87?= Date: Fri, 18 Apr 2025 11:49:32 +0200 Subject: [PATCH 11/11] update log level --- pkg/testcoverage/check.go | 4 ++-- pkg/testcoverage/coverage/module.go | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pkg/testcoverage/check.go b/pkg/testcoverage/check.go index dd3b6691..be018858 100644 --- a/pkg/testcoverage/check.go +++ b/pkg/testcoverage/check.go @@ -32,8 +32,8 @@ func Check(wout io.Writer, cfg Config) (bool, error) { return false, fmt.Errorf("%s: %w", msg, err) } - logger.L.Debug().Msg("running check...") - logger.L.Debug().Any("config", cfg).Msg("using configuration") + logger.L.Info().Msg("running check...") + logger.L.Info().Any("config", cfg).Msg("using configuration") currentStats, err := GenerateCoverageStats(cfg) if err != nil { diff --git a/pkg/testcoverage/coverage/module.go b/pkg/testcoverage/coverage/module.go index b0817a56..a27158bc 100644 --- a/pkg/testcoverage/coverage/module.go +++ b/pkg/testcoverage/coverage/module.go @@ -12,13 +12,13 @@ import ( func findModuleDirective(rootDir string) string { goModFile := findGoModFile(rootDir) if goModFile == "" { - logger.L.Debug().Str("dir", rootDir).Msg("could not find go.mod file in root dir") + logger.L.Warn().Str("dir", rootDir).Msg("could not find go.mod file in root dir") return "" } module := readModuleDirective(goModFile) if module == "" { // coverage-ignore - logger.L.Debug().Msg("`module` directive not found") + logger.L.Warn().Msg("`module` directive not found") } return module