pub trait ReleaseAdapter {
// Required methods
fn adapter(&self) -> Adapter;
fn dry_run(
&self,
ctx: &EffectCtx<'_>,
target: &AdapterTarget,
) -> Result<DryRunReport, AdapterError>;
fn build(
&self,
ctx: &EffectCtx<'_>,
target: &AdapterTarget,
) -> Result<BuildArtifacts, AdapterError>;
fn publish(
&self,
ctx: &EffectCtx<'_>,
target: &AdapterTarget,
) -> Result<PublishReceipt, AdapterError>;
fn timeout(&self) -> Duration;
// Provided methods
fn is_ci_delegated(&self) -> bool { ... }
fn ci_owns_github_release(&self) -> bool { ... }
fn verify(
&self,
ctx: &EffectCtx<'_>,
receipt: &PublishReceipt,
) -> Result<VerifyOutcome, AdapterError> { ... }
}Expand description
The per-ecosystem operations the release coordinator drives through its phase barriers (ADR-0002 §1).
Deliberately has no tag() — the shared git tag and GitHub Release are
owned by the coordinator alone, which is what makes “tag once, after every
publish” a structural guarantee rather than a discipline.
Required Methods§
Sourcefn adapter(&self) -> Adapter
fn adapter(&self) -> Adapter
The adapter identity this implementation operates as (a single struct may
back several related identities, e.g. cargo-publish and cargo-dist).
Sourcefn dry_run(
&self,
ctx: &EffectCtx<'_>,
target: &AdapterTarget,
) -> Result<DryRunReport, AdapterError>
fn dry_run( &self, ctx: &EffectCtx<'_>, target: &AdapterTarget, ) -> Result<DryRunReport, AdapterError>
Re-runnable, side-effect-free preview: the exact commands a real cut
would run for target.
§Errors
Returns AdapterError only if constructing the preview itself fails;
building a preview does not execute the planned commands.
Sourcefn build(
&self,
ctx: &EffectCtx<'_>,
target: &AdapterTarget,
) -> Result<BuildArtifacts, AdapterError>
fn build( &self, ctx: &EffectCtx<'_>, target: &AdapterTarget, ) -> Result<BuildArtifacts, AdapterError>
Re-runnable build of the target’s publishable artifacts.
§Errors
Returns AdapterError if a build command fails or is unsupported.
Sourcefn publish(
&self,
ctx: &EffectCtx<'_>,
target: &AdapterTarget,
) -> Result<PublishReceipt, AdapterError>
fn publish( &self, ctx: &EffectCtx<'_>, target: &AdapterTarget, ) -> Result<PublishReceipt, AdapterError>
Per-target irreversible publish; returns the durable
PublishReceipt.
§Errors
Returns AdapterError if a publish command fails or the publish is
unsupported from this host.
Provided Methods§
Sourcefn is_ci_delegated(&self) -> bool
fn is_ci_delegated(&self) -> bool
Whether this adapter’s publish is CI-delegated — its release artifact
is produced out-of-band by the tag-triggered CI (e.g. cargo-dist’s
release.yml, a release-please merge job, PyPI’s trusted-publisher
workflow), never by the engine’s publish step from this
host. The coordinator skips such a target in publish-all (journalling a
target_delegated fact) rather than calling publish and treating its
honest AdapterError::Unsupported as a phase failure — which would leave
the cut stuck after an irreversible crates.io publish.
This is a first-class capability the coordinator branches on; it is not
inferred from a publish that returns AdapterError::Unsupported. An
adapter that returns Unsupported without declaring itself CI-delegated is
a genuine error and still fails the cut. The invariant every CI-delegated
adapter upholds: is_ci_delegated() ⇒ publish returns
AdapterError::Unsupported.
Defaults to false (the engine owns the publish); the three delegated
identities (cargo-dist, release-please, gh-action-pypi-publish)
override it.
Sourcefn ci_owns_github_release(&self) -> bool
fn ci_owns_github_release(&self) -> bool
Whether this adapter’s tag-triggered CI owns the shared GitHub Release —
its workflow creates and finalizes the Release object (and uploads the
cross-platform binaries into it), so the coordinator must NOT create the
Release itself or the two clash over the same tag
(coordinator-release-vs-cargo-dist-ownership).
This is a strict subset of is_ci_delegated, not
a synonym: an adapter can be CI-delegated for its publish yet not own the
GitHub Release. gh-action-pypi-publish uploads to PyPI (not GitHub) and
release-please is publish-on-merge — neither runs gh release create for
this tag, so for those the coordinator still creates the Release. Only
cargo-dist, whose generated release.yml runs gh release create <tag> … artifacts/* (a create, not an upsert — it errors if the Release pre-exists),
overrides this to true. Defaults to false (the coordinator owns the
Release, the ADR-0002 default).
Sourcefn verify(
&self,
ctx: &EffectCtx<'_>,
receipt: &PublishReceipt,
) -> Result<VerifyOutcome, AdapterError>
fn verify( &self, ctx: &EffectCtx<'_>, receipt: &PublishReceipt, ) -> Result<VerifyOutcome, AdapterError>
Read-only remote reconcile of a receipt against registry state.
The default implementation queries RegistryQuery by the receipt’s
ecosystem + package and classifies via classify_receipt; a lookup
failure yields VerifyOutcome::Unknown. Adapters whose destination is
not observable through RegistryQuery (homebrew taps, GitHub Releases)
override this to return VerifyOutcome::Unknown explicitly.
§Errors
The default never errors (an outage is VerifyOutcome::Unknown, not an
Err); the fallible signature lets an override that shells out report a
genuine command failure.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".