@hed-hog/cli 0.0.60 → 0.0.61

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -23,6 +23,23 @@ spec:
23
23
  env:
24
24
  - name: NODE_ENV
25
25
  value: production
26
+ <% if (app === 'admin') { %>
27
+ - name: INTERNAL_API_URL
28
+ valueFrom:
29
+ configMapKeyRef:
30
+ name: <%= config.appName %>-<%= app %>-config
31
+ key: INTERNAL_API_URL
32
+ - name: NEXT_PUBLIC_API_BASE_URL
33
+ valueFrom:
34
+ configMapKeyRef:
35
+ name: <%= config.appName %>-<%= app %>-config
36
+ key: NEXT_PUBLIC_API_BASE_URL
37
+ - name: NEXT_PUBLIC_API_URL
38
+ valueFrom:
39
+ configMapKeyRef:
40
+ name: <%= config.appName %>-<%= app %>-config
41
+ key: NEXT_PUBLIC_API_URL
42
+ <% } else { %>
26
43
  <%
27
44
  const secretEnvKeys = new Set(['DATABASE_URL', 'ENCRYPTION_SECRET', 'JWT_SECRET', 'PEPPER']);
28
45
  Object.keys(appEnv || {}).sort().filter((key) => key !== 'NODE_ENV').forEach((key) => {
@@ -37,6 +54,7 @@ Object.keys(appEnv || {}).sort().filter((key) => key !== 'NODE_ENV').forEach((ke
37
54
  key: <%= key %>
38
55
  <% } %>
39
56
  <% }); %>
57
+ <% } %>
40
58
  resources:
41
59
  requests:
42
60
  memory: 512Mi
@@ -46,22 +64,28 @@ Object.keys(appEnv || {}).sort().filter((key) => key !== 'NODE_ENV').forEach((ke
46
64
  cpu: 500m
47
65
  startupProbe:
48
66
  httpGet:
49
- path: <%= app === 'api' ? '/health' : '/' %>
67
+ path: <%= app === 'api' || app === 'admin' ? '/health' : '/' %>
50
68
  port: <%= config.appPorts?.[app] ?? (app === 'api' ? 3000 : 80) %>
51
69
  initialDelaySeconds: 15
52
70
  periodSeconds: 10
53
71
  failureThreshold: 12
72
+ <% if (app === 'admin') { %> timeoutSeconds: 5
73
+ <% } %>
54
74
  livenessProbe:
55
75
  httpGet:
56
- path: <%= app === 'api' ? '/health' : '/' %>
76
+ path: <%= app === 'api' || app === 'admin' ? '/health' : '/' %>
57
77
  port: <%= config.appPorts?.[app] ?? (app === 'api' ? 3000 : 80) %>
58
78
  initialDelaySeconds: 0
59
79
  periodSeconds: 15
60
80
  failureThreshold: 3
81
+ <% if (app === 'admin') { %> timeoutSeconds: 5
82
+ <% } %>
61
83
  readinessProbe:
62
84
  httpGet:
63
- path: <%= app === 'api' ? '/health' : '/' %>
85
+ path: <%= app === 'api' || app === 'admin' ? '/health' : '/' %>
64
86
  port: <%= config.appPorts?.[app] ?? (app === 'api' ? 3000 : 80) %>
65
87
  initialDelaySeconds: 0
66
88
  periodSeconds: 10
67
89
  failureThreshold: 3
90
+ <% if (app === 'admin') { %> timeoutSeconds: 5
91
+ <% } %>
@@ -2,20 +2,24 @@ name: Deploy to Kubernetes
2
2
  on:
3
3
  push:
4
4
  branches:
5
- - <%= config.deployBranch || 'production' %>
5
+ - <%= config.deployBranch %>
6
6
  workflow_dispatch:
7
7
  env:
8
8
  REGISTRY: <%= config.containerRegistry %>
9
9
  NAMESPACE: <%= config.namespace %>
10
- K8S_CLUSTER_ID: <%= config.k8sClusterId || config.clusterName %>
10
+ K8S_CLUSTER_ID: <%= config.clusterName %>
11
+ <% if ((config.apps || []).includes('api')) { %>
11
12
  # API environment
12
- API_FRONTEND_URL: <%= config.frontendUrl || (config.domain ? `https://${config.domain}` : '') %>
13
+ API_FRONTEND_URL: <%= config.domain ? 'https://' + config.domain : '' %>
13
14
  API_JWT_EXPIRES_IN: <%= config.jwtExpiresIn || '7d' %>
15
+ <% } %>
16
+ <% if ((config.apps || []).includes('admin')) { %>
14
17
  # Admin environment (runtime-replaced at container startup)
15
- ADMIN_API_BASE_URL: <%= config.domain ? `https://api.${config.domain}` : '' %>
16
- ADMIN_API_URL: <%= config.domain ? `https://api.${config.domain}` : '' %>
17
- ADMIN_INTERNAL_API_URL: http://<%= config.appName %>-api:<%= config.appPorts?.api || 3000 %>
18
- FRONTEND_URLS: <%= config.frontendUrls || (config.domain ? `https://${config.domain}` : '') %>
18
+ ADMIN_API_BASE_URL: <%= config.apiDomain || '' %>
19
+ ADMIN_API_URL: <%= config.apiDomain || '' %>
20
+ ADMIN_INTERNAL_API_URL: http://<%= config.appName %>-api:3100
21
+ FRONTEND_URLS: <%= config.frontendUrls %>
22
+ <% } %>
19
23
  jobs:
20
24
  apply-cluster-config:
21
25
  name: Apply Kubernetes and Helm configs
@@ -34,12 +38,14 @@ jobs:
34
38
  kubectl create namespace ${{ env.NAMESPACE }} --dry-run=client -o yaml | kubectl apply -f -
35
39
  - name: Apply Kubernetes manifests
36
40
  run: |
37
- <% if (config.setupSSL) { %> kubectl apply -f k8s/cert-manager-issuer.yaml
38
- <% } %><% (config.apps || []).forEach((app) => { %> kubectl apply -f k8s/<%= app %> -n ${{ env.NAMESPACE }}
39
- <% }); %><% if (config.setupIngress) { %> kubectl apply -f k8s/ingress.yaml -n ${{ env.NAMESPACE }}
40
- <% } %><% if ((config.infraServices || []).length > 0) { %>
41
+ <% (config.apps || []).forEach(function(app) { %>
42
+ kubectl apply -f k8s/<%= app %> -n ${{ env.NAMESPACE }}
43
+ <% }); %>
44
+
41
45
 
42
- <% if (config.apps.includes('api')) { %> deploy-api:
46
+
47
+ <% if ((config.apps || []).includes('api')) { %>
48
+ deploy-api:
43
49
  name: Deploy API
44
50
  runs-on: ubuntu-latest
45
51
  needs: apply-cluster-config
@@ -77,6 +83,16 @@ jobs:
77
83
  run: |
78
84
  docker build -t ${{ env.REGISTRY }}/<%= config.appName %>-api:${{ github.sha }} \
79
85
  -f apps/api/Dockerfile .
86
+ - name: Validate API runtime image
87
+ run: |
88
+ docker run --rm --entrypoint sh \
89
+ ${{ env.REGISTRY }}/<%= config.appName %>-api:${{ github.sha }} \
90
+ -c '
91
+ set -eu
92
+ test -f /app/apps/api/dist/apps/api/src/main.js
93
+ node -e "require(\"@prisma/client\")"
94
+ node -e "require(\"/app/apps/api/dist/packages/api-prisma/src/generated-client.js\")"
95
+ '
80
96
  - name: Push Docker image (sha)
81
97
  run: |
82
98
  docker push ${{ env.REGISTRY }}/<%= config.appName %>-api:${{ github.sha }}
@@ -171,13 +187,15 @@ jobs:
171
187
  kubectl logs -l app=<%= config.appName %>-api -n ${{ env.NAMESPACE }} --tail=50 --previous 2>/dev/null || true
172
188
  exit 1
173
189
  )
174
-
175
- <% } %><% if (config.apps.includes('admin')) { %> deploy-admin:
190
+ <% } %>
191
+ <% if ((config.apps || []).includes('admin')) { %>
192
+ deploy-admin:
176
193
  name: Deploy ADMIN
177
194
  runs-on: ubuntu-latest
178
195
  needs:
179
196
  - apply-cluster-config
180
- <% if (config.apps.includes('api')) { %> - deploy-api
197
+ <% if ((config.apps || []).includes('api')) { %>
198
+ - deploy-api
181
199
  <% } %>
182
200
  steps:
183
201
  - name: Checkout code
@@ -254,66 +272,4 @@ jobs:
254
272
  kubectl logs -l app=<%= config.appName %>-admin -n ${{ env.NAMESPACE }} --tail=50 --previous 2>/dev/null || true
255
273
  exit 1
256
274
  )
257
- <% } %><% (config.apps || []).filter((app) => app !== 'api' && app !== 'admin').forEach((app) => { %>
258
- deploy-<%= app %>:
259
- name: Deploy <%= app.toUpperCase() %>
260
- runs-on: ubuntu-latest
261
- needs: apply-cluster-config
262
- steps:
263
- - name: Checkout code
264
- uses: actions/checkout@v4
265
- - name: Install doctl
266
- uses: digitalocean/action-doctl@v2
267
- with:
268
- token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }}
269
- - name: Validate DigitalOcean token
270
- run: |
271
- doctl auth validate
272
- doctl account get
273
- - name: Validate Container Registry access
274
- run: |
275
- doctl registry get
276
- doctl registry repository list >/dev/null 2>&1 && doctl registry repository list || echo "doctl registry repository list not available in this version"
277
- - name: Log in to Container Registry
278
- run: doctl registry login --expiry-seconds 1200
279
- - name: Check Docker auth config
280
- run: |
281
- if [ -f "$HOME/.docker/config.json" ]; then
282
- grep -q 'registry.digitalocean.com' "$HOME/.docker/config.json" && echo "Docker auth entry for registry.digitalocean.com found"
283
- else
284
- echo "Docker config not found at $HOME/.docker/config.json"
285
- exit 1
286
- fi
287
- - name: Registry auth probe push
288
- run: |
289
- docker pull hello-world
290
- docker tag hello-world ${{ env.REGISTRY }}/ci-auth-probe-<%= app %>:${{ github.run_id }}
291
- docker push ${{ env.REGISTRY }}/ci-auth-probe-<%= app %>:${{ github.run_id }}
292
- - name: Build Docker image
293
- run: |
294
- docker build -t ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }} \
295
- -f apps/<%= app %>/Dockerfile .
296
- - name: Push Docker image (sha)
297
- run: |
298
- docker push ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }}
299
- - name: Push Docker image (latest)
300
- run: |
301
- docker tag ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }} \
302
- ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:latest
303
- docker push ${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:latest
304
- - name: Save DigitalOcean kubeconfig
305
- run: doctl kubernetes cluster kubeconfig save ${{ env.K8S_CLUSTER_ID }}
306
- - name: Deploy to Kubernetes
307
- run: |
308
- kubectl set image deployment/<%= config.appName %>-<%= app %> \
309
- <%= config.appName %>-<%= app %>=${{ env.REGISTRY }}/<%= config.appName %>-<%= app %>:${{ github.sha }} \
310
- -n ${{ env.NAMESPACE }}
311
- kubectl rollout status deployment/<%= config.appName %>-<%= app %> -n ${{ env.NAMESPACE }} --timeout=5m || (
312
- echo "--- Rollout timed out. Pod status:"
313
- kubectl get pods -l app=<%= config.appName %>-<%= app %> -n ${{ env.NAMESPACE }}
314
- echo "--- Recent events:"
315
- kubectl describe deployment/<%= config.appName %>-<%= app %> -n ${{ env.NAMESPACE }} | tail -20
316
- kubectl logs -l app=<%= config.appName %>-<%= app %> -n ${{ env.NAMESPACE }} --tail=50 --previous 2>/dev/null || true
317
- exit 1
318
- )
319
- <% }); %>
275
+ <% } %>