Skip to content

Commit bb80fef

Browse files
committed
feat: add rage command for bug reporting
1 parent 0a0f0ec commit bb80fef

File tree

8 files changed

+378
-32
lines changed

8 files changed

+378
-32
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ directories = "4.0.1"
2525
blake3 = "1.3.1"
2626
fern = { version = "0.6.1", features = ["colored"] }
2727
chrono = "0.4.19"
28+
dialoguer = "0.10.1"
2829

2930
[dev-dependencies]
3031
assert_cmd = "2.0.4"

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ pub mod linter;
2121
pub mod log_utils;
2222
pub mod path;
2323
pub mod persistent_data;
24+
pub mod rage;
2425
pub mod render;
2526

2627
use git::get_changed_files;

src/log_utils.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use anyhow::{bail, Result};
22
use console::{style, Term};
33
use fern::colors::{Color, ColoredLevelConfig};
4+
use std::path::Path;
45
use std::process::Output;
56

67
use log::Level::Trace;
@@ -32,7 +33,7 @@ pub fn ensure_output(program_name: &str, output: &Output) -> Result<()> {
3233
Ok(())
3334
}
3435

35-
pub fn setup_logger(log_level: LevelFilter, force_color: bool) -> Result<()> {
36+
pub fn setup_logger(log_level: LevelFilter, log_file: &Path, force_color: bool) -> Result<()> {
3637
let builder = fern::Dispatch::new();
3738

3839
let isatty = Term::stderr().features().is_attended();
@@ -61,6 +62,20 @@ pub fn setup_logger(log_level: LevelFilter, force_color: bool) -> Result<()> {
6162
.level(log_level)
6263
.chain(std::io::stderr()),
6364
)
65+
.chain(
66+
fern::Dispatch::new()
67+
.format(move |out, message, record| {
68+
out.finish(format_args!(
69+
"[{} {} {}] {}",
70+
chrono::Utc::now().to_rfc3339_opts(chrono::SecondsFormat::Secs, true),
71+
record.level(),
72+
record.target(),
73+
message
74+
))
75+
})
76+
.level(LevelFilter::Trace)
77+
.chain(fern::log_file(log_file)?),
78+
)
6479
.apply()?;
6580
} else {
6681
builder
@@ -78,6 +93,11 @@ pub fn setup_logger(log_level: LevelFilter, force_color: bool) -> Result<()> {
7893
.level(log_level)
7994
.chain(std::io::stderr()),
8095
)
96+
.chain(
97+
fern::Dispatch::new()
98+
.level(LevelFilter::Trace)
99+
.chain(fern::log_file(log_file)?),
100+
)
81101
.apply()?;
82102
}
83103
Ok(())

src/main.rs

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{collections::HashSet, convert::TryFrom, io::Write};
22

33
use anyhow::{Context, Result};
4+
use chrono::SecondsFormat;
45
use clap::Parser;
56

67
use lintrunner::{
@@ -9,7 +10,8 @@ use lintrunner::{
910
lint_config::{get_linters_from_config, LintRunnerConfig},
1011
log_utils::setup_logger,
1112
path::AbsPath,
12-
persistent_data::{PersistentDataStore},
13+
persistent_data::{ExitInfo, PersistentDataStore, RunInfo},
14+
rage::do_rage,
1315
render::print_error,
1416
PathsOpt, RenderOpt, RevisionOpt,
1517
};
@@ -102,6 +104,13 @@ enum SubCommand {
102104

103105
/// Run linters. This is the default if no subcommand is provided.
104106
Lint,
107+
108+
/// Create a bug report for a past invocation of lintrunner.
109+
Rage {
110+
/// Choose a specific invocation to report on. 0 is the most recent run.
111+
#[clap(long, short)]
112+
invocation: Option<usize>,
113+
},
105114
}
106115

107116
fn do_main() -> Result<i32> {
@@ -128,9 +137,17 @@ fn do_main() -> Result<i32> {
128137
(_, _) => log::LevelFilter::Trace,
129138
};
130139

131-
let persistent_data_store = PersistentDataStore::new(&config_path)?;
140+
let run_info = RunInfo {
141+
args: std::env::args().collect(),
142+
timestamp: chrono::Local::now().to_rfc3339_opts(SecondsFormat::Secs, true),
143+
};
144+
let persistent_data_store = PersistentDataStore::new(&config_path, run_info)?;
132145

133-
setup_logger(log_level, args.force_color)?;
146+
setup_logger(
147+
log_level,
148+
&persistent_data_store.log_file(),
149+
args.force_color,
150+
)?;
134151

135152
let cmd = args.cmd.unwrap_or(SubCommand::Lint);
136153
let lint_runner_config = LintRunnerConfig::new(&config_path)?;
@@ -194,7 +211,7 @@ fn do_main() -> Result<i32> {
194211
PathsOpt::Auto
195212
};
196213

197-
match cmd {
214+
let res = match cmd {
198215
SubCommand::Init { dry_run } => {
199216
// Just run initialization commands, don't actually lint.
200217
do_init(linters, dry_run, &persistent_data_store, &config_path)
@@ -222,7 +239,24 @@ fn do_main() -> Result<i32> {
222239
revision_opt,
223240
)
224241
}
225-
}
242+
SubCommand::Rage { invocation } => do_rage(&persistent_data_store, invocation),
243+
};
244+
245+
let exit_info = match &res {
246+
Ok(code) => ExitInfo {
247+
code: *code,
248+
err: None,
249+
},
250+
Err(err) => ExitInfo {
251+
code: 1,
252+
err: Some(err.to_string()),
253+
},
254+
};
255+
256+
// Write data related to this run out to the persistent data store.
257+
persistent_data_store.write_run_info(exit_info)?;
258+
259+
res
226260
}
227261

228262
fn main() {

0 commit comments

Comments
 (0)