mirror of
https://github.com/go-gitea/gitea.git
synced 2026-05-11 22:15:38 +02:00
ci: combine unit shards (3-way), drop rotation, use make generate-go
Replaces test-unit-nogogit + test-unit-gogit with a single test-unit-shards matrix (3-shard). Each shard runs both the bindata and bindata-gogit test subsets — round-robin partition of GO_TEST_PACKAGES (123 each) and find-gogit-test-pkgs.sh (22-23 each). Combined work split 3 ways gives each shard ~7:46 wall (vs 10:55/7:38 today). PRs no longer write rotated unit caches: build-cache-rotate is dropped, so the shared seeded gobuild key is restored but not re-saved per PR push. Trade-off: cold testcache on every push (vs warm-on-rerun before). Frees ~3 GB of rotated-cache pressure on the 10 GB cap. Unit shards swap `make backend` for `make generate-go` — only the bindata codegen is needed; the gitea executable's link step (~10-15s) is wasted on unit tests since they don't shell out to the binary (db integration tests do — those keep `make backend`). New shared tools/partition-by-shard.sh handles validation + round-robin partitioning; tools/test-integration-shard.sh now uses it. New Makefile targets: test-backend-shard, test-backend-gogit-shard. Co-Authored-By: Claude (Opus 4.7) <noreply@anthropic.com>
This commit is contained in:
parent
28e72633e0
commit
8337e1c5f3
45
.github/workflows/pull-db-tests.yml
vendored
45
.github/workflows/pull-db-tests.yml
vendored
@ -127,10 +127,14 @@ jobs:
|
|||||||
steps:
|
steps:
|
||||||
- run: '[ "${{ needs.test-sqlite-shards.result }}" = "success" ]'
|
- run: '[ "${{ needs.test-sqlite-shards.result }}" = "success" ]'
|
||||||
|
|
||||||
test-unit-nogogit:
|
test-unit-shards:
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
needs: files-changed
|
needs: files-changed
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
shard: [1, 2, 3]
|
||||||
services:
|
services:
|
||||||
elasticsearch:
|
elasticsearch:
|
||||||
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15
|
image: docker.elastic.co/elasticsearch/elasticsearch:8.19.15
|
||||||
@ -175,57 +179,36 @@ jobs:
|
|||||||
- uses: ./.github/actions/go-cache
|
- uses: ./.github/actions/go-cache
|
||||||
with:
|
with:
|
||||||
cache-name: unit
|
cache-name: unit
|
||||||
build-cache-rotate: "true"
|
|
||||||
- name: Add hosts to /etc/hosts
|
- name: Add hosts to /etc/hosts
|
||||||
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
|
run: '[ -e "/.dockerenv" ] || [ -e "/run/.containerenv" ] || echo "127.0.0.1 minio devstoreaccount1.azurite.local mysql elasticsearch meilisearch smtpimap" | sudo tee -a /etc/hosts'
|
||||||
- run: make deps-backend
|
- run: make deps-backend
|
||||||
- run: make backend
|
- run: make generate-go
|
||||||
env:
|
env:
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
- name: unit-tests
|
- name: unit-tests
|
||||||
run: make test-backend test-check
|
run: make test-backend-shard test-check
|
||||||
env:
|
env:
|
||||||
|
TEST_SHARD: ${{ matrix.shard }}
|
||||||
|
TEST_TOTAL_SHARDS: 3
|
||||||
GOTEST_FLAGS: -race -timeout=20m
|
GOTEST_FLAGS: -race -timeout=20m
|
||||||
TAGS: bindata
|
TAGS: bindata
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||||
|
|
||||||
test-unit-gogit:
|
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
|
||||||
needs: files-changed
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
# the gogit-affected package set (modules/git, modules/gitrepo, modules/lfs and
|
|
||||||
# their direct importers) doesn't touch elasticsearch/meilisearch/redis/minio/
|
|
||||||
# azurite — no services needed.
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
||||||
- uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0
|
|
||||||
with:
|
|
||||||
go-version-file: go.mod
|
|
||||||
check-latest: true
|
|
||||||
cache: false
|
|
||||||
- uses: ./.github/actions/go-cache
|
|
||||||
with:
|
|
||||||
cache-name: unit-gogit
|
|
||||||
build-cache-rotate: "true"
|
|
||||||
- run: make deps-backend
|
|
||||||
- run: make backend
|
|
||||||
env:
|
|
||||||
TAGS: bindata gogit
|
|
||||||
GOEXPERIMENT:
|
|
||||||
- name: unit-tests-gogit
|
- name: unit-tests-gogit
|
||||||
run: make test-backend-gogit test-check
|
run: make test-backend-gogit-shard test-check
|
||||||
env:
|
env:
|
||||||
|
TEST_SHARD: ${{ matrix.shard }}
|
||||||
|
TEST_TOTAL_SHARDS: 3
|
||||||
GOTEST_FLAGS: -race -timeout=20m
|
GOTEST_FLAGS: -race -timeout=20m
|
||||||
TAGS: bindata gogit
|
TAGS: bindata gogit
|
||||||
GOEXPERIMENT:
|
GOEXPERIMENT:
|
||||||
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
GITHUB_READ_TOKEN: ${{ secrets.GITHUB_READ_TOKEN }}
|
||||||
|
|
||||||
test-unit:
|
test-unit:
|
||||||
needs: [files-changed, test-unit-nogogit, test-unit-gogit]
|
needs: [files-changed, test-unit-shards]
|
||||||
if: always() && (needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true')
|
if: always() && (needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true')
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- run: '[ "${{ needs.test-unit-nogogit.result }}" = "success" ] && [ "${{ needs.test-unit-gogit.result }}" = "success" ]'
|
- run: '[ "${{ needs.test-unit-shards.result }}" = "success" ]'
|
||||||
|
|
||||||
test-mysql-shards:
|
test-mysql-shards:
|
||||||
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
if: needs.files-changed.outputs.backend == 'true' || needs.files-changed.outputs.actions == 'true'
|
||||||
|
|||||||
14
Makefile
14
Makefile
@ -388,6 +388,20 @@ test-backend-gogit: ## test packages whose code or tests import the gogit-affect
|
|||||||
echo "Running go test with $(GOTEST_FLAGS) -tags '$(TAGS)' over $$(echo $$pkgs | wc -w) gogit-affected packages..." && \
|
echo "Running go test with $(GOTEST_FLAGS) -tags '$(TAGS)' over $$(echo $$pkgs | wc -w) gogit-affected packages..." && \
|
||||||
$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' $$pkgs
|
$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' $$pkgs
|
||||||
|
|
||||||
|
.PHONY: test-backend-shard
|
||||||
|
test-backend-shard: ## run the TEST_SHARD/TEST_TOTAL_SHARDS slice of test-backend
|
||||||
|
@pkgs=$$(echo "$(GO_TEST_PACKAGES)" | tr ' ' '\n' | ./tools/partition-by-shard.sh | tr '\n' ' ') && \
|
||||||
|
if [ -z "$$pkgs" ]; then echo "shard $$TEST_SHARD/$$TEST_TOTAL_SHARDS has no test-backend packages" >&2; exit 1; fi && \
|
||||||
|
echo "Running shard $$TEST_SHARD/$$TEST_TOTAL_SHARDS of test-backend ($$(echo $$pkgs | wc -w) packages)..." && \
|
||||||
|
$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' $$pkgs
|
||||||
|
|
||||||
|
.PHONY: test-backend-gogit-shard
|
||||||
|
test-backend-gogit-shard: ## run the TEST_SHARD/TEST_TOTAL_SHARDS slice of test-backend-gogit
|
||||||
|
@pkgs=$$(./tools/find-gogit-test-pkgs.sh '$(TAGS)' | ./tools/partition-by-shard.sh) && \
|
||||||
|
if [ -z "$$pkgs" ]; then echo "shard $$TEST_SHARD/$$TEST_TOTAL_SHARDS has no gogit-affected packages" >&2; exit 1; fi && \
|
||||||
|
echo "Running shard $$TEST_SHARD/$$TEST_TOTAL_SHARDS of test-backend-gogit ($$(echo $$pkgs | wc -w) packages)..." && \
|
||||||
|
$(GO) test $(GOTEST_FLAGS) -tags='$(TAGS)' $$pkgs
|
||||||
|
|
||||||
.PHONY: test-frontend
|
.PHONY: test-frontend
|
||||||
test-frontend: node_modules ## test frontend files
|
test-frontend: node_modules ## test frontend files
|
||||||
pnpm exec vitest
|
pnpm exec vitest
|
||||||
|
|||||||
20
tools/partition-by-shard.sh
Executable file
20
tools/partition-by-shard.sh
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Print the TEST_SHARD/TEST_TOTAL_SHARDS slice of stdin (newline-separated
|
||||||
|
# items), partitioned round-robin by line number after a deterministic sort.
|
||||||
|
# Required env: TEST_SHARD (1..TEST_TOTAL_SHARDS), TEST_TOTAL_SHARDS (>= 1).
|
||||||
|
|
||||||
|
shard=${TEST_SHARD:?missing TEST_SHARD}
|
||||||
|
total=${TEST_TOTAL_SHARDS:?missing TEST_TOTAL_SHARDS}
|
||||||
|
|
||||||
|
if ! [[ "$total" =~ ^[1-9][0-9]*$ ]]; then
|
||||||
|
echo "TEST_TOTAL_SHARDS must be a positive integer, got: $total" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
if ! [[ "$shard" =~ ^[1-9][0-9]*$ ]] || [ "$shard" -gt "$total" ]; then
|
||||||
|
echo "TEST_SHARD must be in [1, $total], got: $shard" >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
LC_ALL=C sort -u | awk -v r=$((shard - 1)) -v t="$total" 'NR % t == r'
|
||||||
@ -7,29 +7,17 @@ set -euo pipefail
|
|||||||
# a configured database.
|
# a configured database.
|
||||||
|
|
||||||
binary=$1
|
binary=$1
|
||||||
shard=${TEST_SHARD:?missing TEST_SHARD}
|
|
||||||
total=${TEST_TOTAL_SHARDS:?missing TEST_TOTAL_SHARDS}
|
|
||||||
|
|
||||||
if ! [[ "$total" =~ ^[1-9][0-9]*$ ]]; then
|
|
||||||
echo "TEST_TOTAL_SHARDS must be a positive integer, got: $total" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
if ! [[ "$shard" =~ ^[1-9][0-9]*$ ]] || [ "$shard" -gt "$total" ]; then
|
|
||||||
echo "TEST_SHARD must be in [1, $total], got: $shard" >&2
|
|
||||||
exit 2
|
|
||||||
fi
|
|
||||||
|
|
||||||
# match `func Test*(t *testing.T|TB)` only — excludes TestMain (takes *testing.M)
|
# match `func Test*(t *testing.T|TB)` only — excludes TestMain (takes *testing.M)
|
||||||
names=$(grep -hE '^func Test[A-Z][A-Za-z0-9_]*\([a-zA-Z_][a-zA-Z0-9_]* \*testing\.(T|TB)\)' tests/integration/*.go \
|
names=$(grep -hE '^func Test[A-Z][A-Za-z0-9_]*\([a-zA-Z_][a-zA-Z0-9_]* \*testing\.(T|TB)\)' tests/integration/*.go \
|
||||||
| sed -E 's/^func (Test[A-Z][A-Za-z0-9_]*).*/\1/' \
|
| sed -E 's/^func (Test[A-Z][A-Za-z0-9_]*).*/\1/' \
|
||||||
| LC_ALL=C sort -u \
|
| ./tools/partition-by-shard.sh)
|
||||||
| awk -v r=$((shard - 1)) -v t="$total" 'NR % t == r')
|
|
||||||
|
|
||||||
if [ -z "$names" ]; then
|
if [ -z "$names" ]; then
|
||||||
echo "no tests assigned to shard $shard/$total — likely a misconfiguration" >&2
|
echo "no tests assigned to shard $TEST_SHARD/$TEST_TOTAL_SHARDS — likely a misconfiguration" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
pattern=$(echo "$names" | paste -sd '|' -)
|
pattern=$(echo "$names" | paste -sd '|' -)
|
||||||
echo "Running shard $shard/$total ($(echo "$names" | wc -l | tr -d ' ') tests)"
|
echo "Running shard $TEST_SHARD/$TEST_TOTAL_SHARDS ($(echo "$names" | wc -l | tr -d ' ') tests)"
|
||||||
exec "$binary" -test.run "^($pattern)\$"
|
exec "$binary" -test.run "^($pattern)\$"
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user