Skip to main content

release_kit/self_depend/
venue.rs

1//! The venue axis: where a release of `rk` itself is published, and the
2//! reference form a manager records for each.
3//!
4//! One enum owns the list, in the order the reports list them. A venue
5//! joins the list only where this repository's own release proves the
6//! publication in CI, the same claim `packaging:an-advertised-system-is-a-
7//! proven-system` holds for a system. A system package venue has no
8//! variant: no per-project manager pins a system package to a version
9//! inside a repository, so every pair on it would be manual, and the
10//! reason string alone is recorded here.
11
12use clap::ValueEnum;
13use serde::Serialize;
14
15use super::pin::PIN_PREFIX;
16
17/// Where a release of `rk` is published.
18#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, ValueEnum)]
19#[serde(rename_all = "kebab-case")]
20#[value(rename_all = "kebab-case")]
21pub enum Venue {
22    /// The crate on crates.io, built from source by the consumer.
23    Crates,
24    /// The flake this repository serves at every tag.
25    Flake,
26    /// The prebuilt archives attached to a GitHub release.
27    GithubRelease,
28}
29
30/// The reason every pair on a system package venue would carry: a
31/// distribution package is pinned by the host, never inside a
32/// repository, so no manager here can record or move it.
33pub const SYSTEM_PACKAGE_REASON: &str = "system-package-unpinnable";
34
35impl Venue {
36    /// The wire form.
37    #[must_use]
38    pub const fn as_str(self) -> &'static str {
39        match self {
40            Self::Crates => "crates",
41            Self::Flake => "flake",
42            Self::GithubRelease => "github-release",
43        }
44    }
45
46    /// Every venue, in the order the reports list them.
47    pub const ALL: [Self; 3] = [Self::Crates, Self::Flake, Self::GithubRelease];
48
49    /// The forge path the flake and the release archives are served
50    /// from, derived from the pin grammar so the project path has one
51    /// owner.
52    #[must_use]
53    pub fn owner_repo() -> &'static str {
54        PIN_PREFIX
55            .trim_start_matches("github:")
56            .trim_end_matches('/')
57    }
58
59    /// The version as a manager records it for this venue: the flake
60    /// venue records the `v` tag inside a flake reference, the crates
61    /// venue the bare version, and the release venue the bare version a
62    /// release archive is fetched by.
63    #[must_use]
64    pub fn reference(self, tag: &str) -> String {
65        let bare = tag.strip_prefix('v').unwrap_or(tag);
66        match self {
67            Self::Crates | Self::GithubRelease => bare.to_owned(),
68            Self::Flake => format!("{PIN_PREFIX}v{bare}"),
69        }
70    }
71}
72
73#[cfg(test)]
74mod tests {
75    use super::{SYSTEM_PACKAGE_REASON, Venue};
76
77    #[test]
78    fn the_venue_list_is_closed_and_ordered() {
79        assert_eq!(Venue::ALL.len(), 3);
80        let names: Vec<&str> = Venue::ALL.iter().map(|v| v.as_str()).collect();
81        assert_eq!(names, ["crates", "flake", "github-release"]);
82        assert_eq!(Venue::owner_repo(), "gubasso/release-kit");
83        assert!(!SYSTEM_PACKAGE_REASON.is_empty());
84    }
85
86    #[test]
87    fn each_venue_renders_its_reference_form() {
88        assert_eq!(Venue::Crates.reference("v0.2.16"), "0.2.16");
89        assert_eq!(Venue::GithubRelease.reference("0.2.16"), "0.2.16");
90        assert_eq!(
91            Venue::Flake.reference("0.2.16"),
92            "github:gubasso/release-kit/v0.2.16"
93        );
94        assert_eq!(
95            Venue::Flake.reference("v0.2.16"),
96            "github:gubasso/release-kit/v0.2.16",
97            "the tag takes exactly one v"
98        );
99    }
100}