~ knotless Search/
↑↓ move↵ open⇧↵ all results

chadtmiller.com/knotless

git that lives in your Atmosphere account

knotless.dev
1 collaborator

knotless 0.13.0 Latest 2 packages, 1 image

1
10

A release not made says why, rather than always that it exists

Merged chadtmiller.com asked to merge into main from chadtmiller.com/knotless:release/published-already

Only what this pull adds. A release can be yanked, leaving it to read but no one's latest landed as a59f04e, so its changes do not show here again.

.changeset/release-published-already.mdnew+7−0
@@ -0,0 +1,7 @@
---
default: patch
---
# A release that fails to publish says why
Publishing a version now says it is published already only when it is. Any other failure, such as a login that was refused, gives its own reason.
crates/knotless/src/release.rs+13−4
@@ -252,10 +252,19 @@ impl Target {
};
let typed = records::typed(nsid::RELEASE, &record);
let write = remote::create(nsid::RELEASE, &self.rkey, typed);
// A publish that raced this one to the version made the record first.
let made = self.remote.apply(vec![write], auth).await;
made.context(self.published())?;
Ok(self.uri.clone())
let Err(failed) = self.remote.apply(vec![write], auth).await else {
return Ok(self.uri.clone());
};
// A publish that raced this one to the version made the record
// first. A PDS need not say so, as the reference PDS's plain 500
// does not, so only the record tells that from any other failure.
let found = self
.remote
.get_record::<ReleaseRecord>(nsid::RELEASE, &self.rkey);
match found.await? {
Some(_) => bail!(self.published()),
None => Err(failed),
}
}
}
crates/knotless-serve/tests/releases.rs+53−0
@@ -750,6 +750,59 @@ fn pushing_an_image() {
assert_eq!(Pushing::code(p.manifest(&image_digest, &image)).0, 502);
}
// A lost race is told apart from any other failed write, which says what
// went wrong rather than that the version was published.
#[test]
fn a_release_not_made_says_why() {
use knotless::push;
use knotless::records::{RELEASE_MIME, ReleaseFile, ReleasePart};
use knotless::release::{Made, Target};
use knotless::url::RepoUrl;
use knotless::xrpc::Auth;
let mut s = Sandbox::new();
let handle = s.account.handle.clone();
s.set("KNOTLESS_IDENTIFIER", &handle);
let url = s.url("raced");
let work = s.work("w", 1);
s.git(&work, &["push", "-q", &url, "main"]);
let ctx = ctx(&s);
let url = RepoUrl::parse(&url).unwrap();
let rt = tokio::runtime::Runtime::new().unwrap();
rt.block_on(async {
let session = knotless::session::create(&ctx, &handle, &s.account.password);
let auth = session.await.unwrap().auth();
let target = Target::open(&ctx, &url, "tool", "1.0.0").await.unwrap();
let blobs = push::upload(&ctx, &target.remote, &auth, b"x", RELEASE_MIME);
let file = ReleaseFile {
name: "x".into(),
size: 1,
sha256: knotless::release::sha256(b"x"),
parts: blobs
.await
.unwrap()
.into_iter()
.map(|blob| ReleasePart { blob })
.collect(),
};
let stranger = Auth::Bearer("no such token".into());
let create = |auth| target.create(auth, vec![file.clone()], Made::default());
let refused = create(&stranger).await.unwrap_err();
assert!(
!format!("{refused:#}").contains("published already"),
"{refused:#}"
);
create(&auth).await.unwrap();
let lost = create(&auth).await.unwrap_err();
assert!(
format!("{lost:#}").contains("tool 1.0.0 is published already"),
"{lost:#}"
);
});
}
/// An appview handing out the releases in `dir`, whose describeServer
/// answers what `described` holds.
fn appview(dir: &Path, described: Arc<Mutex<serde_json::Value>>) -> Server {