@c-time/frelio-cli 0.1.0
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.
- package/README.md +435 -0
- package/dist/commands/add-staging.d.ts +9 -0
- package/dist/commands/add-staging.js +202 -0
- package/dist/commands/init.d.ts +9 -0
- package/dist/commands/init.js +532 -0
- package/dist/commands/update.d.ts +8 -0
- package/dist/commands/update.js +95 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +28 -0
- package/dist/lib/github-release.d.ts +15 -0
- package/dist/lib/github-release.js +41 -0
- package/dist/lib/initial-content.d.ts +5 -0
- package/dist/lib/initial-content.js +1353 -0
- package/dist/lib/shell.d.ts +12 -0
- package/dist/lib/shell.js +40 -0
- package/dist/lib/templates.d.ts +43 -0
- package/dist/lib/templates.js +211 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,435 @@
|
|
|
1
|
+
# @frelio/cli
|
|
2
|
+
|
|
3
|
+
Frelio CMS のプロジェクトセットアップと管理を行う CLI ツール。
|
|
4
|
+
|
|
5
|
+
対話式のプロンプトに従うだけで、GitHub リポジトリの作成からコンテンツ構造の初期化、Cloudflare のセットアップまで、すべてを自動化する。
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## 前提条件
|
|
10
|
+
|
|
11
|
+
### 1. Node.js のインストール
|
|
12
|
+
|
|
13
|
+
Node.js 20 以上が必要。
|
|
14
|
+
|
|
15
|
+
**Windows:**
|
|
16
|
+
|
|
17
|
+
[Node.js 公式サイト](https://nodejs.org/) から LTS 版をダウンロードしてインストール。
|
|
18
|
+
|
|
19
|
+
または winget:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
winget install OpenJS.NodeJS.LTS
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
**macOS:**
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
brew install node@20
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**Linux (Ubuntu/Debian):**
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
|
|
35
|
+
sudo apt-get install -y nodejs
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
インストール確認:
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
node --version # v20.x.x 以上
|
|
42
|
+
npm --version # 10.x.x 以上
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### 2. Git のインストール
|
|
46
|
+
|
|
47
|
+
**Windows:**
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
winget install Git.Git
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
**macOS:**
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Xcode Command Line Tools に含まれる
|
|
57
|
+
xcode-select --install
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**Linux:**
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
sudo apt-get install git
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. GitHub CLI (`gh`) のインストール
|
|
67
|
+
|
|
68
|
+
GitHub リポジトリの作成、ブランチ管理、デフォルトブランチ設定などに使用する。
|
|
69
|
+
|
|
70
|
+
**Windows:**
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
winget install GitHub.cli
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
**macOS:**
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
brew install gh
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Linux:**
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
# https://github.com/cli/cli/blob/trunk/docs/install_linux.md を参照
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
インストール後、GitHub にログイン:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
gh auth login
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
プロンプトに従い、ブラウザで認証を完了する。
|
|
95
|
+
|
|
96
|
+
### 4. Wrangler CLI のインストール
|
|
97
|
+
|
|
98
|
+
Cloudflare の R2 バケット作成、Pages プロジェクト作成、シークレット設定に使用する。
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
npm install -g wrangler
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Cloudflare にログイン:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
wrangler login
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
ブラウザが開くので、Cloudflare アカウントで認証する。
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## インストール
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
npx @frelio/cli init
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
npm でグローバルインストールする場合:
|
|
121
|
+
|
|
122
|
+
```bash
|
|
123
|
+
npm install -g @frelio/cli
|
|
124
|
+
frelio init
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## コマンド
|
|
130
|
+
|
|
131
|
+
### `frelio init` — プロジェクトの新規作成
|
|
132
|
+
|
|
133
|
+
対話式プロンプトで必要な情報を入力し、プロジェクトをセットアップする。
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
frelio init
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
#### やること
|
|
140
|
+
|
|
141
|
+
1. **前提チェック** — `gh`, `wrangler`, `git` がインストールされ、ログイン済みか確認
|
|
142
|
+
2. **対話式プロンプト** — リポジトリ名、サイトタイトル、R2 設定などを入力
|
|
143
|
+
3. **GitHub OAuth App の案内** — OAuth App の作成手順を表示し、Client ID / Secret を入力
|
|
144
|
+
4. **GitHub リポジトリ作成** — `gh repo create` でプライベートリポジトリを作成・クローン
|
|
145
|
+
5. **コンテンツ初期構造の作成** — `frelio-data/` ディレクトリとメタデータファイルを生成
|
|
146
|
+
6. **GitHub Actions ワークフロー配置** — ステージングビルド、本番プロモート、直接デプロイの3つ
|
|
147
|
+
7. **CMS Admin バンドルの展開** — 最新リリースから `admin/`、`functions/`、`workers/` を配置
|
|
148
|
+
8. **設定ファイル生成** — `admin/config.json`、`wrangler.toml`、`_redirects`、`_routes.json`
|
|
149
|
+
9. **Cloudflare セットアップ** — R2 バケット作成、本番用 Pages プロジェクト作成、ステージング用 Pages プロジェクト作成、OAuth シークレット設定
|
|
150
|
+
10. **ブランチ構造の作成** — `main`、`develop`、`staging` ブランチを作成・プッシュ、デフォルトブランチを `develop` に設定
|
|
151
|
+
|
|
152
|
+
#### プロンプトで聞かれること
|
|
153
|
+
|
|
154
|
+
| 項目 | 説明 | 例 |
|
|
155
|
+
|------|------|----|
|
|
156
|
+
| リポジトリ名 | `owner/repo` 形式 | `my-org/my-site` |
|
|
157
|
+
| サイトタイトル | 管理画面に表示される名前 | `My Website` |
|
|
158
|
+
| 本番 URL | 公開サイトの URL(任意) | `https://example.com` |
|
|
159
|
+
| プレビュー URL | ステージング確認用 URL(任意) | `https://staging.example.com` |
|
|
160
|
+
| R2 バケット名 | ファイルストレージ用バケット | `my-site-files` |
|
|
161
|
+
| R2 公開 URL | ファイル配信の URL | `https://storage.example.com` |
|
|
162
|
+
| 管理者 GitHub ユーザー名 | 最初の管理者ユーザー | `your-username` |
|
|
163
|
+
| OAuth Client ID | GitHub OAuth App の Client ID | `Ov23li...` |
|
|
164
|
+
| OAuth Client Secret | GitHub OAuth App の Client Secret | `********` |
|
|
165
|
+
|
|
166
|
+
#### オプション
|
|
167
|
+
|
|
168
|
+
```bash
|
|
169
|
+
frelio init --skip-github # GitHub 操作をスキップ(手動でリポジトリを用意する場合)
|
|
170
|
+
frelio init --skip-cloudflare # Cloudflare 操作をスキップ(後から設定する場合)
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
#### 生成されるリポジトリ構造
|
|
174
|
+
|
|
175
|
+
```
|
|
176
|
+
my-site/
|
|
177
|
+
├── admin/ # CMS 管理画面(ビルド済み)
|
|
178
|
+
│ ├── index.html
|
|
179
|
+
│ ├── config.json # 実行時設定
|
|
180
|
+
│ └── assets/
|
|
181
|
+
├── public/ # 公開サイトルート(SSG 出力先)
|
|
182
|
+
│ └── _routes.json # ファイル配信ルーティング(/storage/*)
|
|
183
|
+
├── functions/ # Cloudflare Pages Functions
|
|
184
|
+
│ ├── api/
|
|
185
|
+
│ │ ├── auth/ # OAuth 認証エンドポイント
|
|
186
|
+
│ │ └── storage/ # CMS ファイルアップロード API
|
|
187
|
+
│ └── storage/[[path]].ts # R2 ファイル配信(/storage/*)
|
|
188
|
+
├── workers/ # Pages Functions が参照する Worker ソース
|
|
189
|
+
│ └── file-upload/
|
|
190
|
+
├── frelio-data/ # コンテンツデータ
|
|
191
|
+
│ ├── site/
|
|
192
|
+
│ │ ├── content_types/ # スキーマ定義
|
|
193
|
+
│ │ ├── contents/
|
|
194
|
+
│ │ │ ├── published/ # 公開済み
|
|
195
|
+
│ │ │ └── private/ # 下書き
|
|
196
|
+
│ │ ├── templates/ # HTML テンプレート
|
|
197
|
+
│ │ │ └── assets/
|
|
198
|
+
│ │ │ ├── scss/ # スタイルソース
|
|
199
|
+
│ │ │ └── ts/ # スクリプトソース
|
|
200
|
+
│ │ └── data/data-json/ # SSG 中間データ
|
|
201
|
+
│ └── admin/
|
|
202
|
+
│ ├── metadata/ # メタデータ
|
|
203
|
+
│ ├── recipes/ # ビルドレシピ
|
|
204
|
+
│ └── users/ # ユーザー管理
|
|
205
|
+
├── .github/workflows/ # GitHub Actions
|
|
206
|
+
├── vite.config.ts # テンプレートアセットビルド(SCSS/TS)
|
|
207
|
+
├── package.json # vite + sass + typescript
|
|
208
|
+
├── tsconfig.json
|
|
209
|
+
├── wrangler.toml # Cloudflare 設定(R2 バインディング)
|
|
210
|
+
├── _redirects # /admin/* → SPA, /* → /public/:splat
|
|
211
|
+
├── _routes.json # /api/*, /storage/* → Functions
|
|
212
|
+
├── CLAUDE.md # AI アシスタント用プロジェクト説明
|
|
213
|
+
└── version.json # バージョン管理
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
---
|
|
217
|
+
|
|
218
|
+
### `frelio add-staging` — ステージング環境の追加
|
|
219
|
+
|
|
220
|
+
カスタムステージング環境(プレビュー用ブランチ + Cloudflare Pages プロジェクト)を追加する。プロジェクトのルートディレクトリで実行する。
|
|
221
|
+
|
|
222
|
+
```bash
|
|
223
|
+
cd my-site
|
|
224
|
+
frelio add-staging
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
#### やること
|
|
228
|
+
|
|
229
|
+
1. **前提チェック** — `git`, `wrangler` がインストール済みか確認
|
|
230
|
+
2. **対話式プロンプト** — ステージング名、Pages プロジェクト名、カスタムドメインを入力
|
|
231
|
+
3. **Git ブランチ作成** — `develop` から `staging-{name}` ブランチを作成・プッシュ
|
|
232
|
+
4. **Pages プロジェクト作成** — `wrangler pages project create` で作成(Production branch: `staging-{name}`)
|
|
233
|
+
5. **ワークフロー確認** — `build-staging.yml` のブランチリストに対応済みか確認、未対応なら案内を表示
|
|
234
|
+
|
|
235
|
+
#### プロンプトで聞かれること
|
|
236
|
+
|
|
237
|
+
| 項目 | 説明 | 例 |
|
|
238
|
+
|------|------|----|
|
|
239
|
+
| ステージング名 | ブランチ名に使われる識別子 | `design`, `alice` |
|
|
240
|
+
| Pages プロジェクト名 | Cloudflare Pages プロジェクト名 | `my-site-staging-design` |
|
|
241
|
+
| カスタムドメイン | 任意。空欄なら `<project>.pages.dev` | `staging-design.example.com` |
|
|
242
|
+
|
|
243
|
+
#### オプション
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
frelio add-staging --name design # 名前を事前指定
|
|
247
|
+
frelio add-staging --skip-cloudflare # Pages プロジェクト作成をスキップ
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
#### 完了後の手動作業
|
|
251
|
+
|
|
252
|
+
| 作業 | 必須 |
|
|
253
|
+
|------|:----:|
|
|
254
|
+
| Cloudflare Pages でリポジトリを接続 | ○ |
|
|
255
|
+
| カスタムドメインの設定 | - |
|
|
256
|
+
| Cloudflare Access でアクセス制限 | 推奨 |
|
|
257
|
+
| CMS 管理画面の `/staging` ページでブランチを登録 | ○ |
|
|
258
|
+
|
|
259
|
+
---
|
|
260
|
+
|
|
261
|
+
### `frelio update` — CMS Admin の更新
|
|
262
|
+
|
|
263
|
+
CMS Admin バンドルを最新バージョン(または指定バージョン)に更新する。
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
cd my-site
|
|
267
|
+
frelio update
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
#### やること
|
|
271
|
+
|
|
272
|
+
1. `admin/config.json` をバックアップ
|
|
273
|
+
2. 指定バージョン(またはLatest)のリリースをダウンロード
|
|
274
|
+
3. `admin/`、`functions/`、`workers/` を新しいバンドルで置き換え
|
|
275
|
+
4. `admin/config.json` を復元
|
|
276
|
+
|
|
277
|
+
`config.json` は自動的に保護されるため、設定が上書きされることはない。
|
|
278
|
+
|
|
279
|
+
#### オプション
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
frelio update # 最新バージョンに更新
|
|
283
|
+
frelio update --version v1.2.0 # 特定バージョンに更新
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## セットアップ後の手動作業
|
|
289
|
+
|
|
290
|
+
CLI 完了後、Cloudflare Dashboard での設定が必要。
|
|
291
|
+
|
|
292
|
+
### 1. 本番 Pages: GitHub リポジトリの接続
|
|
293
|
+
|
|
294
|
+
CLI が作成した Pages プロジェクトに GitHub リポジトリを接続する。
|
|
295
|
+
|
|
296
|
+
1. [Cloudflare Dashboard](https://dash.cloudflare.com/) → Pages → **本番プロジェクト**(例: `my-site`)を選択
|
|
297
|
+
2. **Settings** → **Builds & deployments** → **Connect to Git**
|
|
298
|
+
3. GitHub リポジトリを選択
|
|
299
|
+
4. ビルド設定:
|
|
300
|
+
- **Production branch**: `main`
|
|
301
|
+
- **Build command**: (空欄)
|
|
302
|
+
- **Build output directory**: `/`
|
|
303
|
+
|
|
304
|
+
### 2. ステージング Pages: GitHub リポジトリの接続
|
|
305
|
+
|
|
306
|
+
CLI が作成したステージング用 Pages プロジェクトに同じリポジトリを接続する。
|
|
307
|
+
|
|
308
|
+
1. Cloudflare Dashboard → Pages → **ステージングプロジェクト**(例: `my-site-staging`)を選択
|
|
309
|
+
2. **Settings** → **Builds & deployments** → **Connect to Git**
|
|
310
|
+
3. 同じ GitHub リポジトリを選択
|
|
311
|
+
4. ビルド設定:
|
|
312
|
+
- **Production branch**: `staging`
|
|
313
|
+
- **Build command**: (空欄)
|
|
314
|
+
- **Build output directory**: `public/`
|
|
315
|
+
|
|
316
|
+
### 3. ステージング: カスタムドメインの設定(任意)
|
|
317
|
+
|
|
318
|
+
デフォルトでは `<project-name>.pages.dev` でアクセスできるが、独自ドメインを使う場合:
|
|
319
|
+
|
|
320
|
+
1. ステージング Pages プロジェクト → **Custom domains** → **Set up a custom domain**
|
|
321
|
+
2. ドメインを入力(例: `staging.example.com`)
|
|
322
|
+
3. DNS レコードの自動追加を確認・承認
|
|
323
|
+
|
|
324
|
+
### 4. ステージング: アクセス制限の設定(推奨)
|
|
325
|
+
|
|
326
|
+
ステージングサイトは公開前のプレビュー用なので、アクセスを制限することを推奨する。
|
|
327
|
+
|
|
328
|
+
#### 方法 A: Cloudflare Access(推奨)
|
|
329
|
+
|
|
330
|
+
メールアドレスベースのアクセス制限。ワンタイムコードまたは Google OAuth で認証する。
|
|
331
|
+
|
|
332
|
+
1. Cloudflare Dashboard → **Zero Trust** → **Access** → **Applications** → **Add an application**
|
|
333
|
+
2. **Self-hosted** を選択
|
|
334
|
+
3. 以下を設定:
|
|
335
|
+
|
|
336
|
+
| 設定項目 | 値 |
|
|
337
|
+
|---------|-----|
|
|
338
|
+
| Application name | `staging` |
|
|
339
|
+
| Application domain | ステージングのドメイン(例: `staging.example.com` or `my-site-staging.pages.dev`) |
|
|
340
|
+
| Policy name | `allowed-users` |
|
|
341
|
+
| Action | Allow |
|
|
342
|
+
| Include rule | **Emails** — アクセスを許可するメールアドレスを列挙 |
|
|
343
|
+
|
|
344
|
+
Cloudflare Access は 50 ユーザーまで無料。
|
|
345
|
+
|
|
346
|
+
#### 方法 B: Cloudflare Pages のアクセス制限
|
|
347
|
+
|
|
348
|
+
Pages プロジェクトの設定でプレビューデプロイメントのアクセスを制限できる(簡易的)。
|
|
349
|
+
|
|
350
|
+
1. ステージング Pages プロジェクト → **Settings** → **General** → **Access Policy**
|
|
351
|
+
2. アクセスポリシーを有効化
|
|
352
|
+
|
|
353
|
+
### 5. R2 カスタムドメインの設定(任意)
|
|
354
|
+
|
|
355
|
+
`wrangler.toml` で `R2_PUBLIC_URL` を設定した場合、R2 バケットにカスタムドメインを紐付ける:
|
|
356
|
+
|
|
357
|
+
1. Cloudflare Dashboard → **R2** → バケットを選択 → **Settings** → **Custom Domains**
|
|
358
|
+
2. カスタムドメインを追加(例: `storage.example.com`)
|
|
359
|
+
|
|
360
|
+
### まとめ: 手動作業チェックリスト
|
|
361
|
+
|
|
362
|
+
| # | 作業 | 必須 |
|
|
363
|
+
|---|------|:----:|
|
|
364
|
+
| 1 | 本番 Pages ↔ GitHub 接続 | ○ |
|
|
365
|
+
| 2 | ステージング Pages ↔ GitHub 接続 | ○ |
|
|
366
|
+
| 3 | ステージング アクセス制限 | 推奨 |
|
|
367
|
+
| 4 | カスタムドメイン設定 | - |
|
|
368
|
+
| 5 | R2 カスタムドメイン | - |
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## GitHub OAuth App の作成手順
|
|
373
|
+
|
|
374
|
+
`frelio init` 実行中に案内が表示されるが、事前に作成しておくこともできる。
|
|
375
|
+
|
|
376
|
+
1. [GitHub Developer Settings](https://github.com/settings/developers) にアクセス
|
|
377
|
+
2. **OAuth Apps** → **New OAuth App**
|
|
378
|
+
3. 以下を入力:
|
|
379
|
+
- **Application name**: `My Site CMS`(任意)
|
|
380
|
+
- **Homepage URL**: `https://<pages-project>.pages.dev`
|
|
381
|
+
- **Authorization callback URL**: `https://<pages-project>.pages.dev/api/auth/callback`
|
|
382
|
+
4. **Register application** をクリック
|
|
383
|
+
5. **Client ID** をメモ
|
|
384
|
+
6. **Generate a new client secret** → **Client Secret** をメモ
|
|
385
|
+
|
|
386
|
+
---
|
|
387
|
+
|
|
388
|
+
## ファイル配信の設定
|
|
389
|
+
|
|
390
|
+
アップロードした画像やファイルを公開配信するには、R2 バケットにカスタムドメインを設定する。
|
|
391
|
+
|
|
392
|
+
1. Cloudflare Dashboard → R2 → バケットを選択 → **Settings** → **Custom Domains**
|
|
393
|
+
2. カスタムドメインを追加(例: `storage.example.com`)
|
|
394
|
+
3. `admin/config.json` の `fileUploadUrl` は `/api/storage` のままでよい(API は Pages Functions が処理する)
|
|
395
|
+
|
|
396
|
+
公開配信 URL(`R2_PUBLIC_URL`)は `wrangler.toml` の `[vars]` で設定済み。
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## トラブルシューティング
|
|
401
|
+
|
|
402
|
+
### `gh: command not found`
|
|
403
|
+
|
|
404
|
+
GitHub CLI がインストールされていない。[前提条件](#3-github-cli-gh-のインストール) を参照。
|
|
405
|
+
|
|
406
|
+
### `wrangler: command not found`
|
|
407
|
+
|
|
408
|
+
Wrangler CLI がインストールされていない。[前提条件](#4-wrangler-cli-のインストール) を参照。
|
|
409
|
+
|
|
410
|
+
### `gh auth status` でエラー
|
|
411
|
+
|
|
412
|
+
`gh auth login` を実行してログインする。
|
|
413
|
+
|
|
414
|
+
### OAuth エラー: "redirect_uri mismatch"
|
|
415
|
+
|
|
416
|
+
GitHub OAuth App の **Authorization callback URL** を確認:
|
|
417
|
+
|
|
418
|
+
- 正: `https://<project>.pages.dev/api/auth/callback`
|
|
419
|
+
- 誤: `https://<project>.pages.dev/auth/callback`(`/api` が抜けている)
|
|
420
|
+
|
|
421
|
+
### R2 バケット作成で "already exists"
|
|
422
|
+
|
|
423
|
+
同名のバケットが既に存在する。CLI は自動的にスキップするので問題ない。
|
|
424
|
+
|
|
425
|
+
### Pages プロジェクト作成で "already exists"
|
|
426
|
+
|
|
427
|
+
同名のプロジェクトが既に存在する。CLI は自動的にスキップするので問題ない。
|
|
428
|
+
|
|
429
|
+
### `config.json` の読み込みに失敗する
|
|
430
|
+
|
|
431
|
+
`admin/config.json` が存在し、正しい JSON であることを確認。`frelio update` で config.json が消えた場合は、バックアップから復元するか手動で再作成する。
|
|
432
|
+
|
|
433
|
+
### 組織リポジトリへのアクセスで 403 エラー
|
|
434
|
+
|
|
435
|
+
GitHub OAuth App に対して組織のアクセス権が付与されていない可能性がある。GitHub → Settings → Applications → Authorized OAuth Apps から対象アプリの組織アクセスを許可(Grant)する。
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* frelio add-staging - ステージング環境(プレビュー用ブランチ)の追加
|
|
3
|
+
*/
|
|
4
|
+
import prompts from 'prompts';
|
|
5
|
+
import { exec, commandExists, log, logStep, logSuccess, logError } from '../lib/shell.js';
|
|
6
|
+
import { generateHash } from '../lib/templates.js';
|
|
7
|
+
export async function addStagingCommand(options) {
|
|
8
|
+
log('');
|
|
9
|
+
log('🌿 ステージング環境の追加');
|
|
10
|
+
log('');
|
|
11
|
+
// 前提チェック
|
|
12
|
+
if (!commandExists('git')) {
|
|
13
|
+
logError('git が見つかりません。');
|
|
14
|
+
process.exit(1);
|
|
15
|
+
}
|
|
16
|
+
// Git リポジトリ内か確認
|
|
17
|
+
try {
|
|
18
|
+
exec('git rev-parse --is-inside-work-tree', { silent: true });
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
logError('Git リポジトリ内で実行してください。');
|
|
22
|
+
process.exit(1);
|
|
23
|
+
}
|
|
24
|
+
// wrangler チェック
|
|
25
|
+
if (!options.skipCloudflare) {
|
|
26
|
+
if (!commandExists('wrangler')) {
|
|
27
|
+
logError('wrangler CLI が見つかりません。`npm i -g wrangler` でインストールしてください。');
|
|
28
|
+
process.exit(1);
|
|
29
|
+
}
|
|
30
|
+
try {
|
|
31
|
+
exec('wrangler whoami', { silent: true });
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
logError('wrangler にログインしていません。`wrangler login` を実行してください。');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
// 本番 Pages プロジェクト名とドメインを推定
|
|
39
|
+
let basePagesProject = '';
|
|
40
|
+
let baseDomain = '';
|
|
41
|
+
try {
|
|
42
|
+
const wranglerToml = exec('cat wrangler.toml', { silent: true });
|
|
43
|
+
const nameMatch = wranglerToml.match(/^name\s*=\s*"([^"]+)"/m);
|
|
44
|
+
if (nameMatch) {
|
|
45
|
+
basePagesProject = nameMatch[1];
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// wrangler.toml がなくても続行
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
const configJson = exec('cat admin/config.json', { silent: true });
|
|
53
|
+
const config = JSON.parse(configJson);
|
|
54
|
+
if (config.productionUrl) {
|
|
55
|
+
const url = new URL(config.productionUrl);
|
|
56
|
+
baseDomain = url.hostname;
|
|
57
|
+
}
|
|
58
|
+
else if (config.previewUrl) {
|
|
59
|
+
// previewUrl から親ドメインを推定(staging-xxx.example.com → example.com)
|
|
60
|
+
const url = new URL(config.previewUrl);
|
|
61
|
+
const parts = url.hostname.split('.');
|
|
62
|
+
if (parts.length > 2) {
|
|
63
|
+
baseDomain = parts.slice(-2).join('.');
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
// config.json がなくても続行
|
|
69
|
+
}
|
|
70
|
+
// 対話式プロンプト
|
|
71
|
+
const response = await prompts([
|
|
72
|
+
{
|
|
73
|
+
type: options.name ? null : 'text',
|
|
74
|
+
name: 'name',
|
|
75
|
+
message: 'ステージング名(staging-{name} のブランチが作成されます):',
|
|
76
|
+
validate: (v) => {
|
|
77
|
+
if (!v)
|
|
78
|
+
return 'ステージング名を入力してください';
|
|
79
|
+
if (!/^[a-z0-9][a-z0-9-]*$/.test(v))
|
|
80
|
+
return '小文字英数字とハイフンのみ使用可能です';
|
|
81
|
+
if (v === 'staging')
|
|
82
|
+
return '"staging" は予約済みです。別の名前を使用してください';
|
|
83
|
+
return true;
|
|
84
|
+
},
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
type: 'text',
|
|
88
|
+
name: 'pagesProject',
|
|
89
|
+
message: 'ステージング用 Pages プロジェクト名:',
|
|
90
|
+
initial: (_prev, values) => {
|
|
91
|
+
const name = options.name || values.name || '';
|
|
92
|
+
return basePagesProject ? `${basePagesProject}-staging-${name}` : '';
|
|
93
|
+
},
|
|
94
|
+
validate: (v) => v.length > 0 || 'プロジェクト名を入力してください',
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
type: 'text',
|
|
98
|
+
name: 'domain',
|
|
99
|
+
message: 'カスタムドメイン(推測困難なハッシュ付き推奨):',
|
|
100
|
+
initial: (_prev, values) => {
|
|
101
|
+
const name = options.name || values.name || '';
|
|
102
|
+
const hash = generateHash();
|
|
103
|
+
if (baseDomain) {
|
|
104
|
+
return `${name}-${hash}.${baseDomain}`;
|
|
105
|
+
}
|
|
106
|
+
const project = basePagesProject || 'site';
|
|
107
|
+
return `${project}-${name}-${hash}.pages.dev`;
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
], { onCancel: () => process.exit(0) });
|
|
111
|
+
const stagingName = options.name || response.name;
|
|
112
|
+
if (!stagingName) {
|
|
113
|
+
log('キャンセルしました。');
|
|
114
|
+
process.exit(0);
|
|
115
|
+
}
|
|
116
|
+
const branchName = `staging-${stagingName}`;
|
|
117
|
+
const pagesProject = response.pagesProject;
|
|
118
|
+
log('');
|
|
119
|
+
const totalSteps = options.skipCloudflare ? 2 : 3;
|
|
120
|
+
let step = 0;
|
|
121
|
+
// Step 1: Git ブランチ作成
|
|
122
|
+
step++;
|
|
123
|
+
logStep(step, totalSteps, `ブランチ "${branchName}" を作成...`);
|
|
124
|
+
try {
|
|
125
|
+
// develop から分岐
|
|
126
|
+
exec('git fetch origin', { silent: true });
|
|
127
|
+
// ブランチが既に存在するか確認
|
|
128
|
+
try {
|
|
129
|
+
exec(`git rev-parse --verify origin/${branchName}`, { silent: true });
|
|
130
|
+
logSuccess(`ブランチ "${branchName}" はリモートに既に存在します`);
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
// ローカルブランチ作成 & プッシュ
|
|
134
|
+
exec(`git branch ${branchName} origin/develop`, { silent: true });
|
|
135
|
+
exec(`git push -u origin ${branchName}`, { silent: true });
|
|
136
|
+
logSuccess(`ブランチ "${branchName}" を作成・プッシュしました`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
logError(`ブランチ作成失敗: ${error.message}`);
|
|
141
|
+
process.exit(1);
|
|
142
|
+
}
|
|
143
|
+
// Step 2: Cloudflare Pages プロジェクト作成
|
|
144
|
+
if (!options.skipCloudflare) {
|
|
145
|
+
step++;
|
|
146
|
+
logStep(step, totalSteps, `Pages プロジェクト "${pagesProject}" を作成...`);
|
|
147
|
+
try {
|
|
148
|
+
exec(`wrangler pages project create ${pagesProject} --production-branch ${branchName}`, {
|
|
149
|
+
silent: true,
|
|
150
|
+
});
|
|
151
|
+
logSuccess(`Pages プロジェクト "${pagesProject}" を作成しました`);
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
const msg = error.message;
|
|
155
|
+
if (msg.includes('already exists')) {
|
|
156
|
+
logSuccess(`Pages プロジェクト "${pagesProject}" は既に存在します`);
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
logError(`Pages プロジェクト作成失敗: ${msg}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Step 3: build-staging.yml のブランチリスト確認
|
|
164
|
+
step++;
|
|
165
|
+
logStep(step, totalSteps, 'GitHub Actions ワークフローを確認...');
|
|
166
|
+
try {
|
|
167
|
+
const workflow = exec('cat .github/workflows/build-staging.yml', { silent: true });
|
|
168
|
+
if (workflow.includes('staging-*') || workflow.includes(`staging-${stagingName}`)) {
|
|
169
|
+
logSuccess('ワークフローは既に対応済みです(ワイルドカードまたは明示列挙)');
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
log(` ⚠ .github/workflows/build-staging.yml の branches に "${branchName}" を追加してください:`);
|
|
173
|
+
log('');
|
|
174
|
+
log(' branches:');
|
|
175
|
+
log(' - staging');
|
|
176
|
+
log(` - ${branchName} # ← 追加`);
|
|
177
|
+
log('');
|
|
178
|
+
log(' または、ワイルドカード "staging-*" を使用するとすべてのカスタム staging に対応できます。');
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
log(' ⚠ .github/workflows/build-staging.yml が見つかりません。手動で確認してください。');
|
|
183
|
+
}
|
|
184
|
+
// 完了
|
|
185
|
+
log('');
|
|
186
|
+
log('✅ ステージング環境の追加が完了しました!');
|
|
187
|
+
log('');
|
|
188
|
+
log(` ブランチ: ${branchName}`);
|
|
189
|
+
if (!options.skipCloudflare) {
|
|
190
|
+
const domain = response.domain || `${pagesProject}.pages.dev`;
|
|
191
|
+
log(` URL: https://${domain}`);
|
|
192
|
+
}
|
|
193
|
+
log('');
|
|
194
|
+
log(' 残りの手動作業:');
|
|
195
|
+
log(' - Cloudflare Pages でリポジトリを接続(GitHub integration)');
|
|
196
|
+
if (response.domain) {
|
|
197
|
+
log(` - Pages プロジェクトにカスタムドメイン "${response.domain}" を設定`);
|
|
198
|
+
}
|
|
199
|
+
log(' - Cloudflare Access でアクセス制限を設定(推奨)');
|
|
200
|
+
log(' - CMS 管理画面の /staging ページでステージングブランチを登録');
|
|
201
|
+
log('');
|
|
202
|
+
}
|