| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430 |
- # This is our main "CI tests" workflow. It runs everything that should run on
- # both PRs and merged commits, and for the latter reports failures to slack.
- name: CI
- env:
- # Our fuzz job, powered by OSS-Fuzz, fails periodically because we upgrade to
- # new Go versions very eagerly. OSS-Fuzz is a little more conservative, and
- # ends up being unable to compile our code.
- #
- # When this happens, we want to disable the fuzz target until OSS-Fuzz catches
- # up. However, we also don't want to forget to turn it back on when OSS-Fuzz
- # can once again build our code.
- #
- # This variable toggles the fuzz job between two modes:
- # - false: we expect fuzzing to be happy, and should report failure if it's not.
- # - true: we expect fuzzing is broken, and should report failure if it start working.
- TS_FUZZ_CURRENTLY_BROKEN: false
- on:
- push:
- branches:
- - "main"
- - "release-branch/*"
- pull_request:
- branches:
- - "*"
- merge_group:
- branches:
- - "main"
- concurrency:
- # For PRs, later CI runs preempt previous ones. e.g. a force push on a PR
- # cancels running CI jobs and starts all new ones.
- #
- # For non-PR pushes, concurrency.group needs to be unique for every distinct
- # CI run we want to have happen. Use run_id, which in practice means all
- # non-PR CI runs will be allowed to run without preempting each other.
- group: ${{ github.workflow }}-$${{ github.pull_request.number || github.run_id }}
- cancel-in-progress: true
- jobs:
- test:
- strategy:
- fail-fast: false # don't abort the entire matrix if one element fails
- matrix:
- include:
- - goarch: amd64
- - goarch: amd64
- variant: race
- - goarch: "386" # thanks yaml
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: build all
- run: ./tool/go build ./...
- env:
- GOARCH: ${{ matrix.goarch }}
- - name: build variant CLIs
- run: |
- export TS_USE_TOOLCHAIN=1
- ./build_dist.sh --extra-small ./cmd/tailscaled
- ./build_dist.sh --box ./cmd/tailscaled
- ./build_dist.sh --extra-small --box ./cmd/tailscaled
- rm -f tailscaled
- env:
- GOARCH: ${{ matrix.goarch }}
- - name: get qemu # for tstest/archtest
- if: matrix.goarch == 'amd64' && matrix.variant == ''
- run: |
- sudo apt-get -y update
- sudo apt-get -y install qemu-user
- - name: build test wrapper
- run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper
- - name: test all
- if: matrix.variant != 'race'
- run: ./tool/go test -exec=/tmp/testwrapper -bench=. -benchtime=1x ./...
- env:
- GOARCH: ${{ matrix.goarch }}
- - name: test all (race)
- if: matrix.variant == 'race'
- run: ./tool/go test -race -exec=/tmp/testwrapper -bench=. -benchtime=1x ./...
- env:
- GOARCH: ${{ matrix.goarch }}
- - name: check that no tracked files changed
- run: git diff --no-ext-diff --name-only --exit-code || (echo "Build/test modified the files above."; exit 1)
- - name: check that no new files were added
- run: |
- # Note: The "error: pathspec..." you see below is normal!
- # In the success case in which there are no new untracked files,
- # git ls-files complains about the pathspec not matching anything.
- # That's OK. It's not worth the effort to suppress. Please ignore it.
- if git ls-files --others --exclude-standard --directory --no-empty-directory --error-unmatch -- ':/*'
- then
- echo "Build/test created untracked files in the repo (file names above)."
- exit 1
- fi
- windows:
- runs-on: windows-2022
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: Restore Cache
- uses: actions/cache@v3
- with:
- # Note: unlike the other setups, this is only grabbing the mod download
- # cache, rather than the whole mod directory, as the download cache
- # contains zips that can be unpacked in parallel faster than they can be
- # fetched and extracted by tar
- path: |
- ~/go/pkg/mod/cache
- ~\AppData\Local\go-build
- # The -2- here should be incremented when the scheme of data to be
- # cached changes (e.g. path above changes).
- # TODO(raggi): add a go version here.
- key: ${{ runner.os }}-go-2-${{ hashFiles('**/go.sum') }}
- - name: test
- # Don't use -bench=. -benchtime=1x.
- # Somewhere in the layers (powershell?)
- # the equals signs cause great confusion.
- run: ./tool/go test -bench . -benchtime 1x ./...
- vm:
- runs-on: ["self-hosted", "linux", "vm"]
- # VM tests run with some privileges, don't let them run on 3p PRs.
- if: github.repository == 'tailscale/tailscale'
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: Run VM tests
- run: ./tool/go test ./tstest/integration/vms -v -no-s3 -run-vm-tests -run=TestRunUbuntu2004
- env:
- HOME: "/tmp"
- TMPDIR: "/tmp"
- XDB_CACHE_HOME: "/var/lib/ghrunner/cache"
-
- cross: # cross-compile checks, build only.
- strategy:
- fail-fast: false # don't abort the entire matrix if one element fails
- matrix:
- include:
- # Note: linux/amd64 is not in this matrix, because that goos/goarch is
- # tested more exhaustively in the 'test' job above.
- - goos: linux
- goarch: arm64
- - goos: linux
- goarch: "386" # thanks yaml
- - goos: linux
- goarch: loong64
- - goos: linux
- goarch: arm
- goarm: "5"
- - goos: linux
- goarch: arm
- goarm: "7"
- # macOS
- - goos: darwin
- goarch: amd64
- - goos: darwin
- goarch: arm64
- # Windows
- - goos: windows
- goarch: amd64
- - goos: windows
- goarch: arm64
- # BSDs
- - goos: freebsd
- goarch: amd64
- - goos: openbsd
- goarch: amd64
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: build all
- run: ./tool/go build ./cmd/...
- env:
- GOOS: ${{ matrix.goos }}
- GOARCH: ${{ matrix.goarch }}
- GOARM: ${{ matrix.goarm }}
- CGO_ENABLED: "0"
- - name: build tests
- run: ./tool/go test -exec=true ./...
- env:
- GOOS: ${{ matrix.goos }}
- GOARCH: ${{ matrix.goarch }}
- CGO_ENABLED: "0"
- ios: # similar to cross above, but iOS can't build most of the repo. So, just
- #make it build a few smoke packages.
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: build some
- run: ./tool/go build ./ipn/... ./wgengine/ ./types/... ./control/controlclient
- env:
- GOOS: ios
- GOARCH: arm64
- android:
- # similar to cross above, but android fails to build a few pieces of the
- # repo. We should fix those pieces, they're small, but as a stepping stone,
- # only test the subset of android that our past smoke test checked.
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- # Super minimal Android build that doesn't even use CGO and doesn't build everything that's needed
- # and is only arm64. But it's a smoke build: it's not meant to catch everything. But it'll catch
- # some Android breakages early.
- # TODO(bradfitz): better; see https://github.com/tailscale/tailscale/issues/4482
- - name: build some
- run: ./tool/go install ./net/netns ./ipn/ipnlocal ./wgengine/magicsock/ ./wgengine/ ./wgengine/router/ ./wgengine/netstack ./util/dnsname/ ./ipn/ ./net/interfaces ./wgengine/router/ ./tailcfg/ ./types/logger/ ./net/dns ./hostinfo ./version
- env:
- GOOS: android
- GOARCH: arm64
- wasm: # builds tsconnect, which is the only wasm build we support
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: build tsconnect client
- run: ./tool/go build ./cmd/tsconnect/wasm ./cmd/tailscale/cli
- env:
- GOOS: js
- GOARCH: wasm
- - name: build tsconnect server
- # Note, no GOOS/GOARCH in env on this build step, we're running a build
- # tool that handles the build itself.
- run: |
- ./tool/go run ./cmd/tsconnect --fast-compression build
- ./tool/go run ./cmd/tsconnect --fast-compression build-pkg
- fuzz:
- # This target periodically breaks (see TS_FUZZ_CURRENTLY_BROKEN at the top
- # of the file), so it's more complex than usual: the 'build fuzzers' step
- # might fail, and depending on the value of 'TS_FUZZ_CURRENTLY_BROKEN', that
- # might or might not be fine. The steps after the build figure out whether
- # the success/failure is expected, and appropriately pass/fail the job
- # overall accordingly.
- #
- # Practically, this means that all steps after 'build fuzzers' must have an
- # explicit 'if' condition, because the default condition for steps is
- # 'success()', meaning "only run this if no previous steps failed".
- if: github.event_name == 'pull_request'
- runs-on: ubuntu-22.04
- steps:
- - name: build fuzzers
- id: build
- uses: google/oss-fuzz/infra/cifuzz/actions/build_fuzzers@master
- # continue-on-error makes steps.build.conclusion be 'success' even if
- # steps.build.outcome is 'failure'. This means this step does not
- # contribute to the job's overall pass/fail evaluation.
- continue-on-error: true
- with:
- oss-fuzz-project-name: 'tailscale'
- dry-run: false
- language: go
- - name: report unexpectedly broken fuzz build
- if: steps.build.outcome == 'failure' && env.TS_FUZZ_CURRENTLY_BROKEN != 'true'
- run: |
- echo "fuzzer build failed, see above for why"
- echo "if the failure is due to OSS-Fuzz not being on the latest Go yet,"
- echo "set TS_FUZZ_CURRENTLY_BROKEN=true in .github/workflows/test.yml"
- echo "to temporarily disable fuzzing until OSS-Fuzz works again."
- exit 1
- - name: report unexpectedly working fuzz build
- if: steps.build.outcome == 'success' && env.TS_FUZZ_CURRENTLY_BROKEN == 'true'
- run: |
- echo "fuzzer build succeeded, but we expect it to be broken"
- echo "please set TS_FUZZ_CURRENTLY_BROKEN=false in .github/workflows/test.yml"
- echo "to reenable fuzz testing"
- exit 1
- - name: run fuzzers
- id: run
- # Run the fuzzers whenever they're able to build, even if we're going to
- # report a failure because TS_FUZZ_CURRENTLY_BROKEN is set to the wrong
- # value.
- if: steps.build.outcome == 'success'
- uses: google/oss-fuzz/infra/cifuzz/actions/run_fuzzers@master
- with:
- oss-fuzz-project-name: 'tailscale'
- fuzz-seconds: 300
- dry-run: false
- language: go
- - name: upload crash
- uses: actions/upload-artifact@v3
- if: steps.run.outcome != 'success' && steps.build.outcome == 'success'
- with:
- name: artifacts
- path: ./out/artifacts
- depaware:
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: check depaware
- run: |
- export PATH=$(./tool/go env GOROOT)/bin:$PATH
- find . -name 'depaware.txt' | xargs -n1 dirname | xargs ./tool/go run github.com/tailscale/depaware --check
- go_generate:
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: check that 'go generate' is clean
- run: |
- pkgs=$(./tool/go list ./... | grep -v dnsfallback)
- ./tool/go generate $pkgs
- echo
- echo
- git diff --name-only --exit-code || (echo "The files above need updating. Please run 'go generate'."; exit 1)
- go_mod_tidy:
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: check that 'go mod tidy' is clean
- run: |
- ./tool/go mod tidy
- echo
- echo
- git diff --name-only --exit-code || (echo "Please run 'go mod tidy'."; exit 1)
- licenses:
- runs-on: ubuntu-22.04
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: check licenses
- run: ./scripts/check_license_headers.sh .
- staticcheck:
- runs-on: ubuntu-22.04
- strategy:
- fail-fast: false # don't abort the entire matrix if one element fails
- matrix:
- goos: ["linux", "windows", "darwin"]
- goarch: ["amd64"]
- include:
- - goos: "windows"
- goarch: "386"
- steps:
- - name: checkout
- uses: actions/checkout@v3
- - name: install staticcheck
- run: GOBIN=~/.local/bin ./tool/go install honnef.co/go/tools/cmd/staticcheck
- - name: run staticcheck
- run: |
- export GOROOT=$(./tool/go env GOROOT)
- export PATH=$GOROOT/bin:$PATH
- staticcheck -- $(./tool/go list ./... | grep -v tempfork)
- env:
- GOOS: ${{ matrix.goos }}
- GOARCH: ${{ matrix.goarch }}
- notify_slack:
- if: always()
- # Any of these jobs failing causes a slack notification.
- needs:
- - android
- - test
- - windows
- - vm
- - cross
- - ios
- - wasm
- - fuzz
- - depaware
- - go_generate
- - go_mod_tidy
- - licenses
- - staticcheck
- runs-on: ubuntu-22.04
- steps:
- - name: notify
- # Only notify slack for merged commits, not PR failures.
- #
- # It may be tempting to move this condition into the job's 'if' block, but
- # don't: Github only collapses the test list into "everything is OK" if
- # all jobs succeeded. A skipped job results in the list staying expanded.
- # By having the job always run, but skipping its only step as needed, we
- # let the CI output collapse nicely in PRs.
- if: failure() && github.event_name == 'push'
- uses: ruby/[email protected]
- with:
- payload: |
- {
- "attachments": [{
- "title": "Failure: ${{ github.workflow }}",
- "title_link": "https://github.com/${{ github.repository }}/commit/${{ github.sha }}/checks",
- "text": "${{ github.repository }}@${{ github.ref_name }}: <https://github.com/${{ github.repository }}/commit/${{ github.sha }}|${{ github.sha }}>",
- "fields": [{ "value": ${{ toJson(github.event.head_commit.message) }}, "short": false }],
- "footer": "${{ github.event.head_commit.committer.name }} at ${{ github.event.head_commit.timestamp }}",
- "color": "danger"
- }]
- }
- env:
- SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
- check_mergeability:
- if: always()
- runs-on: ubuntu-22.04
- needs:
- - android
- - test
- - windows
- - vm
- - cross
- - ios
- - wasm
- - fuzz
- - depaware
- - go_generate
- - go_mod_tidy
- - licenses
- - staticcheck
- steps:
- - name: Decide if change is okay to merge
- if: github.event_name != 'push'
- uses: re-actors/alls-green@release/v1
- with:
- jobs: ${{ toJSON(needs) }}
|