From eca03ce6db9bf185516bf1caefff57cd9a487a94 Mon Sep 17 00:00:00 2001 From: Bryce Lampe Date: Tue, 16 Apr 2024 13:03:21 -0700 Subject: [PATCH] Fix optional/pointer indirection errors --- provider/internal/cache.go | 16 +++++------ provider/internal/cache_test.go | 5 ++-- provider/internal/client_test.go | 29 ++++++++++---------- provider/internal/context.go | 29 +++++++++++++++----- provider/internal/context_test.go | 3 ++- provider/internal/dockerfile.go | 4 +-- provider/internal/dockerfile_test.go | 2 +- provider/internal/export.go | 10 +++---- provider/internal/export_test.go | 5 ++-- provider/internal/image.go | 27 +++++++++++-------- provider/internal/image_test.go | 40 ++++++++++++++++------------ provider/internal/index.go | 35 +++++++++++++++--------- provider/internal/index_test.go | 10 +++---- provider/internal/network.go | 7 +++++ provider/internal/preview.go | 6 ++--- 15 files changed, 138 insertions(+), 90 deletions(-) diff --git a/provider/internal/cache.go b/provider/internal/cache.go index 325264d..2c99ad0 100644 --- a/provider/internal/cache.go +++ b/provider/internal/cache.go @@ -342,7 +342,7 @@ func (c *CacheFromS3) String() string { // CacheWithMode is a cache that can configure its mode. type CacheWithMode struct { - Mode CacheMode `pulumi:"mode,optional"` + Mode *CacheMode `pulumi:"mode,optional"` } // Annotate sets docstrings and defaults on CacheWithMode. @@ -354,10 +354,10 @@ func (c *CacheWithMode) Annotate(a infer.Annotator) { } func (c CacheWithMode) String() string { - if c.Mode == "" { + if c.Mode == nil { return "" } - return fmt.Sprintf("mode=%s", c.Mode) + return fmt.Sprintf("mode=%s", *c.Mode) } // CacheWithIgnoreError exposes an option to ignore errors during caching. @@ -552,9 +552,9 @@ func (c *CacheToRegistry) String() string { // CacheWithCompression is a cache with options to configure compression // settings. type CacheWithCompression struct { - Compression CompressionType `pulumi:"compression,optional"` - CompressionLevel int `pulumi:"compressionLevel,optional"` - ForceCompression *bool `pulumi:"forceCompression,optional"` + Compression *CompressionType `pulumi:"compression,optional"` + CompressionLevel int `pulumi:"compressionLevel,optional"` + ForceCompression *bool `pulumi:"forceCompression,optional"` } // Annotate sets docstrings and defaults on CacheWithCompression. @@ -575,8 +575,8 @@ func (c CacheWithCompression) String() string { return "" } parts := []string{} - if c.Compression != "" { - parts = append(parts, fmt.Sprintf("compression=%s", c.Compression)) + if c.Compression != nil { + parts = append(parts, fmt.Sprintf("compression=%s", *c.Compression)) } if c.CompressionLevel > 0 { cl := c.CompressionLevel diff --git a/provider/internal/cache_test.go b/provider/internal/cache_test.go index 7543de1..ad5dc79 100644 --- a/provider/internal/cache_test.go +++ b/provider/internal/cache_test.go @@ -26,6 +26,7 @@ import ( func TestCacheString(t *testing.T) { t.Parallel() + gzip := Gzip tests := []struct { name string @@ -81,12 +82,12 @@ func TestCacheString(t *testing.T) { given: CacheTo{Local: &CacheToLocal{ Dest: "/foo", CacheWithCompression: CacheWithCompression{ - Compression: "gz2", + Compression: &gzip, CompressionLevel: 100, ForceCompression: pulumi.BoolRef(true), }, }}, - want: "type=local,dest=/foo,compression=gz2,compression-level=22,force-compression=true", + want: "type=local,dest=/foo,compression=gzip,compression-level=22,force-compression=true", }, { name: "ignore-error", diff --git a/provider/internal/client_test.go b/provider/internal/client_test.go index 648db6b..35e3710 100644 --- a/provider/internal/client_test.go +++ b/provider/internal/client_test.go @@ -90,8 +90,9 @@ func TestBuild(t *testing.T) { pctx.EXPECT().Deadline().Return(ctx.Deadline()).AnyTimes() tmpdir := t.TempDir() + max := Max - exampleContext := BuildContext{Context: Context{Location: "../../examples/app"}} + exampleContext := &BuildContext{Context: Context{Location: "../../examples/app"}} tests := []struct { name string @@ -104,7 +105,7 @@ func TestBuild(t *testing.T) { name: "multiPlatform", args: ImageArgs{ Context: exampleContext, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Location: "../../examples/app/Dockerfile.multiPlatform", }, Platforms: []Platform{"plan9/amd64", "plan9/arm64"}, @@ -131,7 +132,7 @@ func TestBuild(t *testing.T) { Tags: []string{"cached"}, CacheTo: []CacheTo{{Local: &CacheToLocal{ Dest: filepath.Join(tmpdir, "cache"), - CacheWithMode: CacheWithMode{Mode: "max"}, + CacheWithMode: CacheWithMode{Mode: &max}, }}}, CacheFrom: []CacheFrom{{Local: &CacheFromLocal{ Src: filepath.Join(tmpdir, "cache"), @@ -142,7 +143,7 @@ func TestBuild(t *testing.T) { name: "buildArgs", args: ImageArgs{ Context: exampleContext, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Location: "../../examples/app/Dockerfile.buildArgs", }, BuildArgs: map[string]string{ @@ -154,7 +155,7 @@ func TestBuild(t *testing.T) { name: "extraHosts", args: ImageArgs{ Context: exampleContext, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Location: "../../examples/app/Dockerfile.extraHosts", }, AddHosts: []string{ @@ -167,7 +168,7 @@ func TestBuild(t *testing.T) { skip: os.Getenv("SSH_AUTH_SOCK") == "", args: ImageArgs{ Context: exampleContext, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Location: "../../examples/app/Dockerfile.sshMount", }, SSH: []SSH{{ID: "default"}}, @@ -177,7 +178,7 @@ func TestBuild(t *testing.T) { name: "secrets", args: ImageArgs{ Context: exampleContext, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Location: "../../examples/app/Dockerfile.secrets", }, Secrets: map[string]string{ @@ -199,7 +200,7 @@ func TestBuild(t *testing.T) { name: "target", args: ImageArgs{ Context: exampleContext, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Location: "../../examples/app/Dockerfile.target", }, Target: "build-me", @@ -208,7 +209,7 @@ func TestBuild(t *testing.T) { { name: "namedContext", args: ImageArgs{ - Context: BuildContext{ + Context: &BuildContext{ Context: Context{ Location: "../../examples/app", }, @@ -218,7 +219,7 @@ func TestBuild(t *testing.T) { }, }, }, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Location: "../../examples/app/Dockerfile.namedContexts", }, }, @@ -226,7 +227,7 @@ func TestBuild(t *testing.T) { { name: "remoteContext", args: ImageArgs{ - Context: BuildContext{ + Context: &BuildContext{ Context: Context{ Location: "https://raw.githubusercontent.com/pulumi/pulumi-docker/api-types/provider/testdata/Dockerfile", }, @@ -236,12 +237,12 @@ func TestBuild(t *testing.T) { { name: "remoteContextWithInline", args: ImageArgs{ - Context: BuildContext{ + Context: &BuildContext{ Context: Context{ Location: "https://github.com/docker-library/hello-world.git", }, }, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Inline: dedent(` FROM busybox COPY hello.c ./ @@ -253,7 +254,7 @@ func TestBuild(t *testing.T) { name: "inline", args: ImageArgs{ Context: exampleContext, - Dockerfile: Dockerfile{ + Dockerfile: &Dockerfile{ Inline: dedent(` FROM alpine RUN echo 👍 diff --git a/provider/internal/context.go b/provider/internal/context.go index 5dc66ca..168aad0 100644 --- a/provider/internal/context.go +++ b/provider/internal/context.go @@ -54,6 +54,13 @@ type BuildContext struct { Named NamedContexts `pulumi:"named,optional"` } +func (bc *BuildContext) namedMap() map[string]string { + if bc == nil { + return nil + } + return bc.Named.Map() +} + // NamedContexts correspond to Docker's `--build-context name=path` options. // The path can be local or a remote URL. type NamedContexts map[string]Context @@ -84,23 +91,31 @@ func (c *Context) Annotate(a infer.Annotator) { // validate returns a non-nil CheckError if the Context is invalid. The // returned Dockerfile may have defaults set to match Docker's default // handling. The returned Dockerfile should be validated separately. -func (c *Context) validate(preview bool, d Dockerfile) (Dockerfile, error) { +func (bc *BuildContext) validate(preview bool, d *Dockerfile) (*Dockerfile, *Context, error) { + if d == nil { + d = &Dockerfile{} + } + c := &Context{} + if bc != nil { + c = &bc.Context + } + if c.Location == "" && preview { // The field is required so we normally wouldn't need to check if it // exists, but during previews it can still be empty if the value is // unknown. This isn't an error, but it does prevent us from performing // a build later. - return d, nil + return d, c, nil } if buildx.IsRemoteURL(c.Location) { // We assume remote URLs are always valid. - return d, nil + return d, c, nil } abs, err := filepath.Abs(c.Location) if err != nil { - return d, newCheckFailure(err, "context.location") + return d, c, newCheckFailure(err, "context.location") } if d.Location == "" && d.Inline == "" { @@ -111,17 +126,17 @@ func (c *Context) validate(preview bool, d Dockerfile) (Dockerfile, error) { if isLocalDir(afero.NewOsFs(), abs) { // Our context exists -- nothing else to check. - return d, nil + return d, c, nil } if c.Location != "-" { - return d, newCheckFailure( + return d, c, newCheckFailure( fmt.Errorf("%q: not a valid directory or URL", c.Location), "context.location", ) } - return d, nil + return d, c, nil } // Annotate sets docstrings on BuildContext. diff --git a/provider/internal/context_test.go b/provider/internal/context_test.go index 4b3c09f..71b0645 100644 --- a/provider/internal/context_test.go +++ b/provider/internal/context_test.go @@ -96,7 +96,8 @@ func TestValidateContext(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - d, err := tt.c.validate(tt.preview, tt.givenD) + bc := &BuildContext{Context: tt.c} + d, _, err := bc.validate(tt.preview, &tt.givenD) if tt.wantErr == "" { assert.NoError(t, err) diff --git a/provider/internal/dockerfile.go b/provider/internal/dockerfile.go index 1f02e8e..2ff5790 100644 --- a/provider/internal/dockerfile.go +++ b/provider/internal/dockerfile.go @@ -54,7 +54,7 @@ func (d *Dockerfile) Annotate(a infer.Annotator) { `)) } -func (d *Dockerfile) validate(preview bool, c Context) error { +func (d *Dockerfile) validate(preview bool, c *Context) error { if d.Location != "" && d.Inline != "" { return newCheckFailure( errors.New(`only specify "file" or "inline", not both`), @@ -88,7 +88,7 @@ func (d *Dockerfile) validate(preview bool, c Context) error { return nil } - if !preview && !buildx.IsRemoteURL(c.Location) { + if !preview && c != nil && !buildx.IsRemoteURL(c.Location) { return newCheckFailure(errors.New("missing 'location' or 'inline'"), "dockerfile") } diff --git a/provider/internal/dockerfile_test.go b/provider/internal/dockerfile_test.go index 7c8d93c..bd9fc74 100644 --- a/provider/internal/dockerfile_test.go +++ b/provider/internal/dockerfile_test.go @@ -90,7 +90,7 @@ func TestValidateDockerfile(t *testing.T) { t.Run(tt.name, func(t *testing.T) { t.Parallel() - err := tt.d.validate(tt.preview, tt.givenC) + err := tt.d.validate(tt.preview, &tt.givenC) if tt.wantErr == "" { assert.NoError(t, err) diff --git a/provider/internal/export.go b/provider/internal/export.go index 2f7752f..0b41a2d 100644 --- a/provider/internal/export.go +++ b/provider/internal/export.go @@ -386,9 +386,9 @@ func (c ExportWithOCI) String() string { // ExportWithCompression is an export with options to configure compression // settings. type ExportWithCompression struct { - Compression CompressionType `pulumi:"compression,optional"` - CompressionLevel int `pulumi:"compressionLevel,optional"` - ForceCompression *bool `pulumi:"forceCompression,optional"` + Compression *CompressionType `pulumi:"compression,optional"` + CompressionLevel int `pulumi:"compressionLevel,optional"` + ForceCompression *bool `pulumi:"forceCompression,optional"` } // Annotate sets docstrings and defaults on ExportWithCompression. @@ -407,8 +407,8 @@ func (e ExportWithCompression) String() string { return "" } parts := []string{} - if e.Compression != "" { - parts = append(parts, fmt.Sprintf("compression=%s", e.Compression)) + if e.Compression != nil { + parts = append(parts, fmt.Sprintf("compression=%s", *e.Compression)) } if e.CompressionLevel > 0 { cl := e.CompressionLevel diff --git a/provider/internal/export_test.go b/provider/internal/export_test.go index b91d31a..60ba4ea 100644 --- a/provider/internal/export_test.go +++ b/provider/internal/export_test.go @@ -93,6 +93,7 @@ func TestValidateExport(t *testing.T) { func TestExportString(t *testing.T) { t.Parallel() + gzip := Gzip tests := []struct { name string given Export @@ -113,13 +114,13 @@ func TestExportString(t *testing.T) { given: Export{Registry: &ExportRegistry{ ExportImage: ExportImage{ ExportWithCompression: ExportWithCompression{ - Compression: "gz2", + Compression: &gzip, CompressionLevel: 100, ForceCompression: pulumi.BoolRef(true), }, }, }}, - want: "type=registry,compression=gz2,compression-level=22,force-compression=true", + want: "type=registry,compression=gzip,compression-level=22,force-compression=true", }, { name: "registry-without-push", diff --git a/provider/internal/image.go b/provider/internal/image.go index 91e8f9c..0806484 100644 --- a/provider/internal/image.go +++ b/provider/internal/image.go @@ -93,15 +93,15 @@ type ImageArgs struct { AddHosts []string `pulumi:"addHosts,optional"` BuildArgs map[string]string `pulumi:"buildArgs,optional"` BuildOnPreview *bool `pulumi:"buildOnPreview,optional"` - Builder BuilderConfig `pulumi:"builder,optional"` + Builder *BuilderConfig `pulumi:"builder,optional"` CacheFrom []CacheFrom `pulumi:"cacheFrom,optional"` CacheTo []CacheTo `pulumi:"cacheTo,optional"` - Context BuildContext `pulumi:"context,optional"` - Dockerfile Dockerfile `pulumi:"dockerfile,optional"` + Context *BuildContext `pulumi:"context,optional"` + Dockerfile *Dockerfile `pulumi:"dockerfile,optional"` Exports []Export `pulumi:"exports,optional"` Labels map[string]string `pulumi:"labels,optional"` Load bool `pulumi:"load,optional"` - Network NetworkMode `pulumi:"network,optional"` + Network *NetworkMode `pulumi:"network,optional"` NoCache bool `pulumi:"noCache,optional"` Platforms []Platform `pulumi:"platforms,optional"` Pull bool `pulumi:"pull,optional"` @@ -555,13 +555,13 @@ func (ia *ImageArgs) validate(preview bool) (controllerapi.BuildOptions, error) ) } - dockerfile, err := ia.Context.validate(preview, ia.Dockerfile) + dockerfile, context, err := ia.Context.validate(preview, ia.Dockerfile) if err != nil { multierr = errors.Join(multierr, err) } ia.Dockerfile = dockerfile - if err := ia.Dockerfile.validate(preview, ia.Context.Context); err != nil { + if err := ia.Dockerfile.validate(preview, context); err != nil { multierr = errors.Join(multierr, err) } @@ -644,19 +644,24 @@ func (ia *ImageArgs) validate(preview bool) (controllerapi.BuildOptions, error) }) } + builder := BuilderConfig{} + if normalized.Builder != nil { + builder = *normalized.Builder + } + opts := controllerapi.BuildOptions{ BuildArgs: normalized.BuildArgs, - Builder: normalized.Builder.Name, + Builder: builder.Name, CacheFrom: cacheFrom, CacheTo: cacheTo, - ContextPath: normalized.Context.Location, + ContextPath: context.Location, DockerfileName: dockerfile.Location, Exports: exports, ExtraHosts: normalized.AddHosts, Labels: normalized.Labels, - NetworkMode: string(normalized.Network), + NetworkMode: normalized.Network.String(), NoCache: normalized.NoCache, - NamedContexts: normalized.Context.Named.Map(), + NamedContexts: normalized.Context.namedMap(), Platforms: platforms, Pull: normalized.Pull, Secrets: secrets, @@ -926,7 +931,7 @@ func (*Image) Diff( if olds.Load != news.Load { diff["load"] = update } - if olds.Network != news.Network { + if !reflect.DeepEqual(olds.Network, news.Network) { diff["network"] = update } if !reflect.DeepEqual(olds.NoCache, news.NoCache) { diff --git a/provider/internal/image_test.go b/provider/internal/image_test.go index 0f3b0b1..c1bdb0d 100644 --- a/provider/internal/image_test.go +++ b/provider/internal/image_test.go @@ -365,12 +365,13 @@ func TestRead(t *testing.T) { func TestImageDiff(t *testing.T) { t.Parallel() emptyDir := t.TempDir() + host := Host hash, err := hashBuildContext(emptyDir, "", nil) require.NoError(t, err) baseArgs := ImageArgs{ - Context: BuildContext{Context: Context{Location: emptyDir}}, - Dockerfile: Dockerfile{Location: "testdata/noop"}, + Context: &BuildContext{Context: Context{Location: emptyDir}}, + Dockerfile: &Dockerfile{Location: "testdata/noop"}, Tags: []string{}, } baseState := ImageState{ @@ -414,6 +415,7 @@ func TestImageDiff(t *testing.T) { { name: "no diff if pull=true but no exports", olds: func(_ *testing.T, is ImageState) ImageState { + fmt.Println("WHOA NELLY") is.Pull = true return is }, @@ -566,7 +568,7 @@ func TestImageDiff(t *testing.T) { name: "diff if context changes", olds: func(*testing.T, ImageState) ImageState { return baseState }, news: func(_ *testing.T, a ImageArgs) ImageArgs { - a.Context.Location = "testdata/ignores" + a.Context = &BuildContext{Context: Context{Location: "testdata/ignores"}} return a }, wantChanges: true, @@ -575,7 +577,7 @@ func TestImageDiff(t *testing.T) { name: "diff if named context changes", olds: func(*testing.T, ImageState) ImageState { return baseState }, news: func(_ *testing.T, a ImageArgs) ImageArgs { - a.Context.Named = NamedContexts{"foo": Context{Location: "bar"}} + a.Context = &BuildContext{Named: NamedContexts{"foo": Context{Location: "bar"}}} return a }, wantChanges: true, @@ -584,7 +586,7 @@ func TestImageDiff(t *testing.T) { name: "diff if network changes", olds: func(*testing.T, ImageState) ImageState { return baseState }, news: func(_ *testing.T, a ImageArgs) ImageArgs { - a.Network = Host + a.Network = &host return a }, wantChanges: true, @@ -593,7 +595,7 @@ func TestImageDiff(t *testing.T) { name: "diff if dockerfile location changes", olds: func(*testing.T, ImageState) ImageState { return baseState }, news: func(_ *testing.T, a ImageArgs) ImageArgs { - a.Dockerfile.Location = "testdata/ignores/basedir/Dockerfile" + a.Dockerfile = &Dockerfile{Location: "testdata/ignores/basedir/Dockerfile"} return a }, wantChanges: true, @@ -602,7 +604,7 @@ func TestImageDiff(t *testing.T) { name: "diff if dockerfile inline changes", olds: func(*testing.T, ImageState) ImageState { return baseState }, news: func(_ *testing.T, a ImageArgs) ImageArgs { - a.Dockerfile.Inline = "FROM scratch" + a.Dockerfile = &Dockerfile{Inline: "FROM scratch"} return a }, wantChanges: true, @@ -629,7 +631,7 @@ func TestImageDiff(t *testing.T) { name: "diff if builder changes", olds: func(*testing.T, ImageState) ImageState { return baseState }, news: func(_ *testing.T, a ImageArgs) ImageArgs { - a.Builder.Name = "foo" + a.Builder = &BuilderConfig{Name: "foo"} return a }, wantChanges: true, @@ -709,6 +711,8 @@ func TestImageDiff(t *testing.T) { for _, tt := range tests { tt := tt + baseState := baseState + baseArgs := baseArgs t.Run(tt.name, func(t *testing.T) { t.Parallel() resp, err := s.Diff(provider.DiffRequest{ @@ -729,7 +733,7 @@ func TestValidateImageArgs(t *testing.T) { args := ImageArgs{ Tags: []string{"a/bad:tag:format"}, Exports: []Export{{Raw: "badexport,-"}}, - Context: BuildContext{Context: Context{Location: "./testdata"}}, + Context: &BuildContext{Context: Context{Location: "./testdata"}}, Platforms: []Platform{","}, CacheFrom: []CacheFrom{{Raw: "=badcachefrom"}}, CacheTo: []CacheTo{{Raw: "=badcacheto"}}, @@ -747,7 +751,7 @@ func TestValidateImageArgs(t *testing.T) { t.Run("buildOnPreview", func(t *testing.T) { t.Parallel() args := ImageArgs{ - Context: BuildContext{Context: Context{Location: "testdata/noop"}}, + Context: &BuildContext{Context: Context{Location: "testdata/noop"}}, Tags: []string{"my-tag"}, Exports: []Export{{Registry: &ExportRegistry{ExportImage{Push: pulumi.BoolRef(true)}}}}, } @@ -775,12 +779,12 @@ func TestValidateImageArgs(t *testing.T) { "known": "value", "": "", }, - Builder: BuilderConfig{}, + Builder: nil, CacheFrom: []CacheFrom{{GHA: &CacheFromGitHubActions{}}, {Raw: ""}}, CacheTo: []CacheTo{{GHA: &CacheToGitHubActions{}}, {Raw: ""}}, - Context: BuildContext{}, + Context: nil, Exports: []Export{{Raw: ""}}, - Dockerfile: Dockerfile{}, + Dockerfile: nil, Platforms: []Platform{"linux/amd64", ""}, Registries: []Registry{ { @@ -803,7 +807,7 @@ func TestValidateImageArgs(t *testing.T) { t.Run("disabled caches", func(t *testing.T) { t.Parallel() args := ImageArgs{ - Context: BuildContext{Context: Context{Location: "testdata/noop"}}, + Context: &BuildContext{Context: Context{Location: "testdata/noop"}}, CacheFrom: []CacheFrom{{Raw: "type=registry", Disabled: true}}, CacheTo: []CacheTo{{Raw: "type=registry", Disabled: true}}, Exports: []Export{{Raw: "type=registry", Disabled: true}}, @@ -853,7 +857,8 @@ func TestValidateImageArgs(t *testing.T) { for _, d := range []Dockerfile{ {Location: path}, {Inline: string(data)}, } { - args := ImageArgs{Dockerfile: d} + d := d + args := ImageArgs{Dockerfile: &d} _, err := args.validate(false) assert.ErrorContains(t, err, "unknown instruction: RUNN (did you mean RUN?)") } @@ -943,13 +948,14 @@ func TestToBuild(t *testing.T) { ctrl := gomock.NewController(t) pctx := NewMockProviderContext(ctrl) pctx.EXPECT().Log(gomock.Any(), gomock.Any()).AnyTimes() + max := Max ia := ImageArgs{ Tags: []string{"foo", "bar"}, Platforms: []Platform{"linux/amd64"}, - Context: BuildContext{Context: Context{Location: "testdata/noop"}}, + Context: &BuildContext{Context: Context{Location: "testdata/noop"}}, CacheTo: []CacheTo{ - {GHA: &CacheToGitHubActions{CacheWithMode: CacheWithMode{Max}}}, + {GHA: &CacheToGitHubActions{CacheWithMode: CacheWithMode{&max}}}, { Registry: &CacheToRegistry{ CacheFromRegistry: CacheFromRegistry{Ref: "docker.io/foo/bar"}, diff --git a/provider/internal/index.go b/provider/internal/index.go index e7c0de9..250d57b 100644 --- a/provider/internal/index.go +++ b/provider/internal/index.go @@ -47,10 +47,10 @@ type Index struct{} // IndexArgs instantiate an Index. type IndexArgs struct { - Tag string `pulumi:"tag"` - Sources []string `pulumi:"sources"` - Push bool `pulumi:"push,optional"` - Registry Registry `pulumi:"registry,optional"` + Tag string `pulumi:"tag"` + Sources []string `pulumi:"sources"` + Push bool `pulumi:"push,optional"` + Registry *Registry `pulumi:"registry,optional"` } // IndexState captures the state of an Index. @@ -268,14 +268,20 @@ func (i *Index) Diff( if !reflect.DeepEqual(olds.Sources, news.Sources) { diff["sources"] = update } - if olds.Registry.Address != news.Registry.Address { - diff["registry.address"] = update - if olds.Registry.Address != "" { - diff["registry.address"] = replace + if olds.Registry != nil && news.Registry != nil { + if olds.Registry.Address != news.Registry.Address { + diff["registry.address"] = update + if olds.Registry.Address != "" { + diff["registry.address"] = replace + } + } + if olds.Registry.Username != news.Registry.Username { + diff["registry.username"] = update } } - if olds.Registry.Username != news.Registry.Username { - diff["registry.username"] = update + if (olds.Registry == nil && news.Registry != nil) || + (olds.Registry != nil && news.Registry == nil) { + diff["registry"] = update } // Intentionally ignore changes to registry.password @@ -301,9 +307,14 @@ func (i *Index) client( // We prefer auth from args, the provider, and state in that order. We // build a slice in reverse order because wrap() will overwrite earlier // entries with later ones. - auths := []Registry{state.Registry} + auths := []Registry{} + if state.Registry != nil { + auths = append(auths, *state.Registry) + } auths = append(auths, cfg.Registries...) - auths = append(auths, args.Registry) + if args.Registry != nil { + auths = append(auths, *args.Registry) + } return wrap(cfg.host, auths...) } diff --git a/provider/internal/index_test.go b/provider/internal/index_test.go index 7dd7bbb..f5122fd 100644 --- a/provider/internal/index_test.go +++ b/provider/internal/index_test.go @@ -138,7 +138,7 @@ func TestIndexDiff(t *testing.T) { { name: "no diff if registry password changes", olds: func(_ *testing.T, s IndexState) IndexState { - s.Registry = Registry{ + s.Registry = &Registry{ Address: "foo", Username: "foo", Password: "foo", @@ -146,7 +146,7 @@ func TestIndexDiff(t *testing.T) { return s }, news: func(_ *testing.T, a IndexArgs) IndexArgs { - a.Registry = Registry{ + a.Registry = &Registry{ Address: "foo", Username: "foo", Password: "DIFFERENT PASSWORD", @@ -159,7 +159,7 @@ func TestIndexDiff(t *testing.T) { name: "diff if registry added", olds: func(*testing.T, IndexState) IndexState { return baseState }, news: func(_ *testing.T, a IndexArgs) IndexArgs { - a.Registry = Registry{Address: "foo.com", Username: "foo", Password: "foo"} + a.Registry = &Registry{Address: "foo.com", Username: "foo", Password: "foo"} return a }, wantChanges: true, @@ -167,7 +167,7 @@ func TestIndexDiff(t *testing.T) { { name: "diff if registry user changes", olds: func(_ *testing.T, s IndexState) IndexState { - s.Registry = Registry{ + s.Registry = &Registry{ Address: "foo", Username: "foo", Password: "foo", @@ -175,7 +175,7 @@ func TestIndexDiff(t *testing.T) { return s }, news: func(_ *testing.T, a IndexArgs) IndexArgs { - a.Registry = Registry{ + a.Registry = &Registry{ Address: "DIFFERENT USER", Username: "foo", Password: "foo", diff --git a/provider/internal/network.go b/provider/internal/network.go index 0302f4c..50e2076 100644 --- a/provider/internal/network.go +++ b/provider/internal/network.go @@ -44,3 +44,10 @@ func (NetworkMode) Values() []infer.EnumValue[NetworkMode] { }, } } + +func (n *NetworkMode) String() string { + if n == nil { + return string(Default) + } + return string(*n) +} diff --git a/provider/internal/preview.go b/provider/internal/preview.go index facc9f0..fc81d00 100644 --- a/provider/internal/preview.go +++ b/provider/internal/preview.go @@ -96,8 +96,8 @@ func (k mapKeeper) keep(m map[string]string) map[string]string { type contextKeeper struct{ preview bool } -func (k contextKeeper) keep(bc BuildContext) BuildContext { - if !k.preview || len(bc.Named) == 0 { +func (k contextKeeper) keep(bc *BuildContext) *BuildContext { + if !k.preview || bc == nil || len(bc.Named) == 0 { return bc } @@ -110,7 +110,7 @@ func (k contextKeeper) keep(bc BuildContext) BuildContext { named[k] = v } - return BuildContext{ + return &BuildContext{ Context: Context{bc.Location}, Named: named, }