diff --git a/buildpack.toml b/buildpack.toml index aad5a6c7..6edb911f 100644 --- a/buildpack.toml +++ b/buildpack.toml @@ -39,6 +39,11 @@ api = "0.8" id = "paketo-buildpacks/pipenv-install" version = "0.7.44" + [[order.group]] + id = "paketo-buildpacks/tini" + optional = true + version = "0.4.8" + [[order.group]] id = "paketo-buildpacks/python-start" version = "0.18.0" @@ -82,6 +87,11 @@ api = "0.8" id = "paketo-buildpacks/pip-install" version = "0.7.45" + [[order.group]] + id = "paketo-buildpacks/tini" + optional = true + version = "0.4.8" + [[order.group]] id = "paketo-buildpacks/python-start" version = "0.18.0" @@ -121,6 +131,11 @@ api = "0.8" id = "paketo-buildpacks/conda-env-update" version = "0.8.42" + [[order.group]] + id = "paketo-buildpacks/tini" + optional = true + version = "0.4.8" + [[order.group]] id = "paketo-buildpacks/python-start" version = "0.18.0" @@ -215,6 +230,11 @@ api = "0.8" id = "paketo-buildpacks/poetry-install" version = "0.6.50" + [[order.group]] + id = "paketo-buildpacks/tini" + optional = true + version = "0.4.8" + [[order.group]] id = "paketo-buildpacks/python-start" version = "0.18.0" @@ -302,6 +322,11 @@ api = "0.8" id = "paketo-buildpacks/python-package-managers-run" version = "0.6.6" + [[order.group]] + id = "paketo-buildpacks/tini" + optional = true + version = "0.4.8" + [[order.group]] id = "paketo-buildpacks/python-start" version = "0.18.0" @@ -337,6 +362,11 @@ api = "0.8" id = "paketo-buildpacks/cpython" version = "1.18.45" + [[order.group]] + id = "paketo-buildpacks/tini" + optional = true + version = "0.4.8" + [[order.group]] id = "paketo-buildpacks/python-start" version = "0.18.0" diff --git a/integration/conda_test.go b/integration/conda_test.go index 285ce2ef..e9c846e9 100644 --- a/integration/conda_test.go +++ b/integration/conda_test.go @@ -103,6 +103,58 @@ func testConda(t *testing.T, context spec.G, it spec.S) { Expect(image.Labels["some-label"]).To(Equal("some-value")) }) + it("creates a working OCI image using tini", func() { + var err error + source, err = occam.Source(filepath.Join("testdata", "conda")) + Expect(err).NotTo(HaveOccurred()) + + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(pythonBuildpack). + WithPullPolicy("never"). + WithEnv(map[string]string{ + "BPE_SOME_VARIABLE": "some-value", + "BP_IMAGE_LABELS": "some-label=some-value", + "BP_LIVE_RELOAD_ENABLED": "true", + "BP_LAUNCH_WITH_TINI": "true", + }). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) + + Eventually(container).Should(BeAvailable()) + + response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) + Expect(err).NotTo(HaveOccurred()) + defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() + + Expect(response.StatusCode).To(Equal(http.StatusOK)) + + content, err := io.ReadAll(response.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(content)).To(ContainSubstring("Hello, world!")) + + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Miniconda"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Conda Env Update"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Tini"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) + + Expect(image.Buildpacks[7].Key).To(Equal("paketo-buildpacks/environment-variables")) + Expect(image.Buildpacks[7].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) + Expect(image.Labels["some-label"]).To(Equal("some-value")) + }) + context("when using CA certificates", func() { var client *http.Client diff --git a/integration/pip_test.go b/integration/pip_test.go index b103bdca..2e4fb079 100644 --- a/integration/pip_test.go +++ b/integration/pip_test.go @@ -104,6 +104,59 @@ func testPip(t *testing.T, context spec.G, it spec.S) { Expect(image.Labels["some-label"]).To(Equal("some-value")) }) + it("creates a working OCI image using tini", func() { + var err error + source, err = occam.Source(filepath.Join("testdata", "pip")) + Expect(err).NotTo(HaveOccurred()) + + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(pythonBuildpack). + WithPullPolicy("never"). + WithEnv(map[string]string{ + "BPE_SOME_VARIABLE": "some-value", + "BP_IMAGE_LABELS": "some-label=some-value", + "BP_LIVE_RELOAD_ENABLED": "true", + "BP_LAUNCH_WITH_TINI": "true", + }). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) + + Eventually(container).Should(BeAvailable()) + + response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) + Expect(err).NotTo(HaveOccurred()) + defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() + + Expect(response.StatusCode).To(Equal(http.StatusOK)) + + content, err := io.ReadAll(response.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(content)).To(ContainSubstring("Hello, World with pip!")) + + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip Install"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Tini"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) + + Expect(image.Buildpacks[8].Key).To(Equal("paketo-buildpacks/environment-variables")) + Expect(image.Buildpacks[8].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) + Expect(image.Labels["some-label"]).To(Equal("some-value")) + }) + context("when using CA certificates", func() { var client *http.Client diff --git a/integration/pipenv_test.go b/integration/pipenv_test.go index 55b89adb..a76d0dc3 100644 --- a/integration/pipenv_test.go +++ b/integration/pipenv_test.go @@ -105,6 +105,60 @@ func testPipenv(t *testing.T, context spec.G, it spec.S) { Expect(image.Labels["some-label"]).To(Equal("some-value")) }) + it("creates a working OCI image using tini", func() { + var err error + source, err = occam.Source(filepath.Join("testdata", "pipenv")) + Expect(err).NotTo(HaveOccurred()) + + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(pythonBuildpack). + WithPullPolicy("never"). + WithEnv(map[string]string{ + "BPE_SOME_VARIABLE": "some-value", + "BP_IMAGE_LABELS": "some-label=some-value", + "BP_LIVE_RELOAD_ENABLED": "true", + "BP_LAUNCH_WITH_TINI": "true", + }). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) + + Eventually(container).Should(BeAvailable()) + + response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) + Expect(err).NotTo(HaveOccurred()) + defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() + + Expect(response.StatusCode).To(Equal(http.StatusOK)) + + content, err := io.ReadAll(response.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(content)).To(ContainSubstring("Hello, World with pipenv!")) + + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pipenv"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pipenv Install"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Tini"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) + + Expect(image.Buildpacks[9].Key).To(Equal("paketo-buildpacks/environment-variables")) + Expect(image.Buildpacks[9].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) + Expect(image.Labels["some-label"]).To(Equal("some-value")) + }) + context("when using CA certificates", func() { var client *http.Client diff --git a/integration/pixi_test.go b/integration/pixi_test.go index feed2e49..28f5028d 100644 --- a/integration/pixi_test.go +++ b/integration/pixi_test.go @@ -103,6 +103,58 @@ func testPixi(t *testing.T, context spec.G, it spec.S) { Expect(image.Labels["some-label"]).To(Equal("some-value")) }) + it("creates a working OCI image using tini", func() { + var err error + source, err = occam.Source(filepath.Join("testdata", "pixi")) + Expect(err).NotTo(HaveOccurred()) + + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(pythonBuildpack). + WithPullPolicy("never"). + WithEnv(map[string]string{ + "BPE_SOME_VARIABLE": "some-value", + "BP_IMAGE_LABELS": "some-label=some-value", + "BP_LIVE_RELOAD_ENABLED": "true", + "BP_LAUNCH_WITH_TINI": "true", + }). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) + + Eventually(container).Should(BeAvailable()) + + response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) + Expect(err).NotTo(HaveOccurred()) + defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() + + Expect(response.StatusCode).To(Equal(http.StatusOK)) + + content, err := io.ReadAll(response.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(content)).To(ContainSubstring("Hello, world!")) + + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack to install python package managers"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for all python package managers"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Tini"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) + + Expect(image.Buildpacks[7].Key).To(Equal("paketo-buildpacks/environment-variables")) + Expect(image.Buildpacks[7].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) + Expect(image.Labels["some-label"]).To(Equal("some-value")) + }) + context("when using CA certificates", func() { var client *http.Client diff --git a/integration/poetry_dep_only_test.go b/integration/poetry_dep_only_test.go index 45c25dcc..da415ef3 100644 --- a/integration/poetry_dep_only_test.go +++ b/integration/poetry_dep_only_test.go @@ -102,5 +102,59 @@ func testPoetryDepOnly(t *testing.T, context spec.G, it spec.S) { Expect(image.Buildpacks[8].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) Expect(image.Labels["some-label"]).To(Equal("some-value")) }) + + it("creates a working OCI image using tini", func() { + var err error + source, err = occam.Source(filepath.Join("testdata", "poetry-dep-only")) + Expect(err).NotTo(HaveOccurred()) + + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(pythonBuildpack). + WithPullPolicy("never"). + WithEnv(map[string]string{ + "BPE_SOME_VARIABLE": "some-value", + "BP_IMAGE_LABELS": "some-label=some-value", + "BP_LIVE_RELOAD_ENABLED": "true", + "BP_LAUNCH_WITH_TINI": "true", + }). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) + + Eventually(container).Should(BeAvailable()) + + response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) + Expect(err).NotTo(HaveOccurred()) + defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() + + Expect(response.StatusCode).To(Equal(http.StatusOK)) + + content, err := io.ReadAll(response.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(content)).To(ContainSubstring("Hello, World!")) + + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CPython"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Pip"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Poetry"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Poetry Install"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Tini"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) + + Expect(image.Buildpacks[9].Key).To(Equal("paketo-buildpacks/environment-variables")) + Expect(image.Buildpacks[9].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) + Expect(image.Labels["some-label"]).To(Equal("some-value")) + }) }) } diff --git a/integration/uv_test.go b/integration/uv_test.go index 3ef944c5..35c289cc 100644 --- a/integration/uv_test.go +++ b/integration/uv_test.go @@ -103,6 +103,58 @@ func testUv(t *testing.T, context spec.G, it spec.S) { Expect(image.Labels["some-label"]).To(Equal("some-value")) }) + it("creates a working OCI image using tini", func() { + var err error + source, err = occam.Source(filepath.Join("testdata", "uv")) + Expect(err).NotTo(HaveOccurred()) + + var logs fmt.Stringer + image, logs, err = pack.WithNoColor().Build. + WithBuildpacks(pythonBuildpack). + WithPullPolicy("never"). + WithEnv(map[string]string{ + "BPE_SOME_VARIABLE": "some-value", + "BP_IMAGE_LABELS": "some-label=some-value", + "BP_LIVE_RELOAD_ENABLED": "true", + "BP_LAUNCH_WITH_TINI": "true", + }). + Execute(name, source) + Expect(err).NotTo(HaveOccurred(), logs.String()) + + container, err = docker.Container.Run. + WithEnv(map[string]string{"PORT": "8080"}). + WithPublish("8080"). + WithPublishAll(). + Execute(image.ID) + Expect(err).NotTo(HaveOccurred()) + + Eventually(container).Should(BeAvailable()) + + response, err := http.Get(fmt.Sprintf("http://localhost:%s", container.HostPort("8080"))) + Expect(err).NotTo(HaveOccurred()) + defer func() { Expect(response.Body.Close()).ToNot(HaveOccurred()) }() + + Expect(response.StatusCode).To(Equal(http.StatusOK)) + + content, err := io.ReadAll(response.Body) + Expect(err).NotTo(HaveOccurred()) + Expect(string(content)).To(ContainSubstring("Hello, world!")) + + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for CA Certificates"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack to install python package managers"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for all python package managers"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Tini"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Python Start"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Procfile"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Environment Variables"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Image Labels"))) + Expect(logs).To(ContainLines(ContainSubstring("Buildpack for Watchexec"))) + + Expect(image.Buildpacks[7].Key).To(Equal("paketo-buildpacks/environment-variables")) + Expect(image.Buildpacks[7].Layers["environment-variables"].Metadata["variables"]).To(Equal(map[string]interface{}{"SOME_VARIABLE": "some-value"})) + Expect(image.Labels["some-label"]).To(Equal("some-value")) + }) + context("when using CA certificates", func() { var client *http.Client diff --git a/package.toml b/package.toml index 5f39eabd..d5f3a36e 100644 --- a/package.toml +++ b/package.toml @@ -56,6 +56,9 @@ [[dependencies]] uri = "docker://docker.io/paketobuildpacks/watchexec:3.11.0" +[[dependencies]] + uri = "docker://docker.io/paketobuildpacks/tini:0.4.8" + [[targets]] arch = "amd64" os = "linux"