@c-time/frelio-cli 1.3.13 → 1.4.1
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 +18 -14
- package/dist/commands/add-staging.d.ts +2 -3
- package/dist/commands/add-staging.js +38 -184
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +164 -373
- package/dist/commands/update.d.ts +2 -0
- package/dist/commands/update.js +11 -67
- package/dist/core/bundle.d.ts +14 -0
- package/dist/core/bundle.js +122 -0
- package/dist/core/cloudflare.d.ts +26 -0
- package/dist/core/cloudflare.js +60 -0
- package/dist/core/config.d.ts +26 -0
- package/dist/core/config.js +120 -0
- package/dist/core/content-structure.d.ts +13 -0
- package/dist/core/content-structure.js +13 -0
- package/dist/core/file-generators.d.ts +28 -0
- package/dist/core/file-generators.js +93 -0
- package/dist/core/git-operations.d.ts +15 -0
- package/dist/core/git-operations.js +78 -0
- package/dist/core/github.d.ts +16 -0
- package/dist/core/github.js +43 -0
- package/dist/core/index.d.ts +22 -0
- package/dist/core/index.js +30 -0
- package/dist/core/prerequisites.d.ts +22 -0
- package/dist/core/prerequisites.js +107 -0
- package/dist/core/status.d.ts +18 -0
- package/dist/core/status.js +122 -0
- package/dist/core/template-scaffold.d.ts +14 -0
- package/dist/core/template-scaffold.js +99 -0
- package/dist/core/terraform.d.ts +7 -0
- package/dist/core/terraform.js +47 -0
- package/dist/core/types.d.ts +48 -0
- package/dist/core/types.js +21 -0
- package/dist/core/workflows.d.ts +11 -0
- package/dist/core/workflows.js +345 -0
- package/dist/index.js +2 -4
- package/dist/lib/github-release.d.ts +15 -0
- package/dist/lib/github-release.js +41 -0
- package/dist/lib/initial-content.js +87 -55
- package/dist/lib/template-renderer.d.ts +16 -0
- package/dist/lib/template-renderer.js +32 -0
- package/dist/lib/templates.d.ts +7 -7
- package/dist/lib/templates.js +311 -214
- package/package.json +2 -3
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/ モジュール共通の型定義
|
|
3
|
+
*
|
|
4
|
+
* 全 core 関数は OperationResult<T> を返す。
|
|
5
|
+
* AI エージェントが結果を構造的に判断できるようにする。
|
|
6
|
+
*/
|
|
7
|
+
import type { ProjectConfig } from '../lib/templates.js';
|
|
8
|
+
export type { ProjectConfig };
|
|
9
|
+
export type ErrorCode = 'NOT_FOUND' | 'ALREADY_EXISTS' | 'AUTH_REQUIRED' | 'COMMAND_MISSING' | 'VALIDATION_ERROR' | 'EXEC_FAILED';
|
|
10
|
+
export type OperationSuccess<T = void> = {
|
|
11
|
+
success: true;
|
|
12
|
+
alreadyExisted?: boolean;
|
|
13
|
+
data: T;
|
|
14
|
+
};
|
|
15
|
+
export type OperationFailure = {
|
|
16
|
+
success: false;
|
|
17
|
+
error: string;
|
|
18
|
+
code: ErrorCode;
|
|
19
|
+
};
|
|
20
|
+
export type OperationResult<T = void> = OperationSuccess<T> | OperationFailure;
|
|
21
|
+
export declare function ok<T>(data: T, alreadyExisted?: boolean): OperationSuccess<T>;
|
|
22
|
+
export declare function okVoid(alreadyExisted?: boolean): OperationSuccess<void>;
|
|
23
|
+
export declare function fail(error: string, code: ErrorCode): OperationFailure;
|
|
24
|
+
export type ProjectStatus = {
|
|
25
|
+
projectDir: string;
|
|
26
|
+
hasGitRepo: boolean;
|
|
27
|
+
hasContentStructure: boolean;
|
|
28
|
+
hasAdminBundle: boolean;
|
|
29
|
+
hasConfigJson: boolean;
|
|
30
|
+
hasWranglerToml: boolean;
|
|
31
|
+
hasWorkflows: boolean;
|
|
32
|
+
hasTerraform: boolean;
|
|
33
|
+
config: ProjectConfig | null;
|
|
34
|
+
branches: string[];
|
|
35
|
+
remoteUrl: string | null;
|
|
36
|
+
missingPrerequisites: string[];
|
|
37
|
+
bundleVersion: string | null;
|
|
38
|
+
};
|
|
39
|
+
export type BuildConfigParams = {
|
|
40
|
+
contentRepo: string;
|
|
41
|
+
githubClientId?: string;
|
|
42
|
+
siteTitle?: string;
|
|
43
|
+
productionUrl?: string;
|
|
44
|
+
stagingDomain?: string;
|
|
45
|
+
r2BucketName?: string;
|
|
46
|
+
r2PublicUrl?: string;
|
|
47
|
+
ownerUsername?: string;
|
|
48
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/ モジュール共通の型定義
|
|
3
|
+
*
|
|
4
|
+
* 全 core 関数は OperationResult<T> を返す。
|
|
5
|
+
* AI エージェントが結果を構造的に判断できるようにする。
|
|
6
|
+
*/
|
|
7
|
+
// ---------------------------------------------------------------------------
|
|
8
|
+
// Helper constructors
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
export function ok(data, alreadyExisted) {
|
|
11
|
+
const result = { success: true, data };
|
|
12
|
+
if (alreadyExisted)
|
|
13
|
+
result.alreadyExisted = true;
|
|
14
|
+
return result;
|
|
15
|
+
}
|
|
16
|
+
export function okVoid(alreadyExisted) {
|
|
17
|
+
return ok(undefined, alreadyExisted);
|
|
18
|
+
}
|
|
19
|
+
export function fail(error, code) {
|
|
20
|
+
return { success: false, error, code };
|
|
21
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/workflows — GitHub Actions ワークフロー生成
|
|
3
|
+
*/
|
|
4
|
+
import { type ProjectConfig, type OperationResult } from './types.js';
|
|
5
|
+
export type WorkflowName = 'deploy-admin' | 'build-staging' | 'promote-production' | 'direct-deploy';
|
|
6
|
+
export declare function generateWorkflow(projectDir: string, config: ProjectConfig, workflow: WorkflowName): OperationResult<{
|
|
7
|
+
path: string;
|
|
8
|
+
}>;
|
|
9
|
+
export declare function generateWorkflows(projectDir: string, config: ProjectConfig): OperationResult<{
|
|
10
|
+
files: string[];
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/workflows — GitHub Actions ワークフロー生成
|
|
3
|
+
*/
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { ok, fail } from './types.js';
|
|
7
|
+
import { writeFile } from '../lib/templates.js';
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
// Individual workflow
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
export function generateWorkflow(projectDir, config, workflow) {
|
|
12
|
+
const workflowsDir = path.join(projectDir, '.github', 'workflows');
|
|
13
|
+
const content = getWorkflowContent(config, workflow);
|
|
14
|
+
const fileName = `${workflow}.yml`;
|
|
15
|
+
const filePath = path.join(workflowsDir, fileName);
|
|
16
|
+
try {
|
|
17
|
+
fs.mkdirSync(workflowsDir, { recursive: true });
|
|
18
|
+
writeFile(filePath, content);
|
|
19
|
+
return ok({ path: filePath });
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
return fail(`ワークフロー生成失敗 (${fileName}): ${e.message}`, 'EXEC_FAILED');
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// All workflows
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
export function generateWorkflows(projectDir, config) {
|
|
29
|
+
const names = ['deploy-admin', 'build-staging', 'promote-production', 'direct-deploy'];
|
|
30
|
+
const files = [];
|
|
31
|
+
for (const name of names) {
|
|
32
|
+
const result = generateWorkflow(projectDir, config, name);
|
|
33
|
+
if (!result.success)
|
|
34
|
+
return result;
|
|
35
|
+
files.push(result.data.path);
|
|
36
|
+
}
|
|
37
|
+
return ok({ files });
|
|
38
|
+
}
|
|
39
|
+
// ---------------------------------------------------------------------------
|
|
40
|
+
// Workflow templates
|
|
41
|
+
// ---------------------------------------------------------------------------
|
|
42
|
+
function getWorkflowContent(config, workflow) {
|
|
43
|
+
switch (workflow) {
|
|
44
|
+
case 'deploy-admin':
|
|
45
|
+
return `name: Deploy Admin
|
|
46
|
+
on:
|
|
47
|
+
push:
|
|
48
|
+
branches: [admin]
|
|
49
|
+
|
|
50
|
+
jobs:
|
|
51
|
+
deploy:
|
|
52
|
+
runs-on: ubuntu-latest
|
|
53
|
+
steps:
|
|
54
|
+
- uses: actions/checkout@v4
|
|
55
|
+
- uses: actions/setup-node@v4
|
|
56
|
+
with:
|
|
57
|
+
node-version: 20
|
|
58
|
+
cache: 'npm'
|
|
59
|
+
- run: npm ci
|
|
60
|
+
- run: npm run build
|
|
61
|
+
- name: Deploy to Cloudflare Pages
|
|
62
|
+
uses: cloudflare/wrangler-action@v3
|
|
63
|
+
with:
|
|
64
|
+
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
65
|
+
accountId: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
66
|
+
command: pages deploy dist --project-name=${config.adminPagesProjectName}
|
|
67
|
+
`;
|
|
68
|
+
case 'build-staging':
|
|
69
|
+
return `# staging ブランチ(デフォルト + カスタム)への push で発火し、SSG を実行する。
|
|
70
|
+
# カスタム staging(staging-*)は artifact アップロードなし(プレビュー専用)。
|
|
71
|
+
name: Build Staging
|
|
72
|
+
on:
|
|
73
|
+
push:
|
|
74
|
+
branches: [staging, 'staging-*']
|
|
75
|
+
|
|
76
|
+
permissions:
|
|
77
|
+
contents: read
|
|
78
|
+
|
|
79
|
+
jobs:
|
|
80
|
+
build:
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
steps:
|
|
83
|
+
- uses: actions/checkout@v4
|
|
84
|
+
- uses: actions/setup-node@v4
|
|
85
|
+
with:
|
|
86
|
+
node-version: 20
|
|
87
|
+
cache: 'npm'
|
|
88
|
+
|
|
89
|
+
# 前回のビルド状態を復元(差分ビルド用)
|
|
90
|
+
- name: Restore SSG cache
|
|
91
|
+
uses: actions/cache@v4
|
|
92
|
+
with:
|
|
93
|
+
path: |
|
|
94
|
+
frelio-data/site/data/data-json
|
|
95
|
+
public
|
|
96
|
+
key: ssg-cache-\${{ github.ref_name }}-\${{ github.sha }}
|
|
97
|
+
restore-keys: |
|
|
98
|
+
ssg-cache-\${{ github.ref_name }}-
|
|
99
|
+
|
|
100
|
+
- run: npm ci
|
|
101
|
+
|
|
102
|
+
# Phase 1: JSON 中間データ生成
|
|
103
|
+
- name: Generate JSON data
|
|
104
|
+
run: npx frelio-data-json-generator
|
|
105
|
+
|
|
106
|
+
# Phase 2: HTML 生成
|
|
107
|
+
- name: Generate HTML
|
|
108
|
+
run: npx frelio-gentl
|
|
109
|
+
|
|
110
|
+
# Phase 3: アセットビルド(静的アセットコピー + Vite)
|
|
111
|
+
- name: Build assets
|
|
112
|
+
run: npm run build
|
|
113
|
+
|
|
114
|
+
# デフォルト staging のみ: artifact をアップロード(本番デプロイ用)
|
|
115
|
+
- name: Upload artifact
|
|
116
|
+
if: github.ref == 'refs/heads/staging'
|
|
117
|
+
uses: actions/upload-artifact@v4
|
|
118
|
+
with:
|
|
119
|
+
name: staging-build
|
|
120
|
+
path: public/
|
|
121
|
+
retention-days: 14
|
|
122
|
+
|
|
123
|
+
# Cloudflare Pages にブランチプレビューとしてデプロイ
|
|
124
|
+
- name: Deploy preview
|
|
125
|
+
uses: cloudflare/wrangler-action@v3
|
|
126
|
+
with:
|
|
127
|
+
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
128
|
+
accountId: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
129
|
+
command: pages deploy public --project-name=${config.pagesProjectName} --branch=\${{ github.ref_name }}
|
|
130
|
+
`;
|
|
131
|
+
case 'promote-production':
|
|
132
|
+
return `# staging → main マージ(push to main)で発火。
|
|
133
|
+
# 最新の staging artifact をダウンロードし、Pages 本番にデプロイする。
|
|
134
|
+
# artifact 欠損時はフォールバックとしてフル SSG ビルドを実行する。
|
|
135
|
+
name: Promote to Production
|
|
136
|
+
on:
|
|
137
|
+
push:
|
|
138
|
+
branches: [main]
|
|
139
|
+
|
|
140
|
+
permissions:
|
|
141
|
+
contents: write
|
|
142
|
+
actions: read
|
|
143
|
+
|
|
144
|
+
jobs:
|
|
145
|
+
deploy:
|
|
146
|
+
runs-on: ubuntu-latest
|
|
147
|
+
steps:
|
|
148
|
+
- uses: actions/checkout@v4
|
|
149
|
+
with:
|
|
150
|
+
fetch-depth: 0
|
|
151
|
+
|
|
152
|
+
# 最新の成功した Build Staging ワークフロー run を検索
|
|
153
|
+
- name: Find latest staging build run
|
|
154
|
+
id: find-run
|
|
155
|
+
uses: actions/github-script@v7
|
|
156
|
+
with:
|
|
157
|
+
script: |
|
|
158
|
+
const runs = await github.rest.actions.listWorkflowRuns({
|
|
159
|
+
owner: context.repo.owner,
|
|
160
|
+
repo: context.repo.repo,
|
|
161
|
+
workflow_id: 'build-staging.yml',
|
|
162
|
+
branch: 'staging',
|
|
163
|
+
status: 'success',
|
|
164
|
+
per_page: 1,
|
|
165
|
+
});
|
|
166
|
+
if (runs.data.workflow_runs.length > 0) {
|
|
167
|
+
core.setOutput('run-id', runs.data.workflow_runs[0].id);
|
|
168
|
+
} else {
|
|
169
|
+
core.setOutput('run-id', '');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
# cross-workflow artifact ダウンロード
|
|
173
|
+
- name: Download staging artifact
|
|
174
|
+
id: download-artifact
|
|
175
|
+
if: steps.find-run.outputs.run-id != ''
|
|
176
|
+
continue-on-error: true
|
|
177
|
+
uses: actions/download-artifact@v4
|
|
178
|
+
with:
|
|
179
|
+
name: staging-build
|
|
180
|
+
path: public/
|
|
181
|
+
github-token: \${{ secrets.GITHUB_TOKEN }}
|
|
182
|
+
run-id: \${{ steps.find-run.outputs.run-id }}
|
|
183
|
+
|
|
184
|
+
# artifact 取得結果を判定
|
|
185
|
+
- name: Check if artifact was downloaded
|
|
186
|
+
id: check-artifact
|
|
187
|
+
run: |
|
|
188
|
+
if [ -d "public" ] && [ "\$(ls -A public 2>/dev/null)" ]; then
|
|
189
|
+
echo "has_artifact=true" >> "\$GITHUB_OUTPUT"
|
|
190
|
+
else
|
|
191
|
+
echo "::warning::Staging artifact not found or expired. Running full SSG build."
|
|
192
|
+
echo "has_artifact=false" >> "\$GITHUB_OUTPUT"
|
|
193
|
+
fi
|
|
194
|
+
|
|
195
|
+
# --- フォールバックビルド(artifact 欠損時のみ) ---
|
|
196
|
+
- name: Setup Node.js (fallback)
|
|
197
|
+
if: steps.check-artifact.outputs.has_artifact == 'false'
|
|
198
|
+
uses: actions/setup-node@v4
|
|
199
|
+
with:
|
|
200
|
+
node-version: 20
|
|
201
|
+
cache: 'npm'
|
|
202
|
+
|
|
203
|
+
- name: Install dependencies (fallback)
|
|
204
|
+
if: steps.check-artifact.outputs.has_artifact == 'false'
|
|
205
|
+
run: npm ci
|
|
206
|
+
|
|
207
|
+
- name: Full SSG build (fallback)
|
|
208
|
+
if: steps.check-artifact.outputs.has_artifact == 'false'
|
|
209
|
+
run: |
|
|
210
|
+
npx frelio-data-json-generator --full-rebuild
|
|
211
|
+
npx frelio-gentl
|
|
212
|
+
npm run build
|
|
213
|
+
|
|
214
|
+
# Cloudflare Pages 本番にデプロイ
|
|
215
|
+
- name: Deploy to production
|
|
216
|
+
uses: cloudflare/wrangler-action@v3
|
|
217
|
+
with:
|
|
218
|
+
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
219
|
+
accountId: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
220
|
+
command: pages deploy public --project-name=${config.pagesProjectName} --branch=main
|
|
221
|
+
|
|
222
|
+
# デプロイタグ作成
|
|
223
|
+
- name: Create deploy tag
|
|
224
|
+
run: |
|
|
225
|
+
VERSION=\$(jq -r '.version' version.json 2>/dev/null || echo "0.0.0")
|
|
226
|
+
PREFIX="d\${VERSION}."
|
|
227
|
+
|
|
228
|
+
LATEST=\$(git tag -l "\${PREFIX}*" | sed "s/^\${PREFIX}//" | sort -n | tail -1)
|
|
229
|
+
NEXT=\$(( \${LATEST:-0} + 1 ))
|
|
230
|
+
|
|
231
|
+
TAG="\${PREFIX}\${NEXT}"
|
|
232
|
+
echo "Creating tag: \$TAG"
|
|
233
|
+
|
|
234
|
+
git config user.name "github-actions[bot]"
|
|
235
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
236
|
+
git tag -a "\$TAG" -m "Production deploy \$TAG"
|
|
237
|
+
git push origin "\$TAG"
|
|
238
|
+
|
|
239
|
+
echo "::notice::Tagged as \$TAG"
|
|
240
|
+
`;
|
|
241
|
+
case 'direct-deploy':
|
|
242
|
+
return `# CMS の「直接デプロイ」ボタンから workflow_dispatch で発火。
|
|
243
|
+
# develop → staging マージ → SSG ビルド → artifact → staging プレビュー →
|
|
244
|
+
# staging → main マージ → 本番デプロイ → デプロイタグ付与
|
|
245
|
+
name: Direct Deploy
|
|
246
|
+
on:
|
|
247
|
+
workflow_dispatch:
|
|
248
|
+
|
|
249
|
+
permissions:
|
|
250
|
+
contents: write
|
|
251
|
+
|
|
252
|
+
jobs:
|
|
253
|
+
build:
|
|
254
|
+
runs-on: ubuntu-latest
|
|
255
|
+
steps:
|
|
256
|
+
- uses: actions/checkout@v4
|
|
257
|
+
with:
|
|
258
|
+
fetch-depth: 0
|
|
259
|
+
|
|
260
|
+
- name: Configure git
|
|
261
|
+
run: |
|
|
262
|
+
git config user.name "github-actions[bot]"
|
|
263
|
+
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
264
|
+
|
|
265
|
+
# Step 1: develop → staging マージ
|
|
266
|
+
- name: Merge develop into staging
|
|
267
|
+
run: |
|
|
268
|
+
git checkout staging
|
|
269
|
+
git merge origin/develop --no-edit
|
|
270
|
+
git push origin staging
|
|
271
|
+
|
|
272
|
+
# Step 2: SSG ビルド
|
|
273
|
+
- uses: actions/setup-node@v4
|
|
274
|
+
with:
|
|
275
|
+
node-version: 20
|
|
276
|
+
cache: 'npm'
|
|
277
|
+
|
|
278
|
+
# 前回の staging ビルド状態を復元(差分ビルド用)
|
|
279
|
+
- name: Restore SSG cache
|
|
280
|
+
uses: actions/cache@v4
|
|
281
|
+
with:
|
|
282
|
+
path: |
|
|
283
|
+
frelio-data/site/data/data-json
|
|
284
|
+
public
|
|
285
|
+
key: ssg-cache-staging-\${{ github.sha }}
|
|
286
|
+
restore-keys: |
|
|
287
|
+
ssg-cache-staging-
|
|
288
|
+
|
|
289
|
+
- run: npm ci
|
|
290
|
+
|
|
291
|
+
- name: Generate JSON data
|
|
292
|
+
run: npx frelio-data-json-generator
|
|
293
|
+
|
|
294
|
+
- name: Generate HTML
|
|
295
|
+
run: npx frelio-gentl
|
|
296
|
+
|
|
297
|
+
- name: Build assets
|
|
298
|
+
run: npm run build
|
|
299
|
+
|
|
300
|
+
# Step 3: artifact アップロード
|
|
301
|
+
- name: Upload artifact
|
|
302
|
+
uses: actions/upload-artifact@v4
|
|
303
|
+
with:
|
|
304
|
+
name: staging-build
|
|
305
|
+
path: public/
|
|
306
|
+
retention-days: 14
|
|
307
|
+
|
|
308
|
+
# Step 4: Cloudflare Pages プレビューデプロイ(staging ブランチ)
|
|
309
|
+
- name: Deploy staging preview
|
|
310
|
+
uses: cloudflare/wrangler-action@v3
|
|
311
|
+
with:
|
|
312
|
+
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
313
|
+
accountId: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
314
|
+
command: pages deploy public --project-name=${config.pagesProjectName} --branch=staging
|
|
315
|
+
|
|
316
|
+
# Step 5: staging → main マージ
|
|
317
|
+
- name: Fast-forward main to staging
|
|
318
|
+
run: |
|
|
319
|
+
git checkout main
|
|
320
|
+
git merge --ff-only staging
|
|
321
|
+
git push origin main
|
|
322
|
+
|
|
323
|
+
# Step 6: Cloudflare Pages 本番デプロイ
|
|
324
|
+
- name: Deploy to production
|
|
325
|
+
uses: cloudflare/wrangler-action@v3
|
|
326
|
+
with:
|
|
327
|
+
apiToken: \${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
328
|
+
accountId: \${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
329
|
+
command: pages deploy public --project-name=${config.pagesProjectName} --branch=main
|
|
330
|
+
|
|
331
|
+
# Step 7: デプロイタグ作成
|
|
332
|
+
- name: Create deploy tag
|
|
333
|
+
run: |
|
|
334
|
+
VERSION=\$(jq -r '.version' version.json 2>/dev/null || echo "0.0.0")
|
|
335
|
+
PREFIX="d\${VERSION}."
|
|
336
|
+
LATEST=\$(git tag -l "\${PREFIX}*" | sed "s/^\${PREFIX}//" | sort -n | tail -1)
|
|
337
|
+
NEXT=\$(( \${LATEST:-0} + 1 ))
|
|
338
|
+
TAG="\${PREFIX}\${NEXT}"
|
|
339
|
+
|
|
340
|
+
git tag -a "\$TAG" -m "Direct deploy \$TAG"
|
|
341
|
+
git push origin "\$TAG"
|
|
342
|
+
echo "::notice::Tagged as \$TAG"
|
|
343
|
+
`;
|
|
344
|
+
}
|
|
345
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ program
|
|
|
13
13
|
.description('Initialize a new Frelio CMS project (creates repo, deploys admin, sets up R2)')
|
|
14
14
|
.option('--skip-github', 'Skip GitHub repository creation')
|
|
15
15
|
.option('--skip-cloudflare', 'Skip Cloudflare setup (R2, Pages)')
|
|
16
|
+
.option('--terraform', 'Generate Terraform files instead of running wrangler commands')
|
|
16
17
|
.option('--content-repo <repo>', 'Repository name (owner/repo)')
|
|
17
18
|
.option('--site-title <title>', 'Site title')
|
|
18
19
|
.option('--production-url <url>', 'Production URL')
|
|
@@ -30,10 +31,7 @@ program
|
|
|
30
31
|
.action(updateCommand);
|
|
31
32
|
program
|
|
32
33
|
.command('add-staging')
|
|
33
|
-
.description('Add a staging environment (
|
|
34
|
+
.description('Add a staging environment (creates branch, uses Pages branch preview)')
|
|
34
35
|
.option('--name <name>', 'Staging name (creates staging-{name} branch)')
|
|
35
|
-
.option('--skip-cloudflare', 'Skip Cloudflare Pages project creation')
|
|
36
|
-
.option('--pages-project <name>', 'Cloudflare Pages project name for staging')
|
|
37
|
-
.option('--domain <domain>', 'Custom domain for staging')
|
|
38
36
|
.action(addStagingCommand);
|
|
39
37
|
program.parse();
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Release からの tarball ダウンロード
|
|
3
|
+
*/
|
|
4
|
+
type ReleaseAsset = {
|
|
5
|
+
name: string;
|
|
6
|
+
browser_download_url: string;
|
|
7
|
+
};
|
|
8
|
+
type Release = {
|
|
9
|
+
tag_name: string;
|
|
10
|
+
assets: ReleaseAsset[];
|
|
11
|
+
};
|
|
12
|
+
export declare function getLatestRelease(): Promise<Release>;
|
|
13
|
+
export declare function getRelease(version: string): Promise<Release>;
|
|
14
|
+
export declare function downloadTarball(release: Release, destDir: string): Promise<string>;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitHub Release からの tarball ダウンロード
|
|
3
|
+
*/
|
|
4
|
+
import { createWriteStream } from 'node:fs';
|
|
5
|
+
import { pipeline } from 'node:stream/promises';
|
|
6
|
+
import { Readable } from 'node:stream';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
const REPO = 'ctime-projects/frelio';
|
|
9
|
+
export async function getLatestRelease() {
|
|
10
|
+
const res = await fetch(`https://api.github.com/repos/${REPO}/releases/latest`, {
|
|
11
|
+
headers: { Accept: 'application/vnd.github.v3+json' },
|
|
12
|
+
});
|
|
13
|
+
if (!res.ok) {
|
|
14
|
+
throw new Error(`Failed to fetch latest release: ${res.status} ${res.statusText}`);
|
|
15
|
+
}
|
|
16
|
+
return res.json();
|
|
17
|
+
}
|
|
18
|
+
export async function getRelease(version) {
|
|
19
|
+
const tag = version.startsWith('v') ? version : `v${version}`;
|
|
20
|
+
const res = await fetch(`https://api.github.com/repos/${REPO}/releases/tags/${tag}`, {
|
|
21
|
+
headers: { Accept: 'application/vnd.github.v3+json' },
|
|
22
|
+
});
|
|
23
|
+
if (!res.ok) {
|
|
24
|
+
throw new Error(`Release ${tag} not found: ${res.status}`);
|
|
25
|
+
}
|
|
26
|
+
return res.json();
|
|
27
|
+
}
|
|
28
|
+
export async function downloadTarball(release, destDir) {
|
|
29
|
+
const asset = release.assets.find((a) => a.name.endsWith('.tar.gz'));
|
|
30
|
+
if (!asset) {
|
|
31
|
+
throw new Error('No tarball found in release assets');
|
|
32
|
+
}
|
|
33
|
+
const destPath = path.join(destDir, asset.name);
|
|
34
|
+
const res = await fetch(asset.browser_download_url);
|
|
35
|
+
if (!res.ok || !res.body) {
|
|
36
|
+
throw new Error(`Failed to download: ${res.status}`);
|
|
37
|
+
}
|
|
38
|
+
const readable = Readable.fromWeb(res.body);
|
|
39
|
+
await pipeline(readable, createWriteStream(destPath));
|
|
40
|
+
return destPath;
|
|
41
|
+
}
|