fix: migrate to github.com/mxschmitt/playwright-go v0.6100.0 - #228
Conversation
The playwright-community GitHub org is archived and playwright-go moved
back to github.com/mxschmitt/playwright-go. v0.6100.0 is the first
release published under the new module path, and its go.mod declares
that path — so resolving it through the old path fails:
module declares its path as: github.com/mxschmitt/playwright-go
but was required as: github.com/playwright-community/playwright-go
Dependabot reports this as go_module_path_mismatch and aborts the entire
update run, which is why every gomod update has been failing and no
playwright-go bump ever landed.
Staying on v0.5700.1 also left CI broken independently: that release
fetches the driver from the *.azureedge.net mirrors, which were retired
with the Azure CDN from Edgio and now 404 for every driver version. The
"Playwright version" step swallowed that failure and emitted an empty
version, so the image build failed far from the cause with
"mcr.microsoft.com/playwright:v: not found". v0.6100.0 assembles the
driver from npm and nodejs.org instead, so the download works again.
Also harden the version detection itself: read the pinned CLI version
straight out of playwright-go instead of running the upstream CLI (which
downloads the whole driver just to print a string), and fail the step
loudly when either version comes back empty.
getPlaywrightCIGoFromBuildInfo keeps recognising the old module path so
consumers mid-migration still resolve.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR migrates the project from the archived github.com/playwright-community/playwright-go module path to github.com/mxschmitt/playwright-go at v0.6100.0, addressing Dependabot module path mismatch failures and the retired Azure CDN driver download failures. It also updates CI to determine the Playwright CLI version without invoking the upstream Playwright CLI command.
Changes:
- Bump and migrate Playwright Go dependency/imports to
github.com/mxschmitt/playwright-go v0.6100.0. - Add a small helper (
internal/cmd/playwrightversion) and update workflows to read the pinned Playwright CLI version via Go code. - Harden CI version-detection steps with
set -euo pipefailand explicit empty-value guards.
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates Playwright-Go link to the new upstream module org/path. |
| go.mod | Switches required module to github.com/mxschmitt/playwright-go v0.6100.0. |
| go.sum | Removes old module checksums and adds new ones for mxschmitt/playwright-go. |
| install.go | Migrates import path used by installation logic. |
| browsers.go | Migrates import path for browser API surface. |
| container.go | Updates module detection to prefer mxschmitt path while retaining fallback for legacy consumers. |
| playwrightci_test.go | Updates tests to import the new module path. |
| benchmark_test.go | Updates benchmarks to import the new module path. |
| examples/example_test.go | Updates examples to import the new module path. |
| internal/cmd/playwrightversion/main.go | New helper to print the pinned Playwright CLI version without running upstream CLI. |
| .github/workflows/ci.yml | Uses helper + strict shell settings to reliably compute Playwright versions. |
| .github/workflows/main.yml | Same Playwright version computation for release/tag pipeline. |
| .github/workflows/pr.yml | Updates Dependabot/Playwright-Go conditional checks to match the new module path. |
| CLAUDE.md | Updates documentation reference to the new Playwright-Go module path. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| - name: Playwright version | ||
| id: playwright | ||
| run: | | ||
| export PLAYWRIGHT_GO_VERSION=$(go list -m all | grep github.com/playwright-community/playwright-go | awk '{print $2}') | ||
| set -euo pipefail | ||
| PLAYWRIGHT_GO_VERSION=$(go list -m -f '{{.Version}}' github.com/mxschmitt/playwright-go) |
Playwright 1.61 hardened its WebSocket server: WSServer.listen now does
`hostname ??= "localhost"`, where 1.57 passed the hostname straight
through to net.Server.listen and so bound every interface by default.
Inside the browser container that means launchServer only listens on
loopback, and Docker's published port has nothing to forward to. The
symptom is two steps removed from the cause:
could not get chromium port: timeout, could not connect to browser
container: could not connect to http://localhost:32772
and then, once a second exec tries to start the same browser while the
first unreachable server is still holding the port:
Error: listen EADDRINUSE: address already in use ::1:1027
Pass host: '0.0.0.0' explicitly so the bind no longer depends on an
upstream default.
WebKit's rendering changed between Playwright 1.57.0 and 1.61.1, so
refresh its reference screenshot the same way the Dependabot workflow
would have: both failed captures were byte-identical before promoting.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The image tag was reverse-engineered from the Playwright CLI version, on
the convention that playwright-go tags v0.{minor}{patch}.{n} for CLI
1.{minor}.{patch}. That held for 13 consecutive releases and then broke:
v0.6100.0 ships CLI 1.61.1, which the convention would have written as
v0.6101.0. We publish images for the v0.6100 line, so the derived tag
now names an image that does not exist.
Read the versions the Go toolchain already recorded instead. A consumer's
own pinned playwright-ci-go version *is* the image tag; failing that, the
playwright-go module version gives the release line exactly, with no
convention to reverse-engineer.
That path only works because getPlaywrightCIGoFromBuildInfo was broken:
`if info, ok := debug.ReadBuildInfo(); !ok` ran the lookup only when
build info was absent, so it always reported failure — and would have
dereferenced a nil *BuildInfo if it ever had entered. Test_BuildInfoPath
asserted the broken result, which is why it went unnoticed. With it
fixed, go list is a fallback for developing in this repository rather
than the only working strategy.
Since neither strategy guesses, there is nothing sensible left to guess
with, so an unresolvable tag is now an error naming WithRepository
instead of a docker pull for a tag that never existed. The v0.5101.0
workaround goes with the formula that needed it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Golang test coverage difference reportCoverage increased by Package report |
The tag job runs go list and go run straight after checkout, with no
actions/setup-go step, so it uses whatever Go the runner image happens
to ship. That is older than the go directive in our go.mod today: the
last successful release run logged
go: downloading go1.25.0 (linux/amd64)
meaning the job silently depended on toolchain auto-download to work at
all. That only holds while GOTOOLCHAIN stays at its default, and it
tracks a runner image default that moves without notice.
Pin it the way ci.yml already does. setup-go also sets GOTOOLCHAIN=local,
so the resolved version becomes authoritative instead of a starting
point for a download.
Reported by Copilot on #228.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 19 out of 21 changed files in this pull request and generated no new comments.
Suppressed comments (2)
imagetag_test.go:111
- Same issue here: the parallel subtest closes over the reused range variable
test, which can cause cases to mix whent.Parallel()runs them concurrently. Shadowtest := testinside the loop.
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
got, ok := versionFromBuildInfo(test.info, true)
assert.Equal(t, test.ok, ok)
assert.Equal(t, test.want, got)
})
imagetag_test.go:36
- The subtest captures the range variable
testwhile callingt.Parallel(). In Go, the range variable is reused, so parallel subtests can read the wrong case values and become flaky. Shadow the loop variable inside the loop before starting the subtest.
This issue also appears on line 104 of the same file.
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
t.Parallel()
got, ok := playwrightGoTagLine(test.version)
assert.Equal(t, test.ok, ok)
assert.Equal(t, test.want, got)
})
Root cause
Dependabot's weekly run and every PR's CI were failing for the same underlying reason: we were pinned to a
playwright-gorelease published under a module path that no longer exists.1. Dependabot aborts every gomod run (failing run)
The
playwright-communityGitHub org is archived; playwright-go moved back togithub.com/mxschmitt/playwright-go(upstream #619).v0.6100.0is the first release under the new path, and itsgo.moddeclares that path. Resolving it through the old path fails:Dependabot surfaces this as
go_module_path_mismatchand exits non-zero for the whole run, not just for playwright-go — which is why the run was red every week even though the goproxy and testcontainers PRs were created fine. Upstream tracks the same symptom in #624.Note that GitHub's repo redirect does still work, and every release up to
v0.6000.0still resolves through the old path. A redirect can't help here: Go verifies themoduleline inside the downloadedgo.mod, which is exactly what stops a redirect from silently substituting a different module.2. Every PR's CI fails
Staying on
v0.5700.1had an independent consequence. That release downloads the driver from the*.azureedge.netmirrors, retired along with the Azure CDN from Edgio, which now 404 for every driver version:The
Playwright versionstep obtained the version by running the upstream CLI, which downloads that driver first. Because the failing command sat insideecho "version="$(...), its exit status was discarded and the step wrote an empty version, surfacing two steps later as an unrelated-looking error:v0.6100.0assembles the driver from npm + nodejs.org instead of the dead CDN (upstream #615), so the migration fixes this too.Two follow-on breakages the upgrade exposed
Moving to Playwright 1.61.1 surfaced two more problems, both fixed here.
Browser servers became unreachable. Playwright 1.61 hardened
WSServer.listenwithhostname ??= "localhost"; 1.57 passed the hostname through tonet.Server.listen, which binds all interfaces. Inside the container that meanslaunchServerlistens only on loopback and Docker's published port has nothing to forward to. It showed up twice removed from the cause — firstcould not get chromium port: timeout ... could not connect to http://localhost:32772, thenlisten EADDRINUSE: address already in use ::1:1027once a second exec tried to start the same browser while the first unreachable server still held the port. Fixed by passinghost: '0.0.0.0'explicitly, so the bind no longer depends on an upstream default.The image tag no longer resolved. The tag was reverse-engineered from the Playwright CLI version, assuming playwright-go tags
v0.{minor}{patch}.{n}for CLI1.{minor}.{patch}. That held for 13 consecutive releases and then broke:v0.6100.0ships CLI 1.61.1, which the convention would have written asv0.6101.0. We publish images for thev0.6100line, so the derived tag names an image that does not exist.Replaced with versions the Go toolchain already recorded — a consumer's own pinned playwright-ci-go version is the image tag, and failing that, playwright-go's module version gives the release line exactly. No convention to reverse-engineer.
That path only worked once a latent bug was fixed:
getPlaywrightCIGoFromBuildInforeadif info, ok := debug.ReadBuildInfo(); !ok, running the lookup only when build info was absent — so it always reported failure, and would have dereferenced a nil*BuildInfohad it ever entered.Test_BuildInfoPathasserted the broken result, which is why it went unnoticed;go listwas silently carrying the whole feature. With it fixed,go listis a fallback for in-repo development rather than the only working strategy.Since neither strategy guesses, an unresolvable tag is now an error naming
WithRepositoryrather than adocker pullfor a tag that never existed.Changes
github.com/mxschmitt/playwright-go, bumped tov0.6100.0(Playwright CLI 1.57.0 → 1.61.1). The archived path is still recognised when resolving versions, so consumers mid-migration keep working.internal/cmd/playwrightversionhelper instead of running the upstream CLI, so a metadata lookup no longer needs a CDN. Plusset -euo pipefailand an empty-value guard in the version step ofci.ymlandmain.yml.host: '0.0.0.0'onlaunchServerinchromium.js/firefox.js/webkit.js.v0.5101.0workaround that went with it.testdata/screenshot-webkit.pngfor WebKit's rendering changes, following the same procedure the Dependabot workflow uses (both failed captures were byte-identical before promoting).No Dependabot
ignorerule is needed: once the old path is gone fromgo.mod, there is nothing left that fails to resolve.Verification
Run locally against a Docker image built from this branch (
PLAYWRIGHT_VERSION=1.61.1):Test_HelloWorldandTest_OverlapLifecycleon chromium and webkit.examplesgreen with noPLAYWRIGHTCI_*overrides, which exercises tag resolution end to end: it resolvedv0.6100.0on its own and pulled the matching image.v0.6100.0on a machine where every azureedge mirror 404s — succeeds in ~7s.go build ./...,go vet ./...,gofmt -l .,golangci-lint run— all clean.playwright-core1.57.0 and 1.61.1 packages and all 14 playwright-go releases, not inferred from the symptom.🤖 Generated with Claude Code