g1t/crates/contracts/src/packages.rs

311 lines10,161 bytesCodeBlame

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member1//! The packages service: the registries a workspace publishes to and
2//! installs from, beside its code (docs/PACKAGES.md). Container images
3//! first, spoken over the OCI Distribution protocol on `g1t.sh/v2/`; npm,
Merge branch 'worktree-agent-a6a121745e81f639f'4//! Composer, Cargo, Go, Maven, NuGet and RubyGems after.
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member5//!
6//! The site reaches it over `POST /rpc/<method>` with the arguments below;
7//! the registries' own protocols are any other request. Mirrors
8//! `packages/contracts/src/packages.ts`.
9//!
10//! Who may do what: a package linked to a repository has that
11//! repository's visibility and roles (Read pulls, Write publishes, Admin
12//! deletes and changes settings). An unlinked one belongs to its workspace:
13//! members by the base permission, owners delete. Public packages pull
14//! anonymously.
15
16use serde::{Deserialize, Serialize};
17
18use crate::audit::Surface;
19use crate::{User, Viewer};
20
21/// Which registry a package is in.
22#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
23#[serde(rename_all = "snake_case")]
24pub enum Ecosystem {
25 Container,
26 Npm,
27 Composer,
28 Cargo,
29 Go,
Merge branch 'worktree-agent-a6a121745e81f639f'30 Maven,
31 Nuget,
32 Rubygems,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member33}
34
35impl Ecosystem {
Merge branch 'worktree-agent-a6a121745e81f639f'36 pub const ALL: [Ecosystem; 8] = [
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member37 Ecosystem::Container,
38 Ecosystem::Npm,
39 Ecosystem::Composer,
40 Ecosystem::Cargo,
41 Ecosystem::Go,
Merge branch 'worktree-agent-a6a121745e81f639f'42 Ecosystem::Maven,
43 Ecosystem::Nuget,
44 Ecosystem::Rubygems,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member45 ];
46
47 pub fn as_str(self) -> &'static str {
48 match self {
49 Ecosystem::Container => "container",
50 Ecosystem::Npm => "npm",
51 Ecosystem::Composer => "composer",
52 Ecosystem::Cargo => "cargo",
53 Ecosystem::Go => "go",
Merge branch 'worktree-agent-a6a121745e81f639f'54 Ecosystem::Maven => "maven",
55 Ecosystem::Nuget => "nuget",
56 Ecosystem::Rubygems => "rubygems",
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member57 }
58 }
59
60 pub fn parse(text: &str) -> Option<Ecosystem> {
61 Ecosystem::ALL.into_iter().find(|e| e.as_str() == text)
62 }
63}
64
65#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
66#[serde(rename_all = "snake_case")]
67pub enum Visibility {
68 Public,
69 #[default]
70 Private,
71}
72
73impl Visibility {
74 pub fn as_str(self) -> &'static str {
75 match self {
76 Visibility::Public => "public",
77 Visibility::Private => "private",
78 }
79 }
80
81 pub fn parse(text: &str) -> Visibility {
82 if text == "public" { Visibility::Public } else { Visibility::Private }
83 }
84}
85
86/// The repository a package is linked to.
87#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
88pub struct LinkedRepo {
89 pub id: String,
90 pub namespace: String,
91 pub name: String,
92}
93
94/// A package as listings show it.
95#[derive(Clone, Debug, Serialize, Deserialize)]
96pub struct PackageSummary {
97 pub id: String,
98 pub workspace: String,
99 pub ecosystem: Ecosystem,
100 /// Without the workspace: `web` for `g1t.sh/acme/web`.
101 pub name: String,
102 /// What a client is given: `g1t.sh/acme/web` for a container image.
103 pub address: String,
104 /// Linked packages follow their repository's visibility.
105 pub visibility: Visibility,
106 pub repo: Option<LinkedRepo>,
107 pub description: Option<String>,
108 pub versions: u32,
109 /// The newest version's tag (for a container image, `latest` when it
110 /// has one) or version.
111 pub latest: Option<String>,
112 /// Bytes its versions hold, each file counted once.
113 pub size: u64,
114 /// Pulls and installs, counted approximately.
115 pub downloads: u64,
116 pub created_at: String,
117 pub updated_at: String,
118}
119
120/// One version: for a container image, one manifest, by digest.
121#[derive(Clone, Debug, Serialize, Deserialize)]
122pub struct PackageVersion {
123 pub id: String,
124 /// A tag, semver or (for container images) the manifest's digest.
125 pub version: String,
126 pub digest: String,
127 /// Bytes of its files: an image's layers, config and manifest.
128 pub size: u64,
129 pub media_type: Option<String>,
130 /// For an OCI artifact: what it is, such as a signature or an SBOM.
131 pub artifact_type: Option<String>,
132 /// For an artifact attached to another version: that version's digest.
133 pub subject: Option<String>,
134 /// For an image index: the platforms it holds, such as `linux/amd64`.
135 pub platforms: Vec<String>,
136 pub tags: Vec<String>,
137 /// The username that published it.
138 pub published_by: Option<String>,
139 pub published_at: String,
npm on g1t.sh: publish and install @<workspace>/<name> with the npm CLI and a g1t token140 /// npm: why the version should no longer be used, when it is deprecated.
141 #[serde(default)]
142 pub deprecated: Option<String>,
Merge branch 'worktree-agent-ac1de8a731938ed81'143 /// NuGet: whether a symbol package (`.snupkg`) was pushed for it.
144 #[serde(default)]
145 pub symbols: bool,
146 /// NuGet: its own downloads, where they are counted by version.
147 #[serde(default)]
148 pub downloads: Option<u64>,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member149}
150
151#[derive(Clone, Debug, Serialize, Deserialize)]
152pub struct PackageTag {
153 pub tag: String,
154 pub digest: String,
155 pub updated_at: String,
156}
157
158/// What the viewer may do with a package.
159#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
160pub struct PackagePermissions {
161 pub pull: bool,
162 pub push: bool,
163 pub delete: bool,
164 /// Change its visibility and link.
165 pub admin: bool,
166}
167
168/// `get_package`.
169#[derive(Clone, Debug, Serialize, Deserialize)]
170pub struct PackageDetail {
171 pub package: PackageSummary,
172 /// Newest first.
173 pub versions: Vec<PackageVersion>,
174 pub tags: Vec<PackageTag>,
175 pub permissions: PackagePermissions,
npm on g1t.sh: publish and install @<workspace>/<name> with the npm CLI and a g1t token176 /// The package's README, as markdown: npm's, from its latest version.
177 #[serde(default)]
178 pub readme: Option<String>,
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member179}
180
181/// `list_packages`: the packages in a workspace the viewer may pull, newest
182/// first. Returns `Outcome<Vec<PackageSummary>>`.
183#[derive(Clone, Debug, Default, Serialize, Deserialize)]
184pub struct ListPackagesArgs {
185 pub workspace: String,
186 pub viewer: Viewer,
187 #[serde(default)]
188 pub ecosystem: Option<Ecosystem>,
189 /// Only those linked to this repository.
190 #[serde(default)]
191 pub repo_id: Option<String>,
192 /// Matched against names.
193 #[serde(default)]
194 pub query: Option<String>,
195}
196
197/// `get_package`. Returns `Outcome<PackageDetail>`; not found when the
198/// viewer may not pull it.
199#[derive(Clone, Debug, Serialize, Deserialize)]
200pub struct GetPackageArgs {
201 pub workspace: String,
202 pub ecosystem: Ecosystem,
203 pub name: String,
204 pub viewer: Viewer,
205}
206
207/// `delete_version`: a version, by its version or digest, or by a tag that
208/// points to it. Its tags go with it. Returns `Outcome<()>`.
209#[derive(Clone, Debug, Serialize, Deserialize)]
210pub struct DeleteVersionArgs {
211 pub actor: User,
212 pub workspace: String,
213 pub ecosystem: Ecosystem,
214 pub name: String,
215 pub version: String,
216 #[serde(default)]
217 pub surface: Option<Surface>,
218}
219
220/// `delete_package`: a package and every version. Returns `Outcome<()>`.
221#[derive(Clone, Debug, Serialize, Deserialize)]
222pub struct DeletePackageArgs {
223 pub actor: User,
224 pub workspace: String,
225 pub ecosystem: Ecosystem,
226 pub name: String,
227 #[serde(default)]
228 pub surface: Option<Surface>,
229}
230
231/// `set_package`: change a package's visibility, or the repository it is
232/// linked to. `link` names a repository of its workspace; `unlink` takes
233/// the link away (the package is then the workspace's, and private until
234/// someone makes it public). A linked package's visibility is its
235/// repository's, so `visibility` is refused for one. Needs Admin. Returns
236/// `Outcome<PackageSummary>`.
237#[derive(Clone, Debug, Serialize, Deserialize)]
238pub struct SetPackageArgs {
239 pub actor: User,
240 pub workspace: String,
241 pub ecosystem: Ecosystem,
242 pub name: String,
243 #[serde(default)]
244 pub visibility: Option<Visibility>,
245 #[serde(default)]
246 pub link: Option<String>,
247 #[serde(default)]
248 pub unlink: bool,
249 #[serde(default)]
250 pub surface: Option<Surface>,
251}
252
253/// `storage`: what a workspace's packages hold, each file counted once, as
254/// public when any public package uses it. For billing. Returns
255/// [`PackageStorage`].
256#[derive(Clone, Debug, Serialize, Deserialize)]
257pub struct StorageArgs {
258 pub workspace: String,
259}
260
Composer from the workspace's own repositories, and go get from g1t.sh261/// `sync_composer`: read a repository's Composer package again now, as a
262/// push would: made, updated or deleted from its branches, tags and
263/// `composer.json`. Returns `bool`: whether it is a package.
264#[derive(Clone, Debug, Serialize, Deserialize)]
265pub struct SyncComposerArgs {
266 pub repo_id: String,
267}
268
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member269#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
270pub struct PackageStorage {
271 pub public_bytes: u64,
272 pub private_bytes: u64,
273}
274
275/// `storage_all`: [`PackageStorage`] for every workspace that has
276/// packages, from one query, for billing's daily measure. Takes `{}`;
277/// returns `Vec<WorkspacePackageStorage>`, by workspace.
278#[derive(Clone, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
279pub struct WorkspacePackageStorage {
280 pub workspace: String,
281 pub public_bytes: u64,
282 pub private_bytes: u64,
283}
284
285#[cfg(test)]
286mod tests {
287 use super::*;
288
289 #[test]
290 fn ecosystems_read_back() {
291 for ecosystem in Ecosystem::ALL {
292 assert_eq!(Ecosystem::parse(ecosystem.as_str()), Some(ecosystem));
293 assert_eq!(serde_json::to_value(ecosystem).unwrap(), ecosystem.as_str());
294 }
295 assert_eq!(Visibility::parse("public"), Visibility::Public);
296 assert_eq!(Visibility::parse("anything"), Visibility::Private);
297 }
298
299 /// The site's copy, `packages/contracts/src/packages.ts`, names the
300 /// same ecosystems and methods.
301 #[test]
302 fn the_typescript_mirror_names_the_same_ecosystems_and_methods() {
303 let ts = include_str!("../../../packages/contracts/src/packages.ts");
304 for ecosystem in Ecosystem::ALL {
305 assert!(ts.contains(&format!("\"{}\"", ecosystem.as_str())), "{}", ecosystem.as_str());
306 }
Composer from the workspace's own repositories, and go get from g1t.sh307 for method in ["list_packages", "get_package", "delete_version", "delete_package", "set_package", "storage", "storage_all", "sync_composer"] {
Packages, with a container registry on g1t.sh; workspaces deleted whole and kept 30 days; Members for every member308 assert!(ts.contains(&format!("\"{method}\"")), "{method}");
309 }
310 }
311}

This file's history is long; its oldest lines are credited to the oldest commit read.