Stabilize modules (#2250)

This commit is contained in:
Casey Rodarmor 2024-07-14 14:22:03 -07:00 committed by GitHub
parent 6747c79082
commit 687007a723
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 96 additions and 226 deletions

View File

@ -667,10 +667,10 @@ $ cat foo.just
mod bar mod bar
$ cat bar.just $ cat bar.just
baz: baz:
$ just --unstable foo bar $ just foo bar
Available recipes: Available recipes:
baz baz
$ just --unstable foo::bar $ just foo::bar
Available recipes: Available recipes:
baz baz
``` ```
@ -3154,9 +3154,11 @@ Missing source files for optional imports do not produce an error.
### Modules<sup>1.19.0</sup> ### Modules<sup>1.19.0</sup>
A `justfile` can declare modules using `mod` statements. `mod` statements are A `justfile` can declare modules using `mod` statements.
currently unstable, so you'll need to use the `--unstable` flag,
`set unstable`, or set the `JUST_UNSTABLE` environment variable to use them. `mod` statements were stabilized in `just`<sup>master</sup>. In earlier
versions, you'll need to use the `--unstable` flag, `set unstable`, or set the
`JUST_UNSTABLE` environment variable to use them.
If you have the following `justfile`: If you have the following `justfile`:
@ -3181,14 +3183,14 @@ uses its own settings.
Recipes in submodules can be invoked as subcommands: Recipes in submodules can be invoked as subcommands:
```sh ```sh
$ just --unstable bar b $ just bar b
B B
``` ```
Or with path syntax: Or with path syntax:
```sh ```sh
$ just --unstable bar::b $ just bar::b
B B
``` ```

View File

@ -37,8 +37,6 @@ impl<'src> Analyzer<'src> {
let mut warnings = Vec::new(); let mut warnings = Vec::new();
let mut unstable = BTreeSet::new();
let mut modules: Table<Justfile> = Table::new(); let mut modules: Table<Justfile> = Table::new();
let mut unexports: HashSet<String> = HashSet::new(); let mut unexports: HashSet<String> = HashSet::new();
@ -94,8 +92,6 @@ impl<'src> Analyzer<'src> {
doc, doc,
.. ..
} => { } => {
unstable.insert(Unstable::Modules);
if let Some(absolute) = absolute { if let Some(absolute) = absolute {
define(*name, "module", false)?; define(*name, "module", false)?;
modules.insert(Self::analyze( modules.insert(Self::analyze(
@ -198,7 +194,7 @@ impl<'src> Analyzer<'src> {
settings, settings,
source: root.into(), source: root.into(),
unexports, unexports,
unstable, unstable_features: BTreeSet::new(),
warnings, warnings,
}) })
} }

View File

@ -720,13 +720,15 @@ impl Config {
}) })
} }
pub(crate) fn require_unstable(&self, message: &str) -> RunResult<'static> { pub(crate) fn require_unstable(
if self.unstable { &self,
justfile: &Justfile,
unstable_feature: UnstableFeature,
) -> RunResult<'static> {
if self.unstable || justfile.settings.unstable {
Ok(()) Ok(())
} else { } else {
Err(Error::Unstable { Err(Error::UnstableFeature { unstable_feature })
message: message.to_owned(),
})
} }
} }

View File

@ -174,8 +174,8 @@ pub(crate) enum Error<'src> {
recipe: String, recipe: String,
suggestion: Option<Suggestion<'src>>, suggestion: Option<Suggestion<'src>>,
}, },
Unstable { UnstableFeature {
message: String, unstable_feature: UnstableFeature,
}, },
WriteJustfile { WriteJustfile {
justfile: PathBuf, justfile: PathBuf,
@ -459,8 +459,8 @@ impl<'src> ColorDisplay for Error<'src> {
write!(f, "\n{suggestion}")?; write!(f, "\n{suggestion}")?;
} }
} }
Unstable { message } => { UnstableFeature { unstable_feature } => {
write!(f, "{message} Invoke `just` with `--unstable`, set the `JUST_UNSTABLE` environment variable, or add `set unstable` to your `justfile` to enable unstable features.")?; write!(f, "{unstable_feature} Invoke `just` with `--unstable`, set the `JUST_UNSTABLE` environment variable, or add `set unstable` to your `justfile` to enable unstable features.")?;
} }
WriteJustfile { justfile, io_error } => { WriteJustfile { justfile, io_error } => {
let justfile = justfile.display(); let justfile = justfile.display();

View File

@ -26,9 +26,9 @@ pub(crate) struct Justfile<'src> {
#[serde(skip)] #[serde(skip)]
pub(crate) source: PathBuf, pub(crate) source: PathBuf,
pub(crate) unexports: HashSet<String>, pub(crate) unexports: HashSet<String>,
pub(crate) warnings: Vec<Warning>,
#[serde(skip)] #[serde(skip)]
pub(crate) unstable: BTreeSet<Unstable>, pub(crate) unstable_features: BTreeSet<UnstableFeature>,
pub(crate) warnings: Vec<Warning>,
} }
impl<'src> Justfile<'src> { impl<'src> Justfile<'src> {
@ -228,12 +228,8 @@ impl<'src> Justfile<'src> {
} }
pub(crate) fn check_unstable(&self, config: &Config) -> RunResult<'src> { pub(crate) fn check_unstable(&self, config: &Config) -> RunResult<'src> {
if !config.unstable && !self.settings.unstable { if let Some(&unstable_feature) = self.unstable_features.iter().next() {
if let Some(unstable) = self.unstable.iter().next() { config.require_unstable(self, unstable_feature)?;
return Err(Error::Unstable {
message: unstable.message(),
});
}
} }
for module in self.modules.values() { for module in self.modules.values() {

View File

@ -42,7 +42,7 @@ pub(crate) use {
shell::Shell, show_whitespace::ShowWhitespace, source::Source, string_kind::StringKind, shell::Shell, show_whitespace::ShowWhitespace, source::Source, string_kind::StringKind,
string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table, string_literal::StringLiteral, subcommand::Subcommand, suggestion::Suggestion, table::Table,
thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency, thunk::Thunk, token::Token, token_kind::TokenKind, unresolved_dependency::UnresolvedDependency,
unresolved_recipe::UnresolvedRecipe, unstable::Unstable, use_color::UseColor, unresolved_recipe::UnresolvedRecipe, unstable_feature::UnstableFeature, use_color::UseColor,
variables::Variables, verbosity::Verbosity, warning::Warning, variables::Variables, verbosity::Verbosity, warning::Warning,
}, },
camino::Utf8Path, camino::Utf8Path,
@ -204,7 +204,7 @@ mod token_kind;
mod unindent; mod unindent;
mod unresolved_dependency; mod unresolved_dependency;
mod unresolved_recipe; mod unresolved_recipe;
mod unstable; mod unstable_feature;
mod use_color; mod use_color;
mod variables; mod variables;
mod verbosity; mod verbosity;

View File

@ -79,7 +79,7 @@ impl Subcommand {
justfile.run(config, &search, overrides, &[])?; justfile.run(config, &search, overrides, &[])?;
} }
Dump => Self::dump(config, ast, justfile)?, Dump => Self::dump(config, ast, justfile)?,
Format => Self::format(config, &search, src, ast)?, Format => Self::format(config, &search, src, ast, justfile)?,
Groups => Self::groups(config, justfile), Groups => Self::groups(config, justfile),
List { path } => Self::list(config, justfile, path)?, List { path } => Self::list(config, justfile, path)?,
Show { path } => Self::show(config, justfile, path)?, Show { path } => Self::show(config, justfile, path)?,
@ -337,8 +337,14 @@ impl Subcommand {
Ok(()) Ok(())
} }
fn format(config: &Config, search: &Search, src: &str, ast: &Ast) -> RunResult<'static> { fn format(
config.require_unstable("The `--fmt` command is currently unstable.")?; config: &Config,
search: &Search,
src: &str,
ast: &Ast,
justfile: &Justfile,
) -> RunResult<'static> {
config.require_unstable(justfile, UnstableFeature::FormatSubcommand)?;
let formatted = ast.to_string(); let formatted = ast.to_string();

View File

@ -1,12 +0,0 @@
#[derive(Copy, Clone, Debug, PartialEq, Ord, Eq, PartialOrd)]
pub(crate) enum Unstable {
Modules,
}
impl Unstable {
pub(crate) fn message(self) -> String {
match self {
Self::Modules => "Modules are currently unstable.".into(),
}
}
}

14
src/unstable_feature.rs Normal file
View File

@ -0,0 +1,14 @@
use super::*;
#[derive(Copy, Clone, Debug, PartialEq, Ord, Eq, PartialOrd)]
pub(crate) enum UnstableFeature {
FormatSubcommand,
}
impl Display for UnstableFeature {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
Self::FormatSubcommand => write!(f, "The `--fmt` command is currently unstable."),
}
}
}

View File

@ -86,7 +86,6 @@ fn recipes_in_submodules_can_be_chosen() {
.args(["--unstable", "--choose"]) .args(["--unstable", "--choose"])
.env("JUST_CHOOSER", "head -n10") .env("JUST_CHOOSER", "head -n10")
.write("bar.just", "baz:\n echo BAZ") .write("bar.just", "baz:\n echo BAZ")
.test_round_trip(false)
.justfile( .justfile(
" "
mod bar mod bar

View File

@ -864,7 +864,6 @@ fn source_file() {
Test::new() Test::new()
.args(["--evaluate", "x"]) .args(["--evaluate", "x"])
.test_round_trip(false)
.justfile( .justfile(
" "
import 'foo.just' import 'foo.just'
@ -875,8 +874,7 @@ fn source_file() {
.run(); .run();
Test::new() Test::new()
.args(["--unstable", "foo", "bar"]) .args(["foo", "bar"])
.test_round_trip(false)
.justfile( .justfile(
" "
mod foo mod foo
@ -890,8 +888,7 @@ fn source_file() {
#[test] #[test]
fn source_directory() { fn source_directory() {
Test::new() Test::new()
.args(["--unstable", "foo", "bar"]) .args(["foo", "bar"])
.test_round_trip(false)
.justfile( .justfile(
" "
mod foo mod foo
@ -984,9 +981,7 @@ import-outer: import-inner
echo '{{ module_directory() }}' echo '{{ module_directory() }}'
", ",
) )
.test_round_trip(false)
.args([ .args([
"--unstable",
"outer", "outer",
"import-outer", "import-outer",
"baz", "baz",

View File

@ -17,7 +17,6 @@ fn import_succeeds() {
@echo A @echo A
", ",
) )
.test_round_trip(false)
.arg("a") .arg("a")
.stdout("B\nA\n") .stdout("B\nA\n")
.run(); .run();
@ -34,7 +33,6 @@ fn missing_import_file_error() {
@echo A @echo A
", ",
) )
.test_round_trip(false)
.arg("a") .arg("a")
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.stderr( .stderr(
@ -60,7 +58,6 @@ fn missing_optional_imports_are_ignored() {
@echo A @echo A
", ",
) )
.test_round_trip(false)
.arg("a") .arg("a")
.stdout("A\n") .stdout("A\n")
.run(); .run();
@ -79,7 +76,6 @@ fn trailing_spaces_after_import_are_ignored() {
@echo A @echo A
", ",
) )
.test_round_trip(false)
.stdout("A\n") .stdout("A\n")
.run(); .run();
} }
@ -99,7 +95,6 @@ fn import_after_recipe() {
import './import.justfile' import './import.justfile'
", ",
) )
.test_round_trip(false)
.stdout("A\n") .stdout("A\n")
.run(); .run();
} }
@ -126,7 +121,6 @@ fn import_recipes_are_not_default() {
"import.justfile": "bar:", "import.justfile": "bar:",
}) })
.justfile("import './import.justfile'") .justfile("import './import.justfile'")
.test_round_trip(false)
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.stderr("error: Justfile contains no default recipe.\n") .stderr("error: Justfile contains no default recipe.\n")
.run(); .run();
@ -143,7 +137,6 @@ fn listed_recipes_in_imports_are_in_load_order() {
) )
.write("import.justfile", "bar:") .write("import.justfile", "bar:")
.args(["--list", "--unsorted"]) .args(["--list", "--unsorted"])
.test_round_trip(false)
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -190,7 +183,6 @@ fn recipes_in_import_are_overridden_by_recipes_in_parent() {
set allow-duplicate-recipes set allow-duplicate-recipes
", ",
) )
.test_round_trip(false)
.arg("a") .arg("a")
.stdout("ROOT\n") .stdout("ROOT\n")
.run(); .run();
@ -216,7 +208,6 @@ fn variables_in_import_are_overridden_by_variables_in_parent() {
@echo {{f}} @echo {{f}}
", ",
) )
.test_round_trip(false)
.arg("a") .arg("a")
.stdout("bar\n") .stdout("bar\n")
.run(); .run();
@ -232,7 +223,6 @@ fn import_paths_beginning_with_tilde_are_expanded_to_homdir() {
import '~/mod.just' import '~/mod.just'
", ",
) )
.test_round_trip(false)
.arg("foo") .arg("foo")
.stdout("FOOBAR\n") .stdout("FOOBAR\n")
.env("HOME", "foobar") .env("HOME", "foobar")
@ -248,7 +238,6 @@ fn imports_dump_correctly() {
import './import.justfile' import './import.justfile'
", ",
) )
.test_round_trip(false)
.arg("--dump") .arg("--dump")
.stdout("import './import.justfile'\n") .stdout("import './import.justfile'\n")
.run(); .run();
@ -263,7 +252,6 @@ fn optional_imports_dump_correctly() {
import? './import.justfile' import? './import.justfile'
", ",
) )
.test_round_trip(false)
.arg("--dump") .arg("--dump")
.stdout("import? './import.justfile'\n") .stdout("import? './import.justfile'\n")
.run(); .run();
@ -279,7 +267,6 @@ fn imports_in_root_run_in_justfile_directory() {
import 'foo/import.justfile' import 'foo/import.justfile'
", ",
) )
.test_round_trip(false)
.arg("bar") .arg("bar")
.stdout("BAZ") .stdout("BAZ")
.run(); .run();
@ -292,8 +279,6 @@ fn imports_in_submodules_run_in_submodule_directory() {
.write("foo/mod.just", "import 'import.just'") .write("foo/mod.just", "import 'import.just'")
.write("foo/import.just", "bar:\n @cat baz") .write("foo/import.just", "bar:\n @cat baz")
.write("foo/baz", "BAZ") .write("foo/baz", "BAZ")
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("bar") .arg("bar")
.stdout("BAZ") .stdout("BAZ")
@ -306,7 +291,6 @@ fn nested_import_paths_are_relative_to_containing_submodule() {
.justfile("import 'foo/import.just'") .justfile("import 'foo/import.just'")
.write("foo/import.just", "import 'bar.just'") .write("foo/import.just", "import 'bar.just'")
.write("foo/bar.just", "bar:\n @echo BAR") .write("foo/bar.just", "bar:\n @echo BAR")
.test_round_trip(false)
.arg("bar") .arg("bar")
.stdout("BAR\n") .stdout("BAR\n")
.run(); .run();
@ -319,8 +303,6 @@ fn recipes_in_nested_imports_run_in_parent_module() {
.write("foo/import.just", "import 'bar/import.just'") .write("foo/import.just", "import 'bar/import.just'")
.write("foo/bar/import.just", "bar:\n @cat baz") .write("foo/bar/import.just", "bar:\n @cat baz")
.write("baz", "BAZ") .write("baz", "BAZ")
.test_round_trip(false)
.arg("--unstable")
.arg("bar") .arg("bar")
.stdout("BAZ") .stdout("BAZ")
.run(); .run();
@ -339,7 +321,6 @@ fn shebang_recipes_in_imports_in_root_run_in_justfile_directory() {
import 'foo/import.justfile' import 'foo/import.justfile'
", ",
) )
.test_round_trip(false)
.arg("bar") .arg("bar")
.stdout("BAZ") .stdout("BAZ")
.run(); .run();
@ -357,7 +338,6 @@ fn recipes_imported_in_root_run_in_command_line_provided_working_directory() {
"--justfile", "--justfile",
"subdir/a.justfile", "subdir/a.justfile",
]) ])
.test_round_trip(false)
.stdout("BAZBAZ") .stdout("BAZBAZ")
.run(); .run();
} }

View File

@ -3,7 +3,7 @@ use super::*;
fn case(justfile: &str, value: Value) { fn case(justfile: &str, value: Value) {
Test::new() Test::new()
.justfile(justfile) .justfile(justfile)
.args(["--dump", "--dump-format", "json", "--unstable"]) .args(["--dump", "--dump-format", "json"])
.stdout(format!("{}\n", serde_json::to_string(&value).unwrap())) .stdout(format!("{}\n", serde_json::to_string(&value).unwrap()))
.run(); .run();
} }
@ -1110,8 +1110,7 @@ fn module() {
.tree(tree! { .tree(tree! {
"foo.just": "bar:", "foo.just": "bar:",
}) })
.args(["--dump", "--dump-format", "json", "--unstable"]) .args(["--dump", "--dump-format", "json"])
.test_round_trip(false)
.stdout(format!( .stdout(format!(
"{}\n", "{}\n",
serde_json::to_string(&json!({ serde_json::to_string(&json!({

View File

@ -12,8 +12,7 @@ fn modules_unsorted() {
mod bar mod bar
", ",
) )
.test_round_trip(false) .args(["--list", "--unsorted"])
.args(["--unstable", "--list", "--unsorted"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -156,8 +155,7 @@ fn list_submodule() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--list", "foo"])
.args(["--unstable", "--list", "foo"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -177,8 +175,7 @@ fn list_nested_submodule() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--list", "foo", "bar"])
.args(["--unstable", "--list", "foo", "bar"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -195,8 +192,7 @@ fn list_nested_submodule() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--list", "foo::bar"])
.args(["--unstable", "--list", "foo::bar"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -209,7 +205,7 @@ fn list_nested_submodule() {
#[test] #[test]
fn list_invalid_path() { fn list_invalid_path() {
Test::new() Test::new()
.args(["--unstable", "--list", "$hello"]) .args(["--list", "$hello"])
.stderr("error: Invalid module path `$hello`\n") .stderr("error: Invalid module path `$hello`\n")
.status(1) .status(1)
.run(); .run();
@ -218,7 +214,7 @@ fn list_invalid_path() {
#[test] #[test]
fn list_unknown_submodule() { fn list_unknown_submodule() {
Test::new() Test::new()
.args(["--unstable", "--list", "hello"]) .args(["--list", "hello"])
.stderr("error: Justfile does not contain submodule `hello`\n") .stderr("error: Justfile does not contain submodule `hello`\n")
.status(1) .status(1)
.run(); .run();
@ -236,8 +232,7 @@ fn list_with_groups_in_modules() {
", ",
) )
.write("bar.just", "[group('BAZ')]\nbaz:") .write("bar.just", "[group('BAZ')]\nbaz:")
.test_round_trip(false) .args(["--list", "--list-submodules"])
.args(["--unstable", "--list", "--list-submodules"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -261,8 +256,7 @@ fn list_displays_recipes_in_submodules() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--list", "--list-submodules"])
.args(["--unstable", "--list", "--list-submodules"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -285,8 +279,7 @@ fn modules_are_space_separated_in_output() {
mod bar mod bar
", ",
) )
.test_round_trip(false) .args(["--list", "--list-submodules"])
.args(["--unstable", "--list", "--list-submodules"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -319,8 +312,7 @@ barbarbar:
", ",
) )
.justfile("mod foo") .justfile("mod foo")
.test_round_trip(false) .args(["--list", "--list-submodules"])
.args(["--unstable", "--list", "--list-submodules"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -341,8 +333,7 @@ fn nested_modules_are_properly_indented() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--list", "--list-submodules"])
.args(["--unstable", "--list", "--list-submodules"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -364,8 +355,7 @@ fn module_doc_rendered() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--list"])
.args(["--unstable", "--list"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -393,8 +383,7 @@ fn module_doc_aligned() {
@echo Hi @echo Hi
", ",
) )
.test_round_trip(false) .args(["--list"])
.args(["--unstable", "--list"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -418,8 +407,7 @@ fn space_before_submodules_following_groups() {
bar: bar:
", ",
) )
.test_round_trip(false) .args(["--list"])
.args(["--unstable", "--list"])
.stdout( .stdout(
" "
Available recipes: Available recipes:
@ -441,8 +429,7 @@ fn no_space_before_submodules_not_following_groups() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--list"])
.args(["--unstable", "--list"])
.stdout( .stdout(
" "
Available recipes: Available recipes:

View File

@ -1,16 +1,16 @@
use super::*; use super::*;
#[test] #[test]
fn modules_are_unstable() { fn modules_are_stable() {
Test::new() Test::new()
.justfile( .justfile(
" "
mod foo mod foo
", ",
) )
.write("foo.just", "") .write("foo.just", "@bar:\n echo ok")
.stderr_regex("error: Modules are currently unstable..*") .args(["foo", "bar"])
.status(EXIT_FAILURE) .stdout("ok\n")
.run(); .run();
} }
@ -23,8 +23,6 @@ fn default_recipe_in_submodule_must_have_no_arguments() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.stderr("error: Recipe `foo` cannot be used as default recipe since it requires at least 1 argument.\n") .stderr("error: Recipe `foo` cannot be used as default recipe since it requires at least 1 argument.\n")
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
@ -40,8 +38,6 @@ fn module_recipes_can_be_run_as_subcommands() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -57,8 +53,6 @@ fn module_recipes_can_be_run_with_path_syntax() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo::foo") .arg("foo::foo")
.stdout("FOO\n") .stdout("FOO\n")
.run(); .run();
@ -74,8 +68,6 @@ fn nested_module_recipes_can_be_run_with_path_syntax() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo::bar::baz") .arg("foo::bar::baz")
.stdout("BAZ\n") .stdout("BAZ\n")
.run(); .run();
@ -84,21 +76,18 @@ fn nested_module_recipes_can_be_run_with_path_syntax() {
#[test] #[test]
fn invalid_path_syntax() { fn invalid_path_syntax() {
Test::new() Test::new()
.test_round_trip(false)
.arg(":foo::foo") .arg(":foo::foo")
.stderr("error: Justfile does not contain recipe `:foo::foo`.\n") .stderr("error: Justfile does not contain recipe `:foo::foo`.\n")
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.run(); .run();
Test::new() Test::new()
.test_round_trip(false)
.arg("foo::foo:") .arg("foo::foo:")
.stderr("error: Justfile does not contain recipe `foo::foo:`.\n") .stderr("error: Justfile does not contain recipe `foo::foo:`.\n")
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.run(); .run();
Test::new() Test::new()
.test_round_trip(false)
.arg("foo:::foo") .arg("foo:::foo")
.stderr("error: Justfile does not contain recipe `foo:::foo`.\n") .stderr("error: Justfile does not contain recipe `foo:::foo`.\n")
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
@ -108,7 +97,6 @@ fn invalid_path_syntax() {
#[test] #[test]
fn missing_recipe_after_invalid_path() { fn missing_recipe_after_invalid_path() {
Test::new() Test::new()
.test_round_trip(false)
.arg(":foo::foo") .arg(":foo::foo")
.arg("bar") .arg("bar")
.stderr("error: Justfile does not contain recipe `:foo::foo`.\n") .stderr("error: Justfile does not contain recipe `:foo::foo`.\n")
@ -126,8 +114,6 @@ fn assignments_are_evaluated_in_modules() {
bar := 'PARENT' bar := 'PARENT'
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("CHILD\n") .stdout("CHILD\n")
@ -143,8 +129,6 @@ fn module_subcommand_runs_default_recipe() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
.run(); .run();
@ -160,8 +144,6 @@ fn modules_can_contain_other_modules() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("bar") .arg("bar")
.arg("baz") .arg("baz")
@ -179,8 +161,6 @@ fn circular_module_imports_are_detected() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("bar") .arg("bar")
.arg("baz") .arg("baz")
@ -207,8 +187,6 @@ foo:
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -229,9 +207,7 @@ foo:
set allow-duplicate-recipes set allow-duplicate-recipes
", ",
) )
.test_round_trip(false)
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stderr( .stderr(
@ -265,9 +241,7 @@ fn modules_conflict_with_recipes() {
^^^ ^^^
", ",
) )
.test_round_trip(false)
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.arg("--unstable")
.run(); .run();
} }
@ -291,9 +265,7 @@ fn modules_conflict_with_aliases() {
^^^ ^^^
", ",
) )
.test_round_trip(false)
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.arg("--unstable")
.run(); .run();
} }
@ -309,7 +281,6 @@ fn modules_conflict_with_other_modules() {
bar: bar:
", ",
) )
.test_round_trip(false)
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.stderr( .stderr(
" "
@ -320,7 +291,6 @@ fn modules_conflict_with_other_modules() {
^^^ ^^^
", ",
) )
.arg("--unstable")
.run(); .run();
} }
@ -333,8 +303,6 @@ fn modules_are_dumped_correctly() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("--dump") .arg("--dump")
.stdout("mod foo\n") .stdout("mod foo\n")
.run(); .run();
@ -349,8 +317,6 @@ fn optional_modules_are_dumped_correctly() {
mod? foo mod? foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("--dump") .arg("--dump")
.stdout("mod? foo\n") .stdout("mod? foo\n")
.run(); .run();
@ -365,8 +331,6 @@ fn modules_can_be_in_subdirectory() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -382,8 +346,6 @@ fn modules_in_subdirectory_can_be_named_justfile() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -399,8 +361,6 @@ fn modules_in_subdirectory_can_be_named_justfile_with_any_case() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -416,8 +376,6 @@ fn modules_in_subdirectory_can_have_leading_dot() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -434,8 +392,6 @@ fn modules_require_unambiguous_file() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.stderr( .stderr(
" "
@ -458,8 +414,6 @@ fn missing_module_file_error() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.stderr( .stderr(
" "
@ -484,8 +438,6 @@ fn missing_optional_modules_do_not_trigger_error() {
@echo BAR @echo BAR
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.stdout("BAR\n") .stdout("BAR\n")
.run(); .run();
} }
@ -501,8 +453,6 @@ fn missing_optional_modules_do_not_conflict() {
", ",
) )
.write("baz.just", "baz:\n @echo BAZ") .write("baz.just", "baz:\n @echo BAZ")
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("baz") .arg("baz")
.stdout("BAZ\n") .stdout("BAZ\n")
@ -521,8 +471,7 @@ fn root_dotenv_is_available_to_submodules() {
) )
.write("foo.just", "foo:\n @echo $DOTENV_KEY") .write("foo.just", "foo:\n @echo $DOTENV_KEY")
.write(".env", "DOTENV_KEY=dotenv-value") .write(".env", "DOTENV_KEY=dotenv-value")
.test_round_trip(false) .args(["foo", "foo"])
.args(["--unstable", "foo", "foo"])
.stdout("dotenv-value\n") .stdout("dotenv-value\n")
.run(); .run();
} }
@ -542,8 +491,7 @@ fn dotenv_settings_in_submodule_are_ignored() {
"set dotenv-load := false\nfoo:\n @echo $DOTENV_KEY", "set dotenv-load := false\nfoo:\n @echo $DOTENV_KEY",
) )
.write(".env", "DOTENV_KEY=dotenv-value") .write(".env", "DOTENV_KEY=dotenv-value")
.test_round_trip(false) .args(["foo", "foo"])
.args(["--unstable", "foo", "foo"])
.stdout("dotenv-value\n") .stdout("dotenv-value\n")
.run(); .run();
} }
@ -557,8 +505,6 @@ fn modules_may_specify_path() {
mod foo 'commands/foo.just' mod foo 'commands/foo.just'
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -574,8 +520,6 @@ fn modules_may_specify_path_to_directory() {
mod foo 'commands/bar' mod foo 'commands/bar'
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOO\n") .stdout("FOO\n")
@ -591,8 +535,6 @@ fn modules_with_paths_are_dumped_correctly() {
mod foo 'commands/foo.just' mod foo 'commands/foo.just'
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("--dump") .arg("--dump")
.stdout("mod foo 'commands/foo.just'\n") .stdout("mod foo 'commands/foo.just'\n")
.run(); .run();
@ -607,8 +549,6 @@ fn optional_modules_with_paths_are_dumped_correctly() {
mod? foo 'commands/foo.just' mod? foo 'commands/foo.just'
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("--dump") .arg("--dump")
.stdout("mod? foo 'commands/foo.just'\n") .stdout("mod? foo 'commands/foo.just'\n")
.run(); .run();
@ -623,7 +563,6 @@ fn recipes_may_be_named_mod() {
@echo FOO @echo FOO
", ",
) )
.test_round_trip(false)
.arg("mod") .arg("mod")
.arg("bar") .arg("bar")
.stdout("FOO\n") .stdout("FOO\n")
@ -640,8 +579,6 @@ fn submodule_linewise_recipes_run_in_submodule_directory() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("BAR") .stdout("BAR")
@ -658,8 +595,6 @@ fn submodule_shebang_recipes_run_in_submodule_directory() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("BAR") .stdout("BAR")
@ -676,8 +611,6 @@ fn module_paths_beginning_with_tilde_are_expanded_to_homdir() {
mod foo '~/mod.just' mod foo '~/mod.just'
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo") .arg("foo")
.arg("foo") .arg("foo")
.stdout("FOOBAR\n") .stdout("FOOBAR\n")
@ -697,8 +630,6 @@ fn recipes_with_same_name_are_both_run() {
@echo ROOT @echo ROOT
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("foo::bar") .arg("foo::bar")
.arg("bar") .arg("bar")
.stdout("MODULE\nROOT\n") .stdout("MODULE\nROOT\n")
@ -708,7 +639,7 @@ fn recipes_with_same_name_are_both_run() {
#[test] #[test]
fn submodule_recipe_not_found_error_message() { fn submodule_recipe_not_found_error_message() {
Test::new() Test::new()
.args(["--unstable", "foo::bar"]) .args(["foo::bar"])
.stderr("error: Justfile does not contain submodule `foo`\n") .stderr("error: Justfile does not contain submodule `foo`\n")
.status(1) .status(1)
.run(); .run();
@ -723,8 +654,7 @@ fn submodule_recipe_not_found_spaced_error_message() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["foo", "baz"])
.args(["--unstable", "foo", "baz"])
.stderr("error: Justfile does not contain recipe `foo baz`.\nDid you mean `bar`?\n") .stderr("error: Justfile does not contain recipe `foo baz`.\nDid you mean `bar`?\n")
.status(1) .status(1)
.run(); .run();
@ -739,8 +669,7 @@ fn submodule_recipe_not_found_colon_separated_error_message() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["foo::baz"])
.args(["--unstable", "foo::baz"])
.stderr("error: Justfile does not contain recipe `foo::baz`.\nDid you mean `bar`?\n") .stderr("error: Justfile does not contain recipe `foo::baz`.\nDid you mean `bar`?\n")
.status(1) .status(1)
.run(); .run();
@ -758,7 +687,7 @@ fn colon_separated_path_does_not_run_recipes() {
@echo BAR @echo BAR
", ",
) )
.args(["--unstable", "foo::bar"]) .args(["foo::bar"])
.stderr("error: Expected submodule at `foo` but found recipe.\n") .stderr("error: Expected submodule at `foo` but found recipe.\n")
.status(1) .status(1)
.run(); .run();
@ -779,8 +708,7 @@ fn expected_submodule_but_found_recipe_in_submodule_error() {
Test::new() Test::new()
.justfile("mod foo") .justfile("mod foo")
.write("foo.just", "bar:") .write("foo.just", "bar:")
.test_round_trip(false) .args(["foo::bar::baz"])
.args(["--unstable", "foo::bar::baz"])
.stderr("error: Expected submodule at `foo::bar` but found recipe.\n") .stderr("error: Expected submodule at `foo::bar` but found recipe.\n")
.status(1) .status(1)
.run(); .run();
@ -805,8 +733,7 @@ fn comments_can_follow_modules() {
mod foo # this is foo mod foo # this is foo
", ",
) )
.test_round_trip(false) .args(["foo", "foo"])
.args(["--unstable", "foo", "foo"])
.stdout("FOO\n") .stdout("FOO\n")
.run(); .run();
} }

View File

@ -66,7 +66,7 @@ fn shell_expanded_strings_are_dumped_correctly() {
", ",
) )
.env("JUST_TEST_VARIABLE", "FOO") .env("JUST_TEST_VARIABLE", "FOO")
.args(["--dump", "--unstable"]) .args(["--dump"])
.stdout("x := x'$JUST_TEST_VARIABLE'\n") .stdout("x := x'$JUST_TEST_VARIABLE'\n")
.run(); .run();
} }
@ -114,9 +114,8 @@ fn shell_expanded_strings_can_be_used_in_mod_paths() {
) )
.write("mod.just", "@bar:\n echo BAR") .write("mod.just", "@bar:\n echo BAR")
.env("JUST_TEST_VARIABLE", "mod.just") .env("JUST_TEST_VARIABLE", "mod.just")
.args(["--unstable", "foo", "bar"]) .args(["foo", "bar"])
.stdout("BAR\n") .stdout("BAR\n")
.test_round_trip(false)
.run(); .run();
} }

View File

@ -110,8 +110,7 @@ fn show_recipe_at_path() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--show", "foo::bar"])
.args(["--unstable", "--show", "foo::bar"])
.stdout("bar:\n @echo MODULE\n") .stdout("bar:\n @echo MODULE\n")
.run(); .run();
} }
@ -134,8 +133,7 @@ fn show_space_separated_path() {
mod foo mod foo
", ",
) )
.test_round_trip(false) .args(["--show", "foo bar"])
.args(["--unstable", "--show", "foo bar"])
.stdout("bar:\n @echo MODULE\n") .stdout("bar:\n @echo MODULE\n")
.run(); .run();
} }

View File

@ -65,8 +65,6 @@ fn submodule_recipes() {
bar: bar:
", ",
) )
.test_round_trip(false)
.arg("--unstable")
.arg("--summary") .arg("--summary")
.stdout("bar foo::foo foo::bar::bar foo::bar::baz::baz foo::bar::baz::biz::biz\n") .stdout("bar foo::foo foo::bar::bar foo::bar::baz::baz foo::bar::baz::biz::biz\n")
.run(); .run();
@ -81,7 +79,6 @@ fn summary_implies_unstable() {
mod foo mod foo
", ",
) )
.test_round_trip(false)
.arg("--summary") .arg("--summary")
.stdout("foo::foo\n") .stdout("foo::foo\n")
.run(); .run();

View File

@ -169,6 +169,7 @@ impl Test {
self self
} }
#[allow(unused)]
pub(crate) fn test_round_trip(mut self, test_round_trip: bool) -> Self { pub(crate) fn test_round_trip(mut self, test_round_trip: bool) -> Self {
self.test_round_trip = test_round_trip; self.test_round_trip = test_round_trip;
self self

View File

@ -2,14 +2,9 @@ use super::*;
#[test] #[test]
fn set_unstable_true_with_env_var() { fn set_unstable_true_with_env_var() {
let justfile = r#"
default:
echo 'foo'
"#;
for val in ["true", "some-arbitrary-string"] { for val in ["true", "some-arbitrary-string"] {
Test::new() Test::new()
.justfile(justfile) .justfile("")
.args(["--fmt"]) .args(["--fmt"])
.env("JUST_UNSTABLE", val) .env("JUST_UNSTABLE", val)
.status(EXIT_SUCCESS) .status(EXIT_SUCCESS)
@ -20,13 +15,9 @@ default:
#[test] #[test]
fn set_unstable_false_with_env_var() { fn set_unstable_false_with_env_var() {
let justfile = r#"
default:
echo 'foo'
"#;
for val in ["0", "", "false"] { for val in ["0", "", "false"] {
Test::new() Test::new()
.justfile(justfile) .justfile("")
.args(["--fmt"]) .args(["--fmt"])
.env("JUST_UNSTABLE", val) .env("JUST_UNSTABLE", val)
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
@ -37,12 +28,8 @@ default:
#[test] #[test]
fn set_unstable_false_with_env_var_unset() { fn set_unstable_false_with_env_var_unset() {
let justfile = r#"
default:
echo 'foo'
"#;
Test::new() Test::new()
.justfile(justfile) .justfile("")
.args(["--fmt"]) .args(["--fmt"])
.status(EXIT_FAILURE) .status(EXIT_FAILURE)
.stderr_regex("error: The `--fmt` command is currently unstable.*") .stderr_regex("error: The `--fmt` command is currently unstable.*")
@ -52,19 +39,16 @@ default:
#[test] #[test]
fn set_unstable_with_setting() { fn set_unstable_with_setting() {
Test::new() Test::new()
.justfile( .justfile("set unstable")
" .arg("--fmt")
set unstable .stderr_regex("Wrote justfile to .*")
mod foo
",
)
.write("foo.just", "@bar:\n echo BAR")
.args(["foo", "bar"])
.stdout("BAR\n")
.run(); .run();
} }
// This test should be re-enabled if we get a new unstable feature which is
// encountered in source files. (As opposed to, for example, the unstable
// `--fmt` subcommand, which is encountered on the command line.)
#[cfg(any())]
#[test] #[test]
fn unstable_setting_does_not_affect_submodules() { fn unstable_setting_does_not_affect_submodules() {
Test::new() Test::new()