gitlab_client/common/
release.rs

1use chrono::{DateTime, Utc};
2use compact_str::CompactString;
3
4#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
5#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
6pub struct Release {
7  pub name: String,
8  pub tag_name: String,
9  pub description: Option<String>,
10  pub created_at: DateTime<Utc>,
11  pub released_at: DateTime<Utc>,
12  pub upcoming_release: bool,
13  pub author: Author,
14  pub commit: Commit,
15  pub milestones: Option<Vec<Milestone>>,
16  pub commit_path: String,
17  pub tag_path: String,
18  pub assets: ReleaseAssets,
19  pub evidences: Vec<ReleaseEvidence>,
20  pub _links: ReleaseLinks,
21}
22
23#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
24#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
25pub struct AuthorId(u64);
26
27impl AuthorId {
28  pub const fn new(id: u64) -> Self {
29    Self(id)
30  }
31
32  pub const fn into_u64(self) -> u64 {
33    self.0
34  }
35}
36
37#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
38#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub struct Author {
40  pub id: AuthorId,
41  pub name: String,
42  pub username: String,
43  pub state: String,
44  pub avatar_url: String,
45  pub web_url: String,
46}
47
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
50pub struct Commit {
51  pub id: String,
52  pub short_id: String,
53  pub title: String,
54  pub created_at: DateTime<Utc>,
55  pub parent_ids: Vec<String>,
56  pub message: String,
57  pub author_name: String,
58  pub author_email: String,
59  pub authored_date: DateTime<Utc>,
60  pub committer_name: String,
61  pub committer_email: String,
62  pub committed_date: DateTime<Utc>,
63}
64
65#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
66#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
67pub struct Milestone {
68  // TODO
69}
70
71#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
72#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
73pub struct ReleaseAssets {
74  pub count: u64,
75  pub sources: Vec<ReleaseSource>,
76  pub links: Vec<ReleaseLink>,
77}
78
79#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
80#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
81pub struct ReleaseSource {
82  pub format: String,
83  pub url: String,
84}
85
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
88pub struct ReleaseEvidence {
89  // TODO
90}
91
92#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
94pub struct ReleaseLinks {
95  closed_issues_url: String,
96  closed_merge_requests_url: String,
97  edit_url: Option<String>,
98  merged_merge_requests_url: String,
99  opened_issues_url: String,
100  opened_merge_requests_url: String,
101  #[cfg_attr(feature = "serde", serde(rename = "self"))]
102  this: String,
103}
104
105/// Criteria used to order releases
106#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
107#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
108pub enum ReleaseOrder {
109  ReleasedAt,
110  CreatedAt,
111}
112
113impl ReleaseOrder {
114  pub fn as_str(self) -> &'static str {
115    match self {
116      Self::ReleasedAt => "released_at",
117      Self::CreatedAt => "created_at",
118    }
119  }
120}
121
122#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
123#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
124pub struct ReleaseLinkId(u64);
125
126impl ReleaseLinkId {
127  pub const fn new(id: u64) -> Self {
128    Self(id)
129  }
130
131  pub const fn into_u64(self) -> u64 {
132    self.0
133  }
134}
135
136#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
137#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
138pub struct ReleaseLink {
139  pub id: ReleaseLinkId,
140  pub name: String,
141  pub url: String,
142  pub direct_asset_url: String,
143  pub link_type: ReleaseLinkType,
144}
145
146#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
147#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
148pub enum ReleaseLinkType {
149  #[cfg_attr(feature = "serde", serde(rename = "other"))]
150  Other,
151  #[cfg_attr(feature = "serde", serde(rename = "runbook"))]
152  Runbook,
153  #[cfg_attr(feature = "serde", serde(rename = "image"))]
154  Image,
155  #[cfg_attr(feature = "serde", serde(rename = "package"))]
156  Package,
157}
158
159impl ReleaseLinkType {
160  pub fn as_str(self) -> &'static str {
161    match self {
162      Self::Other => "other",
163      Self::Runbook => "runbook",
164      Self::Image => "image",
165      Self::Package => "package",
166    }
167  }
168}
169
170#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
171#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
172pub struct InputReleaseAssets<Links = Vec<InputReleaseLink<CompactString>>> {
173  pub links: Links,
174}
175
176pub type InputReleaseAssetsView<'req, Str = CompactString> = InputReleaseAssets<&'req [InputReleaseLink<Str>]>;
177
178impl<Links> InputReleaseAssets<Links> {
179  pub fn as_view<Str>(&self) -> InputReleaseAssetsView<'_, Str>
180  where
181    Links: AsRef<[InputReleaseLink<Str>]>,
182  {
183    InputReleaseAssetsView {
184      links: self.links.as_ref(),
185    }
186  }
187}
188
189#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
190#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
191pub struct InputReleaseLink<Str = CompactString> {
192  pub name: Str,
193  pub url: Str,
194  pub direct_asset_path: Option<Str>,
195  pub link_type: ReleaseLinkType,
196}
197
198pub type InputReleaseLinkView<'req> = InputReleaseLink<&'req str>;
199
200impl<Str: AsRef<str>> InputReleaseLink<Str> {
201  pub fn as_view(&self) -> InputReleaseLinkView<'_> {
202    InputReleaseLinkView {
203      name: self.name.as_ref(),
204      url: self.url.as_ref(),
205      direct_asset_path: self.direct_asset_path.as_ref().map(|s| s.as_ref()),
206      link_type: self.link_type,
207    }
208  }
209}
210
211#[cfg(test)]
212mod test {
213  use super::*;
214  use chrono::{TimeZone, Utc};
215
216  #[cfg_attr(feature = "serde", test)]
217  #[allow(deprecated)]
218  fn read_release() {
219    let raw = r#"{"name": "v0.12.5","tag_name": "v0.12.5","description": null,"created_at": "2023-03-25T23:03:17.165Z","released_at": "2023-03-25T23:03:17.165Z","upcoming_release": false,"author": {"id": 743516,"username": "demurgos","name": "Charles Samborski","state": "active","avatar_url": "https://secure.gravatar.com/avatar/4ccbb457b6d50bb79ec32b66c2f4e301?s=80&d=identicon","web_url": "https://gitlab.com/demurgos"},"commit": {"id": "e8cfd320ee2b8dcee22b0bc0ceaf52d7dd667c2d","short_id": "e8cfd320","created_at": "2023-03-17T00:39:35.000+01:00","parent_ids": ["c8528d12e05c9ee803547eb556cb5394ac3d1abc"],"title": "[bin] Add support for precompiled binary","message": "[bin] Add support for precompiled binary\n\nThis commit adds support for precompiled binaries built in GitLab CI.\n","author_name": "Charles Samborski","author_email": "demurgos@demurgos.net","authored_date": "2023-03-16T23:56:54.000+01:00","committer_name": "Charles Samborski","committer_email": "demurgos@demurgos.net","committed_date": "2023-03-17T00:39:35.000+01:00","trailers": {},"web_url": "https://gitlab.com/eternaltwin/eternaltwin/-/commit/e8cfd320ee2b8dcee22b0bc0ceaf52d7dd667c2d"},"commit_path": "/eternaltwin/eternaltwin/-/commit/e8cfd320ee2b8dcee22b0bc0ceaf52d7dd667c2d","tag_path": "/eternaltwin/eternaltwin/-/tags/v0.12.5","assets": {"count": 5,"sources": [{"format": "zip","url": "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.zip"},{"format": "tar.gz","url": "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.tar.gz"},{"format": "tar.bz2","url": "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.tar.bz2"},{"format": "tar","url": "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.tar"}],"links": [{"id": 1492034,"name": "eternaltwin-x86_64-apple-darwin","url": "https://gitlab.com/eternaltwin/eternaltwin/-/packages/13511182","direct_asset_url": "https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5/downloads/eternaltwin-x86_64-apple-darwin","link_type": "package"}]},"evidences": [{"sha": "f9021712d926f78fc9272ac24733492facd5fb4353ed","filepath": "https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5/evidences/4460894.json","collected_at": "2023-03-25T23:03:17.328Z"}],"_links": {"closed_issues_url": "https://gitlab.com/eternaltwin/eternaltwin/-/issues?release_tag=v0.12.5&scope=all&state=closed","closed_merge_requests_url": "https://gitlab.com/eternaltwin/eternaltwin/-/merge_requests?release_tag=v0.12.5&scope=all&state=closed","edit_url": "https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5/edit","merged_merge_requests_url": "https://gitlab.com/eternaltwin/eternaltwin/-/merge_requests?release_tag=v0.12.5&scope=all&state=merged","opened_issues_url": "https://gitlab.com/eternaltwin/eternaltwin/-/issues?release_tag=v0.12.5&scope=all&state=opened","opened_merge_requests_url": "https://gitlab.com/eternaltwin/eternaltwin/-/merge_requests?release_tag=v0.12.5&scope=all&state=opened","self": "https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5"}}"#;
220    let actual: Release = serde_json::from_str(raw).unwrap();
221    let expected = Release {
222      name: "v0.12.5".to_string(),
223      tag_name: "v0.12.5".to_string(),
224      description: None,
225      created_at: Utc.ymd(2023, 3, 25).and_hms_milli(23, 3, 17, 165),
226      released_at: Utc.ymd(2023, 3, 25).and_hms_milli(23, 3, 17, 165),
227      upcoming_release: false,
228      author: Author {
229        id: AuthorId::new(743516),
230        name: "Charles Samborski".to_string(),
231        username: "demurgos".to_string(),
232        state: "active".to_string(),
233        avatar_url: "https://secure.gravatar.com/avatar/4ccbb457b6d50bb79ec32b66c2f4e301?s=80&d=identicon".to_string(),
234        web_url: "https://gitlab.com/demurgos".to_string(),
235      },
236      commit: Commit {
237        id: "e8cfd320ee2b8dcee22b0bc0ceaf52d7dd667c2d".to_string(),
238        short_id: "e8cfd320".to_string(),
239        title: "[bin] Add support for precompiled binary".to_string(),
240        created_at: Utc.ymd(2023, 3, 16).and_hms(23, 39, 35),
241        parent_ids: vec![
242          "c8528d12e05c9ee803547eb556cb5394ac3d1abc".to_string(),
243        ],
244        message: "[bin] Add support for precompiled binary\n\nThis commit adds support for precompiled binaries built in GitLab CI.\n".to_string(),
245        author_name: "Charles Samborski".to_string(),
246        author_email: "demurgos@demurgos.net".to_string(),
247        authored_date: Utc.ymd(2023, 3, 16).and_hms(22, 56, 54),
248        committer_name: "Charles Samborski".to_string(),
249        committer_email: "demurgos@demurgos.net".to_string(),
250        committed_date: Utc.ymd(2023, 3, 16).and_hms(23, 39, 35),
251      },
252      milestones: None,
253      commit_path: "/eternaltwin/eternaltwin/-/commit/e8cfd320ee2b8dcee22b0bc0ceaf52d7dd667c2d".to_string(),
254      tag_path: "/eternaltwin/eternaltwin/-/tags/v0.12.5".to_string(),
255      assets: ReleaseAssets {
256        count: 5,
257        sources: vec![
258          ReleaseSource {
259            format: "zip".to_string(),
260            url: "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.zip".to_string(),
261          },
262          ReleaseSource {
263            format: "tar.gz".to_string(),
264            url: "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.tar.gz".to_string(),
265          },
266          ReleaseSource {
267            format: "tar.bz2".to_string(),
268            url: "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.tar.bz2".to_string(),
269          },
270          ReleaseSource {
271            format: "tar".to_string(),
272            url: "https://gitlab.com/eternaltwin/eternaltwin/-/archive/v0.12.5/eternaltwin-v0.12.5.tar".to_string(),
273          },
274        ],
275        links: vec![
276          ReleaseLink {
277            id: ReleaseLinkId::new(1492034),
278            name: "eternaltwin-x86_64-apple-darwin".to_string(),
279            url: "https://gitlab.com/eternaltwin/eternaltwin/-/packages/13511182".to_string(),
280            direct_asset_url: "https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5/downloads/eternaltwin-x86_64-apple-darwin".to_string(),
281            link_type: ReleaseLinkType::Package,
282          }
283        ],
284      },
285      evidences: vec![
286        ReleaseEvidence {},
287      ],
288      _links: ReleaseLinks {
289        closed_issues_url: "https://gitlab.com/eternaltwin/eternaltwin/-/issues?release_tag=v0.12.5&scope=all&state=closed".to_string(),
290        closed_merge_requests_url: "https://gitlab.com/eternaltwin/eternaltwin/-/merge_requests?release_tag=v0.12.5&scope=all&state=closed".to_string(),
291        edit_url: Some("https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5/edit".to_string()),
292        merged_merge_requests_url: "https://gitlab.com/eternaltwin/eternaltwin/-/merge_requests?release_tag=v0.12.5&scope=all&state=merged".to_string(),
293        opened_issues_url: "https://gitlab.com/eternaltwin/eternaltwin/-/issues?release_tag=v0.12.5&scope=all&state=opened".to_string(),
294        opened_merge_requests_url: "https://gitlab.com/eternaltwin/eternaltwin/-/merge_requests?release_tag=v0.12.5&scope=all&state=opened".to_string(),
295        this: "https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5".to_string(),
296      },
297    };
298    assert_eq!(actual, expected);
299  }
300
301  #[cfg_attr(feature = "serde", test)]
302  #[allow(deprecated)]
303  fn read_release_link() {
304    let raw = r#"{"id":1492019,"name":"eternaltwin-x86_64-unknown-linux-gnu","url":"https://gitlab.com/eternaltwin/eternaltwin/-/packages/13511234","direct_asset_url":"https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5/downloads/eternaltwin-x86_64-unknown-linux-gnu","link_type":"package"}"#;
305    let actual: ReleaseLink = serde_json::from_str(raw).unwrap();
306    let expected = ReleaseLink {
307      id: ReleaseLinkId::new(1492019),
308      name: "eternaltwin-x86_64-unknown-linux-gnu".to_string(),
309      url: "https://gitlab.com/eternaltwin/eternaltwin/-/packages/13511234".to_string(),
310      direct_asset_url:
311        "https://gitlab.com/eternaltwin/eternaltwin/-/releases/v0.12.5/downloads/eternaltwin-x86_64-unknown-linux-gnu"
312          .to_string(),
313      link_type: ReleaseLinkType::Package,
314    };
315    assert_eq!(actual, expected);
316  }
317
318  #[cfg_attr(feature = "serde", test)]
319  #[allow(deprecated)]
320  fn read_xml2_release_list() {
321    let raw = include_str!("../../test-resources/get-project-release-list/libxml2/output.json");
322    let actual: Vec<Release> = serde_json::from_str(raw).unwrap();
323    assert_eq!(actual.len(), 20);
324  }
325}