Skip to content

Commit 5d5ce4f

Browse files
gustavobertoiclaude
andcommitted
ci(nightly): scheduled nightly build + smoke + optional pre-release
Add .github/workflows/nightly.yml: a scheduled (07:00 UTC daily) + workflow_dispatch lane that runs the full nightly gate (fmt-check, vet, 4-target CGO-free cross-build, CGO=1 test-race, determinism) via a new `make nightly` target, plus an optional, default-OFF goreleaser snapshot pre-release job gated on the NIGHTLY_PRERELEASE repo variable that uploads artifacts (never a git tag, never a semver release). Both jobs are guarded by `github.repository == 'open-source-cloud/devstack'` so scheduled/dispatch runs no-op on forks. The pre-release path publishes goreleaser SNAPSHOT artifacts as workflow artifacts only — it never creates a `nightly` git tag, which would confuse goreleaser's git describe and break release-dryrun on every PR (MEMORY: no-non-semver-tags). Also adds `make cross` (4-target build smoke) and `make nightly` (make ci + cross + determinism) to mirror the workflow locally. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent fd90f84 commit 5d5ce4f

2 files changed

Lines changed: 92 additions & 1 deletion

File tree

‎.github/workflows/nightly.yml‎

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
name: Nightly
2+
3+
# Scheduled nightly health build (spec 07 toolchain, mirrors CI). This lane exists
4+
# to catch drift that the per-PR CI can miss — a new Go point release, a transitive
5+
# dependency that breaks a cross-compile target, or non-deterministic generation —
6+
# BEFORE it bites a real release. It runs the full `make ci` equivalent plus the
7+
# 4-target CGO-free cross-build and the determinism assertion.
8+
#
9+
# It NEVER cuts a real semver release and NEVER pushes a git tag: a stray non-semver
10+
# tag (e.g. `nightly`) confuses `git describe` in goreleaser and breaks the
11+
# release-dryrun lane on every PR (MEMORY: no-non-semver-tags). The optional
12+
# pre-release path (default OFF) publishes goreleaser *snapshot* artifacts as
13+
# workflow artifacts only — no tag is ever created.
14+
15+
on:
16+
schedule:
17+
- cron: "0 7 * * *" # 07:00 UTC daily
18+
workflow_dispatch: {}
19+
20+
permissions:
21+
contents: read
22+
23+
concurrency:
24+
group: nightly-${{ github.ref }}
25+
cancel-in-progress: true
26+
27+
env:
28+
# Single enforced Go toolchain floor (DECISIONS, ARCHITECTURE §7.8) — same as CI.
29+
GO_VERSION: "1.25"
30+
31+
jobs:
32+
# The full nightly gate. Guarded so scheduled runs no-op on forks (a fork inherits
33+
# the schedule but not the org repo name); workflow_dispatch on a fork is likewise
34+
# skipped, keeping this lane a first-party-only signal.
35+
nightly:
36+
if: github.repository == 'open-source-cloud/devstack'
37+
runs-on: ubuntu-latest
38+
steps:
39+
- uses: actions/checkout@v4
40+
- uses: actions/setup-go@v5
41+
with:
42+
go-version: ${{ env.GO_VERSION }}
43+
check-latest: true # nightly's whole point: pick up new Go point releases
44+
cache: true # GOMODCACHE + GOCACHE, keyed by go.sum
45+
46+
# `make ci` (fmt-check + vet + CGO=0 build + CGO=1 test-race) plus the 4-target
47+
# cross-build and the byte-identical generation assertion, all via one target.
48+
- name: nightly gate (fmt-check + vet + cross-build + test-race + determinism)
49+
run: make nightly
50+
51+
# Optional rolling pre-release. Default OFF: enable by setting the repo variable
52+
# gh variable set NIGHTLY_PRERELEASE --body true
53+
# Produces goreleaser SNAPSHOT artifacts (no real version, no git tag) and uploads
54+
# them as workflow artifacts for manual smoke-testing of a nightly build. We do NOT
55+
# create a GitHub Release or a `nightly` git tag — that would trip release-dryrun.
56+
prerelease:
57+
needs: nightly
58+
if: github.repository == 'open-source-cloud/devstack' && vars.NIGHTLY_PRERELEASE == 'true'
59+
runs-on: ubuntu-latest
60+
steps:
61+
- uses: actions/checkout@v4
62+
with:
63+
fetch-depth: 0 # full history for goreleaser's snapshot versioning
64+
- uses: actions/setup-go@v5
65+
with:
66+
go-version: ${{ env.GO_VERSION }}
67+
check-latest: true
68+
cache: true
69+
- uses: goreleaser/goreleaser-action@v6
70+
with:
71+
version: "~> v2"
72+
args: release --snapshot --clean
73+
- name: upload nightly snapshot artifacts
74+
uses: actions/upload-artifact@v4
75+
with:
76+
name: nightly-snapshot
77+
path: |
78+
dist/*.tar.gz
79+
dist/*.deb
80+
dist/*.rpm
81+
dist/checksums.txt
82+
retention-days: 7
83+
if-no-files-found: error

‎Makefile‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ BINDIR ?= $(or $(XDG_BIN_HOME),$(PREFIX)/bin)
2121

2222
# The release binary MUST be CGO-free (static), but `go test -race` REQUIRES cgo.
2323
# So CGO is set per-target, never globally.
24-
.PHONY: build run test test-race integration e2e test-one vet fmt fmt-check lint tidy vuln clean snapshot ci determinism install uninstall smoke help
24+
.PHONY: build run test test-race integration e2e test-one vet fmt fmt-check lint tidy vuln clean snapshot cross ci nightly determinism install uninstall smoke help
2525

2626
build: ## Build the static binary into ./dist
2727
CGO_ENABLED=0 go build -trimpath -ldflags '$(LDFLAGS)' -o dist/$(BINARY) ./cmd/devstack
@@ -63,8 +63,16 @@ tidy: ## go mod tidy
6363
snapshot: ## Local goreleaser snapshot build (no publish)
6464
go run github.com/goreleaser/goreleaser/v2@latest release --snapshot --clean
6565

66+
cross: ## Cross-compile the 4 CGO-free release targets (build-only, output discarded)
67+
@set -eu; for t in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64; do \
68+
echo "-> $$t"; \
69+
GOOS=$${t%/*} GOARCH=$${t#*/} CGO_ENABLED=0 go build -trimpath -ldflags '$(LDFLAGS)' -o /dev/null ./cmd/devstack; \
70+
done
71+
6672
ci: fmt-check vet build test-race ## What CI runs
6773

74+
nightly: fmt-check vet cross test-race determinism ## Full nightly gate (make ci + 4-target cross-build + determinism)
75+
6876
determinism: build ## Assert generation is byte-identical across runs/paths (M1, spec 02)
6977
@set -eu; \
7078
bin="$$PWD/dist/$(BINARY)"; \

0 commit comments

Comments
 (0)