tc-fetch 0.5.0

Download taskcluster artifacts
Documentation
use crate::taskcluster::{IndexResponse, Taskcluster, TaskclusterCI};
use crate::utils::{get_json, url};
use crate::{Error, Result, TaskFilter};
use serde_derive::Deserialize;

#[derive(Debug, Deserialize)]
pub struct Revision {
    pub node: String,
    pub desc: String,
    pub user: String,
    pub parents: Vec<String>,
    pub phase: String,
    pub pushid: u64,
    pub pushuser: String,
}

fn hg_path(repo: &str) -> Option<&'static str> {
    match repo {
        "try" => Some("try"),
        "mozilla-release" => Some("releases/mozilla-release"),
        "mozilla-beta" => Some("releases/mozilla-beta"),
        "mozilla-central" => Some("mozilla-central"),
        "mozilla-inbound" => Some("integration/mozilla-inbound"),
        "autoland" => Some("integration/autoland"),
        _ => None,
    }
}

pub(crate) struct HgmoCI {
    taskcluster: Taskcluster,
    repo: String,
    hg_path: &'static str,
}

impl HgmoCI {
    pub(crate) fn for_repo(taskcluster_base: Option<&str>, repo: String) -> Option<Self> {
        hg_path(&repo).map(|hg_path| HgmoCI {
            taskcluster: Taskcluster::new(
                taskcluster_base.unwrap_or("https://firefox-ci-tc.services.mozilla.com"),
            ),
            repo,
            hg_path,
        })
    }

    fn expand_revision(
        &self,
        client: &reqwest::blocking::Client,
        commit: &str,
    ) -> Result<Option<String>> {
        let url_ = format!(
            "https://hg.mozilla.org/{}/json-rev/{}",
            self.hg_path, commit
        );

        let resp =
            get_json::<Revision>(client, &url_, None, None).map(|revision| Some(revision.node));
        if let Err(Error::Reqwest(ref err)) = resp {
            if let Some(status_code) = err.status() {
                if status_code == reqwest::StatusCode::NOT_FOUND {
                    return Ok(None);
                }
            }
        }
        resp
    }
}

fn commit_is_valid(commit: &str) -> bool {
    commit.len() >= 12 && commit.len() <= 40
}

impl TaskclusterCI for HgmoCI {
    fn taskcluster(&self) -> &Taskcluster {
        &self.taskcluster
    }

    fn default_task_filter(&self) -> Vec<TaskFilter> {
        vec![TaskFilter::new("-web-platform-tests-|-spidermonkey-")
            .expect("Invalid default task filter")]
    }

    fn default_artifact_name(&self) -> &'static str {
        "wptreport.json"
    }

    fn get_taskgroups(
        &self,
        client: &reqwest::blocking::Client,
        commit: &str,
    ) -> Result<Vec<String>> {
        if !commit_is_valid(commit) {
            return Err(Error::String(format!(
                "Commit `{}` needs to be between 12 and 40 characters in length",
                commit
            )));
        }

        let commit = self
            .expand_revision(client, commit)?
            .ok_or_else(|| Error::String(format!("No such revision {}", commit)))?;

        let index = format!(
            "gecko.v2.{}.revision.{}.taskgraph.decision",
            self.repo, commit
        );
        Ok(vec![
            get_json::<IndexResponse>(
                client,
                &url(&self.taskcluster.index_base, &format!("task/{}", index)),
                None,
                None,
            )?
            .taskId,
        ])
    }
}