Skip to content

Commit 24d0d43

Browse files
author
Pier Dolique
committed
refactor(ci): extract reusable workflow for deployment
- ♻️ Create reusable-deploy.yml with parameterized inputs - 🔧 Add working-directory support for monorepo compatibility - 🔐 Move Cloudflare credentials to workflow secrets - ✨ Support customizable build and deploy commands - 🎯 Enable optional typecheck job via input parameter - 🚀 Simplify build-and-deploy.yml to use reusable workflow - 📦 Use defaults.run.working-directory for cleaner syntax
1 parent 891d3e2 commit 24d0d43

2 files changed

Lines changed: 215 additions & 149 deletions

File tree

Lines changed: 5 additions & 149 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
name: Build and Deploy
2-
description: Build the project and deploy to the appropriate environment.
32

43
permissions:
54
contents: read
@@ -16,156 +15,13 @@ on:
1615
branches:
1716
- master
1817

19-
env:
20-
ARTIFACT_NAME: deployment-artifact
21-
ARTIFACT_PATH: .output
22-
2318
concurrency:
2419
group: build-and-deploy-${{ github.ref }}
2520
cancel-in-progress: true
2621

2722
jobs:
28-
# Check Typescript types correctness
29-
test-typecheck:
30-
name: Typecheck
31-
runs-on: ubuntu-24.04
32-
steps:
33-
- name: Checkout repository
34-
uses: actions/checkout@v5
35-
- uses: ./.github/actions/setup-pnpm
36-
with:
37-
install-dependencies: true
38-
- name: Run typecheck
39-
run: |
40-
pnpm test:typecheck
41-
42-
# Build the project and upload artifact
43-
build:
44-
name: Build artifact
45-
runs-on: ubuntu-24.04
46-
steps:
47-
- name: Checkout repository
48-
uses: actions/checkout@v5
49-
- uses: ./.github/actions/setup-pnpm
50-
with:
51-
install-dependencies: true
52-
- name: Build project
53-
run: |
54-
pnpm run build
55-
- name: Upload build artifact
56-
id: upload-artifact
57-
uses: actions/upload-artifact@v5
58-
with:
59-
include-hidden-files: true
60-
if-no-files-found: error
61-
name: ${{ env.ARTIFACT_NAME }}
62-
path: ${{ env.ARTIFACT_PATH }}
63-
64-
deploy-to-staging:
65-
if: github.event_name == 'pull_request'
66-
name: Deploy to staging
67-
runs-on: ubuntu-24.04
68-
permissions:
69-
pull-requests: write
70-
outputs:
71-
wrangler-log: ${{ steps.set-wrangler-log.outputs.wrangler-log }}
72-
needs:
73-
- build
74-
steps:
75-
# Checkout repository
76-
- name: Checkout repository
77-
uses: actions/checkout@v5
78-
79-
# Setup, and download artifact
80-
- uses: ./.github/actions/pre-deploy
81-
with:
82-
artifact-name: ${{ env.ARTIFACT_NAME }}
83-
unpack-path: ${{ env.ARTIFACT_PATH }}
84-
85-
# Set wrangler log file path for capturing output
86-
- name: Set wrangler output file path
87-
id: set-wrangler-log
88-
run: |
89-
WRANGLER_LOG=/tmp/wrangler-$(date '+%s%N').log
90-
echo "wrangler-log=$WRANGLER_LOG" >> $GITHUB_OUTPUT
91-
92-
# Deploy to Cloudflare Workers
93-
- name: Deploy version to staging
94-
id: deploy-version
95-
continue-on-error: true
96-
env:
97-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
98-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
99-
run: |
100-
export WRANGLER_OUTPUT_FILE_PATH=${{ steps.set-wrangler-log.outputs.wrangler-log }}
101-
pnpm run deploy:versions:staging
102-
103-
# Extract deployment URL from wrangler log
104-
- name: Get deployment URL
105-
id: get-deployment-url
106-
continue-on-error: true
107-
run: |
108-
PREVIEW_URL=$(jq --raw-output --slurp 'first(.[] | select(.preview_url) | .preview_url)' ${{ steps.set-wrangler-log.outputs.wrangler-log }})
109-
110-
if [ -z "$PREVIEW_URL" ]; then
111-
echo "Error: No preview_url found in wrangler log"
112-
exit 1
113-
fi
114-
115-
echo "preview-url=$PREVIEW_URL" >> $GITHUB_OUTPUT
116-
117-
# Comment on the pull request with success status
118-
- name: Comment successful deployment URL
119-
if: ${{ steps.get-deployment-url.outcome == 'success' }}
120-
uses: marocchino/sticky-pull-request-comment@v2
121-
with:
122-
message: |
123-
## 🎉 Deployed to Cloudflare!
124-
125-
- Commit: `${{ github.sha }}`
126-
- Preview URL: ${{ steps.get-deployment-url.outputs.preview-url }}
127-
128-
# Comment on the pull request with failure status
129-
- name: Comment deployment failure
130-
if: ${{ steps.get-deployment-url.outcome == 'failure' }}
131-
uses: marocchino/sticky-pull-request-comment@v2
132-
with:
133-
message: |
134-
## ❌ Deployment to Cloudflare failed!
135-
136-
- Commit: `${{ github.sha }}`
137-
- Please check the [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details.
138-
139-
# Fail the workflow if deployment failed
140-
- name: Fail workflow if deployment failed
141-
if: ${{ steps.get-deployment-url.outcome == 'failure' }}
142-
run: |
143-
echo "Deployment to staging failed."
144-
exit 1
145-
146-
deploy-to-production:
147-
if: github.event_name == 'push'
148-
name: Deploy to production
149-
runs-on: ubuntu-24.04
150-
needs:
151-
- build
152-
- test-typecheck
153-
steps:
154-
# Checkout repository
155-
- name: Checkout repository
156-
uses: actions/checkout@v5
157-
158-
# Setup, and download artifact
159-
- uses: ./.github/actions/pre-deploy
160-
with:
161-
artifact-name: ${{ env.ARTIFACT_NAME }}
162-
unpack-path: ${{ env.ARTIFACT_PATH }}
163-
164-
# Deploy to Cloudflare Workers
165-
- name: Deploy to production
166-
id: deploy-production
167-
env:
168-
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
169-
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
170-
run: |
171-
pnpm run deploy:production
23+
deploy:
24+
uses: ./.github/workflows/reusable-deploy.yml
25+
secrets:
26+
cloudflare-account-id: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
27+
cloudflare-api-token: ${{ secrets.CLOUDFLARE_API_TOKEN }}
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
name: Reusable Deploy Workflow
2+
3+
on:
4+
workflow_call:
5+
inputs:
6+
working-directory:
7+
description: Working directory for the project
8+
required: false
9+
default: '.'
10+
type: string
11+
artifact-path:
12+
description: Path to the build output directory
13+
required: false
14+
default: '.output'
15+
type: string
16+
artifact-name:
17+
description: Name of the deployment artifact
18+
required: false
19+
default: 'deployment-artifact'
20+
type: string
21+
build-command:
22+
description: pnpm script name for building the project
23+
required: false
24+
default: 'build'
25+
type: string
26+
typecheck-command:
27+
description: pnpm script name for type checking (optional, skipped if empty)
28+
required: false
29+
default: 'test:typecheck'
30+
type: string
31+
deploy-staging-command:
32+
description: pnpm script name for deploying to staging
33+
required: false
34+
default: 'deploy:versions:staging'
35+
type: string
36+
deploy-production-command:
37+
description: pnpm script name for deploying to production
38+
required: false
39+
default: 'deploy:production'
40+
type: string
41+
secrets:
42+
cloudflare-account-id:
43+
description: Cloudflare account ID
44+
required: true
45+
cloudflare-api-token:
46+
description: Cloudflare API token
47+
required: true
48+
49+
concurrency:
50+
group: ${{ inputs.artifact-name }}-${{ github.ref }}
51+
cancel-in-progress: true
52+
53+
jobs:
54+
# Check Typescript types correctness
55+
test-typecheck:
56+
if: inputs.typecheck-command != ''
57+
name: Typecheck
58+
runs-on: ubuntu-24.04
59+
defaults:
60+
run:
61+
working-directory: ${{ inputs.working-directory }}
62+
steps:
63+
- name: Checkout repository
64+
uses: actions/checkout@v5
65+
- uses: ./.github/actions/setup-pnpm
66+
with:
67+
install-dependencies: true
68+
- name: Run typecheck
69+
run: |
70+
pnpm ${{ inputs.typecheck-command }}
71+
72+
# Build the project and upload artifact
73+
build:
74+
name: Build artifact
75+
runs-on: ubuntu-24.04
76+
defaults:
77+
run:
78+
working-directory: ${{ inputs.working-directory }}
79+
steps:
80+
- name: Checkout repository
81+
uses: actions/checkout@v5
82+
- uses: ./.github/actions/setup-pnpm
83+
with:
84+
install-dependencies: true
85+
- name: Build project
86+
run: |
87+
pnpm run ${{ inputs.build-command }}
88+
- name: Upload build artifact
89+
id: upload-artifact
90+
uses: actions/upload-artifact@v5
91+
with:
92+
include-hidden-files: true
93+
if-no-files-found: error
94+
name: ${{ inputs.artifact-name }}
95+
path: ${{ inputs.artifact-path }}
96+
97+
deploy-to-staging:
98+
if: github.event_name == 'pull_request'
99+
name: Deploy to staging
100+
runs-on: ubuntu-24.04
101+
permissions:
102+
pull-requests: write
103+
outputs:
104+
wrangler-log: ${{ steps.set-wrangler-log.outputs.wrangler-log }}
105+
needs:
106+
- build
107+
defaults:
108+
run:
109+
working-directory: ${{ inputs.working-directory }}
110+
steps:
111+
# Checkout repository
112+
- name: Checkout repository
113+
uses: actions/checkout@v5
114+
115+
# Setup, and download artifact
116+
- uses: ./.github/actions/pre-deploy
117+
with:
118+
artifact-name: ${{ inputs.artifact-name }}
119+
unpack-path: ${{ inputs.artifact-path }}
120+
121+
# Set wrangler log file path for capturing output
122+
- name: Set wrangler output file path
123+
id: set-wrangler-log
124+
run: |
125+
WRANGLER_LOG=/tmp/wrangler-$(date '+%s%N').log
126+
echo "wrangler-log=$WRANGLER_LOG" >> $GITHUB_OUTPUT
127+
128+
# Deploy to Cloudflare Workers
129+
- name: Deploy version to staging
130+
id: deploy-version
131+
continue-on-error: true
132+
env:
133+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.cloudflare-account-id }}
134+
CLOUDFLARE_API_TOKEN: ${{ secrets.cloudflare-api-token }}
135+
run: |
136+
export WRANGLER_OUTPUT_FILE_PATH=${{ steps.set-wrangler-log.outputs.wrangler-log }}
137+
pnpm run ${{ inputs.deploy-staging-command }}
138+
139+
# Extract deployment URL from wrangler log
140+
- name: Get deployment URL
141+
id: get-deployment-url
142+
continue-on-error: true
143+
run: |
144+
PREVIEW_URL=$(jq --raw-output --slurp 'first(.[] | select(.preview_url) | .preview_url)' ${{ steps.set-wrangler-log.outputs.wrangler-log }})
145+
146+
if [ -z "$PREVIEW_URL" ]; then
147+
echo "Error: No preview_url found in wrangler log"
148+
exit 1
149+
fi
150+
151+
echo "preview-url=$PREVIEW_URL" >> $GITHUB_OUTPUT
152+
153+
# Comment on the pull request with success status
154+
- name: Comment successful deployment URL
155+
if: ${{ steps.get-deployment-url.outcome == 'success' }}
156+
uses: marocchino/sticky-pull-request-comment@v2
157+
with:
158+
message: |
159+
## 🎉 Deployed to Cloudflare!
160+
161+
- Commit: `${{ github.sha }}`
162+
- Preview URL: ${{ steps.get-deployment-url.outputs.preview-url }}
163+
164+
# Comment on the pull request with failure status
165+
- name: Comment deployment failure
166+
if: ${{ steps.get-deployment-url.outcome == 'failure' }}
167+
uses: marocchino/sticky-pull-request-comment@v2
168+
with:
169+
message: |
170+
## ❌ Deployment to Cloudflare failed!
171+
172+
- Commit: `${{ github.sha }}`
173+
- Please check the [workflow logs](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for more details.
174+
175+
# Fail the workflow if deployment failed
176+
- name: Fail workflow if deployment failed
177+
if: ${{ steps.get-deployment-url.outcome == 'failure' }}
178+
run: |
179+
echo "Deployment to staging failed."
180+
exit 1
181+
182+
deploy-to-production:
183+
if: github.event_name == 'push'
184+
name: Deploy to production
185+
runs-on: ubuntu-24.04
186+
needs:
187+
- build
188+
- test-typecheck
189+
defaults:
190+
run:
191+
working-directory: ${{ inputs.working-directory }}
192+
steps:
193+
# Checkout repository
194+
- name: Checkout repository
195+
uses: actions/checkout@v5
196+
197+
# Setup, and download artifact
198+
- uses: ./.github/actions/pre-deploy
199+
with:
200+
artifact-name: ${{ inputs.artifact-name }}
201+
unpack-path: ${{ inputs.artifact-path }}
202+
203+
# Deploy to Cloudflare Workers
204+
- name: Deploy to production
205+
id: deploy-production
206+
env:
207+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.cloudflare-account-id }}
208+
CLOUDFLARE_API_TOKEN: ${{ secrets.cloudflare-api-token }}
209+
run: |
210+
pnpm run ${{ inputs.deploy-production-command }}

0 commit comments

Comments
 (0)