Skip to content

Commit dbbd109

Browse files
committed
Add TODO checker
1 parent 5f3d696 commit dbbd109

4 files changed

Lines changed: 94 additions & 2 deletions

File tree

.github/workflows/main.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,16 @@ env:
1919
RUSTFLAGS: "-Dwarnings"
2020

2121
jobs:
22+
todo_check:
23+
runs-on: ubuntu-latest
24+
timeout-minutes: 10
25+
26+
steps:
27+
- uses: actions/checkout@v4
28+
29+
- name: Check todo
30+
run: ./y.sh check-todo
31+
2232
rustfmt:
2333
runs-on: ubuntu-latest
2434
timeout-minutes: 10
@@ -232,7 +242,7 @@ jobs:
232242
runs-on: ubuntu-latest
233243
timeout-minutes: 10
234244
if: ${{ github.ref == 'refs/heads/main' }}
235-
needs: [rustfmt, test, bench, dist]
245+
needs: [todo_check, rustfmt, test, bench, dist]
236246

237247
permissions:
238248
contents: write # for creating the dev tag and release

build_system/main.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod prepare;
1717
mod rustc_info;
1818
mod shared_utils;
1919
mod tests;
20+
mod todo;
2021
mod utils;
2122

2223
fn usage() {
@@ -38,6 +39,7 @@ enum Command {
3839
Test,
3940
AbiCafe,
4041
Bench,
42+
CheckTodo,
4143
}
4244

4345
#[derive(Copy, Clone, Debug)]
@@ -66,6 +68,7 @@ fn main() {
6668
Some("test") => Command::Test,
6769
Some("abi-cafe") => Command::AbiCafe,
6870
Some("bench") => Command::Bench,
71+
Some("check-todo") => Command::CheckTodo,
6972
Some(flag) if flag.starts_with('-') => arg_error!("Expected command found flag {}", flag),
7073
Some(command) => arg_error!("Unknown command {}", command),
7174
None => {
@@ -139,6 +142,10 @@ fn main() {
139142
process::exit(0);
140143
}
141144

145+
if command == Command::CheckTodo {
146+
todo::run();
147+
}
148+
142149
let rustup_toolchain_name = match (env::var("CARGO"), env::var("RUSTC"), env::var("RUSTDOC")) {
143150
(Ok(_), Ok(_), Ok(_)) => None,
144151
(_, Err(_), Err(_)) => Some(rustc_info::get_toolchain_name()),
@@ -202,7 +209,7 @@ fn main() {
202209
))
203210
};
204211
match command {
205-
Command::Prepare => {
212+
Command::Prepare | Command::CheckTodo => {
206213
// Handled above
207214
}
208215
Command::Test => {

build_system/todo.rs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
use std::ffi::OsStr;
2+
use std::path::{Path, PathBuf};
3+
use std::process::Command;
4+
use std::{fs, process};
5+
6+
const EXTENSIONS: &[&str] =
7+
&["rs", "py", "js", "sh", "c", "cpp", "h", "md", "css", "ftl", "toml", "yml", "yaml"];
8+
const SKIP_FILES: &[&str] = &["build_system/todo.rs", ".github/workflows/main.yml"];
9+
10+
fn has_supported_extension(path: &Path) -> bool {
11+
path.extension().is_some_and(|ext| EXTENSIONS.iter().any(|e| ext == OsStr::new(e)))
12+
}
13+
14+
fn list_tracked_files() -> Result<Vec<PathBuf>, String> {
15+
let output = Command::new("git")
16+
.args(["ls-files", "-z"])
17+
.output()
18+
.map_err(|e| format!("Failed to run `git ls-files`: {e}"))?;
19+
20+
if !output.status.success() {
21+
let stderr = String::from_utf8_lossy(&output.stderr);
22+
return Err(format!("`git ls-files` failed: {stderr}"));
23+
}
24+
25+
let mut files = Vec::new();
26+
for entry in output.stdout.split(|b| *b == 0) {
27+
if entry.is_empty() {
28+
continue;
29+
}
30+
let path = std::str::from_utf8(entry).unwrap();
31+
files.push(PathBuf::from(path));
32+
}
33+
34+
Ok(files)
35+
}
36+
37+
pub(crate) fn run() -> ! {
38+
let files = list_tracked_files().unwrap();
39+
let mut error_count = 0;
40+
// Avoid embedding the task marker in source so greps only find real occurrences.
41+
let todo_marker = "todo".to_ascii_uppercase();
42+
43+
for file in files {
44+
if SKIP_FILES.iter().any(|skip| file.ends_with(Path::new(skip))) {
45+
continue;
46+
}
47+
if !has_supported_extension(&file) {
48+
continue;
49+
}
50+
51+
let bytes = fs::read(&file).unwrap();
52+
let contents = std::str::from_utf8(&bytes).unwrap();
53+
54+
for (i, line) in contents.split('\n').enumerate() {
55+
let trimmed = line.trim();
56+
if trimmed.contains(&todo_marker) {
57+
eprintln!(
58+
"{}:{}: {} is used for tasks that should be done before merging a PR; if you want to leave a message in the codebase use FIXME",
59+
file.display(),
60+
i + 1,
61+
todo_marker
62+
);
63+
error_count += 1;
64+
}
65+
}
66+
}
67+
68+
if error_count == 0 {
69+
process::exit(0);
70+
}
71+
72+
eprintln!("found {} {}(s)", error_count, todo_marker);
73+
process::exit(1);
74+
}

build_system/usage.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ USAGE:
66
./y.sh test [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen] [--skip-test TESTNAME]
77
./y.sh abi-cafe [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen]
88
./y.sh bench [--sysroot none|clif|llvm] [--out-dir DIR] [--download-dir DIR] [--no-unstable-features] [--frozen]
9+
./y.sh check-todo
910

1011
OPTIONS:
1112
--sysroot none|clif|llvm

0 commit comments

Comments
 (0)