1+ name : CI
2+
3+ on :
4+ push :
5+ branches : [ "*" ]
6+ pull_request :
7+ branches : [ "*" ]
8+ workflow_dispatch :
9+
10+ jobs :
11+ test :
12+ name : Test
13+ runs-on : ${{ matrix.os }}
14+ strategy :
15+ fail-fast : false
16+ matrix :
17+ os : [ubuntu-latest, macos-latest, windows-latest]
18+ go-version : [1.21.x, 1.22.x, 1.23.x]
19+
20+ steps :
21+ - name : Checkout code
22+ uses : actions/checkout@v4
23+
24+ - name : Set up Go
25+ uses : actions/setup-go@v4
26+ with :
27+ go-version : ${{ matrix.go-version }}
28+
29+ - name : Cache Go modules
30+ uses : actions/cache@v3
31+ with :
32+ path : |
33+ ~/.cache/go-build
34+ ~/go/pkg/mod
35+ key : ${{ runner.os }}-go-${{ matrix.go-version }}-${{ hashFiles('**/go.sum') }}
36+ restore-keys : |
37+ ${{ runner.os }}-go-${{ matrix.go-version }}-
38+ ${{ runner.os }}-go-
39+
40+ - name : Download dependencies
41+ run : go mod download
42+
43+ - name : Verify dependencies
44+ run : go mod verify
45+
46+ - name : Run go vet
47+ run : go vet ./...
48+
49+ - name : Run go fmt check
50+ run : |
51+ if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then
52+ echo "The following files are not formatted:"
53+ gofmt -s -l .
54+ echo "Please run 'go fmt ./...' to format your code."
55+ exit 1
56+ fi
57+ shell : bash
58+
59+ - name : Run tests
60+ run : go test -v -race -coverprofile=coverage.out ./...
61+
62+ - name : Run tests with coverage
63+ run : go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
64+
65+ - name : Upload coverage to Codecov
66+ uses : codecov/codecov-action@v3
67+ with :
68+ file : ./coverage.out
69+ flags : unittests
70+ name : codecov-${{ matrix.os }}-go${{ matrix.go-version }}
71+
72+ lint :
73+ name : Lint
74+ runs-on : ubuntu-latest
75+ steps :
76+ - name : Checkout code
77+ uses : actions/checkout@v4
78+
79+ - name : Set up Go
80+ uses : actions/setup-go@v4
81+ with :
82+ go-version : 1.23.x
83+
84+ - name : Run golangci-lint
85+ uses : golangci/golangci-lint-action@v3
86+ with :
87+ version : latest
88+ args : --timeout=5m
89+
90+ build :
91+ name : Build
92+ runs-on : ${{ matrix.os }}
93+ strategy :
94+ matrix :
95+ os : [ubuntu-latest, macos-latest, windows-latest]
96+
97+ steps :
98+ - name : Checkout code
99+ uses : actions/checkout@v4
100+
101+ - name : Set up Go
102+ uses : actions/setup-go@v4
103+ with :
104+ go-version : 1.23.x
105+
106+ - name : Build binary
107+ run : |
108+ go build -v -o pyinit ./cmd/pyinit
109+ shell : bash
110+
111+ - name : Test binary (Unix)
112+ if : runner.os != 'Windows'
113+ run : ./pyinit --version
114+
115+ - name : Test binary (Windows)
116+ if : runner.os == 'Windows'
117+ run : .\pyinit.exe --version
118+
119+ integration :
120+ name : Integration Tests
121+ runs-on : ubuntu-latest
122+ needs : [test, build]
123+
124+ steps :
125+ - name : Checkout code
126+ uses : actions/checkout@v4
127+
128+ - name : Set up Go
129+ uses : actions/setup-go@v4
130+ with :
131+ go-version : 1.23.x
132+
133+ - name : Run integration tests
134+ run : go test -v ./test/integration/...
135+
136+ - name : Test template rendering
137+ run : go test -v ./pkg/template/...
138+
139+ security :
140+ name : Security Scan
141+ runs-on : ubuntu-latest
142+ steps :
143+ - name : Checkout code
144+ uses : actions/checkout@v4
145+
146+ - name : Set up Go
147+ uses : actions/setup-go@v4
148+ with :
149+ go-version : 1.23.x
150+
151+ - name : Run Gosec Security Scanner
152+ uses : securecodewarrior/github-action-gosec@master
153+ with :
154+ args : ' -no-fail -fmt sarif -out results.sarif ./...'
155+
156+ - name : Upload SARIF file
157+ uses : github/codeql-action/upload-sarif@v2
158+ with :
159+ sarif_file : results.sarif
160+
161+ test-coverage :
162+ name : Test Coverage Report
163+ runs-on : ubuntu-latest
164+ needs : test
165+
166+ steps :
167+ - name : Checkout code
168+ uses : actions/checkout@v4
169+
170+ - name : Set up Go
171+ uses : actions/setup-go@v4
172+ with :
173+ go-version : 1.23.x
174+
175+ - name : Run tests with coverage
176+ run : |
177+ go test -v -race -coverprofile=coverage.out -covermode=atomic ./...
178+ go tool cover -html=coverage.out -o coverage.html
179+
180+ - name : Coverage Summary
181+ run : |
182+ echo "## Coverage Report" >> $GITHUB_STEP_SUMMARY
183+ echo "| Package | Coverage |" >> $GITHUB_STEP_SUMMARY
184+ echo "|---------|----------|" >> $GITHUB_STEP_SUMMARY
185+ go tool cover -func=coverage.out | while read line; do
186+ if [[ $line == *"total:"* ]]; then
187+ coverage=$(echo $line | awk '{print $3}')
188+ echo "| **Total** | **$coverage** |" >> $GITHUB_STEP_SUMMARY
189+ elif [[ $line == *".go:"* ]]; then
190+ file=$(echo $line | awk '{print $1}' | sed 's|.*/||')
191+ coverage=$(echo $line | awk '{print $3}')
192+ echo "| $file | $coverage |" >> $GITHUB_STEP_SUMMARY
193+ fi
194+ done
195+
196+ - name : Upload coverage artifact
197+ uses : actions/upload-artifact@v3
198+ with :
199+ name : coverage-report
200+ path : |
201+ coverage.out
202+ coverage.html
203+
204+ validate-release :
205+ name : Validate Release Readiness
206+ runs-on : ubuntu-latest
207+ if : startsWith(github.ref, 'refs/tags/')
208+ needs : [test, lint, build, integration, security]
209+
210+ steps :
211+ - name : Checkout code
212+ uses : actions/checkout@v4
213+
214+ - name : Set up Go
215+ uses : actions/setup-go@v4
216+ with :
217+ go-version : 1.23.x
218+
219+ - name : Validate all tests pass
220+ run : |
221+ echo "Running final validation for release ${{ github.ref_name }}"
222+ go test -v ./...
223+
224+ - name : Build release binary
225+ run : |
226+ go build -ldflags "-X github.com/Pradyothsp/pyinit/internal/version.Version=${{ github.ref_name }} -X github.com/Pradyothsp/pyinit/internal/version.GitCommit=${{ github.sha }} -X github.com/Pradyothsp/pyinit/internal/version.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)" -o pyinit ./cmd/pyinit
227+
228+ - name : Test release binary
229+ run : |
230+ ./pyinit --version
231+ echo "Release binary validated successfully"
232+
233+ - name : Check version consistency
234+ run : |
235+ binary_version=$(./pyinit --version | head -1 | awk '{print $2}')
236+ tag_version="${{ github.ref_name }}"
237+ if [ "$binary_version" != "$tag_version" ]; then
238+ echo "Version mismatch: binary=$binary_version, tag=$tag_version"
239+ exit 1
240+ fi
241+ echo "Version consistency validated: $binary_version"
242+
243+ notify-status :
244+ name : Notify Build Status
245+ runs-on : ubuntu-latest
246+ needs : [test, lint, build, integration]
247+ if : always()
248+
249+ steps :
250+ - name : Notify Success
251+ if : needs.test.result == 'success' && needs.lint.result == 'success' && needs.build.result == 'success' && needs.integration.result == 'success'
252+ run : |
253+ echo "✅ All CI checks passed successfully!"
254+ echo "- Tests: ✅"
255+ echo "- Linting: ✅"
256+ echo "- Build: ✅"
257+ echo "- Integration: ✅"
258+
259+ - name : Notify Failure
260+ if : needs.test.result == 'failure' || needs.lint.result == 'failure' || needs.build.result == 'failure' || needs.integration.result == 'failure'
261+ run : |
262+ echo "❌ CI checks failed!"
263+ echo "- Tests: ${{ needs.test.result }}"
264+ echo "- Linting: ${{ needs.lint.result }}"
265+ echo "- Build: ${{ needs.build.result }}"
266+ echo "- Integration: ${{ needs.integration.result }}"
267+ exit 1
0 commit comments