CI/CD Pipelines
Aveloxis uses GitHub Actions for continuous integration and deployment. All workflows are in .github/workflows/.
Workflows
Tests (test.yml)
Trigger: Every push to any branch, every PR to main.
Runs go test -race ./... with race detection enabled. Uploads coverage artifact on main branch pushes.
Tests split into two tiers:
Unit tier (default, always runs). Pure Go, no database, covers source-contract tests and logic that can be exercised in-process.
Integration tier (gated by
AVELOXIS_TEST_DB). Runs SQL against a live Postgres. Tests skip with a clear message when the env var is unset, so localgo test ./...stays fast. To run locally:# Create a scratch DB on your existing Postgres instance. psql -h localhost -U aveloxis -d postgres -c "CREATE DATABASE aveloxis_test;" # Apply the schema. AVELOXIS_DBNAME=aveloxis_test aveloxis migrate --config /path/to/test.json # Run only the integration suite. AVELOXIS_TEST_DB="host=localhost port=5432 user=aveloxis password=... dbname=aveloxis_test sslmode=prefer" \ go test ./... -run 'Integration|RealignDueDates_|CompleteJob_' -v # Drop when done. psql -h localhost -U aveloxis -d postgres -c "DROP DATABASE aveloxis_test;"
Never run the integration suite against the production
aveloxisdatabase.RealignDueDatesis unscoped — it updates everystatus='queued'row in the queue, and an integration test that passes7*24hwould silently realign the entire fleet.Conventions for adding integration tests:
Name the test
TestX_YIntegrationor put it in a file ending in_integration_test.go.Seed rows with nanosecond-suffixed synthetic slugs (see
seedRealignRepoininternal/db/queue_realign_integration_test.go) so parallel or repeated runs do not collide onON CONFLICTconstraints.Prefer strict-equality assertions (
approxEqual(..., time.Millisecond)) where the SQL does not involveNOW(), since source-text tests cannot catch interval-arithmetic drift and this is where runtime regressions hide.
Lint (lint.yml)
Trigger: Every PR to main.
Runs golangci-lint with --only-new-issues so existing code doesn’t block PRs. 5-minute timeout for large codebases.
CodeQL (codeql.yml)
Trigger: Every PR to main, plus weekly Monday scan.
Runs GitHub’s CodeQL security analysis with security-extended query suite for Go. Results appear in the Security tab on GitHub.
Container Build (container-build.yml)
Trigger: Every PR to main.
Tests building the Docker image on:
Ubuntu with Docker
Ubuntu with Podman
macOS with Docker (via colima)
Verifies the binary runs inside the container (aveloxis version). Does NOT push images.
Docker Publish (docker-publish.yml)
Trigger: Every push to main.
Builds and publishes Docker images to GitHub Container Registry (ghcr.io/aveloxis/aveloxis). Tags:
latest— always the most recent main buildGit SHA — for pinning to a specific commit
Date stamp (
YYYY.MM.DD) — for pinning to a specific day
Status Badges
All workflows have status badges at the top of the README:
Dockerfile
The multi-stage Dockerfile in the repo root:
Builder stage —
golang:1.25-alpine, downloads dependencies, builds a static binaryRuntime stage —
alpine:3.20, copies the binary, includes git/curl/ca-certificates for facade and libyear phases
Exposed ports: 5555 (monitor), 8082 (web), 8383 (API).
Default command: aveloxis serve --workers 4 --monitor :5555
Running in Docker
# Pull from GHCR
docker pull ghcr.io/aveloxis/aveloxis:latest
# Start all three processes
docker run -d --name aveloxis-serve \
-v ./aveloxis.json:/app/aveloxis.json \
-v /data/repos:/data \
-p 5555:5555 \
ghcr.io/aveloxis/aveloxis:latest serve --workers 40
docker run -d --name aveloxis-web \
-v ./aveloxis.json:/app/aveloxis.json \
-p 8082:8082 \
ghcr.io/aveloxis/aveloxis:latest web
docker run -d --name aveloxis-api \
-v ./aveloxis.json:/app/aveloxis.json \
-p 8383:8383 \
ghcr.io/aveloxis/aveloxis:latest api
All containers share the same aveloxis.json and connect to the same PostgreSQL database.