nimbus_cli/updater/
taskcluster.rs

1// This Source Code Form is subject to the terms of the Mozilla Public
2// License, v. 2.0. If a copy of the MPL was not distributed with this
3// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
5use serde::de::DeserializeOwned;
6use std::time::Duration;
7use update_informer::{
8    http_client::{GenericHttpClient, HeaderMap, HttpClient},
9    Check, Package, Registry, Result,
10};
11
12#[derive(serde::Deserialize)]
13struct Response {
14    version: String,
15}
16
17struct TaskClusterRegistry;
18
19impl Registry for TaskClusterRegistry {
20    const NAME: &'static str = "taskcluster";
21
22    fn get_latest_version<T: HttpClient>(
23        http_client: GenericHttpClient<T>,
24        pkg: &Package,
25    ) -> Result<Option<String>> {
26        let name = pkg.to_string();
27        let url = format!("https://firefox-ci-tc.services.mozilla.com/api/index/v1/task/project.application-services.v2.{name}.latest/artifacts/public%2Fbuild%2F{name}.json");
28        let resp = http_client.get::<Response>(&url)?;
29        Ok(Some(resp.version))
30    }
31}
32
33#[allow(dead_code)]
34pub struct GunzippingHttpClient;
35
36impl HttpClient for GunzippingHttpClient {
37    fn get<T: DeserializeOwned>(url: &str, _timeout: Duration, headers: HeaderMap) -> Result<T> {
38        let mut req = viaduct::Request::get(viaduct::parse_url(url)?);
39
40        for (key, value) in headers {
41            req = req.header(key.to_string(), value.to_string())?;
42        }
43
44        let json = req.send()?.json()?;
45
46        Ok(json)
47    }
48}
49
50/// Check the specifically crafted JSON file for this package to see if there has been a change in version.
51/// This is done every hour.
52pub(crate) fn check_taskcluster_for_update() -> Option<(String, String)> {
53    let name = env!("CARGO_PKG_NAME");
54    let version = env!("CARGO_PKG_VERSION");
55    let interval = Duration::from_secs(60 * 60);
56
57    #[cfg(not(test))]
58    let informer = update_informer::new(TaskClusterRegistry, name, version)
59        .http_client(GunzippingHttpClient)
60        .interval(interval);
61
62    #[cfg(test)]
63    let informer =
64        update_informer::fake(TaskClusterRegistry, name, version, "1.0.0").interval(interval);
65
66    if let Ok(Some(new_version)) = informer.check_version() {
67        Some((format!("v{version}"), new_version.to_string()))
68    } else {
69        None
70    }
71}