diff --git a/CHANGELOG.md b/CHANGELOG.md index 60cab1c4..9d08744d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ - ext-newrelic/10.3.0.315 [David Zuelke] - ext-phalcon/5.1.0 [David Zuelke] +### CHG + +- Fail if platform packages dir is part of app source [David Zuelke] + ## v226 (2022-10-27) ### ADD diff --git a/bin/compile b/bin/compile index 3d6f4c64..b09e7832 100755 --- a/bin/compile +++ b/bin/compile @@ -189,8 +189,48 @@ fi # PHP expects to be installed in /app/.heroku/php because of compiled paths, let's set that up! mkdir -p /app/.heroku -# all system packages live in there -mkdir -p $build_dir/.heroku/php +# other buildpacks use this magic directory, too +mkdir -p $build_dir/.heroku +# all our system packages live in there +mkdir $build_dir/.heroku/php || { + # looks like platform packages are already there + # this can happen if the buildpack is set twice, or if a user is trying to build an already built app + # (e.g. by downloading a slug from Heroku and checking it into Git) + mcount "failures.platform.slug_as_source" + error <<-EOF + Your app source code contains artifacts from a previous build! + + A '.heroku/php/' directory exists in your app source, but this + directory is created during a build of your app and should not + be in your source repository, as it contains binaries for PHP, + web servers, PHP extensions, and so forth. + + This situation can happen if you: + 1) have accidentally set this buildpack on your app twice; + 2) downloaded a built app ("slug") and used it as source code. + + To address situation 1, check the 'heroku buildpacks' command. + + To address situation 2, ensure the following directories are + not part of your source code in your version control system: + - .heroku/ + - .profile.d/ + - vendor/ + + It is recommended you create a new Git repository that doesn't + have these directories in its commit history. If you only + perform a 'git rm', the binaries will remain part of your code + repository, and inflate its size by hundreds of megabytes. You + may also use common techniques for rewriting commit history to + retroactively remove the directories from the old commits that + introduced them. + + If you were using other buildpacks together with PHP, you may + want to ensure that those buildpacks' build artifacts, such as + a Node.js 'node_modules/' directory, are also not part of your + source code repository. + EOF +} # set up Composer export COMPOSER_HOME=$cache_dir/.composer mkdir -p $COMPOSER_HOME diff --git a/test/spec/bugs_spec.rb b/test/spec/bugs_spec.rb index edd00bf2..b5a6d79b 100644 --- a/test/spec/bugs_spec.rb +++ b/test/spec/bugs_spec.rb @@ -30,4 +30,35 @@ end end end + context "that is built twice" do + # sometimes, customers download a slug for an existing app and check that into a new repo + # that means the source includes the binaries in .heroku/php/, which blows up the size by 100s of MB + # it also causes the platform install to fail because Composer sees everything is there and no post-install hooks to set up $PATH etc will be run + context "because of a slug getting used as the app source" do + it "fails the build" do + app = new_app_with_stack_and_platrepo("test/fixtures/default", allow_failure: true).tap do |app| + app.before_deploy(:append) do + FileUtils.mkdir_p(".heroku/php") + FileUtils.touch(".heroku/php/composer.lock") + end + end + app.deploy do |app| + expect(app.output).to match("Your app source code contains artifacts from a previous build") + end + end + end + # it can also happen if the PHP buildpack runs twice during a build + context "because the buildpack ran twice" do + it "fails the build" do + buildpacks = [ + "heroku/php", + :default + ] + app = new_app_with_stack_and_platrepo("test/fixtures/default", buildpacks: buildpacks, allow_failure: true) + app.deploy do |app| + expect(app.output).to match("Your app source code contains artifacts from a previous build") + end + end + end + end end