Skip to content
Closed
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 @@ -4,6 +4,7 @@

- Updated resolve-version binary to use shared `nodejs-data` crate. ([#1611](https://github.com/heroku/heroku-buildpack-nodejs/pull/1611))
- Renamed resolve-version binary to nodejs-data-query with subcommands. Default Node.js version is now derived from the `nodejs-data` crate instead of being hardcoded in shell scripts. ([#1613](https://github.com/heroku/heroku-buildpack-nodejs/pull/1613))
- Warn when deploying with End-of-Life Node.js versions. ([#1616](https://github.com/heroku/heroku-buildpack-nodejs/pull/1616))

## [v341] - 2026-04-02

Expand Down
16 changes: 16 additions & 0 deletions lib/binaries.sh
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ install_nodejs() {
checksum_value=$(echo "$resolve_result" | jq -r .checksum_value)
uses_wide_range=$(echo "$resolve_result" | jq .uses_wide_range)
lts_upper_bound_enforced=$(echo "$resolve_result" | jq .lts_upper_bound_enforced)
eol=$(echo "$resolve_result" | jq .eol)

build_data::set_raw "node_version_eol" "$eol"

if [[ "$uses_wide_range" == "true" ]]; then
echo
Expand All @@ -99,6 +102,19 @@ install_nodejs() {
echo
fi

if [[ "$eol" == "true" ]]; then
output::error <<-EOF
Node.js $version is now End-of-Life (EOL). It no longer receives security
updates, bug fixes, or support from the Node.js project and is no longer
supported on Heroku.

In a future buildpack release, this warning will become a build error. Please
upgrade to a supported version as soon as possible to avoid build failures.

https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
EOF
fi

echo "Downloading and installing node $version..."

if [[ "$version" == "22.5.0" ]]; then
Expand Down
Binary file modified lib/vendor/nodejs-data-query-linux
Binary file not shown.
50 changes: 49 additions & 1 deletion nodejs-data-query/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const UNSUPPORTED_ARCH_EXIT_CODE: i32 = 4;

struct Resolution<'a> {
artifact: &'a NodejsArtifact,
eol: bool,
uses_wide_range: bool,
lts_upper_bound_enforced: bool,
}
Expand Down Expand Up @@ -101,8 +102,11 @@ fn resolve_node_artifact<'a>(
)
};

let final_artifact = lts_artifact.unwrap_or(artifact);

Some(Resolution {
artifact: lts_artifact.unwrap_or(artifact),
eol: !SUPPORTED_NODEJS_VERSIONS.contains(&final_artifact.version.major()),
artifact: final_artifact,
uses_wide_range,
lts_upper_bound_enforced: lts_artifact.is_some(),
})
Expand Down Expand Up @@ -186,6 +190,7 @@ fn cmd_resolve_version(
"checksum_value": hex::encode(&resolution.artifact.checksum.value),
"uses_wide_range": resolution.uses_wide_range,
"lts_upper_bound_enforced": resolution.lts_upper_bound_enforced,
"eol": resolution.eol,
})
);
} else {
Expand Down Expand Up @@ -239,6 +244,13 @@ mod tests {
arch = "amd64"
url = "https://nodejs.org/download/release/v22.21.0/node-v22.21.0-linux-x64.tar.gz"
checksum = "sha256:262b84b02f7e2bc017d4bdb81fec85ca0d6190a5cd0781d2d6e84317c08871f8"

[[artifacts]]
version = "18.20.0"
os = "linux"
arch = "amd64"
url = "https://nodejs.org/download/release/v18.20.0/node-v18.20.0-linux-x64.tar.gz"
checksum = "sha256:80620426d177141aa99376de2ad1cb5ed461104cc53c0a5334df91467c60cac3"
"#;
toml::from_str(contents).unwrap()
}
Expand Down Expand Up @@ -499,4 +511,40 @@ mod tests {
.is_none()
);
}

// --- EOL detection tests ---

#[test]
fn eol_true_for_unsupported_version() {
let inventory = create_inventory();
let requirement = VersionRange::parse("18.x").unwrap();
let resolution = resolve_node_artifact(
&inventory,
Os::Linux,
Arch::Amd64,
&requirement,
TEST_LTS_MAJOR_VERSION,
DISALLOW_WIDE_RANGE,
)
.expect("expected resolution to succeed");
assert_eq!(resolution.artifact.version.major(), 18);
assert!(resolution.eol);
}

#[test]
fn eol_false_for_supported_version() {
let inventory = create_inventory();
let requirement = VersionRange::parse("24.x").unwrap();
let resolution = resolve_node_artifact(
&inventory,
Os::Linux,
Arch::Amd64,
&requirement,
TEST_LTS_MAJOR_VERSION,
DISALLOW_WIDE_RANGE,
)
.expect("expected resolution to succeed");
assert_eq!(resolution.artifact.version.major(), 24);
assert!(!resolution.eol);
}
}
3 changes: 2 additions & 1 deletion spec/ci/node_10_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-10")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_12_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-12")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_14_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-14")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_15_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-15")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_16_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-16")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_17_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-17")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_18_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-18")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_19_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-19")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_20_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-20")
}

it "should deploy successfully" do
it "should deploy successfully without EOL warning" do
app.deploy do |app|
expect(app.output).not_to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_21_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-21")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_22_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-22")
}

it "should deploy successfully" do
it "should deploy successfully without EOL warning" do
app.deploy do |app|
expect(app.output).not_to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_23_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-23")
}

it "should deploy successfully" do
it "should deploy successfully with EOL warning" do
app.deploy do |app|
expect(app.output).to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_24_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-24")
}

it "should deploy successfully" do
it "should deploy successfully without EOL warning" do
app.deploy do |app|
expect(app.output).not_to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
3 changes: 2 additions & 1 deletion spec/ci/node_25_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@
Hatchet::Runner.new("spec/fixtures/repos/node-25")
}

it "should deploy successfully" do
it "should deploy successfully without EOL warning" do
app.deploy do |app|
expect(app.output).not_to include("End-of-Life")
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
Expand Down
Loading