From a000a4fd5c5ac9628902fc0f403f606054beb041 Mon Sep 17 00:00:00 2001 From: Ed Morley <501702+edmorley@users.noreply.github.com> Date: Mon, 8 Jun 2026 18:42:52 +0100 Subject: [PATCH] Fix intermittent profile.d/ scripts test failure from extra trailing newline The profile.d/ scripts test asserts on captured `run_multi` command output using an exact match against a heredoc. The platform log stream that captures the output occasionally appends an extra trailing newline, which intermittently breaks these exact assertions. For example: https://github.com/heroku/heroku-buildpack-python/actions/runs/27144980449/job/80156740097?pr=2099#step:5:628 ``` Failures: 1) .profile.d/ scripts sets the required run-time env vars Failure/Error: expect(output).to eq(<<~OUTPUT) Python buildpack: Detected 512 MB available memory and 8 CPU cores. Python buildpack: Skipping automatic configuration of WEB_CONCURRENCY since it's already set. DYNO_RAM=512 WEB_CONCURRENCY=999 OUTPUT expected: "Python buildpack: Detected 512 MB available memory and 8 CPU cores.\nPython buildpack: Skipping auto...matic configuration of WEB_CONCURRENCY since it's already set.\nDYNO_RAM=512\nWEB_CONCURRENCY=999\n" got: "Python buildpack: Detected 512 MB available memory and 8 CPU cores.\nPython buildpack: Skipping auto...tic configuration of WEB_CONCURRENCY since it's already set.\nDYNO_RAM=512\nWEB_CONCURRENCY=999\n\n" (compared using ==) # ./spec/hatchet/profile_d_scripts_spec.rb:128:in 'block (4 levels) in ' # ./vendor/bundle/ruby/4.0.0/gems/heroku_hatchet-8.0.6/lib/hatchet/app.rb:255:in 'block in Hatchet::App#run_multi' ``` Adds a `normalize_trailing_newlines` spec helper that collapses any trailing newlines down to a single one, and applies it to the exact-match assertions in the test. This absorbs the spurious trailing newline whilst still asserting on the rest of the output exactly. GUS-W-22900269. --- spec/hatchet/profile_d_scripts_spec.rb | 18 +++++++++--------- spec/spec_helper.rb | 6 ++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/spec/hatchet/profile_d_scripts_spec.rb b/spec/hatchet/profile_d_scripts_spec.rb index bb805a69f..20b90418f 100644 --- a/spec/hatchet/profile_d_scripts_spec.rb +++ b/spec/hatchet/profile_d_scripts_spec.rb @@ -27,7 +27,7 @@ 'WEB_CONCURRENCY=this-should-be-preserved', ] app.run_multi(list_envs_cmd, heroku: { env: user_env_vars.join(';'), type: 'example-worker' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) DYNO_RAM=512 FORWARDED_ALLOW_IPS=* GUNICORN_CMD_ARGS=this-should-be-preserved @@ -48,7 +48,7 @@ # Check WEB_CONCURRENCY support when using a Standard-1X dyno. # We set the process type to `web` so that we can test the web-dyno-only log output. app.run_multi(list_concurrency_envs_cmd, heroku: { size: 'standard-1x', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 512 MB available memory and 8 CPU cores. Python buildpack: Defaulting WEB_CONCURRENCY to 2 based on the available memory. DYNO_RAM=512 @@ -59,7 +59,7 @@ # Standard-2X app.run_multi(list_concurrency_envs_cmd, heroku: { size: 'standard-2x', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 1024 MB available memory and 8 CPU cores. Python buildpack: Defaulting WEB_CONCURRENCY to 4 based on the available memory. DYNO_RAM=1024 @@ -70,7 +70,7 @@ # Performance-M app.run_multi(list_concurrency_envs_cmd, heroku: { size: 'performance-m', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 2560 MB available memory and 2 CPU cores. Python buildpack: Defaulting WEB_CONCURRENCY to 5 based on the number of CPU cores. DYNO_RAM=2560 @@ -81,7 +81,7 @@ # Performance-L app.run_multi(list_concurrency_envs_cmd, heroku: { size: 'performance-l', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 14336 MB available memory and 8 CPU cores. Python buildpack: Defaulting WEB_CONCURRENCY to 17 based on the number of CPU cores. DYNO_RAM=14336 @@ -92,7 +92,7 @@ # Performance-L-RAM app.run_multi(list_concurrency_envs_cmd, heroku: { size: 'performance-l-ram', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 30720 MB available memory and 4 CPU cores. Python buildpack: Defaulting WEB_CONCURRENCY to 9 based on the number of CPU cores. DYNO_RAM=30720 @@ -103,7 +103,7 @@ # Performance-XL app.run_multi(list_concurrency_envs_cmd, heroku: { size: 'performance-xl', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 63488 MB available memory and 8 CPU cores. Python buildpack: Defaulting WEB_CONCURRENCY to 17 based on the number of CPU cores. DYNO_RAM=63488 @@ -114,7 +114,7 @@ # Performance-2XL app.run_multi(list_concurrency_envs_cmd, heroku: { size: 'performance-2xl', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 129024 MB available memory and 16 CPU cores. Python buildpack: Defaulting WEB_CONCURRENCY to 33 based on the number of CPU cores. DYNO_RAM=129024 @@ -125,7 +125,7 @@ # Check that WEB_CONCURRENCY is preserved if set, but that we still set DYNO_RAM. app.run_multi(list_concurrency_envs_cmd, heroku: { env: 'WEB_CONCURRENCY=999', type: 'web' }) do |output, _| - expect(output).to eq(<<~OUTPUT) + expect(normalize_trailing_newlines(output)).to eq(<<~OUTPUT) Python buildpack: Detected 512 MB available memory and 8 CPU cores. Python buildpack: Skipping automatic configuration of WEB_CONCURRENCY since it's already set. DYNO_RAM=512 diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index 1fcb598ff..416826cf0 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -62,6 +62,12 @@ def clean_output(output) .gsub(/\e\[[0-9;]+m/, '') end +def normalize_trailing_newlines(output) + # The platform log stream that captures `run`/`run_multi` command output occasionally appends + # an extra trailing newline, which otherwise intermittently breaks exact output assertions. + output.sub(/\n+\z/, "\n") +end + def update_buildpacks(app, buildpacks) # Updates the list of buildpacks for an existing app, until Hatchet supports this natively: # https://github.com/heroku/hatchet/issues/166