Something went wrong. Try again.
forked from tailscale/tailscale
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962# 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: # GOMODCACHE is the same definition on all OSes. Within the workspace, we use # toplevel directories "src" (for the checked out source code), and "gomodcache" # and other caches as siblings to follow. GOMODCACHE: ${{ github.workspace }}/gomodcache CMD_GO_USE_GIT_HASH: "true"
on: push: branches: - "main" - "release-branch/*" pull_request: # all PRs on all 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: gomod-cache: runs-on: ubuntu-24.04 outputs: cache-key: ${{ steps.hash.outputs.key }} steps: - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Compute cache key from go.{mod,sum} id: hash run: echo "key=gomod-cross3-${{ hashFiles('src/go.mod', 'src/go.sum') }}" >> $GITHUB_OUTPUT # See if the cache entry already exists to avoid downloading it # and doing the cache write again. - id: check-cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache # relative to workspace; see env note at top of file key: ${{ steps.hash.outputs.key }} lookup-only: true enableCrossOsArchive: true - name: Download modules if: steps.check-cache.outputs.cache-hit != 'true' working-directory: src run: go mod download - name: Cache Go modules if: steps.check-cache.outputs.cache-hit != 'true' uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # zizmor: ignore[cache-poisoning] v5.0.4 with: path: gomodcache # relative to workspace; see env note at top of file key: ${{ steps.hash.outputs.key }} enableCrossOsArchive: true
race-root-integration: runs-on: ubuntu-24.04 needs: gomod-cache strategy: fail-fast: false # don't abort the entire matrix if one element fails matrix: include: - shard: '1/4' - shard: '2/4' - shard: '3/4' - shard: '4/4' steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: build test wrapper working-directory: src run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper - name: integration tests as root working-directory: src run: PATH=$PWD/tool:$PATH /tmp/testwrapper -exec "sudo -E" -race ./tstest/integration/ env: TS_TEST_SHARD: ${{ matrix.shard }}
test: strategy: fail-fast: false # don't abort the entire matrix if one element fails matrix: include: - goarch: amd64 - goarch: amd64 buildflags: "-race" shard: '1/3' - goarch: amd64 buildflags: "-race" shard: '2/3' - goarch: amd64 buildflags: "-race" shard: '3/3' - goarch: "386" # thanks yaml runs-on: ubuntu-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: Restore Cache id: restore-cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only restoring the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} restore-keys: | ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}-${{ github.job }}- ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}- ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}- ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go- - name: build all if: matrix.buildflags == '' # skip on race builder working-directory: src run: ./tool/go build ${{matrix.buildflags}} ./... env: GOARCH: ${{ matrix.goarch }} - name: build variant CLIs if: matrix.buildflags == '' # skip on race builder working-directory: src run: | ./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.buildflags == '' run: | sudo apt-get -y update sudo apt-get -y install qemu-user - name: build test wrapper working-directory: src run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper - name: test all working-directory: src run: NOBASHDEBUG=true NOPWSHDEBUG=true PATH=$PWD/tool:$PATH /tmp/testwrapper ./... ${{matrix.buildflags}} env: GOARCH: ${{ matrix.goarch }} TS_TEST_SHARD: ${{ matrix.shard }} - name: bench all working-directory: src run: ./tool/go test ${{matrix.buildflags}} -bench=. -benchtime=1x -run='^$' $(for x in $(git grep -l '^func Benchmark' | xargs dirname | sort | uniq); do echo "./$x"; done) env: GOARCH: ${{ matrix.goarch }} - name: check that no tracked files changed working-directory: src 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 working-directory: src 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 - name: Tidy cache working-directory: src shell: bash run: | find $(go env GOCACHE) -type f -mmin +90 -delete - name: Save Cache # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only saving the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-${{ matrix.goarch }}-${{ matrix.buildflags }}-go-${{ matrix.shard }}-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }}
windows: permissions: id-token: write # This is required for requesting the GitHub action identity JWT that can auth to cigocached contents: read # This is required for actions/checkout # ci-windows-github-1 is a 2022 GitHub-managed runner in our org with 8 cores # and 32 GB of RAM. It is connected to a private Azure VNet that hosts cigocached. # https://github.com/organizations/tailscale/settings/actions/github-hosted-runners/5 runs-on: ci-windows-github-1 needs: gomod-cache name: Windows (${{ matrix.name || matrix.shard}}) strategy: fail-fast: false # don't abort the entire matrix if one element fails matrix: include: - key: "win-bench" name: "benchmarks" - key: "win-shard-1-2" shard: "1/2" - key: "win-shard-2-2" shard: "2/2" steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: ${{ github.workspace }}/src
- name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true
- name: Set up cigocacher id: cigocacher-setup uses: ./src/.github/actions/go-cache with: checkout-path: ${{ github.workspace }}/src cache-dir: ${{ github.workspace }}/cigocacher cigocached-url: ${{ vars.CIGOCACHED_AZURE_URL }} cigocached-host: ${{ vars.CIGOCACHED_AZURE_HOST }}
- name: test shell: bash if: matrix.key != 'win-bench' # skip on bench builder working-directory: src # -count=1: a cached pass is never retried, so flakes can't be reported. run: ./tool/go run ./cmd/testwrapper sharded:${{ matrix.shard }} -count=1 env: NOPWSHDEBUG: "true" # to quiet tool/gocross/gocross-wrapper.ps1 in CI TS_TESTWRAPPER_RESULTS_SUMMARY: "1" TS_TESTWRAPPER_RESULTS_PKG: tailscale.com/tstest/integration TS_TESTWRAPPER_RESULTS_JSON: ${{ github.workspace }}/windows-integration-results.json
- name: Upload Windows integration results if: always() && matrix.key != 'win-bench' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: windows-integration-results-${{ matrix.key }} path: ${{ github.workspace }}/windows-integration-results.json if-no-files-found: ignore
- name: bench all shell: bash if: matrix.key == 'win-bench' working-directory: src run: ./tool/go test -bench=. -benchtime=1x -run='^$' $(for x in $(git grep -l '^func Benchmark' | xargs dirname | sort | uniq); do echo "./$x"; done) env: NOPWSHDEBUG: "true" # to quiet tool/gocross/gocross-wrapper.ps1 in CI
- name: Print stats shell: pwsh if: steps.cigocacher-setup.outputs.success == 'true' env: GOCACHEPROG: ${{ env.GOCACHEPROG }} run: | Invoke-Expression "$env:GOCACHEPROG --stats" | jq .
macos: runs-on: macos-latest needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: Restore Cache id: restore-cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/Library/Caches/go-build key: ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} restore-keys: | ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}-${{ github.job }}- ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}- ${{ runner.os }}-go-test- - name: build test wrapper working-directory: src run: ./tool/go build -o /tmp/testwrapper ./cmd/testwrapper - name: test all working-directory: src run: PATH=$PWD/tool:$PATH /tmp/testwrapper ./... - name: check that no tracked files changed working-directory: src 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 working-directory: src 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 - name: Tidy cache working-directory: src run: | find $(./tool/go env GOCACHE) -type f -mmin +90 -delete - name: Save Cache # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: ~/Library/Caches/go-build key: ${{ runner.os }}-go-test-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }}
privileged: needs: gomod-cache runs-on: ubuntu-24.04 container: image: golang:latest # zizmor: ignore[unpinned-images] options: --privileged steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: chown working-directory: src run: chown -R $(id -u):$(id -g) $PWD - name: privileged tests working-directory: src run: ./tool/go test $(./tool/go run ./tool/listpkgs --has-root-tests)
cross: # cross-compile checks, build only. needs: gomod-cache 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-24.04 steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: Restore Cache id: restore-cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only restoring the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} restore-keys: | ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}- ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}- ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go- - name: build all working-directory: src run: ./tool/go build ./cmd/... env: GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} GOARM: ${{ matrix.goarm }} CGO_ENABLED: "0" - name: build tests working-directory: src run: ./tool/go test -exec=true ./... env: GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} CGO_ENABLED: "0" - name: Tidy cache working-directory: src shell: bash run: | find $(go env GOCACHE) -type f -mmin +90 -delete - name: Save Cache # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only saving the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-${{ matrix.goarm }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }}
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-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: build some working-directory: src run: ./tool/go build ./ipn/... ./ssh/tailssh ./wgengine/ ./types/... ./control/controlclient env: GOOS: ios GOARCH: arm64
crossmin: # cross-compile for platforms where we only check cmd/tailscale{,d} needs: gomod-cache strategy: fail-fast: false # don't abort the entire matrix if one element fails matrix: include: # Plan9 - goos: plan9 goarch: amd64 # AIX - goos: aix goarch: ppc64 # Solaris - goos: solaris goarch: amd64 # illumos - goos: illumos goarch: amd64
runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: Restore Cache id: restore-cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only restoring the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} restore-keys: | ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}- ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}- ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go- - name: build core working-directory: src run: ./tool/go build ./cmd/tailscale ./cmd/tailscaled env: GOOS: ${{ matrix.goos }} GOARCH: ${{ matrix.goarch }} GOARM: ${{ matrix.goarm }} CGO_ENABLED: "0" - name: Tidy cache working-directory: src shell: bash run: | find $(go env GOCACHE) -type f -mmin +90 -delete - name: Save Cache # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only saving the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-${{ matrix.goos }}-${{ matrix.goarch }}-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }}
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-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src # 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: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: build some working-directory: src run: ./tool/go install ./net/netns ./ipn/ipnlocal ./wgengine/magicsock/ ./wgengine/ ./wgengine/router/ ./wgengine/netstack ./util/dnsname/ ./ipn/ ./net/netmon ./wgengine/router/ ./tailcfg/ ./types/logger/ ./net/dns ./hostinfo ./version ./ssh/tailssh env: GOOS: android GOARCH: arm64
wasm: # builds tsconnect, which is the only wasm build we support runs-on: ubuntu-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: Restore Cache id: restore-cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only restoring the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }} restore-keys: | ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}- ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}- ${{ runner.os }}-js-wasm-go- - name: build tsconnect client working-directory: src run: ./tool/go build ./cmd/tsconnect/wasm ./cmd/tailscale/cli env: GOOS: js GOARCH: wasm - name: build tsconnect server working-directory: src # 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 - name: verify Google Chrome is available run: | which google-chrome google-chrome --version - name: tsconnect js/wasm headless-browser tests working-directory: src run: ./tool/go test ./tstest/integration/jswasmtest/ -v -timeout 180s --run-headless-browser-tests - name: Tidy cache working-directory: src shell: bash run: | find $(go env GOCACHE) -type f -mmin +90 -delete - name: Save Cache # Save cache even on failure, but only on cache miss and main branch to avoid thrashing. if: always() && steps.restore-cache.outputs.cache-hit != 'true' && github.ref == 'refs/heads/main' uses: actions/cache/save@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: # Note: this is only saving the build cache. Mod cache is shared amongst # all jobs in the workflow. path: | ~/.cache/go-build ~\AppData\Local\go-build key: ${{ runner.os }}-js-wasm-go-${{ hashFiles('**/go.sum') }}-${{ github.job }}-${{ github.run_id }}
tailscale_go: # Subset of tests that depend on our custom Go toolchain. runs-on: ubuntu-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set GOMODCACHE env run: echo "GOMODCACHE=$HOME/.cache/go-mod" >> $GITHUB_ENV - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: test tailscale_go run: ./tool/go test -tags=tailscale_go,ts_enable_sockstats ./net/sockstats/...
depaware: runs-on: ubuntu-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Set GOMODCACHE env run: echo "GOMODCACHE=$HOME/.cache/go-mod" >> $GITHUB_ENV - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: check depaware working-directory: src run: make depaware
go_generate: runs-on: ubuntu-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: check that 'go generate' is clean working-directory: src run: | pkgs=$(./tool/go list ./... | grep -Ev 'dnsfallback|k8s-operator|xdp') ./tool/go generate $pkgs git add -N . # ensure untracked files are noticed echo echo git diff --name-only --exit-code || (echo "The files above need updating. Please run 'go generate'."; exit 1) - name: check that 'genreadme' is clean working-directory: src run: | ./tool/go run ./misc/genreadme git add -N . # ensure untracked files are noticed echo echo git diff --name-only --exit-code || (echo "The files above need updating. Please run './tool/go run ./misc/genreadme'."; exit 1)
make_tidy: runs-on: ubuntu-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: check that 'make tidy' is clean working-directory: src run: | make tidy echo echo git diff --name-only --exit-code || (echo "Please run 'make tidy'"; exit 1)
licenses: runs-on: ubuntu-24.04 needs: gomod-cache steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: check licenses working-directory: src run: | grep -q TestLicenseHeaders *.go || (echo "Expected a test named TestLicenseHeaders"; exit 1) ./tool/go test -v -run=TestLicenseHeaders
staticcheck: runs-on: ubuntu-24.04 needs: gomod-cache name: staticcheck (${{ matrix.name }}) strategy: fail-fast: false # don't abort the entire matrix if one element fails matrix: include: - name: "macOS" goos: "darwin" goarch: "arm64" flags: "--with-tags-all=darwin" - name: "Windows" goos: "windows" goarch: "amd64" flags: "--with-tags-all=windows" - name: "Linux" goos: "linux" goarch: "amd64" flags: "--with-tags-all=linux" - name: "Portable (1/4)" goos: "linux" goarch: "amd64" flags: "--without-tags-any=windows,darwin,linux --shard=1/4" - name: "Portable (2/4)" goos: "linux" goarch: "amd64" flags: "--without-tags-any=windows,darwin,linux --shard=2/4" - name: "Portable (3/4)" goos: "linux" goarch: "amd64" flags: "--without-tags-any=windows,darwin,linux --shard=3/4" - name: "Portable (4/4)" goos: "linux" goarch: "amd64" flags: "--without-tags-any=windows,darwin,linux --shard=4/4"
steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src - name: Restore Go module cache uses: actions/cache/restore@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 with: path: gomodcache key: ${{ needs.gomod-cache.outputs.cache-key }} enableCrossOsArchive: true - name: run staticcheck (${{ matrix.name }}) working-directory: src run: | export GOROOT=$(./tool/go env GOROOT) ./tool/go run -exec \ "env GOOS=${{ matrix.goos }} GOARCH=${{ matrix.goarch }}" \ honnef.co/go/tools/cmd/staticcheck -- \ $(./tool/go run ./tool/listpkgs --ignore-3p --goos=${{ matrix.goos }} --goarch=${{ matrix.goarch }} ${{ matrix.flags }} ./...)
notify_slack: if: always() # Any of these jobs failing causes a slack notification. needs: - android - test - windows - macos - cross - ios - wasm - tailscale_go - depaware - go_generate - make_tidy - licenses - staticcheck runs-on: ubuntu-24.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: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 with: webhook: ${{ secrets.SLACK_WEBHOOK_URL }} webhook-type: incoming-webhook 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" }] }
notify_windows: if: always() needs: - windows runs-on: ubuntu-24.04 steps: - name: checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: path: src persist-credentials: false - name: Download Windows integration results uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: pattern: windows-integration-results-* path: results - name: Build Slack payload id: payload uses: ./src/.github/actions/windows-slack-payload with: result: ${{ needs.windows.result }} title: ${{ github.event.pull_request.title }} header: "<${{ github.event.pull_request.html_url }}|PR #${{ github.event.pull_request.number }}> · `${{ github.event.pull_request.head.ref }}`" status-label: Windows CI tests-label: Windows Integration Tests # One result file per non-bench leg of the windows matrix. expected-files: "2" - name: Send Slack notification env: WEBHOOK: ${{ secrets.WINDOWS_SLACK_WEBHOOK_URL }} if: env.WEBHOOK != '' && github.event_name == 'pull_request' && needs.windows.result != 'cancelled' continue-on-error: true uses: slackapi/slack-github-action@91efab103c0de0a537f72a35f6b8cda0ee76bf0a # v2.1.1 with: webhook: ${{ env.WEBHOOK }} webhook-type: incoming-webhook payload-file-path: payload.json
merge_blocker: if: always() runs-on: ubuntu-24.04 needs: - android - test - windows - macos - cross - ios - wasm - tailscale_go - depaware - go_generate - make_tidy - licenses - staticcheck steps: - name: Decide if change is okay to merge if: github.event_name != 'push' uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }}
# This waits on all the jobs which must never fail. Branch protection rules # enforce these. No flaky tests are allowed in these jobs. (We don't want flaky # tests anywhere, really, but a flaky test here prevents merging.) check_mergeability_strict: if: always() runs-on: ubuntu-24.04 needs: - android - cross - crossmin - ios - tailscale_go - depaware - go_generate - make_tidy - licenses - staticcheck steps: - name: Decide if change is okay to merge if: github.event_name != 'push' uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }}
check_mergeability: if: always() runs-on: ubuntu-24.04 needs: - check_mergeability_strict - test - windows - macos - wasm - race-root-integration - privileged steps: - name: Decide if change is okay to merge if: github.event_name != 'push' uses: re-actors/alls-green@05ac9388f0aebcb5727afa17fcccfecd6f8ec5fe # v1.2.2 with: jobs: ${{ toJSON(needs) }}