From dc95de5a3bdf555c0056f3701ffa6ea864d71ae1 Mon Sep 17 00:00:00 2001 From: Josh W Lewis Date: Fri, 23 Feb 2024 10:23:48 -0600 Subject: [PATCH] Reintroduce Stack, with weak validation (#789) * Reintroduce Stack (but with weaker validation) * Reintroduce stacks into deserialization tests * Add changelog entry for stack reintroduction * Skip serializing empty mixins Co-authored-by: Ed Morley <501702+edmorley@users.noreply.github.com> --------- Co-authored-by: Ed Morley <501702+edmorley@users.noreply.github.com> --- CHANGELOG.md | 3 ++ libcnb-data/src/buildpack/mod.rs | 40 ++++++++++++++++++++ libcnb-data/src/buildpack/stack.rs | 60 ++++++++++++++++++++++++++++++ libcnb/src/layer/tests.rs | 1 + 4 files changed, 104 insertions(+) create mode 100644 libcnb-data/src/buildpack/stack.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 583f0fc7..38cc743b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `libcnb-data': + - Reintroduced support for deserializing `[[stacks]]` in `buildpack.toml`. + ([#789](https://github.com/heroku/libcnb.rs/pull/789)) - `libherokubuildpack`: - Added `buildpack_output` module. This will help buildpack authors provide consistent and delightful output to their buildpack users ([#721](https://github.com/heroku/libcnb.rs/pull/721)) diff --git a/libcnb-data/src/buildpack/mod.rs b/libcnb-data/src/buildpack/mod.rs index 9801c548..06cf27cf 100644 --- a/libcnb-data/src/buildpack/mod.rs +++ b/libcnb-data/src/buildpack/mod.rs @@ -1,5 +1,6 @@ mod api; mod id; +mod stack; mod target; mod version; @@ -8,6 +9,7 @@ use crate::sbom::SbomFormat; pub use api::*; pub use id::*; use serde::Deserialize; +pub use stack::*; use std::collections::HashSet; pub use target::*; pub use version::*; @@ -120,6 +122,8 @@ pub struct ComponentBuildpackDescriptor { pub api: BuildpackApi, pub buildpack: Buildpack, #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub stacks: Vec, + #[serde(default, skip_serializing_if = "Vec::is_empty")] pub targets: Vec, pub metadata: BM, // As of 2024-02-09, the CNB spec does not forbid component buildpacks @@ -257,6 +261,20 @@ uri = "https://example.tld/my-license" [[buildpack.licenses]] uri = "https://example.tld/my-license" +[[stacks]] +id = "heroku-20" + +[[stacks]] +id = "io.buildpacks.stacks.bionic" +mixins = [] + +[[stacks]] +id = "io.buildpacks.stacks.focal" +mixins = ["build:jq", "wget"] + +[[stacks]] +id = "*" + [[targets]] os = "linux" arch = "amd64" @@ -339,6 +357,27 @@ checksum = "abc123" SbomFormat::SpdxJson ]) ); + assert_eq!( + buildpack_descriptor.stacks, + [ + Stack { + id: String::from("heroku-20"), + mixins: Vec::new(), + }, + Stack { + id: String::from("io.buildpacks.stacks.bionic"), + mixins: Vec::new(), + }, + Stack { + id: String::from("io.buildpacks.stacks.focal"), + mixins: vec![String::from("build:jq"), String::from("wget")] + }, + Stack { + id: String::from("*"), + mixins: Vec::new() + } + ] + ); assert_eq!( buildpack_descriptor.targets, [ @@ -529,6 +568,7 @@ version = "0.0.1" ); assert_eq!(buildpack_descriptor.buildpack.licenses, Vec::new()); assert_eq!(buildpack_descriptor.buildpack.sbom_formats, HashSet::new()); + assert_eq!(buildpack_descriptor.stacks, []); assert_eq!(buildpack_descriptor.targets, []); assert_eq!(buildpack_descriptor.metadata, None); } diff --git a/libcnb-data/src/buildpack/stack.rs b/libcnb-data/src/buildpack/stack.rs new file mode 100644 index 00000000..012d6254 --- /dev/null +++ b/libcnb-data/src/buildpack/stack.rs @@ -0,0 +1,60 @@ +use serde::Deserialize; + +// Stacks are deprecated in Buildpack API 0.10, and libcnb.rs effectively +// ignores them. However, they are still supported by the Buildpack API, so +// libcnb should continue to allow them to exist in buildpack.toml. +#[derive(Deserialize, Debug, Eq, PartialEq)] +#[serde(deny_unknown_fields)] +pub struct Stack { + pub id: String, + #[serde(default, skip_serializing_if = "Vec::is_empty")] + pub mixins: Vec, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn deserialize_specific_stack_without_mixins() { + let toml_str = r#" +id = "heroku-20" +"#; + assert_eq!( + toml::from_str::(toml_str), + Ok(Stack { + id: String::from("heroku-20"), + mixins: Vec::new() + }), + ); + } + + #[test] + fn deserialize_specific_stack_with_mixins() { + let toml_str = r#" +id = "io.buildpacks.stacks.focal" +mixins = ["build:jq", "wget"] +"#; + assert_eq!( + toml::from_str::(toml_str), + Ok(Stack { + id: String::from("io.buildpacks.stacks.focal"), + mixins: vec![String::from("build:jq"), String::from("wget")] + }), + ); + } + + #[test] + fn deserialize_any_stack() { + let toml_str = r#" +id = "*" +"#; + assert_eq!( + toml::from_str::(toml_str), + Ok(Stack { + id: String::from("*"), + mixins: vec![], + }), + ); + } +} diff --git a/libcnb/src/layer/tests.rs b/libcnb/src/layer/tests.rs index a549278a..323c7242 100644 --- a/libcnb/src/layer/tests.rs +++ b/libcnb/src/layer/tests.rs @@ -925,6 +925,7 @@ fn build_context(temp_dir: &TempDir) -> BuildContext { licenses: Vec::new(), sbom_formats: HashSet::new(), }, + stacks: vec![], targets: vec![Target { os: Some(String::from("linux")), arch: Some(String::from("amd64")),