use std::time::Duration;
use crate::contract::schema::Adapter;
use crate::protocol::release::{
BuildArtifacts, DryRunReport, PlannedCommand, PublishReceipt, VerifyOutcome,
};
use super::{make_receipt, run_all, AdapterError, AdapterTarget, EffectCtx, ReleaseAdapter};
pub struct BinaryAdapter {
adapter: Adapter,
}
impl BinaryAdapter {
#[must_use]
pub fn new(adapter: Adapter) -> Self {
debug_assert!(matches!(adapter, Adapter::Manual));
Self { adapter }
}
fn tag(t: &AdapterTarget) -> String {
format!("v{}", t.version)
}
}
impl ReleaseAdapter for BinaryAdapter {
fn adapter(&self) -> Adapter {
self.adapter
}
fn dry_run(
&self,
_ctx: &EffectCtx<'_>,
t: &AdapterTarget,
) -> Result<DryRunReport, AdapterError> {
Ok(DryRunReport {
adapter: self.adapter,
planned_commands: vec![PlannedCommand::new(
"gh",
&["release", "view", &Self::tag(t)],
)],
notes: vec!["artifacts are built by the ecosystem's own build step and \
uploaded to the coordinator-owned GitHub Release"
.to_string()],
})
}
fn build(
&self,
_ctx: &EffectCtx<'_>,
_t: &AdapterTarget,
) -> Result<BuildArtifacts, AdapterError> {
Ok(BuildArtifacts {
adapter: self.adapter,
artifacts: vec![],
notes: vec![
"binary target has no build phase (uploads prebuilt artifacts)".to_string(),
],
})
}
fn publish(
&self,
ctx: &EffectCtx<'_>,
t: &AdapterTarget,
) -> Result<PublishReceipt, AdapterError> {
let tag = Self::tag(t);
let slug = ctx.artifacts.repo_slug.as_deref();
let mut args = vec!["release", "upload", tag.as_str()];
if let Some(slug) = slug {
args.push("--repo");
args.push(slug);
}
args.push("--clobber");
args.push("--");
args.extend(ctx.artifacts.assets.iter().map(String::as_str));
run_all(ctx, &[PlannedCommand::new("gh", &args)])?;
let remote_url = slug.map(|slug| format!("https://github.com/{slug}/releases/tag/{tag}"));
Ok(make_receipt(ctx, t, None, remote_url))
}
fn verify(
&self,
_ctx: &EffectCtx<'_>,
_receipt: &PublishReceipt,
) -> Result<VerifyOutcome, AdapterError> {
Ok(VerifyOutcome::Unknown)
}
fn timeout(&self) -> Duration {
Duration::from_secs(600)
}
}