diff --git a/.github/pipeline-descriptor.yml b/.github/pipeline-descriptor.yml index 201c98f..f52582f 100644 --- a/.github/pipeline-descriptor.yml +++ b/.github/pipeline-descriptor.yml @@ -17,14 +17,28 @@ docker_credentials: password: ${{ secrets.JAVA_GCLOUD_SERVICE_ACCOUNT_KEY }} dependencies: -- id: maven - uses: docker://ghcr.io/paketo-buildpacks/actions/maven-dependency:main +- name: Maven 3 + id: maven + uses: docker://ghcr.io/paketo-buildpacks/actions/maven-dependency:main + version_pattern: "^3\\.[\\d]+\\.[\\d]+" with: - uri: https://repo1.maven.org/maven2 - group_id: org.apache.maven - artifact_id: apache-maven - classifier: bin - packaging: tar.gz + uri: https://repo1.maven.org/maven2 + group_id: org.apache.maven + artifact_id: apache-maven + classifier: bin + packaging: tar.gz + version_regex: ^3\\.[\\d]+\\.[\\d]+$ +- name: Maven 4 + id: maven + uses: docker://ghcr.io/paketo-buildpacks/actions/maven-dependency:main + version_pattern: "^4\\.[\\d]+\\.[\\d]+" + with: + uri: https://repo1.maven.org/maven2 + group_id: org.apache.maven + artifact_id: apache-maven + classifier: bin + packaging: tar.gz + version_regex: ^4\\.[\\d]+\\.[\\d]+-.*$ - id: mvnd uses: docker://ghcr.io/paketo-buildpacks/actions/github-release-dependency:main with: diff --git a/.github/workflows/pb-update-maven.yml b/.github/workflows/pb-update-maven-3.yml similarity index 85% rename from .github/workflows/pb-update-maven.yml rename to .github/workflows/pb-update-maven-3.yml index 07ffd91..420abea 100644 --- a/.github/workflows/pb-update-maven.yml +++ b/.github/workflows/pb-update-maven-3.yml @@ -1,4 +1,4 @@ -name: Update maven +name: Update Maven 3 "on": schedule: - cron: 0 5 * * 1-5 @@ -49,6 +49,7 @@ jobs: group_id: org.apache.maven packaging: tar.gz uri: https://repo1.maven.org/maven2 + version_regex: ^3\\.[\\d]+\\.[\\d]+$ - name: Update Buildpack Dependency id: buildpack run: |- @@ -97,18 +98,18 @@ jobs: SHA256: ${{ steps.dependency.outputs.sha256 }} URI: ${{ steps.dependency.outputs.uri }} VERSION: ${{ steps.dependency.outputs.version }} - VERSION_PATTERN: '[\d]+\.[\d]+\.[\d]+' + VERSION_PATTERN: ^3\.[\d]+\.[\d]+ - uses: peter-evans/create-pull-request@v4 with: author: ${{ secrets.JAVA_GITHUB_USERNAME }} <${{ secrets.JAVA_GITHUB_USERNAME }}@users.noreply.github.com> - body: Bumps `maven` from `${{ steps.buildpack.outputs.old-version }}` to `${{ steps.buildpack.outputs.new-version }}`. - branch: update/buildpack/maven + body: Bumps `Maven 3` from `${{ steps.buildpack.outputs.old-version }}` to `${{ steps.buildpack.outputs.new-version }}`. + branch: update/buildpack/maven-3 commit-message: |- - Bump maven from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }} + Bump Maven 3 from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }} - Bumps maven from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }}. + Bumps Maven 3 from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }}. delete-branch: true labels: ${{ steps.buildpack.outputs.version-label }}, type:dependency-upgrade signoff: true - title: Bump maven from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }} + title: Bump Maven 3 from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }} token: ${{ secrets.JAVA_GITHUB_TOKEN }} diff --git a/.github/workflows/pb-update-maven-4.yml b/.github/workflows/pb-update-maven-4.yml new file mode 100644 index 0000000..814157c --- /dev/null +++ b/.github/workflows/pb-update-maven-4.yml @@ -0,0 +1,115 @@ +name: Update Maven 4 +"on": + schedule: + - cron: 0 5 * * 1-5 + workflow_dispatch: {} +jobs: + update: + name: Update Buildpack Dependency + runs-on: + - ubuntu-latest + steps: + - uses: actions/setup-go@v3 + with: + go-version: "1.18" + - name: Install update-buildpack-dependency + run: | + #!/usr/bin/env bash + + set -euo pipefail + + go install -ldflags="-s -w" github.com/paketo-buildpacks/libpak/cmd/update-buildpack-dependency@latest + - name: Install yj + run: | + #!/usr/bin/env bash + + set -euo pipefail + + echo "Installing yj ${YJ_VERSION}" + + mkdir -p "${HOME}"/bin + echo "${HOME}/bin" >> "${GITHUB_PATH}" + + curl \ + --location \ + --show-error \ + --silent \ + --output "${HOME}"/bin/yj \ + "https://github.com/sclevine/yj/releases/download/v${YJ_VERSION}/yj-linux" + + chmod +x "${HOME}"/bin/yj + env: + YJ_VERSION: 5.0.0 + - uses: actions/checkout@v3 + - id: dependency + uses: docker://ghcr.io/paketo-buildpacks/actions/maven-dependency:main + with: + artifact_id: apache-maven + classifier: bin + group_id: org.apache.maven + packaging: tar.gz + uri: https://repo1.maven.org/maven2 + version_regex: ^4\\.[\\d]+\\.[\\d]+-.*$ + - name: Update Buildpack Dependency + id: buildpack + run: |- + #!/usr/bin/env bash + + set -euo pipefail + + OLD_VERSION=$(yj -tj < buildpack.toml | jq -r " + .metadata.dependencies[] | + select( .id == env.ID ) | + select( .version | test( env.VERSION_PATTERN ) ) | + .version") + + update-buildpack-dependency \ + --buildpack-toml buildpack.toml \ + --id "${ID}" \ + --version-pattern "${VERSION_PATTERN}" \ + --version "${VERSION}" \ + --cpe-pattern "${CPE_PATTERN:-}" \ + --cpe "${CPE:-}" \ + --purl-pattern "${PURL_PATTERN:-}" \ + --purl "${PURL:-}" \ + --uri "${URI}" \ + --sha256 "${SHA256}" + + git add buildpack.toml + git checkout -- . + + if [ "$(echo "$OLD_VERSION" | awk -F '.' '{print $1}')" != "$(echo "$VERSION" | awk -F '.' '{print $1}')" ]; then + LABEL="semver:major" + elif [ "$(echo "$OLD_VERSION" | awk -F '.' '{print $2}')" != "$(echo "$VERSION" | awk -F '.' '{print $2}')" ]; then + LABEL="semver:minor" + else + LABEL="semver:patch" + fi + + echo "::set-output name=old-version::${OLD_VERSION}" + echo "::set-output name=new-version::${VERSION}" + echo "::set-output name=version-label::${LABEL}" + env: + CPE: ${{ steps.dependency.outputs.cpe }} + CPE_PATTERN: "" + ID: maven + PURL: ${{ steps.dependency.outputs.purl }} + PURL_PATTERN: "" + SHA256: ${{ steps.dependency.outputs.sha256 }} + URI: ${{ steps.dependency.outputs.uri }} + VERSION: ${{ steps.dependency.outputs.version }} + VERSION_PATTERN: ^4\.[\d]+\.[\d]+ + - uses: peter-evans/create-pull-request@v4 + with: + author: ${{ secrets.JAVA_GITHUB_USERNAME }} <${{ secrets.JAVA_GITHUB_USERNAME }}@users.noreply.github.com> + body: Bumps `Maven 4` from `${{ steps.buildpack.outputs.old-version }}` to `${{ steps.buildpack.outputs.new-version }}`. + branch: update/buildpack/maven-4 + commit-message: |- + Bump Maven 4 from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }} + + Bumps Maven 4 from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }}. + delete-branch: true + labels: ${{ steps.buildpack.outputs.version-label }}, type:dependency-upgrade + signoff: true + title: Bump Maven 4 from ${{ steps.buildpack.outputs.old-version }} to ${{ steps.buildpack.outputs.new-version }} + token: ${{ secrets.JAVA_GITHUB_TOKEN }} diff --git a/README.md b/README.md index 4754280..cc691c1 100644 --- a/README.md +++ b/README.md @@ -31,16 +31,17 @@ The buildpack will do the following: ## Configuration -| Environment Variable | Description | -| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `$BP_MAVEN_BUILD_ARGUMENTS` | Configure the arguments to pass to Maven. Defaults to `-Dmaven.test.skip=true --no-transfer-progress package`. `--batch-mode` will be prepended to the argument list in environments without a TTY. | -| `$BP_MAVEN_BUILT_MODULE` | Configure the module to find application artifact in. Defaults to the root module (empty). | -| `$BP_MAVEN_BUILT_ARTIFACT` | Configure the built application artifact explicitly. Supersedes `$BP_MAVEN_BUILT_MODULE` Defaults to `target/*.[ejw]ar`. Can match a single file, multiple files or a directory. Can be one or more space separated patterns. | -| `$BP_MAVEN_POM_FILE` | Specifies a custom location to the project's `pom.xml` file. It should be a full path to the file under the `/workspace` directory or it should be relative to the root of the project (i.e. `/workspace'). Defaults to `pom.xml`. | -| `$BP_MAVEN_DAEMON_ENABLED` | Triggers apache maven-mvnd to be installed and configured for use instead of Maven. The default value is `false`. Set to `true` to use the Maven Daemon. | -| `$BP_MAVEN_SETTINGS_PATH` | Specifies a custom location to Maven's `settings.xml` file. If `$BP_MAVEN_SETTINGS_PATH` is set and a Maven binding is provided, the binding takes the higher precedence. | -| `$BP_INCLUDE_FILES` | Colon separated list of glob patterns to match source files. Any matched file will be retained in the final image. Defaults to `` (i.e. nothing). | -| `$BP_EXCLUDE_FILES` | Colon separated list of glob patterns to match source files. Any matched file will be specifically removed from the final image. If include patterns are also specified, then they are applied first and exclude patterns can be used to further reduce the fileset. | +| Environment Variable | Description | +| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `$BP_MAVEN_VERSION` | Configure the major Maven version (e.g. `3`, `4`). Since the buildpack only ships a single version of each supported line, updates to the buildpack can change the exact version of Maven installed. If you require a specific minor/patch version of Maven, use the Maven wrapper instead. | +| `$BP_MAVEN_BUILD_ARGUMENTS` | Configure the arguments to pass to Maven. Defaults to `-Dmaven.test.skip=true --no-transfer-progress package`. `--batch-mode` will be prepended to the argument list in environments without a TTY. | +| `$BP_MAVEN_BUILT_MODULE` | Configure the module to find application artifact in. Defaults to the root module (empty). | +| `$BP_MAVEN_BUILT_ARTIFACT` | Configure the built application artifact explicitly. Supersedes `$BP_MAVEN_BUILT_MODULE` Defaults to `target/*.[ejw]ar`. Can match a single file, multiple files or a directory. Can be one or more space separated patterns. | +| `$BP_MAVEN_POM_FILE` | Specifies a custom location to the project's `pom.xml` file. It should be a full path to the file under the `/workspace` directory or it should be relative to the root of the project (i.e. `/workspace'). Defaults to `pom.xml`. | +| `$BP_MAVEN_DAEMON_ENABLED` | Triggers apache maven-mvnd to be installed and configured for use instead of Maven. The default value is `false`. Set to `true` to use the Maven Daemon. | +| `$BP_MAVEN_SETTINGS_PATH` | Specifies a custom location to Maven's `settings.xml` file. If `$BP_MAVEN_SETTINGS_PATH` is set and a Maven binding is provided, the binding takes the higher precedence. | +| `$BP_INCLUDE_FILES` | Colon separated list of glob patterns to match source files. Any matched file will be retained in the final image. Defaults to `` (i.e. nothing). | +| `$BP_EXCLUDE_FILES` | Colon separated list of glob patterns to match source files. Any matched file will be specifically removed from the final image. If include patterns are also specified, then they are applied first and exclude patterns can be used to further reduce the fileset. | ## Bindings diff --git a/buildpack.toml b/buildpack.toml index 477c2ab..9f5b0b4 100644 --- a/buildpack.toml +++ b/buildpack.toml @@ -66,6 +66,12 @@ api = "0.7" description = "the path to a Maven settings file" name = "BP_MAVEN_SETTINGS_PATH" + [[metadata.configurations]] + build = true + default = "3" + description = "the Maven version" + name = "BP_MAVEN_VERSION" + [[metadata.configurations]] build = true default = "" @@ -92,6 +98,20 @@ api = "0.7" type = "Apache-2.0" uri = "https://www.apache.org/licenses/" + [[metadata.dependencies]] + cpes = ["cpe:2.3:a:apache:maven:4.0.0:*:*:*:*:*:*:*"] + id = "maven" + name = "Apache Maven" + purl = "pkg:generic/apache-maven@4.0.0" + sha256 = "4b133c01af2559501c13e6366149c65db87178d0ac354fd1f3204463b6bac7b2" + stacks = ["io.buildpacks.stacks.bionic", "io.paketo.stacks.tiny", "*"] + uri = "https://repo1.maven.org/maven2/org/apache/maven/apache-maven/4.0.0-alpha-2/apache-maven-4.0.0-alpha-2-bin.tar.gz" + version = "4.0.0" + + [[metadata.dependencies.licenses]] + type = "Apache-2.0" + uri = "https://www.apache.org/licenses/" + [[metadata.dependencies]] cpes = ["cpe:2.3:a:apache:mvnd:0.8.2:*:*:*:*:*:*:*"] id = "mvnd" diff --git a/maven/build.go b/maven/build.go index a5723f7..21f8fe1 100644 --- a/maven/build.go +++ b/maven/build.go @@ -95,7 +95,7 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { result.BOM.Entries = append(result.BOM.Entries, *be) } } else { - command, _, _, err = NewNoopMavenManager().Install() + command, _, _, err = NewNoopMavenManager(b.Logger).Install() if err != nil { return libcnb.BuildResult{}, fmt.Errorf("unable pick Maven command\n%w", err) } @@ -146,10 +146,10 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { func (b Build) installMaven(context libcnb.BuildContext) (string, libcnb.LayerContributor, *libcnb.BOMEntry, error) { // be careful changing this, the order does matter to a degree managers := []MavenManager{ - NewDaemonMavenManager(b.configResolver, b.depResolver, b.depCache, context.Layers.Path), - NewStandardMavenManager(context.Application.Path, b.configResolver, b.depResolver, b.depCache, context.Layers.Path), - NewWrapperMavenManager(context.Application.Path, b.configResolver, b.depResolver, b.depCache), - NewNoopMavenManager(), + NewDaemonMavenManager(b.configResolver, b.depResolver, b.depCache, context.Layers.Path, b.Logger), + NewStandardMavenManager(context.Application.Path, b.configResolver, b.depResolver, b.depCache, context.Layers.Path, b.Logger), + NewWrapperMavenManager(context.Application.Path, b.Logger), + NewNoopMavenManager(b.Logger), } for _, manager := range managers { diff --git a/maven/maven_manager.go b/maven/maven_manager.go index 538ddf7..196e0e9 100644 --- a/maven/maven_manager.go +++ b/maven/maven_manager.go @@ -27,12 +27,13 @@ type DaemonMavenManager struct { logger bard.Logger } -func NewDaemonMavenManager(configResolver libpak.ConfigurationResolver, depResolver libpak.DependencyResolver, depCache libpak.DependencyCache, layersPath string) DaemonMavenManager { +func NewDaemonMavenManager(configResolver libpak.ConfigurationResolver, depResolver libpak.DependencyResolver, depCache libpak.DependencyCache, layersPath string, logger bard.Logger) DaemonMavenManager { return DaemonMavenManager{ configResolver: configResolver, depResolver: depResolver, depCache: depCache, layersPath: layersPath, + logger: logger, } } @@ -66,12 +67,14 @@ type StandardMavenManager struct { logger bard.Logger } -func NewStandardMavenManager(appPath string, configResolver libpak.ConfigurationResolver, depResolver libpak.DependencyResolver, depCache libpak.DependencyCache, layersPath string) StandardMavenManager { +func NewStandardMavenManager(appPath string, configResolver libpak.ConfigurationResolver, depResolver libpak.DependencyResolver, depCache libpak.DependencyCache, layersPath string, logger bard.Logger) StandardMavenManager { return StandardMavenManager{ - appPath: appPath, - depResolver: depResolver, - depCache: depCache, - layersPath: layersPath, + appPath: appPath, + configResolver: configResolver, + depResolver: depResolver, + depCache: depCache, + layersPath: layersPath, + logger: logger, } } @@ -89,7 +92,9 @@ func (s StandardMavenManager) ShouldInstall() bool { // Install the standard JVM-based Maven distribution func (s StandardMavenManager) Install() (string, libcnb.LayerContributor, *libcnb.BOMEntry, error) { - dep, err := s.depResolver.Resolve("maven", "") + version, _ := s.configResolver.Resolve("BP_MAVEN_VERSION") + + dep, err := s.depResolver.Resolve("maven", version) if err != nil { return "", nil, nil, fmt.Errorf("unable to find dependency\n%w", err) } @@ -108,9 +113,10 @@ type WrapperMavenManager struct { logger bard.Logger } -func NewWrapperMavenManager(appPath string, configResolver libpak.ConfigurationResolver, depResolver libpak.DependencyResolver, depCache libpak.DependencyCache) WrapperMavenManager { +func NewWrapperMavenManager(appPath string, logger bard.Logger) WrapperMavenManager { return WrapperMavenManager{ appPath: appPath, + logger: logger, } } @@ -163,8 +169,10 @@ type NoopMavenManager struct { logger bard.Logger } -func NewNoopMavenManager() NoopMavenManager { - return NoopMavenManager{} +func NewNoopMavenManager(logger bard.Logger) NoopMavenManager { + return NoopMavenManager{ + logger: logger, + } } // ShouldInstall determines if Maven is on the $PATH diff --git a/maven/maven_manager_test.go b/maven/maven_manager_test.go index ca91b1c..42bb2c1 100644 --- a/maven/maven_manager_test.go +++ b/maven/maven_manager_test.go @@ -3,6 +3,7 @@ package maven_test import ( "bytes" "errors" + "io" "os" "path/filepath" "testing" @@ -10,6 +11,7 @@ import ( "github.com/buildpacks/libcnb" . "github.com/onsi/gomega" "github.com/paketo-buildpacks/libpak" + "github.com/paketo-buildpacks/libpak/bard" "github.com/paketo-buildpacks/maven/v6/maven" "github.com/sclevine/spec" ) @@ -41,25 +43,52 @@ func testMavenManager(t *testing.T, context spec.G, it spec.S) { }) context("StandardMavenManager", func() { + var dc libpak.DependencyCache + var dep3, dep4, dep5 libpak.BuildpackDependency + it.Before(func() { - dep := libpak.BuildpackDependency{ + dep3 = libpak.BuildpackDependency{ URI: "https://localhost/stub-maven-distribution.tar.gz", SHA256: "31ba45356e22aff670af88170f43ff82328e6f323c3ce891ba422bd1031e3308", - Version: "1.1.1", + Version: "3.3.3", ID: "maven", Name: "Maven", } - dc := libpak.DependencyCache{CachePath: "testdata"} + dep4 = libpak.BuildpackDependency{ + URI: "https://localhost/stub-maven-distribution.tar.gz", + SHA256: "31ba45356e22aff670af88170f43ff82328e6f323c3ce891ba422bd1031e3308", + Version: "4.4.4", + ID: "maven", + Name: "Maven", + } + dep5 = libpak.BuildpackDependency{ + URI: "https://localhost/stub-maven-distribution.tar.gz", + SHA256: "31ba45356e22aff670af88170f43ff82328e6f323c3ce891ba422bd1031e3308", + Version: "5.5.5", + ID: "maven", + Name: "Maven", + } + dc = libpak.DependencyCache{CachePath: "testdata"} mavenManager = maven.NewStandardMavenManager( ctx.Application.Path, - libpak.ConfigurationResolver{}, + libpak.ConfigurationResolver{ + Configurations: []libpak.BuildpackConfiguration{ + { + Build: true, + Launch: false, + Default: "3", + Name: "BP_MAVEN_VERSION", + }, + }, + }, libpak.DependencyResolver{ - Dependencies: []libpak.BuildpackDependency{dep}, + Dependencies: []libpak.BuildpackDependency{dep3, dep5}, StackID: "test-stack", }, dc, - "/layers") + "/layers", + bard.NewLogger(io.Discard)) }) it("shouldn't install", func() { @@ -81,6 +110,33 @@ func testMavenManager(t *testing.T, context spec.G, it spec.S) { Expect(layerContrib.Name()).To(Equal("maven")) Expect(layerContrib.(maven.Distribution)).ToNot(BeNil()) }) + + context("user sets version to 4", func() { + it.Before(func() { + t.Setenv("BP_MAVEN_VERSION", "4") + + mavenManager = maven.NewStandardMavenManager( + ctx.Application.Path, + libpak.ConfigurationResolver{}, + libpak.DependencyResolver{ + Dependencies: []libpak.BuildpackDependency{dep4, dep5}, + StackID: "test-stack", + }, + dc, + "/layers", + bard.NewLogger(io.Discard)) + }) + + it("installs a specific version", func() { + cmd, layerContrib, _, err := mavenManager.Install() + Expect(err).NotTo(HaveOccurred()) + + Expect(cmd).To(Equal("/layers/maven/bin/mvn")) + + Expect(layerContrib.Name()).To(Equal("maven")) + Expect(layerContrib.(maven.Distribution)).ToNot(BeNil()) + }) + }) }) context("DaemonMavenManager", func() { @@ -110,7 +166,8 @@ func testMavenManager(t *testing.T, context spec.G, it spec.S) { StackID: "test-stack", }, dc, - "/layers") + "/layers", + bard.NewLogger(io.Discard)) }) it("should install", func() { @@ -135,13 +192,9 @@ func testMavenManager(t *testing.T, context spec.G, it spec.S) { context("WrapperMavenManager", func() { it.Before(func() { - dc := libpak.DependencyCache{CachePath: "testdata"} - mavenManager = maven.NewWrapperMavenManager( ctx.Application.Path, - libpak.ConfigurationResolver{}, - libpak.DependencyResolver{}, - dc) + bard.NewLogger(io.Discard)) }) it("should install", func() { @@ -226,7 +279,7 @@ func testMavenManager(t *testing.T, context spec.G, it spec.S) { mvnFilePath = filepath.Join(addToPath, "mvn") - mavenManager = maven.NewNoopMavenManager() + mavenManager = maven.NewNoopMavenManager(bard.NewLogger(io.Discard)) }) it("should install", func() {