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}