Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lib/backend-api/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1441,6 +1441,19 @@ type ChangePackageVersionArchivedStatusPayload {
packageVersion: PackageVersion!
}

input YankPackageVersionsInput {
packageVersionIds: [ID!]!
reason: String
undo: Boolean
clientMutationId: String
}

type YankPackageVersionsPayload {
clientMutationId: String
package: Package!
packageVersions: [PackageVersion!]!
}

input ChangeUserEmailInput {
newEmail: String!
clientMutationId: String
Expand Down Expand Up @@ -4112,6 +4125,7 @@ type Mutation {
archivePackage(input: ArchivePackageInput!): ArchivePackagePayload
renamePackage(input: RenamePackageInput!): RenamePackagePayload
changePackageVersionArchivedStatus(input: ChangePackageVersionArchivedStatusInput!): ChangePackageVersionArchivedStatusPayload
yankPackageVersions(input: YankPackageVersionsInput!): YankPackageVersionsPayload
invitePackageCollaborator(input: InvitePackageCollaboratorInput!): InvitePackageCollaboratorPayload
acceptPackageCollaboratorInvite(input: AcceptPackageCollaboratorInviteInput!): AcceptPackageCollaboratorInvitePayload
removePackageCollaboratorInvite(input: RemovePackageCollaboratorInviteInput!): RemovePackageCollaboratorInvitePayload
Expand Down Expand Up @@ -5016,13 +5030,16 @@ type PackageVersion implements Node & PackageInstance & PackageReleaseInterface
license: String
licenseFile: String
readme: String
rebuilds: [PackageVersion!]!
witMd: String
repository: String
homepage: String
staticObjectsCompiled: Boolean!
nativeExecutablesCompiled: Boolean!
signature: Signature
isArchived: Boolean!
yankedAt: DateTime
yankReason: String
file: String!
fileSize: BigInt!
totalDownloads: Int!
Expand Down
65 changes: 63 additions & 2 deletions lib/backend-api/src/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -880,7 +880,7 @@ pub async fn fetch_webc_package(
PackageIdent::Named(n) => Url::parse(&format!(
"{default_registry}/{}:{}",
n.full_name(),
n.version_or_default()
n.version_string()
))?,
PackageIdent::Hash(h) => match get_package_release(client, &h.to_string()).await? {
Some(webc) => Url::parse(&webc.webc_url)?,
Expand Down Expand Up @@ -1385,6 +1385,64 @@ pub async fn push_package_release(
.map(|r| r.push_package_release)
}

/// Yank (or, with `undo`, unyank) an explicit set of package versions by node
/// id.
///
/// Requires package-admin rights. Returns only the versions whose yank state
/// changed, so a repeated yank comes back empty.
pub async fn yank_package_versions(
client: &WasmerClient,
package_version_ids: Vec<cynic::Id>,
reason: Option<&str>,
undo: bool,
) -> Result<Vec<types::YankedPackageVersion>, anyhow::Error> {
client
.run_graphql_strict(types::YankPackageVersions::build(
types::YankPackageVersionsVariables {
package_version_ids,
reason,
undo: Some(undo),
},
))
.await
.map(|response| {
response
.yank_package_versions
.map(|payload| payload.package_versions)
.unwrap_or_default()
})
}

/// List every package version as `(node id, version)` pairs, including
/// superseded rebuilds, or `None` when the package doesn't exist.
pub async fn get_package_version_ids(
client: &WasmerClient,
name: String,
) -> Result<Option<Vec<(cynic::Id, String)>>, anyhow::Error> {
let package = client
.run_graphql_strict(types::GetPackageVersionNumbers::build(
types::GetPackageVars { name },
))
.await?
.get_package;

Ok(package.map(|p| {
p.versions
.unwrap_or_default()
.into_iter()
.flatten()
.flat_map(|version| {
std::iter::once((version.id, version.version)).chain(
version
.rebuilds
.into_iter()
.map(|rebuild| (rebuild.id, rebuild.version)),
)
})
.collect()
}))
}

#[allow(clippy::too_many_arguments)]
pub async fn tag_package_release(
client: &WasmerClient,
Expand Down Expand Up @@ -2172,7 +2230,10 @@ pub async fn get_package_version_numbers(
.unwrap_or_default()
.into_iter()
.flatten()
.map(|v| v.version)
.flat_map(|version| {
std::iter::once(version.version)
.chain(version.rebuilds.into_iter().map(|rebuild| rebuild.version))
})
.collect()
}))
}
Expand Down
39 changes: 39 additions & 0 deletions lib/backend-api/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,9 @@ mod queries {
pub pirita_manifest: Option<JSONString>,
pub package: Package,

pub yanked_at: Option<DateTime>,
pub yank_reason: Option<String>,

#[arguments(version: "V3")]
#[cynic(rename = "distribution")]
pub distribution_v3: PackageDistribution,
Expand Down Expand Up @@ -457,6 +460,15 @@ mod queries {
#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "PackageVersion")]
pub struct PackageVersionNumber {
pub id: cynic::Id,
pub version: String,
pub rebuilds: Vec<PackageVersionRebuildNumber>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "PackageVersion")]
pub struct PackageVersionRebuildNumber {
pub id: cynic::Id,
pub version: String,
}

Expand Down Expand Up @@ -529,6 +541,33 @@ mod queries {
pub package_version: Option<PackageVersion>,
}

#[derive(cynic::QueryVariables, Debug)]
pub struct YankPackageVersionsVariables<'a> {
pub package_version_ids: Vec<cynic::Id>,
pub reason: Option<&'a str>,
pub undo: Option<bool>,
}

#[derive(cynic::QueryFragment, Debug)]
#[cynic(graphql_type = "Mutation", variables = "YankPackageVersionsVariables")]
pub struct YankPackageVersions {
#[arguments(input: { packageVersionIds: $package_version_ids, reason: $reason, undo: $undo })]
pub yank_package_versions: Option<YankPackageVersionsPayload>,
}

#[derive(cynic::QueryFragment, Debug)]
pub struct YankPackageVersionsPayload {
pub package_versions: Vec<YankedPackageVersion>,
}

#[derive(cynic::QueryFragment, Debug, Clone)]
#[cynic(graphql_type = "PackageVersion")]
pub struct YankedPackageVersion {
pub version: String,
pub yanked_at: Option<DateTime>,
pub yank_reason: Option<String>,
}

#[derive(cynic::InputObject, Debug)]
pub struct InputSignature<'a> {
pub public_key_key_id: &'a str,
Expand Down
1 change: 1 addition & 0 deletions lib/cli/src/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ impl WasmerCmd {
Package::Unpack(cmd) => cmd.execute(),
Package::Search(cmd) => cmd.run(),
Package::Get(cmd) => cmd.run(),
Package::Yank(cmd) => cmd.run(),
},
Some(Cmd::Container(cmd)) => match cmd {
crate::commands::Container::Unpack(cmd) => cmd.execute(),
Expand Down
5 changes: 3 additions & 2 deletions lib/cli/src/commands/package/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -277,8 +277,9 @@ pub(super) fn package_web_url(

/// Adapter over [`package_web_url`] for a [`NamedPackageIdent`].
pub(super) fn package_web_url_for_ident(client: &WasmerClient, pkg: &NamedPackageIdent) -> String {
// `*` when no version; an exact requirement renders as `=x.y.z`.
let version = pkg.version_or_default().to_string().replace('=', "");
// `*` when no version; an exact requirement renders as `=x.y.z`; an
// exact-build pin keeps its `+wasix.N` build metadata.
let version = pkg.version_string().replace('=', "");
package_web_url(client, &pkg.full_name(), Some(&version))
}

Expand Down
17 changes: 15 additions & 2 deletions lib/cli/src/commands/package/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,11 @@ impl PackageDownload {
// produce an authenticated client.
let client = self.env.client_unauthennticated()?;

let version = id.version_or_default().to_string();
let version = id.version_string();
let version = if version == "*" {
String::from("latest")
} else {
version.to_string()
version
};
let full_name = id.full_name();

Expand All @@ -155,6 +155,19 @@ impl PackageDownload {
)
})?;

// A yanked version still downloads when pinned exactly, so warn and continue.
if package.yanked_at.is_some() {
match package.yank_reason.as_deref() {
Some(reason) => eprintln!(
"warning: {}@{} has been yanked: {reason}",
full_name, package.version
),
None => {
eprintln!("warning: {}@{} has been yanked", full_name, package.version)
}
}
}

let download_url = package
.distribution_v3
.pirita_download_url
Expand Down
2 changes: 1 addition & 1 deletion lib/cli/src/commands/package/get.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ impl PackageGet {
PackageSource::Ident(PackageIdent::Named(id)) => {
let client = self.env.client_unauthennticated()?;

let version = id.version_or_default().to_string();
let version = id.version_string();
let version = if version == "*" {
String::from("latest")
} else {
Expand Down
2 changes: 2 additions & 0 deletions lib/cli/src/commands/package/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod search;
mod tag;
mod tree;
mod unpack;
mod yank;

pub use build::PackageBuild;
pub use common::wait::PublishWait;
Expand All @@ -28,4 +29,5 @@ pub enum Package {
Unpack(unpack::PackageUnpack),
Search(search::PackageSearch),
Get(get::PackageGet),
Yank(yank::PackageYank),
}
1 change: 1 addition & 0 deletions lib/cli/src/commands/package/tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@ fn is_fixed_to_resolved(specified: &PackageSource, resolved_id: &PackageId) -> b
match &specified.tag {
Some(Tag::Named(tag)) => tag == &resolved.version.to_string(),
Some(Tag::VersionReq(req)) => version_req_is_exact(req, &resolved.version),
Some(Tag::ExactBuild(v)) => &resolved.version == v,
None => false,
}
}
Expand Down
Loading
Loading