Update CLI to pass through variables (#4488)

* feat: Update CLI to pass parameters through to Task commands

- Modified build and package commands to accept otherArgs parameter
- Updated task wrapper to forward CLI variables to Task
- Enhanced task.go to properly parse and handle CLI variables (KEY=VALUE format)
- Fixes issue where 'wails3 build' and 'wails3 package' commands weren't forwarding parameters

Fixes #4422

* Update changelog

* Apply suggestion from @coderabbitai[bot]

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Fix cli.mdx

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
Lea Anthony 2025-08-09 21:44:30 +10:00 committed by GitHub
commit bf805b4152
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 809 additions and 32 deletions

View file

@ -1,6 +1,7 @@
---
title: CLI Reference
description: Complete reference for the Wails CLI commands
sidebar:
sidebar:
order: 1
---
@ -9,7 +10,7 @@ The Wails CLI provides a comprehensive set of commands to help you develop, buil
## Core Commands
Core commands are the primary commands used for project creation, development, and building.
Core commands are the primary commands used for project creation, development, and building.
All CLI commands are of the following format: `wails3 <command>`.
@ -52,7 +53,7 @@ When provided, this flag will:
4. Add all files
### `dev`
Runs the application in development mode. This will give you a live view of your frontend code, and you can make changes and see them reflected
Runs the application in development mode. This will give you a live view of your frontend code, and you can make changes and see them reflected
in the running application without having to rebuild the entire application. Changes to your Go code will also be detected and the application
will automatically rebuild and relaunch.
@ -76,22 +77,30 @@ wails3 dev [flags]
### `build`
Builds a debug version of your application. It defaults to building for the current platform and architecture.
```bash
wails3 build
wails3 build [CLI variables...]
```
You can pass CLI variables to customize the build:
```bash
wails3 build PLATFORM=linux CONFIG=production
```
:::note
This is equivalent to running `wails3 task build` which runs the `build` task in the project's main Taskfile. You can customise the build process by editing the `Taskfile.yml` file.
This is equivalent to running `wails3 task build` which runs the `build` task in the project's main Taskfile. Any CLI variables passed to `build` are forwarded to the underlying task. You can customise the build process by editing the `Taskfile.yml` file.
:::
### `package`
Creates platform-specific packages for distribution.
```bash
wails3 package
wails3 package [CLI variables...]
```
You can pass CLI variables to customize the packaging:
```bash
wails3 package VERSION=2.0.0 OUTPUT=myapp.pkg
```
#### Package Types
@ -104,13 +113,80 @@ The following package types are available for each platform:
| macOS | `.app`, |
| Linux | `.AppImage`, `.deb`, `.rpm`, `.archlinux` |
:::note
This is equivalent to `wails3 task package` which runs the `package` task in the project's main Taskfile. You can customise the packaging process by editing the `Taskfile.yml` file.
This is equivalent to `wails3 task package` which runs the `package` task in the project's main Taskfile. Any CLI variables passed to `package` are forwarded to the underlying task. You can customise the packaging process by editing the `Taskfile.yml` file.
:::
### `task`
Runs tasks defined in your project's Taskfile.yml. This is an embedded version of [Taskfile](https://taskfile.dev) that allows you to define and run custom build, test, and deployment tasks.
```bash
wails3 task [taskname] [CLI variables...] [flags]
```
#### CLI Variables
You can pass variables to tasks in the format `KEY=VALUE`:
```bash
wails3 task build PLATFORM=linux CONFIG=production
wails3 task deploy ENV=staging VERSION=1.2.3
```
These variables can be accessed in your Taskfile.yml using Go template syntax:
```yaml
tasks:
build:
cmds:
- echo "Building for {{.PLATFORM | default "darwin"}}"
- echo "Config: {{.CONFIG | default "debug"}}"
```
#### Flags
| Flag | Description | Default |
|--------------|-------------------------------------------|----------|
| `-h` | Shows Task usage | `false` |
| `-i` | Creates a new Taskfile.yml | `false` |
| `-list` | Lists tasks with descriptions | `false` |
| `-list-all` | Lists all tasks (with or without descriptions) | `false` |
| `-json` | Formats task list as JSON | `false` |
| `-status` | Exits with non-zero if task is not up-to-date | `false` |
| `-f` | Forces execution even when task is up-to-date | `false` |
| `-w` | Enables watch mode for the given task | `false` |
| `-v` | Enables verbose mode | `false` |
| `-version` | Prints Task version | `false` |
| `-s` | Disables echoing | `false` |
| `-p` | Executes tasks in parallel | `false` |
| `-dry` | Compiles and prints tasks without executing | `false` |
| `-summary` | Shows summary about a task | `false` |
| `-x` | Pass-through the exit code of the task | `false` |
| `-dir` | Sets directory of execution | |
| `-taskfile` | Choose which Taskfile to run | |
| `-output` | Sets output style: [interleaved|group|prefixed] | |
| `-c` | Colored output (enabled by default) | `true` |
| `-C` | Limit number of tasks to run concurrently | |
| `-interval` | Interval to watch for changes (in seconds) | |
#### Examples
```bash
# Run the default task
wails3 task
# Run a specific task
wails3 task test
# Run a task with variables
wails3 task build PLATFORM=windows ARCH=amd64
# List all available tasks
wails3 task --list
# Run multiple tasks in parallel
wails3 task -p task1 task2 task3
# Watch for changes and re-run task
wails3 task -w dev
```
### `doctor`
Performs a system check and displays a status report.

View file

@ -138,6 +138,29 @@ commands, Wails internally translates them to the appropriate task execution:
- `wails3 build` → `wails3 task build`
- `wails3 package` → `wails3 task package`
### Passing Parameters to Tasks
You can pass CLI variables to tasks using the `KEY=VALUE` format. These variables are forwarded through the alias commands:
```bash
# These are equivalent:
wails3 build PLATFORM=linux CONFIG=production
wails3 task build PLATFORM=linux CONFIG=production
# Package with custom version:
wails3 package VERSION=2.0.0 OUTPUT=myapp.pkg
```
In your `Taskfile.yml`, you can access these variables using Go template syntax:
```yaml
tasks:
build:
cmds:
- echo "Building for {{.PLATFORM | default "darwin"}}"
- go build -tags {{.CONFIG | default "debug"}} -o myapp
```
## Common Build Process
Across all platforms, the build process typically includes the following steps:

View file

@ -18,6 +18,7 @@ After processing, the content will be moved to the main changelog and this file
## Added
<!-- New features, capabilities, or enhancements -->
- Add Content Protection on Windows/Mac by [@leaanthony](https://github.com/leaanthony) based on the original work of [@Taiterbase](https://github.com/Taiterbase) in this [PR](https://github.com/wailsapp/wails/pull/4241)
- Add support for passing CLI variables to Task commands through `wails3 build` and `wails3 package` aliases (#4422) by @leaanthony in [PR](https://github.com/wailsapp/wails/pull/4488)
## Changed
<!-- Changes in existing functionality -->

View file

@ -33,9 +33,22 @@ func main() {
app := clir.NewCli("wails", "The Wails3 CLI", "v3")
app.NewSubCommand("docs", "Open the docs").Action(openDocs)
app.NewSubCommandFunction("init", "Initialise a new project", commands.Init)
app.NewSubCommandFunction("build", "Build the project", commands.Build)
build := app.NewSubCommand("build", "Build the project")
var buildFlags flags.Build
build.AddFlags(&buildFlags)
build.Action(func() error {
return commands.Build(&buildFlags, build.OtherArgs())
})
app.NewSubCommandFunction("dev", "Run in Dev mode", commands.Dev)
app.NewSubCommandFunction("package", "Package application", commands.Package)
pkg := app.NewSubCommand("package", "Package application")
var pkgFlags flags.Package
pkg.AddFlags(&pkgFlags)
pkg.Action(func() error {
return commands.Package(&pkgFlags, pkg.OtherArgs())
})
app.NewSubCommandFunction("doctor", "System status report", commands.Doctor)
app.NewSubCommandFunction("releasenotes", "Show release notes", commands.ReleaseNotes)

View file

@ -32,6 +32,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/pterm/pterm v0.12.80
github.com/samber/lo v1.49.1
github.com/stretchr/testify v1.10.0
github.com/tc-hib/winres v0.3.1
github.com/wailsapp/go-webview2 v1.0.21
github.com/wailsapp/mimetype v1.4.1
@ -50,6 +51,7 @@ require (
github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect
github.com/charmbracelet/x/term v0.2.1 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
)
require (

View file

@ -123,29 +123,62 @@ func RunTask(options *RunTaskOptions, otherArgs []string) error {
return nil
}
var index int
var arg string
for index, arg = range os.Args[2:] {
if !strings.HasPrefix(arg, "-") {
break
}
}
// Parse task name and CLI variables from otherArgs or os.Args
var tasksAndVars []string
for _, taskAndVar := range os.Args[index+2:] {
if taskAndVar == "--" {
break
// Check if we have a task name specified in options
if options.Name != "" {
// If task name is provided via options, use it and treat otherArgs as CLI variables
tasksAndVars = append([]string{options.Name}, otherArgs...)
} else if len(otherArgs) > 0 {
// Use otherArgs directly if provided
tasksAndVars = otherArgs
} else {
// Fall back to parsing os.Args for backward compatibility
var index int
var arg string
for index, arg = range os.Args[2:] {
if !strings.HasPrefix(arg, "-") {
break
}
}
tasksAndVars = append(tasksAndVars, taskAndVar)
}
if len(tasksAndVars) > 0 && len(otherArgs) > 0 {
if tasksAndVars[0] == otherArgs[0] {
otherArgs = otherArgs[1:]
for _, taskAndVar := range os.Args[index+2:] {
if taskAndVar == "--" {
break
}
tasksAndVars = append(tasksAndVars, taskAndVar)
}
}
if err := e.RunTask(context.Background(), &ast.Call{Task: tasksAndVars[0]}); err != nil {
// Default task
if len(tasksAndVars) == 0 {
tasksAndVars = []string{"default"}
}
// Parse task name and CLI variables
taskName := tasksAndVars[0]
cliVars := tasksAndVars[1:]
// Create call with CLI variables
call := &ast.Call{
Task: taskName,
Vars: &ast.Vars{},
}
// Parse CLI variables (format: KEY=VALUE)
for _, v := range cliVars {
if strings.Contains(v, "=") {
parts := strings.SplitN(v, "=", 2)
if len(parts) == 2 {
call.Vars.Set(parts[0], ast.Var{
Value: parts[1],
})
}
}
}
if err := e.RunTask(context.Background(), call); err != nil {
fatal(err.Error())
}
return nil

View file

@ -0,0 +1,289 @@
package commands
import (
"bytes"
"os"
"path/filepath"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/wailsapp/task/v3/taskfile/ast"
)
func TestTaskParameterPassing(t *testing.T) {
// Skip if running in CI without proper environment
if os.Getenv("CI") == "true" && os.Getenv("SKIP_INTEGRATION_TESTS") == "true" {
t.Skip("Skipping integration test in CI")
}
// Create a temporary directory for test
tmpDir, err := os.MkdirTemp("", "wails-task-test-*")
require.NoError(t, err)
defer os.RemoveAll(tmpDir)
// Create a test Taskfile
taskfileContent := `version: '3'
tasks:
build:
cmds:
- echo "PLATFORM={{.PLATFORM | default "default-platform"}}"
- echo "CONFIG={{.CONFIG | default "default-config"}}"
silent: true
package:
cmds:
- echo "VERSION={{.VERSION | default "1.0.0"}}"
- echo "OUTPUT={{.OUTPUT | default "output.pkg"}}"
silent: true
test:
cmds:
- echo "ENV={{.ENV | default "test"}}"
- echo "FLAGS={{.FLAGS | default "none"}}"
silent: true
`
taskfilePath := filepath.Join(tmpDir, "Taskfile.yml")
err = os.WriteFile(taskfilePath, []byte(taskfileContent), 0644)
require.NoError(t, err)
// Save current directory
originalWd, err := os.Getwd()
require.NoError(t, err)
defer os.Chdir(originalWd)
// Change to test directory
err = os.Chdir(tmpDir)
require.NoError(t, err)
tests := []struct {
name string
options *RunTaskOptions
otherArgs []string
expectedOutput []string
}{
{
name: "Build task with parameters",
options: &RunTaskOptions{Name: "build"},
otherArgs: []string{"PLATFORM=linux", "CONFIG=production"},
expectedOutput: []string{
"PLATFORM=linux",
"CONFIG=production",
},
},
{
name: "Package task with parameters",
options: &RunTaskOptions{Name: "package"},
otherArgs: []string{"VERSION=2.5.0", "OUTPUT=myapp.pkg"},
expectedOutput: []string{
"VERSION=2.5.0",
"OUTPUT=myapp.pkg",
},
},
{
name: "Task with default values",
options: &RunTaskOptions{Name: "build"},
otherArgs: []string{},
expectedOutput: []string{
"PLATFORM=default-platform",
"CONFIG=default-config",
},
},
{
name: "Task with partial parameters",
options: &RunTaskOptions{Name: "test"},
otherArgs: []string{"ENV=staging"},
expectedOutput: []string{
"ENV=staging",
"FLAGS=none",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Capture output
output := captureTaskOutput(t, tt.options, tt.otherArgs)
// Verify expected output
for _, expected := range tt.expectedOutput {
assert.Contains(t, output, expected, "Output should contain: %s", expected)
}
})
}
}
func TestCLIParameterFormats(t *testing.T) {
tests := []struct {
name string
otherArgs []string
expectError bool
expectedVars map[string]string
}{
{
name: "Standard KEY=VALUE format",
otherArgs: []string{"build", "KEY1=value1", "KEY2=value2"},
expectedVars: map[string]string{
"KEY1": "value1",
"KEY2": "value2",
},
},
{
name: "Values with equals signs",
otherArgs: []string{"build", "URL=https://example.com?key=value", "FORMULA=a=b+c"},
expectedVars: map[string]string{
"URL": "https://example.com?key=value",
"FORMULA": "a=b+c",
},
},
{
name: "Values with spaces (quoted)",
otherArgs: []string{"build", "MESSAGE=Hello World", "PATH=/usr/local/bin"},
expectedVars: map[string]string{
"MESSAGE": "Hello World",
"PATH": "/usr/local/bin",
},
},
{
name: "Mixed valid and invalid arguments",
otherArgs: []string{"build", "VALID=yes", "invalid-arg", "ANOTHER=value", "--flag"},
expectedVars: map[string]string{
"VALID": "yes",
"ANOTHER": "value",
},
},
{
name: "Empty value",
otherArgs: []string{"build", "EMPTY=", "KEY=value"},
expectedVars: map[string]string{
"EMPTY": "",
"KEY": "value",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
call := parseTaskCall(&RunTaskOptions{}, tt.otherArgs)
// Verify variables
for key, expectedValue := range tt.expectedVars {
var actualValue string
found := false
if call.Vars != nil {
call.Vars.Range(func(k string, v ast.Var) error {
if k == key {
actualValue = v.Value.(string)
found = true
}
return nil
})
}
assert.True(t, found, "Variable %s not found", key)
assert.Equal(t, expectedValue, actualValue, "Variable %s mismatch", key)
}
})
}
}
// Helper function to capture task output
func captureTaskOutput(t *testing.T, options *RunTaskOptions, otherArgs []string) string {
// Save original stdout and stderr
oldStdout := os.Stdout
oldStderr := os.Stderr
defer func() {
os.Stdout = oldStdout
os.Stderr = oldStderr
}()
// Create pipe to capture output
r, w, err := os.Pipe()
require.NoError(t, err)
os.Stdout = w
os.Stderr = w
// Run task in a goroutine
done := make(chan bool)
var taskErr error
go func() {
// Note: This is a simplified version for testing
// In real tests, you might want to mock the Task executor
taskErr = RunTask(options, otherArgs)
w.Close()
done <- true
}()
// Read output
var buf bytes.Buffer
_, err = buf.ReadFrom(r)
require.NoError(t, err)
// Wait for task to complete
<-done
// Check for errors (might be expected in some tests)
if taskErr != nil && !strings.Contains(taskErr.Error(), "expected") {
t.Logf("Task error (might be expected): %v", taskErr)
}
return buf.String()
}
func TestBackwardCompatibility(t *testing.T) {
// Test that the old way of calling tasks still works
tests := []struct {
name string
osArgs []string
expectedTask string
expectedVars map[string]string
}{
{
name: "Legacy os.Args parsing",
osArgs: []string{"wails3", "task", "build", "PLATFORM=windows"},
expectedTask: "build",
expectedVars: map[string]string{
"PLATFORM": "windows",
},
},
{
name: "Legacy with flags before task",
osArgs: []string{"wails3", "task", "--verbose", "test", "ENV=prod"},
expectedTask: "test",
expectedVars: map[string]string{
"ENV": "prod",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Save original os.Args
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
os.Args = tt.osArgs
// Parse using the backward compatibility path
call := parseTaskCall(&RunTaskOptions{}, []string{})
assert.Equal(t, tt.expectedTask, call.Task)
for key, expectedValue := range tt.expectedVars {
var actualValue string
if call.Vars != nil {
call.Vars.Range(func(k string, v ast.Var) error {
if k == key {
actualValue = v.Value.(string)
}
return nil
})
}
assert.Equal(t, expectedValue, actualValue, "Variable %s mismatch", key)
}
})
}
}

View file

@ -0,0 +1,188 @@
package commands
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/wailsapp/task/v3/taskfile/ast"
)
func TestParseTaskAndVars(t *testing.T) {
tests := []struct {
name string
options *RunTaskOptions
otherArgs []string
osArgs []string
expectedTask string
expectedVars map[string]string
}{
{
name: "Task name in options with CLI variables",
options: &RunTaskOptions{Name: "build"},
otherArgs: []string{"PLATFORM=linux", "CONFIG=production"},
expectedTask: "build",
expectedVars: map[string]string{
"PLATFORM": "linux",
"CONFIG": "production",
},
},
{
name: "Task name and variables in otherArgs",
options: &RunTaskOptions{},
otherArgs: []string{"test", "ENV=staging", "DEBUG=true"},
expectedTask: "test",
expectedVars: map[string]string{
"ENV": "staging",
"DEBUG": "true",
},
},
{
name: "Only task name, no variables",
options: &RunTaskOptions{},
otherArgs: []string{"deploy"},
expectedTask: "deploy",
expectedVars: map[string]string{},
},
{
name: "Default task when no args provided",
options: &RunTaskOptions{},
otherArgs: []string{},
osArgs: []string{"wails3", "task"}, // Set explicit os.Args to avoid test framework interference
expectedTask: "default",
expectedVars: map[string]string{},
},
{
name: "Variables with equals signs in values",
options: &RunTaskOptions{Name: "build"},
otherArgs: []string{"URL=https://example.com?key=value", "CONFIG=key1=val1,key2=val2"},
expectedTask: "build",
expectedVars: map[string]string{
"URL": "https://example.com?key=value",
"CONFIG": "key1=val1,key2=val2",
},
},
{
name: "Skip non-variable arguments",
options: &RunTaskOptions{Name: "build"},
otherArgs: []string{"PLATFORM=linux", "some-arg", "CONFIG=debug", "--flag"},
expectedTask: "build",
expectedVars: map[string]string{
"PLATFORM": "linux",
"CONFIG": "debug",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Save original os.Args
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
if tt.osArgs != nil {
os.Args = tt.osArgs
}
// Parse the task and variables
call := parseTaskCall(tt.options, tt.otherArgs)
// Verify task name
assert.Equal(t, tt.expectedTask, call.Task)
// Verify variables
if len(tt.expectedVars) > 0 {
require.NotNil(t, call.Vars)
// Check each expected variable
for key, expectedValue := range tt.expectedVars {
var actualValue string
call.Vars.Range(func(k string, v ast.Var) error {
if k == key {
actualValue = v.Value.(string)
}
return nil
})
assert.Equal(t, expectedValue, actualValue, "Variable %s mismatch", key)
}
} else if call.Vars != nil {
// Ensure no variables were set when none expected
count := 0
call.Vars.Range(func(k string, v ast.Var) error {
count++
return nil
})
assert.Equal(t, 0, count, "Expected no variables but found %d", count)
}
})
}
}
// Helper function to extract the task parsing logic for testing
func parseTaskCall(options *RunTaskOptions, otherArgs []string) *ast.Call {
var tasksAndVars []string
// Check if we have a task name specified in options
if options.Name != "" {
// If task name is provided via options, use it and treat otherArgs as CLI variables
tasksAndVars = append([]string{options.Name}, otherArgs...)
} else if len(otherArgs) > 0 {
// Use otherArgs directly if provided
tasksAndVars = otherArgs
} else {
// Fall back to parsing os.Args for backward compatibility
var index int
var arg string
for index, arg = range os.Args[2:] {
if len(arg) > 0 && arg[0] != '-' {
break
}
}
for _, taskAndVar := range os.Args[index+2:] {
if taskAndVar == "--" {
break
}
tasksAndVars = append(tasksAndVars, taskAndVar)
}
}
// Default task
if len(tasksAndVars) == 0 {
tasksAndVars = []string{"default"}
}
// Parse task name and CLI variables
taskName := tasksAndVars[0]
cliVars := tasksAndVars[1:]
// Create call with CLI variables
call := &ast.Call{
Task: taskName,
Vars: &ast.Vars{},
}
// Parse CLI variables (format: KEY=VALUE)
for _, v := range cliVars {
if idx := findEquals(v); idx != -1 {
key := v[:idx]
value := v[idx+1:]
call.Vars.Set(key, ast.Var{
Value: value,
})
}
}
return call
}
// Helper to find the first equals sign
func findEquals(s string) int {
for i, r := range s {
if r == '=' {
return i
}
}
return -1
}

View file

@ -7,16 +7,23 @@ import (
"github.com/wailsapp/wails/v3/internal/flags"
)
func Build(_ *flags.Build) error {
return wrapTask("build")
// runTaskFunc is a variable to allow mocking in tests
var runTaskFunc = RunTask
func Build(_ *flags.Build, otherArgs []string) error {
return wrapTask("build", otherArgs)
}
func Package(_ *flags.Package) error {
return wrapTask("package")
func Package(_ *flags.Package, otherArgs []string) error {
return wrapTask("package", otherArgs)
}
func wrapTask(command string) error {
func wrapTask(command string, otherArgs []string) error {
term.Warningf("`wails3 %s` is an alias for `wails3 task %s`. Use `wails task` for better control and more options.\n", command, command)
os.Args = []string{"wails3", "task", command}
return RunTask(&RunTaskOptions{}, []string{})
// Rebuild os.Args to include the command and all additional arguments
newArgs := []string{"wails3", "task", command}
newArgs = append(newArgs, otherArgs...)
os.Args = newArgs
// Pass the task name via options and otherArgs as CLI variables
return runTaskFunc(&RunTaskOptions{Name: command}, otherArgs)
}

View file

@ -0,0 +1,145 @@
package commands
import (
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/wailsapp/wails/v3/internal/flags"
)
func TestWrapTask(t *testing.T) {
tests := []struct {
name string
command string
otherArgs []string
expectedOsArgs []string
}{
{
name: "Build with parameters",
command: "build",
otherArgs: []string{"PLATFORM=linux", "CONFIG=debug"},
expectedOsArgs: []string{"wails3", "task", "build", "PLATFORM=linux", "CONFIG=debug"},
},
{
name: "Package with parameters",
command: "package",
otherArgs: []string{"VERSION=1.0.0", "OUTPUT=app.pkg"},
expectedOsArgs: []string{"wails3", "task", "package", "VERSION=1.0.0", "OUTPUT=app.pkg"},
},
{
name: "Build without parameters",
command: "build",
otherArgs: []string{},
expectedOsArgs: []string{"wails3", "task", "build"},
},
{
name: "Build with complex parameter values",
command: "build",
otherArgs: []string{"URL=https://example.com?key=value", "TAGS=tag1,tag2,tag3"},
expectedOsArgs: []string{"wails3", "task", "build", "URL=https://example.com?key=value", "TAGS=tag1,tag2,tag3"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Save original os.Args
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
// Mock RunTask to capture the arguments
originalRunTask := runTaskFunc
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
defer func() { runTaskFunc = originalRunTask }()
// Execute wrapTask
err := wrapTaskInternal(tt.command, tt.otherArgs)
assert.NoError(t, err)
// Verify os.Args was set correctly
assert.Equal(t, tt.expectedOsArgs, os.Args)
// Verify RunTask was called with correct parameters
assert.Equal(t, tt.command, capturedOptions.Name)
assert.Equal(t, tt.otherArgs, capturedOtherArgs)
})
}
}
func TestBuildCommand(t *testing.T) {
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
// Test Build command
buildFlags := &flags.Build{}
otherArgs := []string{"PLATFORM=darwin", "CONFIG=release"}
err := Build(buildFlags, otherArgs)
assert.NoError(t, err)
assert.Equal(t, "build", capturedOptions.Name)
assert.Equal(t, otherArgs, capturedOtherArgs)
}
func TestPackageCommand(t *testing.T) {
// Save original RunTask
originalRunTask := runTaskFunc
defer func() { runTaskFunc = originalRunTask }()
// Mock RunTask to capture the arguments
var capturedOptions *RunTaskOptions
var capturedOtherArgs []string
runTaskFunc = func(options *RunTaskOptions, otherArgs []string) error {
capturedOptions = options
capturedOtherArgs = otherArgs
return nil
}
// Save original os.Args
originalArgs := os.Args
defer func() { os.Args = originalArgs }()
// Test Package command
packageFlags := &flags.Package{}
otherArgs := []string{"VERSION=2.0.0", "OUTPUT=myapp.dmg"}
err := Package(packageFlags, otherArgs)
assert.NoError(t, err)
assert.Equal(t, "package", capturedOptions.Name)
assert.Equal(t, otherArgs, capturedOtherArgs)
}
// Variables to enable mocking in tests
var (
wrapTaskFunc = wrapTask
)
// Internal version that uses the function variables for testing
func wrapTaskInternal(command string, otherArgs []string) error {
// Note: We skip the warning message in tests
// Rebuild os.Args to include the command and all additional arguments
newArgs := []string{"wails3", "task", command}
newArgs = append(newArgs, otherArgs...)
os.Args = newArgs
// Pass the task name via options and otherArgs as CLI variables
return runTaskFunc(&RunTaskOptions{Name: command}, otherArgs)
}