diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml index 6c36d4f..1f8ded6 100644 --- a/.github/workflows/benchmark.yml +++ b/.github/workflows/benchmark.yml @@ -2,30 +2,38 @@ name: Run benchmarks permissions: contents: read +# Opt-in only. Upstream ran this on an 8-core ARM machine on every push; on a +# shared 2-core runner the same job takes ~47 minutes, and the numbers it +# produces are not worth that. Comparing the base branch against *itself* on a +# GitHub-hosted runner swings -4.9% to +5.3% run to run, which is wider than +# most changes worth detecting -- so an automatic delta here would mostly +# report noise, at 47 minutes a PR. +# +# Run it deliberately from the Actions tab when a change is expected to move +# performance, and confirm anything that matters on a quiet machine. on: - push: - branches: - - "*" - pull_request: - types: [opened, reopened, synchronize] + workflow_dispatch: concurrency: group: ${{ github.ref }} cancel-in-progress: true jobs: + # Dispatched from a branch: benchmark it against main. benchmark: if: github.ref != 'refs/heads/main' - runs-on: - group: ARM LINUX SHARED - labels: arm-8core-linux + # Upstream runs this on DataDog's self-hosted ARM pool, which does not + # exist in this fork -- jobs targeting it queue forever. GitHub-hosted + # runners are shared and noisy, so treat a benchstat delta here as a hint + # and confirm anything that matters on a quiet machine. + runs-on: ubuntu-latest strategy: matrix: go-version: [ '1.25.7' ] steps: - name: Setup Go ${{ matrix.go-version }} - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ matrix.go-version }} - name: Display Go version @@ -84,17 +92,20 @@ jobs: path: bench + # Dispatched from main: refresh the cached baseline the job above compares to. benchmark_main: if: github.ref == 'refs/heads/main' - runs-on: - group: ARM LINUX SHARED - labels: arm-8core-linux + # Upstream runs this on DataDog's self-hosted ARM pool, which does not + # exist in this fork -- jobs targeting it queue forever. GitHub-hosted + # runners are shared and noisy, so treat a benchstat delta here as a hint + # and confirm anything that matters on a quiet machine. + runs-on: ubuntu-latest strategy: matrix: go-version: [ '1.25.7' ] steps: - name: Setup Go ${{ matrix.go-version }} - uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b + uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5.4.0 with: go-version: ${{ matrix.go-version }} - name: Display Go version diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index abd310f..71e2591 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -6,31 +6,73 @@ on: pull_request: types: [opened, reopened, synchronize] -jobs: - build: +# Nothing here writes to the repository. Declared explicitly because the +# default for a workflow without this block is whatever the repository +# setting says, which is not necessarily read-only. +permissions: + contents: read + +# Supersede an in-flight run when the same ref is pushed again. Keyed by +# workflow as well as ref so it does not fight the other workflows. +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +jobs: + test: runs-on: ubuntu-latest + timeout-minutes: 20 strategy: + # Report every Go version that fails, not just the first. + fail-fast: false matrix: - go-version: [ '1.25', '1.25.7' ] + go-version: ['1.25', '1.25.7'] steps: - - uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 + # Actions are pinned to a commit SHA rather than a tag: a tag can be + # moved to point at different code, a SHA cannot. The trailing comment + # is the tag that SHA carried when it was pinned, so the next person + # can tell what they are bumping from. + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + # The build never pushes, so leave no credentials in .git/config + # for a later step to pick up. + persist-credentials: false + - name: Setup Go ${{ matrix.go-version }} - uses: actions/setup-go@7b8cf10d4e4a01d4992d18a89f4d7dc5a3e6d6f4 # v4.3.0 + uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version: ${{ matrix.go-version }} + - name: Display Go version run: go version - - name: Install dependencies - run: go get . + + - name: Check formatting + run: | + unformatted=$(gofmt -l .) + if [ -n "$unformatted" ]; then + echo "::error::gofmt reported unformatted files:" + echo "$unformatted" + exit 1 + fi + + - name: Vet + run: go vet ./... + - name: Build run: go build -v ./... + - name: Test run: go test -v ./... - - name: Test Race + + - name: Test with race detector run: go test -race -v ./... - - name: Fuzz Normalizer - run: go test -fuzz=FuzzNormalizer -fuzztime 60s - - name: Fuzz Obfuscator and Normalizer - run: go test -fuzz=FuzzObfuscatorAndNormalizer -fuzztime 60s + + # -run '^$' selects no unit tests, so the fuzz budget is spent fuzzing + # rather than re-running the suite that already ran above. + - name: Fuzz normalizer + run: go test -run '^$' -fuzz=FuzzNormalizer -fuzztime 60s + + - name: Fuzz obfuscator and normalizer + run: go test -run '^$' -fuzz=FuzzObfuscatorAndNormalizer -fuzztime 60s