Skip to content

Commit 5d1cfa7

Browse files
author
devituz
committed
ci: GitHub Actions workflows (CI, release, CodeQL) + Dependabot
CI workflow (.github/workflows/ci.yml): - Test matrix: ubuntu-latest + macos-latest, Go 1.25 - Builds and tests core module + adapters/gin separately - -race -count=1 for both - Lint job: gofmt check, go vet (core + adapter), staticcheck - Bench sanity: -benchtime=1x to verify benchmarks still compile - Per-branch concurrency cancellation (no queue buildup on rapid pushes) Release workflow (.github/workflows/release.yml): - Triggers on `v*.*.*` semver tags (skips adapters/gin/v* — those are pure Go-module markers, no binary) - Cross-platform matrix: linux-amd64, darwin-amd64, darwin-arm64, windows-amd64. Each builds on native runner so CGO + sqlite3 just work - Outputs lago + artisan binaries with version baked via -ldflags - Aggregates artifacts → SHA-256 checksums → softprops/action-gh-release - Warms the Go module proxy after release so `go get @latest` resolves the new tag immediately CodeQL (.github/workflows/codeql.yml): - Runs on push/PR + weekly Monday cron — catches dependency CVEs - security-and-quality query set, Go autobuild - Posts findings to GitHub Security tab Dependabot (.github/dependabot.yml): - Weekly Go module updates for / and /adapters/gin (grouped PRs) - Monthly GitHub Actions updates - Asia/Tashkent timezone for PR opening
1 parent 24c68cf commit 5d1cfa7

4 files changed

Lines changed: 279 additions & 0 deletions

File tree

.github/dependabot.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
version: 2
2+
3+
updates:
4+
# Core Go module
5+
- package-ecosystem: gomod
6+
directory: '/'
7+
schedule:
8+
interval: weekly
9+
day: monday
10+
time: '08:00'
11+
timezone: Asia/Tashkent
12+
open-pull-requests-limit: 5
13+
commit-message:
14+
prefix: 'chore(deps)'
15+
include: scope
16+
groups:
17+
go-deps:
18+
patterns: ['*']
19+
20+
# adapters/gin sub-module
21+
- package-ecosystem: gomod
22+
directory: '/adapters/gin'
23+
schedule:
24+
interval: weekly
25+
day: monday
26+
time: '08:00'
27+
timezone: Asia/Tashkent
28+
open-pull-requests-limit: 5
29+
commit-message:
30+
prefix: 'chore(deps/gin)'
31+
include: scope
32+
groups:
33+
gin-deps:
34+
patterns: ['*']
35+
36+
# GitHub Actions themselves
37+
- package-ecosystem: github-actions
38+
directory: '/'
39+
schedule:
40+
interval: monthly
41+
day: monday
42+
time: '08:00'
43+
timezone: Asia/Tashkent
44+
commit-message:
45+
prefix: 'chore(ci)'
46+
include: scope

.github/workflows/ci.yml

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
# Cancel superseded runs from the same PR/branch so the queue stays short.
10+
concurrency:
11+
group: ci-${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
test:
16+
name: Test (${{ matrix.os }})
17+
runs-on: ${{ matrix.os }}
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
os: [ubuntu-latest, macos-latest]
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- uses: actions/setup-go@v5
26+
with:
27+
go-version: '1.25'
28+
cache: true
29+
30+
- name: Build (core)
31+
run: go build ./...
32+
33+
- name: Test (core)
34+
run: go test -race -count=1 -timeout 5m ./...
35+
36+
- name: Build (adapters/gin)
37+
working-directory: adapters/gin
38+
run: go build ./...
39+
40+
- name: Test (adapters/gin)
41+
working-directory: adapters/gin
42+
run: go test -race -count=1 -timeout 5m ./...
43+
44+
lint:
45+
name: Lint
46+
runs-on: ubuntu-latest
47+
steps:
48+
- uses: actions/checkout@v4
49+
50+
- uses: actions/setup-go@v5
51+
with:
52+
go-version: '1.25'
53+
cache: true
54+
55+
- name: gofmt
56+
run: |
57+
out=$(gofmt -l . 2>&1)
58+
if [ -n "$out" ]; then
59+
echo "::error::gofmt found unformatted files:"
60+
echo "$out"
61+
exit 1
62+
fi
63+
64+
- name: go vet (core)
65+
run: go vet ./...
66+
67+
- name: go vet (adapters/gin)
68+
working-directory: adapters/gin
69+
run: go vet ./...
70+
71+
- name: staticcheck
72+
uses: dominikh/staticcheck-action@v1
73+
with:
74+
version: latest
75+
install-go: false
76+
77+
bench-sanity:
78+
name: Benchmarks compile
79+
runs-on: ubuntu-latest
80+
steps:
81+
- uses: actions/checkout@v4
82+
83+
- uses: actions/setup-go@v5
84+
with:
85+
go-version: '1.25'
86+
cache: true
87+
88+
# `-run=^$` skips tests; `-benchtime=1x` runs each bench exactly once.
89+
# We only want to confirm benchmarks still compile and execute, not
90+
# measure them — the timing matrix lives elsewhere.
91+
- name: Bench dry-run
92+
run: go test -run=^$ -bench=. -benchtime=1x ./benchmarks/...

.github/workflows/codeql.yml

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
name: CodeQL
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
# Weekly run on Monday at 04:00 UTC — catches CVEs in dependencies
10+
# even when no code lands.
11+
- cron: '0 4 * * 1'
12+
13+
permissions:
14+
actions: read
15+
contents: read
16+
security-events: write
17+
18+
jobs:
19+
analyze:
20+
name: Analyze (Go)
21+
runs-on: ubuntu-latest
22+
23+
steps:
24+
- uses: actions/checkout@v4
25+
26+
- uses: actions/setup-go@v5
27+
with:
28+
go-version: '1.25'
29+
cache: true
30+
31+
- name: Initialize CodeQL
32+
uses: github/codeql-action/init@v3
33+
with:
34+
languages: go
35+
queries: security-and-quality
36+
37+
- name: Autobuild
38+
uses: github/codeql-action/autobuild@v3
39+
40+
- name: Perform CodeQL analysis
41+
uses: github/codeql-action/analyze@v3
42+
with:
43+
category: '/language:go'

.github/workflows/release.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: Release
2+
3+
on:
4+
push:
5+
tags:
6+
# Trigger only on root-module semver tags. The `adapters/gin/v*` tags
7+
# are pure Go-module markers — they don't produce binaries.
8+
- 'v[0-9]+.[0-9]+.[0-9]+'
9+
- 'v[0-9]+.[0-9]+.[0-9]+-*'
10+
11+
permissions:
12+
contents: write
13+
14+
jobs:
15+
build:
16+
name: Build (${{ matrix.target.label }})
17+
runs-on: ${{ matrix.target.os }}
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
target:
22+
- { os: ubuntu-latest, label: linux-amd64, goos: linux, goarch: amd64, ext: '' }
23+
- { os: macos-13, label: darwin-amd64, goos: darwin, goarch: amd64, ext: '' }
24+
- { os: macos-latest, label: darwin-arm64, goos: darwin, goarch: arm64, ext: '' }
25+
- { os: windows-latest, label: windows-amd64, goos: windows, goarch: amd64, ext: '.exe' }
26+
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- uses: actions/setup-go@v5
31+
with:
32+
go-version: '1.25'
33+
cache: true
34+
35+
# mattn/go-sqlite3 needs CGO. We build on the native runner for each
36+
# target so the C toolchain is already present — no cross-compile
37+
# gymnastics required.
38+
- name: Build lago + artisan
39+
shell: bash
40+
env:
41+
CGO_ENABLED: '1'
42+
GOOS: ${{ matrix.target.goos }}
43+
GOARCH: ${{ matrix.target.goarch }}
44+
run: |
45+
mkdir -p dist
46+
VERSION="${GITHUB_REF_NAME}"
47+
LDFLAGS="-s -w -X main.version=${VERSION}"
48+
49+
go build -ldflags="${LDFLAGS}" -o "dist/lago-${{ matrix.target.label }}${{ matrix.target.ext }}" ./cmd/lago
50+
go build -ldflags="${LDFLAGS}" -o "dist/artisan-${{ matrix.target.label }}${{ matrix.target.ext }}" ./cmd/artisan
51+
52+
- uses: actions/upload-artifact@v4
53+
with:
54+
name: binaries-${{ matrix.target.label }}
55+
path: dist/*
56+
if-no-files-found: error
57+
retention-days: 7
58+
59+
release:
60+
name: Publish release
61+
runs-on: ubuntu-latest
62+
needs: [build]
63+
steps:
64+
- uses: actions/checkout@v4
65+
66+
- uses: actions/download-artifact@v4
67+
with:
68+
path: dist
69+
pattern: binaries-*
70+
merge-multiple: true
71+
72+
- name: Generate SHA-256 checksums
73+
run: |
74+
cd dist
75+
shasum -a 256 * > SHA256SUMS
76+
77+
- name: Create GitHub release
78+
uses: softprops/action-gh-release@v2
79+
with:
80+
files: |
81+
dist/lago-*
82+
dist/artisan-*
83+
dist/SHA256SUMS
84+
generate_release_notes: true
85+
fail_on_unmatched_files: true
86+
87+
# Notifies the Go module proxy to fetch the new version so `go get @latest`
88+
# resolves it without waiting for the periodic refresh.
89+
warm-proxy:
90+
name: Warm Go proxy
91+
runs-on: ubuntu-latest
92+
needs: [release]
93+
steps:
94+
- name: Trigger pkg.go.dev fetch
95+
run: |
96+
VERSION="${GITHUB_REF_NAME}"
97+
curl -fsSL "https://proxy.golang.org/github.com/devituz/lagodev/@v/${VERSION}.info" || true
98+
curl -fsSL "https://proxy.golang.org/github.com/devituz/lagodev/adapters/gin/@v/${VERSION}.info" || true

0 commit comments

Comments
 (0)