Skip to content

Commit

Permalink
Add check to disable publishing unstable APIs
Browse files Browse the repository at this point in the history
Signed-off-by: Ryan Bottriell <ryan@bottriell.ca>
  • Loading branch information
rydrman committed Feb 16, 2024
1 parent 4a0f218 commit a6a69cb
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 17 deletions.
20 changes: 20 additions & 0 deletions crates/spk-cli/common/src/publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ pub struct Publisher {
from: Arc<storage::RepositoryHandle>,
to: Arc<storage::RepositoryHandle>,
skip_source_packages: bool,
allow_unstable_api: bool,
force: bool,
}

Expand All @@ -42,6 +43,7 @@ impl Publisher {
from: source,
to: destination,
skip_source_packages: false,
allow_unstable_api: false,
force: false,
}
}
Expand All @@ -64,6 +66,12 @@ impl Publisher {
self
}

/// Allow publishing packages defined with an unstable api version
pub fn allow_unstable_api(mut self, allow_unstable_api: bool) -> Self {
self.allow_unstable_api = allow_unstable_api;
self
}

/// Forcefully publishing a package will overwrite an existing publish if it exists.
pub fn force(mut self, force: bool) -> Self {
self.force = force;
Expand Down Expand Up @@ -93,6 +101,12 @@ impl Publisher {
}
Err(err) => return Err(err.into()),
Ok(recipe) => {
if !recipe.api_version().is_stable() && !self.allow_unstable_api {
return Err(Error::String(format!(
"Recipe has unstable api version, and allow unstable is not set: {:?}",
recipe.api_version()
)));
}
tracing::info!("publishing recipe: {}", recipe.ident().format_ident());
if self.force {
self.to.force_publish_recipe(&recipe).await?;
Expand Down Expand Up @@ -151,6 +165,12 @@ impl Publisher {

tracing::debug!(" loading package: {}", build.format_ident());
let spec = self.from.read_package(build).await?;
if !spec.api_version().is_stable() && !self.allow_unstable_api {
return Err(Error::String(format!(
"Package build has unstable api version, and allow unstable is not set: {:?}",
spec.api_version()
)));
}
let components = self.from.read_components(build).await?;
tracing::info!("publishing package: {}", spec.ident().format_ident());
let env_spec = components.values().cloned().collect();
Expand Down
7 changes: 7 additions & 0 deletions crates/spk-cli/group2/src/cmd_publish.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ pub struct Publish {
#[clap(long, short)]
force: bool,

/// Allow publishing package specs written in unstable api versions
///
/// The api version of a spec is the value of the `api` field within it.
#[clap(long)]
allow_unstable_api: bool,

/// The local packages to publish
///
/// This can be an entire package version with all builds or a
Expand All @@ -54,6 +60,7 @@ impl Run for Publish {

let publisher = Publisher::new(Arc::new(source.into()), Arc::new(target.into()))
.skip_source_packages(self.no_source)
.allow_unstable_api(self.allow_unstable_api)
.force(self.force);

let mut published = Vec::new();
Expand Down
60 changes: 43 additions & 17 deletions crates/spk-schema/src/spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,15 @@ pub enum SpecRecipe {
V0Platform(super::v0::Platform),
}

impl SpecRecipe {
pub fn api_version(&self) -> RecipeApiVersion {
match self {
Self::V0Package(_) => RecipeApiVersion::V0Package,
Self::V0Platform(_) => RecipeApiVersion::V0Platform,
}
}
}

impl Recipe for SpecRecipe {
type Output = Spec;
type Variant = SpecVariant;
Expand Down Expand Up @@ -398,8 +407,8 @@ impl FromYaml for SpecRecipe {
// fairly generic, eg: 'expected struct YamlMapping'
#[derive(Deserialize)]
struct YamlMapping {
#[serde(default = "ApiVersion::default")]
api: ApiVersion,
#[serde(default = "RecipeApiVersion::default")]
api: RecipeApiVersion,
}

let with_version = match serde_yaml::from_str::<YamlMapping>(&yaml) {
Expand All @@ -413,12 +422,12 @@ impl FromYaml for SpecRecipe {
};

match with_version.api {
ApiVersion::V0Package => {
RecipeApiVersion::V0Package => {
let inner = serde_yaml::from_str(&yaml)
.map_err(|err| SerdeError::new(yaml, SerdeYamlError(err)))?;
Ok(Self::V0Package(inner))
}
ApiVersion::V0Platform => {
RecipeApiVersion::V0Platform => {
let inner = serde_yaml::from_str(&yaml)
.map_err(|err| SerdeError::new(yaml, SerdeYamlError(err)))?;
Ok(Self::V0Platform(inner))
Expand Down Expand Up @@ -490,6 +499,14 @@ pub enum Spec {
V0Package(super::v0::Spec<BuildIdent>),
}

impl Spec {
pub fn api_version(&self) -> PackageApiVersion {
match self {
Self::V0Package(_) => PackageApiVersion::V0Package,
}
}
}

impl Satisfy<PkgRequest> for Spec {
fn check_satisfies_request(&self, request: &PkgRequest) -> Compatibility {
match self {
Expand Down Expand Up @@ -659,8 +676,8 @@ impl FromYaml for Spec {
// fairly generic, eg: 'expected struct YamlMapping'
#[derive(Deserialize)]
struct YamlMapping {
#[serde(default = "ApiVersion::default")]
api: ApiVersion,
#[serde(default = "PackageApiVersion::default")]
api: PackageApiVersion,
}

let with_version = match serde_yaml::from_str::<YamlMapping>(&yaml) {
Expand All @@ -674,12 +691,7 @@ impl FromYaml for Spec {
};

match with_version.api {
ApiVersion::V0Package => {
let inner = serde_yaml::from_str(&yaml)
.map_err(|err| SerdeError::new(yaml, SerdeYamlError(err)))?;
Ok(Self::V0Package(inner))
}
ApiVersion::V0Platform => {
PackageApiVersion::V0Package => {
let inner = serde_yaml::from_str(&yaml)
.map_err(|err| SerdeError::new(yaml, SerdeYamlError(err)))?;
Ok(Self::V0Package(inner))
Expand All @@ -694,16 +706,30 @@ impl AsRef<Spec> for Spec {
}
}

#[derive(Deserialize, Serialize, Copy, Clone)]
pub enum ApiVersion {
#[derive(Default, Debug, Deserialize, Serialize, Copy, Clone)]
pub enum RecipeApiVersion {
#[default]
#[serde(rename = "v0/package")]
V0Package,
#[serde(rename = "v0/platform")]
V0Platform,
}

impl Default for ApiVersion {
fn default() -> Self {
Self::V0Package
impl RecipeApiVersion {
pub fn is_stable(&self) -> bool {
matches!(self, Self::V0Package)
}
}

#[derive(Default, Debug, Deserialize, Serialize, Copy, Clone)]
pub enum PackageApiVersion {
#[default]
#[serde(rename = "v0/package")]
V0Package,
}

impl PackageApiVersion {
pub fn is_stable(&self) -> bool {
matches!(self, Self::V0Package)
}
}

0 comments on commit a6a69cb

Please sign in to comment.