Skip to content

Commit 8d34061

Browse files
committed
refactor(deploy): enhance deployment workflows and documentation
- Updated `DEPLOY.md` for clarity on docs deployment and versioning. - Modified GitHub Actions workflows to include selective deployment based on changes. - Added environment variable for Node.js version compatibility in API deployment. - Improved Dockerfile for Lambda API to support cross-compilation for arm64 architecture.
1 parent 95411f8 commit 8d34061

4 files changed

Lines changed: 93 additions & 37 deletions

File tree

.github/workflows/deploy-api.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
name: Deploy API to Lambda
22

3+
env:
4+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
5+
36
on:
47
push:
58
branches:

.github/workflows/deploy.yml

Lines changed: 81 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# Registry Deploy: test both components, build arm64 images, push to ECR, deploy stack.
1+
# Registry Deploy: test both components, build arm64 images (selective), push to ECR, deploy to EC2.
22
#
33
# Triggers:
4-
# - Push to main touching api/** or web/** or this workflow
5-
# - Manual dispatch with optional force deploy (skip tests)
4+
# - Push to main touching api/** or web/** or this workflow → build & deploy only what changed
5+
# - Manual dispatch: choose API only, Web only, or both (default)
66

77
name: Registry Deploy
88

@@ -19,12 +19,52 @@ on:
1919
description: "Force deploy (skip tests)"
2020
type: boolean
2121
default: false
22+
deploy_api:
23+
description: "Deploy API"
24+
type: boolean
25+
default: true
26+
deploy_web:
27+
description: "Deploy Web"
28+
type: boolean
29+
default: true
2230

2331
concurrency:
2432
group: registry-deploy
2533
cancel-in-progress: false
2634

35+
env:
36+
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
37+
2738
jobs:
39+
# ── What to build (path filter on push; inputs on manual) ─────────────────
40+
41+
changes:
42+
runs-on: ubuntu-latest
43+
outputs:
44+
build_api: ${{ steps.set.outputs.build_api }}
45+
build_web: ${{ steps.set.outputs.build_web }}
46+
steps:
47+
- uses: actions/checkout@v4
48+
with:
49+
fetch-depth: 0
50+
51+
- uses: dorny/paths-filter@v3
52+
id: paths
53+
with:
54+
filters: |
55+
api: 'api/**'
56+
web: 'web/**'
57+
58+
- id: set
59+
run: |
60+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
61+
echo "build_api=${{ inputs.deploy_api }}" >> $GITHUB_OUTPUT
62+
echo "build_web=${{ inputs.deploy_web }}" >> $GITHUB_OUTPUT
63+
else
64+
echo "build_api=${{ steps.paths.outputs.api }}" >> $GITHUB_OUTPUT
65+
echo "build_web=${{ steps.paths.outputs.web }}" >> $GITHUB_OUTPUT
66+
fi
67+
2868
# ── Tests ──────────────────────────────────────────────────────────────
2969

3070
test-api:
@@ -74,11 +114,12 @@ jobs:
74114
# ── Build & Push ───────────────────────────────────────────────────────
75115

76116
build-and-push:
77-
needs: [test-api, test-web]
117+
needs: [changes, test-api, test-web]
78118
if: |
79119
always() &&
80120
(needs.test-api.result == 'success' || needs.test-api.result == 'skipped') &&
81121
(needs.test-web.result == 'success' || needs.test-web.result == 'skipped') &&
122+
(needs.changes.outputs.build_api == 'true' || needs.changes.outputs.build_web == 'true') &&
82123
github.ref == 'refs/heads/main'
83124
runs-on: ubuntu-latest
84125
permissions:
@@ -100,6 +141,7 @@ jobs:
100141
- uses: docker/setup-buildx-action@v3
101142

102143
- name: Build and push API image
144+
if: needs.changes.outputs.build_api == 'true'
103145
uses: docker/build-push-action@v6
104146
with:
105147
context: api
@@ -112,6 +154,7 @@ jobs:
112154
cache-to: type=gha,mode=max,scope=registry-api
113155

114156
- name: Build and push Web image
157+
if: needs.changes.outputs.build_web == 'true'
115158
uses: docker/build-push-action@v6
116159
with:
117160
context: web
@@ -126,7 +169,7 @@ jobs:
126169
# ── Deploy ─────────────────────────────────────────────────────────────
127170

128171
deploy:
129-
needs: build-and-push
172+
needs: [build-and-push, changes]
130173
runs-on: ubuntu-latest
131174
permissions:
132175
contents: read
@@ -143,46 +186,59 @@ jobs:
143186
aws-region: us-east-1
144187

145188
- name: Deploy via EC2 Instance Connect
189+
env:
190+
DEPLOY_API: ${{ needs.changes.outputs.build_api }}
191+
DEPLOY_WEB: ${{ needs.changes.outputs.build_web }}
146192
run: |
147-
# Generate ephemeral SSH key (valid ~60s after push)
148193
ssh-keygen -t ed25519 -f /tmp/deploy_key -N "" -q
149194
aws ec2-instance-connect send-ssh-public-key \
150195
--instance-id "$EC2_INSTANCE_ID" \
151196
--instance-os-user ubuntu \
152197
--ssh-public-key file:///tmp/deploy_key.pub
153198
154-
# Rolling deploy: pull new images, restart web first (faster), then api
199+
# Build compose up args from what we deployed
200+
UP_ARGS=""
201+
if [ "$DEPLOY_API" = "true" ] && [ "$DEPLOY_WEB" = "true" ]; then
202+
UP_ARGS="web api"
203+
elif [ "$DEPLOY_WEB" = "true" ]; then
204+
UP_ARGS="web"
205+
elif [ "$DEPLOY_API" = "true" ]; then
206+
UP_ARGS="api"
207+
fi
208+
155209
ssh -i /tmp/deploy_key -o StrictHostKeyChecking=no ubuntu@"$EC2_HOST" \
156210
"set -euo pipefail && \
157211
aws ecr get-login-password --region us-east-1 | docker login --username AWS --password-stdin $ECR_REGISTRY && \
158212
cd /opt/devsper-registry && \
159-
docker compose -f docker-compose.prod.yml --env-file .env.prod pull api web && \
160-
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --no-deps web && \
213+
docker compose -f docker-compose.prod.yml --env-file .env.prod pull $UP_ARGS && \
214+
([ \"$DEPLOY_WEB\" = true ] && docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --no-deps web || true) && \
161215
sleep 3 && \
162-
docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --no-deps api && \
216+
([ \"$DEPLOY_API\" = true ] && docker compose -f docker-compose.prod.yml --env-file .env.prod up -d --no-deps api || true) && \
163217
docker image prune -f"
164218
165219
rm -f /tmp/deploy_key /tmp/deploy_key.pub
166220
167221
- name: Smoke test
222+
env:
223+
DEPLOY_API: ${{ needs.changes.outputs.build_api }}
224+
DEPLOY_WEB: ${{ needs.changes.outputs.build_web }}
168225
run: |
169226
echo "Waiting for services to stabilize..."
170-
sleep 8
171-
172-
# Check API health
173-
curl -sf --retry 3 --retry-delay 5 "https://registry.devsper.com/health" || \
174-
{ echo "FAIL: /health"; exit 1; }
227+
sleep 15
175228
176-
# Check JWKS endpoint
177-
curl -sf --retry 3 --retry-delay 5 "https://registry.devsper.com/auth/jwks" || \
178-
{ echo "FAIL: /auth/jwks"; exit 1; }
229+
BASE="https://registry.devsper.com"
230+
CURL_OPTS="-sf --retry 5 --retry-delay 8 --retry-all-errors"
179231
180-
# Check web frontend
181-
curl -sf --retry 3 --retry-delay 5 "https://registry.devsper.com/" || \
182-
{ echo "FAIL: / (web)"; exit 1; }
232+
if [ "$DEPLOY_API" = "true" ]; then
233+
echo "Checking API..."
234+
curl $CURL_OPTS "$BASE/health" || { echo "FAIL: /health"; exit 1; }
235+
curl $CURL_OPTS "$BASE/auth/jwks" || { echo "FAIL: /auth/jwks"; exit 1; }
236+
curl $CURL_OPTS "$BASE/api/v1/packages" || { echo "FAIL: /api/v1/packages"; exit 1; }
237+
fi
183238
184-
# Check packages API
185-
curl -sf --retry 3 --retry-delay 5 "https://registry.devsper.com/api/v1/packages" || \
186-
{ echo "FAIL: /api/v1/packages"; exit 1; }
239+
if [ "$DEPLOY_WEB" = "true" ]; then
240+
echo "Checking web..."
241+
curl $CURL_OPTS "$BASE/" || { echo "FAIL: / (web)"; exit 1; }
242+
fi
187243
188-
echo "All smoke tests passed"
244+
echo "All smoke tests passed"

DEPLOY.md

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,9 @@ Triggers on push to `main` touching `registry/**`, or manual dispatch.
2222

2323
Manual dispatch supports a `force` boolean to skip tests.
2424

25-
### `docs-deploy.yml`Docs Deploy
25+
### Docs deploy
2626

27-
Triggers on push to `main` touching `website/**`, or manual dispatch.
28-
29-
Single job: build Docusaurus, rsync `website/build/` to EC2 `/opt/devsper-docs/`, verify with curl.
30-
31-
### `docs.yml` — Docs Versioning
32-
33-
Triggers on release published. Creates a versioned docs snapshot via `docusaurus docs:version` and opens a PR to merge it into main.
27+
Docs site and its deploy live in the **docs** repo. Push to `main` there builds Docusaurus and rsyncs `build/` to EC2 `/opt/devsper-docs/` (see `docs/.github/workflows/deploy-ec2.yml`). Versioning (if used) is also handled in the docs repo.
3428

3529
## GitHub Configuration
3630

@@ -149,6 +143,7 @@ Trigger via GitHub Actions → "Docs Deploy" → Run workflow.
149143
Or build locally and rsync:
150144

151145
```bash
152-
cd website && npm ci && npm run build
153-
rsync -azP --delete website/build/ ubuntu@<ec2-host>:/opt/devsper-docs/
146+
# From the docs repo root:
147+
npm ci && npm run build
148+
rsync -azP --delete build/ ubuntu@<ec2-host>:/opt/devsper-docs/
154149
```

api/Dockerfile.lambda

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
# Lambda-compatible Dockerfile for Go API
22
# Uses AWS Lambda Web Adapter to proxy Lambda invoke → HTTP on :8080
3+
# Builder runs on host arch (e.g. amd64 on CI); we cross-compile Go for arm64.
34

4-
# Stage 1: builder
5-
FROM golang:1.24-alpine AS builder
5+
ARG BUILDPLATFORM
6+
# Stage 1: builder (native platform so no exec format error on amd64 runners)
7+
FROM --platform=$BUILDPLATFORM golang:1.24-alpine AS builder
68
RUN apk add --no-cache ca-certificates git
79
WORKDIR /app
810
COPY go.mod go.sum ./

0 commit comments

Comments
 (0)