Skip to content
Merged
Show file tree
Hide file tree
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
20 changes: 20 additions & 0 deletions desktop/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,26 @@ go 1.26.4

replace github.com/midagedev/gadak => ../

// wails v3.0.0-beta.12 plus wailsapp/wails#6006, nothing else. The tag is
// the upstream tag with those two commits cherry-picked
// (github.com/midagedev/wails, branch gadak/v3.0.0-beta.12); `git diff
// v3.0.0-beta.12..v3.0.0-beta.12-gadak.1` is 10 lines in one file.
//
// Why: webview_window_windows.go registers a "*" WebResourceRequested
// filter for asset serving, so on Windows EVERY request the WebView makes
// runs through edge.Chromium's handler — and that handler called
// log.Fatal(err) when args.GetRequest() failed. One transient COM failure
// on one request killed gadak, skipping deferred cleanup, and log.Fatal
// does not even reach the error callback wails' own SetErrorCallback
// configures. The PR drops the request and logs instead.
//
// The PR is open and unblocked (its only review comment was addressed and
// resolved the same day) — it is waiting on a maintainer, and gadak is not.
// DELETE THIS REPLACE when it merges into a beta we take: the fork branch
// exists only to carry it, and every wails bump has to redo it (fetch the
// new tag, cherry-pick, tag as -gadak.N) until then.
replace github.com/wailsapp/wails/v3 => github.com/midagedev/wails/v3 v3.0.0-beta.12-gadak.1

require (
github.com/midagedev/gadak v0.0.0
github.com/wailsapp/wails/v3 v3.0.0-beta.12
Expand Down
4 changes: 2 additions & 2 deletions desktop/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byF
github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
github.com/midagedev/issuetap v0.0.0-20260828070557-ccb366aea250 h1:SXqP1UxBFdBUHTThplIgw5LCr5IcvFwWbeDP+ku36Xk=
github.com/midagedev/issuetap v0.0.0-20260828070557-ccb366aea250/go.mod h1:VI3sqskL2eqVH88g5jS9hAHTWPF8SJocH69p2/xh5Z0=
github.com/midagedev/wails/v3 v3.0.0-beta.12-gadak.1 h1:SCcBMBdM3MVtoPv9FaVJZMUd1Hl9sGEzy7Cx5Q5kRXY=
github.com/midagedev/wails/v3 v3.0.0-beta.12-gadak.1/go.mod h1:zKZYhB3WjrN5LhJWbnOAVMN0Xf8qTozbw2nf5micKl4=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
Expand All @@ -48,8 +50,6 @@ github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/wailsapp/wails/v3 v3.0.0-beta.12 h1:Vema2kFgJvkwPovQ8GMBBrkZNm5cKVR4bYzSCMgU+PU=
github.com/wailsapp/wails/v3 v3.0.0-beta.12/go.mod h1:zKZYhB3WjrN5LhJWbnOAVMN0Xf8qTozbw2nf5micKl4=
golang.org/x/mod v0.37.0 h1:vF1DjpVEshcIqoEaauuHebaLk1O1forxjxBaVn884JQ=
golang.org/x/mod v0.37.0/go.mod h1:m8S8VeM9r4dzDwjrKO0a1sZP3YjeMamRRlD+fmR2Q/0=
golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM=
Expand Down
39 changes: 39 additions & 0 deletions desktop/platforms_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,47 @@ func TestPinnedWailsVersionIsNamed(t *testing.T) {
}
}

// replacedWailsVersion is the version go.mod redirects the wails module to,
// or "" when there is no replace. Distinct from pinnedWailsVersion: the
// require line names the upstream base even while a fork carries the build.
func replacedWailsVersion(t *testing.T) string {
t.Helper()
body, err := os.ReadFile("go.mod")
if err != nil {
t.Fatal(err)
}
const prefix = "replace github.com/wailsapp/wails/v3 "
for _, line := range strings.Split(string(body), "\n") {
line = strings.TrimSpace(line)
if !strings.HasPrefix(line, prefix) {
continue
}
fields := strings.Fields(line)
if len(fields) >= 5 {
return fields[4]
}
t.Fatalf("go.mod wails replace is not a module@version form: %q", line)
}
return ""
}

func TestWailsModuleVersionMatchesGoMod(t *testing.T) {
want := pinnedWailsVersion(t)
// 2026-08-30 (GDK-1024 fork policy, docs/runbooks/upstream-pr.md): a
// `replace` onto a fork makes the built binary's version legitimately
// differ from the require line, and wailsModuleVersion() prefers
// Replace.Version by design — it reports what actually linked. So the
// assertion narrows rather than relaxes: the fork must be a patch ON
// the pin (prefix), and the binary must be the fork, not the base.
// FAIL-first: this test went red on the commit that added the replace,
// "wailsModuleVersion() = \"v3.0.0-beta.12-gadak.1\", go.mod has
// \"v3.0.0-beta.12\"" — the run is on PR #78, job "Desktop tests".
if fork := replacedWailsVersion(t); fork != "" {
if !strings.HasPrefix(fork, want) {
t.Fatalf("go.mod replaces wails with %q, which is not a patch on the pinned %q — a fork cut from a different upstream base is a silent version bump", fork, want)
}
want = fork
}
if got := wailsModuleVersion(); got != want {
t.Fatalf("wailsModuleVersion() = %q, go.mod has %q", got, want)
}
Expand Down
58 changes: 58 additions & 0 deletions docs/runbooks/upstream-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,64 @@ unconsidered.
- Do not open follow-up issues in the target's tracker on a bot's
suggestion; that is the maintainers' call.

## Shipping a PR the upstream has not merged

A good PR can sit for weeks on a maintainer who is busy, and gadak does not
have to wait behind it (user decision 2026-08-30: *"업스트림 머지 안된건
포크해서라도 나가자"*). Ship it from a fork branch, pinned, with an
expiry note.

Do this only when the defect is **reachable in gadak** — say how, in the
`replace` comment. wails#6006's reachability is one line of upstream source
(`webview_window_windows.go` registers a `"*"` filter, so every Windows
request runs the handler that called `log.Fatal`). A PR that is merely good
is an upstream contribution, not a dependency change.

Go, measured 2026-08-30 on `desktop/` (wails v3):

```bash
# 1. A distribution branch: the tag we are on, plus the PR's commits only.
git -C ~/repo/<fork> branch -f gadak/<upstream-tag> <upstream-tag>
git -C ~/repo/<fork> checkout gadak/<upstream-tag>
git -C ~/repo/<fork> cherry-pick <pr-sha>... # the PR's commits
git -C ~/repo/<fork> tag <upstream-tag>-gadak.1
git -C ~/repo/<fork> push fork gadak/<upstream-tag> <upstream-tag>-gadak.1

# 2. Pin it.
go mod edit -replace <module>=<fork-module>@<upstream-tag>-gadak.1
go mod tidy && go build ./... && GOOS=windows go build ./...
```

Two things that are not obvious and cost a round if guessed:

- **The fork's `go.mod` module line stays as upstream's.** Go resolves the
package path from the *original* module path and only checks that the
replacement's declared path matches the *replacement requirement* — so a
fork works with no import rewriting at all. (Rewriting the module path is
the folklore answer; it would break every internal import.)
- **Tag the fork branch.** Without a tag, `go mod tidy` derives a
pseudo-version from the nearest tag reachable *in the fork*, which was
`v3.0.0-beta.9.0.2026…` for a branch cut from beta.12 — a `go.mod` line
that reads like a downgrade. `<upstream-tag>-gadak.N` reads like what it
is and sorts as a prerelease.

- **A pin gate that reads the build has to be taught about the replace.**
`debug.ReadBuildInfo()` reports the *replacement's* version, so
`desktop.TestWailsModuleVersionMatchesGoMod` went red on the very commit
that added the fork. The fix is not to relax it: the gate now reads the
`replace` line too and asserts the fork version is *prefixed by* the
required upstream version — so `v3.0.0-beta.12-gadak.1` passes while a
fork silently cut from a different base still fails. Name the fork tag
`<upstream-tag>-gadak.N` and that holds for free.

Then, in the repo: the `replace` carries a comment saying which PR, why the
defect is reachable, and **"delete this when it merges"**. A `replace` with
no expiry is how a fork becomes permanent by accident. Every upstream bump
redoes the branch (new tag → cherry-pick → `-gadak.N+1`) until the merge.

A `desktop/` change needs a PR — the Windows and Linux desktop jobs are the
ones local gates cannot run (CLAUDE.md).

## Lead-only boundary

Fork, push, `gh pr create`, replies, and any tracker write are lead actions.
Expand Down
Loading