diff --git a/examples/simple-app-build-local-mvn/build.yml b/examples/simple-app-build-local-mvn/build.yml new file mode 100644 index 00000000..cfb7c34a --- /dev/null +++ b/examples/simple-app-build-local-mvn/build.yml @@ -0,0 +1,26 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: kbld-simple-app-build-local-bazel +spec: + selector: + matchLabels: + app: kbld-simple-app-build-local-bazel + template: + metadata: + labels: + app: kbld-simple-app-build-local-bazel + spec: + containers: + - name: my-app + image: simple-app +--- +apiVersion: kbld.k14s.io/v1alpha1 +kind: Config +sources: +- image: simple-app + path: test/e2e/assets/simple-app + maven: + run: + target: helloworld + name: simple-app diff --git a/pkg/kbld/builder/docker/docker.go b/pkg/kbld/builder/docker/docker.go index 5fb14330..51cd0a3a 100644 --- a/pkg/kbld/builder/docker/docker.go +++ b/pkg/kbld/builder/docker/docker.go @@ -308,6 +308,8 @@ func (d Docker) Inspect(ref string) (InspectData, error) { cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf + d.logger.NewPrefixedWriter(ref + " | ").Write([]byte(fmt.Sprintf("running command: %s\n", cmd))) + err := cmd.Run() if err != nil { return InspectData{}, err diff --git a/pkg/kbld/builder/maven/jib.go b/pkg/kbld/builder/maven/jib.go new file mode 100644 index 00000000..45f2906c --- /dev/null +++ b/pkg/kbld/builder/maven/jib.go @@ -0,0 +1,80 @@ +package maven + +import ( + "bytes" + ctlbdk "carvel.dev/kbld/pkg/kbld/builder/docker" + "carvel.dev/kbld/pkg/kbld/config" + ctllog "carvel.dev/kbld/pkg/kbld/logger" + "fmt" + "io" + "os/exec" + "path/filepath" + "regexp" +) + +var defaultImageTag = "latest" +var ImageID = regexp.MustCompile("(sha256:)([0-9a-z]+)") + +type Jib struct { + docker ctlbdk.Docker + logger ctllog.Logger +} + +func NewMavenJib(docker ctlbdk.Docker, logger ctllog.Logger) Jib { + return Jib{docker: docker, logger: logger} +} + +func (b *Jib) Run(image, directory string, opts config.SourceJibRunOpts) (ctlbdk.TmpRef, error) { + + prefixedLogger := b.logger.NewPrefixedWriter(image + " | ") + + prefixedLogger.Write([]byte(fmt.Sprintf("starting build (using kbld jib build): %s\n", directory))) + defer prefixedLogger.Write([]byte("finished build (using kbld jib build)\n")) + + tag := opts.Tag + if tag == nil { + tag = &defaultImageTag + } + targetImage := fmt.Sprintf("%s:%s", image, *tag) + + var stdoutBuf, stderrBuf bytes.Buffer + + if opts.Target == nil { + return ctlbdk.TmpRef{}, fmt.Errorf("Expected target to be specified, but was not") + } + + // Base arguments for the Maven Jib command. + cmdArgs := []string{ + "compile", + "jib:dockerBuild", + "-Dimage=" + targetImage, + "-Djib.allowInsecureRegistries=true", + } + + if opts.RawOptions != nil { + cmdArgs = append(cmdArgs, *opts.RawOptions...) + } + + cmd := exec.Command("mvn", cmdArgs...) + + cmd.Dir = filepath.Join(directory, *opts.Target) + cmd.Stdout = io.MultiWriter(&stdoutBuf, prefixedLogger) + cmd.Stderr = io.MultiWriter(&stderrBuf, prefixedLogger) + + prefixedLogger.Write([]byte(fmt.Sprintf("running command: %s\n", cmd))) + + if err := cmd.Run(); err != nil { + prefixedLogger.Write([]byte(fmt.Sprintf("error: %s\n", err))) + return ctlbdk.TmpRef{}, err + } + + inspectData, err := b.docker.Inspect(targetImage) + if err != nil { + prefixedLogger.Write([]byte(fmt.Sprintf("inspect error: %s\n", err))) + return ctlbdk.TmpRef{}, err + } + + prefixedLogger.Write([]byte(fmt.Sprintf("digest: %s, id: %s\n", inspectData.RepoDigests, inspectData.ID))) + + return b.docker.RetagStable(ctlbdk.NewTmpRef(inspectData.ID), image, inspectData.ID, prefixedLogger) +} diff --git a/pkg/kbld/config/config.go b/pkg/kbld/config/config.go index 3e4a4afd..8c857ee6 100644 --- a/pkg/kbld/config/config.go +++ b/pkg/kbld/config/config.go @@ -61,6 +61,7 @@ type Source struct { KubectlBuildkit *SourceKubectlBuildkitOpts Ko *SourceKoOpts Bazel *SourceBazelOpts + Maven *SourceJibOpts } type ImageOverride struct { diff --git a/pkg/kbld/config/config_jib.go b/pkg/kbld/config/config_jib.go new file mode 100644 index 00000000..efad76d0 --- /dev/null +++ b/pkg/kbld/config/config_jib.go @@ -0,0 +1,14 @@ +// Copyright 2024 The Carvel Authors. +// SPDX-License-Identifier: Apache-2.0 + +package config + +type SourceJibOpts struct { + Run SourceJibRunOpts +} + +type SourceJibRunOpts struct { + Target *string `json:"target"` + RawOptions *[]string `json:"rawOptions"` + Tag *string `json:"tag,omitempty"` +} diff --git a/pkg/kbld/image/built.go b/pkg/kbld/image/built.go index c4dc3fb8..6cbb7f9e 100644 --- a/pkg/kbld/image/built.go +++ b/pkg/kbld/image/built.go @@ -4,6 +4,7 @@ package image import ( + maven "carvel.dev/kbld/pkg/kbld/builder/maven" "path/filepath" ctlbbz "carvel.dev/kbld/pkg/kbld/builder/bazel" @@ -25,13 +26,14 @@ type BuiltImage struct { kubectlBuildkit ctlbkb.KubectlBuildkit ko ctlbko.Ko bazel ctlbbz.Bazel + maven maven.Jib } func NewBuiltImage(url string, buildSource ctlconf.Source, imgDst *ctlconf.ImageDestination, docker ctlbdk.Docker, dockerBuildx ctlbdk.Buildx, pack ctlbpk.Pack, - kubectlBuildkit ctlbkb.KubectlBuildkit, ko ctlbko.Ko, bazel ctlbbz.Bazel) BuiltImage { + kubectlBuildkit ctlbkb.KubectlBuildkit, ko ctlbko.Ko, bazel ctlbbz.Bazel, maven maven.Jib) BuiltImage { - return BuiltImage{url, buildSource, imgDst, docker, dockerBuildx, pack, kubectlBuildkit, ko, bazel} + return BuiltImage{url, buildSource, imgDst, docker, dockerBuildx, pack, kubectlBuildkit, ko, bazel, maven} } func (i BuiltImage) URL() (string, []ctlconf.Origin, error) { @@ -84,6 +86,14 @@ func (i BuiltImage) URL() (string, []ctlconf.Origin, error) { urlRepo, i.buildSource.Path, i.imgDst, *i.buildSource.Docker.Buildx) return url, origins, err + case i.buildSource.Maven != nil: + dockerTmpRef, err := i.maven.Run(urlRepo, i.buildSource.Path, i.buildSource.Maven.Run) + if err != nil { + return "", nil, err + } + + return i.optionalPushWithDocker(dockerTmpRef, origins) + // Fall back on Docker by default default: if i.buildSource.Docker == nil { diff --git a/pkg/kbld/image/factory.go b/pkg/kbld/image/factory.go index 8a708948..376726b1 100644 --- a/pkg/kbld/image/factory.go +++ b/pkg/kbld/image/factory.go @@ -4,6 +4,7 @@ package image import ( + maven2 "carvel.dev/kbld/pkg/kbld/builder/maven" "fmt" ctlbbz "carvel.dev/kbld/pkg/kbld/builder/bazel" @@ -72,9 +73,10 @@ func (f Factory) New(url string) Image { kubectlBuildkit := ctlbkb.NewKubectlBuildkit(f.logger) ko := ctlbko.NewKo(f.logger) bazel := ctlbbz.NewBazel(docker, f.logger) + maven := maven2.NewMavenJib(docker, f.logger) var builtImg Image = NewBuiltImage(url, srcConf, imgDstConf, - docker, dockerBuildx, pack, kubectlBuildkit, ko, bazel) + docker, dockerBuildx, pack, kubectlBuildkit, ko, bazel, maven) if imgDstConf != nil { builtImg = NewTaggedImage(builtImg, *imgDstConf, f.registry) diff --git a/test/e2e/assets/simple-app/helloworld/pom.xml b/test/e2e/assets/simple-app/helloworld/pom.xml new file mode 100644 index 00000000..6fa8c294 --- /dev/null +++ b/test/e2e/assets/simple-app/helloworld/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + example + helloworld + 1 + + + UTF-8 + 3.4.6 + 3.8.0 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + ${maven-compiler-plugin.version} + + 1.8 + 1.8 + + + + + + com.google.cloud.tools + jib-maven-plugin + ${jib-maven-plugin.version} + + + gcr.io/distroless/java + + + image-built-with-jib + + + + + package + + build + + + + + + + diff --git a/test/e2e/assets/simple-app/helloworld/src/main/java/example/HelloWorld.java b/test/e2e/assets/simple-app/helloworld/src/main/java/example/HelloWorld.java new file mode 100644 index 00000000..842bd9ee --- /dev/null +++ b/test/e2e/assets/simple-app/helloworld/src/main/java/example/HelloWorld.java @@ -0,0 +1,9 @@ +package example; + +public class HelloWorld { + + public static void main(String[] args) throws Exception { + System.out.println("Hello world"); + + } +}