1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
use crate::unwrap;
use rusty_yaml::Yaml;
use std::fmt::{Display, Error, Formatter};
use std::process::exit;
pub struct Scheduler {
    /// Name of scheduler
    name: String,
    /// This field is the password for whitelisting other people's pull requests. When
    /// a non-whitelisted user makes a pull request, we don't want to test their code until
    /// we know that it is safe. When an admin deems it's safe, they can use this password
    /// to mark the pull/merge request as safe. After posting this password, the request
    /// will permanently be marked as safe.
    /// This password is a regular expression, so you can match multiple phrases or cases
    /// if you'd like.
    /// The reason it is in the scheduler is because we want to give permission to unknown users
    /// on a per schedule basis. We want to have power over when a scheduler is allowed to assign
    /// a job, not what job is assigned.
    password: String,
    /// A regex expr that accepts a branch name.
    /// This scheduler will only operate on the
    /// branches with names that match this regex.
    branch: String,
    /// Regex exprs accepting file names.
    /// When these file names are changed in a branch,
    /// They will trigger the scheduler's workers.
    file_triggers: Vec<String>,
    /// The builders to trigger
    buildernames: Vec<String>,
}
impl Scheduler {
    /// Create new scheduler
    fn new<S>(name: S, password: S, branch: S, file_triggers: Vec<S>, buildernames: Vec<S>) -> Self
    where
        S: Display,
    {
        Self {
            name: name.to_string(),
            password: password.to_string(),
            branch: branch.to_string(),
            file_triggers: file_triggers
                .iter()
                .map(|s| {
                    s.to_string()
                        .trim()
                        .trim_start_matches("\"")
                        .trim_end_matches("\"")
                        .to_string()
                })
                .collect(),
            buildernames: buildernames
                .iter()
                .map(|s| {
                    s.to_string()
                        .trim()
                        .trim_start_matches("\"")
                        .trim_end_matches("\"")
                        .to_string()
                })
                .collect(),
        }
    }
}
impl Display for Scheduler {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        write!(
            f,
            "
@util.renderer
def {name}_triggers(props):
    builders = {buildernames}
    triggers = {triggers}
    if not is_whitelisted(props, \"{password}\"):
        print('NOT WHITELISTED!!!')
        return []
    for f in props.files:
        for regex in triggers:
            if re.fullmatch(regex, str(f)):
                return builders
    return []
c['schedulers'].append(schedulers.AnyBranchScheduler(name=\"{name}\",
    change_filter=util.ChangeFilter(branch_re=\"{branch}\"),
    builderNames={name}_triggers))
c['schedulers'].append(schedulers.ForceScheduler(name=\"force_{name}\",
    builderNames={buildernames}))
",
            name = self.name.replace("-", "_"),
            password = self.password.trim_matches('"'),
            branch = self.branch.trim_start_matches("\"").trim_end_matches("\""),
            triggers = format!("{:?}", self.file_triggers)
                .replace("\\\"", "")
                .replace("\\\\\\\\", "\\\\"),
            buildernames = format!("{:?}", self.buildernames)
        )
    }
}
impl From<Yaml> for Scheduler {
    fn from(yaml: Yaml) -> Self {
        let name = yaml.get_name();
        for section in ["branch", "password", "triggers", "builders"].iter() {
            if !yaml.has_section(section) {
                error!("There was an error creating a scheduler: The '{}' section is not specified for '{}'", section, name);
                exit(1);
            }
        }
        let branch: String = unwrap(&yaml, "branch");
        let password: String = unwrap(&yaml, "password");
        let mut triggers = vec![];
        for trigger in yaml.get_section("triggers").unwrap() {
            triggers.push(trigger.to_string());
        }
        let mut builders = vec![];
        for builder in yaml.get_section("builders").unwrap() {
            builders.push(builder.to_string());
        }
        Scheduler::new(name, password, branch, triggers, builders)
    }
}