Skip to content

Commit 8c97784

Browse files
authored
Add a shell option for Command steps. (#958)
Co-authored-by: Dylan Anthony <[email protected]>
1 parent 382c41c commit 8c97784

File tree

11 files changed

+72
-6
lines changed

11 files changed

+72
-6
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
default: minor
3+
---
4+
5+
# Add a `shell` variable for `Command` steps
6+
7+
You can now add `shell=true` to a `Command` step to run the command in the current shell.
8+
This lets you opt in to the pre-0.15.0 behavior.
9+
10+
```toml
11+
[[workflows.steps]]
12+
type = "Command"
13+
command = "echo $AN_ENV_VAR"
14+
shell = true
15+
```

docs/src/content/docs/reference/Config File/Steps/command.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Command
33
---
44

5-
Run a command in your current shell after optionally replacing some variables.
5+
Run a command after optionally replacing some variables.
66
This step is here to cover the infinite things you might want to do that Knope doesn't yet know how to do itself.
77
If you have a lot of these steps or a complex `command`,
88
you might want to run a script in something like Bash or Python,
@@ -11,7 +11,7 @@ then call that script with a command.
1111
## Example
1212

1313
If the current version for your project is `1.0.0`,
14-
the following workflow step will run `git tag v.1.0.0` in your current shell.
14+
the following workflow step will run the `git` command with the arguments `tag` and `v.version`.
1515

1616
```toml
1717
[[workflows.steps]]
@@ -27,3 +27,17 @@ and the value is one of the [available variables](/reference/config-file/variabl
2727
**Take care when selecting a key to replace** as Knope will replace _any_ matching string that it finds.
2828
Replacements occur in the order they're declared in the config,
2929
so Knope may replace earlier substitutions with later ones.
30+
31+
## Shell mode
32+
33+
By default, Knope splits commands into the executable name and its arguments, and calls the executable directly.
34+
This works around common issues with Windows shells, particularly when quoting arguments.
35+
However, you may want to use your current shell to run the command, for example to access environment variables or
36+
to use shell features like pipes or redirection. You can do this by setting `shell=true` in the step configuration.
37+
38+
```toml
39+
[[workflows.steps]]
40+
type = "Command"
41+
command = "echo $AN_ENV_VAR && echo $ANOTHER_ENV_VAR"
42+
shell = true
43+
```

knope.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ type = "PrepareRelease"
2727

2828
[[workflows.steps]]
2929
type = "Command"
30+
shell = true
3031
command = "npx prettier CHANGELOG.md --write && git add CHANGELOG.md"
3132

3233
[[workflows.steps]]

src/config/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,10 +369,12 @@ fn generate_workflows(has_forge: bool, packages: &[Package]) -> Vec<Workflow> {
369369
Step::Command {
370370
command: format!("git commit -m \"{commit_message}\"",),
371371
variables,
372+
shell: None,
372373
},
373374
Step::Command {
374375
command: String::from("git push"),
375376
variables: None,
377+
shell: None,
376378
},
377379
Step::Release,
378380
]
@@ -381,15 +383,18 @@ fn generate_workflows(has_forge: bool, packages: &[Package]) -> Vec<Workflow> {
381383
Step::Command {
382384
command: format!("git commit -m \"{commit_message}\""),
383385
variables,
386+
shell: None,
384387
},
385388
Step::Release,
386389
Step::Command {
387390
command: String::from("git push"),
388391
variables: None,
392+
shell: None,
389393
},
390394
Step::Command {
391395
command: String::from("git push --tags"),
392396
variables: None,
397+
shell: None,
393398
},
394399
]
395400
};

src/step/command.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::{
1212
pub(crate) fn run_command(
1313
mut run_type: RunType,
1414
mut command: String,
15+
shell: bool,
1516
variables: Option<IndexMap<String, Variable>>,
1617
) -> Result<RunType, Error> {
1718
let (state, dry_run_stdout) = match &mut run_type {
@@ -31,7 +32,11 @@ pub(crate) fn run_command(
3132
writeln!(stdout, "Would run {command}")?;
3233
return Ok(run_type);
3334
}
34-
let status = execute::command(command).status()?;
35+
let status = if shell {
36+
execute::shell(command).status()?
37+
} else {
38+
execute::command(command).status()?
39+
};
3540
if status.success() {
3641
return Ok(run_type);
3742
}
@@ -66,6 +71,7 @@ mod test_run_command {
6671
let result = run_command(
6772
RunType::Real(State::new(None, None, None, Vec::new(), Verbose::No)),
6873
command.to_string(),
74+
false,
6975
None,
7076
);
7177

@@ -74,6 +80,7 @@ mod test_run_command {
7480
let result = run_command(
7581
RunType::Real(State::new(None, None, None, Vec::new(), Verbose::No)),
7682
String::from("exit 1"),
83+
false,
7784
None,
7885
);
7986
assert!(result.is_err());

src/step/mod.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,9 @@ pub(crate) enum Step {
7171
/// A map of value-to-replace to [Variable][`crate::command::Variable`] to replace
7272
/// it with.
7373
variables: Option<IndexMap<String, Variable>>,
74+
#[serde(default, skip_serializing_if = "Option::is_none")]
75+
/// Whether to run the command in the platform's shell or not
76+
shell: Option<bool>,
7477
},
7578
/// This will look through all commits since the last tag and parse any
7679
/// [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) it finds. It will
@@ -110,9 +113,11 @@ impl Step {
110113
Step::SwitchBranches => git::switch_branches(run_type)?,
111114
Step::RebaseBranch { to } => git::rebase_branch(&to, run_type)?,
112115
Step::BumpVersion(rule) => releases::bump_version(run_type, &rule)?,
113-
Step::Command { command, variables } => {
114-
command::run_command(run_type, command, variables)?
115-
}
116+
Step::Command {
117+
command,
118+
variables,
119+
shell,
120+
} => command::run_command(run_type, command, shell.is_some_and(|it| it), variables)?,
116121
Step::PrepareRelease(prepare_release) => {
117122
releases::prepare_release(run_type, &prepare_release)?
118123
}

tests/commands/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#[cfg(not(windows))]
2+
mod shell;

tests/commands/shell/in/knope.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[[workflows]]
2+
name = "shell-command"
3+
4+
[[workflows.steps]]
5+
type = "Command"
6+
shell = true
7+
command = "echo $AN_ENV_VAR"

tests/commands/shell/mod.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use crate::helpers::TestCase;
2+
3+
#[test]
4+
fn shell() {
5+
TestCase::new(file!())
6+
.env("AN_ENV_VAR", "a value")
7+
.run("shell-command");
8+
}

tests/commands/shell/stdout.log

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
a value

0 commit comments

Comments
 (0)