github_workflows_update/updater/
github.rs1use reqwest::header::USER_AGENT;
6use tracing::instrument;
7use url::Url;
8
9use crate::error::Error;
10use crate::error::Result;
11use crate::version::Version;
12
13#[instrument(level = "debug")]
14async fn get_json(url: &Url) -> Result<serde_json::Value> {
15 let client = reqwest::Client::new();
16 let mut builder = client.get(url.as_str());
17 builder = builder.header(USER_AGENT, "reqwest");
18 builder = builder.header("Accept", "application/vnd.github.v3+json");
19 if let Ok(token) = std::env::var("PERSONAL_TOKEN") {
20 builder = builder.header("Authorization", format!("token {}", token));
21 }
22 let response = builder.send().await?;
23 if !response.status().is_success() {
24 return Err(Error::HttpError(url.clone(), response.status()));
25 }
26 Ok(response.json::<serde_json::Value>().await?)
27}
28
29#[instrument(level = "debug")]
30fn parse_versions(data: serde_json::Value) -> Result<Vec<Version>> {
31 let re_ref = regex::Regex::new(r"^refs/tags/(?P<version>.+)$").unwrap();
32 data.as_array()
33 .ok_or_else(|| Error::JsonParsing("invalid type for layer object list".into()))?
34 .iter()
35 .map(|tag_obj| {
36 tag_obj
37 .as_object()
38 .ok_or_else(|| Error::JsonParsing("invalid type for tag object".into()))?
39 .get("ref")
40 .ok_or_else(|| Error::JsonParsing("ref field not found in tag object".into()))
41 .map(|ref_value| {
42 let version_str = ref_value.as_str().ok_or_else(|| {
43 Error::JsonParsing("invalid type for ref field in tag object".into())
44 })?;
45 let m = re_ref.captures(version_str).ok_or_else(|| {
46 Error::JsonParsing(format!(
47 "could not match github ref {} to tag regex",
48 version_str
49 ))
50 })?;
51 let version_str = m.name("version").unwrap().as_str();
52 Version::new(version_str)
53 .ok_or_else(|| Error::VersionParsing(version_str.into()))
54 })?
55 })
56 .collect::<Result<Vec<Version>>>()
57}
58
59#[instrument(level = "debug")]
60pub async fn get_versions(url: &Url) -> Result<Vec<Version>> {
61 let data = get_json(url).await?;
62 let versions = parse_versions(data)?;
63 Ok(versions)
64}
65
66#[test]
67fn test_docker_parse_versions() -> Result<()> {
68 let json_str = r#"
69[
70 {
71 "ref": "refs/tags/v0.1",
72 "node_id": "REF_kwDOHcsoLq5yZWZzL3RhZ3MvdjAuMQ",
73 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/refs/tags/v0.1",
74 "object": {
75 "sha": "ca550057e88e5885030e756b90bd040ad7840cee",
76 "type": "commit",
77 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/commits/ca550057e88e5885030e756b90bd040ad7840cee"
78 }
79 },
80 {
81 "ref": "refs/tags/0.2",
82 "node_id": "REF_kwDOHcsoLq5yZWZzL3RhZ3MvdjAuMg",
83 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/refs/tags/v0.2",
84 "object": {
85 "sha": "2b80e7d13e4b1738a17887b4d66143433267cea6",
86 "type": "commit",
87 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/commits/2b80e7d13e4b1738a17887b4d66143433267cea6"
88 }
89 },
90 {
91 "ref": "refs/tags/latest",
92 "node_id": "REF_kwDOHcsoLq5yZWZzL3RhZ3MvdjAuMw",
93 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/refs/tags/v0.3",
94 "object": {
95 "sha": "c7d367f5f10a2605aa43a540f9f88177d5fa12ac",
96 "type": "commit",
97 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/commits/c7d367f5f10a2605aa43a540f9f88177d5fa12ac"
98 }
99 },
100 {
101 "ref": "refs/tags/v0.4",
102 "node_id": "REF_kwDOHcsoLq5yZWZzL3RhZ3MvdjAuNA",
103 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/refs/tags/v0.4",
104 "object": {
105 "sha": "04bb04c23563d3302fe6ca0c2b832e9e67c47d58",
106 "type": "commit",
107 "url": "https://api.github.com/repos/lpenz/ghworkflow-rust/git/commits/04bb04c23563d3302fe6ca0c2b832e9e67c47d58"
108 }
109 }
110]
111"#;
112 let json_value: serde_json::Value = serde_json::from_str(json_str)?;
113 let mut versions = parse_versions(json_value)?.into_iter().collect::<Vec<_>>();
114 versions.sort();
115 let versions = versions
116 .into_iter()
117 .map(|v| format!("{}", v))
118 .collect::<Vec<_>>();
119 assert_eq!(versions, ["latest", "v0.1", "0.2", "v0.4"]);
120 Ok(())
121}