feat: bind repository to Linear/Jira/Sentry issue watchers #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Backend Tests | |
| on: | |
| push: | |
| branches: [main] | |
| paths: | |
| - "apps/backend/**" | |
| - ".github/workflows/backend-tests.yml" | |
| - "!**/*.md" | |
| - "!**/*.mdx" | |
| - "!**/*.markdown" | |
| pull_request: | |
| branches: [main] | |
| paths: | |
| - "apps/backend/**" | |
| - ".github/workflows/backend-tests.yml" | |
| - "!**/*.md" | |
| - "!**/*.mdx" | |
| - "!**/*.markdown" | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: true | |
| # Least-privilege default. The Linux `test` job and the Windows `test-windows` | |
| # job only read source and run tests — no PR/issue writes, no release ops. | |
| # `packages: read` is required for the Linux job to pull the kandev-ci | |
| # container image from GHCR (currently public; explicit grant keeps the | |
| # workflow working if the package ever goes private). Declaring any scope | |
| # explicitly zeroes out every unlisted one. | |
| permissions: | |
| contents: read | |
| packages: read | |
| jobs: | |
| test: | |
| name: Run Backend Tests | |
| runs-on: ubuntu-latest | |
| # Pre-baked image bundles Go, golangci-lint, go-licenses, Docker CLI, Node, | |
| # pnpm, and the Playwright base — see .github/docker/ci-base/Dockerfile. | |
| # Skips the per-run setup-go / golangci-lint download steps below. | |
| container: ghcr.io/kdlbs/kandev-ci:build-latest | |
| defaults: | |
| run: | |
| # Container jobs default to `sh` (dash); pin to bash so `set -o pipefail` | |
| # and other bash-isms in the steps below work without per-step overrides. | |
| shell: bash | |
| working-directory: apps/backend | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| with: | |
| fetch-depth: 0 | |
| # actions/checkout under a container job marks the workspace as a safe | |
| # directory automatically, but subsequent `git` invocations from steps | |
| # that run outside the action (e.g. the gofmt diff below) can still hit | |
| # "dubious ownership" when the runner UID differs from the repo owner. | |
| - name: Mark workspace safe for git | |
| shell: bash | |
| working-directory: ${{ github.workspace }} | |
| run: git config --global --add safe.directory "$GITHUB_WORKSPACE" | |
| - name: Cache Go modules | |
| # Homelab self-hosted runners (kept for future re-enablement; the | |
| # `container:` above forces the job onto a github-hosted runner today, | |
| # so this condition is dormant). If homelab is reactivated, split this | |
| # job into a matrix where the homelab variant omits `container:`. | |
| if: ${{ contains(runner.name, 'homelab') }} | |
| uses: actions/cache@v4 | |
| with: | |
| path: | | |
| ~/go/pkg/mod | |
| ~/.cache/go-build | |
| ~/.cache/golangci-lint | |
| key: go-${{ runner.os }}-${{ hashFiles('apps/backend/go.sum') }} | |
| restore-keys: go-${{ runner.os }}- | |
| - name: Build | |
| run: go build -v ./cmd/kandev | |
| - name: Resolve base SHA | |
| shell: bash | |
| working-directory: ${{ github.workspace }} | |
| run: | | |
| set -euo pipefail | |
| if [[ "${{ github.event_name }}" == "pull_request" ]]; then | |
| BASE_SHA="${{ github.event.pull_request.base.sha }}" | |
| else | |
| BASE_SHA="${{ github.event.before }}" | |
| fi | |
| if [[ -z "${BASE_SHA}" || "${BASE_SHA}" == "0000000000000000000000000000000000000000" ]]; then | |
| BASE_SHA="$(git rev-list --max-parents=0 HEAD)" | |
| fi | |
| echo "BASE_SHA=${BASE_SHA}" >> "$GITHUB_ENV" | |
| echo "Base SHA: ${BASE_SHA}" | |
| - name: Check gofmt | |
| shell: bash | |
| run: | | |
| set -euo pipefail | |
| CHANGED_GO_FILES="$( | |
| git diff --name-only --diff-filter=ACMRT "${BASE_SHA}"..."${{ github.sha }}" -- apps/backend \ | |
| | grep -E '^apps/backend/.*\.go$' \ | |
| || true | |
| )" | |
| if [[ -z "${CHANGED_GO_FILES}" ]]; then | |
| echo "No backend Go files changed." | |
| exit 0 | |
| fi | |
| UNFORMATTED="$(echo "${CHANGED_GO_FILES}" | sed 's#^apps/backend/##' | xargs gofmt -l)" | |
| if [[ -n "${UNFORMATTED}" ]]; then | |
| echo "The following changed Go files are not formatted with gofmt:" | |
| echo "${UNFORMATTED}" | |
| exit 1 | |
| fi | |
| - name: Run golangci-lint | |
| # golangci-lint is preinstalled in the kandev-ci image; invoke it | |
| # directly instead of going through `golangci/golangci-lint-action`, | |
| # which would re-download its own binary on every run. `--timeout=5m` | |
| # matches the action's previous implicit default (the binary's own | |
| # default is 1m, which can trip on cold caches). | |
| shell: bash | |
| run: golangci-lint run ./... --new-from-rev="${BASE_SHA}" --timeout=5m | |
| - name: Run tests | |
| run: | | |
| set -o pipefail | |
| go test -v -race -coverprofile=coverage.out -covermode=atomic -json ./... 2>&1 | tee test-results.json | |
| - name: Generate test report | |
| uses: robherley/go-test-action@v0 | |
| if: always() | |
| with: | |
| fromJSONFile: apps/backend/test-results.json | |
| - name: Upload test artifacts | |
| uses: actions/upload-artifact@v5 | |
| if: always() | |
| with: | |
| name: test-results | |
| path: | | |
| apps/backend/coverage.out | |
| apps/backend/test-results.json | |
| retention-days: 30 | |
| postgres-boot: | |
| name: Backend Postgres boot | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| container: ghcr.io/kdlbs/kandev-ci:build-latest | |
| services: | |
| postgres: | |
| image: postgres:16 | |
| env: | |
| POSTGRES_USER: kandev | |
| POSTGRES_PASSWORD: kandev | |
| POSTGRES_DB: kandev_admin | |
| options: >- | |
| --health-cmd "pg_isready -U kandev -d kandev_admin" | |
| --health-interval 5s | |
| --health-timeout 5s | |
| --health-retries 12 | |
| defaults: | |
| run: | |
| shell: bash | |
| working-directory: apps/backend | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Run Postgres boot smoke test | |
| env: | |
| KANDEV_TEST_POSTGRES_DSN: host=postgres port=5432 user=kandev password=kandev dbname=kandev_admin sslmode=disable | |
| run: go test -v -race -run TestPostgresBootInitializesRepositories ./cmd/kandev | |
| test-windows: | |
| name: Backend (windows) | |
| runs-on: windows-latest | |
| timeout-minutes: 15 | |
| # Least-privilege: this job only reads source and runs tests, no PR/issue | |
| # writes or release operations. Flagged by CodeQL workflow audit + matching | |
| # CodeRabbit nitpick. | |
| permissions: | |
| contents: read | |
| defaults: | |
| run: | |
| working-directory: apps/backend | |
| steps: | |
| - name: Checkout code | |
| uses: actions/checkout@v6 | |
| - name: Set up Go | |
| uses: actions/setup-go@v6 | |
| with: | |
| go-version-file: apps/backend/go.mod | |
| cache-dependency-path: apps/backend/go.sum | |
| # Compile-checks every `*_windows.go` file (pty/conpty wrapper, job-object | |
| # launcher, shell, signals, sysprocattr, vscode cleanup, …). The rest of | |
| # the suite is build-tag-gated out automatically. | |
| - name: Build | |
| run: go build ./... | |
| - name: Vet | |
| run: go vet ./... | |
| # Scope to packages with non-trivial Windows-specific code paths. | |
| # Tests that genuinely cannot run on Windows (Unix sockets, POSIX | |
| # symlinks under default Windows ACLs, delete-while-open) call t.Skip | |
| # in source with a documented reason. The shell-fixture tests now use | |
| # a self-hosting Go helper (see testmain_test.go) so they run on | |
| # every platform. | |
| - name: Test windows-sensitive packages | |
| run: go test -race -v ./internal/agentctl/server/process/... ./internal/agent/runtime/agentctl/launcher/... |