Repository navigation
160 lines (131 loc) · 6.14 KB
/
Copy pathdeploy-library-api.yml
File metadata and controls
160 lines (131 loc) · 6.14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# This workflow uses devbox for dependency management and builds/deploys the library API
# to Cloud Run when a version tag is pushed (e.g., library-api-v1.0.0).
name: 'Build and Deploy Library API to Cloud Run'
on:
push:
tags:
- 'library-api-v*'
env:
PROJECT_ID: 'benefit-decision-toolkit-play'
REGION: 'us-central1'
SERVICE: 'benefit-decision-toolkit-play'
API_NAME: 'library-api'
WORKLOAD_IDENTITY_PROVIDER: 'projects/1034049717668/locations/global/workloadIdentityPools/github-actions-google-cloud/providers/github'
jobs:
deploy:
runs-on: 'ubuntu-latest'
permissions:
contents: 'read'
id-token: 'write'
steps:
- name: 'Checkout'
uses: 'actions/checkout@v4'
- name: 'Setup devbox'
uses: ./.github/actions/devbox-setup
# Cache Maven dependencies to speed up builds
- name: 'Cache Maven dependencies'
uses: 'actions/cache@v4'
with:
path: ~/.m2/repository
key: ${{ runner.os }}-maven-${{ hashFiles('library-api/pom.xml') }}
restore-keys: |
${{ runner.os }}-maven-
# Extract version from pom.xml (source of truth) using Maven
- name: 'Extract version from pom.xml'
id: extract_version
run: |
# Use -f to specify the pom.xml path (devbox runs from repo root)
VERSION=$(devbox run -q -- mvn -f library-api/pom.xml help:evaluate -Dexpression=project.version -q -DforceStdout 2>&1 | tail -1 | xargs)
echo "Extracted VERSION: '${VERSION}'"
# Validate it's a semantic version
if ! [[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
echo "ERROR: Invalid version format: '$VERSION'"
echo "Expected semantic version (e.g., 0.1.2)"
exit 1
fi
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
# Create revision-safe version string (replace dots with dashes for Cloud Run)
REVISION_VERSION=$(echo "${VERSION}" | tr '.' '-')
echo "revision_version=${REVISION_VERSION}" >> "$GITHUB_OUTPUT"
echo "Extracted version from pom.xml: ${VERSION}"
echo "Revision version: ${REVISION_VERSION}"
# Validate that git tag exists for this pom.xml version
- name: 'Validate git tag matches pom.xml version'
run: |
devbox run -q -- bin/validate-library-api-version
# Configure Workload Identity Federation and generate an access token
- id: 'auth'
name: 'Authenticate to Google Cloud'
uses: 'google-github-actions/auth@v2'
with:
workload_identity_provider: '${{ env.WORKLOAD_IDENTITY_PROVIDER }}'
service_account: cicd-build-deploy-api@benefit-decision-toolkit-play.iam.gserviceaccount.com
project_id: ${{ env.PROJECT_ID }}
# Configure Docker to use gcloud as a credential helper (using devbox gcloud)
- name: 'Configure Docker'
run: |
devbox run -q -- gcloud auth configure-docker ${{ env.REGION }}-docker.pkg.dev
# Build the Quarkus app with Maven using devbox environment
- name: 'Build Quarkus App'
working-directory: library-api
run: |
devbox run -q build-library-api-ci
- name: 'Build and Push Container'
working-directory: library-api
run: |-
VERSION="${{ steps.extract_version.outputs.version }}"
DOCKER_TAG_VERSIONED="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.API_NAME }}:v${VERSION}"
DOCKER_TAG_LATEST="${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.API_NAME }}:latest"
# Build and tag with version
docker build -f src/main/docker/Dockerfile.jvm --tag "${DOCKER_TAG_VERSIONED}" --tag "${DOCKER_TAG_LATEST}" .
# Verify the release image can start before publishing it.
CONTAINER_NAME="library-api-smoke"
trap 'docker rm --force "${CONTAINER_NAME}" >/dev/null 2>&1 || true' EXIT
docker run --detach --name "${CONTAINER_NAME}" --env PORT=8080 --publish 127.0.0.1:8080:8080 "${DOCKER_TAG_VERSIONED}"
for attempt in {1..30}; do
if curl --fail --silent http://127.0.0.1:8080/q/health/ready >/dev/null; then
break
fi
if ! docker inspect --format '{{.State.Running}}' "${CONTAINER_NAME}" | grep --quiet true; then
echo "ERROR: Container exited before becoming ready"
docker logs "${CONTAINER_NAME}"
exit 1
fi
if [[ "${attempt}" -eq 30 ]]; then
echo "ERROR: Container did not become ready within 30 seconds"
docker logs "${CONTAINER_NAME}"
exit 1
fi
sleep 1
done
docker rm --force "${CONTAINER_NAME}"
trap - EXIT
# Push both tags
docker push "${DOCKER_TAG_VERSIONED}"
docker push "${DOCKER_TAG_LATEST}"
echo "Pushed images:"
echo " - ${DOCKER_TAG_VERSIONED}"
echo " - ${DOCKER_TAG_LATEST}"
- name: 'Deploy to Cloud Run'
id: deploy
uses: 'google-github-actions/deploy-cloudrun@v2'
with:
service: '${{ env.API_NAME }}'
region: '${{ env.REGION }}'
image: '${{ env.REGION }}-docker.pkg.dev/${{ env.PROJECT_ID }}/${{ env.SERVICE }}/${{ env.API_NAME }}:v${{ steps.extract_version.outputs.version }}'
tag: '${{ env.API_NAME }}-v${{ steps.extract_version.outputs.revision_version }}'
flags: '--allow-unauthenticated --max-instances=2 --service-account=library-api-service-account@${{ env.PROJECT_ID }}.iam.gserviceaccount.com'
# Show deployment output
- name: 'Show deployment output'
run: |
echo "Deployment complete!"
echo "Service URL: ${{ steps.deploy.outputs.url }}"
echo "Version: v${{ steps.extract_version.outputs.version }}"
echo "Revision: ${{ env.API_NAME }}-v${{ steps.extract_version.outputs.revision_version }}"
sync-metadata:
needs: deploy
permissions:
contents: read
id-token: write
uses: ./.github/workflows/load-library-metadata.yml
secrets: inherit