diff --git a/action.yml b/action.yml index 3d80f6e..e012c71 100644 --- a/action.yml +++ b/action.yml @@ -63,13 +63,13 @@ inputs: description: "Base name for release assets, before the -- suffix" required: false default: "" - task: + wails3-command: description: > - Wails v3 stack: the Taskfile target to run. Empty runs :build, which - produces a bare binary — a project wanting the bundle or an installer - names its package target here. + Wails v3 stack: which wails3 CLI verb to run — `build` for the bare + binary, `package` for the platform's installable artefact (.app, the NSIS + installer, the Linux packages). required: false - default: "" + default: "build" entry: description: > Deno stack: entry module to compile. Empty probes for run.ts, main.ts, @@ -139,6 +139,7 @@ runs: app-working-directory: ${{ inputs.app-working-directory }} go-directory: ${{ inputs.go-directory }} release-asset-prefix: ${{ inputs.release-asset-prefix }} + wails3-command: ${{ inputs.wails3-command }} entry: ${{ inputs.entry }} permissions: ${{ inputs.permissions }} deb: ${{ inputs.deb }} diff --git a/actions/action.yml b/actions/action.yml index 2b7f3a1..5db31f4 100644 --- a/actions/action.yml +++ b/actions/action.yml @@ -64,6 +64,10 @@ inputs: description: "Base name for release assets, before the -- suffix" required: false default: "" + wails3-command: + description: "Wails v3 stack: the wails3 CLI verb — build or package." + required: false + default: "build" entry: description: "Deno stack: entry module to compile. Empty probes for the usual names." required: false @@ -172,12 +176,11 @@ runs: build-name: ${{ inputs.build-name }} app-working-directory: ${{ inputs.app-working-directory }} release-asset-prefix: ${{ inputs.release-asset-prefix }} - # The v3 stack runs the project's own Taskfile target, so which target - # is the whole configuration. Unforwarded it defaulted to :build on - # every caller — a caller asking for a package target got a bare binary - # and no error, because Actions ignores a `with:` key the action does - # not declare. - task: ${{ inputs.task }} + # build gives the bare binary, package the installable artefact. A + # caller wanting the second and getting the first finds out at whatever + # step next expects a bundle, so this is the difference between a + # release that has installers and one that does not. + wails3-command: ${{ inputs.wails3-command }} - name: Call Go wrapper id: go diff --git a/actions/build/wails3/action.yml b/actions/build/wails3/action.yml index a6c2605..5c66901 100644 --- a/actions/build/wails3/action.yml +++ b/actions/build/wails3/action.yml @@ -38,10 +38,10 @@ inputs: description: "Root of the app being built" required: false default: "." - task: - description: "Taskfile target; defaults to :build from the runner" + wails3-command: + description: "The wails3 CLI verb — build for the binary, package for the installable artefact" required: false - default: "" + default: "build" wails3-tool: description: "How to invoke wails3; defaults to the module-pinned `go tool wails3`" required: false @@ -103,7 +103,7 @@ runs: build: ${{ inputs.build }} app-working-directory: ${{ inputs.app-working-directory }} build-name: ${{ inputs.build-name }} - task: ${{ inputs.task }} + wails3-command: ${{ inputs.wails3-command }} wails3-tool: ${{ inputs.wails3-tool }} - name: Sign artifacts (OS-conditional) diff --git a/actions/build/wails3/build/action.yml b/actions/build/wails3/build/action.yml index 29a9b99..1d66245 100644 --- a/actions/build/wails3/build/action.yml +++ b/actions/build/wails3/build/action.yml @@ -1,13 +1,14 @@ name: "Build Wails v3 App" description: > - Builds a Wails v3 application through its Taskfile and normalises the - executable bits per OS. + Builds or packages a Wails v3 application through the wails3 CLI and + normalises the executable bits per OS. - Wails v3 is not v2 with a new flag set. There is no `wails build` invocation - to compose: the project owns a Taskfile, wails3 runs targets in it, and the - per-platform targets are where the real build lives. So this action runs the - project's own target rather than reconstructing the command, which keeps CI - and a developer's local build the same path. + Wails v3 is not v2 with a new flag set — there are no build flags to compose, + because a v3 project describes its own build. But the CLI still owns the + verbs: `wails3 build` and `wails3 package`. Both dispatch to the project's + build description internally, which is Wails' business rather than this + action's, so this runs the verb and lets Wails decide what it means. CI and a + developer's machine then take the same path through the same tool. inputs: build: @@ -21,12 +22,13 @@ inputs: build-name: description: "Binary or bundle name, used to locate the output" required: true - task: + wails3-command: description: > - Taskfile target to run. Defaults to :build, resolved from the runner — - darwin:build, linux:build, windows:build — which is the wails3 convention. + Which wails3 CLI verb to run: `build` for the bare binary, `package` for + the platform's installable artefact — the .app bundle, the NSIS + installer, the Linux packages. required: false - default: "" + default: "build" wails3-tool: description: > How to invoke wails3. Defaults to `go tool wails3`, which resolves the @@ -37,33 +39,33 @@ inputs: default: "go tool wails3" outputs: - TASK_RUN: - description: "The Taskfile target that was executed" - value: ${{ steps.target.outputs.TASK }} + WAILS3_COMMAND: + description: "The wails3 verb that was executed" + value: ${{ steps.verb.outputs.COMMAND }} runs: using: "composite" steps: - - name: Resolve the Taskfile target - id: target + # Only the two verbs. Anything else would reach the CLI as a subcommand it + # does not have, and the failure would name wails3 rather than the caller + # that asked for it. + - name: Resolve the wails3 verb + id: verb shell: bash - working-directory: ${{ inputs.app-working-directory }} env: - REQUESTED: ${{ inputs.task }} + REQUESTED: ${{ inputs.wails3-command }} run: | set -euo pipefail - if [ -n "$REQUESTED" ]; then - TASK="$REQUESTED" - else - case "${RUNNER_OS}" in - macOS) TASK="darwin:build" ;; - Linux) TASK="linux:build" ;; - Windows) TASK="windows:build" ;; - *) echo "::error::unsupported runner OS '${RUNNER_OS}'"; exit 1 ;; - esac - fi - echo "TASK=$TASK" >> "$GITHUB_OUTPUT" - echo "[DEBUG_LOG] (wails3) target=$TASK" + COMMAND="${REQUESTED:-build}" + case "$COMMAND" in + build|package) ;; + *) + echo "::error::wails3-command must be 'build' or 'package', got '$COMMAND'" + exit 1 + ;; + esac + echo "COMMAND=$COMMAND" >> "$GITHUB_OUTPUT" + echo "[DEBUG_LOG] (wails3) command=$COMMAND" # A project that pins wails3 with a go.mod tool directive builds with the # version it was tested against. Falling back to an install is for projects @@ -86,20 +88,11 @@ runs: go install github.com/wailsapp/wails/v3/cmd/wails3@latest fi - - name: Install Task - shell: bash - run: | - set -euo pipefail - if ! command -v task >/dev/null 2>&1; then - go install github.com/go-task/task/v3/cmd/task@latest - echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH" - fi - - name: Build if: inputs.build == 'true' shell: bash working-directory: ${{ inputs.app-working-directory }} - run: ${{ inputs.wails3-tool }} task ${{ steps.target.outputs.TASK }} + run: ${{ inputs.wails3-tool }} ${{ steps.verb.outputs.COMMAND }} # wails3 writes to bin/. The bundle layout differs per platform, so the # executable bit is set where each platform actually keeps the binary. diff --git a/tests/action_contracts.py b/tests/action_contracts.py index 4ffa68e..f4a6edc 100755 --- a/tests/action_contracts.py +++ b/tests/action_contracts.py @@ -108,6 +108,21 @@ def main() -> int: # Inputs need a description or the marketplace listing renders blanks. declared = (doc.get("inputs") or {}) + + # ${{ inputs.X }} where X is not declared in *this* file resolves to the + # empty string. Nothing warns — not the runner, not the caller, not the + # forwarding check above, which only asks whether a name a file declares + # gets passed on. Forwarding an input the file never declared satisfies + # it while passing nothing, so a chain can be repaired at one hop, report + # sound, and still be severed at the next. That is how `task` was added + # to the root action and forwarded from the orchestrator, and every + # Wails v3 build carried on running its default target. + for i, line in enumerate(path.read_text().split("\n"), 1): + for ref in re.findall(r"inputs\.([A-Za-z0-9_-]+)", line): + if ref not in declared: + problems.append( + f"{rel}:{i}: references inputs.{ref}, which this file does " + f"not declare — it will always be empty") for name, spec in declared.items(): if not isinstance(spec, dict) or not spec.get("description"): problems.append(f"{rel}: input {name} has no description")