name: ci on: push: branches: - main pull_request: workflow_dispatch: permissions: contents: read # Cancel in-progress runs for pull requests when developers push # additional changes concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} jobs: changes: runs-on: ubuntu-latest outputs: docs-only: ${{ steps.filter.outputs.docs_count == steps.filter.outputs.all_count }} docs: ${{ steps.filter.outputs.docs }} go: ${{ steps.filter.outputs.go }} site: ${{ steps.filter.outputs.site }} k8s: ${{ steps.filter.outputs.k8s }} ci: ${{ steps.filter.outputs.ci }} db: ${{ steps.filter.outputs.db }} gomod: ${{ steps.filter.outputs.gomod }} offlinedocs-only: ${{ steps.filter.outputs.offlinedocs_count == steps.filter.outputs.all_count }} offlinedocs: ${{ steps.filter.outputs.offlinedocs }} tailnet-integration: ${{ steps.filter.outputs.tailnet-integration }} steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 # For pull requests it's not necessary to checkout the code - name: check changed files uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: filter with: filters: | all: - "**" docs: - "docs/**" - "README.md" - "examples/web-server/**" - "examples/monitoring/**" - "examples/lima/**" db: - "**.sql" - "coderd/database/**" go: - "**.sql" - "**.go" - "**.golden" - "go.mod" - "go.sum" # Other non-Go files that may affect Go code: - "**.rego" - "**.sh" - "**.tpl" - "**.gotmpl" - "**.gotpl" - "Makefile" - "site/static/error.html" # Main repo directories for completeness in case other files are # touched: - "agent/**" - "cli/**" - "cmd/**" - "coderd/**" - "enterprise/**" - "examples/**" - "helm/**" - "provisioner/**" - "provisionerd/**" - "provisionersdk/**" - "pty/**" - "scaletest/**" - "tailnet/**" - "testutil/**" gomod: - "go.mod" - "go.sum" site: - "site/**" k8s: - "helm/**" - "scripts/Dockerfile" - "scripts/Dockerfile.base" - "scripts/helm.sh" ci: - ".github/actions/**" - ".github/workflows/ci.yaml" offlinedocs: - "offlinedocs/**" tailnet-integration: - "tailnet/**" - "go.mod" - "go.sum" - id: debug run: | echo "${{ toJSON(steps.filter )}}" # Disabled due to instability. See: https://github.com/coder/coder/issues/14553 # Re-enable once the flake hash calculation is stable. # update-flake: # needs: changes # if: needs.changes.outputs.gomod == 'true' # runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} # steps: # - name: Checkout # uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 # with: # fetch-depth: 1 # # See: https://github.com/stefanzweifel/git-auto-commit-action?tab=readme-ov-file#commits-made-by-this-action-do-not-trigger-new-workflow-runs # token: ${{ secrets.CDRCI_GITHUB_TOKEN }} # - name: Setup Go # uses: ./.github/actions/setup-go # - name: Update Nix Flake SRI Hash # run: ./scripts/update-flake.sh # # auto update flake for dependabot # - uses: stefanzweifel/git-auto-commit-action@8621497c8c39c72f3e2a999a26b4ca1b5058a842 # v5.0.1 # if: github.actor == 'dependabot[bot]' # with: # # Allows dependabot to still rebase! # commit_message: "[dependabot skip] Update Nix Flake SRI Hash" # commit_user_name: "dependabot[bot]" # commit_user_email: "49699333+dependabot[bot]@users.noreply.github.com>" # commit_author: "dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>" # # require everyone else to update it themselves # - name: Ensure No Changes # if: github.actor != 'dependabot[bot]' # run: git diff --exit-code lint: needs: changes if: needs.changes.outputs.offlinedocs-only == 'false' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Node uses: ./.github/actions/setup-node - name: Setup Go uses: ./.github/actions/setup-go - name: Get golangci-lint cache dir run: | linter_ver=$(egrep -o 'GOLANGCI_LINT_VERSION=\S+' dogfood/coder/Dockerfile | cut -d '=' -f 2) go install github.com/golangci/golangci-lint/cmd/golangci-lint@v$linter_ver dir=$(golangci-lint cache status | awk '/Dir/ { print $2 }') echo "LINT_CACHE_DIR=$dir" >> $GITHUB_ENV - name: golangci-lint cache uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3 with: path: | ${{ env.LINT_CACHE_DIR }} key: golangci-lint-${{ runner.os }}-${{ hashFiles('**/*.go') }} restore-keys: | golangci-lint-${{ runner.os }}- # Check for any typos - name: Check for typos uses: crate-ci/typos@392b78fe18a52790c53f42456e46124f77346842 # v1.34.0 with: config: .github/workflows/typos.toml - name: Fix the typos if: ${{ failure() }} run: | echo "::notice:: you can automatically fix typos from your CLI: cargo install typos-cli typos -c .github/workflows/typos.toml -w" # Needed for helm chart linting - name: Install helm uses: azure/setup-helm@b9e51907a09c216f16ebe8536097933489208112 # v4.3.0 with: version: v3.9.2 - name: make lint run: | make --output-sync=line -j lint - name: Check workflow files run: | bash <(curl https://raw.githubusercontent.com/rhysd/actionlint/main/scripts/download-actionlint.bash) 1.7.4 ./actionlint -color -shellcheck= -ignore "set-output" shell: bash - name: Check for unstaged files run: | rm -f ./actionlint ./typos ./scripts/check_unstaged.sh shell: bash gen: timeout-minutes: 8 runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} if: ${{ !cancelled() }} steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Node uses: ./.github/actions/setup-node - name: Setup Go uses: ./.github/actions/setup-go - name: Setup sqlc uses: ./.github/actions/setup-sqlc - name: Setup Terraform uses: ./.github/actions/setup-tf - name: go install tools uses: ./.github/actions/setup-go-tools - name: Install Protoc run: | mkdir -p /tmp/proto pushd /tmp/proto curl -L -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v23.4/protoc-23.4-linux-x86_64.zip unzip protoc.zip cp -r ./bin/* /usr/local/bin cp -r ./include /usr/local/bin/include popd - name: make gen run: | # Remove golden files to detect discrepancy in generated files. make clean/golden-files # Notifications require DB, we could start a DB instance here but # let's just restore for now. git checkout -- coderd/notifications/testdata/rendered-templates # no `-j` flag as `make` fails with: # coderd/rbac/object_gen.go:1:1: syntax error: package statement must be first make --output-sync -B gen - name: Check for unstaged files run: ./scripts/check_unstaged.sh fmt: needs: changes if: needs.changes.outputs.offlinedocs-only == 'false' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} timeout-minutes: 7 steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Node uses: ./.github/actions/setup-node - name: Check Go version run: IGNORE_NIX=true ./scripts/check_go_versions.sh # Use default Go version - name: Setup Go uses: ./.github/actions/setup-go - name: Install shfmt run: go install mvdan.cc/sh/v3/cmd/shfmt@v3.7.0 - name: make fmt run: | export PATH=${PATH}:$(go env GOPATH)/bin make --output-sync -j -B fmt - name: Check for unstaged files run: ./scripts/check_unstaged.sh test-go-pg: # make sure to adjust NUM_PARALLEL_PACKAGES and NUM_PARALLEL_TESTS below # when changing runner sizes runs-on: ${{ matrix.os == 'ubuntu-latest' && github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || matrix.os && matrix.os == 'macos-latest' && github.repository_owner == 'coder' && 'depot-macos-latest' || matrix.os == 'windows-2022' && github.repository_owner == 'coder' && 'depot-windows-2022-16' || matrix.os }} needs: changes if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' # This timeout must be greater than the timeout set by `go test` in # `make test-postgres` to ensure we receive a trace of running # goroutines. Setting this to the timeout +5m should work quite well # even if some of the preceding steps are slow. timeout-minutes: 25 strategy: matrix: os: - ubuntu-latest - macos-latest - windows-2022 steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit # macOS indexes all new files in the background. Our Postgres tests # create and destroy thousands of databases on disk, and Spotlight # tries to index all of them, seriously slowing down the tests. - name: Disable Spotlight Indexing if: runner.os == 'macOS' run: | enabled=$(sudo mdutil -a -s | grep "Indexing enabled" | wc -l) if [ $enabled -eq 0 ]; then echo "Spotlight indexing is already disabled" exit 0 fi sudo mdutil -a -i off sudo mdutil -X / sudo launchctl bootout system /System/Library/LaunchDaemons/com.apple.metadata.mds.plist # Set up RAM disks to speed up the rest of the job. This action is in # a separate repository to allow its use before actions/checkout. - name: Setup RAM Disks if: runner.os == 'Windows' uses: coder/setup-ramdisk-action@e1100847ab2d7bcd9d14bcda8f2d1b0f07b36f1b - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Go Paths id: go-paths uses: ./.github/actions/setup-go-paths - name: Download Go Build Cache id: download-go-build-cache uses: ./.github/actions/test-cache/download with: key-prefix: test-go-build-${{ runner.os }}-${{ runner.arch }} cache-path: ${{ steps.go-paths.outputs.cached-dirs }} - name: Setup Go uses: ./.github/actions/setup-go with: # Runners have Go baked-in and Go will automatically # download the toolchain configured in go.mod, so we don't # need to reinstall it. It's faster on Windows runners. use-preinstalled-go: ${{ runner.os == 'Windows' }} # Cache is already downloaded above use-cache: false - name: Setup Terraform uses: ./.github/actions/setup-tf - name: Download Test Cache id: download-cache uses: ./.github/actions/test-cache/download with: key-prefix: test-go-pg-${{ runner.os }}-${{ runner.arch }} - name: Setup Embedded Postgres Cache Paths id: embedded-pg-cache uses: ./.github/actions/setup-embedded-pg-cache-paths - name: Download Embedded Postgres Cache id: download-embedded-pg-cache uses: ./.github/actions/embedded-pg-cache/download with: key-prefix: embedded-pg-${{ runner.os }}-${{ runner.arch }} cache-path: ${{ steps.embedded-pg-cache.outputs.cached-dirs }} - name: Normalize File and Directory Timestamps shell: bash # Normalize file modification timestamps so that go test can use the # cache from the previous CI run. See https://github.com/golang/go/issues/58571 # for more details. run: | find . -type f ! -path ./.git/\*\* | mtimehash find . -type d ! -path ./.git/\*\* -exec touch -t 200601010000 {} + - name: Test with PostgreSQL Database env: POSTGRES_VERSION: "13" TS_DEBUG_DISCO: "true" LC_CTYPE: "en_US.UTF-8" LC_ALL: "en_US.UTF-8" shell: bash run: | set -o errexit set -o pipefail if [ "${{ runner.os }}" == "Windows" ]; then # Create a temp dir on the R: ramdisk drive for Windows. The default # C: drive is extremely slow: https://github.com/actions/runner-images/issues/8755 mkdir -p "R:/temp/embedded-pg" go run scripts/embedded-pg/main.go -path "R:/temp/embedded-pg" -cache "${EMBEDDED_PG_CACHE_DIR}" elif [ "${{ runner.os }}" == "macOS" ]; then # Postgres runs faster on a ramdisk on macOS too mkdir -p /tmp/tmpfs sudo mount_tmpfs -o noowners -s 8g /tmp/tmpfs go run scripts/embedded-pg/main.go -path /tmp/tmpfs/embedded-pg -cache "${EMBEDDED_PG_CACHE_DIR}" elif [ "${{ runner.os }}" == "Linux" ]; then make test-postgres-docker fi # if macOS, install google-chrome for scaletests # As another concern, should we really have this kind of external dependency # requirement on standard CI? if [ "${{ matrix.os }}" == "macos-latest" ]; then brew install google-chrome fi # macOS will output "The default interactive shell is now zsh" # intermittently in CI... if [ "${{ matrix.os }}" == "macos-latest" ]; then touch ~/.bash_profile && echo "export BASH_SILENCE_DEPRECATION_WARNING=1" >> ~/.bash_profile fi if [ "${{ runner.os }}" == "Windows" ]; then # Our Windows runners have 16 cores. # On Windows Postgres chokes up when we have 16x16=256 tests # running in parallel, and dbtestutil.NewDB starts to take more than # 10s to complete sometimes causing test timeouts. With 16x8=128 tests # Postgres tends not to choke. NUM_PARALLEL_PACKAGES=8 NUM_PARALLEL_TESTS=16 # Only the CLI and Agent are officially supported on Windows and the rest are too flaky PACKAGES="./cli/... ./enterprise/cli/... ./agent/..." elif [ "${{ runner.os }}" == "macOS" ]; then # Our macOS runners have 8 cores. We set NUM_PARALLEL_TESTS to 16 # because the tests complete faster and Postgres doesn't choke. It seems # that macOS's tmpfs is faster than the one on Windows. NUM_PARALLEL_PACKAGES=8 NUM_PARALLEL_TESTS=16 # Only the CLI and Agent are officially supported on macOS and the rest are too flaky PACKAGES="./cli/... ./enterprise/cli/... ./agent/..." elif [ "${{ runner.os }}" == "Linux" ]; then # Our Linux runners have 8 cores. NUM_PARALLEL_PACKAGES=8 NUM_PARALLEL_TESTS=8 PACKAGES="./..." fi # by default, run tests with cache TESTCOUNT="" if [ "${{ github.ref }}" == "refs/heads/main" ]; then # on main, run tests without cache TESTCOUNT="-count=1" fi mkdir -p "$RUNNER_TEMP/sym" source scripts/normalize_path.sh # terraform gets installed in a random directory, so we need to normalize # the path to the terraform binary or a bunch of cached tests will be # invalidated. See scripts/normalize_path.sh for more details. normalize_path_with_symlinks "$RUNNER_TEMP/sym" "$(dirname $(which terraform))" gotestsum --format standard-quiet --packages "$PACKAGES" \ -- -timeout=20m -v -p $NUM_PARALLEL_PACKAGES -parallel=$NUM_PARALLEL_TESTS $TESTCOUNT - name: Upload failed test db dumps uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: failed-test-db-dump-${{matrix.os}} path: "**/*.test.sql" - name: Upload Go Build Cache uses: ./.github/actions/test-cache/upload with: cache-key: ${{ steps.download-go-build-cache.outputs.cache-key }} cache-path: ${{ steps.go-paths.outputs.cached-dirs }} - name: Upload Test Cache uses: ./.github/actions/test-cache/upload with: cache-key: ${{ steps.download-cache.outputs.cache-key }} - name: Upload Embedded Postgres Cache uses: ./.github/actions/embedded-pg-cache/upload # We only use the embedded Postgres cache on macOS and Windows runners. if: runner.OS == 'macOS' || runner.OS == 'Windows' with: cache-key: ${{ steps.download-embedded-pg-cache.outputs.cache-key }} cache-path: "${{ steps.embedded-pg-cache.outputs.embedded-pg-cache }}" - name: Upload test stats to Datadog timeout-minutes: 1 continue-on-error: true uses: ./.github/actions/upload-datadog if: success() || failure() with: api-key: ${{ secrets.DATADOG_API_KEY }} # NOTE: this could instead be defined as a matrix strategy, but we want to # only block merging if tests on postgres 13 fail. Using a matrix strategy # here makes the check in the above `required` job rather complicated. test-go-pg-17: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} needs: - changes if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' # This timeout must be greater than the timeout set by `go test` in # `make test-postgres` to ensure we receive a trace of running # goroutines. Setting this to the timeout +5m should work quite well # even if some of the preceding steps are slow. timeout-minutes: 25 steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Go uses: ./.github/actions/setup-go - name: Setup Terraform uses: ./.github/actions/setup-tf - name: Download Test Cache id: download-cache uses: ./.github/actions/test-cache/download with: key-prefix: test-go-pg-17-${{ runner.os }}-${{ runner.arch }} - name: Test with PostgreSQL Database env: POSTGRES_VERSION: "17" TS_DEBUG_DISCO: "true" run: | make test-postgres - name: Upload Test Cache uses: ./.github/actions/test-cache/upload with: cache-key: ${{ steps.download-cache.outputs.cache-key }} - name: Upload test stats to Datadog timeout-minutes: 1 continue-on-error: true uses: ./.github/actions/upload-datadog if: success() || failure() with: api-key: ${{ secrets.DATADOG_API_KEY }} test-go-race-pg: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-16' || 'ubuntu-latest' }} needs: changes if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' timeout-minutes: 25 steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Go uses: ./.github/actions/setup-go - name: Setup Terraform uses: ./.github/actions/setup-tf - name: Download Test Cache id: download-cache uses: ./.github/actions/test-cache/download with: key-prefix: test-go-race-pg-${{ runner.os }}-${{ runner.arch }} # We run race tests with reduced parallelism because they use more CPU and we were finding # instances where tests appear to hang for multiple seconds, resulting in flaky tests when # short timeouts are used. # c.f. discussion on https://github.com/coder/coder/pull/15106 - name: Run Tests env: POSTGRES_VERSION: "17" run: | make test-postgres-docker gotestsum --junitfile="gotests.xml" --packages="./..." -- -race -parallel 4 -p 4 - name: Upload Test Cache uses: ./.github/actions/test-cache/upload with: cache-key: ${{ steps.download-cache.outputs.cache-key }} - name: Upload test stats to Datadog timeout-minutes: 1 continue-on-error: true uses: ./.github/actions/upload-datadog if: always() with: api-key: ${{ secrets.DATADOG_API_KEY }} # Tailnet integration tests only run when the `tailnet` directory or `go.sum` # and `go.mod` are changed. These tests are to ensure we don't add regressions # to tailnet, either due to our code or due to updating dependencies. # # These tests are skipped in the main go test jobs because they require root # and mess with networking. test-go-tailnet-integration: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} needs: changes # Unnecessary to run on main for now if: needs.changes.outputs.tailnet-integration == 'true' || needs.changes.outputs.ci == 'true' timeout-minutes: 20 steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Go uses: ./.github/actions/setup-go # Used by some integration tests. - name: Install Nginx run: sudo apt-get update && sudo apt-get install -y nginx - name: Run Tests run: make test-tailnet-integration test-js: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} needs: changes if: needs.changes.outputs.site == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' timeout-minutes: 20 steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Node uses: ./.github/actions/setup-node - run: pnpm test:ci --max-workers $(nproc) working-directory: site test-e2e: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-4' || 'ubuntu-latest' }} needs: changes strategy: fail-fast: false matrix: variant: - premium: false name: test-e2e #- premium: true # name: test-e2e-premium # Skip test-e2e on forks as they don't have access to CI secrets if: (needs.changes.outputs.go == 'true' || needs.changes.outputs.site == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main') && !(github.event.pull_request.head.repo.fork) timeout-minutes: 20 name: ${{ matrix.variant.name }} steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 - name: Setup Node uses: ./.github/actions/setup-node - name: Setup Go uses: ./.github/actions/setup-go # Assume that the checked-in versions are up-to-date - run: make gen/mark-fresh name: make gen - run: make site/e2e/bin/coder name: make coder - run: pnpm build env: NODE_OPTIONS: ${{ github.repository_owner == 'coder' && '--max_old_space_size=8192' || '' }} working-directory: site - run: pnpm playwright:install working-directory: site # Run tests that don't require a premium license without a premium license - run: pnpm playwright:test --forbid-only --workers 1 if: ${{ !matrix.variant.premium }} env: DEBUG: pw:api working-directory: site # Run all of the tests with a premium license - run: pnpm playwright:test --forbid-only --workers 1 if: ${{ matrix.variant.premium }} env: DEBUG: pw:api CODER_E2E_LICENSE: ${{ secrets.CODER_E2E_LICENSE }} CODER_E2E_REQUIRE_PREMIUM_TESTS: "1" working-directory: site - name: Upload Playwright Failed Tests if: always() && github.actor != 'dependabot[bot]' && runner.os == 'Linux' && !github.event.pull_request.head.repo.fork uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: failed-test-videos${{ matrix.variant.premium && '-premium' || '' }} path: ./site/test-results/**/*.webm retention-days: 7 - name: Upload pprof dumps if: always() && github.actor != 'dependabot[bot]' && runner.os == 'Linux' && !github.event.pull_request.head.repo.fork uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: debug-pprof-dumps${{ matrix.variant.premium && '-premium' || '' }} path: ./site/test-results/**/debug-pprof-*.txt retention-days: 7 # Reference guide: # https://www.chromatic.com/docs/turbosnap-best-practices/#run-with-caution-when-using-the-pull_request-event chromatic: # REMARK: this is only used to build storybook and deploy it to Chromatic. runs-on: ubuntu-latest needs: changes if: needs.changes.outputs.site == 'true' || needs.changes.outputs.ci == 'true' steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # 👇 Ensures Chromatic can read your full git history fetch-depth: 0 # 👇 Tells the checkout which commit hash to reference ref: ${{ github.event.pull_request.head.ref }} - name: Setup Node uses: ./.github/actions/setup-node # This step is not meant for mainline because any detected changes to # storybook snapshots will require manual approval/review in order for # the check to pass. This is desired in PRs, but not in mainline. - name: Publish to Chromatic (non-mainline) if: github.ref != 'refs/heads/main' && github.repository_owner == 'coder' uses: chromaui/action@58d9ffb36c90c97a02d061544ecc849cc4a242a9 # v13.1.3 env: NODE_OPTIONS: "--max_old_space_size=4096" STORYBOOK: true with: # Do a fast, testing build for change previews buildScriptName: "storybook:ci" exitOnceUploaded: true # This will prevent CI from failing when Chromatic detects visual changes exitZeroOnChanges: true # Chromatic states its fine to make this token public. See: # https://www.chromatic.com/docs/github-actions#forked-repositories projectToken: 695c25b6cb65 workingDir: "./site" storybookBaseDir: "./site" storybookConfigDir: "./site/.storybook" # Prevent excessive build runs on minor version changes skip: "@(renovate/**|dependabot/**)" # Run TurboSnap to trace file dependencies to related stories # and tell chromatic to only take snapshots of relevant stories onlyChanged: true # Avoid uploading single files, because that's very slow zip: true # This is a separate step for mainline only that auto accepts and changes # instead of holding CI up. Since we squash/merge, this is defensive to # avoid the same changeset from requiring review once squashed into # main. Chromatic is supposed to be able to detect that we use squash # commits, but it's good to be defensive in case, otherwise CI remains # infinitely "in progress" in mainline unless we re-review each build. - name: Publish to Chromatic (mainline) if: github.ref == 'refs/heads/main' && github.repository_owner == 'coder' uses: chromaui/action@58d9ffb36c90c97a02d061544ecc849cc4a242a9 # v13.1.3 env: NODE_OPTIONS: "--max_old_space_size=4096" STORYBOOK: true with: autoAcceptChanges: true # This will prevent CI from failing when Chromatic detects visual changes exitZeroOnChanges: true # Do a full build with documentation for mainline builds buildScriptName: "storybook:build" projectToken: 695c25b6cb65 workingDir: "./site" storybookBaseDir: "./site" storybookConfigDir: "./site/.storybook" # Run TurboSnap to trace file dependencies to related stories # and tell chromatic to only take snapshots of relevant stories onlyChanged: true # Avoid uploading single files, because that's very slow zip: true offlinedocs: name: offlinedocs needs: changes runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} if: needs.changes.outputs.offlinedocs == 'true' || needs.changes.outputs.ci == 'true' || needs.changes.outputs.docs == 'true' steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # 0 is required here for version.sh to work. fetch-depth: 0 - name: Setup Node uses: ./.github/actions/setup-node with: directory: offlinedocs - name: Install Protoc run: | mkdir -p /tmp/proto pushd /tmp/proto curl -L -o protoc.zip https://github.com/protocolbuffers/protobuf/releases/download/v23.4/protoc-23.4-linux-x86_64.zip unzip protoc.zip cp -r ./bin/* /usr/local/bin cp -r ./include /usr/local/bin/include popd - name: Setup Go uses: ./.github/actions/setup-go - name: Install go tools uses: ./.github/actions/setup-go-tools - name: Setup sqlc uses: ./.github/actions/setup-sqlc - name: Format run: | cd offlinedocs pnpm format:check - name: Lint run: | cd offlinedocs pnpm lint - name: Build # no `-j` flag as `make` fails with: # coderd/rbac/object_gen.go:1:1: syntax error: package statement must be first run: | make build/coder_docs_"$(./scripts/version.sh)".tgz required: runs-on: ubuntu-latest needs: - fmt - lint - gen - test-go-pg - test-go-race-pg - test-js - test-e2e - offlinedocs - sqlc-vet # Allow this job to run even if the needed jobs fail, are skipped or # cancelled. if: always() steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Ensure required checks run: | echo "Checking required checks" echo "- fmt: ${{ needs.fmt.result }}" echo "- lint: ${{ needs.lint.result }}" echo "- gen: ${{ needs.gen.result }}" echo "- test-go-pg: ${{ needs.test-go-pg.result }}" echo "- test-go-race-pg: ${{ needs.test-go-race-pg.result }}" echo "- test-js: ${{ needs.test-js.result }}" echo "- test-e2e: ${{ needs.test-e2e.result }}" echo "- offlinedocs: ${{ needs.offlinedocs.result }}" echo # We allow skipped jobs to pass, but not failed or cancelled jobs. if [[ "${{ contains(needs.*.result, 'failure') }}" == "true" || "${{ contains(needs.*.result, 'cancelled') }}" == "true" ]]; then echo "One of the required checks has failed or has been cancelled" exit 1 fi echo "Required checks have passed" # Builds the dylibs and upload it as an artifact so it can be embedded in the main build build-dylib: needs: changes # We always build the dylibs on Go changes to verify we're not merging unbuildable code, # but they need only be signed and uploaded on coder/coder main. if: needs.changes.outputs.go == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' runs-on: ${{ github.repository_owner == 'coder' && 'depot-macos-latest' || 'macos-latest' }} steps: # Harden Runner doesn't work on macOS - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Setup build tools run: | brew install bash gnu-getopt make echo "$(brew --prefix bash)/bin" >> $GITHUB_PATH echo "$(brew --prefix gnu-getopt)/bin" >> $GITHUB_PATH echo "$(brew --prefix make)/libexec/gnubin" >> $GITHUB_PATH - name: Switch XCode Version uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd # v1.6.0 with: xcode-version: "16.1.0" - name: Setup Go uses: ./.github/actions/setup-go - name: Install rcodesign if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }} run: | set -euo pipefail wget -O /tmp/rcodesign.tar.gz https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-macos-universal.tar.gz sudo tar -xzf /tmp/rcodesign.tar.gz \ -C /usr/local/bin \ --strip-components=1 \ apple-codesign-0.22.0-macos-universal/rcodesign rm /tmp/rcodesign.tar.gz - name: Setup Apple Developer certificate and API key if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }} run: | set -euo pipefail touch /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8} chmod 600 /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8} echo "$AC_CERTIFICATE_P12_BASE64" | base64 -d > /tmp/apple_cert.p12 echo "$AC_CERTIFICATE_PASSWORD" > /tmp/apple_cert_password.txt echo "$AC_APIKEY_P8_BASE64" | base64 -d > /tmp/apple_apikey.p8 env: AC_CERTIFICATE_P12_BASE64: ${{ secrets.AC_CERTIFICATE_P12_BASE64 }} AC_CERTIFICATE_PASSWORD: ${{ secrets.AC_CERTIFICATE_PASSWORD }} AC_APIKEY_P8_BASE64: ${{ secrets.AC_APIKEY_P8_BASE64 }} - name: Build dylibs run: | set -euxo pipefail go mod download make gen/mark-fresh make build/coder-dylib env: CODER_SIGN_DARWIN: ${{ github.ref == 'refs/heads/main' && '1' || '0' }} AC_CERTIFICATE_FILE: /tmp/apple_cert.p12 AC_CERTIFICATE_PASSWORD_FILE: /tmp/apple_cert_password.txt - name: Upload build artifacts if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }} uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: dylibs path: | ./build/*.h ./build/*.dylib retention-days: 7 - name: Delete Apple Developer certificate and API key if: ${{ github.repository_owner == 'coder' && github.ref == 'refs/heads/main' }} run: rm -f /tmp/{apple_cert.p12,apple_cert_password.txt,apple_apikey.p8} build: # This builds and publishes ghcr.io/coder/coder-preview:main for each commit # to main branch. needs: - changes - build-dylib if: github.ref == 'refs/heads/main' && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-22.04' }} permissions: # Necessary to push docker images to ghcr.io. packages: write # Necessary for GCP authentication (https://github.com/google-github-actions/setup-gcloud#usage) # Also necessary for keyless cosign (https://docs.sigstore.dev/cosign/signing/overview/) # And for GitHub Actions attestation id-token: write # Required for GitHub Actions attestation attestations: write env: DOCKER_CLI_EXPERIMENTAL: "enabled" outputs: IMAGE: ghcr.io/coder/coder-preview:${{ steps.build-docker.outputs.tag }} steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: GHCR Login uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3.4.0 with: registry: ghcr.io username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Setup Node uses: ./.github/actions/setup-node - name: Setup Go uses: ./.github/actions/setup-go - name: Install rcodesign run: | set -euo pipefail wget -O /tmp/rcodesign.tar.gz https://github.com/indygreg/apple-platform-rs/releases/download/apple-codesign%2F0.22.0/apple-codesign-0.22.0-x86_64-unknown-linux-musl.tar.gz sudo tar -xzf /tmp/rcodesign.tar.gz \ -C /usr/bin \ --strip-components=1 \ apple-codesign-0.22.0-x86_64-unknown-linux-musl/rcodesign rm /tmp/rcodesign.tar.gz - name: Setup Apple Developer certificate run: | set -euo pipefail touch /tmp/{apple_cert.p12,apple_cert_password.txt} chmod 600 /tmp/{apple_cert.p12,apple_cert_password.txt} echo "$AC_CERTIFICATE_P12_BASE64" | base64 -d > /tmp/apple_cert.p12 echo "$AC_CERTIFICATE_PASSWORD" > /tmp/apple_cert_password.txt env: AC_CERTIFICATE_P12_BASE64: ${{ secrets.AC_CERTIFICATE_P12_BASE64 }} AC_CERTIFICATE_PASSWORD: ${{ secrets.AC_CERTIFICATE_PASSWORD }} # Necessary for signing Windows binaries. - name: Setup Java uses: actions/setup-java@c5195efecf7bdfc987ee8bae7a71cb8b11521c00 # v4.7.1 with: distribution: "zulu" java-version: "11.0" - name: Install go-winres run: go install github.com/tc-hib/go-winres@d743268d7ea168077ddd443c4240562d4f5e8c3e # v0.3.3 - name: Install nfpm run: go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.35.1 - name: Install zstd run: sudo apt-get install -y zstd - name: Install cosign uses: ./.github/actions/install-cosign - name: Install syft uses: ./.github/actions/install-syft - name: Setup Windows EV Signing Certificate run: | set -euo pipefail touch /tmp/ev_cert.pem chmod 600 /tmp/ev_cert.pem echo "$EV_SIGNING_CERT" > /tmp/ev_cert.pem wget https://github.com/ebourg/jsign/releases/download/6.0/jsign-6.0.jar -O /tmp/jsign-6.0.jar env: EV_SIGNING_CERT: ${{ secrets.EV_SIGNING_CERT }} # Setup GCloud for signing Windows binaries. - name: Authenticate to Google Cloud id: gcloud_auth uses: google-github-actions/auth@b7593ed2efd1c1617e1b0254da33b86225adb2a5 # v2.1.12 with: workload_identity_provider: ${{ secrets.GCP_CODE_SIGNING_WORKLOAD_ID_PROVIDER }} service_account: ${{ secrets.GCP_CODE_SIGNING_SERVICE_ACCOUNT }} token_format: "access_token" - name: Setup GCloud SDK uses: google-github-actions/setup-gcloud@6a7c903a70c8625ed6700fa299f5ddb4ca6022e9 # v2.1.5 - name: Download dylibs uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0 with: name: dylibs path: ./build - name: Insert dylibs run: | mv ./build/*amd64.dylib ./site/out/bin/coder-vpn-darwin-amd64.dylib mv ./build/*arm64.dylib ./site/out/bin/coder-vpn-darwin-arm64.dylib mv ./build/*arm64.h ./site/out/bin/coder-vpn-darwin-dylib.h - name: Build run: | set -euxo pipefail go mod download version="$(./scripts/version.sh)" tag="main-$(echo "$version" | sed 's/+/-/g')" echo "tag=$tag" >> $GITHUB_OUTPUT make gen/mark-fresh make -j \ build/coder_linux_{amd64,arm64,armv7} \ build/coder_"$version"_windows_amd64.zip \ build/coder_"$version"_linux_amd64.{tar.gz,deb} env: # The Windows slim binary must be signed for Coder Desktop to accept # it. The darwin executables don't need to be signed, but the dylibs # do (see above). CODER_SIGN_WINDOWS: "1" CODER_WINDOWS_RESOURCES: "1" CODER_SIGN_GPG: "1" CODER_GPG_RELEASE_KEY_BASE64: ${{ secrets.GPG_RELEASE_KEY_BASE64 }} CODER_SIGN_DARWIN: "1" AC_CERTIFICATE_FILE: /tmp/apple_cert.p12 AC_CERTIFICATE_PASSWORD_FILE: /tmp/apple_cert_password.txt EV_KEY: ${{ secrets.EV_KEY }} EV_KEYSTORE: ${{ secrets.EV_KEYSTORE }} EV_TSA_URL: ${{ secrets.EV_TSA_URL }} EV_CERTIFICATE_PATH: /tmp/ev_cert.pem GCLOUD_ACCESS_TOKEN: ${{ steps.gcloud_auth.outputs.access_token }} JSIGN_PATH: /tmp/jsign-6.0.jar - name: Build Linux Docker images id: build-docker env: CODER_IMAGE_BASE: ghcr.io/coder/coder-preview CODER_IMAGE_TAG_PREFIX: main DOCKER_CLI_EXPERIMENTAL: "enabled" run: | set -euxo pipefail # build Docker images for each architecture version="$(./scripts/version.sh)" tag="main-$(echo "$version" | sed 's/+/-/g')" echo "tag=$tag" >> $GITHUB_OUTPUT # build images for each architecture # note: omitting the -j argument to avoid race conditions when pushing make build/coder_"$version"_linux_{amd64,arm64,armv7}.tag # only push if we are on main branch if [ "${{ github.ref }}" == "refs/heads/main" ]; then # build and push multi-arch manifest, this depends on the other images # being pushed so will automatically push them # note: omitting the -j argument to avoid race conditions when pushing make push/build/coder_"$version"_linux_{amd64,arm64,armv7}.tag # Define specific tags tags=("$tag" "main" "latest") # Create and push a multi-arch manifest for each tag # we are adding `latest` tag and keeping `main` for backward # compatibality for t in "${tags[@]}"; do ./scripts/build_docker_multiarch.sh \ --push \ --target "ghcr.io/coder/coder-preview:$t" \ --version $version \ $(cat build/coder_"$version"_linux_{amd64,arm64,armv7}.tag) done fi - name: SBOM Generation and Attestation if: github.ref == 'refs/heads/main' continue-on-error: true env: COSIGN_EXPERIMENTAL: 1 run: | set -euxo pipefail # Define image base and tags IMAGE_BASE="ghcr.io/coder/coder-preview" TAGS=("${{ steps.build-docker.outputs.tag }}" "main" "latest") # Generate and attest SBOM for each tag for tag in "${TAGS[@]}"; do IMAGE="${IMAGE_BASE}:${tag}" SBOM_FILE="coder_sbom_${tag//[:\/]/_}.spdx.json" echo "Generating SBOM for image: ${IMAGE}" syft "${IMAGE}" -o spdx-json > "${SBOM_FILE}" echo "Attesting SBOM to image: ${IMAGE}" cosign clean --force=true "${IMAGE}" cosign attest --type spdxjson \ --predicate "${SBOM_FILE}" \ --yes \ "${IMAGE}" done # GitHub attestation provides SLSA provenance for the Docker images, establishing a verifiable # record that these images were built in GitHub Actions with specific inputs and environment. # This complements our existing cosign attestations which focus on SBOMs. # # We attest each tag separately to ensure all tags have proper provenance records. # TODO: Consider refactoring these steps to use a matrix strategy or composite action to reduce duplication # while maintaining the required functionality for each tag. - name: GitHub Attestation for Docker image id: attest_main if: github.ref == 'refs/heads/main' continue-on-error: true uses: actions/attest@ce27ba3b4a9a139d9a20a4a07d69fabb52f1e5bc # v2.4.0 with: subject-name: "ghcr.io/coder/coder-preview:main" predicate-type: "https://slsa.dev/provenance/v1" predicate: | { "buildType": "https://github.com/actions/runner-images/", "builder": { "id": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" }, "invocation": { "configSource": { "uri": "git+https://github.com/${{ github.repository }}@${{ github.ref }}", "digest": { "sha1": "${{ github.sha }}" }, "entryPoint": ".github/workflows/ci.yaml" }, "environment": { "github_workflow": "${{ github.workflow }}", "github_run_id": "${{ github.run_id }}" } }, "metadata": { "buildInvocationID": "${{ github.run_id }}", "completeness": { "environment": true, "materials": true } } } push-to-registry: true - name: GitHub Attestation for Docker image (latest tag) id: attest_latest if: github.ref == 'refs/heads/main' continue-on-error: true uses: actions/attest@ce27ba3b4a9a139d9a20a4a07d69fabb52f1e5bc # v2.4.0 with: subject-name: "ghcr.io/coder/coder-preview:latest" predicate-type: "https://slsa.dev/provenance/v1" predicate: | { "buildType": "https://github.com/actions/runner-images/", "builder": { "id": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" }, "invocation": { "configSource": { "uri": "git+https://github.com/${{ github.repository }}@${{ github.ref }}", "digest": { "sha1": "${{ github.sha }}" }, "entryPoint": ".github/workflows/ci.yaml" }, "environment": { "github_workflow": "${{ github.workflow }}", "github_run_id": "${{ github.run_id }}" } }, "metadata": { "buildInvocationID": "${{ github.run_id }}", "completeness": { "environment": true, "materials": true } } } push-to-registry: true - name: GitHub Attestation for version-specific Docker image id: attest_version if: github.ref == 'refs/heads/main' continue-on-error: true uses: actions/attest@ce27ba3b4a9a139d9a20a4a07d69fabb52f1e5bc # v2.4.0 with: subject-name: "ghcr.io/coder/coder-preview:${{ steps.build-docker.outputs.tag }}" predicate-type: "https://slsa.dev/provenance/v1" predicate: | { "buildType": "https://github.com/actions/runner-images/", "builder": { "id": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}" }, "invocation": { "configSource": { "uri": "git+https://github.com/${{ github.repository }}@${{ github.ref }}", "digest": { "sha1": "${{ github.sha }}" }, "entryPoint": ".github/workflows/ci.yaml" }, "environment": { "github_workflow": "${{ github.workflow }}", "github_run_id": "${{ github.run_id }}" } }, "metadata": { "buildInvocationID": "${{ github.run_id }}", "completeness": { "environment": true, "materials": true } } } push-to-registry: true # Report attestation failures but don't fail the workflow - name: Check attestation status if: github.ref == 'refs/heads/main' run: | if [[ "${{ steps.attest_main.outcome }}" == "failure" ]]; then echo "::warning::GitHub attestation for main tag failed" fi if [[ "${{ steps.attest_latest.outcome }}" == "failure" ]]; then echo "::warning::GitHub attestation for latest tag failed" fi if [[ "${{ steps.attest_version.outcome }}" == "failure" ]]; then echo "::warning::GitHub attestation for version-specific tag failed" fi - name: Prune old images if: github.ref == 'refs/heads/main' uses: vlaurin/action-ghcr-prune@0cf7d39f88546edd31965acba78cdcb0be14d641 # v0.6.0 with: token: ${{ secrets.GITHUB_TOKEN }} organization: coder container: coder-preview keep-younger-than: 7 # days keep-tags: latest keep-tags-regexes: ^pr prune-tags-regexes: | ^main- ^v prune-untagged: true - name: Upload build artifacts if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 with: name: coder path: | ./build/*.zip ./build/*.tar.gz ./build/*.deb retention-days: 7 deploy: name: "deploy" runs-on: ubuntu-latest timeout-minutes: 30 needs: - changes - build if: | github.ref == 'refs/heads/main' && !github.event.pull_request.head.repo.fork && needs.changes.outputs.docs-only == 'false' permissions: contents: read id-token: write steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Authenticate to Google Cloud uses: google-github-actions/auth@b7593ed2efd1c1617e1b0254da33b86225adb2a5 # v2.1.12 with: workload_identity_provider: projects/573722524737/locations/global/workloadIdentityPools/github/providers/github service_account: coder-ci@coder-dogfood.iam.gserviceaccount.com - name: Set up Google Cloud SDK uses: google-github-actions/setup-gcloud@6a7c903a70c8625ed6700fa299f5ddb4ca6022e9 # v2.1.5 - name: Set up Flux CLI uses: fluxcd/flux2/action@6bf37f6a560fd84982d67f853162e4b3c2235edb # v2.6.4 with: # Keep this and the github action up to date with the version of flux installed in dogfood cluster version: "2.5.1" - name: Get Cluster Credentials uses: google-github-actions/get-gke-credentials@8e574c49425fa7efed1e74650a449bfa6a23308a # v2.3.4 with: cluster_name: dogfood-v2 location: us-central1-a project_id: coder-dogfood-v2 - name: Reconcile Flux run: | set -euxo pipefail flux --namespace flux-system reconcile source git flux-system flux --namespace flux-system reconcile source git coder-main flux --namespace flux-system reconcile kustomization flux-system flux --namespace flux-system reconcile kustomization coder flux --namespace flux-system reconcile source chart coder-coder flux --namespace flux-system reconcile source chart coder-coder-provisioner flux --namespace coder reconcile helmrelease coder flux --namespace coder reconcile helmrelease coder-provisioner # Just updating Flux is usually not enough. The Helm release may get # redeployed, but unless something causes the Deployment to update the # pods won't be recreated. It's important that the pods get recreated, # since we use `imagePullPolicy: Always` to ensure we're running the # latest image. - name: Rollout Deployment run: | set -euxo pipefail kubectl --namespace coder rollout restart deployment/coder kubectl --namespace coder rollout status deployment/coder kubectl --namespace coder rollout restart deployment/coder-provisioner kubectl --namespace coder rollout status deployment/coder-provisioner kubectl --namespace coder rollout restart deployment/coder-provisioner-tagged kubectl --namespace coder rollout status deployment/coder-provisioner-tagged deploy-wsproxies: runs-on: ubuntu-latest needs: build if: github.ref == 'refs/heads/main' && !github.event.pull_request.head.repo.fork steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Setup flyctl uses: superfly/flyctl-actions/setup-flyctl@fc53c09e1bc3be6f54706524e3b82c4f462f77be # v1.5 - name: Deploy workspace proxies run: | flyctl deploy --image "$IMAGE" --app paris-coder --config ./.github/fly-wsproxies/paris-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_PARIS" --yes flyctl deploy --image "$IMAGE" --app sydney-coder --config ./.github/fly-wsproxies/sydney-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_SYDNEY" --yes flyctl deploy --image "$IMAGE" --app sao-paulo-coder --config ./.github/fly-wsproxies/sao-paulo-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_SAO_PAULO" --yes flyctl deploy --image "$IMAGE" --app jnb-coder --config ./.github/fly-wsproxies/jnb-coder.toml --env "CODER_PROXY_SESSION_TOKEN=$TOKEN_JNB" --yes env: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} IMAGE: ${{ needs.build.outputs.IMAGE }} TOKEN_PARIS: ${{ secrets.FLY_PARIS_CODER_PROXY_SESSION_TOKEN }} TOKEN_SYDNEY: ${{ secrets.FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN }} TOKEN_SAO_PAULO: ${{ secrets.FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN }} TOKEN_JNB: ${{ secrets.FLY_JNB_CODER_PROXY_SESSION_TOKEN }} # sqlc-vet runs a postgres docker container, runs Coder migrations, and then # runs sqlc-vet to ensure all queries are valid. This catches any mistakes # in migrations or sqlc queries that makes a query unable to be prepared. sqlc-vet: runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} needs: changes if: needs.changes.outputs.db == 'true' || needs.changes.outputs.ci == 'true' || github.ref == 'refs/heads/main' steps: - name: Harden Runner uses: step-security/harden-runner@ec9f2d5744a09debf3a187a3f4f675c53b671911 # v2.13.0 with: egress-policy: audit - name: Checkout uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 1 # We need golang to run the migration main.go - name: Setup Go uses: ./.github/actions/setup-go - name: Setup sqlc uses: ./.github/actions/setup-sqlc - name: Setup and run sqlc vet run: | make sqlc-vet notify-slack-on-failure: needs: - required runs-on: ubuntu-latest if: failure() && github.ref == 'refs/heads/main' steps: - name: Send Slack notification run: | curl -X POST -H 'Content-type: application/json' \ --data '{ "blocks": [ { "type": "header", "text": { "type": "plain_text", "text": "❌ CI Failure in main", "emoji": true } }, { "type": "section", "fields": [ { "type": "mrkdwn", "text": "*Workflow:*\n${{ github.workflow }}" }, { "type": "mrkdwn", "text": "*Committer:*\n${{ github.actor }}" }, { "type": "mrkdwn", "text": "*Commit:*\n${{ github.sha }}" } ] }, { "type": "section", "text": { "type": "mrkdwn", "text": "*View failure:* <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|Click here>" } } ] }' ${{ secrets.CI_FAILURE_SLACK_WEBHOOK }}