Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## [Unreleased]

- The build now errors if an existing Python virtual environment is found in the build directory at `.venv/` or `venv/`. This replaces the warning displayed since September 2025. ([#1990](https://github.com/heroku/heroku-buildpack-python/pull/1990))
- Stopped adding the current working directory to `PATH`. ([#1987](https://github.com/heroku/heroku-buildpack-python/pull/1987))

## [v323] - 2025-12-05
Expand Down
11 changes: 8 additions & 3 deletions bin/compile
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,19 @@ cd "${BUILD_DIR}"
# Runs a `bin/pre_compile` script if found in the app source, allowing build customisation.
hooks::run_hook "pre_compile"

# These checks are after the pre_compile hook, so that we can check not only the original
# app source, but also that the hook hasn't written to these locations either.
# These later checks are after the pre_compile hook so that we can check not only the
# original app source, but also that the hook hasn't written to these locations either.
checks::existing_python_dir_present "${BUILD_DIR}"
checks::existing_venv_dir_present "${BUILD_DIR}"

package_manager="$(package_manager::determine_package_manager "${BUILD_DIR}")"
build_data::set_string "package_manager" "${package_manager}"

# This check is after the package manager step to improve the UX when the package manager file
# is missing and the venv directory was the only reason the buildpack passed detection.
# (Since once they remove the venv detection will fail, which would prevent us from being able
# to display the more helpful "missing package manager file" error message on the next build).
checks::existing_venv_dir_present "${BUILD_DIR}"

cached_python_full_version="$(cache::cached_python_full_version "${CACHE_DIR}")"

# We use the Bash 4.3+ `nameref` feature to pass back multiple values from this function
Expand Down
32 changes: 23 additions & 9 deletions lib/checks.sh
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ function checks::existing_venv_dir_present() {

for venv_name in ".venv" "venv"; do
if [[ -f "${build_dir}/${venv_name}/pyvenv.cfg" ]]; then
output::warning <<-EOF
Warning: Existing '${venv_name}/' directory found.
output::error <<-EOF
Error: Existing '${venv_name}/' directory found.

Your app's source code contains an existing directory named
'${venv_name}/', which looks like a Python virtual environment:
Expand All @@ -122,17 +122,31 @@ function checks::existing_venv_dir_present() {
single machine and so won't work when run somewhere else.

If you've committed a '${venv_name}/' directory to your Git repo, you
must delete it and add the directory to your .gitignore file:
must delete it and add the directory to your .gitignore file.

To do this:
1. Run 'git rm --cached -r ${venv_name}/' to remove the directory
from the Git index.
2. Create a '.gitignore' file in the root of your repository
if it doesn't already exist.
3. Add the '${venv_name}/' directory to the .gitignore file as a
new entry on its own line (don't include the quotes).
4. Stage the change using 'git add .gitignore' and then
'git commit' all changes.

For more information, see:
https://docs.github.com/en/get-started/git-basics/ignoring-files

If the directory was created by a 'bin/pre_compile' hook or an
earlier buildpack, you must update them to create the virtual
environment in a different location.
If the directory was created by a 'bin/pre_compile' hook or
an earlier buildpack, you must instead update them to create
the virtual environment in a different location.

In future versions of the buildpack, this warning will be turned
into an error.
Note: This error replaces the previous warning which had been
displayed in build logs since 2nd September 2025.
EOF
build_data::set_string "existing_venv_dir_present" "${venv_name}"
build_data::set_string "failure_reason" "checks::existing-venv-dir"
build_data::set_string "failure_detail" "${venv_name}"
exit 1
fi
done
}
32 changes: 22 additions & 10 deletions spec/hatchet/checks_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,14 @@
end

context 'when the app source contains a venv directory' do
let(:app) { Hatchet::Runner.new('spec/fixtures/venv_in_app_source') }
let(:app) { Hatchet::Runner.new('spec/fixtures/venv_in_app_source', allow_failure: true) }

it 'outputs a warning before continuing to build' do
it 'fails the build with an informative error message' do
app.deploy do |app|
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Python app detected
remote:
remote: ! Warning: Existing '.venv/' directory found.
remote: ! Error: Existing '.venv/' directory found.
remote: !
remote: ! Your app's source code contains an existing directory named
remote: ! '.venv/', which looks like a Python virtual environment:
Expand All @@ -94,17 +94,29 @@
remote: ! single machine and so won't work when run somewhere else.
remote: !
remote: ! If you've committed a '.venv/' directory to your Git repo, you
remote: ! must delete it and add the directory to your .gitignore file:
remote: ! must delete it and add the directory to your .gitignore file.
remote: !
remote: ! To do this:
remote: ! 1. Run 'git rm --cached -r .venv/' to remove the directory
remote: ! from the Git index.
remote: ! 2. Create a '.gitignore' file in the root of your repository
remote: ! if it doesn't already exist.
remote: ! 3. Add the '.venv/' directory to the .gitignore file as a
remote: ! new entry on its own line (don't include the quotes).
remote: ! 4. Stage the change using 'git add .gitignore' and then
remote: ! 'git commit' all changes.
remote: !
remote: ! For more information, see:
remote: ! https://docs.github.com/en/get-started/git-basics/ignoring-files
remote: !
remote: ! If the directory was created by a 'bin/pre_compile' hook or an
remote: ! earlier buildpack, you must update them to create the virtual
remote: ! environment in a different location.
remote: ! If the directory was created by a 'bin/pre_compile' hook or
remote: ! an earlier buildpack, you must instead update them to create
remote: ! the virtual environment in a different location.
remote: !
remote: ! In future versions of the buildpack, this warning will be turned
remote: ! into an error.
remote: ! Note: This error replaces the previous warning which had been
remote: ! displayed in build logs since 2nd September 2025.
remote:
remote: -----> Using Python 3.14 specified in .python-version
remote: ! Push rejected, failed to compile Python app.
OUTPUT
end
end
Expand Down