name: ci on: push: branches: - main - release/* 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - name: check changed files uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4.0.1 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" # Icon and theme files tested by Go (scripts/gensite): - "site/static/icon/**" - "site/src/theme/**" # Main repo directories for completeness in case other files are # touched: - "agent/**" - "aibridge/**" - "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/**" offlinedocs: - "offlinedocs/**" tailnet-integration: - "tailnet/**" - "go.mod" - "go.sum" - id: debug run: | echo "$FILTER_JSON" env: FILTER_JSON: ${{ toJSON(steps.filter.outputs) }} # 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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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=$(grep -Eo 'GOLANGCI_LINT_VERSION=\S+' dogfood/coder/ubuntu-26.04/Dockerfile | cut -d '=' -f 2) ./.github/scripts/retry.sh -- 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@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 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@631208b7aac2daa8b707f55e7331f9112b0e062d # v1.44.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@dda3372f752e03dde6b3237bc9431cdc2f7a02a2 # v5.0.0 with: version: v3.9.2 continue-on-error: true id: setup-helm - name: Install helm (fallback) if: steps.setup-helm.outcome == 'failure' # Fallback to Buildkite's apt repository if get.helm.sh is down. # See: https://github.com/coder/internal/issues/1109 run: | set -euo pipefail curl -fsSL https://packages.buildkite.com/helm-linux/helm-debian/gpgkey | gpg --dearmor | sudo tee /usr/share/keyrings/helm.gpg > /dev/null echo "deb [signed-by=/usr/share/keyrings/helm.gpg] https://packages.buildkite.com/helm-linux/helm-debian/any/ any main" | sudo tee /etc/apt/sources.list.d/helm-stable-debian.list sudo apt-get update sudo apt-get install -y helm=3.9.2-1 - name: Verify helm version run: helm version --short - 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 lint-actions: needs: changes # Only run this job if changes to CI workflow files are detected. This job # can flake as it reaches out to GitHub to check referenced actions. if: needs.changes.outputs.ci == 'true' runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} steps: - name: Harden Runner uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - name: Setup Go uses: ./.github/actions/setup-go - name: make lint/actions run: make --output-sync=line -j lint/actions env: # Used by zizmor to lint third-party GitHub actions. GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} gen: timeout-minutes: 20 runs-on: ${{ github.repository_owner == 'coder' && 'depot-ubuntu-22.04-8' || 'ubuntu-latest' }} if: ${{ !cancelled() }} steps: - name: Harden Runner uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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 sudo cp -r ./bin/* /usr/local/bin sudo cp -r ./include /usr/local/bin/include popd - name: make gen timeout-minutes: 8 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 make -j --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: 20 steps: - name: Harden Runner uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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: ./.github/scripts/retry.sh -- go install mvdan.cc/sh/v3/cmd/shfmt@v3.7.0 - name: make fmt timeout-minutes: 7 run: | 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` 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: fail-fast: false matrix: os: - ubuntu-latest - macos-latest - windows-2022 steps: - name: Harden Runner uses: step-security/harden-runner@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 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 -Fc "Indexing enabled" || true; }) 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 # v0.1.0 - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - name: Setup Go Paths id: go-paths uses: ./.github/actions/setup-go-paths - name: Setup GNU tools (macOS) uses: ./.github/actions/setup-gnu-tools - name: Setup Go uses: ./.github/actions/setup-go with: use-cache: true - 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: Normalize Terraform Path for Caching shell: bash # Terraform gets installed in a random directory, so we need to normalize # the path or many cached tests will be invalidated. run: | mkdir -p "$RUNNER_TEMP/sym" source scripts/normalize_path.sh normalize_path_with_symlinks "$RUNNER_TEMP/sym" "$(dirname "$(which terraform)")" - name: Setup RAM disk for Embedded Postgres (Windows) if: runner.os == 'Windows' shell: bash # The default C: drive is extremely slow: # https://github.com/actions/runner-images/issues/8755 run: mkdir -p "R:/temp/embedded-pg" - name: Setup RAM disk for Embedded Postgres (macOS) if: runner.os == 'macOS' shell: bash run: | # Postgres runs faster on a ramdisk on macOS. mkdir -p /tmp/tmpfs sudo mount_tmpfs -o noowners -s 8g /tmp/tmpfs # macOS will output "The default interactive shell is now zsh" intermittently in CI. touch ~/.bash_profile && echo "export BASH_SILENCE_DEPRECATION_WARNING=1" >> ~/.bash_profile - name: Increase PTY limit (macOS) if: runner.os == 'macOS' shell: bash run: | # Increase PTY limit to avoid exhaustion during tests. # Default is 511; 999 is the maximum value on CI runner. sudo sysctl -w kern.tty.ptmx_max=999 - name: Test with PostgreSQL Database (Linux) if: runner.os == 'Linux' uses: ./.github/actions/test-go-pg with: postgres-version: "13" # Our Linux runners have 8 cores. test-parallelism-packages: "8" test-parallelism-tests: "8" # By default, run tests with cache for improved speed (possibly at the expense of correctness). # On main, run tests without cache for the inverse. test-count: ${{ github.ref == 'refs/heads/main' && '1' || '' }} - name: Test with PostgreSQL Database (macOS) if: runner.os == 'macOS' uses: ./.github/actions/test-go-pg with: postgres-version: "13" # Our macOS runners have 8 cores. # Even though this parallelism seems high, we've observed relatively low flakiness in the past. # See https://github.com/coder/coder/pull/21091#discussion_r2609891540. test-parallelism-packages: "8" test-parallelism-tests: "16" # By default, run tests with cache for improved speed (possibly at the expense of correctness). # On main, run tests without cache for the inverse. test-count: ${{ github.ref == 'refs/heads/main' && '1' || '' }} # Only the CLI and Agent are officially supported on macOS; the rest are too flaky. test-packages: "./cli/... ./enterprise/cli/... ./agent/..." embedded-pg-path: "/tmp/tmpfs/embedded-pg" embedded-pg-cache: ${{ steps.embedded-pg-cache.outputs.embedded-pg-cache }} - name: Test with PostgreSQL Database (Windows) if: runner.os == 'Windows' uses: ./.github/actions/test-go-pg with: postgres-version: "13" # 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. test-parallelism-packages: "8" test-parallelism-tests: "16" # By default, run tests with cache for improved speed (possibly at the expense of correctness). # On main, run tests without cache for the inverse. test-count: ${{ github.ref == 'refs/heads/main' && '1' || '' }} # Only the CLI and Agent are officially supported on Windows; the rest are too flaky. test-packages: "./cli/... ./enterprise/cli/... ./agent/..." embedded-pg-path: "R:/temp/embedded-pg" embedded-pg-cache: ${{ steps.embedded-pg-cache.outputs.embedded-pg-cache }} - name: Upload failed test db dumps uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: failed-test-db-dump-${{matrix.os}} path: "**/*.test.sql" - 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 }} 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` 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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: Normalize Terraform Path for Caching shell: bash # Terraform gets installed in a random directory, so we need to normalize # the path or many cached tests will be invalidated. run: | mkdir -p "$RUNNER_TEMP/sym" source scripts/normalize_path.sh normalize_path_with_symlinks "$RUNNER_TEMP/sym" "$(dirname "$(which terraform)")" - name: Test with PostgreSQL Database uses: ./.github/actions/test-go-pg with: postgres-version: "17" # Our Linux runners have 8 cores. test-parallelism-packages: "8" test-parallelism-tests: "8" # By default, run tests with cache for improved speed (possibly at the expense of correctness). # On main, run tests without cache for the inverse. test-count: ${{ github.ref == 'refs/heads/main' && '1' || '' }} - 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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 }} - name: Normalize Terraform Path for Caching shell: bash # Terraform gets installed in a random directory, so we need to normalize # the path or many cached tests will be invalidated. run: | mkdir -p "$RUNNER_TEMP/sym" source scripts/normalize_path.sh normalize_path_with_symlinks "$RUNNER_TEMP/sym" "$(dirname "$(which terraform)")" # 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 # Our Linux runners have 16 cores, but we reduce parallelism since race detection adds a lot of overhead. # We aim to have parallelism match CPU count (4*4=16) to avoid making flakes worse. - name: Run Tests uses: ./.github/actions/test-go-pg with: postgres-version: "17" test-parallelism-packages: "4" test-parallelism-tests: "4" race-detection: "true" - 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: failed-test-videos${{ matrix.variant.premium && '-premium' || '' }} path: ./site/test-results/**/*.webm retention-days: 7 - name: Upload debug log if: always() && github.actor != 'dependabot[bot]' && runner.os == 'Linux' && !github.event.pull_request.head.repo.fork uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coderd-debug-logs${{ matrix.variant.premium && '-premium' || '' }} path: ./site/e2e/test-results/debug.log 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@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.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 }} persist-credentials: false - 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@f191a0224b10e1a38b2091cefb7b7a2337009116 # v16.0.0 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@f191a0224b10e1a38b2091cefb7b7a2337009116 # v16.0.0 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: # 0 is required here for version.sh to work. fetch-depth: 0 persist-credentials: false - 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 sudo cp -r ./bin/* /usr/local/bin sudo 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 - name: Check for unstaged files run: ./scripts/check_unstaged.sh required: runs-on: ubuntu-latest needs: - changes - fmt - lint - lint-actions - gen - test-go-pg - test-go-pg-17 - test-go-race-pg - test-js - test-e2e - offlinedocs - sqlc-vet - check-build # 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Ensure required checks run: | # zizmor: ignore[template-injection] We're just reading needs.x.result here, no risk of injection echo "Checking required checks" echo "- changes: ${{ needs.changes.result }}" echo "- fmt: ${{ needs.fmt.result }}" echo "- lint: ${{ needs.lint.result }}" echo "- lint-actions: ${{ needs.lint-actions.result }}" echo "- gen: ${{ needs.gen.result }}" echo "- test-go-pg: ${{ needs.test-go-pg.result }}" echo "- test-go-pg-17: ${{ needs.test-go-pg-17.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 "- check-build: ${{ needs.check-build.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" check-build: # This job runs make build to verify compilation on PRs. # The build doesn't get signed, and is not suitable for usage, unlike the # `build` job that runs on main. needs: changes if: needs.changes.outputs.go == '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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 persist-credentials: false - name: Setup Node uses: ./.github/actions/setup-node - name: Setup Go uses: ./.github/actions/setup-go - name: Install go-winres run: ./.github/scripts/retry.sh -- go install github.com/tc-hib/go-winres@d743268d7ea168077ddd443c4240562d4f5e8c3e # v0.3.3 - name: Install nfpm run: ./.github/scripts/retry.sh -- go install github.com/goreleaser/nfpm/v2/cmd/nfpm@v2.35.1 - name: Install zstd run: sudo apt-get install -y zstd - name: Build run: | set -euxo pipefail ./.github/scripts/retry.sh -- go mod download make gen/mark-fresh make build build: # This builds and publishes ghcr.io/coder/coder-preview:main for each commit # to main branch. needs: - changes if: (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 0 persist-credentials: false - name: GHCR Login uses: docker/login-action@b45d80f862d83dbcd57f89517bcf500b2ab88fb2 # v4.0.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 with: use-cache: false - 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@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0 with: distribution: "zulu" java-version: "11.0" - name: Install go-winres run: ./.github/scripts/retry.sh -- go install github.com/tc-hib/go-winres@d743268d7ea168077ddd443c4240562d4f5e8c3e # v0.3.3 - name: Install nfpm run: ./.github/scripts/retry.sh -- 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@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 with: workload_identity_provider: ${{ vars.GCP_CODE_SIGNING_WORKLOAD_ID_PROVIDER }} service_account: ${{ vars.GCP_CODE_SIGNING_SERVICE_ACCOUNT }} token_format: "access_token" - name: Setup GCloud SDK uses: google-github-actions/setup-gcloud@aa5489c8933f4cc7a4f7d45035b3b1440c9c10db # v3.0.1 - name: Build run: | set -euxo pipefail ./.github/scripts/retry.sh -- go mod download version="$(./scripts/version.sh)" tag="main-${version//+/-}" 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,arm64,armv7}.{tar.gz,deb} env: # The Windows and Darwin slim binaries must be signed for Coder # Desktop to accept them. 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 # Enable React profiling build and discoverable source maps # for the dogfood deployment (dev.coder.com). This also # applies to release/* branch builds, but those still # produce coder-preview images, not release images. # Release images are built by release.yaml (no profiling). CODER_REACT_PROFILING: "true" # Free up disk space before building Docker images. The preceding # Build step produces ~2 GB of binaries and packages, the Go build # cache is ~1.3 GB, and node_modules is ~500 MB. Docker image # builds, pushes, and SBOM generation need headroom that isn't # available without reclaiming some of that space. - name: Clean up build cache run: | set -euxo pipefail # Go caches are no longer needed — binaries are already compiled. go clean -cache -modcache # Remove .apk and .rpm packages that are not uploaded as # artifacts and were only built as make prerequisites. rm -f ./build/*.apk ./build/*.rpm - name: Build Linux Docker images id: build-docker env: CODER_IMAGE_BASE: ghcr.io/coder/coder-preview DOCKER_CLI_EXPERIMENTAL: "enabled" # Skip building .deb/.rpm/.apk/.tar.gz as prerequisites for # the Docker image targets — they were already built above. DOCKER_IMAGE_NO_PREREQUISITES: "true" run: | set -euxo pipefail # build Docker images for each architecture version="$(./scripts/version.sh)" tag="${version//+/-}" 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 or release branch if [[ "${GITHUB_REF}" == "refs/heads/main" || "${GITHUB_REF}" == refs/heads/release/* ]]; 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") if [ "${GITHUB_REF}" == "refs/heads/main" ]; then tags+=("main" "latest") elif [[ "${GITHUB_REF}" == refs/heads/release/* ]]; then tags+=("release-${GITHUB_REF#refs/heads/release/}") fi # 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 echo "Pushing multi-arch manifest for tag: $t" # shellcheck disable=SC2046 ./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 BUILD_TAG: ${{ steps.build-docker.outputs.tag }} run: | set -euxo pipefail # Define image base and tags IMAGE_BASE="ghcr.io/coder/coder-preview" TAGS=("${BUILD_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 - name: Resolve Docker image digests for attestation id: docker_digests if: github.ref == 'refs/heads/main' continue-on-error: true env: IMAGE_BASE: ghcr.io/coder/coder-preview BUILD_TAG: ${{ steps.build-docker.outputs.tag }} run: | set -euxo pipefail main_digest=$(docker buildx imagetools inspect --raw "${IMAGE_BASE}:main" | sha256sum | awk '{print "sha256:"$1}') echo "main_digest=${main_digest}" >> "$GITHUB_OUTPUT" latest_digest=$(docker buildx imagetools inspect --raw "${IMAGE_BASE}:latest" | sha256sum | awk '{print "sha256:"$1}') echo "latest_digest=${latest_digest}" >> "$GITHUB_OUTPUT" version_digest=$(docker buildx imagetools inspect --raw "${IMAGE_BASE}:${BUILD_TAG}" | sha256sum | awk '{print "sha256:"$1}') echo "version_digest=${version_digest}" >> "$GITHUB_OUTPUT" - name: GitHub Attestation for Docker image id: attest_main if: github.ref == 'refs/heads/main' && steps.docker_digests.outputs.main_digest != '' continue-on-error: true uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 with: subject-name: ghcr.io/coder/coder-preview subject-digest: ${{ steps.docker_digests.outputs.main_digest }} push-to-registry: true - name: GitHub Attestation for Docker image (latest tag) id: attest_latest if: github.ref == 'refs/heads/main' && steps.docker_digests.outputs.latest_digest != '' continue-on-error: true uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 with: subject-name: ghcr.io/coder/coder-preview subject-digest: ${{ steps.docker_digests.outputs.latest_digest }} push-to-registry: true - name: GitHub Attestation for version-specific Docker image id: attest_version if: github.ref == 'refs/heads/main' && steps.docker_digests.outputs.version_digest != '' continue-on-error: true uses: actions/attest@59d89421af93a897026c735860bf21b6eb4f7b26 # v4.1.0 with: subject-name: ghcr.io/coder/coder-preview subject-digest: ${{ steps.docker_digests.outputs.version_digest }} push-to-registry: true # Report attestation failures but don't fail the workflow - name: Check attestation status if: github.ref == 'refs/heads/main' run: | # zizmor: ignore[template-injection] We're just reading steps.attest_x.outcome here, no risk of injection 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 artifact (coder-linux-amd64.tar.gz) if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coder-linux-amd64.tar.gz path: ./build/*_linux_amd64.tar.gz retention-days: 7 - name: Upload build artifact (coder-linux-amd64.deb) if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coder-linux-amd64.deb path: ./build/*_linux_amd64.deb retention-days: 7 - name: Upload build artifact (coder-linux-arm64.tar.gz) if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coder-linux-arm64.tar.gz path: ./build/*_linux_arm64.tar.gz retention-days: 7 - name: Upload build artifact (coder-linux-arm64.deb) if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coder-linux-arm64.deb path: ./build/*_linux_arm64.deb retention-days: 7 - name: Upload build artifact (coder-linux-armv7.tar.gz) if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coder-linux-armv7.tar.gz path: ./build/*_linux_armv7.tar.gz retention-days: 7 - name: Upload build artifact (coder-linux-armv7.deb) if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coder-linux-armv7.deb path: ./build/*_linux_armv7.deb retention-days: 7 - name: Upload build artifact (coder-windows-amd64.zip) if: github.ref == 'refs/heads/main' uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0 with: name: coder-windows-amd64.zip path: ./build/*_windows_amd64.zip retention-days: 7 # Deploy is handled in deploy.yaml so we can apply concurrency limits. deploy: needs: - changes - build if: | (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/heads/release/')) && needs.changes.outputs.docs-only == 'false' && !github.event.pull_request.head.repo.fork uses: ./.github/workflows/deploy.yaml with: image: ${{ needs.build.outputs.IMAGE }} permissions: contents: read id-token: write packages: write # to retag image as dogfood secrets: FLY_API_TOKEN: ${{ secrets.FLY_API_TOKEN }} FLY_PARIS_CODER_PROXY_SESSION_TOKEN: ${{ secrets.FLY_PARIS_CODER_PROXY_SESSION_TOKEN }} FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN: ${{ secrets.FLY_SYDNEY_CODER_PROXY_SESSION_TOKEN }} FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN: ${{ secrets.FLY_SAO_PAULO_CODER_PROXY_SESSION_TOKEN }} FLY_JNB_CODER_PROXY_SESSION_TOKEN: ${{ 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@fe104658747b27e96e4f7e80cd0a94068e53901d # v2.16.1 with: egress-policy: audit - name: Checkout uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: fetch-depth: 1 persist-credentials: false - 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: | ESCAPED_PROMPT=$(printf "%s" "<@U09LQ75AHKR> $BLINK_CI_FAILURE_PROMPT" | jq -Rsa .) 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", "text": { "type": "mrkdwn", "text": "*View failure:* <'"${RUN_URL}"'|Click here>" } }, { "type": "section", "text": { "type": "mrkdwn", "text": '"$ESCAPED_PROMPT"' } } ] }' "${SLACK_WEBHOOK}" env: SLACK_WEBHOOK: ${{ secrets.CI_FAILURE_SLACK_WEBHOOK }} RUN_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" BLINK_CI_FAILURE_PROMPT: ${{ vars.BLINK_CI_FAILURE_PROMPT }}