Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions docs/tasks/file-tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Ensure that the file is executable, otherwise mise will not be able to detect it
chmod +x mise-tasks/build
```

On Windows there is no permission bit to set, and `chmod` is not the answer there — see
[Windows](#windows) for what makes a file task detectable instead.
:::

Having the code in a bash file and not TOML helps make it work
Expand Down Expand Up @@ -128,6 +130,54 @@ Write-Host "Hello from PowerShell, current directory is $current_directory"

:::

## Windows

Windows has no execute permission for mise to look at, so it decides whether a file is a task a
different way. A file is a task if **either** holds:

- its extension is one of [`windows_executable_extensions`](/configuration/settings.html#windows_executable_extensions)
— by default `exe`, `bat`, `cmd`, `com`, `ps1`, `vbs`
- it starts with a **shebang**

The two answer different questions. The extension means Windows itself can run the file; the shebang
means mise can work out an interpreter for it. Windows does not implement shebangs — mise reads the
line and starts the interpreter itself — which is why a `.sh` script, or a file with no extension at
all, is still a task there as long as it has one.

The practical consequence is that a file with **neither** is invisible on Windows even though it
works on Linux and macOS:

```bash [mise-tasks/build]
# no shebang, no extension -> not a task on Windows
cargo build
```

Adding `#!/usr/bin/env bash` is usually all it takes, and it costs nothing on the other platforms.

### Writing one task for both platforms

File tasks have no equivalent of a TOML task's
[`run_windows`](/tasks/task-configuration.html#run-windows) — the script _is_ the command, so there
is nowhere to put a second one. Write the two scripts side by side instead, giving the Windows one an
executable extension and the other no extension at all:

```
mise-tasks/
build # #!/usr/bin/env bash
build.ps1 # the Windows version
```

On Windows mise prefers the native script: `build.ps1` answers to `build`, and the extensionless
file is dropped. On Linux and macOS the `.ps1` has no execute permission, so only `build` is found.
`mise run build` does the right thing on each.

Marking the `.ps1` executable on Linux or macOS does not break that — it simply appears there as a
separate task called `build.ps1`, since the rename to `build` only happens on Windows.

If there is more than one Windows candidate — say `build.ps1` _and_ `build.cmd` — mise cannot choose
between them, so it leaves everything alone: all three files stay, listed as `build`, `build.ps1`
and `build.cmd`.

## Editing tasks

This script can be edited by running `mise tasks edit build` (using `$EDITOR`). If it doesn't exist it will be created.
Expand Down