-
Notifications
You must be signed in to change notification settings - Fork 0
224 lines (200 loc) · 10.2 KB
/
Copy pathdeploy-static-site.yml
File metadata and controls
224 lines (200 loc) · 10.2 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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# React SPAをビルドしてS3にデプロイし、CloudFrontのキャッシュを更新
# - dev環境: PR作成時または手動実行
# - prod環境: mainブランチへのpushまたは手動実行
name: Deploy Static Site to S3
# トリガー条件
on:
# mainブランチへのpush時(prod環境にデプロイ)
push:
branches:
- main
paths:
# frontend関連ファイルの変更時のみ実行
- "frontend/**"
- ".github/workflows/deploy-static-site.yml"
# PR作成時(dev環境にデプロイしてプレビュー)
pull_request:
branches:
- main
paths:
- "frontend/**"
- ".github/workflows/deploy-static-site.yml"
# 手動実行(環境を選択可能)
workflow_dispatch:
inputs:
environment:
description: 'Environment to deploy to'
required: true
type: choice
options:
- dev
- prod
jobs:
deploy:
runs-on: ubuntu-latest
permissions:
contents: read # コードの読み取り権限
pull-requests: write # PRにデプロイ結果をコメントする権限
steps:
- uses: actions/checkout@v3
# デプロイ先の環境を決定するロジック
# - workflow_dispatch(手動実行): ユーザーが選択した環境
# - pull_request: dev環境(プレビュー用)
# - push to main: prod環境(本番リリース)
- name: Determine environment
id: set-env
run: |
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
echo "environment=${{ github.event.inputs.environment }}" >> $GITHUB_OUTPUT
elif [ "${{ github.event_name }}" == "pull_request" ]; then
echo "environment=dev" >> $GITHUB_OUTPUT
elif [ "${{ github.ref }}" == "refs/heads/main" ]; then
echo "environment=prod" >> $GITHUB_OUTPUT
else
echo "environment=dev" >> $GITHUB_OUTPUT
fi
# 環境ごとのS3バケット名、ドメイン、APIエンドポイントを設定
# これらの値はフロントエンドのビルド時に環境変数として使用される
- name: Set environment variables
id: set-vars
run: |
if [ "${{ steps.set-env.outputs.environment }}" == "prod" ]; then
echo "bucket_name=note-app.kanare.dev" >> $GITHUB_OUTPUT
echo "domain_name=note-app.kanare.dev" >> $GITHUB_OUTPUT
echo "api_base_url=https://api.note-app.kanare.dev" >> $GITHUB_OUTPUT
else
echo "bucket_name=dev.note-app.kanare.dev" >> $GITHUB_OUTPUT
echo "domain_name=dev.note-app.kanare.dev" >> $GITHUB_OUTPUT
echo "api_base_url=https://api-dev.note-app.kanare.dev" >> $GITHUB_OUTPUT
fi
# AWS認証情報を設定(S3へのアップロードとCloudFront操作に必要)
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v3
with:
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
aws-region: ap-northeast-1
# デプロイ先のS3バケットが存在するか確認
# バケットが存在しない場合はエラーで終了(先にTerraformでインフラを構築する必要がある)
- name: Check if S3 bucket exists
run: |
if ! aws s3 ls "s3://${{ steps.set-vars.outputs.bucket_name }}" > /dev/null 2>&1; then
echo "❌ S3バケット ${{ steps.set-vars.outputs.bucket_name }} が存在しないため、デプロイをスキップします"
echo "💡 先にTerraformで ${{ steps.set-env.outputs.environment }} 環境のインフラを構築してください"
exit 1
fi
echo "✅ S3バケット ${{ steps.set-vars.outputs.bucket_name }} が見つかりました"
# TerraformのoutputsからCognito設定を取得するためにセットアップ
- name: Setup Terraform
uses: hashicorp/setup-terraform@v2
with:
terraform_version: 1.5.0
# TerraformのoutputsからCognito User Pool IDとClient IDを取得
# フロントエンドのビルドに必須の環境変数(Cognito認証に使用)
# フォールバック: Terraform失敗時はGitHub Secretsから取得
- name: Get Cognito configuration from Terraform outputs
id: get-cognito
run: |
cd terraform/environments/${{ steps.set-env.outputs.environment }}
# Terraform init (backend設定を読み込むため)
echo "Initializing Terraform..."
if terraform init > /dev/null 2>&1; then
echo "✅ Terraform initialized successfully"
# Terraform outputsから値を取得(エラー出力を完全に無視)
USER_POOL_ID=$(terraform output -raw cognito_user_pool_id 2>&1 | grep -v "╷" | grep -v "│" | grep -v "╵" | head -n1 || echo "")
USER_POOL_CLIENT_ID=$(terraform output -raw cognito_user_pool_client_id 2>&1 | grep -v "╷" | grep -v "│" | grep -v "╵" | head -n1 || echo "")
# 出力値の検証(AWS User Pool IDの形式チェック)
if [[ "$USER_POOL_ID" =~ ^[a-z]+-[a-z]+-[0-9]+_[a-zA-Z0-9]+$ ]] && [[ "$USER_POOL_CLIENT_ID" =~ ^[a-zA-Z0-9]+$ ]]; then
echo "✅ Terraform outputsからCognito設定を取得しました"
echo "user_pool_id=$USER_POOL_ID" >> $GITHUB_OUTPUT
echo "user_pool_client_id=$USER_POOL_CLIENT_ID" >> $GITHUB_OUTPUT
else
echo "⚠️ Terraform outputs validation failed. Using Secrets..."
USER_POOL_ID=""
USER_POOL_CLIENT_ID=""
fi
else
echo "⚠️ Terraform init failed. Using Secrets..."
USER_POOL_ID=""
USER_POOL_CLIENT_ID=""
fi
# Secretsから取得(フォールバック)
if [ -z "$USER_POOL_ID" ] || [ -z "$USER_POOL_CLIENT_ID" ]; then
if [ "${{ steps.set-env.outputs.environment }}" == "prod" ]; then
echo "user_pool_id=${{ secrets.VITE_USER_POOL_ID }}" >> $GITHUB_OUTPUT
echo "user_pool_client_id=${{ secrets.VITE_USER_POOL_CLIENT_ID }}" >> $GITHUB_OUTPUT
else
echo "user_pool_id=${{ secrets.VITE_USER_POOL_ID_DEV }}" >> $GITHUB_OUTPUT
echo "user_pool_client_id=${{ secrets.VITE_USER_POOL_CLIENT_ID_DEV }}" >> $GITHUB_OUTPUT
fi
fi
# フロントエンドのnpm依存関係をインストール
# npm ci: package-lock.jsonから再現性の高いクリーンインストール
- name: Install dependencies
run: |
cd frontend
npm ci
# React SPAをビルド(production最適化)
# 環境変数にAPI URL、AWSリージョン、Cognito設定を注入
- name: Build static site
run: |
cd frontend
npm run build
env:
VITE_API_BASE_URL: ${{ steps.set-vars.outputs.api_base_url }}
VITE_AWS_REGION: ap-northeast-1
VITE_USER_POOL_ID: ${{ steps.get-cognito.outputs.user_pool_id }}
VITE_USER_POOL_CLIENT_ID: ${{ steps.get-cognito.outputs.user_pool_client_id }}
# ビルド成果物(frontend/dist/)をS3バケットに同期
# --delete: S3側の古いファイルを削除して完全同期
- name: Sync static files to S3
run: |
aws s3 sync frontend/dist/ s3://${{ steps.set-vars.outputs.bucket_name }}/ --delete
echo "✅ デプロイ完了: https://${{ steps.set-vars.outputs.domain_name }}"
# 環境に対応するCloudFront DistributionのIDを取得
# ドメイン名(Aliases)から該当するDistributionを検索
- name: Get CloudFront distribution ID
id: get-cloudfront
run: |
DISTRIBUTION_ID=$(aws cloudfront list-distributions \
--query "DistributionList.Items[?Aliases.Items[?contains(@, '${{ steps.set-vars.outputs.domain_name }}')]].Id | [0]" \
--output text)
if [ "$DISTRIBUTION_ID" != "None" ] && [ -n "$DISTRIBUTION_ID" ]; then
echo "distribution_id=$DISTRIBUTION_ID" >> $GITHUB_OUTPUT
echo "✅ CloudFront Distribution ID: $DISTRIBUTION_ID"
else
echo "⚠️ CloudFront distributionが見つかりませんでした"
echo "distribution_id=" >> $GITHUB_OUTPUT
fi
# CloudFrontのキャッシュを無効化(最新コンテンツをすぐに配信)
# S3にアップロードしただけではCloudFrontは古いキャッシュを返すため必須
- name: Invalidate CloudFront cache
if: steps.get-cloudfront.outputs.distribution_id != ''
run: |
aws cloudfront create-invalidation \
--distribution-id ${{ steps.get-cloudfront.outputs.distribution_id }} \
--paths "/*"
echo "✅ CloudFrontキャッシュを無効化しました"
# PR作成時にデプロイ結果をコメントで通知
# プレビューURLと環境詳細を表示してレビュアーが確認しやすくする
- name: Comment on PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v6
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const distributionId = '${{ steps.get-cloudfront.outputs.distribution_id }}';
const cloudFrontStatus = distributionId ? '✅ Cache invalidated' : '⚠️ No distribution found';
const output = `### 🚀 Static Site Deployed to **${{ steps.set-env.outputs.environment }}** environment
**Preview URL**: https://${{ steps.set-vars.outputs.domain_name }}
**Environment Details**:
- S3 Bucket: \`${{ steps.set-vars.outputs.bucket_name }}\`
- API URL: \`${{ steps.set-vars.outputs.api_base_url }}\`
- CloudFront: ${cloudFrontStatus}
*Deployed by: @${{ github.actor }}*`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
});