From b823ec5016f3211c55b1e77244e5ef01dba693c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 22 Sep 2023 18:53:59 +0200 Subject: [PATCH 1/2] Remove deps from go.mod for knative.dev/hack --- cmd/script/main.go | 7 +- cmd/script/main_test.go | 22 +- embed.go | 4 +- embed_test.go | 4 +- go.mod | 20 -- go.sum | 44 ---- pkg/constraints/types.go | 48 +++++ pkg/inflator/cli/app.go | 66 +++--- pkg/inflator/cli/app_test.go | 19 +- pkg/inflator/cli/exec.go | 51 +++++ pkg/inflator/cli/flags.go | 25 ++- pkg/inflator/cli/print.go | 33 +++ pkg/inflator/extract/errors.go | 5 +- pkg/inflator/extract/extract.go | 7 +- pkg/inflator/extract/extract_test.go | 4 +- pkg/retcode/retcode.go | 21 ++ pkg/utest/assert/contain.go | 41 ++++ pkg/utest/assert/empty.go | 52 +++++ pkg/utest/assert/equal.go | 43 ++++ pkg/utest/assert/error.go | 55 +++++ pkg/utest/assert/format.go | 153 +++++++++++++ pkg/utest/assert/testingt.go | 10 + pkg/utest/require/error.go | 19 ++ pkg/utest/require/testingt.go | 13 ++ .../github.com/pkg/errors/LICENSE | 23 -- .../github.com/spf13/cobra/LICENSE.txt | 174 --------------- .../github.com/spf13/pflag/LICENSE | 28 --- .../wavesoftware/go-commandline/LICENSE | 201 ------------------ .../wavesoftware/go-retcode/LICENSE | 201 ------------------ 29 files changed, 639 insertions(+), 754 deletions(-) create mode 100644 pkg/constraints/types.go create mode 100644 pkg/inflator/cli/exec.go create mode 100644 pkg/inflator/cli/print.go create mode 100644 pkg/retcode/retcode.go create mode 100644 pkg/utest/assert/contain.go create mode 100644 pkg/utest/assert/empty.go create mode 100644 pkg/utest/assert/equal.go create mode 100644 pkg/utest/assert/error.go create mode 100644 pkg/utest/assert/format.go create mode 100644 pkg/utest/assert/testingt.go create mode 100644 pkg/utest/require/error.go create mode 100644 pkg/utest/require/testingt.go delete mode 100644 third_party/VENDOR-LICENSE/github.com/pkg/errors/LICENSE delete mode 100644 third_party/VENDOR-LICENSE/github.com/spf13/cobra/LICENSE.txt delete mode 100644 third_party/VENDOR-LICENSE/github.com/spf13/pflag/LICENSE delete mode 100644 third_party/VENDOR-LICENSE/github.com/wavesoftware/go-commandline/LICENSE delete mode 100644 third_party/VENDOR-LICENSE/github.com/wavesoftware/go-retcode/LICENSE diff --git a/cmd/script/main.go b/cmd/script/main.go index c80d3490..288e1071 100644 --- a/cmd/script/main.go +++ b/cmd/script/main.go @@ -16,13 +16,10 @@ limitations under the License. package main -import ( - "github.com/wavesoftware/go-commandline" - "knative.dev/hack/pkg/inflator/cli" -) +import "knative.dev/hack/pkg/inflator/cli" func main() { - commandline.New(new(cli.App)).ExecuteOrDie(cli.Options...) + cli.ExecuteOrDie(cli.Options...) } // RunMain is used by tests to run the main function. diff --git a/cmd/script/main_test.go b/cmd/script/main_test.go index 599accec..d2991fd2 100644 --- a/cmd/script/main_test.go +++ b/cmd/script/main_test.go @@ -20,10 +20,9 @@ import ( "bytes" "testing" - "github.com/stretchr/testify/assert" - "github.com/wavesoftware/go-commandline" main "knative.dev/hack/cmd/script" "knative.dev/hack/pkg/inflator/cli" + "knative.dev/hack/pkg/utest/assert" ) func TestMainFn(t *testing.T) { @@ -33,20 +32,23 @@ func TestMainFn(t *testing.T) { func() { main.RunMain() }, - commandline.WithArgs("--help"), - commandline.WithOutput(&buf), - commandline.WithExit(func(c int) { - retcode = &c - }), + func(ex *cli.Execution) { + ex.Stdout = &buf + ex.Stderr = &buf + ex.Args = []string{"--help"} + ex.Exit = func(c int) { + retcode = &c + } + }, ) assert.Nil(t, retcode) - assert.Contains(t, buf.String(), "Script will extract Hack scripts") + assert.ContainsSubstring(t, buf.String(), "Script will extract Hack scripts") } -func withOptions(fn func(), options ...commandline.Option) { +func withOptions(fn func(), options ...cli.Option) { prev := cli.Options cli.Options = options - defer func(p []commandline.Option) { + defer func(p []cli.Option) { cli.Options = p }(prev) fn() diff --git a/embed.go b/embed.go index 4e39c21a..62f856ec 100644 --- a/embed.go +++ b/embed.go @@ -16,7 +16,9 @@ limitations under the License. package hack -import "embed" +import ( + "embed" +) //go:embed *.sh var Scripts embed.FS diff --git a/embed_test.go b/embed_test.go index 9d305d87..51ff148c 100644 --- a/embed_test.go +++ b/embed_test.go @@ -19,9 +19,9 @@ package hack_test import ( "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "knative.dev/hack" + "knative.dev/hack/pkg/utest/assert" + "knative.dev/hack/pkg/utest/require" ) func TestScriptsAreEmbedded(t *testing.T) { diff --git a/go.mod b/go.mod index fb7e406a..c3481aba 100644 --- a/go.mod +++ b/go.mod @@ -1,23 +1,3 @@ module knative.dev/hack go 1.18 - -require ( - github.com/pkg/errors v0.9.1 - github.com/spf13/cobra v1.5.0 - github.com/stretchr/testify v1.8.1 - github.com/wavesoftware/go-commandline v1.0.0 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/google/go-cmp v0.5.6 // indirect - github.com/inconshreveable/mousetrap v1.0.0 // indirect - github.com/kr/text v0.2.0 // indirect - github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/spf13/pflag v1.0.5 // indirect - github.com/wavesoftware/go-retcode v1.0.0 // indirect - gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect - gopkg.in/yaml.v3 v3.0.1 // indirect -) diff --git a/go.sum b/go.sum index e207138d..e69de29b 100644 --- a/go.sum +++ b/go.sum @@ -1,44 +0,0 @@ -github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= -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/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= -github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -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/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU= -github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM= -github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/wavesoftware/go-commandline v1.0.0 h1:n7nrFr1unfiUcF7shA1rYf+YhXB12pY8uNYqPgFsHio= -github.com/wavesoftware/go-commandline v1.0.0/go.mod h1:C9yRtwZxJSck99kk6SRRkOtC2ppQF/KDRy0yrzWJuHU= -github.com/wavesoftware/go-retcode v1.0.0 h1:Z53+VpIHMvRMtjS6jPScdihbAN1ks3lIJ5Mj32gCpno= -github.com/wavesoftware/go-retcode v1.0.0/go.mod h1:BLqIIXhB/PQ+izkkRGfSQgu95BDtMmUBuvTJ/gkSWVM= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo= diff --git a/pkg/constraints/types.go b/pkg/constraints/types.go new file mode 100644 index 00000000..e01d665a --- /dev/null +++ b/pkg/constraints/types.go @@ -0,0 +1,48 @@ +// See: https://cs.opensource.google/go/x/exp/+/92128663:constraints/constraints.go + +// Package constraints defines a set of useful constraints to be used +// with type parameters. +package constraints + +// Signed is a constraint that permits any signed integer type. +// If future releases of Go add new predeclared signed integer types, +// this constraint will be modified to include them. +type Signed interface { + ~int | ~int8 | ~int16 | ~int32 | ~int64 +} + +// Unsigned is a constraint that permits any unsigned integer type. +// If future releases of Go add new predeclared unsigned integer types, +// this constraint will be modified to include them. +type Unsigned interface { + ~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr +} + +// Integer is a constraint that permits any integer type. +// If future releases of Go add new predeclared integer types, +// this constraint will be modified to include them. +type Integer interface { + Signed | Unsigned +} + +// Float is a constraint that permits any floating-point type. +// If future releases of Go add new predeclared floating-point types, +// this constraint will be modified to include them. +type Float interface { + ~float32 | ~float64 +} + +// Complex is a constraint that permits any complex numeric type. +// If future releases of Go add new predeclared complex numeric types, +// this constraint will be modified to include them. +type Complex interface { + ~complex64 | ~complex128 +} + +// Ordered is a constraint that permits any ordered type: any type +// that supports the operators < <= >= >. +// If future releases of Go add new ordered types, +// this constraint will be modified to include them. +type Ordered interface { + Integer | Float | ~string +} diff --git a/pkg/inflator/cli/app.go b/pkg/inflator/cli/app.go index 5a5cfeb4..7c12d95e 100644 --- a/pkg/inflator/cli/app.go +++ b/pkg/inflator/cli/app.go @@ -1,37 +1,55 @@ package cli import ( - "os" + "fmt" - "github.com/spf13/cobra" - "github.com/wavesoftware/go-commandline" "knative.dev/hack/pkg/inflator/extract" + "knative.dev/hack/pkg/retcode" ) -// Options to override the commandline for testing purposes. -var Options []commandline.Option //nolint:gochecknoglobals +// Execute will execute the application. +func Execute(opts []Option) Result { + ex := Execution{}.Default().Configure(opts) + fl, err := parseArgs(&ex) + if err != nil { + return Result{ + Execution: ex, + Err: err, + } + } + op := createOperation(fl, ex.Args) + return Result{ + Execution: ex, + Err: op.Extract(ex), + } +} + +// ExecuteOrDie will execute the application or perform os.Exit in case of error. +func ExecuteOrDie(opts ...Option) { + if r := Execute(opts); r.Err != nil { + r.PrintErrln(fmt.Sprintf("%v", r.Err)) + r.Exit(retcode.Calc(r.Err)) + } +} -type App struct{} +type usageErr struct{} + +func (u usageErr) Error() string { + return `Hacks as Go self-extracting binary + +Will extract Hack scripts to a temporary directory, and provide a source +file path to requested shell script. -func (a App) Command() *cobra.Command { - fl := &flags{} - c := &cobra.Command{ - Use: "script library.sh", - Short: "Script is a tool for running Hack scripts", - Long: "Script will extract Hack scripts to a temporary directory, " + - "and provide a source file path to requested script", - Example: ` # In Bash script -source "$(go run knative.dev/hack/cmd/script@latest library.sh)"`, - SilenceUsage: true, - Args: cobra.ExactArgs(1), - RunE: func(cmd *cobra.Command, argv []string) error { - op := createOperation(fl, argv) - return op.Extract(cmd) - }, - } - c.SetOut(os.Stdout) - return fl.withFlags(c) +source "$(go run knative.dev/hack/cmd/script@latest library.sh)" + +Usage: + script [flags] library.sh + +Flags: + -h, --help help + -v, --verbose verbose output +` } func createOperation(fl *flags, argv []string) extract.Operation { diff --git a/pkg/inflator/cli/app_test.go b/pkg/inflator/cli/app_test.go index 62686246..297eed47 100644 --- a/pkg/inflator/cli/app_test.go +++ b/pkg/inflator/cli/app_test.go @@ -4,27 +4,28 @@ import ( "bytes" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "knative.dev/hack/pkg/inflator/cli" "knative.dev/hack/pkg/inflator/extract" + "knative.dev/hack/pkg/utest/assert" + "knative.dev/hack/pkg/utest/require" ) -func TestApp(t *testing.T) { +func TestExecute(t *testing.T) { tmpdir := t.TempDir() t.Setenv(extract.HackScriptsDirEnvVar, tmpdir) t.Setenv(cli.ManualVerboseEnvVar, "true") - c := cli.App{}.Command() var ( outb bytes.Buffer errb bytes.Buffer ) - c.SetOut(&outb) - c.SetErr(&errb) - c.SetArgs([]string{"e2e-tests.sh"}) - err := c.Execute() - require.NoError(t, err) + r := cli.Execute([]cli.Option{func(ex *cli.Execution) { + ex.Args = []string{"e2e-tests.sh"} + ex.Stdout = &outb + ex.Stderr = &errb + }}) + + require.NoError(t, r.Err) assert.Equal(t, outb.String(), tmpdir+"/e2e-tests.sh\n") assert.Equal(t, errb.String(), "") } diff --git a/pkg/inflator/cli/exec.go b/pkg/inflator/cli/exec.go new file mode 100644 index 00000000..3f3617b2 --- /dev/null +++ b/pkg/inflator/cli/exec.go @@ -0,0 +1,51 @@ +package cli + +import ( + "io" + "os" +) + +// Execution is used to execute a command. +type Execution struct { + Args []string + Stdout io.Writer + Stderr io.Writer + Exit func(code int) +} + +// Default will set default values for the execution. +func (e Execution) Default() Execution { + if e.Stdout == nil { + e.Stdout = os.Stdout + } + if e.Stderr == nil { + e.Stderr = os.Stderr + } + if e.Exit == nil { + e.Exit = os.Exit + } + if len(e.Args) == 0 { + e.Args = os.Args[1:] + } + return e +} + +// Configure will configure the execution. +func (e Execution) Configure(opts []Option) Execution { + for _, opt := range opts { + opt(&e) + } + return e +} + +// Option is used to configure an App. +type Option func(*Execution) + +// Options to override the commandline for testing purposes. +var Options []Option //nolint:gochecknoglobals + +// Result is a result of execution. +type Result struct { + Execution + Err error +} diff --git a/pkg/inflator/cli/flags.go b/pkg/inflator/cli/flags.go index ce49e7e9..3e933181 100644 --- a/pkg/inflator/cli/flags.go +++ b/pkg/inflator/cli/flags.go @@ -3,8 +3,6 @@ package cli import ( "os" "strings" - - "github.com/spf13/cobra" ) const ( @@ -17,10 +15,25 @@ type flags struct { verbose bool } -func (f *flags) withFlags(c *cobra.Command) *cobra.Command { - fl := c.PersistentFlags() - fl.BoolVarP(&f.verbose, "verbose", "v", isCiServer(), "Print verbose output on Stderr") - return c +func parseArgs(ex *Execution) (*flags, error) { + f := flags{ + verbose: isCiServer(), + } + if len(ex.Args) == 0 { + return nil, usageErr{} + } + for i := 0; i < len(ex.Args); i++ { + if ex.Args[i] == "-v" || ex.Args[i] == "--verbose" { + f.verbose = true + ex.Args = append(ex.Args[:i], ex.Args[i+1:]...) + i-- + } + + if ex.Args[i] == "-h" || ex.Args[i] == "--help" { + return nil, usageErr{} + } + } + return &f, nil } func isCiServer() bool { diff --git a/pkg/inflator/cli/print.go b/pkg/inflator/cli/print.go new file mode 100644 index 00000000..ca734572 --- /dev/null +++ b/pkg/inflator/cli/print.go @@ -0,0 +1,33 @@ +package cli + +import "fmt" + +// Print is a convenience method to Print to the defined output, fallback to Stderr if not set. +func (e Execution) Print(i ...interface{}) { + fmt.Fprint(e.Stdout, i...) +} + +// Println is a convenience method to Println to the defined output, fallback to Stderr if not set. +func (e Execution) Println(i ...interface{}) { + e.Print(fmt.Sprintln(i...)) +} + +// Printf is a convenience method to Printf to the defined output, fallback to Stderr if not set. +func (e Execution) Printf(format string, i ...interface{}) { + e.Print(fmt.Sprintf(format, i...)) +} + +// PrintErr is a convenience method to Print to the defined Err output, fallback to Stderr if not set. +func (e Execution) PrintErr(i ...interface{}) { + fmt.Fprint(e.Stderr, i...) +} + +// PrintErrln is a convenience method to Println to the defined Err output, fallback to Stderr if not set. +func (e Execution) PrintErrln(i ...interface{}) { + e.PrintErr(fmt.Sprintln(i...)) +} + +// PrintErrf is a convenience method to Printf to the defined Err output, fallback to Stderr if not set. +func (e Execution) PrintErrf(format string, i ...interface{}) { + e.PrintErr(fmt.Sprintf(format, i...)) +} diff --git a/pkg/inflator/extract/errors.go b/pkg/inflator/extract/errors.go index 0d09d7a5..f6583458 100644 --- a/pkg/inflator/extract/errors.go +++ b/pkg/inflator/extract/errors.go @@ -1,9 +1,8 @@ package extract import ( + "errors" "fmt" - - "github.com/pkg/errors" ) var ( @@ -21,5 +20,5 @@ func wrapErr(err error, target error) error { if errors.Is(err, target) { return err } - return errors.WithStack(fmt.Errorf("%w: %v", target, err)) + return fmt.Errorf("%w: %v", target, err) } diff --git a/pkg/inflator/extract/extract.go b/pkg/inflator/extract/extract.go index 2275c165..8874fee0 100644 --- a/pkg/inflator/extract/extract.go +++ b/pkg/inflator/extract/extract.go @@ -7,7 +7,7 @@ import ( "path" "strings" - "knative.dev/hack" + hack "knative.dev/hack" ) const ( @@ -43,6 +43,11 @@ type Operation struct { func (o Operation) Extract(prtr Printer) error { l := logger{o.Verbose, prtr} hackRootDir := os.Getenv(HackScriptsDirEnvVar) + if f, err := hack.Scripts.Open(o.ScriptName); err != nil { + return wrapErr(err, ErrUnexpected) + } else if err = f.Close(); err != nil { + return wrapErr(err, ErrUnexpected) + } if hackRootDir == "" { hackRootDir = path.Join(os.TempDir(), "knative", "hack", "scripts") } diff --git a/pkg/inflator/extract/extract_test.go b/pkg/inflator/extract/extract_test.go index da46ac95..f60b99a6 100644 --- a/pkg/inflator/extract/extract_test.go +++ b/pkg/inflator/extract/extract_test.go @@ -7,9 +7,9 @@ import ( "strings" "testing" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" "knative.dev/hack/pkg/inflator/extract" + "knative.dev/hack/pkg/utest/assert" + "knative.dev/hack/pkg/utest/require" ) func TestExtract(t *testing.T) { diff --git a/pkg/retcode/retcode.go b/pkg/retcode/retcode.go new file mode 100644 index 00000000..06182824 --- /dev/null +++ b/pkg/retcode/retcode.go @@ -0,0 +1,21 @@ +package retcode + +import "hash/crc32" + +var ( + // LowerBound is the lower bound of the POSIX retcode range. Use this to + // configure the package. + LowerBound = 1 + // UpperBound is the upper bound of the POSIX retcode range. Use this to + // configure the package. + UpperBound = 255 +) + +// Calc will calculate an POSIX retcode from an error. +func Calc(err error) int { + if err == nil { + return 0 + } + upper := UpperBound - LowerBound + return int(crc32.ChecksumIEEE([]byte(err.Error())))%upper + LowerBound +} diff --git a/pkg/utest/assert/contain.go b/pkg/utest/assert/contain.go new file mode 100644 index 00000000..971b132a --- /dev/null +++ b/pkg/utest/assert/contain.go @@ -0,0 +1,41 @@ +package assert + +import ( + "fmt" + "strings" + + "knative.dev/hack/pkg/constraints" +) + +// Contains asserts that the specified list(array, slice...) contains the +// specified substring or element. +// +// assert.Contains(t, ["Hello", "World"], "World") +func Contains[O constraints.Ordered](t TestingT, haystack []O, needle O, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + for _, el := range haystack { + if el == needle { + return true + } + } + return Fail(t, fmt.Sprintf("%#v does not contain %#v", haystack, needle), msgAndArgs...) +} + +// ContainsSubstring asserts that the specified string contains the specified +// substring. +// +// assert.ContainsSubstring(t, "Hello World", "World") +func ContainsSubstring(t TestingT, haystack, needle string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + + if !strings.Contains(haystack, needle) { + return Fail(t, fmt.Sprintf("%#v does not contain substring %#v", haystack, needle), msgAndArgs...) + } + + return true +} diff --git a/pkg/utest/assert/empty.go b/pkg/utest/assert/empty.go new file mode 100644 index 00000000..44497ce8 --- /dev/null +++ b/pkg/utest/assert/empty.go @@ -0,0 +1,52 @@ +package assert + +import ( + "fmt" + "reflect" +) + +// Nil asserts that the specified object is nil. +// +// assert.Nil(t, err) +func Nil(t TestingT, object any, msgAndArgs ...interface{}) bool { + if isNil(object) { + return true + } + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) +} + +// isNil checks if a specified object is nil or not, without Failing. +func isNil(object any) bool { + if object == nil { + return true + } + + value := reflect.ValueOf(object) + kind := value.Kind() + isNilableKind := containsKind( + []reflect.Kind{ + reflect.Chan, reflect.Func, + reflect.Interface, reflect.Map, + reflect.Ptr, reflect.Slice}, + kind) + + if isNilableKind && value.IsNil() { + return true + } + + return false +} + +// containsKind checks if a specified kind in the slice of kinds. +func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { + for i := 0; i < len(kinds); i++ { + if kind == kinds[i] { + return true + } + } + + return false +} diff --git a/pkg/utest/assert/equal.go b/pkg/utest/assert/equal.go new file mode 100644 index 00000000..6c74b9db --- /dev/null +++ b/pkg/utest/assert/equal.go @@ -0,0 +1,43 @@ +package assert + +import ( + "fmt" + + "knative.dev/hack/pkg/constraints" +) + +// Greater asserts that the first element is greater than the second +// +// assert.Greater(t, 2, 1) +// assert.Greater(t, float64(2), float64(1)) +// assert.Greater(t, "b", "a") +func Greater[O constraints.Ordered](t TestingT, e1, e2 O, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if e1 > e2 { + return true + } + return Fail(t, fmt.Sprintf("\"%v\" is not greater than \"%v\"", e1, e2), msgAndArgs...) +} + +// Equal asserts that two objects are equal. +// +// assert.Equal(t, 123, 123) +// +// Pointer variable equality is determined based on the equality of the +// referenced values (as opposed to the memory addresses). Function equality +// cannot be determined and will always fail. +func Equal[C comparable](t TestingT, expected, actual C, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if expected != actual { + return Fail(t, fmt.Sprintf("Not equal: \n"+ + "expected: %#v\n"+ + "actual : %#v", expected, actual), msgAndArgs...) + } + + return true + +} diff --git a/pkg/utest/assert/error.go b/pkg/utest/assert/error.go new file mode 100644 index 00000000..ef79d963 --- /dev/null +++ b/pkg/utest/assert/error.go @@ -0,0 +1,55 @@ +package assert + +import ( + "fmt" + "strings" +) + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) bool { + if err != nil { + if h, ok := t.(tHelper); ok { + h.Helper() + } + return Fail(t, fmt.Sprintf("Received unexpected error:\n%+v", err), msgAndArgs...) + } + + return true +} + +// Fail reports a failure through +func Fail(t TestingT, failureMessage string, msgAndArgs ...interface{}) bool { + if h, ok := t.(tHelper); ok { + h.Helper() + } + content := []labeledContent{ + {"Error Trace", strings.Join(CallerInfo(), "\n\t\t\t")}, + {"Error", failureMessage}, + } + + // Add test name if the Go version supports it + if n, ok := t.(interface { + Name() string + }); ok { + content = append(content, labeledContent{"Test", n.Name()}) + } + + message := messageFromMsgAndArgs(msgAndArgs...) + if len(message) > 0 { + content = append(content, labeledContent{"Messages", message}) + } + + t.Errorf("\n%s", ""+labeledOutput(content...)) + + return false +} + +type labeledContent struct { + label string + content string +} diff --git a/pkg/utest/assert/format.go b/pkg/utest/assert/format.go new file mode 100644 index 00000000..6eb300be --- /dev/null +++ b/pkg/utest/assert/format.go @@ -0,0 +1,153 @@ +package assert + +import ( + "bufio" + "bytes" + "fmt" + "path/filepath" + "runtime" + "strings" + "unicode" + "unicode/utf8" +) + +/* CallerInfo is necessary because the assert functions use the testing object +internally, causing it to print the file:line of the assert method, rather than where +the problem actually occurred in calling code.*/ + +// CallerInfo returns an array of strings containing the file and line number +// of each stack frame leading from the current test to the assert call that +// failed. +func CallerInfo() []string { + + var pc uintptr + var ok bool + var file string + var line int + var name string + + callers := []string{} + for i := 0; ; i++ { + pc, file, line, ok = runtime.Caller(i) + if !ok { + // The breaks below failed to terminate the loop, and we ran off the + // end of the call stack. + break + } + + // This is a huge edge case, but it will panic if this is the case, see #180 + if file == "" { + break + } + + f := runtime.FuncForPC(pc) + if f == nil { + break + } + name = f.Name() + + // testing.tRunner is the standard library function that calls + // tests. Subtests are called directly by tRunner, without going through + // the Test/Benchmark/Example function that contains the t.Run calls, so + // with subtests we should break when we hit tRunner, without adding it + // to the list of callers. + if name == "testing.tRunner" { + break + } + + parts := strings.Split(file, "/") + file = parts[len(parts)-1] + if len(parts) > 1 { + dir := parts[len(parts)-2] + if (dir != "assert" && dir != "mock" && dir != "require") || file == "mock_test.go" { + path, _ := filepath.Abs(file) + callers = append(callers, fmt.Sprintf("%s:%d", path, line)) + } + } + + // Drop the package + segments := strings.Split(name, ".") + name = segments[len(segments)-1] + if isTest(name, "Test") || + isTest(name, "Benchmark") || + isTest(name, "Example") { + break + } + } + + return callers +} + +// Stolen from the `go test` tool. +// isTest tells whether name looks like a test (or benchmark, according to prefix). +// It is a Test (say) if there is a character after Test that is not a lower-case letter. +// We don't want TesticularCancer. +func isTest(name, prefix string) bool { + if !strings.HasPrefix(name, prefix) { + return false + } + if len(name) == len(prefix) { // "Test" is ok + return true + } + r, _ := utf8.DecodeRuneInString(name[len(prefix):]) + return !unicode.IsLower(r) +} + +func messageFromMsgAndArgs(msgAndArgs ...interface{}) string { + if len(msgAndArgs) == 0 || msgAndArgs == nil { + return "" + } + if len(msgAndArgs) == 1 { + msg := msgAndArgs[0] + if msgAsStr, ok := msg.(string); ok { + return msgAsStr + } + return fmt.Sprintf("%+v", msg) + } + if len(msgAndArgs) > 1 { + return fmt.Sprintf(msgAndArgs[0].(string), msgAndArgs[1:]...) + } + return "" +} + +// labeledOutput returns a string consisting of the provided labeledContent. Each labeled output is appended in the following manner: +// +// \t{{label}}:{{align_spaces}}\t{{content}}\n +// +// The initial carriage return is required to undo/erase any padding added by testing.T.Errorf. The "\t{{label}}:" is for the label. +// If a label is shorter than the longest label provided, padding spaces are added to make all the labels match in length. Once this +// alignment is achieved, "\t{{content}}\n" is added for the output. +// +// If the content of the labeledOutput contains line breaks, the subsequent lines are aligned so that they start at the same location as the first line. +func labeledOutput(content ...labeledContent) string { + longestLabel := 0 + for _, v := range content { + if len(v.label) > longestLabel { + longestLabel = len(v.label) + } + } + var output string + for _, v := range content { + output += "\t" + v.label + ":" + strings.Repeat(" ", longestLabel-len(v.label)) + "\t" + indentMessageLines(v.content, longestLabel) + "\n" + } + return output +} + +// Aligns the provided message so that all lines after the first line start at the same location as the first line. +// Assumes that the first line starts at the correct location (after carriage return, tab, label, spacer and tab). +// The longestLabelLen parameter specifies the length of the longest label in the output (required becaues this is the +// basis on which the alignment occurs). +func indentMessageLines(message string, longestLabelLen int) string { + outBuf := new(bytes.Buffer) + + for i, scanner := 0, bufio.NewScanner(strings.NewReader(message)); scanner.Scan(); i++ { + // no need to align first line because it starts at the correct location (after the label) + if i != 0 { + // append alignLen+1 spaces to align with "{{longestLabel}}:" before adding tab + outBuf.WriteString("\n\t" + strings.Repeat(" ", longestLabelLen+1) + "\t") + } + outBuf.WriteString(scanner.Text()) + } + + return outBuf.String() +} diff --git a/pkg/utest/assert/testingt.go b/pkg/utest/assert/testingt.go new file mode 100644 index 00000000..17d26e12 --- /dev/null +++ b/pkg/utest/assert/testingt.go @@ -0,0 +1,10 @@ +package assert + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + Errorf(format string, args ...interface{}) +} + +type tHelper interface { + Helper() +} diff --git a/pkg/utest/require/error.go b/pkg/utest/require/error.go new file mode 100644 index 00000000..f5d640ea --- /dev/null +++ b/pkg/utest/require/error.go @@ -0,0 +1,19 @@ +package require + +import "knative.dev/hack/pkg/utest/assert" + +// NoError asserts that a function returned no error (i.e. `nil`). +// +// actualObj, err := SomeFunction() +// if assert.NoError(t, err) { +// assert.Equal(t, expectedObj, actualObj) +// } +func NoError(t TestingT, err error, msgAndArgs ...interface{}) { + if h, ok := t.(tHelper); ok { + h.Helper() + } + if assert.NoError(t, err, msgAndArgs...) { + return + } + t.FailNow() +} diff --git a/pkg/utest/require/testingt.go b/pkg/utest/require/testingt.go new file mode 100644 index 00000000..61f26c18 --- /dev/null +++ b/pkg/utest/require/testingt.go @@ -0,0 +1,13 @@ +package require + +import "knative.dev/hack/pkg/utest/assert" + +// TestingT is an interface wrapper around *testing.T +type TestingT interface { + assert.TestingT + FailNow() +} + +type tHelper interface { + Helper() +} diff --git a/third_party/VENDOR-LICENSE/github.com/pkg/errors/LICENSE b/third_party/VENDOR-LICENSE/github.com/pkg/errors/LICENSE deleted file mode 100644 index 835ba3e7..00000000 --- a/third_party/VENDOR-LICENSE/github.com/pkg/errors/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2015, Dave Cheney -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/VENDOR-LICENSE/github.com/spf13/cobra/LICENSE.txt b/third_party/VENDOR-LICENSE/github.com/spf13/cobra/LICENSE.txt deleted file mode 100644 index 298f0e26..00000000 --- a/third_party/VENDOR-LICENSE/github.com/spf13/cobra/LICENSE.txt +++ /dev/null @@ -1,174 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. diff --git a/third_party/VENDOR-LICENSE/github.com/spf13/pflag/LICENSE b/third_party/VENDOR-LICENSE/github.com/spf13/pflag/LICENSE deleted file mode 100644 index 63ed1cfe..00000000 --- a/third_party/VENDOR-LICENSE/github.com/spf13/pflag/LICENSE +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2012 Alex Ogier. All rights reserved. -Copyright (c) 2012 The Go Authors. All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - - * Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above -copyright notice, this list of conditions and the following disclaimer -in the documentation and/or other materials provided with the -distribution. - * Neither the name of Google Inc. nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/third_party/VENDOR-LICENSE/github.com/wavesoftware/go-commandline/LICENSE b/third_party/VENDOR-LICENSE/github.com/wavesoftware/go-commandline/LICENSE deleted file mode 100644 index 05612468..00000000 --- a/third_party/VENDOR-LICENSE/github.com/wavesoftware/go-commandline/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2022 Wave Software - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/third_party/VENDOR-LICENSE/github.com/wavesoftware/go-retcode/LICENSE b/third_party/VENDOR-LICENSE/github.com/wavesoftware/go-retcode/LICENSE deleted file mode 100644 index 261eeb9e..00000000 --- a/third_party/VENDOR-LICENSE/github.com/wavesoftware/go-retcode/LICENSE +++ /dev/null @@ -1,201 +0,0 @@ - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. From c7d4a1a63ff109bb52678561ba4411f17815281a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Chris=20Suszy=C5=84ski?= Date: Fri, 22 Sep 2023 19:32:51 +0200 Subject: [PATCH 2/2] Ensure the knative.dev/hack package doesn't have any deps --- cmd/script/main_test.go | 8 ++--- pkg/inflator/cli/app.go | 20 ------------- pkg/inflator/cli/usage.go | 25 ++++++++++++++++ pkg/inflator/extract/extract.go | 2 +- pkg/retcode/retcode.go | 7 +++++ pkg/utest/assert/empty.go | 52 --------------------------------- test/go.mod | 1 + test/go.sum | 2 ++ test/no_deps_test.go | 32 ++++++++++++++++++++ 9 files changed, 72 insertions(+), 77 deletions(-) create mode 100644 pkg/inflator/cli/usage.go delete mode 100644 pkg/utest/assert/empty.go create mode 100644 test/no_deps_test.go diff --git a/cmd/script/main_test.go b/cmd/script/main_test.go index d2991fd2..bc97fb28 100644 --- a/cmd/script/main_test.go +++ b/cmd/script/main_test.go @@ -27,7 +27,7 @@ import ( func TestMainFn(t *testing.T) { var buf bytes.Buffer - var retcode *int + var retcode = -1_234_567_890 // nolint:gomnd // gate value withOptions( func() { main.RunMain() @@ -37,12 +37,12 @@ func TestMainFn(t *testing.T) { ex.Stderr = &buf ex.Args = []string{"--help"} ex.Exit = func(c int) { - retcode = &c + retcode = c } }, ) - assert.Nil(t, retcode) - assert.ContainsSubstring(t, buf.String(), "Script will extract Hack scripts") + assert.Equal(t, 0, retcode) + assert.ContainsSubstring(t, buf.String(), "Hacks as Go self-extracting binary") } func withOptions(fn func(), options ...cli.Option) { diff --git a/pkg/inflator/cli/app.go b/pkg/inflator/cli/app.go index 7c12d95e..445adca2 100644 --- a/pkg/inflator/cli/app.go +++ b/pkg/inflator/cli/app.go @@ -32,26 +32,6 @@ func ExecuteOrDie(opts ...Option) { } } -type usageErr struct{} - -func (u usageErr) Error() string { - return `Hacks as Go self-extracting binary - -Will extract Hack scripts to a temporary directory, and provide a source -file path to requested shell script. - -# In Bash script -source "$(go run knative.dev/hack/cmd/script@latest library.sh)" - -Usage: - script [flags] library.sh - -Flags: - -h, --help help - -v, --verbose verbose output -` -} - func createOperation(fl *flags, argv []string) extract.Operation { return extract.Operation{ ScriptName: argv[0], diff --git a/pkg/inflator/cli/usage.go b/pkg/inflator/cli/usage.go new file mode 100644 index 00000000..e338e536 --- /dev/null +++ b/pkg/inflator/cli/usage.go @@ -0,0 +1,25 @@ +package cli + +type usageErr struct{} + +func (u usageErr) Retcode() int { + return 0 +} + +func (u usageErr) Error() string { + return `Hacks as Go self-extracting binary + +Will extract Hack scripts to a temporary directory, and provide a source +file path to requested shell script. + +# In Bash script +source "$(go run knative.dev/hack/cmd/script@latest library.sh)" + +Usage: + script [flags] library.sh + +Flags: + -h, --help help + -v, --verbose verbose output +` +} diff --git a/pkg/inflator/extract/extract.go b/pkg/inflator/extract/extract.go index 8874fee0..b48ac568 100644 --- a/pkg/inflator/extract/extract.go +++ b/pkg/inflator/extract/extract.go @@ -7,7 +7,7 @@ import ( "path" "strings" - hack "knative.dev/hack" + "knative.dev/hack" ) const ( diff --git a/pkg/retcode/retcode.go b/pkg/retcode/retcode.go index 06182824..886eb0e6 100644 --- a/pkg/retcode/retcode.go +++ b/pkg/retcode/retcode.go @@ -16,6 +16,13 @@ func Calc(err error) int { if err == nil { return 0 } + if r, ok := err.(retcodeErr); ok { + return r.Retcode() + } upper := UpperBound - LowerBound return int(crc32.ChecksumIEEE([]byte(err.Error())))%upper + LowerBound } + +type retcodeErr interface { + Retcode() int +} diff --git a/pkg/utest/assert/empty.go b/pkg/utest/assert/empty.go deleted file mode 100644 index 44497ce8..00000000 --- a/pkg/utest/assert/empty.go +++ /dev/null @@ -1,52 +0,0 @@ -package assert - -import ( - "fmt" - "reflect" -) - -// Nil asserts that the specified object is nil. -// -// assert.Nil(t, err) -func Nil(t TestingT, object any, msgAndArgs ...interface{}) bool { - if isNil(object) { - return true - } - if h, ok := t.(tHelper); ok { - h.Helper() - } - return Fail(t, fmt.Sprintf("Expected nil, but got: %#v", object), msgAndArgs...) -} - -// isNil checks if a specified object is nil or not, without Failing. -func isNil(object any) bool { - if object == nil { - return true - } - - value := reflect.ValueOf(object) - kind := value.Kind() - isNilableKind := containsKind( - []reflect.Kind{ - reflect.Chan, reflect.Func, - reflect.Interface, reflect.Map, - reflect.Ptr, reflect.Slice}, - kind) - - if isNilableKind && value.IsNil() { - return true - } - - return false -} - -// containsKind checks if a specified kind in the slice of kinds. -func containsKind(kinds []reflect.Kind, kind reflect.Kind) bool { - for i := 0; i < len(kinds); i++ { - if kind == kinds[i] { - return true - } - } - - return false -} diff --git a/test/go.mod b/test/go.mod index 2681b6c7..a19bd963 100644 --- a/test/go.mod +++ b/test/go.mod @@ -5,6 +5,7 @@ go 1.18 require ( github.com/stretchr/testify v1.8.1 github.com/thanhpk/randstr v1.0.4 + golang.org/x/mod v0.12.0 ) require ( diff --git a/test/go.sum b/test/go.sum index 2d7ebaeb..8a1b8448 100644 --- a/test/go.sum +++ b/test/go.sum @@ -19,6 +19,8 @@ github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKs github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/thanhpk/randstr v1.0.4 h1:IN78qu/bR+My+gHCvMEXhR/i5oriVHcTB/BJJIRTsNo= github.com/thanhpk/randstr v1.0.4/go.mod h1:M/H2P1eNLZzlDwAzpkkkUvoyNNMbzRGhESZuEQk3r0U= +golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc= +golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/test/no_deps_test.go b/test/no_deps_test.go new file mode 100644 index 00000000..a413ef25 --- /dev/null +++ b/test/no_deps_test.go @@ -0,0 +1,32 @@ +package sample_test + +import ( + "os" + "testing" + + "golang.org/x/mod/modfile" +) + +func TestNoDependenciesPresent(t *testing.T) { + var ( + bytes []byte + err error + ) + if bytes, err = os.ReadFile("../go.mod"); err != nil { + t.Fatal(err) + } + + var mf *modfile.File + if mf, err = modfile.ParseLax("go.mod", bytes, nil); err != nil { + t.Fatal(err) + } + + if len(mf.Require) > 0 { + deps := make([]string, 0, len(mf.Require)) + for _, r := range mf.Require { + deps = append(deps, r.Mod.String()) + } + t.Errorf("go.mod file should not have dependencies, but has %d: %+q", + len(mf.Require), deps) + } +}