-
Notifications
You must be signed in to change notification settings - Fork 1
149 lines (134 loc) · 5.1 KB
/
deploy-infra.yml
File metadata and controls
149 lines (134 loc) · 5.1 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
name: Deploy frontend to infrastructure
concurrency:
group: deploy-infra-${{ github.ref }}-${{ inputs.WORKFLOW_PHASE || 'dev' }}
cancel-in-progress: true
on:
workflow_dispatch:
inputs:
WORKFLOW_PHASE:
description: "Phase to deploy"
required: true
default: dev
type: choice
options:
- dev
- prd
push:
branches:
- main
permissions:
contents: read
jobs:
config:
runs-on: ubuntu-latest
outputs:
phase: ${{ steps.set.outputs.phase }}
matrix: ${{ steps.set.outputs.matrix }}
keys: ${{ steps.set.outputs.keys }}
keys_display: ${{ steps.set.outputs.keys_display }}
env:
PHASE: ${{ github.event_name == 'workflow_dispatch' && inputs.WORKFLOW_PHASE || 'dev' }}
steps:
- id: set
run: |
set -euo pipefail
# Per-phase {key, app} list. `key` matches infra repo's vars.yaml
# `frontends.<key>` and is also the upload-artifact name suffix.
# `mode` is derived from PHASE at build time, not encoded here.
case "$PHASE" in
dev)
INCLUDE='[
{"key":"admin-dev","app":"pyconkr-admin"},
{"key":"participant-dev","app":"pyconkr-participant-portal"},
{"key":"pyconkr-dev","app":"pyconkr-2026"}
]' ;;
prd)
INCLUDE='[
{"key":"admin","app":"pyconkr-admin"},
{"key":"participant","app":"pyconkr-participant-portal"},
{"key":"pyconkr-2026","app":"pyconkr-2026"},
{"key":"pyconkr-2025","app":"pyconkr-2025"}
]' ;;
esac
MATRIX=$(jq -nc --argjson inc "$INCLUDE" '{include: $inc}')
KEYS=$(echo "$MATRIX" | jq -c '[.include[].key]')
KEYS_DISPLAY=$(echo "$MATRIX" | jq -r '[.include[].key] | join(" & ")')
{
echo "phase=$PHASE"
echo "matrix=$MATRIX"
echo "keys=$KEYS"
echo "keys_display=$KEYS_DISPLAY"
} >> "$GITHUB_OUTPUT"
build:
needs: config
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix: ${{ fromJson(needs.config.outputs.matrix) }}
env:
VITE_MODE: ${{ needs.config.outputs.phase == 'prd' && 'production' || 'development' }}
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v6
- uses: actions/setup-node@v6
with:
node-version: "24"
cache: "pnpm"
cache-dependency-path: "pnpm-lock.yaml"
- run: pnpm install --frozen-lockfile
- name: Build ${{ matrix.app }} (${{ env.VITE_MODE }})
run: pnpm build:@apps/${{ matrix.app }} --mode ${{ env.VITE_MODE }}
# Artifact name = `frontend-<key>` (infra repo vars.yaml `frontends.<key>`).
- uses: actions/upload-artifact@v7
with:
name: frontend-${{ matrix.key }}
path: apps/${{ matrix.app }}/dist/
retention-days: 7
if-no-files-found: error
trigger:
if: always()
needs: [config, build]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
with:
sparse-checkout: .github/actions
- name: Generate App token (cross-repo dispatch)
id: app-token
if: needs.build.result == 'success'
uses: actions/create-github-app-token@v3
with:
client-id: ${{ vars.DEPLOY_APP_CLIENT_ID }}
private-key: ${{ secrets.DEPLOY_APP_PRIVATE_KEY }}
owner: ${{ github.repository_owner }}
repositories: ${{ secrets.INFRA_REPO_NAME }}
- name: Dispatch deploy-frontend to infrastructure
if: needs.build.result == 'success'
env:
GH_TOKEN: ${{ steps.app-token.outputs.token }}
INFRA_REPO: ${{ github.repository_owner }}/${{ secrets.INFRA_REPO_NAME }}
PHASE: ${{ needs.config.outputs.phase }}
KEYS: ${{ needs.config.outputs.keys }}
run: |
set -euo pipefail
# Build payload via jq so `keys` stays a real JSON array (gh api -f
# would coerce values to strings).
jq -n \
--arg phase "$PHASE" \
--arg src "${{ github.repository }}" \
--arg run "${{ github.run_id }}" \
--argjson keys "$KEYS" \
'{event_type:"deploy-frontend",client_payload:{phase:$phase,source_repo:$src,source_run_id:$run,keys:$keys}}' \
| gh api "repos/$INFRA_REPO/dispatches" --input -
# If build failed/cancelled, dispatch is skipped — fail this job so
# job.status reflects the real outcome for the slack step.
- name: Propagate upstream status
if: contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')
run: exit 1
- uses: ./.github/actions/notify-slack-deploy
if: always()
with:
slack-token: ${{ secrets.SLACK_BOT_TOKEN }}
slack-channel: ${{ vars.SLACK_DEPLOYMENT_ALERT_CHANNEL }}
header-prefix: "frontend → infrastructure (${{ needs.config.outputs.phase || '?' }})"
section-text: "${{ needs.config.outputs.keys_display || '?' }} 빌드"