-
Notifications
You must be signed in to change notification settings - Fork 0
179 lines (160 loc) · 7.73 KB
/
Copy pathdeploy.yml
File metadata and controls
179 lines (160 loc) · 7.73 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
name: Deploy to VPS
on:
push:
branches: [main]
workflow_dispatch: {}
concurrency:
group: deploy-vps
cancel-in-progress: false
jobs:
deploy:
runs-on: ubuntu-latest
timeout-minutes: 40
needs: []
defaults:
run:
working-directory: site
env:
DEPLOY_HOST: ${{ secrets.DEPLOY_HOST }}
DEPLOY_USER: ${{ secrets.DEPLOY_USER }}
DEPLOY_PATH: ${{ secrets.DEPLOY_PATH }}
steps:
- uses: actions/checkout@v4
# 218ツール×17言語=約7,800ページのSSGでランナーのディスクが枯渇する(ENOSPC)。
# ビルド前に未使用のプリインストールSDKを削除して約30GB確保する。
- name: Free disk space
working-directory: /
run: |
echo "Before:"; df -h / | tail -1
sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/.ghcup \
/usr/local/lib/android /usr/local/share/boost \
/usr/local/share/powershell /usr/share/swift "$AGENT_TOOLSDIRECTORY" || true
sudo docker image prune -af || true
echo "After:"; df -h / | tail -1
- uses: actions/setup-node@v4
with:
node-version: "24"
cache: "npm"
cache-dependency-path: site/package-lock.json
- name: Install dependencies
run: npm ci --no-fund --no-audit
- name: Type check
run: npm run typecheck
- name: i18n / SEO audits
run: |
npm run audit:i18n
npm run audit:seo
- name: Unit tests
run: npm test
- name: Production build (standalone)
run: npm run build
env:
NEXT_PUBLIC_SITE_URL: https://toolify365.com
NEXT_PUBLIC_ORG_NAME: Toolify
NEXT_PUBLIC_CONTACT_EMAIL: app.develop.sk@gmail.com
NEXT_PUBLIC_ADSENSE_CLIENT: ca-pub-4927026308242118
NEXT_PUBLIC_FC_ID: ""
NEXT_PUBLIC_BING_SITE_VERIFICATION: ${{ secrets.BING_SITE_VERIFICATION }}
NEXT_PUBLIC_YANDEX_SITE_VERIFICATION: ${{ secrets.YANDEX_SITE_VERIFICATION }}
# AdSense ad unit slot IDs (set after AdSense approval; empty = placeholder shown)
NEXT_PUBLIC_ADSENSE_SLOT_BANNER: ${{ secrets.ADSENSE_SLOT_BANNER }}
NEXT_PUBLIC_ADSENSE_SLOT_INARTICLE: ${{ secrets.ADSENSE_SLOT_INARTICLE }}
NEXT_PUBLIC_ADSENSE_SLOT_STICKY: ${{ secrets.ADSENSE_SLOT_STICKY }}
NEXT_PUBLIC_ADSENSE_SLOT_BELOWRESULT: ${{ secrets.ADSENSE_SLOT_BELOWRESULT }}
NEXT_PUBLIC_ADSENSE_SLOT_INFEED: ${{ secrets.ADSENSE_SLOT_INFEED }}
NEXT_PUBLIC_ADSENSE_SLOT_ANCHOR: ${{ secrets.ADSENSE_SLOT_ANCHOR }}
NEXT_PUBLIC_GA_ID: ${{ secrets.GA_ID }}
NEXT_PUBLIC_CLARITY_PROJECT_ID: ${{ secrets.CLARITY_PROJECT_ID }}
# 楽天市場 価格比較ツール (/api/price-search) — サーバーサイドのみ
RAKUTEN_APP_ID: ${{ secrets.RAKUTEN_APP_ID }}
RAKUTEN_ACCESS_KEY: ${{ secrets.RAKUTEN_ACCESS_KEY }}
RAKUTEN_AFFILIATE_ID: ${{ secrets.RAKUTEN_AFFILIATE_ID }}
# 楽天アプリ登録のApplication URLと一致させる
RAKUTEN_ORIGIN_URL: ${{ secrets.RAKUTEN_ORIGIN_URL }}
# Amazon アソシエイト (承認後に設定)
NEXT_PUBLIC_AMAZON_PARTNER_TAG: ${{ secrets.AMAZON_PARTNER_TAG }}
- name: Set up SSH
run: |
mkdir -p ~/.ssh
echo "${{ secrets.DEPLOY_SSH_KEY }}" > ~/.ssh/deploy_key
chmod 600 ~/.ssh/deploy_key
ssh-keyscan -H "$DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null
- name: Write runtime env file for VPS
env:
RAKUTEN_APP_ID: ${{ secrets.RAKUTEN_APP_ID }}
RAKUTEN_ACCESS_KEY: ${{ secrets.RAKUTEN_ACCESS_KEY }}
RAKUTEN_AFFILIATE_ID: ${{ secrets.RAKUTEN_AFFILIATE_ID }}
RAKUTEN_ORIGIN_URL: ${{ secrets.RAKUTEN_ORIGIN_URL }}
run: |
printf 'RAKUTEN_APP_ID=%s\nRAKUTEN_ACCESS_KEY=%s\nRAKUTEN_AFFILIATE_ID=%s\nRAKUTEN_ORIGIN_URL=%s\n' \
"$RAKUTEN_APP_ID" "$RAKUTEN_ACCESS_KEY" "$RAKUTEN_AFFILIATE_ID" "$RAKUTEN_ORIGIN_URL" \
> .next/standalone/.env.local
- name: rsync standalone artifacts to VPS
run: |
rsync -az --delete \
-e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new" \
.next/standalone/ "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/"
rsync -az --delete \
-e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new" \
.next/static/ "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/.next/static/"
rsync -az --delete \
-e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new" \
public/ "$DEPLOY_USER@$DEPLOY_HOST:$DEPLOY_PATH/public/"
- name: Clear ISR / full-route cache on VPS
run: |
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
"$DEPLOY_USER@$DEPLOY_HOST" \
"rm -rf \"$DEPLOY_PATH/.next/cache/\" && echo 'cache cleared'"
- name: Reload toolify on VPS via PM2 (zero-downtime)
run: |
ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=accept-new \
"$DEPLOY_USER@$DEPLOY_HOST" \
"pm2 reload toolify --update-env && pm2 save"
- name: Smoke test live URL
run: |
set -e
for i in 1 2 3 4 5; do
if curl -sSfL -o /dev/null -w "%{http_code}" --max-time 15 https://toolify365.com/en/tools/bmi-calculator | grep -q 200 && curl -sSf --max-time 10 https://toolify365.com/feed-ja.xml | grep -q "<rss"; then
echo "✓ Live URL returning 200"
exit 0
fi
echo "Attempt $i failed, retrying in 5s..."
sleep 5
done
echo "✗ Live URL not returning 200 after 5 attempts"
exit 1
# Pinterest RSS自動投稿の回帰ガード(2026-07-21の実障害):
# feedのenclosure画像が全item同一になると、Pinterestの画像ハッシュ重複排除で
# ピン化が2枚で無言停止する(/api/og がクエリを読まなくなる等の回帰で再発しうる)。
# 先頭3itemの画像を実取得しMD5が2種以上あることを検証。失敗=workflow赤で
# 朝のCI監視ルーチンが検知する。
- name: Guard feed pin images are unique (Pinterest dedupe)
run: |
set -e
urls=$(curl -sSf --max-time 15 https://toolify365.com/feed.xml \
| grep -o 'enclosure url="[^"]*"' | sed 's/enclosure url="//;s/"$//;s/\&/\&/g' | head -3)
[ -n "$urls" ] || { echo "✗ feedにenclosureが無い"; exit 1; }
md5s=""
while IFS= read -r u; do
curl -sSf --max-time 30 "$u" -o /tmp/pin.png
bytes=$(wc -c < /tmp/pin.png | tr -d ' ')
h=$(md5sum /tmp/pin.png | cut -d' ' -f1)
echo " $h ${bytes}B $u"
# 2026-08-14の実障害: /api/og が edge ランタイムでフォントを読めず、
# 全リクエストが 70B の 1×1 透明PNG フォールバックに落ちていた。
# 「200が返る」だけでは検知できないのでバイト数で門番する。
if [ "$bytes" -lt 20000 ]; then
echo "✗ ピン画像が ${bytes}B しかない → /api/og が空白PNGフォールバックに落ちている"
exit 1
fi
md5s="$md5s$h\n"
done <<< "$urls"
uniq_count=$(printf "%b" "$md5s" | sort -u | grep -c .)
if [ "$uniq_count" -lt 2 ]; then
echo "✗ feedのピン画像が全て同一(MD5 1種) → Pinterest重複排除でRSS投稿が止まる回帰"
exit 1
fi
echo "✓ ピン画像 unique ($uniq_count 種/3件)"
- name: Cleanup SSH key
if: always()
run: rm -f ~/.ssh/deploy_key