tcfetch/
hgmo.rs

1use crate::taskcluster::{IndexResponse, Taskcluster, TaskclusterCI};
2use crate::utils::{get_json, url};
3use crate::{Error, Result, TaskFilter};
4use serde_derive::Deserialize;
5
6#[derive(Debug, Deserialize)]
7pub struct Revision {
8    pub node: String,
9    pub desc: String,
10    pub user: String,
11    pub parents: Vec<String>,
12    pub phase: String,
13    pub pushid: u64,
14    pub pushuser: String,
15}
16
17fn hg_path(repo: &str) -> Option<&'static str> {
18    match repo {
19        "try" => Some("try"),
20        "mozilla-release" => Some("releases/mozilla-release"),
21        "mozilla-beta" => Some("releases/mozilla-beta"),
22        "mozilla-central" => Some("mozilla-central"),
23        "mozilla-inbound" => Some("integration/mozilla-inbound"),
24        "autoland" => Some("integration/autoland"),
25        _ => None,
26    }
27}
28
29pub(crate) struct HgmoCI {
30    taskcluster: Taskcluster,
31    repo: String,
32    hg_path: &'static str,
33}
34
35impl HgmoCI {
36    pub(crate) fn for_repo(taskcluster_base: Option<&str>, repo: String) -> Option<Self> {
37        hg_path(&repo).map(|hg_path| HgmoCI {
38            taskcluster: Taskcluster::new(
39                taskcluster_base.unwrap_or("https://firefox-ci-tc.services.mozilla.com"),
40            ),
41            repo,
42            hg_path,
43        })
44    }
45
46    fn expand_revision(
47        &self,
48        client: &reqwest::blocking::Client,
49        commit: &str,
50    ) -> Result<Option<String>> {
51        let url_ = format!(
52            "https://hg.mozilla.org/{}/json-rev/{}",
53            self.hg_path, commit
54        );
55
56        let resp =
57            get_json::<Revision>(client, &url_, None, None).map(|revision| Some(revision.node));
58        if let Err(Error::Reqwest(ref err)) = resp {
59            if let Some(status_code) = err.status() {
60                if status_code == reqwest::StatusCode::NOT_FOUND {
61                    return Ok(None);
62                }
63            }
64        }
65        resp
66    }
67}
68
69fn commit_is_valid(commit: &str) -> bool {
70    commit.len() >= 12 && commit.len() <= 40
71}
72
73impl TaskclusterCI for HgmoCI {
74    fn taskcluster(&self) -> &Taskcluster {
75        &self.taskcluster
76    }
77
78    fn default_task_filter(&self) -> Vec<TaskFilter> {
79        vec![TaskFilter::new("-web-platform-tests-|-spidermonkey-")
80            .expect("Invalid default task filter")]
81    }
82
83    fn default_artifact_name(&self) -> &'static str {
84        "wptreport.json"
85    }
86
87    fn get_taskgroups(
88        &self,
89        client: &reqwest::blocking::Client,
90        commit: &str,
91    ) -> Result<Vec<String>> {
92        if !commit_is_valid(commit) {
93            return Err(Error::String(format!(
94                "Commit `{}` needs to be between 12 and 40 characters in length",
95                commit
96            )));
97        }
98
99        let commit = self
100            .expand_revision(client, commit)?
101            .ok_or_else(|| Error::String(format!("No such revision {}", commit)))?;
102
103        let index = format!(
104            "gecko.v2.{}.revision.{}.taskgraph.decision",
105            self.repo, commit
106        );
107        Ok(vec![
108            get_json::<IndexResponse>(
109                client,
110                &url(&self.taskcluster.index_base, &format!("task/{}", index)),
111                None,
112                None,
113            )?
114            .taskId,
115        ])
116    }
117}