diff options
Diffstat (limited to '')
-rwxr-xr-x | src/doc/rustc-dev-guide/ci/check-in.sh | 38 | ||||
-rwxr-xr-x | src/doc/rustc-dev-guide/ci/check_line_lengths.sh | 43 | ||||
-rw-r--r-- | src/doc/rustc-dev-guide/ci/date-check/Cargo.lock | 133 | ||||
-rw-r--r-- | src/doc/rustc-dev-guide/ci/date-check/Cargo.toml | 12 | ||||
-rw-r--r-- | src/doc/rustc-dev-guide/ci/date-check/src/main.rs | 242 | ||||
-rwxr-xr-x | src/doc/rustc-dev-guide/ci/linkcheck.sh | 31 |
6 files changed, 499 insertions, 0 deletions
diff --git a/src/doc/rustc-dev-guide/ci/check-in.sh b/src/doc/rustc-dev-guide/ci/check-in.sh new file mode 100755 index 000000000..4477789c7 --- /dev/null +++ b/src/doc/rustc-dev-guide/ci/check-in.sh @@ -0,0 +1,38 @@ +#!/bin/sh + +set -eu + +# This is not a very smart script +if [ $# != 2 ]; then + echo "usage: $0 <since> <number-of-prs-merged>" + if [ $# = 0 ]; then + echo "help: you can find the last check-in at" \ + "https://rust-lang.zulipchat.com/#narrow/stream/238009-t-compiler.2Fmeetings/search/wg-rustc-dev-guide" + elif [ $# = 1 ] ; then + echo "help: you can find the number of PRs merged at" \ + "https://github.com/rust-lang/rustc-dev-guide/pulls?q=is%3Apr+is%3Amerged+updated%3A%3E$1" + fi + exit 1 +fi + +curl() { + command curl -s "$@" +} + +# Get recently updated PRs +curl "https://api.github.com/repos/rust-lang/rustc-dev-guide/pulls?state=closed&per_page=$2" \ + | jq '[.[] | select(.merged_at > "'"$1"'")]' > pulls.json + +show_pulls() { + jq -r '.[] | { title, number, html_url, user: .user.login } | "- " + .title + " [#" + (.number | tostring) + "](" + .html_url + ")"' +} + +echo "### Most notable changes" +echo +show_pulls < pulls.json +echo +echo "### Most notable WIPs" +echo +# If there are more than 30 PRs open at a time, you'll need to set `per_page`. +# For now this seems unlikely. +curl "https://api.github.com/repos/rust-lang/rustc-dev-guide/pulls?state=open" | show_pulls diff --git a/src/doc/rustc-dev-guide/ci/check_line_lengths.sh b/src/doc/rustc-dev-guide/ci/check_line_lengths.sh new file mode 100755 index 000000000..31cda5c65 --- /dev/null +++ b/src/doc/rustc-dev-guide/ci/check_line_lengths.sh @@ -0,0 +1,43 @@ +#!/usr/bin/env bash + +if [ "$1" == "--help" ]; then + echo 'Usage:' "[MAX_LINE_LENGTH=n] $0 [file ...]" + exit 1 +fi + +if [ "$MAX_LINE_LENGTH" == "" ]; then + MAX_LINE_LENGTH=100 +fi + +if [ "$1" == "" ]; then + shopt -s globstar + files=( src/**/*.md ) +else + files=( "$@" ) +fi + +echo "Checking line lengths in all source files <= $MAX_LINE_LENGTH chars..." + +echo "Offending files and lines:" +(( bad_lines = 0 )) +(( inside_block = 0 )) +for file in "${files[@]}"; do + echo "$file" + (( line_no = 0 )) + while IFS="" read -r line || [[ -n "$line" ]] ; do + (( line_no++ )) + if [[ "$line" =~ ^'```' ]] ; then + (( inside_block = !$inside_block )) + continue + fi + if ! (( $inside_block )) \ + && ! [[ "$line" =~ " | "|"-|-"|"://"|"]:"|\[\^[^\ ]+\]: ]] \ + && (( "${#line}" > $MAX_LINE_LENGTH )) ; then + (( bad_lines++ )) + echo -e "\t$line_no : $line" + fi + done < "$file" +done + +echo "$bad_lines offending lines found." +(( $bad_lines == 0 )) diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock b/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock new file mode 100644 index 000000000..00fa3def8 --- /dev/null +++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.lock @@ -0,0 +1,133 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "time", + "winapi", +] + +[[package]] +name = "date-check" +version = "0.1.0" +dependencies = [ + "chrono", + "glob", + "regex", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" + +[[package]] +name = "libc" +version = "0.2.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89203f3fba0a3795506acaad8ebce3c80c0af93f994d5a1d7a0b1eeb23271929" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + +[[package]] +name = "regex" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "time" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +dependencies = [ + "libc", + "wasi", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml new file mode 100644 index 000000000..472529511 --- /dev/null +++ b/src/doc/rustc-dev-guide/ci/date-check/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "date-check" +version = "0.1.0" +authors = ["Noah Lev <camelidcamel@gmail.com>"] +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +glob = "0.3" +regex = "1" +chrono = "0.4" diff --git a/src/doc/rustc-dev-guide/ci/date-check/src/main.rs b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs new file mode 100644 index 000000000..bbea2bf38 --- /dev/null +++ b/src/doc/rustc-dev-guide/ci/date-check/src/main.rs @@ -0,0 +1,242 @@ +use std::{ + collections::BTreeMap, + convert::TryInto as _, + env, fmt, fs, + path::{Path, PathBuf}, +}; + +use chrono::{Datelike as _, TimeZone as _, Utc}; +use glob::glob; +use regex::Regex; + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +struct Date { + year: u32, + month: u32, +} + +impl Date { + fn months_since(self, other: Date) -> Option<u32> { + let self_chrono = Utc.ymd(self.year.try_into().unwrap(), self.month, 1); + let other_chrono = Utc.ymd(other.year.try_into().unwrap(), other.month, 1); + let duration_since = self_chrono.signed_duration_since(other_chrono); + let months_since = duration_since.num_days() / 30; + if months_since < 0 { + None + } else { + Some(months_since.try_into().unwrap()) + } + } +} + +impl fmt::Display for Date { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:04}-{:02}", self.year, self.month) + } +} + +fn make_date_regex() -> Regex { + Regex::new( + r"(?x) # insignificant whitespace mode + <!--\s* + [dD]ate:\s* + (?P<y>\d{4}) # year + - + (?P<m>\d{2}) # month + \s*-->", + ) + .unwrap() +} + +fn collect_dates_from_file(date_regex: &Regex, text: &str) -> Vec<(usize, Date)> { + let mut line = 1; + let mut end_of_last_cap = 0; + date_regex + .captures_iter(&text) + .map(|cap| { + ( + cap.get(0).unwrap().range(), + Date { + year: cap["y"].parse().unwrap(), + month: cap["m"].parse().unwrap(), + }, + ) + }) + .map(|(byte_range, date)| { + line += text[end_of_last_cap..byte_range.end] + .chars() + .filter(|c| *c == '\n') + .count(); + end_of_last_cap = byte_range.end; + (line, date) + }) + .collect() +} + +fn collect_dates(paths: impl Iterator<Item = PathBuf>) -> BTreeMap<PathBuf, Vec<(usize, Date)>> { + let date_regex = make_date_regex(); + let mut data = BTreeMap::new(); + for path in paths { + let text = fs::read_to_string(&path).unwrap(); + let dates = collect_dates_from_file(&date_regex, &text); + if !dates.is_empty() { + data.insert(path, dates); + } + } + data +} + +fn filter_dates( + current_month: Date, + min_months_since: u32, + dates_by_file: impl Iterator<Item = (PathBuf, Vec<(usize, Date)>)>, +) -> impl Iterator<Item = (PathBuf, Vec<(usize, Date)>)> { + dates_by_file + .map(move |(path, dates)| { + ( + path, + dates + .into_iter() + .filter(|(_, date)| { + current_month + .months_since(*date) + .expect("found date that is after current month") + >= min_months_since + }) + .collect::<Vec<_>>(), + ) + }) + .filter(|(_, dates)| !dates.is_empty()) +} + +fn main() { + let root_dir = env::args() + .nth(1) + .expect("expect root Markdown directory as CLI argument"); + let root_dir_path = Path::new(&root_dir); + let glob_pat = format!("{}/**/*.md", root_dir); + let today_chrono = Utc::today(); + let current_month = Date { + year: today_chrono.year_ce().1, + month: today_chrono.month(), + }; + + let dates_by_file = collect_dates(glob(&glob_pat).unwrap().map(Result::unwrap)); + let dates_by_file: BTreeMap<_, _> = + filter_dates(current_month, 6, dates_by_file.into_iter()).collect(); + + if dates_by_file.is_empty() { + println!("empty"); + } else { + println!("Date Reference Triage for {}", current_month); + println!("## Procedure"); + println!(); + println!( + "Each of these dates should be checked to see if the docs they annotate are \ + up-to-date. Each date should be updated (in the Markdown file where it appears) to \ + use the current month ({current_month}), or removed if the docs it annotates are not \ + expected to fall out of date quickly.", + current_month = current_month + ); + println!(); + println!( + "Please check off each date once a PR to update it (and, if applicable, its \ + surrounding docs) has been merged. Please also mention that you are working on a \ + particular set of dates so duplicate work is avoided." + ); + println!(); + println!("Finally, once all the dates have been updated, please close this issue."); + println!(); + println!("## Dates"); + println!(); + + for (path, dates) in dates_by_file { + println!( + "- [ ] {}", + path.strip_prefix(&root_dir_path).unwrap().display() + ); + for (line, date) in dates { + println!(" - [ ] line {}: {}", line, date); + } + } + println!(); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_months_since() { + let date1 = Date { + year: 2020, + month: 3, + }; + let date2 = Date { + year: 2021, + month: 1, + }; + assert_eq!(date2.months_since(date1), Some(10)); + } + + #[test] + fn test_date_regex() { + let regex = make_date_regex(); + assert!(regex.is_match("foo <!-- date: 2021-01 --> bar")); + } + + #[test] + fn test_date_regex_capitalized() { + let regex = make_date_regex(); + assert!(regex.is_match("foo <!-- Date: 2021-08 --> bar")); + } + + #[test] + fn test_collect_dates_from_file() { + let text = "Test1\n<!-- date: 2021-01 -->\nTest2\nFoo<!-- date: 2021-02 \ + -->\nTest3\nTest4\nFoo<!-- date: 2021-03 -->Bar\n<!-- date: 2021-04 \ + -->\nTest5\nTest6\nTest7\n<!-- date: \n\n2021-05 -->\nTest8 + "; + assert_eq!( + collect_dates_from_file(&make_date_regex(), text), + vec![ + ( + 2, + Date { + year: 2021, + month: 1, + } + ), + ( + 4, + Date { + year: 2021, + month: 2, + } + ), + ( + 7, + Date { + year: 2021, + month: 3, + } + ), + ( + 8, + Date { + year: 2021, + month: 4, + } + ), + ( + 14, + Date { + year: 2021, + month: 5, + } + ), + ] + ); + } +} diff --git a/src/doc/rustc-dev-guide/ci/linkcheck.sh b/src/doc/rustc-dev-guide/ci/linkcheck.sh new file mode 100755 index 000000000..5d49d1337 --- /dev/null +++ b/src/doc/rustc-dev-guide/ci/linkcheck.sh @@ -0,0 +1,31 @@ +#!/usr/bin/env bash + +set -e +set -o pipefail + +# https://docs.github.com/en/actions/reference/environment-variables +if [ "$GITHUB_EVENT_NAME" = "schedule" ] ; then # running in scheduled job + FLAGS="" + + echo "Doing full link check." + set -x +elif [ "$GITHUB_EVENT_NAME" = "pull_request" ] ; then # running in PR CI build + if [ -z "$BASE_SHA" ]; then + echo "error: unexpected state: BASE_SHA must be non-empty in CI" + exit 1 + fi + + CHANGED_FILES=$(git diff --name-only $BASE_SHA... | tr '\n' ' ') + FLAGS="--no-cache -f $CHANGED_FILES" + + echo "Checking files changed since $BASE_SHA: $CHANGED_FILES" + set -x +else # running locally + COMMIT_RANGE=master... + CHANGED_FILES=$(git diff --name-only $COMMIT_RANGE | tr '\n' ' ') + FLAGS="-f $CHANGED_FILES" + + echo "Checking files changed in $COMMIT_RANGE: $CHANGED_FILES" +fi + +exec mdbook-linkcheck $FLAGS |