Skip to content

Commit b863136

Browse files
schneemsedmorley
andauthoredMay 17, 2024··
Support Heroku-24 and ARM architecture (#284)
* Support Heroku-24 and ARM architecture Heroku 24 stack image supports both arm64 and amd64. The Ruby binaries are available on heroku-24 compiled to these two stacks heroku/docker-heroku-ruby-builder#38. The buildpack adds support by: - Updating the `buildpackl.toml` to include ARM architecture - Using architecture information to build the URL for Ubuntu 24.04 (heroku-24) - Integration testing on all supported Ubuntu versions * Fix multi arch test compilation From: https://github.com/heroku/buildpacks-ruby/pull/284/files#r1603946649. The tests currently fail locally on a Mac (arm64/aarch64) because tests are always being compiled for amd64/x86. This change is a workaround to force compilation to the current target architecture. * Apply suggestions from code review Co-authored-by: Ed Morley <501702+edmorley@users.noreply.github.com> * Fix variable name --------- Co-authored-by: Ed Morley <501702+edmorley@users.noreply.github.com>
1 parent 6966b88 commit b863136

File tree

6 files changed

+87
-15
lines changed

6 files changed

+87
-15
lines changed
 

‎Cargo.lock

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎buildpacks/ruby/CHANGELOG.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
- The buildpack now implements Buildpack API 0.10 instead of 0.9, and so requires `lifecycle` 0.17.x or newer. ([#283](https://github.com/heroku/buildpacks-ruby/pull/283/files#commit-suggestions))
10+
### Changed
11+
12+
- The buildpack now implements Buildpack API 0.10 instead of 0.9, and so requires `lifecycle` 0.17.x or newer. ([#283](https://github.com/heroku/buildpacks-ruby/pull/283))
13+
14+
### Added
15+
16+
- Added support for Ubuntu 24.04 (and thus Heroku-24 / `heroku/builder:24`). ([#284](https://github.com/heroku/buildpacks-ruby/pull/284))
1117

1218
## [2.1.3] - 2024-03-18
1319

‎buildpacks/ruby/buildpack.toml

+12
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,17 @@ version = "20.04"
2828
name = "ubuntu"
2929
version = "22.04"
3030

31+
[[targets.distros]]
32+
name = "ubuntu"
33+
version = "24.04"
34+
35+
[[targets]]
36+
os = "linux"
37+
arch = "arm64"
38+
39+
[[targets.distros]]
40+
name = "ubuntu"
41+
version = "24.04"
42+
3143
[metadata.release]
3244
image = { repository = "docker.io/heroku/buildpack-ruby" }

‎buildpacks/ruby/src/layers/ruby_install_layer.rs

+11-4
Original file line numberDiff line numberDiff line change
@@ -236,11 +236,18 @@ fn download_url(
236236
let filename = format!("ruby-{version}.tgz");
237237
let base = "https://heroku-buildpack-ruby.s3.us-east-1.amazonaws.com";
238238
let mut url = Url::parse(base).map_err(RubyInstallError::UrlParseError)?;
239+
{
240+
let mut segments = url
241+
.path_segments_mut()
242+
.map_err(|()| RubyInstallError::InvalidBaseUrl(String::from(base)))?;
243+
244+
segments.push(&target.stack_name().map_err(RubyInstallError::TargetError)?);
245+
if target.is_arch_aware() {
246+
segments.push(&target.cpu_architecture);
247+
}
248+
segments.push(&filename);
249+
}
239250

240-
url.path_segments_mut()
241-
.map_err(|()| RubyInstallError::InvalidBaseUrl(String::from(base)))?
242-
.push(&target.stack_name().map_err(RubyInstallError::TargetError)?)
243-
.push(&filename);
244251
Ok(url)
245252
}
246253

‎buildpacks/ruby/src/target_id.rs

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,30 @@
1-
use serde::{Deserialize, Serialize};
2-
3-
#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
4-
#[serde(deny_unknown_fields)]
1+
#[derive(Debug, Clone, PartialEq, Eq)]
52
pub(crate) struct TargetId {
63
pub(crate) distro_name: String,
74
pub(crate) distro_version: String,
85
pub(crate) cpu_architecture: String,
96
}
10-
7+
const ARCH_AWARE_VERSIONS: &[&str] = &["24.04"];
118
const DISTRO_VERSION_STACK: &[(&str, &str, &str)] = &[
129
("ubuntu", "20.04", "heroku-20"),
1310
("ubuntu", "22.04", "heroku-22"),
11+
("ubuntu", "24.04", "heroku-24"),
1412
];
1513

1614
#[derive(Debug, thiserror::Error)]
1715
pub(crate) enum TargetIdError {
18-
#[error("Distro name and version {0}-{1} is not supported. Must be one of: {}", DISTRO_VERSION_STACK.iter().map(|&(name, version, _)| format!("{name}-{version}")).collect::<Vec<_>>().join(", "))]
16+
#[error("Distro name and version '{0}-{1}' is not supported. Must be one of: {}", DISTRO_VERSION_STACK.iter().map(|&(name, version, _)| format!("'{name}-{version}'")).collect::<Vec<_>>().join(", "))]
1917
UnknownDistroNameVersionCombo(String, String),
2018

21-
#[error("Cannot convert stack name {0} into a target OS. Must be one of: {}", DISTRO_VERSION_STACK.iter().map(|&(_, _, stack)| String::from(stack)).collect::<Vec<_>>().join(", "))]
19+
#[error("Cannot convert stack name '{0}' into a target OS. Must be one of: {}", DISTRO_VERSION_STACK.iter().map(|&(_, _, stack)| format!("'{stack}'")).collect::<Vec<_>>().join(", "))]
2220
UnknownStack(String),
2321
}
2422

2523
impl TargetId {
24+
pub(crate) fn is_arch_aware(&self) -> bool {
25+
ARCH_AWARE_VERSIONS.contains(&self.distro_version.as_str())
26+
}
27+
2628
pub(crate) fn stack_name(&self) -> Result<String, TargetIdError> {
2729
DISTRO_VERSION_STACK
2830
.iter()
@@ -53,6 +55,13 @@ impl TargetId {
5355
mod test {
5456
use super::*;
5557

58+
#[test]
59+
fn test_arch_aware_versions_are_also_known_as_a_stack() {
60+
for version in ARCH_AWARE_VERSIONS {
61+
assert!(DISTRO_VERSION_STACK.iter().any(|&(_, v, _)| &v == version));
62+
}
63+
}
64+
5665
#[test]
5766
fn test_stack_name() {
5867
assert_eq!(

‎buildpacks/ruby/tests/integration_test.rs

+39-1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ use ureq::Response;
1616
#[test]
1717
#[ignore = "integration test"]
1818
fn test_migrating_metadata() {
19+
// This test is a placeholder for when a change modifies metadata structures.
20+
// Remove the return and update the `buildpack-ruby` reference to the latest version.
21+
#![allow(unreachable_code)]
22+
return;
23+
1924
let builder = "heroku/builder:22";
2025
let app_dir = "tests/fixtures/default_ruby";
2126

@@ -57,9 +62,28 @@ fn test_default_app_ubuntu20() {
5762

5863
#[test]
5964
#[ignore = "integration test"]
60-
fn test_default_app_latest_distro() {
65+
fn test_default_app_ubuntu22() {
6166
TestRunner::default().build(
6267
BuildConfig::new("heroku/builder:22", "tests/fixtures/default_ruby"),
68+
|context| {
69+
println!("{}", context.pack_stdout);
70+
assert_contains!(context.pack_stdout, "# Heroku Ruby Buildpack");
71+
assert_contains!(
72+
context.pack_stdout,
73+
r#"`BUNDLE_BIN="/layers/heroku_ruby/gems/bin" BUNDLE_CLEAN="1" BUNDLE_DEPLOYMENT="1" BUNDLE_GEMFILE="/workspace/Gemfile" BUNDLE_PATH="/layers/heroku_ruby/gems" BUNDLE_WITHOUT="development:test" bundle install`"#);
74+
75+
assert_contains!(context.pack_stdout, "Installing webrick");
76+
},
77+
);
78+
}
79+
80+
#[test]
81+
#[ignore = "integration test"]
82+
fn test_default_app_latest_distro() {
83+
let config = amd_arm_builder_config("heroku/builder:24", "tests/fixtures/default_ruby");
84+
85+
TestRunner::default().build(
86+
config,
6387
|context| {
6488
println!("{}", context.pack_stdout);
6589
assert_contains!(context.pack_stdout, "# Heroku Ruby Buildpack");
@@ -257,3 +281,17 @@ fn frac_seconds(seconds: f64) -> Duration {
257281
}
258282

259283
const TEST_PORT: u16 = 1234;
284+
285+
// TODO: Once Pack build supports `--platform` and libcnb-test adjusted accordingly, change this
286+
// to allow configuring the target arch independently of the builder name (eg via env var).
287+
fn amd_arm_builder_config(builder_name: &str, app_dir: &str) -> BuildConfig {
288+
let mut config = BuildConfig::new(builder_name, app_dir);
289+
290+
match builder_name {
291+
"heroku/builder:24" if cfg!(target_arch = "aarch64") => {
292+
config.target_triple("aarch64-unknown-linux-musl")
293+
}
294+
_ => config.target_triple("x86_64-unknown-linux-musl"),
295+
};
296+
config
297+
}

1 commit comments

Comments
 (1)

nickhammond commented on Jun 24, 2024

@nickhammond

Exciting!!!

Please sign in to comment.