diff --git a/README.md b/README.md index 55d3939..688e10f 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ # `gcr.io/paketo-buildpacks/dist-zip` + The Paketo Buildpack for DistZip is a Cloud Native Buildpack that contributes a Process Type for DistZip-style applications. ## Behavior + This buildpack will participate all the following conditions are met * Exactly one file matching `/$BP_APPLICATION_SCRIPT` exists @@ -16,12 +18,14 @@ When `$BP_LIVE_RELOAD_ENABLE` is true: * Contributes `reload` process type ## Configuration + | Environment Variable | Description | | ------------------------- | ------------------------------------------------------------------------------------------------- | | `$BP_APPLICATION_SCRIPT` | Configures the application start script, using [Bash Pattern Matching][b]. Defaults to `*/bin/*`. | | `$BP_LIVE_RELOAD_ENABLED` | Enable live process reloading. Defaults to false. | ## License + This buildpack is released under version 2.0 of the [Apache License][a]. [a]: http://www.apache.org/licenses/LICENSE-2.0 diff --git a/buildpack.toml b/buildpack.toml index 914d583..ab5c489 100644 --- a/buildpack.toml +++ b/buildpack.toml @@ -1,4 +1,4 @@ -# Copyright 2018-2020 the original author or authors. +# Copyright 2018-2024 the original author or authors. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -27,12 +27,6 @@ api = "0.7" type = "Apache-2.0" uri = "https://github.com/paketo-buildpacks/dist-zip/blob/main/LICENSE" -[[stacks]] -id = "io.buildpacks.stacks.bionic" - -[[stacks]] -id = "io.paketo.stacks.tiny" - [[stacks]] id = "*" diff --git a/distzip/build.go b/distzip/build.go index e82f4bd..17fa1f4 100644 --- a/distzip/build.go +++ b/distzip/build.go @@ -22,6 +22,7 @@ import ( "os" "path/filepath" + "github.com/heroku/color" "github.com/paketo-buildpacks/libpak/effect" "github.com/paketo-buildpacks/libpak/sbom" @@ -67,6 +68,11 @@ func (b Build) Build(context libcnb.BuildContext) (libcnb.BuildResult, error) { return libcnb.BuildResult{}, fmt.Errorf("unable to create configuration resolver\n%w", err) } + err = os.Chmod(s, 0755) + if err != nil { + b.Logger.Bodyf("%s Unable to make script executable\n%w", color.YellowString("WARNING:"), err.Error()) + } + result.Processes = append(result.Processes, libcnb.Process{Type: "dist-zip", Command: s}, libcnb.Process{Type: "task", Command: s}, diff --git a/distzip/build_test.go b/distzip/build_test.go index 36102b8..fa7cc7f 100644 --- a/distzip/build_test.go +++ b/distzip/build_test.go @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,7 +19,6 @@ package distzip_test import ( "fmt" "io/fs" - "io/ioutil" "os" "path/filepath" "testing" @@ -43,7 +42,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) { it.Before(func() { var err error - ctx.Application.Path, err = ioutil.TempDir("", "build-application") + ctx.Application.Path = t.TempDir() Expect(err).NotTo(HaveOccurred()) ctx.Buildpack.Metadata = map[string]interface{}{ @@ -61,17 +60,12 @@ func testBuild(t *testing.T, context spec.G, it spec.S) { }} sbomScanner = mocks.SBOMScanner{} sbomScanner.On("ScanLaunch", ctx.Application.Path, libcnb.SyftJSON, libcnb.CycloneDXJSON).Return(nil) - - }) - - it.After(func() { - Expect(os.RemoveAll(ctx.Application.Path)).To(Succeed()) }) context("DistZip exists", func() { it.Before(func() { Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "app", "bin"), 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "test-script"), []byte{}, 0755)) + Expect(os.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "test-script"), []byte{}, 0755)) }) it("contributes processes", func() { @@ -88,11 +82,7 @@ func testBuild(t *testing.T, context spec.G, it spec.S) { context("$BP_LIVE_RELOAD_ENABLED is true", func() { it.Before(func() { - Expect(os.Setenv("BP_LIVE_RELOAD_ENABLED", "true")).To(Succeed()) - }) - - it.After(func() { - Expect(os.Unsetenv("BP_LIVE_RELOAD_ENABLED")).To(Succeed()) + t.Setenv("BP_LIVE_RELOAD_ENABLED", "true") }) it("contributes reloadable process type", func() { @@ -138,6 +128,32 @@ func testBuild(t *testing.T, context spec.G, it spec.S) { }) }) + context("DistZip exists but isn't executable", func() { + var scriptPath string + + it.Before(func() { + scriptPath = filepath.Join(ctx.Application.Path, "app", "bin", "test-script") + Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "app", "bin"), 0755)).To(Succeed()) + Expect(os.WriteFile(scriptPath, []byte{}, 0644)) + }) + + it("contributes processes and marks the script executable", func() { + result, err := distzip.Build{SBOMScanner: &sbomScanner}.Build(ctx) + Expect(err).NotTo(HaveOccurred()) + + Expect(result.Processes).To(ContainElements( + libcnb.Process{Type: "dist-zip", Command: scriptPath}, + libcnb.Process{Type: "task", Command: scriptPath}, + libcnb.Process{Type: "web", Command: scriptPath, Default: true}, + )) + sbomScanner.AssertCalled(t, "ScanLaunch", ctx.Application.Path, libcnb.SyftJSON, libcnb.CycloneDXJSON) + + info, err := os.Stat(scriptPath) + Expect(err).NotTo(HaveOccurred()) + Expect(info.Mode().Perm().String()).To(Equal("-rwxr-xr-x")) + }) + }) + context("DistZip does not exists", func() { it("passes plan entries to subsequent buildpacks", func() { result, err := distzip.Build{}.Build(ctx) diff --git a/distzip/detect_test.go b/distzip/detect_test.go index 18a436b..c8afc60 100644 --- a/distzip/detect_test.go +++ b/distzip/detect_test.go @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "os" "path/filepath" "testing" @@ -45,7 +44,7 @@ func testDetect(t *testing.T, context spec.G, it spec.S) { it.Before(func() { var err error - ctx.Application.Path, err = ioutil.TempDir("", "dist-zip") + ctx.Application.Path = t.TempDir() Expect(err).NotTo(HaveOccurred()) ctx.Buildpack.Metadata = map[string]interface{}{ @@ -62,10 +61,6 @@ func testDetect(t *testing.T, context spec.G, it spec.S) { Logger: bard.NewLoggerWithOptions(io.Discard, bard.WithDebug(buf))} }) - it.After(func() { - Expect(os.RemoveAll(ctx.Application.Path)).To(Succeed()) - }) - context("application script not found", func() { it("requires jvm-application-package", func() { Expect(detect.Detect(ctx)).To(Equal(libcnb.DetectResult{ @@ -90,8 +85,8 @@ func testDetect(t *testing.T, context spec.G, it spec.S) { context("multiple application scripts", func() { it.Before(func() { Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "app", "bin"), 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script-1"), []byte{}, 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script-2"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script-1"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script-2"), []byte{}, 0755)).To(Succeed()) }) it("requires jvm-application-package", func() { @@ -121,7 +116,7 @@ func testDetect(t *testing.T, context spec.G, it spec.S) { context("single application script", func() { it.Before(func() { Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "app", "bin"), 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script"), []byte{}, 0755)).To(Succeed()) }) it("requires and provides jvm-application-package", func() { @@ -147,14 +142,10 @@ func testDetect(t *testing.T, context spec.G, it spec.S) { context("$BP_LIVE_RELOAD_ENABLED is set", func() { it.Before(func() { - Expect(os.Setenv("BP_LIVE_RELOAD_ENABLED", "true")).To(Succeed()) + t.Setenv("BP_LIVE_RELOAD_ENABLED", "true") Expect(os.MkdirAll(filepath.Join(ctx.Application.Path, "app", "bin"), 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script"), []byte{}, 0755)).To(Succeed()) - }) - - it.After(func() { - Expect(os.Unsetenv("BP_LIVE_RELOAD_ENABLED")).To(Succeed()) + Expect(os.WriteFile(filepath.Join(ctx.Application.Path, "app", "bin", "script"), []byte{}, 0755)).To(Succeed()) }) it("requires watchexec", func() { diff --git a/distzip/script_resolver_test.go b/distzip/script_resolver_test.go index 8f79527..8a1bb33 100644 --- a/distzip/script_resolver_test.go +++ b/distzip/script_resolver_test.go @@ -1,5 +1,5 @@ /* - * Copyright 2018-2020 the original author or authors. + * Copyright 2018-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,6 @@ import ( "bytes" "fmt" "io" - "io/ioutil" "os" "path/filepath" "testing" @@ -43,7 +42,7 @@ func testScriptResolver(t *testing.T, context spec.G, it spec.S) { it.Before(func() { var err error - r.ApplicationPath, err = ioutil.TempDir("", "script-resolver") + r.ApplicationPath = t.TempDir() Expect(err).NotTo(HaveOccurred()) r.ConfigurationResolver = libpak.ConfigurationResolver{Configurations: []libpak.BuildpackConfiguration{ @@ -54,14 +53,10 @@ func testScriptResolver(t *testing.T, context spec.G, it spec.S) { }} }) - it.After(func() { - Expect(os.RemoveAll(r.ApplicationPath)).To(Succeed()) - }) - it("returns script", func() { Expect(os.MkdirAll(filepath.Join(r.ApplicationPath, "app", "bin"), 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "alpha.sh"), []byte{}, 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "alpha.bat"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "alpha.sh"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "alpha.bat"), []byte{}, 0755)).To(Succeed()) s, ok, err := r.Resolve() Expect(err).NotTo(HaveOccurred()) @@ -72,17 +67,13 @@ func testScriptResolver(t *testing.T, context spec.G, it spec.S) { context("$BP_APPLICATION_SCRIPT", func() { it.Before(func() { - Expect(os.Setenv("BP_APPLICATION_SCRIPT", filepath.Join("bin", "*.bat"))).To(Succeed()) - }) - - it.After(func() { - Expect(os.Unsetenv("BP_APPLICATION_SCRIPT")).To(Succeed()) + t.Setenv("BP_APPLICATION_SCRIPT", filepath.Join("bin", "*.bat")) }) it("returns script from $BP_APPLICATION_SCRIPT", func() { Expect(os.MkdirAll(filepath.Join(r.ApplicationPath, "bin"), 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(r.ApplicationPath, "bin", "alpha.sh"), []byte{}, 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(r.ApplicationPath, "bin", "alpha.bat"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(r.ApplicationPath, "bin", "alpha.sh"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(r.ApplicationPath, "bin", "alpha.bat"), []byte{}, 0755)).To(Succeed()) s, ok, err := r.Resolve() Expect(err).NotTo(HaveOccurred()) @@ -104,8 +95,8 @@ func testScriptResolver(t *testing.T, context spec.G, it spec.S) { r.Logger = bard.NewLoggerWithOptions(io.Discard, bard.WithDebug(buf)) Expect(os.MkdirAll(filepath.Join(r.ApplicationPath, "app", "bin"), 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "alpha"), []byte{}, 0755)).To(Succeed()) - Expect(ioutil.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "bravo"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "alpha"), []byte{}, 0755)).To(Succeed()) + Expect(os.WriteFile(filepath.Join(r.ApplicationPath, "app", "bin", "bravo"), []byte{}, 0755)).To(Succeed()) _, _, err := r.Resolve() diff --git a/go.mod b/go.mod index 2012330..696805b 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.20 require ( github.com/buildpacks/libcnb v1.30.1 + github.com/heroku/color v0.0.6 github.com/onsi/gomega v1.31.1 github.com/paketo-buildpacks/libpak v1.68.2 github.com/sclevine/spec v1.4.0 @@ -15,7 +16,6 @@ require ( github.com/creack/pty v1.1.21 // indirect github.com/davecgh/go-spew v1.1.1 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/heroku/color v0.0.6 // indirect github.com/imdario/mergo v0.3.16 // indirect github.com/mattn/go-colorable v0.1.13 // indirect github.com/mattn/go-isatty v0.0.20 // indirect