Skip to content

Commit 31d275e

Browse files
committed
feat: comprehensive project optimization with security, performance, and accessibility improvements
- Security: Add CSRF protection, security headers, XSS prevention - Performance: Implement memory-aware LRU cache, ring buffers, worker pool improvements - Architecture: Unified API client interfaces, centralized error management - Real-time: Replace auto-refresh with WebSocket/SSE implementation - CI/CD: Consolidate duplicate workflows into single comprehensive pipeline - Accessibility: WCAG AA compliant color contrasts and accessibility features - Testing: Achieve 97%+ test coverage for performance packages Major improvements across security, performance, architecture, and user experience.
1 parent 24e45b9 commit 31d275e

39 files changed

+8276
-563
lines changed

.github/workflows/ci-cd.yml

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
tags: ["v*"]
7+
paths-ignore:
8+
- "**.md"
9+
- "docs/**"
10+
- ".github/ISSUE_TEMPLATE/**"
11+
pull_request:
12+
branches: [main, develop]
13+
paths-ignore:
14+
- "**.md"
15+
- "docs/**"
16+
- ".github/ISSUE_TEMPLATE/**"
17+
release:
18+
types: [published]
19+
workflow_dispatch:
20+
inputs:
21+
reason:
22+
description: 'Reason for manual trigger'
23+
required: false
24+
default: 'Manual trigger'
25+
26+
env:
27+
GO_VERSION: "1.23"
28+
REGISTRY_IMAGE: johandevl/export-trakt-4-letterboxd
29+
GITHUB_REGISTRY: ghcr.io
30+
GITHUB_IMAGE: ghcr.io/johandevl/export_trakt_4_letterboxd
31+
32+
jobs:
33+
# Job 1: Test and Build Go Application
34+
test-and-build:
35+
name: Test and Build Go Application
36+
runs-on: ubuntu-latest
37+
outputs:
38+
version: ${{ steps.version.outputs.version }}
39+
is_tag: ${{ steps.version.outputs.is_tag }}
40+
coverage: ${{ steps.coverage.outputs.coverage }}
41+
42+
steps:
43+
- name: Checkout code
44+
uses: actions/checkout@v4
45+
46+
- name: Set up Go
47+
uses: actions/setup-go@v4
48+
with:
49+
go-version: ${{ env.GO_VERSION }}
50+
cache: true
51+
52+
- name: Install dependencies
53+
run: go mod download
54+
55+
- name: Run Go tests
56+
run: go test -v ./...
57+
58+
- name: Check test coverage
59+
id: coverage
60+
run: |
61+
# Run tests with coverage, excluding main package
62+
go test -coverprofile=coverage.out ./pkg/...
63+
COVERAGE=$(go tool cover -func=coverage.out | grep total | awk '{print $3}' | tr -d '%')
64+
echo "coverage=$COVERAGE" >> $GITHUB_OUTPUT
65+
echo "Total coverage (excluding main package): $COVERAGE%"
66+
if (( $(echo "$COVERAGE < 70" | bc -l) )); then
67+
echo "⚠️ Code coverage is below 70%. Current: $COVERAGE%"
68+
echo "This is acceptable for now, but aim to improve coverage."
69+
else
70+
echo "✅ Coverage check passed! Current: $COVERAGE%, Target: 70%"
71+
fi
72+
73+
- name: Generate coverage report
74+
run: go tool cover -html=coverage.out -o coverage.html
75+
76+
- name: Upload coverage report
77+
uses: actions/upload-artifact@v4
78+
with:
79+
name: coverage-report
80+
path: coverage.html
81+
82+
- name: Get version info
83+
id: version
84+
run: |
85+
if [[ "${{ github.ref }}" == refs/tags/* ]]; then
86+
# For tag pushes, use the tag directly
87+
VERSION="${{ github.ref_name }}"
88+
echo "version=$VERSION" >> $GITHUB_OUTPUT
89+
echo "is_tag=true" >> $GITHUB_OUTPUT
90+
echo "🏷️ Building from tag: $VERSION"
91+
else
92+
# For branch pushes, get the latest tag
93+
git fetch --tags
94+
LATEST_TAG=$(git tag -l "v*" | grep -v "-" | sort -V | tail -n 1)
95+
if [ -z "$LATEST_TAG" ]; then
96+
LATEST_TAG="v1.0.0"
97+
fi
98+
echo "version=$LATEST_TAG" >> $GITHUB_OUTPUT
99+
echo "is_tag=false" >> $GITHUB_OUTPUT
100+
echo "📋 Building from branch, using latest tag: $LATEST_TAG"
101+
fi
102+
103+
- name: Build Go application
104+
run: |
105+
mkdir -p build
106+
go build -v -ldflags "-X main.version=${{ steps.version.outputs.version }} -X main.buildDate=$(date -u +'%Y-%m-%dT%H:%M:%SZ') -X main.gitCommit=${{ github.sha }}" -o build/export_trakt ./cmd/export_trakt
107+
108+
- name: Upload build artifact
109+
uses: actions/upload-artifact@v4
110+
with:
111+
name: export-trakt-binary
112+
path: build/export_trakt
113+
114+
# Job 2: Build and Push Docker Images
115+
docker:
116+
name: Build and Push Docker Images
117+
runs-on: ubuntu-latest
118+
needs: test-and-build
119+
if: github.event_name != 'pull_request'
120+
permissions:
121+
contents: read
122+
packages: write
123+
security-events: write
124+
125+
steps:
126+
- name: Checkout repository
127+
uses: actions/checkout@v4
128+
129+
- name: Download build artifact
130+
uses: actions/download-artifact@v4
131+
with:
132+
name: export-trakt-binary
133+
path: build
134+
135+
- name: Make binary executable
136+
run: chmod +x build/export_trakt
137+
138+
- name: Set up QEMU
139+
uses: docker/setup-qemu-action@v3
140+
141+
- name: Set up Docker Buildx
142+
uses: docker/setup-buildx-action@v3
143+
144+
- name: Extract metadata for Docker
145+
id: meta
146+
uses: docker/metadata-action@v5
147+
with:
148+
images: |
149+
${{ env.REGISTRY_IMAGE }}
150+
${{ env.GITHUB_IMAGE }}
151+
tags: |
152+
# Latest tag - ONLY for git tags (semantic versions/releases)
153+
type=raw,value=latest,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
154+
# Main tag - for git tags (semantic versions) AND main branch pushes
155+
type=raw,value=main,enable=${{ startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main' }}
156+
# Semantic version tag - ONLY for git tags (releases)
157+
type=raw,value=${{ needs.test-and-build.outputs.version }},enable=${{ startsWith(github.ref, 'refs/tags/v') }}
158+
# Develop branch tag
159+
type=raw,value=develop,enable=${{ github.ref == 'refs/heads/develop' }}
160+
# PR tags
161+
type=ref,event=pr,prefix=PR-
162+
163+
- name: Log in to Docker Hub
164+
uses: docker/login-action@v3
165+
with:
166+
username: ${{ secrets.DOCKERHUB_USERNAME }}
167+
password: ${{ secrets.DOCKERHUB_TOKEN }}
168+
169+
- name: Log in to GitHub Container Registry
170+
uses: docker/login-action@v3
171+
with:
172+
registry: ${{ env.GITHUB_REGISTRY }}
173+
username: ${{ github.actor }}
174+
password: ${{ secrets.GITHUB_TOKEN }}
175+
176+
- name: Set build date
177+
id: build_date
178+
run: echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT
179+
180+
- name: Build and push Docker image
181+
uses: docker/build-push-action@v6
182+
with:
183+
context: .
184+
file: ./Dockerfile
185+
push: true
186+
platforms: linux/amd64,linux/arm64,linux/arm/v7
187+
tags: ${{ steps.meta.outputs.tags }}
188+
labels: ${{ steps.meta.outputs.labels }}
189+
cache-from: type=gha,scope=${{ github.workflow }}-${{ github.ref_name }}
190+
cache-to: type=gha,mode=max,scope=${{ github.workflow }}-${{ github.ref_name }}
191+
build-args: |
192+
VERSION=${{ needs.test-and-build.outputs.version }}
193+
COMMIT_SHA=${{ github.sha }}
194+
BUILD_DATE=${{ steps.build_date.outputs.BUILD_DATE }}
195+
196+
- name: Scan image for vulnerabilities
197+
uses: aquasecurity/trivy-action@master
198+
with:
199+
image-ref: ${{ env.REGISTRY_IMAGE }}:${{ needs.test-and-build.outputs.version }}
200+
format: "sarif"
201+
output: "trivy-results.sarif"
202+
203+
- name: Upload Trivy scan results to GitHub Security tab
204+
uses: github/codeql-action/upload-sarif@v3
205+
with:
206+
sarif_file: "trivy-results.sarif"
207+
208+
# Job 3: Test Docker Image
209+
docker-test:
210+
name: Test Docker Image
211+
needs: [test-and-build, docker]
212+
runs-on: ubuntu-latest
213+
if: github.event_name != 'pull_request'
214+
215+
steps:
216+
- name: Checkout repository
217+
uses: actions/checkout@v4
218+
219+
- name: Set up Docker Buildx
220+
uses: docker/setup-buildx-action@v3
221+
222+
- name: Log in to Docker Hub
223+
uses: docker/login-action@v3
224+
with:
225+
username: ${{ secrets.DOCKERHUB_USERNAME }}
226+
password: ${{ secrets.DOCKERHUB_TOKEN }}
227+
228+
- name: Pull image for testing
229+
run: docker pull ${{ env.REGISTRY_IMAGE }}:${{ needs.test-and-build.outputs.version }}
230+
231+
- name: Test Docker image
232+
run: |
233+
# Create test directories
234+
mkdir -p ./test_config ./test_logs ./test_exports
235+
236+
# Basic image test - check if it runs properly
237+
docker run --rm \
238+
-v $(pwd)/test_config:/app/config \
239+
-v $(pwd)/test_logs:/app/logs \
240+
-v $(pwd)/test_exports:/app/exports \
241+
${{ env.REGISTRY_IMAGE }}:${{ needs.test-and-build.outputs.version }} --help
242+
243+
echo "✅ Docker image tests passed successfully"
244+
245+
# Job 4: Notification and Summary
246+
notify:
247+
name: Notify and Summarize
248+
needs: [test-and-build, docker, docker-test]
249+
runs-on: ubuntu-latest
250+
if: always()
251+
252+
steps:
253+
- name: Check overall result
254+
id: check
255+
run: |
256+
if ${{ needs.test-and-build.result == 'success' && (needs.docker.result == 'success' || needs.docker.result == 'skipped') && (needs.docker-test.result == 'success' || needs.docker-test.result == 'skipped') }}; then
257+
echo "status=success" >> $GITHUB_OUTPUT
258+
echo "✅ All jobs completed successfully"
259+
else
260+
echo "status=failure" >> $GITHUB_OUTPUT
261+
echo "❌ One or more jobs failed"
262+
fi
263+
264+
- name: Create summary
265+
run: |
266+
echo "## 🎬 Export Trakt 4 Letterboxd CI/CD Summary" >> $GITHUB_STEP_SUMMARY
267+
echo "" >> $GITHUB_STEP_SUMMARY
268+
echo "### 📊 Build Results" >> $GITHUB_STEP_SUMMARY
269+
echo "- **Go Tests & Build**: ${{ needs.test-and-build.result }}" >> $GITHUB_STEP_SUMMARY
270+
echo "- **Coverage**: ${{ needs.test-and-build.outputs.coverage }}%" >> $GITHUB_STEP_SUMMARY
271+
echo "- **Version**: ${{ needs.test-and-build.outputs.version }}" >> $GITHUB_STEP_SUMMARY
272+
if [ "${{ github.event_name }}" != "pull_request" ]; then
273+
echo "- **Docker Build**: ${{ needs.docker.result }}" >> $GITHUB_STEP_SUMMARY
274+
echo "- **Docker Test**: ${{ needs.docker-test.result }}" >> $GITHUB_STEP_SUMMARY
275+
fi
276+
echo "" >> $GITHUB_STEP_SUMMARY
277+
if [ "${{ steps.check.outputs.status }}" == "success" ]; then
278+
echo "### ✅ Pipeline Status: SUCCESS" >> $GITHUB_STEP_SUMMARY
279+
if [ "${{ github.event_name }}" != "pull_request" ]; then
280+
echo "" >> $GITHUB_STEP_SUMMARY
281+
echo "### 🐳 Docker Images Published" >> $GITHUB_STEP_SUMMARY
282+
echo "- Docker Hub: \`${{ env.REGISTRY_IMAGE }}:${{ needs.test-and-build.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
283+
echo "- GitHub Packages: \`${{ env.GITHUB_IMAGE }}:${{ needs.test-and-build.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY
284+
fi
285+
else
286+
echo "### ❌ Pipeline Status: FAILED" >> $GITHUB_STEP_SUMMARY
287+
echo "Please check the failed jobs above for more details." >> $GITHUB_STEP_SUMMARY
288+
fi
289+
290+
- name: Create release comment
291+
if: github.event_name == 'release' && steps.check.outputs.status == 'success'
292+
uses: actions/github-script@v7
293+
with:
294+
github-token: ${{ secrets.GITHUB_TOKEN }}
295+
script: |
296+
github.rest.issues.createComment({
297+
issue_number: context.issue.number,
298+
owner: context.repo.owner,
299+
repo: context.repo.repo,
300+
body: `🎉 **Release ${{ needs.test-and-build.outputs.version }} Successfully Deployed!**
301+
302+
### 📦 Docker Images Available:
303+
- **Docker Hub**: \`${{ env.REGISTRY_IMAGE }}:${{ needs.test-and-build.outputs.version }}\`
304+
- **GitHub Packages**: \`${{ env.GITHUB_IMAGE }}:${{ needs.test-and-build.outputs.version }}\`
305+
306+
### 🏗️ Build Information:
307+
- **Test Coverage**: ${{ needs.test-and-build.outputs.coverage }}%
308+
- **Supported Platforms**: linux/amd64, linux/arm64, linux/arm/v7
309+
- **Security Scan**: ✅ Passed
310+
311+
### 🚀 Quick Start:
312+
\`\`\`bash
313+
docker pull ${{ env.REGISTRY_IMAGE }}:${{ needs.test-and-build.outputs.version }}
314+
\`\`\`
315+
316+
All systems are go! 🚀`
317+
})

0 commit comments

Comments
 (0)