Skip to content

Commit d5c548c

Browse files
authored
Merge pull request #4 from watany-dev/claude/enhance-ci-pipeline-6VE3k
2 parents f6c3448 + d9c8c4b commit d5c548c

9 files changed

Lines changed: 309 additions & 11 deletions

File tree

.github/workflows/ci.yml

Lines changed: 152 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,19 @@ on:
66
branches:
77
- main
88

9+
# Cancel duplicate runs on the same PR/branch, but keep history on main.
10+
concurrency:
11+
group: ci-${{ github.workflow }}-${{ github.ref }}
12+
cancel-in-progress: ${{ github.ref != 'refs/heads/main' }}
13+
914
# Default to read-only. Individual jobs may grant additional scopes if needed.
1015
permissions:
1116
contents: read
1217

1318
jobs:
14-
check:
19+
lint:
1520
runs-on: ubuntu-latest
21+
timeout-minutes: 10
1622

1723
permissions:
1824
contents: read
@@ -27,4 +33,148 @@ jobs:
2733
go-version-file: go.mod
2834

2935
- run: go mod download
30-
- run: make check
36+
- run: make fmt-check
37+
- run: make lint
38+
- run: make typecheck
39+
- run: make deadcode
40+
41+
test:
42+
strategy:
43+
fail-fast: false
44+
matrix:
45+
os: [ubuntu-latest, macos-latest, windows-latest]
46+
47+
runs-on: ${{ matrix.os }}
48+
timeout-minutes: 15
49+
50+
permissions:
51+
contents: read
52+
53+
steps:
54+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
55+
with:
56+
persist-credentials: false
57+
58+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
59+
with:
60+
go-version-file: go.mod
61+
62+
# The e2e test shells out to `git`. Confirm it's available so a missing
63+
# binary fails loud here instead of producing a confusing test error.
64+
- name: Verify git is available
65+
run: git --version
66+
67+
- run: go mod download
68+
69+
- name: Run tests with race detector
70+
# Tee verbose output to a file so we can attach it as an artifact on
71+
# failure — Actions logs aren't accessible to anonymous viewers, and
72+
# OS-specific failures are easier to triage with full -v output.
73+
shell: bash
74+
run: |
75+
set -o pipefail
76+
go test -race -shuffle=on -v ./... 2>&1 | tee test-output.txt
77+
78+
- name: Upload test output (always)
79+
if: always()
80+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
81+
with:
82+
name: test-output-${{ matrix.os }}
83+
path: test-output.txt
84+
if-no-files-found: warn
85+
86+
- name: Enforce coverage threshold (Linux only)
87+
if: matrix.os == 'ubuntu-latest'
88+
run: make coverage
89+
90+
- name: Upload coverage profile
91+
if: matrix.os == 'ubuntu-latest'
92+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
93+
with:
94+
name: coverage
95+
path: coverage.out
96+
if-no-files-found: error
97+
98+
vuln:
99+
runs-on: ubuntu-latest
100+
timeout-minutes: 5
101+
102+
permissions:
103+
contents: read
104+
105+
steps:
106+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
107+
with:
108+
persist-credentials: false
109+
110+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
111+
with:
112+
go-version-file: go.mod
113+
114+
- run: go mod download
115+
- run: make vuln
116+
117+
build:
118+
strategy:
119+
fail-fast: false
120+
matrix:
121+
include:
122+
- goos: darwin
123+
goarch: amd64
124+
- goos: darwin
125+
goarch: arm64
126+
- goos: linux
127+
goarch: amd64
128+
- goos: linux
129+
goarch: arm64
130+
- goos: windows
131+
goarch: amd64
132+
133+
runs-on: ubuntu-latest
134+
timeout-minutes: 10
135+
136+
permissions:
137+
contents: read
138+
139+
steps:
140+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
141+
with:
142+
persist-credentials: false
143+
144+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
145+
with:
146+
go-version-file: go.mod
147+
148+
- run: go mod download
149+
150+
# Cross-compile sanity check using the same flags as release.yml. We do
151+
# not upload the binary here — release.yml is the canonical producer of
152+
# signed, reproducible artifacts. This job exists so PRs catch breakage
153+
# in a target before it reaches a tag.
154+
- name: Cross-compile
155+
env:
156+
GOOS: ${{ matrix.goos }}
157+
GOARCH: ${{ matrix.goarch }}
158+
run: |
159+
go build -trimpath -buildvcs=true -o /dev/null ./cmd/git-real
160+
161+
actionlint:
162+
runs-on: ubuntu-latest
163+
timeout-minutes: 5
164+
165+
permissions:
166+
contents: read
167+
168+
steps:
169+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
170+
with:
171+
persist-credentials: false
172+
173+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
174+
with:
175+
go-version-file: go.mod
176+
177+
- run: go mod download
178+
179+
- name: Lint workflow files (actionlint)
180+
run: make actionlint

.github/workflows/codeql.yml

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
name: codeql
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- main
10+
schedule:
11+
# Weekly on Monday 06:17 UTC (off-peak, randomized minute to avoid
12+
# contention with other repos scheduled on the hour).
13+
- cron: "17 6 * * 1"
14+
15+
permissions:
16+
contents: read
17+
18+
jobs:
19+
analyze:
20+
name: analyze (go)
21+
runs-on: ubuntu-latest
22+
timeout-minutes: 30
23+
24+
permissions:
25+
contents: read
26+
actions: read
27+
security-events: write
28+
29+
strategy:
30+
fail-fast: false
31+
matrix:
32+
language: [go]
33+
34+
steps:
35+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
36+
with:
37+
persist-credentials: false
38+
39+
- uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0
40+
with:
41+
go-version-file: go.mod
42+
43+
- name: Initialize CodeQL
44+
uses: github/codeql-action/init@b2f9ef845756500b97acbdaf5c1dd4e9c1d15734 # v3.35.2
45+
with:
46+
languages: ${{ matrix.language }}
47+
build-mode: autobuild
48+
49+
- name: Perform CodeQL analysis
50+
uses: github/codeql-action/analyze@b2f9ef845756500b97acbdaf5c1dd4e9c1d15734 # v3.35.2
51+
with:
52+
category: "/language:${{ matrix.language }}"
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
name: dependency-review
2+
3+
on:
4+
pull_request:
5+
6+
permissions:
7+
contents: read
8+
9+
jobs:
10+
review:
11+
runs-on: ubuntu-latest
12+
timeout-minutes: 5
13+
# Skip dependency-review on Dependabot's own PRs (it would re-review its
14+
# own bumps, often spuriously) and let it run unblocking elsewhere — we'll
15+
# tighten the policy once the repository's Dependency Graph status is
16+
# confirmed enabled. Until then, this is best-effort and non-blocking.
17+
continue-on-error: true
18+
19+
permissions:
20+
contents: read
21+
22+
steps:
23+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1
24+
25+
- uses: actions/dependency-review-action@2031cfc080254a8a887f58cffee85186f0e49e48 # v4.9.0

.github/workflows/release.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ jobs:
7676
7777
# Pin the build timestamp to the tag commit's author date so that
7878
# rebuilding from the same source produces a byte-identical binary.
79-
export SOURCE_DATE_EPOCH="$(git log -1 --format=%ct)"
79+
# (declare and export separately so a `git log` failure isn't masked
80+
# by `export`'s exit status — shellcheck SC2155)
81+
SOURCE_DATE_EPOCH="$(git log -1 --format=%ct)"
82+
export SOURCE_DATE_EPOCH
8083
8184
go build \
8285
-trimpath \

Makefile

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ LDFLAGS := -s -w \
1919
-X main.commit=$(COMMIT) \
2020
-X main.date=$(DATE)
2121

22-
.PHONY: build fmt fmt-check lint typecheck deadcode test coverage check
22+
.PHONY: build fmt fmt-check lint typecheck deadcode test test-race coverage vuln actionlint check
2323

2424
build:
2525
$(GO) build -trimpath -buildvcs=true -ldflags='$(LDFLAGS)' -o git-real ./cmd/git-real
@@ -51,7 +51,16 @@ deadcode:
5151
test:
5252
$(GO) test ./...
5353

54+
test-race:
55+
$(GO) test -race -shuffle=on ./...
56+
5457
coverage:
5558
COVERAGE_THRESHOLD=$(COVERAGE_THRESHOLD) bash ./scripts/check-coverage.sh
5659

60+
vuln:
61+
$(GO) tool govulncheck ./...
62+
63+
actionlint:
64+
$(GO) tool actionlint
65+
5766
check: fmt-check lint typecheck deadcode coverage

cmd/git-real/e2e_test.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ func TestMainEndToEnd(t *testing.T) {
2222
runGit(t, repoDir, "config", "user.name", "GitReal Test")
2323
runGit(t, repoDir, "config", "user.email", "test@example.com")
2424
runGit(t, repoDir, "config", "commit.gpgsign", "false")
25+
runGit(t, repoDir, "config", "core.autocrlf", "false")
2526

2627
writeFile(t, filepath.Join(repoDir, "file.txt"), "base\n")
2728
runGit(t, repoDir, "add", "file.txt")
@@ -129,6 +130,7 @@ func TestMainOnceCancelledByContext(t *testing.T) {
129130
runGit(t, repoDir, "config", "user.name", "GitReal Test")
130131
runGit(t, repoDir, "config", "user.email", "test@example.com")
131132
runGit(t, repoDir, "config", "commit.gpgsign", "false")
133+
runGit(t, repoDir, "config", "core.autocrlf", "false")
132134

133135
writeFile(t, filepath.Join(repoDir, "file.txt"), "base\n")
134136
runGit(t, repoDir, "add", "file.txt")

go.mod

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,17 +3,30 @@ module github.com/watany-dev/gitreal
33
go 1.26
44

55
tool (
6+
github.com/rhysd/actionlint/cmd/actionlint
67
golang.org/x/tools/cmd/deadcode
8+
golang.org/x/vuln/cmd/govulncheck
79
honnef.co/go/tools/cmd/staticcheck
810
)
911

1012
require (
1113
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c // indirect
14+
github.com/bmatcuk/doublestar/v4 v4.10.0 // indirect
15+
github.com/clipperhouse/uax29/v2 v2.7.0 // indirect
16+
github.com/fatih/color v1.19.0 // indirect
17+
github.com/mattn/go-colorable v0.1.14 // indirect
18+
github.com/mattn/go-isatty v0.0.20 // indirect
19+
github.com/mattn/go-runewidth v0.0.21 // indirect
20+
github.com/mattn/go-shellwords v1.0.12 // indirect
21+
github.com/rhysd/actionlint v1.7.12 // indirect
22+
github.com/robfig/cron/v3 v3.0.1 // indirect
23+
go.yaml.in/yaml/v4 v4.0.0-rc.3 // indirect
1224
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 // indirect
1325
golang.org/x/mod v0.35.0 // indirect
1426
golang.org/x/sync v0.20.0 // indirect
1527
golang.org/x/sys v0.43.0 // indirect
16-
golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa // indirect
28+
golang.org/x/telemetry v0.0.0-20260421165255-392afab6f40e // indirect
1729
golang.org/x/tools v0.44.0 // indirect
30+
golang.org/x/vuln v1.3.0 // indirect
1831
honnef.co/go/tools v0.7.0 // indirect
1932
)

go.sum

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,49 @@
11
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c h1:pxW6RcqyfI9/kWtOwnv/G+AzdKuy2ZrqINhenH4HyNs=
22
github.com/BurntSushi/toml v1.4.1-0.20240526193622-a339e1f7089c/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
3-
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
4-
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
3+
github.com/bmatcuk/doublestar/v4 v4.10.0 h1:zU9WiOla1YA122oLM6i4EXvGW62DvKZVxIe6TYWexEs=
4+
github.com/bmatcuk/doublestar/v4 v4.10.0/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
5+
github.com/clipperhouse/uax29/v2 v2.7.0 h1:+gs4oBZ2gPfVrKPthwbMzWZDaAFPGYK72F0NJv2v7Vk=
6+
github.com/clipperhouse/uax29/v2 v2.7.0/go.mod h1:EFJ2TJMRUaplDxHKj1qAEhCtQPW2tJSwu5BF98AuoVM=
7+
github.com/fatih/color v1.19.0 h1:Zp3PiM21/9Ld6FzSKyL5c/BULoe/ONr9KlbYVOfG8+w=
8+
github.com/fatih/color v1.19.0/go.mod h1:zNk67I0ZUT1bEGsSGyCZYZNrHuTkJJB+r6Q9VuMi0LE=
9+
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786 h1:rcv+Ippz6RAtvaGgKxc+8FQIpxHgsF+HBzPyYL2cyVU=
10+
github.com/google/go-cmdtest v0.4.1-0.20220921163831-55ab3332a786/go.mod h1:apVn/GCasLZUVpAJ6oWAuyP7Ne7CEsQbTnc0plM3m+o=
11+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
12+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
13+
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
14+
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
15+
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
16+
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
17+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
18+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
19+
github.com/mattn/go-runewidth v0.0.21 h1:jJKAZiQH+2mIinzCJIaIG9Be1+0NR+5sz/lYEEjdM8w=
20+
github.com/mattn/go-runewidth v0.0.21/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs=
21+
github.com/mattn/go-shellwords v1.0.12 h1:M2zGm7EW6UQJvDeQxo4T51eKPurbeFbe8WtebGE2xrk=
22+
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
23+
github.com/rhysd/actionlint v1.7.12 h1:vQ4GeJN86C0QH+gTUQcs8McmK62OLT3kmakPMtEWYnY=
24+
github.com/rhysd/actionlint v1.7.12/go.mod h1:krOUhujIsJusovkaYzQ/VNH8PFexjNKqU0q5XI/4w+g=
25+
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
26+
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
27+
go.yaml.in/yaml/v4 v4.0.0-rc.3 h1:3h1fjsh1CTAPjW7q/EMe+C8shx5d8ctzZTrLcs/j8Go=
28+
go.yaml.in/yaml/v4 v4.0.0-rc.3/go.mod h1:aZqd9kCMsGL7AuUv/m/PvWLdg5sjJsZ4oHDEnfPPfY0=
529
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678 h1:1P7xPZEwZMoBoz0Yze5Nx2/4pxj6nw9ZqHWXqP0iRgQ=
630
golang.org/x/exp/typeparams v0.0.0-20231108232855-2478ac86f678/go.mod h1:AbB0pIl9nAr9wVwH+Z2ZpaocVmF5I4GyWCDIsVjR0bk=
731
golang.org/x/mod v0.35.0 h1:Ww1D637e6Pg+Zb2KrWfHQUnH2dQRLBQyAtpr/haaJeM=
832
golang.org/x/mod v0.35.0/go.mod h1:+GwiRhIInF8wPm+4AoT6L0FA1QWAad3OMdTRx4tFYlU=
933
golang.org/x/sync v0.20.0 h1:e0PTpb7pjO8GAtTs2dQ6jYa5BWYlMuX047Dco/pItO4=
1034
golang.org/x/sync v0.20.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0=
35+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
1136
golang.org/x/sys v0.43.0 h1:Rlag2XtaFTxp19wS8MXlJwTvoh8ArU6ezoyFsMyCTNI=
1237
golang.org/x/sys v0.43.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
13-
golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa h1:efT73AJZfAAUV7SOip6pWGkwJDzIGiKBZGVzHYa+ve4=
14-
golang.org/x/telemetry v0.0.0-20260409153401-be6f6cb8b1fa/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE=
38+
golang.org/x/telemetry v0.0.0-20260421165255-392afab6f40e h1:OXgN37M6hqjaAvb7CJK9vJ+7Z/6lvIm5bXho5poo/Wk=
39+
golang.org/x/telemetry v0.0.0-20260421165255-392afab6f40e/go.mod h1:kHjTxDEnAu6/Nl9lDkzjWpR+bmKfxeiRuSDlsMb70gE=
1540
golang.org/x/tools v0.44.0 h1:UP4ajHPIcuMjT1GqzDWRlalUEoY+uzoZKnhOjbIPD2c=
1641
golang.org/x/tools v0.44.0/go.mod h1:KA0AfVErSdxRZIsOVipbv3rQhVXTnlU6UhKxHd1seDI=
1742
golang.org/x/tools/go/expect v0.1.1-deprecated h1:jpBZDwmgPhXsKZC6WhL20P4b/wmnpsEAGHaNy0n/rJM=
1843
golang.org/x/tools/go/expect v0.1.1-deprecated/go.mod h1:eihoPOH+FgIqa3FpoTwguz/bVUSGBlGQU67vpBeOrBY=
44+
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated h1:1h2MnaIAIXISqTFKdENegdpAgUXz6NrPEsbIeWaBRvM=
45+
golang.org/x/tools/go/packages/packagestest v0.1.1-deprecated/go.mod h1:RVAQXBGNv1ib0J382/DPCRS/BPnsGebyM1Gj5VSDpG8=
46+
golang.org/x/vuln v1.3.0 h1:hZYzR8uRhYhDSX88d+40TWbKAVw7BIvRWm26rtEn8jw=
47+
golang.org/x/vuln v1.3.0/go.mod h1:MIY2PaR1y52stzZM3uHBboUAdVJvSVMl5nP3OQrwQaE=
1948
honnef.co/go/tools v0.7.0 h1:w6WUp1VbkqPEgLz4rkBzH/CSU6HkoqNLp6GstyTx3lU=
2049
honnef.co/go/tools v0.7.0/go.mod h1:pm29oPxeP3P82ISxZDgIYeOaf9ta6Pi0EWvCFoLG2vc=

0 commit comments

Comments
 (0)