Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Heroku-24 and ARM architecture #284

Merged
merged 4 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from 2 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
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 9 additions & 1 deletion buildpacks/ruby/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

- 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))
### Changed
edmorley marked this conversation as resolved.
Show resolved Hide resolved

- 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))

### Added

- Added support for Ubuntu 24.04 (and thus Heroku-24 / `heroku/builder:24`). ([#284](https://github.com/heroku/buildpacks-ruby/pull/284))

### Fixed
schneems marked this conversation as resolved.
Show resolved Hide resolved

## [2.1.3] - 2024-03-18

Expand Down
12 changes: 12 additions & 0 deletions buildpacks/ruby/buildpack.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,17 @@ version = "20.04"
name = "ubuntu"
version = "22.04"

[[targets.distros]]
name = "ubuntu"
version = "24.04"

[[targets]]
os = "linux"
arch = "arm64"

[[targets.distros]]
name = "ubuntu"
version = "24.04"

[metadata.release]
image = { repository = "docker.io/heroku/buildpack-ruby" }
15 changes: 11 additions & 4 deletions buildpacks/ruby/src/layers/ruby_install_layer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,11 +236,18 @@ fn download_url(
let filename = format!("ruby-{version}.tgz");
let base = "https://heroku-buildpack-ruby.s3.us-east-1.amazonaws.com";
let mut url = Url::parse(base).map_err(RubyInstallError::UrlParseError)?;
{
let mut segments = url
.path_segments_mut()
.map_err(|()| RubyInstallError::InvalidBaseUrl(String::from(base)))?;

segments.push(&target.stack_name().map_err(RubyInstallError::TargetError)?);
if target.is_arch_aware() {
segments.push(&target.cpu_architecture);
}
segments.push(&filename);
}

url.path_segments_mut()
.map_err(|()| RubyInstallError::InvalidBaseUrl(String::from(base)))?
.push(&target.stack_name().map_err(RubyInstallError::TargetError)?)
.push(&filename);
Ok(url)
}

Expand Down
23 changes: 16 additions & 7 deletions buildpacks/ruby/src/target_id.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,30 @@
use serde::{Deserialize, Serialize};

#[derive(Deserialize, Serialize, Debug, Clone, PartialEq, Eq)]
#[serde(deny_unknown_fields)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub(crate) struct TargetId {
pub(crate) distro_name: String,
pub(crate) distro_version: String,
pub(crate) cpu_architecture: String,
}

const ARCH_AWARE_VERSIONS: &[&str] = &["24.04"];
const DISTRO_VERSION_STACK: &[(&str, &str, &str)] = &[
("ubuntu", "20.04", "heroku-20"),
("ubuntu", "22.04", "heroku-22"),
("ubuntu", "24.04", "heroku-24"),
];

#[derive(Debug, thiserror::Error)]
pub(crate) enum TargetIdError {
#[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(", "))]
#[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(", "))]
UnknownDistroNameVersionCombo(String, String),

#[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(", "))]
#[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(", "))]
UnknownStack(String),
}

impl TargetId {
pub(crate) fn is_arch_aware(&self) -> bool {
ARCH_AWARE_VERSIONS.contains(&self.distro_version.as_str())
}

pub(crate) fn stack_name(&self) -> Result<String, TargetIdError> {
DISTRO_VERSION_STACK
.iter()
Expand Down Expand Up @@ -53,6 +55,13 @@ impl TargetId {
mod test {
use super::*;

#[test]
fn test_arch_aware_versions_are_also_known_as_a_stack() {
for version in ARCH_AWARE_VERSIONS {
assert!(DISTRO_VERSION_STACK.iter().any(|&(_, v, _)| &v == version));
}
}

#[test]
fn test_stack_name() {
assert_eq!(
Expand Down
40 changes: 39 additions & 1 deletion buildpacks/ruby/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,11 @@ use ureq::Response;
#[test]
#[ignore = "integration test"]
fn test_migrating_metadata() {
// This test is a placeholder for when a change modifies metadata structures.
// Remove the return and update the `buildpack-ruby` reference to the latest version.
#![allow(unreachable_code)]
return;

let builder = "heroku/builder:22";
let app_dir = "tests/fixtures/default_ruby";

Expand Down Expand Up @@ -57,9 +62,28 @@ fn test_default_app_ubuntu20() {

#[test]
#[ignore = "integration test"]
fn test_default_app_latest_distro() {
fn test_default_app_ubuntu22() {
TestRunner::default().build(
BuildConfig::new("heroku/builder:22", "tests/fixtures/default_ruby"),
|context| {
println!("{}", context.pack_stdout);
assert_contains!(context.pack_stdout, "# Heroku Ruby Buildpack");
assert_contains!(
context.pack_stdout,
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`"#);

assert_contains!(context.pack_stdout, "Installing webrick");
},
);
}

#[test]
#[ignore = "integration test"]
fn test_default_app_latest_distro() {
schneems marked this conversation as resolved.
Show resolved Hide resolved
let config = amd_arm_builder_config("heroku/builder:24", "tests/fixtures/default_ruby");

TestRunner::default().build(
config,
|context| {
println!("{}", context.pack_stdout);
assert_contains!(context.pack_stdout, "# Heroku Ruby Buildpack");
Expand Down Expand Up @@ -257,3 +281,17 @@ fn frac_seconds(seconds: f64) -> Duration {
}

const TEST_PORT: u16 = 1234;

// TODO: Once Pack build supports `--platform` and libcnb-test adjusted accordingly, change this
// to allow configuring the target arch independently of the builder name (eg via env var).
fn amd_arm_builder_config(builder_name: &str, app_dir: &str) -> BuildConfig {
let mut builder = BuildConfig::new(builder_name, app_dir);
schneems marked this conversation as resolved.
Show resolved Hide resolved

match builder_name {
"heroku/builder:24" if cfg!(target_arch = "aarch64") => {
builder.target_triple("aarch64-unknown-linux-musl")
}
_ => builder.target_triple("x86_64-unknown-linux-musl"),
};
builder
schneems marked this conversation as resolved.
Show resolved Hide resolved
}