Skip to content

Commit cc3ad4d

Browse files
committed
[ty] Add --config-file
217
1 parent 4e68dd9 commit cc3ad4d

File tree

10 files changed

+264
-55
lines changed

10 files changed

+264
-55
lines changed

crates/ty/docs/cli.md

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/ty/src/args.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ pub(crate) struct CheckCommand {
107107
#[clap(flatten)]
108108
pub(crate) config: ConfigsArg,
109109

110+
/// A path to a `ty.toml` configuration file
111+
///
112+
/// `pyproject.toml` files are not accepted.
113+
/// When provided, this file will be used in place of any discovered configuration (including user-level configuration).
114+
/// ty will skip project discovery and default to the current working directory.
115+
/// Paths are anchored at the current working directory.
116+
#[arg(long)]
117+
pub(crate) config_file: Option<SystemPathBuf>,
118+
110119
/// The format to use for printing diagnostic messages.
111120
#[arg(long)]
112121
pub(crate) output_format: Option<OutputFormat>,

crates/ty/src/lib.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use ruff_db::diagnostic::{Diagnostic, DisplayDiagnosticConfig, Severity};
2323
use ruff_db::max_parallelism;
2424
use ruff_db::system::{OsSystem, SystemPath, SystemPathBuf};
2525
use salsa::plumbing::ZalsaDatabase;
26-
use ty_project::metadata::options::Options;
26+
use ty_project::metadata::options::MetaOptions;
2727
use ty_project::watch::ProjectWatcher;
2828
use ty_project::{Db, DummyReporter, Reporter, watch};
2929
use ty_project::{ProjectDatabase, ProjectMetadata};
@@ -102,12 +102,17 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
102102
.map(|path| SystemPath::absolute(path, &cwd))
103103
.collect();
104104

105-
let system = OsSystem::new(cwd);
105+
let system = OsSystem::new(cwd.clone());
106106
let watch = args.watch;
107107
let exit_zero = args.exit_zero;
108+
let config_file = args.config_file.clone();
109+
110+
let mut project_metadata = match &config_file {
111+
Some(config_file) => ProjectMetadata::from_config_file(config_file.clone(), cwd, &system)?,
112+
None => ProjectMetadata::discover(&project_path, &system)?,
113+
};
108114

109115
let cli_options = args.into_options();
110-
let mut project_metadata = ProjectMetadata::discover(&project_path, &system)?;
111116
project_metadata.apply_cli_options(cli_options.clone());
112117
project_metadata.apply_configuration_files(&system)?;
113118

@@ -117,7 +122,8 @@ fn run_check(args: CheckCommand) -> anyhow::Result<ExitStatus> {
117122
db.project().set_included_paths(&mut db, check_paths);
118123
}
119124

120-
let (main_loop, main_loop_cancellation_token) = MainLoop::new(cli_options);
125+
let meta_options = MetaOptions::new(config_file, cli_options);
126+
let (main_loop, main_loop_cancellation_token) = MainLoop::new(meta_options);
121127

122128
// Listen to Ctrl+C and abort the watch mode.
123129
let main_loop_cancellation_token = Mutex::new(Some(main_loop_cancellation_token));
@@ -178,19 +184,19 @@ struct MainLoop {
178184
/// The file system watcher, if running in watch mode.
179185
watcher: Option<ProjectWatcher>,
180186

181-
cli_options: Options,
187+
meta_options: MetaOptions,
182188
}
183189

184190
impl MainLoop {
185-
fn new(cli_options: Options) -> (Self, MainLoopCancellationToken) {
191+
fn new(meta_options: MetaOptions) -> (Self, MainLoopCancellationToken) {
186192
let (sender, receiver) = crossbeam_channel::bounded(10);
187193

188194
(
189195
Self {
190196
sender: sender.clone(),
191197
receiver,
192198
watcher: None,
193-
cli_options,
199+
meta_options,
194200
},
195201
MainLoopCancellationToken { sender },
196202
)
@@ -340,7 +346,7 @@ impl MainLoop {
340346
MainLoopMessage::ApplyChanges(changes) => {
341347
revision += 1;
342348
// Automatically cancels any pending queries and waits for them to complete.
343-
db.apply_changes(changes, Some(&self.cli_options));
349+
db.apply_changes(changes, Some(&self.meta_options));
344350
if let Some(watcher) = self.watcher.as_mut() {
345351
watcher.update(db);
346352
}

crates/ty/tests/cli.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,41 @@ fn check_conda_prefix_var_to_resolve_path() -> anyhow::Result<()> {
16291629
----- stderr -----
16301630
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
16311631
");
1632+
1633+
Ok(())
1634+
}
1635+
1636+
#[test]
1637+
fn config_file_override() -> anyhow::Result<()> {
1638+
let case = TestCase::with_files(vec![
1639+
("test.py", r"print(x) # [unresolved-reference]"),
1640+
(
1641+
"ty-override.toml",
1642+
r#"
1643+
[terminal]
1644+
error-on-warning = true
1645+
"#,
1646+
),
1647+
])?;
1648+
1649+
assert_cmd_snapshot!(case.command().arg("--warn").arg("unresolved-reference").arg("--config-file").arg("ty-override.toml"), @r"
1650+
success: false
1651+
exit_code: 1
1652+
----- stdout -----
1653+
warning[unresolved-reference]: Name `x` used when not defined
1654+
--> test.py:1:7
1655+
|
1656+
1 | print(x) # [unresolved-reference]
1657+
| ^
1658+
|
1659+
info: rule `unresolved-reference` was selected on the command line
1660+
1661+
Found 1 diagnostic
1662+
1663+
----- stderr -----
1664+
WARN ty is pre-release software and not ready for production use. Expect to encounter bugs, missing features, and fatal errors.
1665+
");
1666+
16321667
Ok(())
16331668
}
16341669

0 commit comments

Comments
 (0)