diff --git a/cmd/porter/bundle.go b/cmd/porter/bundle.go index 164dd30d9..54927b46a 100644 --- a/cmd/porter/bundle.go +++ b/cmd/porter/bundle.go @@ -89,6 +89,8 @@ The docker driver builds the bundle image using the local Docker host. To use a _ = f.MarkHidden("driver") // Hide the driver flag since there aren't any choices to make right now f.StringArrayVar(&opts.BuildArgs, "build-arg", nil, "Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times. Max length is 5,000 characters.") + f.StringArrayVar(&opts.BuildContexts, "build-context", nil, + "Define additional build context with specified contents. May be specified multiple times.") f.StringArrayVar(&opts.SSH, "ssh", nil, "SSH agent socket or keys to expose to the build (format: default|[=|[,]]). May be specified multiple times.") f.StringArrayVar(&opts.Secrets, "secret", nil, diff --git a/docs/content/docs/references/cli/build.md b/docs/content/docs/references/cli/build.md index 2a1e51afb..d8933b2ed 100644 --- a/docs/content/docs/references/cli/build.md +++ b/docs/content/docs/references/cli/build.md @@ -37,18 +37,19 @@ porter build [flags] ### Options ``` - --build-arg stringArray Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times. Max length is 5,000 characters. - --custom stringArray Define an individual key-value pair for the custom section in the form of NAME=VALUE. Use dot notation to specify a nested custom field. May be specified multiple times. Max length is 5,000 characters when used as a build argument. - -d, --dir string Path to the build context directory where all bundle assets are located. Defaults to the current directory. - -f, --file string Path to the Porter manifest. The path is relative to the build context directory. Defaults to porter.yaml in the current directory. - -h, --help help for build - --insecure-registry Don't require TLS when pulling referenced images - --name string Override the bundle name - --no-cache Do not use the Docker cache when building the bundle image. - --no-lint Do not run the linter - --secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). Custom values are accessible as build arguments in the template Dockerfile and in the manifest using template variables. May be specified multiple times. - --ssh stringArray SSH agent socket or keys to expose to the build (format: default|[=|[,]]). May be specified multiple times. - --version string Override the bundle version + --build-arg stringArray Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times. Max length is 5,000 characters. + --build-context stringArray Define additional build context with specified contents. May be specified multiple times. + --custom stringArray Define an individual key-value pair for the custom section in the form of NAME=VALUE. Use dot notation to specify a nested custom field. May be specified multiple times. Max length is 5,000 characters when used as a build argument. + -d, --dir string Path to the build context directory where all bundle assets are located. Defaults to the current directory. + -f, --file string Path to the Porter manifest. The path is relative to the build context directory. Defaults to porter.yaml in the current directory. + -h, --help help for build + --insecure-registry Don't require TLS when pulling referenced images + --name string Override the bundle name + --no-cache Do not use the Docker cache when building the bundle image. + --no-lint Do not run the linter + --secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). Custom values are accessible as build arguments in the template Dockerfile and in the manifest using template variables. May be specified multiple times. + --ssh stringArray SSH agent socket or keys to expose to the build (format: default|[=|[,]]). May be specified multiple times. + --version string Override the bundle version ``` ### Options inherited from parent commands diff --git a/docs/content/docs/references/cli/bundles_build.md b/docs/content/docs/references/cli/bundles_build.md index f9ca1fffd..8ccfc1f68 100644 --- a/docs/content/docs/references/cli/bundles_build.md +++ b/docs/content/docs/references/cli/bundles_build.md @@ -37,18 +37,19 @@ porter bundles build [flags] ### Options ``` - --build-arg stringArray Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times. Max length is 5,000 characters. - --custom stringArray Define an individual key-value pair for the custom section in the form of NAME=VALUE. Use dot notation to specify a nested custom field. May be specified multiple times. Max length is 5,000 characters when used as a build argument. - -d, --dir string Path to the build context directory where all bundle assets are located. Defaults to the current directory. - -f, --file string Path to the Porter manifest. The path is relative to the build context directory. Defaults to porter.yaml in the current directory. - -h, --help help for build - --insecure-registry Don't require TLS when pulling referenced images - --name string Override the bundle name - --no-cache Do not use the Docker cache when building the bundle image. - --no-lint Do not run the linter - --secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). Custom values are accessible as build arguments in the template Dockerfile and in the manifest using template variables. May be specified multiple times. - --ssh stringArray SSH agent socket or keys to expose to the build (format: default|[=|[,]]). May be specified multiple times. - --version string Override the bundle version + --build-arg stringArray Set build arguments in the template Dockerfile (format: NAME=VALUE). May be specified multiple times. Max length is 5,000 characters. + --build-context stringArray Define additional build context with specified contents. May be specified multiple times. + --custom stringArray Define an individual key-value pair for the custom section in the form of NAME=VALUE. Use dot notation to specify a nested custom field. May be specified multiple times. Max length is 5,000 characters when used as a build argument. + -d, --dir string Path to the build context directory where all bundle assets are located. Defaults to the current directory. + -f, --file string Path to the Porter manifest. The path is relative to the build context directory. Defaults to porter.yaml in the current directory. + -h, --help help for build + --insecure-registry Don't require TLS when pulling referenced images + --name string Override the bundle name + --no-cache Do not use the Docker cache when building the bundle image. + --no-lint Do not run the linter + --secret stringArray Secret file to expose to the build (format: id=mysecret,src=/local/secret). Custom values are accessible as build arguments in the template Dockerfile and in the manifest using template variables. May be specified multiple times. + --ssh stringArray SSH agent socket or keys to expose to the build (format: default|[=|[,]]). May be specified multiple times. + --version string Override the bundle version ``` ### Options inherited from parent commands diff --git a/pkg/build/build.go b/pkg/build/build.go index 7e2829faf..f0f08b04c 100644 --- a/pkg/build/build.go +++ b/pkg/build/build.go @@ -61,6 +61,9 @@ type BuildImageOptions struct { // BuildArgs is the set of docker build --build-arg specified. BuildArgs []string + // BuildContexts is the set of docker build --build-context specified. + BuildContexts []string + // NoCache is the docker build --no-cache flag specified. NoCache bool } diff --git a/pkg/build/buildkit/buildx.go b/pkg/build/buildkit/buildx.go index a951828de..d14fe07aa 100644 --- a/pkg/build/buildkit/buildx.go +++ b/pkg/build/buildkit/buildx.go @@ -120,6 +120,8 @@ func (b *Builder) BuildBundleImage(ctx context.Context, manifest *manifest.Manif } span.SetAttributes(tracing.ObjectAttribute("build-args", args)) + buildContexts := parseBuildContexts(opts.BuildContexts) + buildxOpts := map[string]buildx.Options{ "default": { Tags: []string{manifest.Image}, @@ -127,6 +129,7 @@ func (b *Builder) BuildBundleImage(ctx context.Context, manifest *manifest.Manif ContextPath: b.Getwd(), DockerfilePath: b.getDockerfilePath(), InStream: buildx.NewSyncMultiReader(b.In), + NamedContexts: buildContexts, }, BuildArgs: args, Session: currentSession, @@ -243,6 +246,26 @@ func parseBuildArgs(unparsed []string, parsed map[string]string) { } } +func parseBuildContexts(unparsed []string) map[string]buildx.NamedContext { + parsed := make(map[string]buildx.NamedContext) + + for _, arg := range unparsed { + parts := strings.SplitN(arg, "=", 2) + if len(parts) < 2 { + // ignore --build-context with only one part + continue + } + + name := parts[0] + value := parts[1] + parsed[name] = buildx.NamedContext{ + Path: value, + } + } + + return parsed +} + func (b *Builder) TagBundleImage(ctx context.Context, origTag, newTag string) error { ctx, log := tracing.StartSpan(ctx, attribute.String("source-tag", origTag), attribute.String("destination-tag", newTag)) defer log.EndSpan() diff --git a/pkg/build/buildkit/buildx_test.go b/pkg/build/buildkit/buildx_test.go index 775d4a9b8..e8ebcc908 100644 --- a/pkg/build/buildkit/buildx_test.go +++ b/pkg/build/buildkit/buildx_test.go @@ -8,6 +8,7 @@ import ( "get.porter.sh/porter/pkg/build" "get.porter.sh/porter/pkg/config" "get.porter.sh/porter/pkg/manifest" + buildx "github.com/docker/buildx/build" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -33,6 +34,26 @@ func Test_parseBuildArgs(t *testing.T) { } } +func Test_parseBuildContexts(t *testing.T) { + testcases := []struct { + name string + inputArgs []string + wantArgs map[string]buildx.NamedContext + }{ + {name: "valid args", inputArgs: []string{"A=1", "B=2=2", "C="}, + wantArgs: map[string]buildx.NamedContext{"A": {Path: "1"}, "B": {Path: "2=2"}, "C": {}}}, + {name: "missing equal sign", inputArgs: []string{"A"}, + wantArgs: map[string]buildx.NamedContext{}}, + } + + for _, tc := range testcases { + t.Run(tc.name, func(t *testing.T) { + var gotArgs = parseBuildContexts(tc.inputArgs) + assert.Equal(t, tc.wantArgs, gotArgs) + }) + } +} + func Test_flattenMap(t *testing.T) { tt := []struct { desc string