@@ -2,151 +2,110 @@ name: CI + Deploy (prebuilt)
22
33on :
44 push :
5- branches : [ '**' ] # prod only for main; others -> preview
5+ branches : [ '**' ]
66 pull_request :
7- branches : [ main ] # PRs into main get preview link
7+ branches : [ main ]
88
99permissions :
1010 contents : read
11- issues : write
12- pull-requests : write
1311 deployments : write
12+ pull-requests : write
1413
1514env :
1615 VERCEL_TOKEN : ${{ secrets.VERCEL_TOKEN }}
1716 VERCEL_ORG : ${{ secrets.VERCEL_ORG_ID }}
1817
1918jobs :
20- build_and_test :
19+ build_and_deploy :
2120 runs-on : ubuntu-latest
2221 steps :
22+ # Checkout repo
2323 - uses : actions/checkout@v4
24+
25+ # Setup Node.js + cache
2426 - uses : actions/setup-node@v4
2527 with :
2628 node-version : 18
2729 cache : ' npm'
28- - name : Install
29- run : npm ci || npm install
30- - name : Lint
31- run : npm run -s | grep -qE '(^| )lint( |:)' && npm run lint || echo "No lint script"
32- - name : Unit tests
33- run : npm run -s | grep -qE '(^| )test( |:)' && npm test --ci --passWithNoTests=false || echo "No test script"
34- - name : E2E tests (optional)
35- run : npm run -s | grep -qE '(^| )e2e( |:)' && npm run e2e || echo "No e2e script"
36- - name : App build
37- run : npm run build
38- - name : Build summary
39- run : echo "Build & tests passed ✅" >> "$GITHUB_STEP_SUMMARY"
4030
41- deploy :
42- needs : build_and_test
43- if : ${{ success() }}
44- runs-on : ubuntu-latest
45- steps :
46- # PR conflict notice (comment)
47- - name : Warn if conflicts detected
48- if : ${{ github.event_name == 'pull_request' && github.event.pull_request.mergeable == false }}
49- uses : actions/github-script@v7
50- with :
51- script : |
52- await github.rest.issues.createComment({
53- ...context.repo,
54- issue_number: context.payload.pull_request.number,
55- body: "⚠️ **Merge conflict detected!**\nPlease resolve conflicts before merging."
56- })
31+ # Install dependencies
32+ - name : Install dependencies
33+ run : npm ci || npm install
5734
58- # PR conflict → fail checks (stops deploy)
59- - name : Fail if conflicts detected
60- if : ${{ github.event_name == 'pull_request' && github.event.pull_request.mergeable == false }}
61- run : |
62- echo "::error title=Merge conflict detected::Please resolve conflicts before merging."
63- exit 1
35+ # Build project
36+ - name : Build app
37+ run : npm run build
6438
65- - uses : actions/checkout@v4
66- - uses : actions/setup-node@v4
67- with :
68- node-version : 18
69- cache : ' npm'
70- - name : Install Vercel CLI
39+ # Install Vercel CLI
40+ - name : Setup Vercel CLI
7141 run : npm i -g vercel@latest
7242
73- - name : Decide target
74- id : tgt
43+ # Define target (preview or production)
44+ - name : Define target
45+ id : target
7546 run : |
76- if [ "${{ github.event_name }}" = "pull_request" ]; then
77- echo "target=preview" >> $GITHUB_OUTPUT
78- elif [ "${{ github.ref_name }}" = "main" ]; then
79- echo "target=production" >> $GITHUB_OUTPUT
47+ if [ "${{ github.ref_name }}" = "main" ]; then
48+ echo "env=production" >> $GITHUB_OUTPUT
8049 else
81- echo "target =preview" >> $GITHUB_OUTPUT
50+ echo "env =preview" >> $GITHUB_OUTPUT
8251 fi
8352
84- - name : Pull Vercel project settings
53+ # Pull project config and environment vars
54+ - name : Pull Vercel settings
8555 run : |
8656 vercel pull --yes \
87- --environment "${{ steps.tgt .outputs.target }}" \
88- --token "${{ env.VERCEL_TOKEN }}" \
89- --scope "${{ env.VERCEL_ORG }}"
57+ --environment= "${{ steps.target .outputs.env }}" \
58+ --token= "${{ env.VERCEL_TOKEN }}" \
59+ --scope= "${{ env.VERCEL_ORG }}"
9060
91- - name : Vercel prebuild
61+ # Prebuild app (creates .vercel/output)
62+ - name : Prebuild Vercel output
9263 run : |
9364 vercel build \
94- --token "${{ env.VERCEL_TOKEN }}" \
95- --scope "${{ env.VERCEL_ORG }}"
65+ --token= "${{ env.VERCEL_TOKEN }}" \
66+ --scope= "${{ env.VERCEL_ORG }}"
9667
97- - name : Deploy (prebuilt)
68+ # Deploy prebuilt build to Vercel
69+ - name : Deploy prebuilt build
9870 id : deploy
99- env :
100- VC_TOKEN : ${{ env.VERCEL_TOKEN }}
101- VC_TEAM : ${{ env.VERCEL_ORG }}
102- TARGET : ${{ steps.tgt.outputs.target }}
10371 run : |
10472 set -e
105- ARGS=(deploy --yes --token "$VC_TOKEN" --scope "$VC_TEAM" --prebuilt)
106- [ "$TARGET" = "production" ] && ARGS+=(--prod) || true
107- URL="$(vercel "${ARGS[@]}")"
108- echo "url=$URL" >> "$GITHUB_OUTPUT"
109- echo "Deployed: $URL"
110-
111- - name : Summary
112- run : |
113- echo "### Deployment" >> "$GITHUB_STEP_SUMMARY"
114- echo "- Target: **${{ steps.tgt.outputs.target }}**" >> "$GITHUB_STEP_SUMMARY"
115- if [ "${{ steps.tgt.outputs.target }}" = "production" ]; then
116- echo "- URL: (hidden for production)" >> "$GITHUB_STEP_SUMMARY"
73+ if [ "${{ steps.target.outputs.env }}" = "production" ]; then
74+ URL=$(vercel deploy --prebuilt --prod --yes --token "${{ env.VERCEL_TOKEN }}" --scope "${{ env.VERCEL_ORG }}")
11775 else
118- echo "- URL: ${{ steps.deploy.outputs.url }}" >> "$GITHUB_STEP_SUMMARY"
76+ URL=$(vercel deploy --prebuilt --yes --token "${{ env.VERCEL_TOKEN }}" --scope "${{ env.VERCEL_ORG }}")
77+ fi
78+ echo "url=$URL" >> "$GITHUB_OUTPUT"
79+ echo "✅ Deployed to $URL"
11980
120- - name : Post Preview URL to PR
121- if : ${{ github.event_name == 'pull_request' && steps.deploy.outputs.url != '' }}
81+ # Comment on PRs (preview link only)
82+ - name : Comment Preview URL on PR
83+ if : ${{ github.event_name == 'pull_request' }}
12284 uses : actions/github-script@v7
12385 with :
12486 script : |
12587 await github.rest.issues.createComment({
12688 ...context.repo,
12789 issue_number: context.payload.pull_request.number,
128- body: `✅ Preview ready: ${{ steps.deploy.outputs.url }}`
90+ body: `✅ ** Preview ready:** ${{ steps.deploy.outputs.url }}`
12991 })
13092
131- - name : Link deployment to commit
132- if : ${{ github.event_name == 'push' && steps.deploy.outputs.url != '' }}
93+ # Create GitHub Deployment card for main branch
94+ - name : Create Deployment Card
95+ if : ${{ github.ref_name == 'main' }}
13396 uses : actions/github-script@v7
13497 with :
13598 script : |
136- const isProd = (context.ref === 'refs/heads/main');
137- const envName = isProd ? 'production' : context.ref.replace('refs/heads/', '');
13899 const { data: dep } = await github.rest.repos.createDeployment({
139100 ...context.repo,
140101 ref: context.sha,
141- environment: envName ,
102+ environment: 'production' ,
142103 auto_merge: false,
143104 required_contexts: []
144105 });
145- const status = {
106+ await github.rest.repos.createDeploymentStatus( {
146107 ...context.repo,
147108 deployment_id: dep.id,
148109 state: 'success',
149- environment: envName
150- };
151- if (!isProd) status.environment_url = '${{ steps.deploy.outputs.url }}';
152- await github.rest.repos.createDeploymentStatus(status);
110+ environment: 'production'
111+ });
0 commit comments