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 @@ -6,6 +6,7 @@
- Updated resolve-version binary to use shared `nodejs-data` crate. ([#1617](https://github.com/heroku/heroku-buildpack-nodejs/pull/1617))
- Improve resolve-version logic for detecting highest LTS to use when a wide version range is requested. ([#1618](https://github.com/heroku/heroku-buildpack-nodejs/pull/1618))
- Default Node.js version is now derived from the `nodejs-data` crate instead of being hardcoded in shell scripts. ([#1620](https://github.com/heroku/heroku-buildpack-nodejs/pull/1620))
- Warn when deploying with End-of-Life Node.js versions. ([#1621](https://github.com/heroku/heroku-buildpack-nodejs/pull/1621))

## [v342] - 2026-04-16

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

build_data::set_raw "node_version_eol" "$eol"

if [[ "$uses_wide_range" == "true" ]]; then
output::warning <<-EOF
Expand All @@ -100,6 +103,19 @@ install_nodejs() {
EOF
fi

if [[ "$eol" == "true" ]]; then
output::warning <<-EOF
Comment thread
colincasey marked this conversation as resolved.
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
Comment thread
colincasey marked this conversation as resolved.
fi

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

if [[ "$version" == "22.5.0" ]]; then
Expand Down
Binary file modified lib/vendor/resolve-version-linux
Binary file not shown.
53 changes: 51 additions & 2 deletions resolve-version/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
use clap::{Command, arg, value_parser};
use libherokubuildpack::inventory::artifact::{Arch, Os};
use nodejs_data::{
NodejsArtifact, NodejsInventory, RECOMMENDED_LTS_VERSION, Version, VersionError, VersionRange,
NodejsArtifact, NodejsInventory, RECOMMENDED_LTS_VERSION, SUPPORTED_NODEJS_VERSIONS, Version,
VersionError, VersionRange,
};
use std::env::consts;

Expand All @@ -14,6 +15,7 @@ struct Resolution<'a> {
artifact: &'a NodejsArtifact,
uses_wide_range: bool,
lts_upper_bound_enforced: bool,
eol: bool,
}

fn main() {
Expand Down Expand Up @@ -99,6 +101,7 @@ fn main() {
"lts_upper_bound_enforced": resolution.lts_upper_bound_enforced,
"default": default,
"lts_version": RECOMMENDED_LTS_VERSION.to_string(),
"eol": resolution.eol,
})
);
} else {
Expand Down Expand Up @@ -173,8 +176,11 @@ fn resolve_node_artifact<'a>(
)
};

let artifact = lts_artifact.unwrap_or(resolved_artifact);

Some(Resolution {
artifact: lts_artifact.unwrap_or(resolved_artifact),
eol: !SUPPORTED_NODEJS_VERSIONS.contains(&artifact.version.major()),
artifact,
uses_wide_range,
lts_upper_bound_enforced: lts_artifact.is_some(),
})
Expand Down Expand Up @@ -470,6 +476,42 @@ mod tests {
assert_eq!(result.unwrap().to_string(), "22.x");
}

// --- 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);
}

fn create_inventory() -> NodejsInventory {
let contents = r#"
[[artifacts]]
Expand All @@ -492,6 +534,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.8"
os = "linux"
arch = "amd64"
url = "https://nodejs.org/download/release/v18.20.8/node-v18.20.8-linux-x64.tar.gz"
checksum = "sha256:27a9f3f14d5e99ad05a07ed3524ba3ee92f8ff8b6db5ff80b00f9feb5ec8097a"
"#;
toml::from_str(contents).unwrap()
}
Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_10_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 10.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 10.x...
remote:
remote: ! Node.js 10.24.1 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 10.24.1...
remote: Validating checksum
remote: Using default npm version: 6.14.12
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end

Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_12_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 12.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 12.x...
remote:
remote: ! Node.js 12.22.12 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 12.22.12...
remote: Validating checksum
remote: Using default npm version: 6.14.16
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end

Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_14_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 14.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 14.x...
remote:
remote: ! Node.js 14.21.3 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 14.21.3...
remote: Validating checksum
remote: Using default npm version: 6.14.18
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end

Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_15_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 15.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 15.x...
remote:
remote: ! Node.js 15.14.0 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 15.14.0...
remote: Validating checksum
remote: Using default npm version: 7.7.6
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end

Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_16_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 16.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 16.x...
remote:
remote: ! Node.js 16.20.2 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 16.20.2...
remote: Validating checksum
remote: Using default npm version: 8.19.4
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
end
Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_17_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 17.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 17.x...
remote:
remote: ! Node.js 17.9.1 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 17.9.1...
remote: Validating checksum
remote: Using default npm version: 8.11.0
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
end
Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_18_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 18.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 18.x...
remote:
remote: ! Node.js 18.20.8 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 18.20.8...
remote: Validating checksum
remote: Using default npm version: 10.8.2
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
end
Expand Down
14 changes: 12 additions & 2 deletions spec/ci/node_19_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,29 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to include(<<~OUTPUT)
remote: -----> Installing binaries
remote: engines.node (package.json): 19.x
remote: engines.npm (package.json): unspecified (use default)
remote:
remote: Resolving node version 19.x...
remote:
remote: ! Node.js 19.9.0 is now End-of-Life (EOL). It no longer receives security
remote: ! updates, bug fixes, or support from the Node.js project and is no longer
remote: ! supported on Heroku.
remote: !
remote: ! In a future buildpack release, this warning will become a build error. Please
remote: ! upgrade to a supported version as soon as possible to avoid build failures.
remote: !
remote: ! https://devcenter.heroku.com/articles/nodejs-support#supported-node-js-versions
remote:
remote: Downloading and installing node 19.9.0...
remote: Validating checksum
remote: Using default npm version: 9.6.3
OUTPUT
expect(successful_body(app).strip).to eq("Hello, world!")
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion spec/ci/node_20_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
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(successful_body(app).strip).to eq("Hello, world!")
expect(clean_output(app.output)).to match(Regexp.new(<<~'REGEX'))
Expand Down
Loading