1use crate::tag::CalendarTag;
2
3#[derive(Clone, Copy, Debug, Eq, PartialEq)]
4pub enum ReleaseIntent {
5 Existing,
6 New,
7}
8
9#[derive(Clone, Debug, Eq, PartialEq)]
10pub struct ReleaseCandidate {
11 pub repository: String,
12 pub commit: String,
13 pub tag: CalendarTag,
14 pub intent: ReleaseIntent,
15 pub tag_already_sealed: bool,
16}
17
18#[derive(Clone, Debug, Eq, PartialEq)]
19pub struct SealedRelease {
20 pub release: ReleaseCandidate,
21 pub tag_object: String,
22}
23
24#[derive(Clone, Debug, Eq, Hash, PartialEq)]
25pub enum ArtifactIdentity {
26 GithubReleaseAsset {
27 name: String,
28 },
29 MavenPackage {
30 group_id: String,
31 artifact_id: String,
32 version: String,
33 extension: String,
34 classifier: Option<String>,
35 },
36 OciImage {
37 repository: String,
38 tag: String,
39 platform: String,
40 },
41}
42
43impl ArtifactIdentity {
44 pub(crate) fn maven_file_name(&self) -> anyhow::Result<String> {
45 let Self::MavenPackage {
46 artifact_id,
47 version,
48 extension,
49 classifier,
50 ..
51 } = self
52 else {
53 anyhow::bail!("expected a Maven artifact identity");
54 };
55 let suffix = match classifier {
56 Some(classifier) => {
57 validate_maven_attachment(classifier, extension)?;
58 format!("-{classifier}")
59 }
60 None => String::new(),
61 };
62 Ok(format!("{artifact_id}-{version}{suffix}.{extension}"))
63 }
64}
65
66pub(crate) fn validate_maven_attachment(classifier: &str, extension: &str) -> anyhow::Result<()> {
67 if !classifier
68 .as_bytes()
69 .first()
70 .is_some_and(u8::is_ascii_alphanumeric)
71 || !classifier
72 .bytes()
73 .all(|byte| byte.is_ascii_alphanumeric() || b"._-".contains(&byte))
74 {
75 anyhow::bail!(
76 "Maven attachment classifier must be a nonempty safe identifier: `{classifier}`"
77 );
78 }
79 if !matches!(extension, "jar" | "zip") {
80 anyhow::bail!("Maven attachment extension must be jar or zip: `{extension}`");
81 }
82 Ok(())
83}
84
85#[derive(Clone, Debug, Eq, PartialEq)]
86pub struct TargetPlan {
87 pub name: String,
88 pub publisher: String,
89 pub release: ReleaseCandidate,
90 pub artifacts: Vec<ArtifactIdentity>,
91}
92
93#[derive(Clone, Debug, Eq, PartialEq)]
94pub struct PreparedArtifact {
95 pub identity: ArtifactIdentity,
96 pub path: std::path::PathBuf,
97 pub sha256: String,
98}
99
100#[derive(Clone, Debug, Eq, PartialEq)]
101pub struct ArtifactManifest {
102 pub target: String,
103 pub publisher: String,
104 pub release: ReleaseCandidate,
105 pub artifacts: Vec<PreparedArtifact>,
106}
107
108#[derive(Clone, Debug, Eq, PartialEq)]
109pub struct ReleasePlan {
110 pub tool_version: String,
111 pub release: ReleaseCandidate,
112 pub targets: Vec<TargetPlan>,
113}