diff --git a/internal/commands/commands.go b/internal/commands/commands.go index 11fa645ca5..80ac770d13 100644 --- a/internal/commands/commands.go +++ b/internal/commands/commands.go @@ -25,6 +25,7 @@ type PackClient interface { NewBuildpack(context.Context, client.NewBuildpackOptions) error PackageBuildpack(ctx context.Context, opts client.PackageBuildpackOptions) error PackageExtension(ctx context.Context, opts client.PackageBuildpackOptions) error + NewExtension(ctx context.Context, options client.NewExtensionOptions) error Build(context.Context, client.BuildOptions) error RegisterBuildpack(context.Context, client.RegisterBuildpackOptions) error YankBuildpack(client.YankBuildpackOptions) error diff --git a/internal/commands/extension.go b/internal/commands/extension.go index bc4ab36476..22cf86e32b 100644 --- a/internal/commands/extension.go +++ b/internal/commands/extension.go @@ -19,7 +19,7 @@ func NewExtensionCommand(logger logging.Logger, cfg config.Config, client PackCl // client and packageConfigReader to be passed later on cmd.AddCommand(ExtensionPackage(logger, cfg, client, packageConfigReader)) // client to be passed later on - cmd.AddCommand(ExtensionNew(logger)) + cmd.AddCommand(ExtensionNew(logger, client)) cmd.AddCommand(ExtensionPull(logger, cfg, client)) cmd.AddCommand(ExtensionRegister(logger, cfg, client)) cmd.AddCommand(ExtensionYank(logger, cfg, client)) diff --git a/internal/commands/extension_new.go b/internal/commands/extension_new.go index d91e424cb0..79c610c873 100644 --- a/internal/commands/extension_new.go +++ b/internal/commands/extension_new.go @@ -1,8 +1,19 @@ package commands import ( + "context" + "fmt" + "os" + "path/filepath" + "runtime" + "strings" + "github.com/spf13/cobra" + "github.com/buildpacks/pack/internal/style" + "github.com/buildpacks/pack/internal/target" + "github.com/buildpacks/pack/pkg/client" + "github.com/buildpacks/pack/pkg/dist" "github.com/buildpacks/pack/pkg/logging" ) @@ -11,25 +22,80 @@ type ExtensionNewFlags struct { API string Path string Stacks []string + Targets []string Version string } // extensioncreator type to be added here and argument also to be added in the function +type ExtensionCreator interface { + NewExtension(ctx context.Context, options client.NewExtensionOptions) error +} // ExtensionNew generates the scaffolding of an extension -func ExtensionNew(logger logging.Logger) *cobra.Command { +func ExtensionNew(logger logging.Logger, creator ExtensionCreator) *cobra.Command { + var flags ExtensionNewFlags cmd := &cobra.Command{ Use: "new ", Short: "Creates basic scaffolding of an extension", Args: cobra.MatchAll(cobra.ExactArgs(1), cobra.OnlyValidArgs), Example: "pack extension new ", RunE: logError(logger, func(cmd *cobra.Command, args []string) error { - // logic will go here + id := args[0] + idParts := strings.Split(id, "/") + dirName := idParts[len(idParts)-1] + + var path string + if len(flags.Path) == 0 { + cwd, err := os.Getwd() + if err != nil { + return err + } + path = filepath.Join(cwd, dirName) + } else { + path = flags.Path + } + + _, err := os.Stat(path) + if !os.IsNotExist(err) { + return fmt.Errorf("directory %s exists", style.Symbol(path)) + } + + var targets []dist.Target + if len(flags.Targets) == 0 && len(flags.Stacks) == 0 { + targets = []dist.Target{{ + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }} + } else { + if targets, err = target.ParseTargets(flags.Targets, logger); err != nil { + return err + } + } + + if err := creator.NewExtension(cmd.Context(), client.NewExtensionOptions{ + API: flags.API, + ID: id, + Path: path, + Targets: targets, + Version: flags.Version, + }); err != nil { + return err + } + + logger.Infof("Successfully created %s", style.Symbol(id)) return nil }), } - - // flags will go here + cmd.Flags().StringVarP(&flags.API, "api", "a", "0.9", "Buildpack API compatibility of the generated extension") + cmd.Flags().StringVarP(&flags.Path, "path", "p", "", "Path to generate the extension") + cmd.Flags().StringVarP(&flags.Version, "version", "V", "1.0.0", "Version of the generated extension") + cmd.Flags().MarkDeprecated("stacks", "prefer `--targets` instead: https://github.com/buildpacks/rfcs/blob/main/text/0096-remove-stacks-mixins.md") + cmd.Flags().StringSliceVarP(&flags.Targets, "targets", "t", nil, + `Targets are the list platforms that one targeting, these are generated as part of scaffolding inside buildpack.toml file. one can provide target platforms in format [os][/arch][/variant]:[distroname@osversion@anotherversion];[distroname@osversion] + - Base case for two different architectures : '--targets "linux/amd64" --targets "linux/arm64"' + - case for distribution version: '--targets "windows/amd64:windows-nano@10.0.19041.1415"' + - case for different architecture with distributed versions : '--targets "linux/arm/v6:ubuntu@14.04" --targets "linux/arm/v6:ubuntu@16.04"' + `) AddHelpFlag(cmd, "new") return cmd diff --git a/internal/commands/extension_new_test.go b/internal/commands/extension_new_test.go new file mode 100644 index 0000000000..3f6a94c92e --- /dev/null +++ b/internal/commands/extension_new_test.go @@ -0,0 +1,180 @@ +package commands_test + +import ( + "bytes" + "os" + "path/filepath" + "runtime" + "testing" + + "github.com/buildpacks/pack/pkg/client" + "github.com/buildpacks/pack/pkg/dist" + "github.com/buildpacks/pack/pkg/logging" + + "github.com/golang/mock/gomock" + "github.com/heroku/color" + "github.com/sclevine/spec" + "github.com/sclevine/spec/report" + "github.com/spf13/cobra" + + "github.com/buildpacks/pack/internal/commands" + "github.com/buildpacks/pack/internal/commands/testmocks" + h "github.com/buildpacks/pack/testhelpers" +) + +func TestExtensionNewCommand(t *testing.T) { + color.Disable(true) + defer color.Disable(false) + spec.Run(t, "ExtensionNewCommand", testExtensionNewCommand, spec.Parallel(), spec.Report(report.Terminal{})) +} + +func testExtensionNewCommand(t *testing.T, when spec.G, it spec.S) { + var ( + command *cobra.Command + logger *logging.LogWithWriters + outBuf bytes.Buffer + mockController *gomock.Controller + mockClient *testmocks.MockPackClient + tmpDir string + ) + targets := []dist.Target{{ + OS: runtime.GOOS, + Arch: runtime.GOARCH, + }} + + it.Before(func() { + var err error + tmpDir, err = os.MkdirTemp("", "build-test") + h.AssertNil(t, err) + + logger = logging.NewLogWithWriters(&outBuf, &outBuf) + mockController = gomock.NewController(t) + mockClient = testmocks.NewMockPackClient(mockController) + + command = commands.ExtensionNew(logger, mockClient) + }) + + it.After(func() { + os.RemoveAll(tmpDir) + }) + + when("ExtensionNew#Execute", func() { + it("uses the args to generate artifacts", func() { + mockClient.EXPECT().NewExtension(gomock.Any(), client.NewExtensionOptions{ + API: "0.9", + ID: "example/some-cnb", + Path: filepath.Join(tmpDir, "some-cnb"), + Version: "1.0.0", + Targets: targets, + }).Return(nil).MaxTimes(1) + + path := filepath.Join(tmpDir, "some-cnb") + command.SetArgs([]string{"--path", path, "example/some-cnb"}) + + err := command.Execute() + h.AssertNil(t, err) + }) + + it("stops if the directory already exists", func() { + err := os.MkdirAll(tmpDir, 0600) + h.AssertNil(t, err) + + command.SetArgs([]string{"--path", tmpDir, "example/some-cnb"}) + err = command.Execute() + h.AssertNotNil(t, err) + h.AssertContains(t, outBuf.String(), "ERROR: directory") + }) + + when("target flag is specified, ", func() { + it("it uses target to generate artifacts", func() { + mockClient.EXPECT().NewExtension(gomock.Any(), client.NewExtensionOptions{ + API: "0.9", + ID: "example/targets", + Path: filepath.Join(tmpDir, "targets"), + Version: "1.0.0", + Targets: []dist.Target{{ + OS: "linux", + Arch: "arm", + ArchVariant: "v6", + Distributions: []dist.Distribution{{ + Name: "ubuntu", + Versions: []string{"14.04", "16.04"}, + }}, + }}, + }).Return(nil).MaxTimes(1) + + path := filepath.Join(tmpDir, "targets") + command.SetArgs([]string{"--path", path, "example/targets", "--targets", "linux/arm/v6:ubuntu@14.04@16.04"}) + + err := command.Execute() + h.AssertNil(t, err) + }) + it("it should show error when invalid [os]/[arch] passed", func() { + mockClient.EXPECT().NewExtension(gomock.Any(), client.NewExtensionOptions{ + API: "0.9", + ID: "example/targets", + Path: filepath.Join(tmpDir, "targets"), + Version: "1.0.0", + Targets: []dist.Target{{ + OS: "os", + Arch: "arm", + ArchVariant: "v6", + Distributions: []dist.Distribution{{ + Name: "ubuntu", + Versions: []string{"14.04", "16.04"}, + }}, + }}, + }).Return(nil).MaxTimes(1) + + path := filepath.Join(tmpDir, "targets") + command.SetArgs([]string{"--path", path, "example/targets", "--targets", "os/arm/v6:ubuntu@14.04@16.04"}) + + err := command.Execute() + h.AssertNotNil(t, err) + }) + when("it should", func() { + it("support format [os][/arch][/variant]:[name@version@version2];[some-name@version@version2]", func() { + mockClient.EXPECT().NewExtension(gomock.Any(), client.NewExtensionOptions{ + API: "0.9", + ID: "example/targets", + Path: filepath.Join(tmpDir, "targets"), + Version: "1.0.0", + Targets: []dist.Target{ + { + OS: "linux", + Arch: "arm", + ArchVariant: "v6", + Distributions: []dist.Distribution{ + { + Name: "ubuntu", + Versions: []string{"14.04", "16.04"}, + }, + { + Name: "debian", + Versions: []string{"8.10", "10.9"}, + }, + }, + }, + { + OS: "windows", + Arch: "amd64", + Distributions: []dist.Distribution{ + { + Name: "windows-nano", + Versions: []string{"10.0.19041.1415"}, + }, + }, + }, + }, + }).Return(nil).MaxTimes(1) + + path := filepath.Join(tmpDir, "targets") + command.SetArgs([]string{"--path", path, "example/targets", "--targets", "linux/arm/v6:ubuntu@14.04@16.04;debian@8.10@10.9", "-t", "windows/amd64:windows-nano@10.0.19041.1415"}) + + err := command.Execute() + h.AssertNil(t, err) + }) + }) + }) + }) +} diff --git a/internal/commands/testmocks/mock_pack_client.go b/internal/commands/testmocks/mock_pack_client.go index f49b92def9..6d1650321f 100644 --- a/internal/commands/testmocks/mock_pack_client.go +++ b/internal/commands/testmocks/mock_pack_client.go @@ -157,6 +157,20 @@ func (mr *MockPackClientMockRecorder) NewBuildpack(arg0, arg1 interface{}) *gomo return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewBuildpack", reflect.TypeOf((*MockPackClient)(nil).NewBuildpack), arg0, arg1) } +// NewExtension mocks base method. +func (m *MockPackClient) NewExtension(arg0 context.Context, arg1 client.NewExtensionOptions) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewExtension", arg0, arg1) + ret0, _ := ret[0].(error) + return ret0 +} + +// NewExtension indicates an expected call of NewExtension. +func (mr *MockPackClientMockRecorder) NewExtension(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewExtension", reflect.TypeOf((*MockPackClient)(nil).NewExtension), arg0, arg1) +} + // PackageBuildpack mocks base method. func (m *MockPackClient) PackageBuildpack(arg0 context.Context, arg1 client.PackageBuildpackOptions) error { m.ctrl.T.Helper() diff --git a/pkg/client/new_extension.go b/pkg/client/new_extension.go new file mode 100644 index 0000000000..4f62d8d1c1 --- /dev/null +++ b/pkg/client/new_extension.go @@ -0,0 +1,118 @@ +package client + +import ( + "context" + "os" + "path/filepath" + + "github.com/BurntSushi/toml" + + "github.com/buildpacks/lifecycle/api" + + "github.com/buildpacks/pack/internal/style" + "github.com/buildpacks/pack/pkg/dist" +) + +var ( + bashBinGenerate = `#!/usr/bin/env bash + + set -eo pipefail + + # 1. GET ARGS + output_dir=$CNB_OUTPUT_DIR + + # 2. GENERATE build.Dockerfile + cat >> "${output_dir}/build.Dockerfile" <> "${output_dir}/run.Dockerfile" < 0 { // nolint + return nil // Order extension or stack extension, no validation required + } else if e.WithLinuxBuild && os == DefaultTargetOSLinux && arch == DefaultTargetArch { + return nil + } else if e.WithWindowsBuild && os == DefaultTargetOSWindows && arch == DefaultTargetArch { + return nil + } + } + for _, target := range e.Targets() { + if target.OS == os { + if target.Arch == "" || arch == "" || target.Arch == arch { + if len(target.Distributions) == 0 || distroName == "" || distroVersion == "" { + return nil + } + for _, distro := range target.Distributions { + if distro.Name == distroName { + if len(distro.Versions) == 0 { + return nil + } + for _, version := range distro.Versions { + if version == distroVersion { + return nil + } + } + } + } + } + } + } + type osDistribution struct { + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` + } + type target struct { + OS string `json:"os"` + Arch string `json:"arch"` + Distribution osDistribution `json:"distribution"` + } + return fmt.Errorf( + "unable to satisfy target os/arch constraints; build image: %s, extension %s: %s", + toJSONMaybe(target{ + OS: os, + Arch: arch, + Distribution: osDistribution{Name: distroName, Version: distroVersion}, + }), + style.Symbol(e.Info().FullName()), + toJSONMaybe(e.Targets()), + ) } func (e *ExtensionDescriptor) EscapedID() string { @@ -44,5 +98,5 @@ func (e *ExtensionDescriptor) Stacks() []Stack { } func (e *ExtensionDescriptor) Targets() []Target { - return nil + return e.WithTargets } diff --git a/pkg/testmocks/mock_access_checker.go b/pkg/testmocks/mock_access_checker.go new file mode 100644 index 0000000000..558b85a580 --- /dev/null +++ b/pkg/testmocks/mock_access_checker.go @@ -0,0 +1,48 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/buildpacks/pack/pkg/client (interfaces: AccessChecker) + +// Package testmocks is a generated GoMock package. +package testmocks + +import ( + reflect "reflect" + + gomock "github.com/golang/mock/gomock" +) + +// MockAccessChecker is a mock of AccessChecker interface. +type MockAccessChecker struct { + ctrl *gomock.Controller + recorder *MockAccessCheckerMockRecorder +} + +// MockAccessCheckerMockRecorder is the mock recorder for MockAccessChecker. +type MockAccessCheckerMockRecorder struct { + mock *MockAccessChecker +} + +// NewMockAccessChecker creates a new mock instance. +func NewMockAccessChecker(ctrl *gomock.Controller) *MockAccessChecker { + mock := &MockAccessChecker{ctrl: ctrl} + mock.recorder = &MockAccessCheckerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use. +func (m *MockAccessChecker) EXPECT() *MockAccessCheckerMockRecorder { + return m.recorder +} + +// Check mocks base method. +func (m *MockAccessChecker) Check(arg0 string) bool { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Check", arg0) + ret0, _ := ret[0].(bool) + return ret0 +} + +// Check indicates an expected call of Check. +func (mr *MockAccessCheckerMockRecorder) Check(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Check", reflect.TypeOf((*MockAccessChecker)(nil).Check), arg0) +} diff --git a/pkg/testmocks/mock_docker_client.go b/pkg/testmocks/mock_docker_client.go index 18b51c18f1..5ba29fec53 100644 --- a/pkg/testmocks/mock_docker_client.go +++ b/pkg/testmocks/mock_docker_client.go @@ -224,10 +224,10 @@ func (mr *MockCommonAPIClientMockRecorder) ContainerCreate(arg0, arg1, arg2, arg } // ContainerDiff mocks base method. -func (m *MockCommonAPIClient) ContainerDiff(arg0 context.Context, arg1 string) ([]container.ContainerChangeResponseItem, error) { +func (m *MockCommonAPIClient) ContainerDiff(arg0 context.Context, arg1 string) ([]container.FilesystemChange, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ContainerDiff", arg0, arg1) - ret0, _ := ret[0].([]container.ContainerChangeResponseItem) + ret0, _ := ret[0].([]container.FilesystemChange) ret1, _ := ret[1].(error) return ret0, ret1 } @@ -1338,7 +1338,7 @@ func (mr *MockCommonAPIClientMockRecorder) PluginUpgrade(arg0, arg1, arg2 interf } // RegistryLogin mocks base method. -func (m *MockCommonAPIClient) RegistryLogin(arg0 context.Context, arg1 types.AuthConfig) (registry.AuthenticateOKBody, error) { +func (m *MockCommonAPIClient) RegistryLogin(arg0 context.Context, arg1 registry.AuthConfig) (registry.AuthenticateOKBody, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "RegistryLogin", arg0, arg1) ret0, _ := ret[0].(registry.AuthenticateOKBody) @@ -1725,7 +1725,7 @@ func (mr *MockCommonAPIClientMockRecorder) VolumeInspectWithRaw(arg0, arg1 inter } // VolumeList mocks base method. -func (m *MockCommonAPIClient) VolumeList(arg0 context.Context, arg1 filters.Args) (volume.ListResponse, error) { +func (m *MockCommonAPIClient) VolumeList(arg0 context.Context, arg1 volume.ListOptions) (volume.ListResponse, error) { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "VolumeList", arg0, arg1) ret0, _ := ret[0].(volume.ListResponse) diff --git a/tools/go.sum b/tools/go.sum index 3511f5a3bf..3617a95580 100644 --- a/tools/go.sum +++ b/tools/go.sum @@ -72,6 +72,7 @@ github.com/ashanbrown/forbidigo v1.5.1/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1 github.com/ashanbrown/makezero v1.1.1 h1:iCQ87C0V0vSyO+M9E/FZYbu65auqH0lnsOkf5FcB28s= github.com/ashanbrown/makezero v1.1.1/go.mod h1:i1bJLCRSCHOcOa9Y6MyF2FTfMZMFdHvxKHxgO5Z1axI= github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8= +github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= @@ -130,6 +131,7 @@ github.com/fatih/structtag v1.2.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4 github.com/firefart/nonamedreturns v1.0.4 h1:abzI1p7mAEPYuR4A+VLKn4eNDOycjYo2phmY9sfv40Y= github.com/firefart/nonamedreturns v1.0.4/go.mod h1:TDhe/tjI1BXo48CmYbUduTV7BdIga8MAO/xbKdcVsGI= github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= +github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= github.com/fzipp/gocyclo v0.6.0 h1:lsblElZG7d3ALtGMx9fmxeTKZaLLpU8mET09yN4BBLo= @@ -146,6 +148,7 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0= +github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-toolsmith/astcast v1.1.0 h1:+JN9xZV1A+Re+95pgnMgDboWNVnIMMQXwfBwLRPgSC8= github.com/go-toolsmith/astcast v1.1.0/go.mod h1:qdcuFWeGGS2xX5bLM/c3U9lewg7+Zu4mr+xPwZIB4ZU= @@ -159,6 +162,7 @@ github.com/go-toolsmith/astfmt v1.1.0/go.mod h1:OrcLlRwu0CuiIBp/8b5PYF9ktGVZUjlN github.com/go-toolsmith/astp v1.1.0 h1:dXPuCl6u2llURjdPLLDxJeZInAeZ0/eZwFJmqZMnpQA= github.com/go-toolsmith/astp v1.1.0/go.mod h1:0T1xFGz9hicKs8Z5MfAqSUitoUYS30pDMsRVIDHs8CA= github.com/go-toolsmith/pkgload v1.2.2 h1:0CtmHq/02QhxcF7E9N5LIFcYFsMR5rdovfqTtRKkgIk= +github.com/go-toolsmith/pkgload v1.2.2/go.mod h1:R2hxLNRKuAsiXCo2i5J6ZQPhnPMOVtU+f0arbFPWCus= github.com/go-toolsmith/strparse v1.0.0/go.mod h1:YI2nUKP9YGZnL/L1/DLFBfixrcjslWct4wyljWhSRy8= github.com/go-toolsmith/strparse v1.1.0 h1:GAioeZUK9TGxnLS+qfdqNbA4z0SSm5zVNtCQiyP2Bvw= github.com/go-toolsmith/strparse v1.1.0/go.mod h1:7ksGy58fsaQkGQlY8WVoBFNyEPMGuJin1rfoPS4lBSQ= @@ -269,6 +273,7 @@ github.com/gostaticanalysis/nilerr v0.1.1 h1:ThE+hJP0fEp4zWLkWHWcRyI2Od0p7DlgYG3 github.com/gostaticanalysis/nilerr v0.1.1/go.mod h1:wZYb6YI5YAxxq0i1+VJbY0s2YONW0HU0GPE3+5PWN4A= github.com/gostaticanalysis/testutil v0.3.1-0.20210208050101-bfb5c8eec0e4/go.mod h1:D+FIZ+7OahH3ePw/izIEeH5I06eKs1IKI4Xr64/Am3M= github.com/gostaticanalysis/testutil v0.4.0 h1:nhdCmubdmDF6VEatUNjgUZBJKWRqugoISdUv3PPQgHY= +github.com/gostaticanalysis/testutil v0.4.0/go.mod h1:bLIoPefWXrRi/ssLFWX1dx7Repi5x3CuviD3dgAZaBU= github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA= github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= @@ -317,9 +322,11 @@ github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= +github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= 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/kulti/thelper v0.6.3 h1:ElhKf+AlItIu+xGnI990no4cE2+XaSu1ULymV2Yulxs= github.com/kulti/thelper v0.6.3/go.mod h1:DsqKShOvP40epevkFrvIwkCMNYxMeTNjdWL4dqWHZ6I= github.com/kunwardeep/paralleltest v1.0.6 h1:FCKYMF1OF2+RveWlABsdnmsvJrei5aoyZoaGS+Ugg8g= @@ -375,6 +382,7 @@ github.com/nakabonne/nestif v0.3.1/go.mod h1:9EtoZochLn5iUprVDmDjqGKPofoUEBL8U4N github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354 h1:4kuARK6Y6FxaNu/BnU2OAaLF86eTVhP2hjTB6iMvItA= github.com/nbutton23/zxcvbn-go v0.0.0-20210217022336-fa2cb2858354/go.mod h1:KSVJerMDfblTH7p5MZaTt+8zaT2iEk3AkVb9PQdZuE8= 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/nishanths/exhaustive v0.9.5 h1:TzssWan6orBiLYVqewCG8faud9qlFntJE30ACpzmGME= github.com/nishanths/exhaustive v0.9.5/go.mod h1:IbwrGdVMizvDcIxPYGVdQn5BqWJaOwpCvg4RGb8r/TA= github.com/nishanths/predeclared v0.2.2 h1:V2EPdZPliZymNAn79T8RkNApBjMmVKh5XRpLm/w98Vk= @@ -384,7 +392,9 @@ github.com/nunnatsa/ginkgolinter v0.9.0/go.mod h1:FHaMLURXP7qImeH6bvxWJUpyH+2tuq github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= github.com/onsi/ginkgo/v2 v2.8.0 h1:pAM+oBNPrpXRs+E/8spkeGx9QgekbRVyr74EUvRVOUI= +github.com/onsi/ginkgo/v2 v2.8.0/go.mod h1:6JsQiECmxCa3V5st74AL/AmsV482EDdVrGaVW6z3oYU= github.com/onsi/gomega v1.26.0 h1:03cDLK28U6hWvCAns6NeydX3zIm4SF3ci69ulidS32Q= +github.com/onsi/gomega v1.26.0/go.mod h1:r+zV744Re+DiYCIPRlYOTxn0YkOLcAnW8k1xXdMPGhM= github.com/otiai10/copy v1.2.0 h1:HvG945u96iNadPoG2/Ja2+AUJeW5YuFQMixq9yirC+k= github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw= github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE= @@ -436,6 +446,7 @@ github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567 h1:M8mH9eK4OUR4l github.com/quasilyte/stdinfo v0.0.0-20220114132959-f7386bf02567/go.mod h1:DWNGW8A4Y+GyBgPuaQJuWiy0XYftx4Xm/y5Jqk9I6VQ= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/ryancurrah/gomodguard v1.3.0 h1:q15RT/pd6UggBXVBuLps8BXRvl5GPBcwVA7BJHMLuTw= github.com/ryancurrah/gomodguard v1.3.0/go.mod h1:ggBxb3luypPEzqVtq33ee7YSN35V28XeGnid8dnni50= @@ -547,6 +558,7 @@ go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI= +go.uber.org/goleak v1.1.11/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ= go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4= go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60= @@ -652,6 +664,7 @@ golang.org/x/net v0.3.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE= golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ= +golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -934,6 +947,7 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/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/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=