1
- name : Build and Push Non-Production Images
1
+ name : Build, Test & Push to GHCR
2
2
3
3
on :
4
4
push :
8
8
types : [opened, synchronize, reopened]
9
9
workflow_dispatch :
10
10
11
+ concurrency :
12
+ group : ${{ github.workflow }}-${{ github.ref }}
13
+ cancel-in-progress : true
14
+
15
+ permissions :
16
+ contents : read
17
+
11
18
env :
12
19
REGISTRY : ghcr.io
13
20
ORG_NAME : refactor-group
14
21
REPO_NAME : refactor-platform-fe
22
+ NODE_ENV : test
15
23
16
24
jobs :
17
- build_and_push_amd64 :
25
+ # === LINT JOB ===
26
+ lint :
27
+ name : Lint & Format Check
18
28
runs-on : ubuntu-24.04
19
29
20
- permissions :
21
- contents : read
22
- packages : write
23
- id-token : write
30
+ steps :
31
+ - name : Checkout
32
+ uses : actions/checkout@v4
33
+
34
+ - name : Setup Node.js
35
+ uses : actions/setup-node@v5
36
+ with :
37
+ node-version : 24.x
38
+ cache : ' npm'
39
+ cache-dependency-path : package-lock.json
40
+
41
+ - name : Install dependencies
42
+ run : npm ci --prefer-offline
43
+
44
+ - name : Run ESLint
45
+ run : npm run lint
46
+
47
+ # === TEST JOB ===
48
+ test :
49
+ name : Build & Test
50
+ runs-on : ubuntu-24.04
24
51
25
52
steps :
26
- - uses : actions/checkout@v4
53
+ - name : Checkout
54
+ uses : actions/checkout@v4
27
55
28
- - uses : docker/setup-buildx-action@v3
56
+ - name : Setup Node.js
57
+ uses : actions/setup-node@v5
29
58
with :
30
- install : true
59
+ node-version : 24.x
60
+ cache : ' npm'
61
+ cache-dependency-path : package-lock.json
31
62
32
- - name : Docker login
33
- uses : docker/login-action@v2
63
+ # 🎯 Next.js build cache (job-specific to prevent race conditions)
64
+ - name : Cache Next.js build
65
+ uses : actions/cache@v4
34
66
with :
35
- registry : ${{ env.REGISTRY }}
36
- username : ${{ github.actor }}
37
- password : ${{ secrets.GITHUB_TOKEN }}
67
+ path : .next/cache
68
+ key : ${{ runner.os }}-nextjs-test-${{ hashFiles('**/package-lock.json') }}-${{ hashFiles('**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx') }}
69
+ restore-keys : |
70
+ ${{ runner.os }}-nextjs-test-${{ hashFiles('**/package-lock.json') }}-
71
+ ${{ runner.os }}-nextjs-${{ hashFiles('**/package-lock.json') }}-
72
+
73
+ # 🎯 Playwright browser cache
74
+ - name : Cache Playwright browsers
75
+ uses : actions/cache@v4
76
+ with :
77
+ path : ~/.cache/ms-playwright
78
+ key : ${{ runner.os }}-playwright-${{ hashFiles('**/package-lock.json') }}
79
+ restore-keys : |
80
+ ${{ runner.os }}-playwright-
38
81
39
- - name : Set Image Tag
40
- id : vars
41
- run : |
42
- BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF##*/}}
43
- IMAGE_BASE="${{ env.REGISTRY }}/${{ env.ORG_NAME }}/${{ env.REPO_NAME }}/${BRANCH_NAME}"
44
- echo "tag=${IMAGE_BASE}:amd64" >> $GITHUB_OUTPUT
82
+ - name : Install dependencies
83
+ run : npm ci --prefer-offline
45
84
46
- - name : Build + Push AMD64
47
- id : build
48
- uses : docker/build-push-action@v5
49
- with :
50
- context : .
51
- file : ./Dockerfile
52
- target : runner
53
- platforms : linux/amd64
54
- push : true
55
- provenance : true
56
- sbom : true
57
- build-args : |
58
- NEXT_PUBLIC_BACKEND_SERVICE_PROTOCOL=${{ vars.BACKEND_SERVICE_PROTOCOL }}
59
- NEXT_PUBLIC_BACKEND_SERVICE_HOST=${{ vars.BACKEND_SERVICE_HOST }}
60
- NEXT_PUBLIC_BACKEND_SERVICE_PORT=${{ vars.BACKEND_SERVICE_PORT }}
61
- NEXT_PUBLIC_BACKEND_SERVICE_API_PATH=${{ vars.BACKEND_SERVICE_API_PATH }}
62
- NEXT_PUBLIC_BACKEND_API_VERSION=${{ vars.BACKEND_API_VERSION }}
63
- NEXT_PUBLIC_TIPTAP_APP_ID=${{ vars.TIPTAP_APP_ID }}
64
- FRONTEND_SERVICE_PORT=${{ vars.FRONTEND_SERVICE_PORT }}
65
- FRONTEND_SERVICE_INTERFACE=${{ vars.FRONTEND_SERVICE_INTERFACE }}
66
- tags : ${{ steps.vars.outputs.tag }}
67
- cache-from : type=gha,scope=amd64
68
- cache-to : type=gha,mode=max,scope=amd64
85
+ - name : Build application
86
+ run : npm run build
69
87
70
- build_and_push_arm64 :
71
- runs-on : ubuntu-24.04
88
+ - name : Install Playwright browsers
89
+ run : npx playwright install --with-deps
90
+
91
+ - name : Run unit tests
92
+ run : npm run test:run
93
+
94
+ - name : Run E2E tests
95
+ run : npm run test:e2e
72
96
97
+ # === DOCKER BUILD & PUSH JOB ===
98
+ docker :
99
+ name : Build & Push Docker Image
100
+ runs-on : ubuntu-24.04
101
+ needs : [lint, test] # Only run if lint and test pass
102
+ if : github.event_name == 'push' || github.event_name == 'pull_request'
73
103
permissions :
74
104
contents : read
75
105
packages : write
106
+ attestations : write
76
107
id-token : write
77
108
78
109
steps :
79
- - uses : actions/checkout@v4
110
+ - name : Checkout
111
+ uses : actions/checkout@v4
80
112
81
- - uses : docker/setup-buildx-action@v3
82
- with :
83
- install : true
113
+ - name : Set up Docker Buildx
114
+ uses : docker/setup-buildx-action@v3
84
115
85
116
- name : Docker login
86
- uses : docker/login-action@v2
117
+ uses : docker/login-action@v3
87
118
with :
88
119
registry : ${{ env.REGISTRY }}
89
120
username : ${{ github.actor }}
90
121
password : ${{ secrets.GITHUB_TOKEN }}
91
122
92
- - name : Set Image Tag
93
- id : vars
123
+ - name : Determine Image Tags
124
+ id : tags
94
125
run : |
95
126
BRANCH_NAME=${GITHUB_HEAD_REF:-${GITHUB_REF##*/}}
96
127
IMAGE_BASE="${{ env.REGISTRY }}/${{ env.ORG_NAME }}/${{ env.REPO_NAME }}/${BRANCH_NAME}"
97
- echo "tag=${IMAGE_BASE}:arm64" >> $GITHUB_OUTPUT
128
+ echo "frontend_tags=$IMAGE_BASE:latest,$IMAGE_BASE:${{ github.sha }}" >> $GITHUB_OUTPUT
129
+ echo "frontend_image_name=$IMAGE_BASE" >> $GITHUB_OUTPUT
98
130
99
- - name : Build + Push ARM64
100
- id : build
131
+ - name : Build and Push Frontend Image
132
+ id : push_frontend
101
133
uses : docker/build-push-action@v5
102
134
with :
103
135
context : .
104
136
file : ./Dockerfile
105
137
target : runner
106
- platforms : linux/arm64
138
+ platforms : linux/amd64
107
139
push : true
108
140
provenance : true
109
141
sbom : true
@@ -116,6 +148,30 @@ jobs:
116
148
NEXT_PUBLIC_TIPTAP_APP_ID=${{ vars.TIPTAP_APP_ID }}
117
149
FRONTEND_SERVICE_PORT=${{ vars.FRONTEND_SERVICE_PORT }}
118
150
FRONTEND_SERVICE_INTERFACE=${{ vars.FRONTEND_SERVICE_INTERFACE }}
119
- tags : ${{ steps.vars.outputs.tag }}
120
- cache-from : type=gha,scope=arm64
121
- cache-to : type=gha,mode=max,scope=arm64
151
+ tags : ${{ steps.tags.outputs.frontend_tags }}
152
+ cache-from : type=gha,scope=frontend-nonprod
153
+ cache-to : type=gha,mode=max,scope=frontend-nonprod
154
+ labels : |
155
+ org.opencontainers.image.title=Refactor Platform Frontend
156
+ org.opencontainers.image.description=Next.js frontend for refactor coaching platform
157
+ org.opencontainers.image.source=${{ github.server_url }}/${{ github.repository }}
158
+ org.opencontainers.image.revision=${{ github.sha }}
159
+
160
+ - name : Attest Frontend Build
161
+ if : github.ref == 'refs/heads/main' && github.event_name == 'push'
162
+ uses : actions/attest-build-provenance@v2
163
+ with :
164
+ subject-name : ${{ steps.tags.outputs.frontend_image_name }}
165
+ subject-digest : ${{ steps.push_frontend.outputs.digest }}
166
+ push-to-registry : true
167
+
168
+ - name : Print Usage Instructions
169
+ run : |
170
+ echo "🎉 Build, Test & Push completed successfully!"
171
+ echo ""
172
+ echo "📦 Frontend Image Pushed:"
173
+ echo " docker pull ${{ steps.tags.outputs.frontend_image_name }}:latest"
174
+ echo " docker pull ${{ steps.tags.outputs.frontend_image_name }}:${{ github.sha }}"
175
+ echo ""
176
+ echo "🚀 Run Frontend:"
177
+ echo " docker run --rm --env-file .env -p 3000:3000 ${{ steps.tags.outputs.frontend_image_name }}:latest"
0 commit comments