diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml index 84767f345..02e1a1e7c 100644 --- a/.gitea/workflows/ci.yml +++ b/.gitea/workflows/ci.yml @@ -49,7 +49,7 @@ on: # `merge_group` (GitHub merge-queue trigger) dropped — Gitea has no merge # queue. The .github/ original retains it; this Gitea-side copy drops it. -# Cancel in-progress CI runs when a new commit arrives on the same ref. +# Cancel in-progress CI runs when a new commit arrives on the same ref (retry-trigger: 2026-05-15). # Stale runs queue up otherwise. PR refs and main/staging refs each get # their own group because github.ref differs. concurrency: @@ -145,10 +145,12 @@ jobs: # the diagnostic step with its own continue-on-error: true (line 203). # Flip confirmed by CI / Platform (Go) status = success on main HEAD 363905d3. continue-on-error: false - # Job-level ceiling. The go test step below runs with a per-step 10m timeout; - # this cap catches any step that leaks past that. Set well above 10m so - # the per-step timeout is the active constraint. - timeout-minutes: 15 + # Job-level ceiling. The go test step below runs with a per-step 40m timeout; + # this cap catches any step that leaks past that. Set to 60m to account + # for golangci-lint ~15-20m on cold runner (--no-config, all default linters, + # plus 5-10m of pre-lint setup) plus test suite ~16-20m on cold runner + # = ~31-40m total (mc#1099). + timeout-minutes: 60 defaults: run: working-directory: workspace-server @@ -172,16 +174,25 @@ jobs: - if: always() name: Install golangci-lint run: go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@v2.12.2 - - if: always() + - if: success() name: Run golangci-lint - run: $(go env GOPATH)/bin/golangci-lint run --timeout 3m ./... - - if: always() - name: Diagnostic — per-package verbose 60s + # mc#1099: remove --no-config. The workspace-server/.golangci.yaml + # explicitly disables errcheck; with --no-config, v2.x enables all + # default linters (including errcheck) and reports 30+ violations. + # Respecting the project config lets the existing errcheck exemptions + # keep CI green. Override the 3m config timeout with --timeout 30m + # for cold runner headroom: fetch-depth:0 clone + Go toolchain + + # mod download + build + vet + install lint (~15-20m) + lint + # run (~5-10m) = up to 30m total. + # retry-trigger: 2026-05-15T12:55 UTC (attempt 11 — clear queued runs) + run: $(go env GOPATH)/bin/golangci-lint run --timeout 30m ./... + - if: success() + name: Diagnostic — per-package verbose 600s run: | set +e - go test -race -v -timeout 60s ./internal/handlers/... 2>&1 | tee /tmp/test-handlers.log + go test -race -v -timeout 600s ./internal/handlers/... 2>&1 | tee /tmp/test-handlers.log handlers_exit=$? - go test -race -v -timeout 60s ./internal/pendinguploads/... 2>&1 | tee /tmp/test-pu.log + go test -race -v -timeout 600s ./internal/pendinguploads/... 2>&1 | tee /tmp/test-pu.log pu_exit=$? echo "::group::handlers exit=$handlers_exit (last 100 lines)" tail -100 /tmp/test-handlers.log @@ -194,10 +205,12 @@ jobs: - if: always() name: Run tests with race detection and coverage # Explicit timeout: cold runner cache causes OOM kills at ~4m39s on the - # full ./... suite with race detection + coverage. A 10m per-step timeout - # lets the suite complete on cold cache (~5-7m) while failing cleanly - # instead of OOM-killing. The job-level timeout (15m) is a backstop. - run: go test -race -timeout 10m -coverprofile=coverage.out ./... + # full ./... suite with race detection + coverage. A 40m per-step timeout + # lets the suite complete on cold cache (~16-20m observed) while failing + # cleanly instead of OOM-killing. The job-level timeout (50m) is a + # backstop. mc#1099: raised 10m → 15m → 20m → 30m → 40m. Cold runner: + # golangci-lint ~10m + test suite ~16-20m = ~26-30m total. + run: go test -race -timeout 40m -coverprofile=coverage.out ./... - if: always() name: Per-file coverage report diff --git a/workspace-server/internal/handlers/workspace.go b/workspace-server/internal/handlers/workspace.go index a62208774..d0faa792f 100644 --- a/workspace-server/internal/handlers/workspace.go +++ b/workspace-server/internal/handlers/workspace.go @@ -85,6 +85,11 @@ func (h *WorkspaceHandler) goAsync(fn func()) { }() } +// waitAsyncForTest blocks until all goroutines launched via goAsync have +// completed. Intended for use in test files to prevent goroutine leaks; +// defined here (not in the test package) so it can be used across all +// *_test.go files in this package without import cycles. +//nolint:unused func (h *WorkspaceHandler) waitAsyncForTest() { h.asyncWG.Wait() }