diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c6cf6d37..c7116b9a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,7 +4,7 @@ All pull request authors must have a Contributor License Agreement (CLA) on-file with us. Please sign the Contributor License Agreements for Cloud Foundry ([Individual or Corporate](https://www.cloudfoundry.org/community/cla/)) via the EasyCLA application when you submit your first Pull Request. -When sending signed CLA please provide your github username in case of individual CLA or the list of github usernames that can make pull requests on behalf of your organization. +When sending signed CLA please provide your Github username in case of individual CLA or the list of Github usernames that can make pull requests on behalf of your organization. If you are confident that you're covered under a Corporate CLA, please make sure you've publicized your membership in the appropriate Github Org, per these instructions. diff --git a/README.md b/README.md index 897a55ab..eda068e0 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,20 @@ This buildpack supports running Django and Flask apps. Official buildpack documentation can be found at [python buildpack docs](http://docs.cloudfoundry.org/buildpacks/python/index.html). +## Adding new dependencies + +If you want to add a new dependency to the buildpack, please add it to the [config.yml](https://github.com/cloudfoundry/buildpacks-ci/blob/5a63d13df09f83d5dff7c71d0a12c3e2dc798d39/pipelines/dependency-builds/config.yml#L272) file. For example, if you want to add a new version of Python, add an entry like the following: + +```yaml +python: + lines: + - line: 3.14.X + deprecation_date: 2030-10-07 + link: https://peps.python.org/pep-0745/ +``` + +The new dependency will be automatically added to the buildpack [manifest.yml](manifest.yml) file. + ### Building the Buildpack To build this buildpack, run the following commands from the buildpack's directory: @@ -24,7 +38,7 @@ To build this buildpack, run the following commands from the buildpack's directo 1. Install buildpack-packager ```bash - go install github.com/cloudfoundry/libbuildpack/packager/buildpack-packager + go install github.com/cloudfoundry/libbuildpack/packager/buildpack-packager@latest ``` 1. Build the buildpack diff --git a/VERSION b/VERSION index f8e233b2..77fee73a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -1.9.0 +1.9.3 diff --git a/manifest.yml b/manifest.yml index 0347326c..4a67572d 100644 --- a/manifest.yml +++ b/manifest.yml @@ -27,8 +27,8 @@ dependency_deprecation_dates: dependencies: - name: flit-core version: 3.12.0 - uri: https://buildpacks.cloudfoundry.org/dependencies/flit-core/flit-core_3.12.0_linux_noarch_any-stack_ce08b8fa.tgz - sha256: ce08b8faf08c0be08c4c8c5617442bf36641e8c1cc26e9c3ad295d70252edffb + uri: https://buildpacks.cloudfoundry.org/dependencies/flit-core/flit-core_3.12.0_linux_noarch_cflinuxfs4_2e12c5e8.tgz + sha256: 2e12c5e8572cdb9c2c4010eb133f9a49e219d12e18a3c81f7c8cc62ddb5d343e cf_stacks: - cflinuxfs4 - cflinuxfs5 @@ -98,21 +98,30 @@ dependencies: source: https://files.pythonhosted.org/packages/ca/5b/8ce5227713d692913c186d9a3164eee0236fbc3eaca87d7e2bd5dbb1da36/pipenv-2024.4.1.tar.gz source_sha256: e8ea6105c1cdda7d5c19df7bd6439a006751f3d4e017602c791e7b51314adf84 - name: pipenv - version: 2026.5.2 - uri: https://buildpacks.cloudfoundry.org/dependencies/pipenv/pipenv_2026.5.2_linux_noarch_cflinuxfs4_74c1a3ab.tgz - sha256: 74c1a3ab922ae87de22698eeec0aaa7ba54a1b7af767144eb52d34ef0c7acab5 + version: 2026.6.2 + uri: https://buildpacks.cloudfoundry.org/dependencies/pipenv/pipenv_2026.6.2_linux_noarch_cflinuxfs4_e7ab4f20.tgz + sha256: e7ab4f20cc4b191369fa3b8818967fd2a23e7fc1331a0984a0f98c2f3fd12efd cf_stacks: - cflinuxfs4 - source: https://files.pythonhosted.org/packages/00/bf/9e5a536eae91adcbed6ee9c44861250bdfdc42bf2663680ce44cf5253fdb/pipenv-2026.5.2.tar.gz - source_sha256: cf5985038a4cc4a1ffe9b48a2e580d2595245823dcc5684d07b1a53929ab47cc + source: https://files.pythonhosted.org/packages/26/4e/24ece5e63a4a81034453970e2289896f977999550abee4dcf81f1e0e963e/pipenv-2026.6.2.tar.gz + source_sha256: fe513e97f3fc7027df22647aaf2b9de892f345f7e56dc0422e70b1213d641400 - name: pipenv - version: 2026.5.2 - uri: https://buildpacks.cloudfoundry.org/dependencies/pipenv/pipenv_2026.5.2_linux_noarch_cflinuxfs5_569f70b0.tgz - sha256: 569f70b09c3b3440c6385aad160bef6b3539fd7b6211a73bfe41600d8b3fdfad + version: 2026.6.2 + uri: https://buildpacks.cloudfoundry.org/dependencies/pipenv/pipenv_2026.6.2_linux_noarch_cflinuxfs5_5bec7356.tgz + sha256: 5bec7356540b18c3759d1bc2e6952c9d25fac4376123ddfbd9811e25911de313 cf_stacks: - cflinuxfs5 - source: https://files.pythonhosted.org/packages/00/bf/9e5a536eae91adcbed6ee9c44861250bdfdc42bf2663680ce44cf5253fdb/pipenv-2026.5.2.tar.gz - source_sha256: cf5985038a4cc4a1ffe9b48a2e580d2595245823dcc5684d07b1a53929ab47cc + source: https://files.pythonhosted.org/packages/26/4e/24ece5e63a4a81034453970e2289896f977999550abee4dcf81f1e0e963e/pipenv-2026.6.2.tar.gz + source_sha256: fe513e97f3fc7027df22647aaf2b9de892f345f7e56dc0422e70b1213d641400 +- name: poetry-core + version: 2.4.1 + uri: https://buildpacks.cloudfoundry.org/dependencies/poetry-core/poetry-core_2.4.1_linux_noarch_cflinuxfs4_e8608303.tgz + sha256: e8608303f2f76854a35a5ffe33bf8f89887b639a4bc2aef0d2e024732552ba02 + cf_stacks: + - cflinuxfs4 + - cflinuxfs5 + source: https://files.pythonhosted.org/packages/b2/f2/fa88c58efb9a737c7e0e40e470edd0973fe33f0f277d24dcf17454b50974/poetry_core-2.4.1.tar.gz + source_sha256: 89dceb6c10e9c6d8650a16183400e3c9ff9ddee13b0a81023b5575334a2b3744 - name: python version: 3.10.19 uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.10.19_linux_x64_cflinuxfs3_d754b71d.tgz @@ -147,16 +156,16 @@ dependencies: source_sha256: 563d2a1b2a5ba5d5409b5ecd05a0e1bf9b028cf3e6a6f0c87a5dc8dc3f2d9182 - name: python version: 3.11.15 - uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.11.15_linux_x64_cflinuxfs4_830cc0e2.tgz - sha256: 830cc0e2fb2b3232e683f415b5011314703ac58b4acd4e000976963788c94865 + uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.11.15_linux_x64_cflinuxfs4_d89c37b3.tgz + sha256: d89c37b356478929b97231fb2d4090d0ecc06d4293459dabd7b8881250350647 cf_stacks: - cflinuxfs4 source: https://www.python.org/ftp/python/3.11.15/Python-3.11.15.tgz source_sha256: f4de1b10bd6c70cbb9fa1cd71fc5038b832747a74ee59d599c69ce4846defb50 - name: python version: 3.11.15 - uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.11.15_linux_x64_cflinuxfs5_ded45956.tgz - sha256: ded45956efaaa20ecdd5914182b96ea47b3e9e82bc68fe1ea08820fa319689c4 + uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.11.15_linux_x64_cflinuxfs5_240344f9.tgz + sha256: 240344f919c73c5ca96ac44c8a91faba0b8950fa36d4d81c50956988024ae06b cf_stacks: - cflinuxfs5 source: https://www.python.org/ftp/python/3.11.15/Python-3.11.15.tgz @@ -186,21 +195,21 @@ dependencies: source: https://www.python.org/ftp/python/3.13.9/Python-3.13.9.tgz source_sha256: c4c066af19c98fb7835d473bebd7e23be84f6e9874d47db9e39a68ee5d0ce35c - name: python - version: 3.13.13 - uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.13.13_linux_x64_cflinuxfs4_8311abbf.tgz - sha256: 8311abbf60e3c061a70eabca62ccddba613ee0eeac790ec6f7e42b75213a05f1 + version: 3.13.14 + uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.13.14_linux_x64_cflinuxfs4_b80d4954.tgz + sha256: b80d495440e016c5b3e3fce4914d1971ae2c9ce921bcacd8df2499ee181a7c3b cf_stacks: - cflinuxfs4 - source: https://www.python.org/ftp/python/3.13.13/Python-3.13.13.tgz - source_sha256: f9cde7b0e2ec8165d7326e2a0f59ea2686ce9d0c617dbbb3d66a7e54d31b74b9 + source: https://www.python.org/ftp/python/3.13.14/Python-3.13.14.tgz + source_sha256: 5ae535a36af0ebca6fca176ecb8197f5db9c1cb8c8f0cd12cdf1787046db1f41 - name: python - version: 3.13.13 - uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.13.13_linux_x64_cflinuxfs5_953e784f.tgz - sha256: 953e784f168dfcb66192b209181f2bbf4f9b6e554edb1938d367d7b1498aaa5f + version: 3.13.14 + uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.13.14_linux_x64_cflinuxfs5_2345b267.tgz + sha256: 2345b267ba4fe4d8a61d0d9898fb64fa264c3f67baead6266fedbd340f7ad0be cf_stacks: - cflinuxfs5 - source: https://www.python.org/ftp/python/3.13.13/Python-3.13.13.tgz - source_sha256: f9cde7b0e2ec8165d7326e2a0f59ea2686ce9d0c617dbbb3d66a7e54d31b74b9 + source: https://www.python.org/ftp/python/3.13.14/Python-3.13.14.tgz + source_sha256: 5ae535a36af0ebca6fca176ecb8197f5db9c1cb8c8f0cd12cdf1787046db1f41 - name: python version: 3.14.2 uri: https://buildpack-dependencies.tanzu.vmware.com/cf/python/python_3.14.2_linux_x64_cflinuxfs3_82c1798d.tgz @@ -210,25 +219,25 @@ dependencies: source: https://www.python.org/ftp/python/3.14.2/Python-3.14.2.tgz source_sha256: c609e078adab90e2c6bacb6afafacd5eaf60cd94cf670f1e159565725fcd448d - name: python - version: 3.14.4 - uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.14.4_linux_x64_cflinuxfs4_c99dfa05.tgz - sha256: c99dfa053d8b47dab158af2e072d0a4c80c6593443cb97e759e45de1934afc96 + version: 3.14.6 + uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.14.6_linux_x64_cflinuxfs4_c52b4106.tgz + sha256: c52b41063dd371cf395cbfd74e75768a0646a405fd4a01819bd2cb01089bd2d7 cf_stacks: - cflinuxfs4 - source: https://www.python.org/ftp/python/3.14.4/Python-3.14.4.tgz - source_sha256: b4c059d5895f030e7df9663894ce3732bfa1b32cd3ab2883980266a45ce3cb3b + source: https://www.python.org/ftp/python/3.14.6/Python-3.14.6.tgz + source_sha256: 74d0d71d0600e477651a077101d6e62d1e2e69b8e992ba18c993dd643b7ba222 - name: python - version: 3.14.4 - uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.14.4_linux_x64_cflinuxfs5_ae27ea8c.tgz - sha256: ae27ea8c3e4b063be4f1dfbfcb37b65fe55be0c9812f275f56e68df96e7283ec + version: 3.14.6 + uri: https://buildpacks.cloudfoundry.org/dependencies/python/python_3.14.6_linux_x64_cflinuxfs5_2255dcee.tgz + sha256: 2255dcee486edf026b12492768b10ec01d3d79ee98d18f8a572b45c1704be6c5 cf_stacks: - cflinuxfs5 - source: https://www.python.org/ftp/python/3.14.4/Python-3.14.4.tgz - source_sha256: b4c059d5895f030e7df9663894ce3732bfa1b32cd3ab2883980266a45ce3cb3b + source: https://www.python.org/ftp/python/3.14.6/Python-3.14.6.tgz + source_sha256: 74d0d71d0600e477651a077101d6e62d1e2e69b8e992ba18c993dd643b7ba222 - name: setuptools version: 82.0.1 - uri: https://buildpacks.cloudfoundry.org/dependencies/setuptools/setuptools_82.0.1_linux_noarch_any-stack_934b4323.tgz - sha256: 934b4323475131e04577a24eff3774f75a1219948f49c63afcd5e35a507d8ba7 + uri: https://buildpacks.cloudfoundry.org/dependencies/setuptools/setuptools_82.0.1_linux_noarch_cflinuxfs4_37ffb2f1.tgz + sha256: 37ffb2f161394d9ccb578cee2dca5a2432a24f48af7910a9546e3ef0af356bfe cf_stacks: - cflinuxfs4 - cflinuxfs5 diff --git a/src/python/supply/supply.go b/src/python/supply/supply.go index b36a48fd..44cb9499 100644 --- a/src/python/supply/supply.go +++ b/src/python/supply/supply.go @@ -743,19 +743,29 @@ func (s *Supplier) RunPipVendored() error { // dependencies - wheel and setuptools. These are packaged by the dependency // pipeline within the "pip" dependency. func (s *Supplier) InstallCommonBuildDependencies() error { - var commonDeps = []string{"wheel", "setuptools"} tempPath := filepath.Join("/tmp", "common_build_deps") if err := s.Installer.InstallOnlyVersion("pip", tempPath); err != nil { return err } + for _, dep := range []string{"flit-core", "poetry-core"} { + if err := s.Installer.InstallOnlyVersion(dep, tempPath); err != nil { + return fmt.Errorf("could not prepare build-time dependency %s: %v", dep, err) + } + s.Log.Info("Installing build-time dependency %s (bootstrap)", dep) + if err := s.runPipInstall(tempPath, "--no-build-isolation"); err != nil { + return fmt.Errorf("could not bootstrap-install %s: %v", dep, err) + } + } - for _, dep := range commonDeps { + for _, dep := range []string{"wheel", "setuptools"} { s.Log.Info("Installing build-time dependency %s", dep) - args := []string{dep, "--no-index", "--upgrade-strategy=only-if-needed", fmt.Sprintf("--find-links=%s", tempPath)} + args := []string{dep, "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", fmt.Sprintf("--find-links=%s", tempPath)} if err := s.runPipInstall(args...); err != nil { return fmt.Errorf("could not install build-time dependency %s: %v", dep, err) } } + + return nil } diff --git a/src/python/supply/supply_test.go b/src/python/supply/supply_test.go index b7947dc3..a8d15d41 100644 --- a/src/python/supply/supply_test.go +++ b/src/python/supply/supply_test.go @@ -633,22 +633,57 @@ MarkupSafe==2.0.1 Describe("InstallCommonBuildDependencies", func() { Context("successful installation", func() { - It("runs command to install wheel and setuptools", func() { + It("bootstraps flit-core, poetry-core, wheel and setuptools", func() { mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") - mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") - mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "setuptools", "--no-index", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockInstaller.EXPECT().InstallOnlyVersion("poetry-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "setuptools", "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps") Expect(supplier.InstallCommonBuildDependencies()).To(Succeed()) }) }) - Context("installation fails", func() { - BeforeEach(func() { - mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps").Return(fmt.Errorf("some-pip-error")) + Context("flit-core bootstrap fails", func() { + It("returns a useful error message", func() { + mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation").Return(fmt.Errorf("bootstrap-error")) + Expect(supplier.InstallCommonBuildDependencies()).To(MatchError("could not bootstrap-install flit-core: bootstrap-error")) }) + }) + Context("poetry-core preparation fails", func() { It("returns a useful error message", func() { - mockInstaller.EXPECT().InstallOnlyVersion(gomock.Any(), gomock.Any()).Times(1) + mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockInstaller.EXPECT().InstallOnlyVersion("poetry-core", "/tmp/common_build_deps").Return(fmt.Errorf("prepare-error")) + Expect(supplier.InstallCommonBuildDependencies()).To(MatchError("could not prepare build-time dependency poetry-core: prepare-error")) + }) + }) + + Context("poetry-core bootstrap fails", func() { + It("returns a useful error message", func() { + mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockInstaller.EXPECT().InstallOnlyVersion("poetry-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation").Return(fmt.Errorf("poetry-error")) + Expect(supplier.InstallCommonBuildDependencies()).To(MatchError("could not bootstrap-install poetry-core: poetry-error")) + }) + }) + + Context("wheel installation fails", func() { + It("returns a useful error message", func() { + mockInstaller.EXPECT().InstallOnlyVersion("pip", "/tmp/common_build_deps") + mockInstaller.EXPECT().InstallOnlyVersion("flit-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockInstaller.EXPECT().InstallOnlyVersion("poetry-core", "/tmp/common_build_deps") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "/tmp/common_build_deps", "--no-build-isolation") + mockCommand.EXPECT().Execute(buildDir, gomock.Any(), gomock.Any(), "python", "-m", "pip", "install", "wheel", "--no-index", "--no-build-isolation", "--upgrade-strategy=only-if-needed", "--find-links=/tmp/common_build_deps").Return(fmt.Errorf("some-pip-error")) Expect(supplier.InstallCommonBuildDependencies()).To(MatchError("could not install build-time dependency wheel: some-pip-error")) }) })