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/go.mod b/go.mod index 1aaccb0d..678e09e6 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module carvel.dev/kbld go 1.23.8 require ( - carvel.dev/imgpkg v0.46.1 - carvel.dev/vendir v0.44.0 + carvel.dev/imgpkg v0.43.1 + carvel.dev/vendir v0.40.0 github.com/cppforlife/cobrautil v0.0.0-20221021151949-d60711905d65 github.com/cppforlife/go-cli-ui v0.0.0-20220428182907-73db60c7611a github.com/google/go-containerregistry v0.20.3 @@ -13,7 +13,7 @@ require ( github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 golang.org/x/sync v0.14.0 - k8s.io/apimachinery v0.32.1 + k8s.io/apimachinery v0.30.7 sigs.k8s.io/yaml v1.4.0 ) @@ -25,7 +25,6 @@ require ( github.com/docker/cli v27.5.0+incompatible // indirect github.com/docker/distribution v2.8.3+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.2 // indirect - github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/gogo/protobuf v1.3.2 // indirect github.com/google/gofuzz v1.2.0 // indirect @@ -45,7 +44,6 @@ require ( github.com/spf13/pflag v1.0.6 // indirect github.com/vbatts/tar-split v0.11.6 // indirect github.com/vito/go-interact v1.0.1 // indirect - github.com/x448/float16 v0.8.4 // indirect golang.org/x/mod v0.22.0 // indirect golang.org/x/net v0.38.0 // indirect golang.org/x/sys v0.32.0 // indirect @@ -58,5 +56,5 @@ require ( k8s.io/klog/v2 v2.130.1 // indirect k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect - sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect ) diff --git a/go.sum b/go.sum index 8bc4c421..c6b50030 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ -carvel.dev/imgpkg v0.46.1 h1:UOYaPllQJRsbzSl61IiNvmDZA5z4951i/KaSROAC1W0= -carvel.dev/imgpkg v0.46.1/go.mod h1:Q1E+7tpoiPbVNjb7HSmLZP7E1j0w6mWFzDarOXW1HiI= -carvel.dev/vendir v0.44.0 h1:vfq5KgGbbLlxHrE0prY7gZgiEQpjwo4lS2akCaVkcxA= -carvel.dev/vendir v0.44.0/go.mod h1:gslrJ0HPiy8gtJYsQZHzIVuGfOG0nfDKDupEm7uBWVQ= +carvel.dev/imgpkg v0.43.1 h1:AjvY2Rpz7FIRd1jxOHMyAZwAV6MiqKOLyjT+gzhznbI= +carvel.dev/imgpkg v0.43.1/go.mod h1:mLKnJumG8xtUY4ItDHZCj8XFfCwCdIr26pyxSvP3EPo= +carvel.dev/vendir v0.40.0 h1:JdhCp/EjAPGI8F5zoAVYwZHf1sPEFee19RpgGb3ciT8= +carvel.dev/vendir v0.40.0/go.mod h1:XPdluJu7322RZNx05AA4gYnV52aKywBdh7Ma12GuM2Q= github.com/carvel-dev/semver/v4 v4.0.1-0.20240402203627-beb83fbf25e4 h1:F4rZiMGZyC66j9VB7doVOE4tFHF1yNEihQlOuht4jmM= github.com/carvel-dev/semver/v4 v4.0.1-0.20240402203627-beb83fbf25e4/go.mod h1:4cFTBLAr/U11ykiEEQMccu4uJ1i0GS+atJmeETHCFtI= github.com/containerd/stargz-snapshotter/estargz v0.16.3 h1:7evrXtoh1mSbGj/pfRccTampEyKpjpOnS3CyiV1Ebr8= @@ -29,8 +29,6 @@ github.com/docker/docker-credential-helpers v0.8.2/go.mod h1:P3ci7E3lwkZg6XiHdRK github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= -github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= -github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= @@ -91,8 +89,8 @@ github.com/onsi/ginkgo v1.16.4 h1:29JGrr5oVBm5ulCWet69zQkzWipVXIol6ygQUe/EzNc= github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= -github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4= -github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= +github.com/onsi/gomega v1.31.0 h1:54UJxxj6cPInHS3a35wm6BK/F9nHYueZ1NVujHDrnXE= +github.com/onsi/gomega v1.31.0/go.mod h1:DW9aCi7U6Yi40wNVAvT6kzFnEVEI5n3DloYBiKiT6zk= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= @@ -119,8 +117,6 @@ github.com/vbatts/tar-split v0.11.6 h1:4SjTW5+PU11n6fZenf2IPoV8/tz3AaYHMWjf23env github.com/vbatts/tar-split v0.11.6/go.mod h1:dqKNtesIOr2j2Qv3W/cHjnvk9I8+G7oAkFDFN6TCBEI= github.com/vito/go-interact v1.0.1 h1:O8xi8c93bRUv2Tb/v6HdiuGc+WnWt+AQzF74MOOdlBs= github.com/vito/go-interact v1.0.1/go.mod h1:HrdHSJXD2yn1MhlTwSIMeFgQ5WftiIorszVGd3S/DAA= -github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= -github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= @@ -192,6 +188,7 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= @@ -200,15 +197,15 @@ 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.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= -k8s.io/apimachinery v0.32.1 h1:683ENpaCBjma4CYqsmZyhEzrGz6cjn1MY/X2jB2hkZs= -k8s.io/apimachinery v0.32.1/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE= +k8s.io/apimachinery v0.30.7 h1:CoQFxvzPFKwU1eJGN/8LgM3ZJBC3hKgvwGqRrL43uIY= +k8s.io/apimachinery v0.30.7/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc= k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8= sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA= -sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= 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..8ba3e4c4 --- /dev/null +++ b/pkg/kbld/builder/maven/jib.go @@ -0,0 +1,78 @@ +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" +) + +var defaultImageTag = "latest" + +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"); + + } +}