Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 89 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: ci

# Run the repo's checks on pull requests, and on pushes to main so a merge that
# breaks something is attributed to the merge rather than to the next PR.
#
# The checks mirror the Makefile targets a contributor runs locally (fmt, vet,
# test), so CI failing means the same command fails on their machine. gofmt is
# checked with -l rather than `make fmt`, which rewrites files: CI must report
# formatting, not silently fix it and test something the author never wrote.
#
# Tests are self-contained — they bind ephemeral localhost ports and set HOME to
# a temp dir, and the container tests assert on generated command strings without
# invoking a real runtime — so no services, credentials, or network egress are
# needed.

on:
pull_request:
push:
branches: [main]

# Read-only: nothing here writes to the repo, and the default token grants more.
permissions:
contents: read

# A force-push or a quick follow-up commit makes an in-flight run obsolete;
# cancel it rather than paying for a result nobody reads. Pushes to main are
# keyed per-ref, so consecutive merges do not cancel each other.
concurrency:
group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}

jobs:
test:
name: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7

- uses: actions/setup-go@v7
with:
# go.mod is the single source of the Go version, as in release.yml.
go-version-file: go.mod

# Before the build, so a formatting failure is reported in seconds rather
# than after the slowest step.
- name: Check formatting
run: |
unformatted="$(gofmt -l .)"
if [ -n "$unformatted" ]; then
echo "These files need gofmt:" >&2
echo "$unformatted" >&2
exit 1
fi

# `go mod tidy` writing nothing proves go.mod and go.sum match the imports.
# Checked against the real files rather than a copy so the diff names them.
- name: Check go.mod is tidy
run: |
go mod tidy
if ! git diff --quiet -- go.mod go.sum; then
echo "go.mod/go.sum are not tidy; run 'make tidy' and commit the result:" >&2
git diff -- go.mod go.sum >&2
exit 1
fi

- name: Vet
run: make vet

- name: Build
run: go build ./...

# -count=1 defeats the test cache, which would otherwise let a green result
# stand in for a run that never happened on this commit.
- name: Test
run: go test ./... -count=1

# A second pass under the race detector. Separate from the run above so a
# plain failure is not reported as a race, and because the suite is fast
# enough (a few seconds) that running it twice costs little.
- name: Test with the race detector
run: go test ./... -race -count=1

# Test order is a real source of flakes here: the suite mutates process
# state (HOME, XDG_CONFIG_HOME, cobra flag values), and cmd/root_test.go
# documents a pflag hazard where a flag's first Set in a later test can
# append rather than replace. Shuffling surfaces that in CI instead of on
# someone's unrelated PR.
- name: Test in a shuffled order
run: go test ./... -count=1 -shuffle=on
19 changes: 19 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,25 @@ rossoctl namespaces list --json
rossoctl -v agents list
```

## Tests

```sh
make test # go test ./...
make vet
gofmt -l . # prints files needing formatting; make fmt rewrites them
go test ./... -race -count=1
go test ./... -count=1 -shuffle=on
```

The suite needs no services, credentials, or network access: tests bind ephemeral
localhost ports and point `HOME` at a temp directory, and the container tests
assert on the command strings they would run rather than invoking a real runtime.

`.github/workflows/ci.yml` runs exactly these on every pull request and on pushes
to `main`, plus a `go mod tidy` check. Shuffled order is included because the
suite mutates process state (`HOME`, cobra flag values), so an order-dependent
test is a real risk — see the pflag hazard documented in `cmd/root_test.go`.

## Full docs

See [the documentation](./docs)