Skip to content
113 linesCodeBlameRaw

Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.

Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar1//! The dependency update file on the default branch: which of
2//! [`DEPENDABOT_PATHS`] is read, and what it says, as the Security page
3//! shows it. A file under `.g1t/` is read in place of one under
4//! `.github/`, which is reported as ignored. Reading and checking the
5//! format is `config`'s; acting on it is `version_updates`'s.
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor6
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar7use g1t_contracts::updates::{DEPENDABOT_PATHS, VersionUpdateEntry, VersionUpdatesState};
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor8
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar9use crate::config::{self, Config, Entry};
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor10
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar11/// A file found: its path and its text, if it is text.
12pub type Found = (String, Option<String>);
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor13
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar14/// The file to read among those found (each a path and its text, in any
15/// order), and the others, which are ignored.
16pub fn choose(found: Vec<Found>) -> Option<(Found, Vec<String>)> {
17 let mut found = found;
18 found.sort_by_key(|(path, _)| DEPENDABOT_PATHS.iter().position(|known| known == path).unwrap_or(usize::MAX));
19 let mut found = found.into_iter();
20 let first = found.next()?;
21 Some((first, found.map(|(path, _)| path).collect()))
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor22}
23
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar24/// How one entry is shown. `seed` picks its time of day when the
25/// schedule names none: the repository's id.
26pub fn entry_view(entry: &Entry, seed: &str, default_branch: Option<&str>) -> VersionUpdateEntry {
27 let schedule_seed = format!("{seed}:{}", entry.id());
28 VersionUpdateEntry {
29 id: entry.id(),
30 ecosystem: entry.ecosystem.clone(),
31 directories: entry.directories.clone(),
32 supported: entry.supported(),
33 interval: entry.schedule.as_ref().map(|schedule| schedule.interval.as_str().to_owned()).unwrap_or_default(),
34 schedule: entry.schedule.as_ref().map(|schedule| schedule.describe(&schedule_seed)).unwrap_or_default(),
35 open_pull_requests_limit: entry.open_pull_requests_limit,
36 target_branch: entry.target_branch.clone(),
37 multi_ecosystem_group: entry.multi_ecosystem_group.clone(),
38 groups: entry.groups.clone(),
39 ignore: entry.ignore.clone(),
40 allow: entry.allow.clone(),
41 labels: entry.labels.clone(),
42 assignees: entry.assignees.clone(),
43 reviewers: entry.reviewers.clone(),
44 milestone: entry.milestone,
45 versioning_strategy: entry.versioning_strategy.clone(),
46 options: entry.options.clone(),
47 notes: config::notes(entry, default_branch),
48 ..VersionUpdateEntry::default()
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor49 }
50}
51
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar52/// The schedule seed for an entry of a repository: what keeps its picked
53/// time of day the same from one read to the next.
54pub fn seed(repo_id: &str, entry: &Entry) -> String {
55 format!("{repo_id}:{}", entry.id())
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor56}
57
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar58/// What the file at `path` says, for the Security page. `None` text is a
59/// file too large or not text.
60pub fn state(
61 path: &str,
62 text: Option<&str>,
63 ignored_paths: Vec<String>,
64 repo_id: &str,
65 default_branch: Option<&str>,
66) -> (VersionUpdatesState, Option<Config>) {
67 let mut state = VersionUpdatesState { found: true, path: Some(path.to_owned()), ignored_paths, ..VersionUpdatesState::default() };
68 let Some(text) = text else {
69 state.error = Some(format!("{path} is too large to read or is not text."));
70 return (state, None);
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor71 };
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar72 let read = config::read(text);
73 state.updates = read.config.updates.iter().map(|entry| entry_view(entry, repo_id, default_branch)).collect();
74 state.registries = read.config.registries.iter().map(|registry| registry.info()).collect();
75 state.error = read.problems.first().map(|problem| problem.sentence());
76 let valid = read.problems.is_empty();
77 state.problems = read.problems;
78 (state, valid.then_some(read.config))
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor79}
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar86 fn g1t_comes_before_github() {
87 let found = vec![
88 (".github/dependabot.yml".to_owned(), Some("a".to_owned())),
89 (".g1t/dependabot.yaml".to_owned(), Some("b".to_owned())),
90 ];
91 let ((path, text), ignored) = choose(found).unwrap();
92 assert_eq!((path.as_str(), text.as_deref()), (".g1t/dependabot.yaml", Some("b")));
93 assert_eq!(ignored, [".github/dependabot.yml"]);
94 assert!(choose(Vec::new()).is_none());
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor95 }
96
97 #[test]
Teams and CODEOWNERS, labels and milestones, dependency updates, the security suite, and a clearer top bar98 fn the_page_sees_entries_and_problems() {
99 let source = "version: 2\nupdates:\n - package-ecosystem: npm\n directory: /\n schedule:\n interval: weekly\n time: \"05:00\"\n - package-ecosystem: docker\n directory: /\n schedule: {interval: monthly}\n";
100 let (found, config) = state(".github/dependabot.yml", Some(source), Vec::new(), "rep_1", Some("main"));
101 assert!(config.is_some() && found.error.is_none());
102 assert_eq!(found.updates.len(), 2);
103 assert_eq!(found.updates[0].schedule, "Mondays at 05:00 (UTC)");
104 assert!(found.updates[0].supported && !found.updates[1].supported);
105 assert_eq!(found.updates[0].id, "npm:/");
106
107 let (broken, config) = state(".github/dependabot.yml", Some("version: 2\nupdates:\n - package-ecosystem: npm\n"), Vec::new(), "rep_1", None);
108 assert!(config.is_none());
109 assert_eq!(broken.error.as_deref(), Some("line 3, updates[0]: `directory` (or `directories`) is required: where the manifest is, such as \"/\"."));
110 let (binary, _) = state(".g1t/dependabot.yml", None, Vec::new(), "rep_1", None);
111 assert!(binary.error.unwrap().contains("too large"));
The sidebar asks billing whether it is on, not for the account, so no page waits on the card processor112 }
113}

This file's history is long; its oldest lines are credited to the oldest commit read.