Resolve the site's /1/ links against the release the source builds until it is published
Getting started lists every file the source release ships, each linked through /1/, and the site's link check resolved /1/ against the newest published release only. So any file added to the source was a 404 from the day it was added until the release that carries it was cut: copy.js turned the check red on every Getting started page, 36 lines, though the site goes out with that release and will serve it. While the source is ahead of releases/ (no releases/<Version>/, or one holding other files than build.Dist builds now), the check now serves the source's build beside the published releases and points the /M/ rewrite at it, as the edge will once the release is cut. Once releases/ holds what the source builds, /1/ resolves against the newest published release as before. Today Version is still 1.0.0 and releases/1.0.0/ exists, so "no releases/<Version>/" alone would not have covered it; the files are compared too. The build sits under <Version>/ when that is free and under unreleased/ when Version is published already, so a pinned /<Version>/ link still reaches the bytes that version shipped. Rejected: listing unreleased files on Getting started without a link (a design change to the page), and leaving the check red until the release (every task in between would run red). The check was red on today's tree first: 36 lines, each "getting-started.html: a href https://fiesta.rastrillo.org/1/copy.js resolves to /1/copy.js, which the edge answers with a 404". Green with the change, and on 95bd8cc, before copy.js, the source equals releases/1.0.0/ and /1/ resolves against it as before. A new control, red by name under each mutation: a scratch page links /1/fiesta.css (published), /1/copy.js (only in the source build) and /1/missing.js (in neither). Against 1.0.0 the last two fail; served as the release to come, under the same version or a new one, only /1/missing.js does. unpublished is false for a release equal to the source build (its stamp aside), true with one file changed and true with no directory. Mutations: servingSource adding nothing, any /1/ link accepted, unpublished always false, unpublished always true; each turns the control red. The ship-time guard, refusing to ship unless releases/<Version>/ exists, is not here; it goes with shipping.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 file changed,
+160
−2
internal/www/links_test.go+160 −2
CI failed — run details
CI log
=== gofmt ===
=== no-rastrillo ===
go test -run '^(TestFiestaNeverImportsRastrillo|TestThePublicPackagesLinkNoBrowser)$' -count=1 .
ok amadan.net/rastrillo/fiesta 0.147s
=== size ===
go test ./internal/build -run '^TestTheOneLinkIsUnder25KiBGzipped$' -count=1 -v
=== RUN TestTheOneLinkIsUnder25KiBGzipped
build_test.go:138: fiesta-plain.css: 152856 bytes, 22303 bytes gzipped (21.8 KiB of the 25.0 KiB limit)
build_test.go:138: fiesta-signal.css: 152951 bytes, 22414 bytes gzipped (21.9 KiB of the 25.0 KiB limit)
build_test.go:138: fiesta.css: 155770 bytes, 23018 bytes gzipped (22.5 KiB of the 25.0 KiB limit)
--- PASS: TestTheOneLinkIsUnder25KiBGzipped (0.02s)
PASS
ok amadan.net/rastrillo/fiesta/internal/build 0.024s
=== history ===
history: 11 commits; release tags: v1.0.0
=== suite ===
--- shard 0 of 48 ---
==> shard 0 of 48: make root
go build ./...
go vet ./...
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh root 'internal/gallery@3 cmd/fiesta@2 internal/www@2'
ok amadan.net/rastrillo/fiesta 2.886s
ok amadan.net/rastrillo/fiesta/check 5.327s
ok amadan.net/rastrillo/fiesta/example 0.097s
? amadan.net/rastrillo/fiesta/hack/seed/english [no test files]
ok amadan.net/rastrillo/fiesta/internal/axe 0.122s
ok amadan.net/rastrillo/fiesta/internal/build 1.040s
ok amadan.net/rastrillo/fiesta/internal/codeview 0.004s
? amadan.net/rastrillo/fiesta/internal/harness [no test files]
ok amadan.net/rastrillo/fiesta/internal/markup 0.009s
ok amadan.net/rastrillo/fiesta/internal/nodetest 0.355s
ok amadan.net/rastrillo/fiesta/internal/site 3.290s
ok amadan.net/rastrillo/fiesta/internal/tokens 0.011s
suite: root took 13s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m10.240000s 0m2.040000s
--- shard 1 of 48 ---
==> shard 1 of 48: make test.internal.gallery~1of3
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.gallery~1of3'
gotest: slice 1 of 3 of ./internal/gallery/ runs 35 of 105 test tests
ok amadan.net/rastrillo/fiesta/internal/gallery 62.450s
suite: test.internal.gallery~1of3 took 68s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m48.480000s 0m1.210000s
--- shard 2 of 48 ---
==> shard 2 of 48: make test.internal.gallery~2of3
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.gallery~2of3'
gotest: slice 2 of 3 of ./internal/gallery/ runs 35 of 105 test tests
ok amadan.net/rastrillo/fiesta/internal/gallery 61.284s
suite: test.internal.gallery~2of3 took 67s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m46.470000s 0m1.290000s
--- shard 3 of 48 ---
==> shard 3 of 48: make test.internal.gallery~3of3
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.gallery~3of3'
gotest: slice 3 of 3 of ./internal/gallery/ runs 35 of 105 test tests
ok amadan.net/rastrillo/fiesta/internal/gallery 58.210s
suite: test.internal.gallery~3of3 took 64s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m44.080000s 0m1.270000s
--- shard 4 of 48 ---
==> shard 4 of 48: make test.cmd.fiesta~1of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'cmd.fiesta~1of2'
gotest: slice 1 of 2 of ./cmd/fiesta/ runs 7 of 12 test tests
ok amadan.net/rastrillo/fiesta/cmd/fiesta 48.368s
suite: test.cmd.fiesta~1of2 took 52s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m32.700000s 0m2.100000s
--- shard 5 of 48 ---
==> shard 5 of 48: make test.cmd.fiesta~2of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'cmd.fiesta~2of2'
gotest: slice 2 of 2 of ./cmd/fiesta/ runs 5 of 12 test tests
ok amadan.net/rastrillo/fiesta/cmd/fiesta 51.778s
suite: test.cmd.fiesta~2of2 took 56s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m35.060000s 0m2.340000s
--- shard 6 of 48 ---
==> shard 6 of 48: make test.internal.www~1of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.www~1of2'
gotest: slice 1 of 2 of ./internal/www/ runs 11 of 25 test tests
ok amadan.net/rastrillo/fiesta/internal/www 63.201s
suite: test.internal.www~1of2 took 68s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m46.460000s 0m1.670000s
--- shard 7 of 48 ---
==> shard 7 of 48: make test.internal.www~2of2
FIESTA_TEST_REQUIRE_NODE=1 FIESTA_TEST_REQUIRE_GIT=1 FIESTA_TEST_REQUIRE_TAGS=1 ./hack/gotest.sh test 'internal.www~2of2'
gotest: slice 2 of 2 of ./internal/www/ runs 14 of 25 test tests
ok amadan.net/rastrillo/fiesta/internal/www 59.924s
suite: test.internal.www~2of2 took 65s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m44.570000s 0m1.690000s
--- shard 8 of 48 ---
==> shard 8 of 48: make staticcheck
go run honnef.co/go/tools/cmd/staticcheck@v0.8.2 -tags browser ./...
suite: staticcheck took 12s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m15.010000s 0m1.000000s
--- shard 9 of 48 ---
==> shard 9 of 48: make govulncheck
go run golang.org/x/vuln/cmd/govulncheck@v1.8.0 ./...
=== Symbol Results ===
No vulnerabilities found.
Your code is affected by 0 vulnerabilities.
This scan also found 2 vulnerabilities in packages you import and 5
vulnerabilities in modules you require, but your code doesn't appear to call
these vulnerabilities.
Use '-show verbose' for more details.
suite: govulncheck took 8s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m3.080000s 0m0.330000s
--- shard 10 of 48 ---
==> shard 10 of 48: make gitleaks
go run github.com/zricethezav/gitleaks/v8@v8.30.1 git --no-banner --redact --log-opts='--full-history --diff-filter=tuxdb HEAD' .
[90m12:16AM[0m [32mINF[0m [1mUnknown SCM platform. Use --platform to include links in findings.[0m [36mhost=[0mamadan.net
[90m12:16AM[0m [32mINF[0m [1m11 commits scanned.[0m
[90m12:16AM[0m [32mINF[0m [1mscanned ~8173605 bytes (8.17 MB) in 6.62s[0m
[90m12:16AM[0m [32mINF[0m [1mno leaks found[0m
suite: gitleaks took 7s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m6.860000s 0m0.160000s
--- shard 11 of 48 ---
==> shard 11 of 48: make browser.internal.harness
./hack/gotest.sh browser 'internal.harness'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: ./internal/harness/ runs its 10 browser tests
ok amadan.net/rastrillo/fiesta/internal/harness 6.632s
suite: browser.internal.harness took 10s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m1.750000s 0m1.240000s
--- shard 12 of 48 ---
==> shard 12 of 48: make browser.check~1of13
./hack/gotest.sh browser 'check~1of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 1 of 13 of ./check/ runs 14 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 80.255s
suite: browser.check~1of13 took 90s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m42.460000s 0m13.340000s
--- shard 13 of 48 ---
==> shard 13 of 48: make browser.check~2of13
./hack/gotest.sh browser 'check~2of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 2 of 13 of ./check/ runs 15 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 80.738s
suite: browser.check~2of13 took 91s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m42.610000s 0m13.400000s
--- shard 14 of 48 ---
==> shard 14 of 48: make browser.check~3of13
./hack/gotest.sh browser 'check~3of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 3 of 13 of ./check/ runs 15 of 204 browser tests
--- FAIL: TestEveryOneOhExampleRendersAsItDid2of4 (300.63s)
oneoh_browser_test.go:318: context deadline exceeded
FAIL
FAIL amadan.net/rastrillo/fiesta/check 325.966s
FAIL
make[1]: *** [Makefile:234: browser.check~3of13] Error 1
suite: browser.check~3of13 took 336s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m34.040000s 0m11.280000s
make: *** [Makefile:76: suite] Error 2
amadan: step suite shard 14 of 48 failed: exit status 2
--- shard 15 of 48 ---
==> shard 15 of 48: make browser.check~4of13
./hack/gotest.sh browser 'check~4of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 4 of 13 of ./check/ runs 15 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 81.922s
suite: browser.check~4of13 took 92s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m45.510000s 0m15.440000s
--- shard 16 of 48 ---
==> shard 16 of 48: make browser.check~5of13
./hack/gotest.sh browser 'check~5of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 5 of 13 of ./check/ runs 15 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 82.601s
suite: browser.check~5of13 took 92s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m44.230000s 0m12.000000s
--- shard 17 of 48 ---
==> shard 17 of 48: make browser.check~6of13
./hack/gotest.sh browser 'check~6of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 6 of 13 of ./check/ runs 16 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 85.155s
suite: browser.check~6of13 took 95s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m41.690000s 0m13.320000s
--- shard 18 of 48 ---
==> shard 18 of 48: make browser.check~7of13
./hack/gotest.sh browser 'check~7of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 7 of 13 of ./check/ runs 16 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 84.934s
suite: browser.check~7of13 took 95s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m47.680000s 0m12.160000s
--- shard 19 of 48 ---
==> shard 19 of 48: make browser.check~8of13
./hack/gotest.sh browser 'check~8of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 8 of 13 of ./check/ runs 16 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 80.423s
suite: browser.check~8of13 took 91s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m36.310000s 0m13.190000s
--- shard 20 of 48 ---
==> shard 20 of 48: make browser.check~9of13
./hack/gotest.sh browser 'check~9of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 9 of 13 of ./check/ runs 16 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 83.473s
suite: browser.check~9of13 took 93s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m40.110000s 0m13.350000s
--- shard 21 of 48 ---
==> shard 21 of 48: make browser.check~10of13
./hack/gotest.sh browser 'check~10of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 10 of 13 of ./check/ runs 16 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 89.319s
suite: browser.check~10of13 took 99s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m51.820000s 0m11.710000s
--- shard 22 of 48 ---
==> shard 22 of 48: make browser.check~11of13
./hack/gotest.sh browser 'check~11of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 11 of 13 of ./check/ runs 16 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 83.427s
suite: browser.check~11of13 took 94s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m46.560000s 0m17.230000s
--- shard 23 of 48 ---
==> shard 23 of 48: make browser.check~12of13
./hack/gotest.sh browser 'check~12of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 12 of 13 of ./check/ runs 17 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 78.788s
suite: browser.check~12of13 took 89s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m31.970000s 0m10.210000s
--- shard 24 of 48 ---
==> shard 24 of 48: make browser.check~13of13
./hack/gotest.sh browser 'check~13of13'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: slice 13 of 13 of ./check/ runs 17 of 204 browser tests
ok amadan.net/rastrillo/fiesta/check 79.104s
suite: browser.check~13of13 took 89s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m29.100000s 0m9.800000s
--- shard 25 of 48 ---
==> shard 25 of 48: make browser.internal.gallery~1of18
./hack/gotest.sh browser 'internal.gallery~1of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 1 of 18 of ./internal/gallery/ runs 6 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 32.438s
suite: browser.internal.gallery~1of18 took 42s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m14.410000s 0m2.950000s
--- shard 26 of 48 ---
==> shard 26 of 48: make browser.internal.gallery~2of18
./hack/gotest.sh browser 'internal.gallery~2of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 2 of 18 of ./internal/gallery/ runs 6 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 49.740s
suite: browser.internal.gallery~2of18 took 58s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m15.630000s 0m3.740000s
--- shard 27 of 48 ---
==> shard 27 of 48: make browser.internal.gallery~3of18
./hack/gotest.sh browser 'internal.gallery~3of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 3 of 18 of ./internal/gallery/ runs 6 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 59.176s
suite: browser.internal.gallery~3of18 took 68s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m15.970000s 0m4.200000s
--- shard 28 of 48 ---
==> shard 28 of 48: make browser.internal.gallery~4of18
./hack/gotest.sh browser 'internal.gallery~4of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 4 of 18 of ./internal/gallery/ runs 6 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 58.921s
suite: browser.internal.gallery~4of18 took 68s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m18.920000s 0m5.590000s
--- shard 29 of 48 ---
==> shard 29 of 48: make browser.internal.gallery~5of18
./hack/gotest.sh browser 'internal.gallery~5of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 5 of 18 of ./internal/gallery/ runs 6 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 60.772s
suite: browser.internal.gallery~5of18 took 70s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m16.800000s 0m4.610000s
--- shard 30 of 48 ---
==> shard 30 of 48: make browser.internal.gallery~6of18
./hack/gotest.sh browser 'internal.gallery~6of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 6 of 18 of ./internal/gallery/ runs 6 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 55.050s
suite: browser.internal.gallery~6of18 took 64s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m15.390000s 0m3.840000s
--- shard 31 of 48 ---
==> shard 31 of 48: make browser.internal.gallery~7of18
./hack/gotest.sh browser 'internal.gallery~7of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 7 of 18 of ./internal/gallery/ runs 5 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 55.344s
suite: browser.internal.gallery~7of18 took 64s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m13.830000s 0m2.830000s
--- shard 32 of 48 ---
==> shard 32 of 48: make browser.internal.gallery~8of18
./hack/gotest.sh browser 'internal.gallery~8of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 8 of 18 of ./internal/gallery/ runs 5 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 57.765s
suite: browser.internal.gallery~8of18 took 67s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m18.210000s 0m5.240000s
--- shard 33 of 48 ---
==> shard 33 of 48: make browser.internal.gallery~9of18
./hack/gotest.sh browser 'internal.gallery~9of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 9 of 18 of ./internal/gallery/ runs 5 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 64.422s
suite: browser.internal.gallery~9of18 took 73s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m22.240000s 0m7.010000s
--- shard 34 of 48 ---
==> shard 34 of 48: make browser.internal.gallery~10of18
./hack/gotest.sh browser 'internal.gallery~10of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 10 of 18 of ./internal/gallery/ runs 2 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 61.289s
suite: browser.internal.gallery~10of18 took 70s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m14.000000s 0m2.700000s
--- shard 35 of 48 ---
==> shard 35 of 48: make browser.internal.gallery~11of18
./hack/gotest.sh browser 'internal.gallery~11of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 11 of 18 of ./internal/gallery/ runs 2 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 62.708s
suite: browser.internal.gallery~11of18 took 72s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m13.930000s 0m2.660000s
--- shard 36 of 48 ---
==> shard 36 of 48: make browser.internal.gallery~12of18
./hack/gotest.sh browser 'internal.gallery~12of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 12 of 18 of ./internal/gallery/ runs 2 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 63.006s
suite: browser.internal.gallery~12of18 took 72s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m18.320000s 0m4.800000s
--- shard 37 of 48 ---
==> shard 37 of 48: make browser.internal.gallery~13of18
./hack/gotest.sh browser 'internal.gallery~13of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 13 of 18 of ./internal/gallery/ runs 3 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 64.557s
suite: browser.internal.gallery~13of18 took 74s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m19.200000s 0m5.200000s
--- shard 38 of 48 ---
==> shard 38 of 48: make browser.internal.gallery~14of18
./hack/gotest.sh browser 'internal.gallery~14of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 14 of 18 of ./internal/gallery/ runs 4 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 66.627s
suite: browser.internal.gallery~14of18 took 76s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m19.300000s 0m5.330000s
--- shard 39 of 48 ---
==> shard 39 of 48: make browser.internal.gallery~15of18
./hack/gotest.sh browser 'internal.gallery~15of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 15 of 18 of ./internal/gallery/ runs 4 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 65.001s
suite: browser.internal.gallery~15of18 took 74s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m19.440000s 0m5.570000s
--- shard 40 of 48 ---
==> shard 40 of 48: make browser.internal.gallery~16of18
./hack/gotest.sh browser 'internal.gallery~16of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 16 of 18 of ./internal/gallery/ runs 5 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 63.045s
suite: browser.internal.gallery~16of18 took 72s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m16.230000s 0m4.090000s
--- shard 41 of 48 ---
==> shard 41 of 48: make browser.internal.gallery~17of18
./hack/gotest.sh browser 'internal.gallery~17of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 17 of 18 of ./internal/gallery/ runs 5 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 66.697s
suite: browser.internal.gallery~17of18 took 76s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m19.880000s 0m5.880000s
--- shard 42 of 48 ---
==> shard 42 of 48: make browser.internal.gallery~18of18
./hack/gotest.sh browser 'internal.gallery~18of18'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 18 of 18 of ./internal/gallery/ runs 5 of 83 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery 67.051s
suite: browser.internal.gallery~18of18 took 76s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m19.160000s 0m5.450000s
--- shard 43 of 48 ---
==> shard 43 of 48: make browser.internal.gallery.history
./hack/gotest.sh browser 'internal.gallery.history'
gotest: on ip-172-31-19-71, driving /opt/amadan-browser/chromium-1234/chrome-linux/chrome
gotest: ./internal/gallery/history/ runs its 3 browser tests
ok amadan.net/rastrillo/fiesta/internal/gallery/history 32.414s
suite: browser.internal.gallery.history took 38s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m21.340000s 0m2.140000s
--- shard 44 of 48 ---
==> shard 44 of 48: make browser.internal.www~1of4
./hack/gotest.sh browser 'internal.www~1of4'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 1 of 4 of ./internal/www/ runs 4 of 22 browser tests
ok amadan.net/rastrillo/fiesta/internal/www 69.872s
suite: browser.internal.www~1of4 took 78s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m31.240000s 0m2.130000s
--- shard 45 of 48 ---
==> shard 45 of 48: make browser.internal.www~2of4
./hack/gotest.sh browser 'internal.www~2of4'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 2 of 4 of ./internal/www/ runs 6 of 22 browser tests
ok amadan.net/rastrillo/fiesta/internal/www 66.949s
suite: browser.internal.www~2of4 took 75s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m45.700000s 0m2.680000s
--- shard 46 of 48 ---
==> shard 46 of 48: make browser.internal.www~3of4
./hack/gotest.sh browser 'internal.www~3of4'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 3 of 4 of ./internal/www/ runs 6 of 22 browser tests
ok amadan.net/rastrillo/fiesta/internal/www 81.140s
suite: browser.internal.www~3of4 took 89s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m51.910000s 0m3.020000s
--- shard 47 of 48 ---
==> shard 47 of 48: make browser.internal.www~4of4
./hack/gotest.sh browser 'internal.www~4of4'
gotest: on ip-172-31-19-71, driving the harness's own choice (/usr/local/bin/chromium)
gotest: slice 4 of 4 of ./internal/www/ runs 6 of 22 browser tests
ok amadan.net/rastrillo/fiesta/internal/www 77.186s
suite: browser.internal.www~4of4 took 85s; CPU, user then system, of this shell and then of the role:
0m0.000000s 0m0.000000s
0m46.000000s 0m2.990000s
amadan: job failed at step suite shard 14 of 48 — its output is above, not at the tail of this log
Intent
diff --git a/internal/www/links_test.go b/internal/www/links_test.go| index 98466d8..e82d648 100644 |
| --- a/internal/www/links_test.go |
| +++ b/internal/www/links_test.go |
| @@ -1,17 +1,26 @@ |
| package www_test |
| import ( |
| + "bytes" |
| "fmt" |
| + "io/fs" |
| + "maps" |
| "net/http" |
| "net/http/httptest" |
| "net/url" |
| + "os" |
| "regexp" |
| + "slices" |
| "sort" |
| "strings" |
| "testing" |
| + "testing/fstest" |
| xhtml "golang.org/x/net/html" |
| + "amadan.net/rastrillo/fiesta" |
| + "amadan.net/rastrillo/fiesta/internal/build" |
| + "amadan.net/rastrillo/fiesta/internal/site" |
| "amadan.net/rastrillo/fiesta/internal/www" |
| ) |
| @@ -198,6 +207,66 @@ func linkProblems(t *testing.T, tree map[string][]byte) (problems []string, page |
| return problems, pages |
| } |
| +// unpublished reports whether the source is ahead of releases/: there |
| +// is no releases/<version>/, or it holds other files than dist, the |
| +// release the source builds. That is the stretch between a change to |
| +// the source and the release that carries it, and the stretch the |
| +// design system's pages spend linking files of the release to come. |
| +func unpublished(releases fs.FS, version string, dist map[string][]byte) (bool, error) { |
| + if _, err := fs.Stat(releases, version); err != nil { |
| + return true, nil |
| + } |
| + dir, err := fs.Sub(releases, version) |
| + if err != nil { |
| + return false, err |
| + } |
| + published, err := site.Release(dir) |
| + if err != nil { |
| + return false, err |
| + } |
| + return !maps.EqualFunc(published, dist, bytes.Equal), nil |
| +} |
| + |
| +// servingSource is tree as the edge will serve it once dist is |
| +// released: dist sits beside the published releases, and the rewrite |
| +// for version's major sends /M/ to it rather than to the newest |
| +// published release. It sits under version/ when that is free, where |
| +// fiesta release will put it, and under unreleased/ when version is |
| +// published already and the source has moved past it, so a pinned |
| +// /version/ link still reaches the bytes that version shipped. |
| +func servingSource(t *testing.T, tree map[string][]byte, version string, dist map[string][]byte) map[string][]byte { |
| + t.Helper() |
| + out := maps.Clone(tree) |
| + dir := version |
| + for name := range tree { |
| + if strings.HasPrefix(name, version+"/") { |
| + dir = "unreleased" |
| + break |
| + } |
| + } |
| + for name, data := range dist { |
| + out[dir+"/"+name] = data |
| + } |
| + major, _, _ := strings.Cut(version, ".") |
| + prefix := "/" + major + "/* " |
| + rule := prefix + "/" + dir + "/:splat 200" |
| + var lines []string |
| + found := false |
| + for _, line := range strings.Split(strings.TrimSuffix(string(tree["_redirects"]), "\n"), "\n") { |
| + if strings.HasPrefix(line, prefix) { |
| + line, found = rule, true |
| + } |
| + lines = append(lines, line) |
| + } |
| + if !found { |
| + // A new major's first release: its rule goes first, as |
| + // site.Build writes the newest major's. |
| + lines = append([]string{rule}, lines...) |
| + } |
| + out["_redirects"] = []byte(strings.Join(lines, "\n") + "\n") |
| + return out |
| +} |
| + |
| // TestEveryLinkInTheSiteResolves: on every page of the built site, |
| // the landing page in each language, the design system's index, every |
| // example page and every frame, every href, src and srcset reaches a |
| @@ -208,10 +277,20 @@ func linkProblems(t *testing.T, tree map[string][]byte) (problems []string, page |
| // is held to the same rule as the hreflang links: the site's own, |
| // through the rewrite to the newest release. |
| // |
| +// While the source is unpublished (see unpublished), /1/ is resolved |
| +// against the release the source builds, not the newest published one: |
| +// the design system lists every file the source ships, linked through |
| +// /1/, and the site goes out with the release that carries them. Read |
| +// against 1.0.0 alone, every new file is a 404 from the day it is |
| +// added to the day the release is cut. Once releases/ holds what the |
| +// source builds, /1/ resolves against it as the edge will. |
| +// |
| // The control comes first: a scratch site whose one page links a |
| // missing page, a missing fragment, a wrong path under the site's own |
| // origin and an outside URL that is not on the list. The check has to |
| -// name all four, or a clean run of the real site proves nothing. |
| +// name all four, or a clean run of the real site proves nothing. A |
| +// second control holds the unpublished stretch: a file the source |
| +// builds resolves through /1/, and one it does not build still fails. |
| func TestEveryLinkInTheSiteResolves(t *testing.T) { |
| control := map[string][]byte{ |
| "_redirects": []byte("/1/* /1.0.0/:splat 200\n"), |
| @@ -237,11 +316,25 @@ func TestEveryLinkInTheSiteResolves(t *testing.T) { |
| if len(problems) != 4 { |
| t.Errorf("the control has 4 broken links and %d were reported:\n %s", len(problems), strings.Join(problems, "\n ")) |
| } |
| + unpublishedControl(t) |
| if t.Failed() { |
| return |
| } |
| - problems, pages := linkProblems(t, builtSite(t)) |
| + tree := builtSite(t) |
| + dist, err := build.Dist(fiesta.FS(), fiesta.Version) |
| + if err != nil { |
| + t.Fatalf("building the release the source would publish: %v", err) |
| + } |
| + ahead, err := unpublished(os.DirFS("../../releases"), fiesta.Version, dist) |
| + if err != nil { |
| + t.Fatalf("reading releases/%s: %v", fiesta.Version, err) |
| + } |
| + if ahead { |
| + t.Logf("the source is ahead of releases/%s, so /1/ resolves against the release it builds", fiesta.Version) |
| + tree = servingSource(t, tree, fiesta.Version, dist) |
| + } |
| + problems, pages := linkProblems(t, tree) |
| for _, p := range problems { |
| t.Error(p) |
| } |
| @@ -268,3 +361,68 @@ func TestEveryLinkInTheSiteResolves(t *testing.T) { |
| t.Errorf("%d example pages and %d frames were read; the design system has both", examples, frames) |
| } |
| } |
| + |
| +// unpublishedControl is the unpublished stretch on scratch trees. A |
| +// page links /1/fiesta.css, which 1.0.0 has, /1/copy.js, which only |
| +// the source builds, and /1/missing.js, which nothing does. Read |
| +// against 1.0.0 alone the last two fail; served as the release to come |
| +// only the last does. unpublished is held on both sides: a release |
| +// equal to the source build (its stamp aside) is published, one with a |
| +// file changed or none at all is not. |
| +func unpublishedControl(t *testing.T) { |
| + t.Helper() |
| + dist := map[string][]byte{"fiesta.css": []byte("body{}"), "copy.js": []byte("0")} |
| + dist["SHA256SUMS"] = sumsOf(dist) |
| + tree := map[string][]byte{ |
| + "_redirects": []byte("/1/* /1.0.0/:splat 200\n"), |
| + "1.0.0/fiesta.css": []byte("body{}"), |
| + "index.html": []byte(`<main id="main"><link rel="stylesheet" href="/1/fiesta.css">` + |
| + `<script src="/1/copy.js"></script><script src="/1/missing.js"></script></main>`), |
| + } |
| + for _, c := range []struct { |
| + name string |
| + tree map[string][]byte |
| + want []string |
| + }{ |
| + {"against 1.0.0", tree, []string{"/1/copy.js", "/1/missing.js"}}, |
| + {"as the release to come", servingSource(t, tree, "1.0.0", dist), []string{"/1/missing.js"}}, |
| + {"as a new version's release", servingSource(t, tree, "1.1.0", dist), []string{"/1/missing.js"}}, |
| + } { |
| + problems, _ := linkProblems(t, c.tree) |
| + var got []string |
| + for _, p := range problems { |
| + for _, link := range []string{"/1/fiesta.css", "/1/copy.js", "/1/missing.js"} { |
| + if strings.Contains(p, "resolves to "+link+",") { |
| + got = append(got, link) |
| + } |
| + } |
| + } |
| + if len(got) != len(problems) || !slices.Equal(got, c.want) { |
| + t.Errorf("the unpublished control, %s, reported %q; want only %q broken", c.name, problems, c.want) |
| + } |
| + } |
| + |
| + stamp := &fstest.MapFile{Data: []byte("fiesta release\n")} |
| + same := fstest.MapFS{"1.0.0/" + site.StampName: stamp} |
| + changed := fstest.MapFS{"1.0.0/" + site.StampName: stamp} |
| + for name, data := range dist { |
| + same["1.0.0/"+name] = &fstest.MapFile{Data: data} |
| + changed["1.0.0/"+name] = &fstest.MapFile{Data: data} |
| + } |
| + changed["1.0.0/copy.js"] = &fstest.MapFile{Data: []byte("1")} |
| + changed["1.0.0/SHA256SUMS"] = &fstest.MapFile{Data: sumsOf(map[string][]byte{"fiesta.css": dist["fiesta.css"], "copy.js": []byte("1")})} |
| + for _, c := range []struct { |
| + name string |
| + releases fs.FS |
| + want bool |
| + }{ |
| + {"the same files", same, false}, |
| + {"one file changed", changed, true}, |
| + {"no release directory", fstest.MapFS{}, true}, |
| + } { |
| + got, err := unpublished(c.releases, "1.0.0", dist) |
| + if err != nil || got != c.want { |
| + t.Errorf("unpublished with %s = %v, %v; want %v", c.name, got, err, c.want) |
| + } |
| + } |
| +} |