Merge pull request #8069 from esengine/ci/wails-version-pin

ci(wails): unify the CLI and library version pin / 统一 Wails CLI 与依赖版本锁定
This commit is contained in:
SivanCola authored and GitHub committed 2026-08-10 04:04:05 +08:00
commit d541409e26
9 files changed
+257 -10

No files matched your search

+7 -2
View File
@@ -321,7 +321,7 @@ jobs:
- name: Install Wails CLI
run: |
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
go install github.com/wailsapp/wails/v2/cmd/wails@v2.12.0
go install "github.com/wailsapp/wails/v2/cmd/wails@$(cat "$GITHUB_WORKSPACE/.wails-version")"
- name: gofmt
run: |
@@ -449,7 +449,7 @@ jobs:
- name: Install Wails CLI
run: |
echo "$(go env GOPATH)/bin" >> "$GITHUB_PATH"
go install github.com/wailsapp/wails/v2/cmd/wails@v2.12.0
go install "github.com/wailsapp/wails/v2/cmd/wails@$(cat "$GITHUB_WORKSPACE/.wails-version")"
# go:embed of frontend/dist needs a built frontend before the package
# compiles, same as the ubuntu desktop leg.
@@ -492,6 +492,11 @@ jobs:
- name: repo standards
run: go run ./tools/repolint
- name: wails version pin
run: |
bash scripts/check-wails-pin.sh
bash scripts/check-wails-pin.test.sh
# `make lint-install` reads the same file, so a local run and this job
# cannot drift onto different linter versions.
- id: golangci
+1 -1
View File
@@ -371,7 +371,7 @@ jobs:
rm -f "$RUNNER_TEMP/cert.p12"
- name: Install Wails CLI
run: go install github.com/wailsapp/wails/v2/cmd/wails@v2.12.0
run: go install "github.com/wailsapp/wails/v2/cmd/wails@$(cat "$GITHUB_WORKSPACE/.wails-version")"
# Official Windows releases must fail closed. Forks can still exercise
# unsigned packaging without repository secrets, but esengine releases
+1
View File
@@ -0,0 +1 @@
v2.13.0
+2
View File
@@ -8,6 +8,8 @@ everything you need to get started.
- **Go 1.25+** — the project targets the latest stable Go release
- **Git** — for version control
- **Node.js** (optional) — only if you work on the desktop app (`desktop/`)
- **Wails CLI** (desktop only) — run `make wails-install` so the CLI matches
`desktop/go.mod`
## Getting started
+8 -1
View File
@@ -8,8 +8,9 @@ LDFLAGS := -s -w \
GOEXE := $(shell go env GOEXE)
# One pin for the Makefile and the CI lint job; see .github/workflows/ci.yml.
GOLANGCI_VERSION := $(shell cat .golangci-version)
WAILS_VERSION := $(shell tr -d '[:space:]' < .wails-version)
.PHONY: build vet fmt lint lint-go lint-install lint-cross lint-update test desktop-test desktop-test-short desktop-test-times sdk-test sdk-test-race hooks cross clean
.PHONY: build vet fmt lint lint-go lint-install lint-cross lint-update wails-install test desktop-test desktop-test-short desktop-test-times sdk-test sdk-test-race hooks cross clean
build:
CGO_ENABLED=0 go build -ldflags "$(LDFLAGS)" -o bin/reasonix$(GOEXE) ./cmd/reasonix
@@ -26,6 +27,8 @@ fmt:
# particular never surface in `go vet`.
lint: lint-go
go run ./tools/repolint
bash scripts/check-wails-pin.sh
bash scripts/check-wails-pin.test.sh
lint-go:
@command -v golangci-lint >/dev/null || { echo "golangci-lint not installed; run: make lint-install"; exit 1; }
@@ -41,6 +44,10 @@ lint-install:
lint-update:
go run ./tools/repolint -update
wails-install:
bash scripts/check-wails-pin.sh
go install "github.com/wailsapp/wails/v2/cmd/wails@$(WAILS_VERSION)"
# Linting one GOOS leaves every //go:build windows and darwin file unchecked.
lint-cross:
@for t in "linux ." "darwin ." "windows ." "linux desktop" "windows desktop"; do \
+2 -1
View File
@@ -35,7 +35,8 @@ vet / test ./...` skip this directory, while the import path stays under
- Go (matches the parent module).
- Node + **pnpm** (`npm i -g pnpm`).
- Wails CLI: `go install github.com/wailsapp/wails/v2/cmd/wails@latest`
- Wails CLI matching the library: run `make wails-install` from the repository
root. The target reads the shared `.wails-version` pin.
- Platform webview libs: macOS ships WebKit; Windows needs the Edge **WebView2**
runtime; Linux needs `libgtk-3-dev` plus WebKitGTK. The default build links
against **WebKitGTK 4.0**; distros that only ship **4.1** (Fedora 40+, Ubuntu
+22 -5
View File
@@ -63,6 +63,14 @@ go_bin_dir() {
printf '%s' "$gobin"
}
installed_wails_version() {
local output
if ! output="$(wails version 2>/dev/null)"; then
return 1
fi
awk 'match($0, /v[0-9]+\.[0-9]+\.[0-9]+/) { print substr($0, RSTART, RLENGTH); exit }' <<<"$output"
}
sanitize_semver_id() {
local value="$1"
value="$(printf '%s' "$value" | tr '[:upper:]' '[:lower:]' | sed -E 's/[^0-9A-Za-z]+/-/g; s/^-+//; s/-+$//; s/-+/-/g')"
@@ -127,9 +135,11 @@ default_version() {
}
install_or_check_tools() {
local os install_tools
local os install_tools wails_pin wails_version
os="${1%/*}"
install_tools="${PROD_TEST_INSTALL_TOOLS:-1}"
wails_pin="$(tr -d '[:space:]' < "$ROOT/.wails-version")"
[[ -n "$wails_pin" ]] || fail ".wails-version is empty"
need_cmd git
need_cmd go
@@ -151,14 +161,21 @@ install_or_check_tools() {
fi
fi
if ! command -v wails >/dev/null 2>&1; then
wails_version=""
if command -v wails >/dev/null 2>&1; then
wails_version="$(installed_wails_version || true)"
fi
if [[ "$wails_version" != "$wails_pin" ]]; then
if [[ "$install_tools" == "1" ]]; then
echo "==> installing Wails CLI"
go install github.com/wailsapp/wails/v2/cmd/wails@v2.12.0
echo "==> installing Wails CLI $wails_pin (found ${wails_version:-none})"
go install "github.com/wailsapp/wails/v2/cmd/wails@$wails_pin"
hash -r
else
fail "wails not found. Install with: go install github.com/wailsapp/wails/v2/cmd/[email protected]"
fail "Wails CLI ${wails_version:-not found} does not match .wails-version $wails_pin. Run: make wails-install"
fi
fi
wails_version="$(installed_wails_version || true)"
[[ "$wails_version" == "$wails_pin" ]] || fail "Wails CLI ${wails_version:-not found} does not match .wails-version $wails_pin after installation"
case "$os" in
darwin)
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env bash
# The Wails CLI and the Wails library must be the same version.
#
# They drift silently in both directions. Dependabot bumps the library in
# desktop/go.mod but cannot see the CLI, whose version is a string inside three
# workflow files; and `wails dev` rewrites desktop/go.mod down to whatever CLI
# the developer has installed, so a local run can quietly revert a dependency
# upgrade. One pin, read by everyone, and this check to prove it held.
set -euo pipefail
root="${1:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}"
pin="$(tr -d '[:space:]' < "$root/.wails-version")"
mod="$(awk '/github.com\/wailsapp\/wails\/v2 v/ {print $2; exit}' "$root/desktop/go.mod")"
module="github.com/wailsapp/wails/v2/cmd/wails"
if [ -z "$pin" ]; then
echo "check-wails-pin: .wails-version is empty" >&2
exit 1
fi
if [[ ! "$pin" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "check-wails-pin: .wails-version must contain one stable semantic version (vMAJOR.MINOR.PATCH), got: $pin" >&2
exit 1
fi
if [ "$pin" != "$mod" ]; then
cat >&2 <<MSG
check-wails-pin: version drift
.wails-version $pin
desktop/go.mod $mod
Running \`wails dev\` with an older CLI rewrites desktop/go.mod to match it. If the
library upgrade is intended, bump .wails-version too so CI installs the same CLI;
otherwise restore go.mod (git checkout -- desktop/go.mod desktop/go.sum).
MSG
exit 1
fi
for workflow in "$root"/.github/workflows/ci.yml "$root"/.github/workflows/release-desktop.yml; do
if grep -q "cmd/wails@v" "$workflow"; then
echo "check-wails-pin: $(basename "$workflow") hard-codes a CLI version; read .wails-version instead" >&2
exit 1
fi
# Several desktop steps run with working-directory: desktop, where a bare
# `cat .wails-version` resolves to nothing and installs wails@"".
if grep -q 'cat \.wails-version' "$workflow"; then
echo "check-wails-pin: $(basename "$workflow") reads .wails-version relative to the job's working directory; use \$GITHUB_WORKSPACE" >&2
exit 1
fi
done
# The workflows are not the only way developers build a release. Reject every
# tracked install source except the three supported ways to read the shared pin.
install_lines="$(git -C "$root" grep -nF "$module@" -- . || true)"
unexpected_sources="$(awk -v module="$module" '
index($0, ".github/workflows/ci.yml:") == 1 && index($0, module "@$(cat \"$GITHUB_WORKSPACE/.wails-version\")") { next }
index($0, ".github/workflows/release-desktop.yml:") == 1 && index($0, module "@$(cat \"$GITHUB_WORKSPACE/.wails-version\")") { next }
index($0, "Makefile:") == 1 && index($0, module "@$(WAILS_VERSION)") { next }
index($0, "prod_test:") == 1 && index($0, module "@$wails_pin") { next }
{ print }
' <<<"$install_lines")"
if [[ -n "$unexpected_sources" ]]; then
cat >&2 <<MSG
check-wails-pin: Wails CLI installs must read the shared .wails-version pin; found unsupported sources:
$unexpected_sources
MSG
exit 1
fi
# Keep setup docs from bypassing the shared pin too. The escaped dots keep this
# regex from matching its own source.
hard_coded="$(git -C "$root" grep -nE 'github\.com/wailsapp/wails/v2/cmd/wails@(v[0-9]|latest)' -- . || true)"
if [[ -n "$hard_coded" ]]; then
cat >&2 <<MSG
check-wails-pin: Wails CLI installs must read .wails-version; found:
$hard_coded
MSG
exit 1
fi
workflow_install="go install \"$module@\$(cat \"\$GITHUB_WORKSPACE/.wails-version\")\""
for workflow in "$root"/.github/workflows/ci.yml "$root"/.github/workflows/release-desktop.yml; do
grep -Fq "$workflow_install" "$workflow" || {
echo "check-wails-pin: $(basename "$workflow") must install Wails from \$GITHUB_WORKSPACE/.wails-version" >&2
exit 1
}
done
grep -Fq 'WAILS_VERSION := $(shell tr -d '\''[:space:]'\'' < .wails-version)' "$root/Makefile" || {
echo "check-wails-pin: Makefile must read WAILS_VERSION from .wails-version" >&2
exit 1
}
grep -Fq "go install \"$module@\$(WAILS_VERSION)\"" "$root/Makefile" || {
echo "check-wails-pin: make wails-install must install WAILS_VERSION" >&2
exit 1
}
grep -Fq 'make wails-install' "$root/desktop/README.md" || {
echo "check-wails-pin: desktop/README.md must direct developers to make wails-install" >&2
exit 1
}
grep -Fq 'wails version' "$root/prod_test" || {
echo "check-wails-pin: prod_test must verify the installed Wails CLI version" >&2
exit 1
}
grep -Fq "go install \"$module@\$wails_pin\"" "$root/prod_test" || {
echo "check-wails-pin: prod_test must install the shared Wails pin" >&2
exit 1
}
echo "check-wails-pin: CLI and library both pinned at $pin"
+107
View File
@@ -0,0 +1,107 @@
#!/usr/bin/env bash
set -euo pipefail
root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
scratch="$(mktemp -d)"
trap 'rm -rf "$scratch"' EXIT
wails_module="github.com/wailsapp/wails/v2/cmd/wails"
fixture_pin="v9.8.7"
repo_pin="$(tr -d '[:space:]' < "$root/.wails-version")"
fake_mismatch="v0.0.0"
if [[ "$fake_mismatch" == "$repo_pin" ]]; then
fake_mismatch="v0.0.1"
fi
make_fixture() {
local name="$1"
local fixture="$scratch/$name"
mkdir -p "$fixture/.github/workflows" "$fixture/desktop" "$fixture/scripts"
cp "$root/scripts/check-wails-pin.sh" "$fixture/scripts/check-wails-pin.sh"
printf '%s\n' "$fixture_pin" > "$fixture/.wails-version"
printf 'github.com/wailsapp/wails/v2 %s\n' "$fixture_pin" > "$fixture/desktop/go.mod"
printf 'run: go install "%s@$(cat "$GITHUB_WORKSPACE/.wails-version")"\n' "$wails_module" > "$fixture/.github/workflows/ci.yml"
cp "$fixture/.github/workflows/ci.yml" "$fixture/.github/workflows/release-desktop.yml"
printf 'go install "%s@$wails_pin"\nwails version\n' "$wails_module" > "$fixture/prod_test"
printf 'Run `make wails-install`.\n' > "$fixture/desktop/README.md"
printf 'WAILS_VERSION := $(shell tr -d '\''[:space:]'\'' < .wails-version)\nwails-install:\n\tgo install "%s@$(WAILS_VERSION)"\n' "$wails_module" > "$fixture/Makefile"
git -C "$fixture" init -q
git -C "$fixture" add .
printf '%s' "$fixture"
}
expect_failure() {
local fixture="$1"
local expected="$2"
local output
if output="$(bash "$fixture/scripts/check-wails-pin.sh" "$fixture" 2>&1)"; then
echo "check-wails-pin test: expected failure containing: $expected" >&2
exit 1
fi
grep -Fq "$expected" <<<"$output" || {
echo "check-wails-pin test: missing failure text: $expected" >&2
echo "$output" >&2
exit 1
}
}
fixture="$(make_fixture valid)"
bash "$fixture/scripts/check-wails-pin.sh" "$fixture" >/dev/null
fixture="$(make_fixture prod-test-hard-code)"
printf 'go install %[email protected]\n' "$wails_module" >> "$fixture/prod_test"
git -C "$fixture" add prod_test
expect_failure "$fixture" 'prod_test:'
fixture="$(make_fixture docs-latest)"
printf 'go install %s@latest\n' "$wails_module" >> "$fixture/desktop/README.md"
git -C "$fixture" add desktop/README.md
expect_failure "$fixture" 'desktop/README.md:'
fixture="$(make_fixture module-drift)"
printf 'github.com/wailsapp/wails/v2 v9.8.8\n' > "$fixture/desktop/go.mod"
expect_failure "$fixture" 'version drift'
fixture="$(make_fixture workflow-cwd)"
printf 'run: go install "%s@$(cat .wails-version)"\n' "$wails_module" > "$fixture/.github/workflows/ci.yml"
expect_failure "$fixture" "reads .wails-version relative to the job's working directory"
fixture="$(make_fixture workflow-other-source)"
printf 'run: go install "%s@$WAILS_VERSION"\n' "$wails_module" > "$fixture/.github/workflows/ci.yml"
expect_failure "$fixture" 'unsupported sources'
fixture="$(make_fixture makefile-hard-code)"
printf 'WAILS_VERSION := %s\nwails-install:\n\tgo install "%s@$(WAILS_VERSION)"\n' "$fixture_pin" "$wails_module" > "$fixture/Makefile"
expect_failure "$fixture" 'Makefile must read WAILS_VERSION from .wails-version'
fixture="$(make_fixture invalid-pin)"
printf '%s;unexpected\n' "$fixture_pin" > "$fixture/.wails-version"
printf 'github.com/wailsapp/wails/v2 %s;unexpected\n' "$fixture_pin" > "$fixture/desktop/go.mod"
expect_failure "$fixture" '.wails-version must contain one stable semantic version'
fake_bin="$scratch/fake-bin"
mkdir -p "$fake_bin"
printf '#!/usr/bin/env bash\nprintf "%s\\n"\n' "$fake_mismatch" > "$fake_bin/wails"
printf '#!/usr/bin/env bash\nexit 0\n' > "$fake_bin/pnpm"
chmod +x "$fake_bin/wails" "$fake_bin/pnpm"
if output="$(GOBIN="$fake_bin" PATH="$fake_bin:$PATH" PROD_TEST_INSTALL_TOOLS=0 PROD_TEST_FAST=1 DESKTOP_BUILD_SKIP_DMG=1 PROD_TEST_OPEN_DIST=0 "$root/prod_test" darwin/arm64 2>&1)"; then
echo "check-wails-pin test: prod_test accepted a mismatched installed Wails CLI" >&2
exit 1
fi
grep -Fq "Wails CLI $fake_mismatch does not match .wails-version $repo_pin" <<<"$output" || {
echo "check-wails-pin test: prod_test did not report the installed-version mismatch" >&2
echo "$output" >&2
exit 1
}
printf '#!/usr/bin/env bash\nexit 1\n' > "$fake_bin/wails"
if output="$(GOBIN="$fake_bin" PATH="$fake_bin:$PATH" PROD_TEST_INSTALL_TOOLS=0 PROD_TEST_FAST=1 DESKTOP_BUILD_SKIP_DMG=1 PROD_TEST_OPEN_DIST=0 "$root/prod_test" darwin/arm64 2>&1)"; then
echo "check-wails-pin test: prod_test accepted a broken installed Wails CLI" >&2
exit 1
fi
grep -Fq "Wails CLI not found does not match .wails-version $repo_pin" <<<"$output" || {
echo "check-wails-pin test: prod_test did not report the broken installed CLI" >&2
echo "$output" >&2
exit 1
}
echo "check-wails-pin tests: ok"