project-auto-wizard 0.9.1 → 0.11.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 +83 -4
- package/package.json +1 -1
- package/payload/config/breaking-changes.json +24 -1
- package/payload/flutter-app/android/fastlane/Fastfile.playstore +86 -0
- package/payload/flutter-app/ios/ExportOptions.plist +31 -0
- package/payload/flutter-app/ios/fastlane/Fastfile +117 -0
- package/payload/scripts/__pycache__/changelog_manager.cpython-314.pyc +0 -0
- package/payload/scripts/__pycache__/issue_helper.cpython-314.pyc +0 -0
- package/payload/scripts/__pycache__/version_manager.cpython-314.pyc +0 -0
- package/payload/scripts/changelog_manager.py +2 -2
- package/payload/scripts/version_manager.py +2 -2
- package/payload/version.yml.template +1 -0
- package/payload/workflows/common/secret-backup/PROJECT-COMMON-SECRET-FILE-UPLOAD.yaml +12 -12
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-FIREBASE-CICD.yaml +48 -20
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD.yaml +44 -19
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-SELFHOSTED-CICD.yaml +28 -36
- package/payload/workflows/flutter/PROJECT-FLUTTER-ANDROID-TEST-APK.yaml +33 -46
- package/payload/workflows/flutter/{PROJECT-FLUTTER-SUH-LAB-APP-BUILD-TRIGGER.yaml → PROJECT-FLUTTER-APP-BUILD-TRIGGER.yaml} +38 -38
- package/payload/workflows/flutter/PROJECT-FLUTTER-CI.yaml +123 -32
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT.yaml +57 -42
- package/payload/workflows/flutter/PROJECT-FLUTTER-IOS-TESTFLIGHT.yaml +61 -40
- package/payload/workflows/go/PROJECT-GO-CI.yaml +47 -0
- package/payload/workflows/go/PROJECT-GO-PR-PREVIEW.yaml +40 -40
- package/payload/workflows/next/PROJECT-NEXT-CI.yaml +47 -0
- package/payload/workflows/python/PROJECT-PYTHON-CI.yaml +47 -0
- package/payload/workflows/python/PROJECT-PYTHON-PR-PREVIEW.yaml +40 -40
- package/payload/workflows/react/PROJECT-REACT-CI.yaml +47 -0
- package/payload/workflows/spring/nexus/PROJECT-SPRING-GITHUB-PACKAGES-PUBLISH.yml +1 -0
- package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-CI.yml +47 -0
- package/payload/workflows/spring/nexus/PROJECT-SPRING-NEXUS-PUBLISH.yml +1 -0
- package/payload/workflows/spring/server-deploy/PROJECT-SPRING-PR-PREVIEW.yaml +39 -39
- package/src/cli/args.js +37 -0
- package/src/cli/help.js +4 -0
- package/src/commands/doctor.js +55 -2
- package/src/commands/dry-run.js +10 -0
- package/src/commands/full.js +28 -3
- package/src/commands/interactive-flutter.js +95 -0
- package/src/commands/interactive.js +51 -5
- package/src/commands/status.js +20 -2
- package/src/context.js +6 -0
- package/src/core/breaking.js +7 -3
- package/src/core/copy/flutter-app.js +42 -0
- package/src/core/copy/workflows.js +21 -9
- package/src/core/detect-fs.js +9 -1
- package/src/core/flutter-options.js +118 -0
- package/src/core/installed-stores.js +12 -0
- package/src/core/verify.js +2 -2
- package/src/core/version-yml.js +40 -5
- package/src/core/wizard-env.js +26 -4
- package/src/index.js +32 -1
- package/src/ui/env-plan.js +8 -5
- package/src/ui/prompts.js +88 -3
- package/src/ui/status-cards.js +13 -1
- package/src/ui/summary.js +24 -5
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
# project-auto-wizard:managed-workflow
|
|
2
2
|
# ===================================================================
|
|
3
|
-
# Flutter 테스트 앱 빌드 트리거 워크플로우
|
|
3
|
+
# Flutter 테스트 앱 빌드 트리거 워크플로우
|
|
4
4
|
# ===================================================================
|
|
5
5
|
#
|
|
6
6
|
# 이 워크플로우는 PR 또는 이슈에 댓글로 빌드 명령어를 작성하면
|
|
7
7
|
# Android와 iOS 테스트 앱 빌드를 자동으로 트리거합니다.
|
|
8
8
|
#
|
|
9
9
|
# 주요 특징:
|
|
10
|
-
# - PR/이슈 댓글 감지: "
|
|
10
|
+
# - PR/이슈 댓글 감지: "/wizard app build / apk build / ios build" 키워드 감지 (어순 무관: build app 도 동작)
|
|
11
11
|
# - repository_dispatch 이벤트로 빌드 워크플로우 트리거
|
|
12
12
|
# - PR/이슈 번호 + 빌드 횟수로 고유한 빌드 번호 생성 (예: 38700, 38701...)
|
|
13
13
|
# - 브랜치명에서 이슈 번호 자동 추출 (YYYYMMDD_#이슈번호_내용 형식)
|
|
14
14
|
# - 테스트 버전은 version.yml에서 동적으로 읽어 사용 (빌드 번호로 운영/테스트 구분)
|
|
15
15
|
#
|
|
16
16
|
# 사용 방법:
|
|
17
|
-
# - PR에 댓글 작성: "
|
|
18
|
-
# - PR에 댓글 작성: "
|
|
19
|
-
# - PR에 댓글 작성: "
|
|
20
|
-
# - 이슈에 댓글 작성: 위 명령어 동일 (
|
|
17
|
+
# - PR에 댓글 작성: "/wizard app build" (Android + iOS 모두 빌드)
|
|
18
|
+
# - PR에 댓글 작성: "/wizard apk build" (Android만 빌드)
|
|
19
|
+
# - PR에 댓글 작성: "/wizard ios build" (iOS만 빌드)
|
|
20
|
+
# - 이슈에 댓글 작성: 위 명령어 동일 (Issue Helper 댓글 필요)
|
|
21
21
|
# - 어순은 무관: "build app" / "build apk" / "build ios"로 적어도 동일하게 동작
|
|
22
|
-
# - 특정 브랜치 지정: "
|
|
23
|
-
# 예: "
|
|
24
|
-
# 브랜치명을 생략하면 PR head 또는 이슈의
|
|
22
|
+
# - 특정 브랜치 지정: "/wizard app build <브랜치명>" (명령어 뒤에 브랜치명을 적으면 해당 브랜치를 빌드)
|
|
23
|
+
# 예: "/wizard apk build 20260609_#349_feature" → 해당 브랜치로 Android 빌드
|
|
24
|
+
# 브랜치명을 생략하면 PR head 또는 이슈의 Issue Helper 댓글 브랜치를 사용
|
|
25
25
|
#
|
|
26
26
|
# 트리거되는 워크플로우:
|
|
27
27
|
# - PROJECT-FLUTTER-ANDROID-TEST-APK.yaml (event_type: build-android-app)
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
#
|
|
30
30
|
# ===================================================================
|
|
31
31
|
|
|
32
|
-
name: PROJECT-Flutter-
|
|
32
|
+
name: PROJECT-Flutter-App-Build-Trigger
|
|
33
33
|
|
|
34
34
|
on:
|
|
35
35
|
issue_comment:
|
|
@@ -43,9 +43,9 @@ permissions:
|
|
|
43
43
|
jobs:
|
|
44
44
|
trigger-builds:
|
|
45
45
|
name: 빌드 워크플로우 트리거
|
|
46
|
-
#
|
|
46
|
+
# /wizard app build / /wizard apk build / /wizard ios build 키워드 감지 (어순 무관)
|
|
47
47
|
if: |
|
|
48
|
-
contains(github.event.comment.body, '
|
|
48
|
+
contains(github.event.comment.body, '/wizard') &&
|
|
49
49
|
(
|
|
50
50
|
(contains(github.event.comment.body, 'build') && contains(github.event.comment.body, 'app')) ||
|
|
51
51
|
(contains(github.event.comment.body, 'apk') && contains(github.event.comment.body, 'build')) ||
|
|
@@ -93,27 +93,27 @@ jobs:
|
|
|
93
93
|
// 어순은 양방향 지원: "{타입} build"(app/apk/ios build)와 "build {타입}"(build app 등) 모두 허용.
|
|
94
94
|
// apk가 app으로 오인되지 않도록 app 토큰은 \b 단어경계로 정확히 끊는다(apk·application 제외).
|
|
95
95
|
// apk/ios를 app보다 먼저 검사해, "apk build"가 app 분기로 새지 않게 한다.
|
|
96
|
-
if (comment.match(
|
|
97
|
-
//
|
|
96
|
+
if (comment.match(/\/wizard[^\S\r\n]+apk[^\S\r\n]+build/) || comment.match(/\/wizard[^\S\r\n]+build[^\S\r\n]+apk/)) {
|
|
97
|
+
// /wizard apk build [브랜치] (또는 build apk) → Android만
|
|
98
98
|
buildAndroid = true;
|
|
99
99
|
buildType = 'apk';
|
|
100
|
-
m = rawComment.match(
|
|
101
|
-
|| rawComment.match(
|
|
100
|
+
m = rawComment.match(/\/wizard[^\S\r\n]+apk[^\S\r\n]+build(?:[^\S\r\n]+(\S+))?/i)
|
|
101
|
+
|| rawComment.match(/\/wizard[^\S\r\n]+build[^\S\r\n]+apk(?:[^\S\r\n]+(\S+))?/i);
|
|
102
102
|
customBranch = (m && m[1]) || '';
|
|
103
|
-
} else if (comment.match(
|
|
104
|
-
//
|
|
103
|
+
} else if (comment.match(/\/wizard[^\S\r\n]+ios[^\S\r\n]+build/) || comment.match(/\/wizard[^\S\r\n]+build[^\S\r\n]+ios/)) {
|
|
104
|
+
// /wizard ios build [브랜치] (또는 build ios) → iOS만
|
|
105
105
|
buildIos = true;
|
|
106
106
|
buildType = 'ios';
|
|
107
|
-
m = rawComment.match(
|
|
108
|
-
|| rawComment.match(
|
|
107
|
+
m = rawComment.match(/\/wizard[^\S\r\n]+ios[^\S\r\n]+build(?:[^\S\r\n]+(\S+))?/i)
|
|
108
|
+
|| rawComment.match(/\/wizard[^\S\r\n]+build[^\S\r\n]+ios(?:[^\S\r\n]+(\S+))?/i);
|
|
109
109
|
customBranch = (m && m[1]) || '';
|
|
110
|
-
} else if (comment.match(
|
|
111
|
-
//
|
|
110
|
+
} else if (comment.match(/\/wizard[^\S\r\n]+app\b[^\S\r\n]+build/) || comment.match(/\/wizard[^\S\r\n]+build[^\S\r\n]+app\b/)) {
|
|
111
|
+
// /wizard app build [브랜치] (또는 build app) → Android + iOS 모두
|
|
112
112
|
buildAndroid = true;
|
|
113
113
|
buildIos = true;
|
|
114
114
|
buildType = 'app';
|
|
115
|
-
m = rawComment.match(
|
|
116
|
-
|| rawComment.match(
|
|
115
|
+
m = rawComment.match(/\/wizard[^\S\r\n]+app\b[^\S\r\n]+build(?:[^\S\r\n]+(\S+))?/i)
|
|
116
|
+
|| rawComment.match(/\/wizard[^\S\r\n]+build[^\S\r\n]+app\b(?:[^\S\r\n]+(\S+))?/i);
|
|
117
117
|
customBranch = (m && m[1]) || '';
|
|
118
118
|
}
|
|
119
119
|
|
|
@@ -175,7 +175,7 @@ jobs:
|
|
|
175
175
|
} catch (error) {
|
|
176
176
|
console.log('ℹ️ PR이 아닙니다. 이슈에서 브랜치 정보를 찾습니다...');
|
|
177
177
|
|
|
178
|
-
// 2. PR이 아니면 이슈에서 "
|
|
178
|
+
// 2. PR이 아니면 이슈에서 "Issue Helper" 댓글 찾기
|
|
179
179
|
sourceType = 'ISSUE';
|
|
180
180
|
sourceNumber = issueNumber.toString();
|
|
181
181
|
relatedIssueNumber = issueNumber.toString();
|
|
@@ -203,27 +203,27 @@ jobs:
|
|
|
203
203
|
per_page: 100
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
-
// "
|
|
206
|
+
// "Issue Helper" 댓글 찾기
|
|
207
207
|
const guideComment = comments.data.find(c =>
|
|
208
|
-
c.body.includes('
|
|
208
|
+
c.body.includes('<!-- project-auto-wizard issue helper -->')
|
|
209
209
|
);
|
|
210
210
|
|
|
211
211
|
if (!guideComment) {
|
|
212
|
-
console.log('❌ "
|
|
212
|
+
console.log('❌ "Issue Helper" 댓글을 찾을 수 없습니다.');
|
|
213
213
|
core.setOutput('found', 'false');
|
|
214
|
-
core.setOutput('errorMessage', '이슈에서 "
|
|
214
|
+
core.setOutput('errorMessage', '이슈에서 "Issue Helper" 댓글을 찾을 수 없습니다. 브랜치 정보가 포함된 댓글이 필요합니다.');
|
|
215
215
|
return;
|
|
216
216
|
}
|
|
217
217
|
|
|
218
|
-
console.log('✅ "
|
|
218
|
+
console.log('✅ "Issue Helper" 댓글 발견');
|
|
219
219
|
|
|
220
220
|
// 브랜치명 추출 (### 브랜치 다음 ``` 블록 내용)
|
|
221
|
-
const branchMatch = guideComment.body.match(/###
|
|
221
|
+
const branchMatch = guideComment.body.match(/### 브랜치(?:명)?\s*```\s*([\s\S]*?)\s*```/);
|
|
222
222
|
|
|
223
223
|
if (!branchMatch) {
|
|
224
224
|
console.log('❌ 브랜치 정보를 파싱할 수 없습니다.');
|
|
225
225
|
core.setOutput('found', 'false');
|
|
226
|
-
core.setOutput('errorMessage', '"
|
|
226
|
+
core.setOutput('errorMessage', '"Issue Helper" 댓글에서 브랜치 정보를 파싱할 수 없습니다. 댓글 형식을 확인해주세요.');
|
|
227
227
|
return;
|
|
228
228
|
}
|
|
229
229
|
|
|
@@ -262,9 +262,9 @@ jobs:
|
|
|
262
262
|
|
|
263
263
|
**해결 방법:**
|
|
264
264
|
- PR에서 빌드하는 경우: PR 페이지에서 댓글을 작성해주세요.
|
|
265
|
-
- 이슈에서 빌드하는 경우: "
|
|
265
|
+
- 이슈에서 빌드하는 경우: "Issue Helper" 댓글이 있어야 합니다.
|
|
266
266
|
- 댓글에 \`### 브랜치\` 섹션과 브랜치명이 포함되어 있어야 합니다.
|
|
267
|
-
- 또는 댓글에 브랜치명을 직접 지정할 수 있습니다:
|
|
267
|
+
- 또는 댓글에 브랜치명을 직접 지정할 수 있습니다: \`/wizard app build <브랜치명>\``;
|
|
268
268
|
|
|
269
269
|
await github.rest.issues.createComment({
|
|
270
270
|
owner: context.repo.owner,
|
|
@@ -329,7 +329,7 @@ jobs:
|
|
|
329
329
|
'',
|
|
330
330
|
'### 💡 확인 사항',
|
|
331
331
|
'1. 브랜치가 원격 저장소에 push되었는지 확인하세요',
|
|
332
|
-
'2. "
|
|
332
|
+
'2. "Issue Helper" 댓글의 브랜치명이 올바른지 확인하세요',
|
|
333
333
|
'3. 브랜치명에 오타가 없는지 확인하세요',
|
|
334
334
|
'',
|
|
335
335
|
`🔗 [워크플로우 로그](${runUrl})`
|
|
@@ -377,7 +377,7 @@ jobs:
|
|
|
377
377
|
// iOS 빌드: ios 빌드 + app 공용 빌드 둘 다 카운트 (어순 무관)
|
|
378
378
|
buildCount = comments.data.filter(c => {
|
|
379
379
|
const body = c.body.toLowerCase();
|
|
380
|
-
return body.includes('
|
|
380
|
+
return body.includes('/wizard') && body.includes('build') && (
|
|
381
381
|
body.includes('ios') || body.includes('app')
|
|
382
382
|
);
|
|
383
383
|
}).length;
|
|
@@ -387,7 +387,7 @@ jobs:
|
|
|
387
387
|
// Android 빌드: apk 빌드 + app 공용 빌드 둘 다 카운트 (어순 무관)
|
|
388
388
|
buildCount = comments.data.filter(c => {
|
|
389
389
|
const body = c.body.toLowerCase();
|
|
390
|
-
return body.includes('
|
|
390
|
+
return body.includes('/wizard') && body.includes('build') && (
|
|
391
391
|
body.includes('apk') || body.includes('app')
|
|
392
392
|
);
|
|
393
393
|
}).length;
|
|
@@ -397,7 +397,7 @@ jobs:
|
|
|
397
397
|
// 전체 앱 빌드: 모든 빌드 명령어 카운트 (어순 무관)
|
|
398
398
|
buildCount = comments.data.filter(c => {
|
|
399
399
|
const body = c.body.toLowerCase();
|
|
400
|
-
return body.includes('
|
|
400
|
+
return body.includes('/wizard') && body.includes('build') && (
|
|
401
401
|
body.includes('ios') ||
|
|
402
402
|
body.includes('apk') ||
|
|
403
403
|
body.includes('app')
|
|
@@ -32,7 +32,10 @@
|
|
|
32
32
|
# FLUTTER_VERSION : Flutter SDK 버전
|
|
33
33
|
# JAVA_VERSION : Java 버전 (Android 빌드용)
|
|
34
34
|
# XCODE_VERSION : Xcode 버전 (iOS 빌드용)
|
|
35
|
-
# ENV_FILE_PATH : .env
|
|
35
|
+
# ENV_FILE_PATH : dotenv 모드에서 .env를 만들 경로 (Flutter 루트 기준, 기본값: .env)
|
|
36
|
+
# ENV_MODE : 환경변수 전달 방식 — dart-define(--dart-define-from-file) | dotenv(.env 파일)
|
|
37
|
+
# FLUTTER_PROJECT_DIR : Flutter 루트 경로 (설치 시 자동 설정, 모노레포는 app 등)
|
|
38
|
+
# PROJECT_PATH : 변경 감지 기준 경로 (설치 시 자동 설정, "."이면 항상 실행)
|
|
36
39
|
#
|
|
37
40
|
# ==========================================================================================
|
|
38
41
|
# 🔑 필수 GitHub Secrets
|
|
@@ -40,6 +43,8 @@
|
|
|
40
43
|
# ENV_FILE (선택): .env 파일 내용
|
|
41
44
|
#
|
|
42
45
|
# ※ CI는 빌드 검증 목적이므로 서명/배포 관련 Secrets 불필요
|
|
46
|
+
# ※ 모노레포에서 이 CI를 required check로 쓰려면 개별 job이 아니라 `ci-gate` 하나만 등록하세요.
|
|
47
|
+
# (경로가 바뀌지 않아 건너뛴 job은 Success로 집계되고, ci-gate가 최종 결과를 판정합니다)
|
|
43
48
|
# ==========================================================================================
|
|
44
49
|
|
|
45
50
|
name: PROJECT-Flutter-CI
|
|
@@ -73,6 +78,13 @@ permissions:
|
|
|
73
78
|
# 🔧 프로젝트별 설정 (아래 값들을 수정하세요)
|
|
74
79
|
# ==========================================================================================
|
|
75
80
|
env:
|
|
81
|
+
# 🎯 모노레포 변경 감지 경로 (설치 시 자동 설정, 단일 레포는 ".")
|
|
82
|
+
PROJECT_PATH: "." # @wizard auto:project-path
|
|
83
|
+
# Flutter 루트 경로(레포 루트 기준). 단일레포면 ".", 모노레포면 "app" 등 — 설치 시 자동 설정
|
|
84
|
+
FLUTTER_PROJECT_DIR: "." # @wizard auto:flutter-root
|
|
85
|
+
# 환경변수 전달 방식 (dart-define | dotenv) — 설치 시 선택값으로 자동 설정
|
|
86
|
+
ENV_MODE: "dart-define" # @wizard auto:flutter-env-mode
|
|
87
|
+
|
|
76
88
|
# 🎯 CI 모드 설정
|
|
77
89
|
ANALYZE_ONLY: "false" # true: analyze만 실행 (빌드 스킵), false: analyze + 빌드
|
|
78
90
|
|
|
@@ -84,18 +96,44 @@ env:
|
|
|
84
96
|
FLUTTER_VERSION: "3.35.5"
|
|
85
97
|
JAVA_VERSION: "__JAVA_VERSION__" # @wizard ask:17
|
|
86
98
|
XCODE_VERSION: "26.0"
|
|
87
|
-
ENV_FILE_PATH: ".env" #
|
|
99
|
+
ENV_FILE_PATH: ".env" # dotenv 모드에서 .env를 만들 경로 (Flutter 루트 기준, 커스터마이징 가능)
|
|
88
100
|
|
|
89
101
|
concurrency:
|
|
90
102
|
group: flutter-ci-${{ github.ref }}
|
|
91
103
|
cancel-in-progress: true
|
|
92
104
|
|
|
93
105
|
jobs:
|
|
106
|
+
# ===================================================================
|
|
107
|
+
# Job 0: 변경 감지 (PROJECT_PATH 아래가 바뀌었을 때만 이후 job 실행)
|
|
108
|
+
# ===================================================================
|
|
109
|
+
changes:
|
|
110
|
+
name: 변경 감지
|
|
111
|
+
runs-on: ubuntu-latest
|
|
112
|
+
permissions:
|
|
113
|
+
contents: read
|
|
114
|
+
pull-requests: read
|
|
115
|
+
outputs:
|
|
116
|
+
project: ${{ steps.filter.outputs.project }}
|
|
117
|
+
steps:
|
|
118
|
+
- name: Checkout repository
|
|
119
|
+
uses: actions/checkout@v7
|
|
120
|
+
|
|
121
|
+
- name: 프로젝트 경로 변경 여부 판별
|
|
122
|
+
id: filter
|
|
123
|
+
if: ${{ github.event_name != 'workflow_dispatch' }}
|
|
124
|
+
uses: dorny/paths-filter@v4
|
|
125
|
+
with:
|
|
126
|
+
filters: |
|
|
127
|
+
project:
|
|
128
|
+
- '${{ env.PROJECT_PATH == '.' && '**' || format('{0}/**', env.PROJECT_PATH) }}'
|
|
129
|
+
|
|
94
130
|
# ===================================================================
|
|
95
131
|
# Job 1: 준비 단계
|
|
96
132
|
# ===================================================================
|
|
97
133
|
prepare:
|
|
98
134
|
name: CI 준비
|
|
135
|
+
needs: changes
|
|
136
|
+
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true') }}
|
|
99
137
|
runs-on: ubuntu-latest
|
|
100
138
|
|
|
101
139
|
outputs:
|
|
@@ -229,7 +267,11 @@ jobs:
|
|
|
229
267
|
analyze:
|
|
230
268
|
name: 코드 분석
|
|
231
269
|
runs-on: ubuntu-latest
|
|
232
|
-
needs: prepare
|
|
270
|
+
needs: [changes, prepare]
|
|
271
|
+
if: ${{ (github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true') }}
|
|
272
|
+
defaults:
|
|
273
|
+
run:
|
|
274
|
+
working-directory: ${{ env.FLUTTER_PROJECT_DIR }}
|
|
233
275
|
|
|
234
276
|
outputs:
|
|
235
277
|
status: ${{ steps.result.outputs.status }}
|
|
@@ -246,13 +288,20 @@ jobs:
|
|
|
246
288
|
- name: Checkout repository
|
|
247
289
|
uses: actions/checkout@v7
|
|
248
290
|
|
|
249
|
-
# .env 파일
|
|
250
|
-
- name:
|
|
291
|
+
# 환경변수 준비 — ENV_MODE=dotenv면 .env 파일, dart-define이면 프로젝트 밖 임시 파일(--dart-define-from-file)
|
|
292
|
+
- name: Prepare env file
|
|
293
|
+
env:
|
|
294
|
+
ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
|
|
251
295
|
run: |
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
296
|
+
if [ "$ENV_MODE" = "dotenv" ]; then
|
|
297
|
+
printf '%s\n' "$ENV_CONTENT" > "$ENV_FILE_PATH"
|
|
298
|
+
echo "✅ $ENV_FILE_PATH file created"
|
|
299
|
+
elif [ -n "$ENV_CONTENT" ]; then
|
|
300
|
+
DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
|
|
301
|
+
printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
|
|
302
|
+
echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
|
|
303
|
+
echo "dart-define file prepared"
|
|
304
|
+
fi
|
|
256
305
|
|
|
257
306
|
# Flutter 설정
|
|
258
307
|
- name: Set up Flutter
|
|
@@ -271,7 +320,7 @@ jobs:
|
|
|
271
320
|
uses: actions/cache@v6
|
|
272
321
|
with:
|
|
273
322
|
path: ~/.pub-cache
|
|
274
|
-
key: ${{ runner.os }}-flutter-pub-${{ hashFiles('
|
|
323
|
+
key: ${{ runner.os }}-flutter-pub-${{ hashFiles(format('{0}/**/pubspec.lock', env.FLUTTER_PROJECT_DIR)) }}
|
|
275
324
|
restore-keys: ${{ runner.os }}-flutter-pub-
|
|
276
325
|
|
|
277
326
|
# 프로젝트 의존성 설치
|
|
@@ -317,10 +366,14 @@ jobs:
|
|
|
317
366
|
build-android:
|
|
318
367
|
name: Android 빌드
|
|
319
368
|
if: |
|
|
369
|
+
(github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true') &&
|
|
320
370
|
needs.prepare.outputs.analyze_only != 'true' &&
|
|
321
371
|
needs.prepare.outputs.enable_android == 'true'
|
|
322
372
|
runs-on: ubuntu-latest
|
|
323
|
-
needs: prepare
|
|
373
|
+
needs: [changes, prepare]
|
|
374
|
+
defaults:
|
|
375
|
+
run:
|
|
376
|
+
working-directory: ${{ env.FLUTTER_PROJECT_DIR }}
|
|
324
377
|
|
|
325
378
|
outputs:
|
|
326
379
|
status: ${{ steps.result.outputs.status }}
|
|
@@ -337,13 +390,20 @@ jobs:
|
|
|
337
390
|
- name: Checkout repository
|
|
338
391
|
uses: actions/checkout@v7
|
|
339
392
|
|
|
340
|
-
# .env 파일
|
|
341
|
-
- name:
|
|
393
|
+
# 환경변수 준비 — ENV_MODE=dotenv면 .env 파일, dart-define이면 프로젝트 밖 임시 파일(--dart-define-from-file)
|
|
394
|
+
- name: Prepare env file
|
|
395
|
+
env:
|
|
396
|
+
ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
|
|
342
397
|
run: |
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
398
|
+
if [ "$ENV_MODE" = "dotenv" ]; then
|
|
399
|
+
printf '%s\n' "$ENV_CONTENT" > "$ENV_FILE_PATH"
|
|
400
|
+
echo "✅ $ENV_FILE_PATH file created"
|
|
401
|
+
elif [ -n "$ENV_CONTENT" ]; then
|
|
402
|
+
DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
|
|
403
|
+
printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
|
|
404
|
+
echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
|
|
405
|
+
echo "dart-define file prepared"
|
|
406
|
+
fi
|
|
347
407
|
|
|
348
408
|
# Flutter 설정
|
|
349
409
|
- name: Set up Flutter
|
|
@@ -362,7 +422,7 @@ jobs:
|
|
|
362
422
|
uses: actions/cache@v6
|
|
363
423
|
with:
|
|
364
424
|
path: ~/.pub-cache
|
|
365
|
-
key: ${{ runner.os }}-flutter-pub-${{ hashFiles('
|
|
425
|
+
key: ${{ runner.os }}-flutter-pub-${{ hashFiles(format('{0}/**/pubspec.lock', env.FLUTTER_PROJECT_DIR)) }}
|
|
366
426
|
restore-keys: ${{ runner.os }}-flutter-pub-
|
|
367
427
|
|
|
368
428
|
# Gradle 캐시
|
|
@@ -372,7 +432,7 @@ jobs:
|
|
|
372
432
|
path: |
|
|
373
433
|
~/.gradle/caches
|
|
374
434
|
~/.gradle/wrapper
|
|
375
|
-
key: ${{ runner.os }}-gradle-${{ hashFiles('
|
|
435
|
+
key: ${{ runner.os }}-gradle-${{ hashFiles(format('{0}/android/**/build.gradle', env.FLUTTER_PROJECT_DIR), format('{0}/android/**/gradle-wrapper.properties', env.FLUTTER_PROJECT_DIR)) }}
|
|
376
436
|
restore-keys: |
|
|
377
437
|
${{ runner.os }}-gradle-
|
|
378
438
|
|
|
@@ -399,7 +459,7 @@ jobs:
|
|
|
399
459
|
|
|
400
460
|
# Gradle 셋업
|
|
401
461
|
- name: Setup Gradle
|
|
402
|
-
working-directory: android
|
|
462
|
+
working-directory: ${{ env.FLUTTER_PROJECT_DIR }}/android
|
|
403
463
|
run: |
|
|
404
464
|
chmod +x gradlew
|
|
405
465
|
echo "✅ Gradle wrapper permissions set"
|
|
@@ -409,7 +469,7 @@ jobs:
|
|
|
409
469
|
id: build
|
|
410
470
|
run: |
|
|
411
471
|
echo "📦 Flutter APK 빌드 시작 (debug)..."
|
|
412
|
-
flutter build apk --debug
|
|
472
|
+
flutter build apk --debug ${DART_DEFINE_FILE:+--dart-define-from-file="$DART_DEFINE_FILE"}
|
|
413
473
|
echo "✅ APK 빌드 완료"
|
|
414
474
|
ls -la ./build/app/outputs/flutter-apk/ || true
|
|
415
475
|
|
|
@@ -439,10 +499,14 @@ jobs:
|
|
|
439
499
|
build-ios:
|
|
440
500
|
name: iOS 빌드
|
|
441
501
|
if: |
|
|
502
|
+
(github.event_name == 'workflow_dispatch' || needs.changes.outputs.project == 'true') &&
|
|
442
503
|
needs.prepare.outputs.analyze_only != 'true' &&
|
|
443
504
|
needs.prepare.outputs.enable_ios == 'true'
|
|
444
505
|
runs-on: macos-26
|
|
445
|
-
needs: prepare
|
|
506
|
+
needs: [changes, prepare]
|
|
507
|
+
defaults:
|
|
508
|
+
run:
|
|
509
|
+
working-directory: ${{ env.FLUTTER_PROJECT_DIR }}
|
|
446
510
|
|
|
447
511
|
outputs:
|
|
448
512
|
status: ${{ steps.result.outputs.status }}
|
|
@@ -479,13 +543,20 @@ jobs:
|
|
|
479
543
|
echo "=== Downloading iOS platform ==="
|
|
480
544
|
xcodebuild -downloadPlatform iOS
|
|
481
545
|
|
|
482
|
-
# .env 파일
|
|
483
|
-
- name:
|
|
546
|
+
# 환경변수 준비 — ENV_MODE=dotenv면 .env 파일, dart-define이면 프로젝트 밖 임시 파일(--dart-define-from-file)
|
|
547
|
+
- name: Prepare env file
|
|
548
|
+
env:
|
|
549
|
+
ENV_CONTENT: ${{ secrets.ENV_FILE || secrets.ENV }}
|
|
484
550
|
run: |
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
551
|
+
if [ "$ENV_MODE" = "dotenv" ]; then
|
|
552
|
+
printf '%s\n' "$ENV_CONTENT" > "$ENV_FILE_PATH"
|
|
553
|
+
echo "✅ $ENV_FILE_PATH file created"
|
|
554
|
+
elif [ -n "$ENV_CONTENT" ]; then
|
|
555
|
+
DART_DEFINE_FILE="$RUNNER_TEMP/dart-define.env"
|
|
556
|
+
printf '%s\n' "$ENV_CONTENT" > "$DART_DEFINE_FILE"
|
|
557
|
+
echo "DART_DEFINE_FILE=$DART_DEFINE_FILE" >> "$GITHUB_ENV"
|
|
558
|
+
echo "dart-define file prepared"
|
|
559
|
+
fi
|
|
489
560
|
|
|
490
561
|
# Flutter 설정
|
|
491
562
|
- name: Set up Flutter
|
|
@@ -504,7 +575,7 @@ jobs:
|
|
|
504
575
|
uses: actions/cache@v6
|
|
505
576
|
with:
|
|
506
577
|
path: ~/.pub-cache
|
|
507
|
-
key: ${{ runner.os }}-flutter-pub-${{ hashFiles('
|
|
578
|
+
key: ${{ runner.os }}-flutter-pub-${{ hashFiles(format('{0}/**/pubspec.lock', env.FLUTTER_PROJECT_DIR)) }}
|
|
508
579
|
restore-keys: ${{ runner.os }}-flutter-pub-
|
|
509
580
|
|
|
510
581
|
# 프로젝트 의존성 설치
|
|
@@ -534,7 +605,7 @@ jobs:
|
|
|
534
605
|
id: build
|
|
535
606
|
run: |
|
|
536
607
|
echo "📦 Flutter iOS 빌드 시작..."
|
|
537
|
-
flutter build ios --release --no-codesign
|
|
608
|
+
flutter build ios --release --no-codesign ${DART_DEFINE_FILE:+--dart-define-from-file="$DART_DEFINE_FILE"}
|
|
538
609
|
echo "✅ iOS 빌드 완료"
|
|
539
610
|
|
|
540
611
|
# 빌드 결과 기록
|
|
@@ -562,9 +633,9 @@ jobs:
|
|
|
562
633
|
# ===================================================================
|
|
563
634
|
report:
|
|
564
635
|
name: 결과 보고
|
|
565
|
-
if: always() && github.event_name == 'pull_request'
|
|
636
|
+
if: always() && github.event_name == 'pull_request' && needs.changes.outputs.project == 'true'
|
|
566
637
|
runs-on: ubuntu-latest
|
|
567
|
-
needs: [prepare, analyze, build-android, build-ios]
|
|
638
|
+
needs: [changes, prepare, analyze, build-android, build-ios]
|
|
568
639
|
|
|
569
640
|
steps:
|
|
570
641
|
- name: 최종 결과 댓글 업데이트
|
|
@@ -714,3 +785,23 @@ jobs:
|
|
|
714
785
|
} else {
|
|
715
786
|
console.log('⚠️ 댓글 ID가 없어 업데이트를 건너뜁니다.');
|
|
716
787
|
}
|
|
788
|
+
|
|
789
|
+
# ===================================================================
|
|
790
|
+
# Job 6: CI Gate (required check로 등록할 단일 진입점)
|
|
791
|
+
# ===================================================================
|
|
792
|
+
# 건너뛴(skipped) job은 통과로 보고 failure/cancelled가 하나라도 있으면 실패한다.
|
|
793
|
+
ci-gate:
|
|
794
|
+
name: CI Gate
|
|
795
|
+
if: ${{ always() }}
|
|
796
|
+
needs: [changes, prepare, analyze, build-android, build-ios, report]
|
|
797
|
+
runs-on: ubuntu-latest
|
|
798
|
+
steps:
|
|
799
|
+
- name: 결과 집계
|
|
800
|
+
env:
|
|
801
|
+
RESULTS: ${{ toJSON(needs.*.result) }}
|
|
802
|
+
run: |
|
|
803
|
+
echo "needs 결과: $RESULTS"
|
|
804
|
+
if echo "$RESULTS" | grep -Eq '"(failure|cancelled)"'; then
|
|
805
|
+
echo "실패하거나 취소된 job이 있습니다."
|
|
806
|
+
exit 1
|
|
807
|
+
fi
|