use std::time::Duration;
use crate::contract::schema::Adapter;
use crate::protocol::release::{BuildArtifacts, DryRunReport, PlannedCommand, PublishReceipt};
use super::{make_receipt, run_all, AdapterError, AdapterTarget, EffectCtx, ReleaseAdapter};
pub struct CargoAdapter {
adapter: Adapter,
}
impl CargoAdapter {
#[must_use]
pub fn new(adapter: Adapter) -> Self {
debug_assert!(matches!(
adapter,
Adapter::CargoPublish | Adapter::CargoDist
));
Self { adapter }
}
}
impl ReleaseAdapter for CargoAdapter {
fn adapter(&self) -> Adapter {
self.adapter
}
fn dry_run(
&self,
_ctx: &EffectCtx<'_>,
t: &AdapterTarget,
) -> Result<DryRunReport, AdapterError> {
let planned_commands = match self.adapter {
Adapter::CargoDist => vec![PlannedCommand::new(
"dist",
&["plan", "--output-format=json"],
)],
_ => vec![PlannedCommand::new(
"cargo",
&["publish", "-p", &t.package, "--dry-run"],
)],
};
Ok(DryRunReport {
adapter: self.adapter,
planned_commands,
notes: vec![],
})
}
fn build(
&self,
ctx: &EffectCtx<'_>,
t: &AdapterTarget,
) -> Result<BuildArtifacts, AdapterError> {
let (cmds, artifacts) = match self.adapter {
Adapter::CargoDist => (
vec![PlannedCommand::new("dist", &["build"])],
vec!["dist/".to_string()],
),
_ => (
vec![PlannedCommand::new("cargo", &["package", "-p", &t.package])],
vec![format!("{}-{}.crate", t.package, t.version)],
),
};
run_all(ctx, &cmds)?;
Ok(BuildArtifacts {
adapter: self.adapter,
artifacts,
notes: vec![],
})
}
fn publish(
&self,
ctx: &EffectCtx<'_>,
t: &AdapterTarget,
) -> Result<PublishReceipt, AdapterError> {
if matches!(self.adapter, Adapter::CargoDist) {
return Err(AdapterError::Unsupported {
adapter: self.adapter,
operation: "publish",
});
}
run_all(
ctx,
&[PlannedCommand::new("cargo", &["publish", "-p", &t.package])],
)?;
let remote_url = Some(format!(
"https://crates.io/crates/{}/{}",
t.package, t.version
));
Ok(make_receipt(ctx, t, None, remote_url))
}
fn timeout(&self) -> Duration {
Duration::from_secs(600)
}
}