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
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ npx project-auto-wizard
|
|
|
17
17
|
[](package.json)
|
|
18
18
|
|
|
19
19
|
<!-- AUTO-VERSION-SECTION: DO NOT EDIT MANUALLY -->
|
|
20
|
-
## 최신 버전 : v0.
|
|
20
|
+
## 최신 버전 : v0.10.0 (2026-09-21)
|
|
21
21
|
|
|
22
22
|
[전체 버전 기록 보기](CHANGELOG.md)
|
|
23
23
|
|
|
@@ -66,7 +66,7 @@ flutter.APP_ARTIFACT_NAME:
|
|
|
66
66
|
|
|
67
67
|
`spring`/`flutter`는 아래처럼 단일 CI 이상으로 깊게 구성되어 있습니다:
|
|
68
68
|
|
|
69
|
-
- **flutter**: Android(Firebase/Playstore/Selfhosted/TestAPK 배포), iOS(TestFlight/Test-TestFlight), CI, Lab 트리거까지 8종
|
|
69
|
+
- **flutter**: Android(Firebase/Playstore/Selfhosted/TestAPK 배포), iOS(TestFlight/Test-TestFlight), CI, Lab 트리거까지 8종 — 스토어 배포(Play Store·TestFlight)는 고른 플랫폼만 설치되고 fastlane 파일도 함께 생성됩니다. 환경변수 방식·배포 모드 등 자세한 내용은 아래 "Flutter 워크플로우 상세"를 참고하세요.
|
|
70
70
|
- **spring**: 서버 배포 1종(단일 서버 / 무중단 Nginx / 무중단 Traefik / 배포 안 함 중 택1) + PR 프리뷰 + 라이브러리 publish 2종(Nexus·GitHub Packages, `--nexus` opt-in)
|
|
71
71
|
- 서버 배포 워크플로우는 **서로 대체재**라 하나만 설치합니다. 대화형에서 고르면 그것만 깔리고 **`push` 트리거까지 켜진 채로** 설치됩니다. 비대화형은 `--deploy-style simple|nginx|traefik|none` (기본: `simple`).
|
|
72
72
|
- 고른 방식은 `version.yml`에 기록되므로 다시 실행해도 묻지 않습니다. 방식을 바꾸면 **이전 워크플로우를 마법사가 정리합니다** — 손대지 않은 파일은 삭제하고, 수정한 파일은 `.bak`으로 옮겨 내용을 보존합니다. 남겨두면 배포가 두 번 돕니다.
|
|
@@ -75,6 +75,81 @@ flutter.APP_ARTIFACT_NAME:
|
|
|
75
75
|
- **python**: CI / PR 프리뷰 / SimpleCICD
|
|
76
76
|
- **go**: CI(Dockerfile 불필요, go test/vet/build/lint) / PR 프리뷰 / SimpleCICD(Dockerfile 있는 프로젝트만 해당)
|
|
77
77
|
|
|
78
|
+
<a id="flutter-store"></a>
|
|
79
|
+
|
|
80
|
+
#### Flutter 워크플로우 상세
|
|
81
|
+
|
|
82
|
+
프로젝트 타입에 `flutter`가 포함되면 마법사가 아래 선택지 3개를 묻습니다. 고른 값은 `version.yml`의 `metadata.template.options`(`env_mode`, `flutter_store`, `android_deploy_mode`, `ios_deploy_mode`)에 기록되므로 다시 실행해도 묻지 않고, 나중에 바꾸려면 확인 화면의 **수정하기 > 환경변수 방식 / 스토어 배포 대상 / 배포 모드**를 쓰세요. Flutter가 없는 프로젝트에는 이 질문·저장값이 전혀 나타나지 않습니다.
|
|
83
|
+
|
|
84
|
+
| 선택지 | 값 | 기본값 | CLI 플래그 |
|
|
85
|
+
|---|---|---|---|
|
|
86
|
+
| 환경변수 방식 | `dart-define` / `dotenv` | 신규 설치는 `dart-define`. `version.yml`이 이미 있고 저장값이 없는 설치는 기존 동작을 보존하려고 `dotenv` 유지 | `--flutter-env-mode` |
|
|
87
|
+
| 스토어 배포 대상 | Android(Play Store) / iOS(TestFlight) 다중 선택 | 대화형 신규 설치는 아무것도 선택하지 않은 상태, 비대화형·플래그 미지정은 현행 동작(둘 다 설치). 저장값이 없는 기존 설치는 이미 설치된 스토어 워크플로우에서 초기 선택을 추론 | `--flutter-store android,ios,none` |
|
|
88
|
+
| 배포 모드 | 고른 플랫폼별 `store_only` / `store_prepare` / `store_submit` | `store_only` | `--android-deploy-mode`, `--ios-deploy-mode` |
|
|
89
|
+
|
|
90
|
+
**설치되는 구성**
|
|
91
|
+
|
|
92
|
+
- 항상 설치: `CI`, `ANDROID-FIREBASE-CICD`, `ANDROID-SELFHOSTED-CICD`, `ANDROID-TEST-APK`, `APP-BUILD-TRIGGER`
|
|
93
|
+
- Android를 고르면: `ANDROID-PLAYSTORE-CICD` + `android/fastlane/Fastfile.playstore`
|
|
94
|
+
- iOS를 고르면: `IOS-TESTFLIGHT` + `IOS-TEST-TESTFLIGHT` + `ios/fastlane/Fastfile` + `ios/ExportOptions.plist`
|
|
95
|
+
- fastlane은 위 스토어 배포 워크플로우에서만 씁니다. `SELFHOSTED`와 `TEST-APK`는 `flutter build apk --release`를 직접 실행하며 Ruby·fastlane을 설치하지 않습니다.
|
|
96
|
+
- `Fastfile`과 `ExportOptions.plist`는 **Flutter 루트 기준**으로(모노레포는 `--paths flutter=app`이면 `app/` 아래) **없을 때만 생성**합니다. 이미 있으면 덮어쓰지 않고 설치 요약과 `--dry-run`에 "기존 파일 유지"로 표시하며, `--mode uninstall`도 이 파일들은 건드리지 않습니다(사용자 소유 파일).
|
|
97
|
+
- 스토어 대상을 해제하고 다시 실행하면 배포 방식을 바꿀 때와 같은 규칙으로 정리합니다 — 손대지 않은 워크플로우는 삭제하고, 수정한 것은 `.bak`으로 옮겨 보존합니다. `Fastfile`·`ExportOptions.plist`는 삭제하지 않습니다.
|
|
98
|
+
|
|
99
|
+
**환경변수 방식**
|
|
100
|
+
|
|
101
|
+
두 방식 모두 시크릿 `ENV_FILE`(없으면 `ENV`)에 `.env` 형식으로 값을 넣어 두면 됩니다. 두 방식을 동시에 쓰는 모드는 없습니다.
|
|
102
|
+
|
|
103
|
+
- `dart-define`: `ENV_FILE`을 프로젝트 밖 임시 경로(러너 임시 폴더)에 쓰고 모든 `flutter build`에 `--dart-define-from-file`로 넘깁니다. 프로젝트 루트에는 `.env`를 만들지 않으며, 코드에서는 `String.fromEnvironment('KEY')`로 읽습니다. 값이 아닌 파일 경로를 넘기므로 `--verbose` 로그에도 값이 명령줄에 노출되지 않습니다.
|
|
104
|
+
- `dotenv`: Flutter 루트에 `.env`를 만든 뒤 빌드합니다(`build_runner`가 그 뒤에 실행되는 순서 유지). `flutter_dotenv`·`envied`를 쓰는 프로젝트가 여기에 해당합니다. 이 `.env`에는 아래 파서 제약이 적용되지 않습니다.
|
|
105
|
+
|
|
106
|
+
`dart-define` 방식에서 `ENV_FILE`은 Flutter의 `--dart-define-from-file` 파서가 읽으므로 다음 범위만 지원됩니다 (근거: Flutter 3.47.5 `flutter_tools/lib/src/runner/flutter_command.dart`의 `DotEnvRegex`).
|
|
107
|
+
|
|
108
|
+
- 내용이 `{`로 시작하면 JSON 파일로 해석하고, 그렇지 않으면 `KEY=값` 줄로 해석합니다. 키는 `[a-zA-Z_][a-zA-Z0-9_]*` 형태여야 합니다.
|
|
109
|
+
- `#`로 시작하는 주석 줄과 빈 줄은 무시합니다.
|
|
110
|
+
- 값은 `"…"`, `'…'`, `` `…` `` 따옴표가 벗겨지고 그 뒤의 `# 주석`은 제거됩니다. 따옴표 없는 값은 공백 또는 `#` 앞까지 읽으며, 값 안의 `=`는 허용됩니다.
|
|
111
|
+
- `export KEY=값` 형태와 멀티라인(`"""`) 값은 지원하지 않아 빌드가 오류로 종료됩니다.
|
|
112
|
+
|
|
113
|
+
**배포 모드** — 플랫폼별로 아래처럼 동작합니다(모르는 값은 `store_only`로 취급). 기본값은 워크플로우 표현식의 폴백 자리에 반영되며, 저장소 변수 `ANDROID_DEPLOY_MODE`·`IOS_DEPLOY_MODE`와 `workflow_dispatch` 입력이 항상 우선합니다.
|
|
114
|
+
|
|
115
|
+
| 모드 | Play Store (Android) | TestFlight / App Store (iOS) |
|
|
116
|
+
|---|---|---|
|
|
117
|
+
| `store_only` | internal 트랙에 업로드 | TestFlight 업로드 |
|
|
118
|
+
| `store_prepare` | production 트랙에 draft 상태로 업로드 (Play Console에서 직접 출시) | 앱 버전·메타데이터 준비까지 (심사 제출 안 함) |
|
|
119
|
+
| `store_submit` | production 트랙에 심사 제출 | 심사 제출까지 |
|
|
120
|
+
|
|
121
|
+
> `store_submit`을 고르면 **main push마다 심사가 자동 제출**됩니다.
|
|
122
|
+
|
|
123
|
+
**필요한 Secrets · Variables** — 설치 완료 화면과 실행 로그에도 설치된 워크플로우가 실제로 요구하는 Secret 목록이 출력됩니다.
|
|
124
|
+
|
|
125
|
+
| 대상 | Secrets | Variables |
|
|
126
|
+
|---|---|---|
|
|
127
|
+
| 모든 Flutter 빌드 | `ENV_FILE` (없으면 `ENV`) | — |
|
|
128
|
+
| Android 서명 (`PLAYSTORE`·`FIREBASE`·`TEST-APK`) | `RELEASE_KEYSTORE_BASE64`, `RELEASE_KEYSTORE_PASSWORD`, `RELEASE_KEY_ALIAS`, `RELEASE_KEY_PASSWORD`, `GOOGLE_SERVICES_JSON` | — |
|
|
129
|
+
| Play Store (`PLAYSTORE`) | `GOOGLE_PLAY_SERVICE_ACCOUNT_JSON_BASE64`, `ANDROID_PACKAGE_NAME` | `ANDROID_PACKAGE_NAME`(Secret이 없을 때 대신 사용), `ANDROID_DEPLOY_MODE`(선택) |
|
|
130
|
+
| iOS (`IOS-TESTFLIGHT`·`IOS-TEST-TESTFLIGHT`) | `APP_STORE_CONNECT_API_KEY_BASE64`, `APP_STORE_CONNECT_API_KEY_ID`, `APP_STORE_CONNECT_ISSUER_ID`, `APPLE_CERTIFICATE_BASE64`, `APPLE_CERTIFICATE_PASSWORD`, `APPLE_PROVISIONING_PROFILE_BASE64`, `IOS_PROVISIONING_PROFILE_NAME`, `IOS_BUNDLE_ID`, `SECRETS_XCCONFIG`(선택) | `IOS_BUNDLE_ID`(Secret이 없을 때 대신 사용), `IOS_DEPLOY_MODE`(선택) |
|
|
131
|
+
| Firebase 배포 (`FIREBASE`·`TEST-APK`) | `FIREBASE_SERVICE_ACCOUNT_JSON_BASE64` | — |
|
|
132
|
+
| Selfhosted 배포 (`SELFHOSTED`) | `SERVER_HOST`, `SERVER_USER`, `SERVER_PASSWORD`, `DEBUG_KEYSTORE` | — |
|
|
133
|
+
|
|
134
|
+
`ANDROID_PACKAGE_NAME`은 `PLAYSTORE` 워크플로우가 fastlane에 패키지명으로 넘깁니다(`secrets` 우선, 없으면 `vars`). iOS의 `IOS_BUNDLE_ID`와 같은 플랫폼 접두사 규칙입니다.
|
|
135
|
+
|
|
136
|
+
**`ExportOptions.plist`에 채워야 할 값** — 마법사가 만든 `ios/ExportOptions.plist`에는 아래 플레이스홀더가 들어 있어 실제 값으로 바꿔야 합니다. 채우지 않고 `IOS-TESTFLIGHT`를 실행하면 `xcodebuild`의 알기 어려운 오류 대신 플레이스홀더가 남았다는 메시지로 검증 단계에서 중단되며, `--mode doctor`도 같은 항목을 WARN으로 알려줍니다.
|
|
137
|
+
|
|
138
|
+
| 플레이스홀더 | 채울 값 |
|
|
139
|
+
|---|---|
|
|
140
|
+
| `__TEAM_ID__` | Apple Developer Team ID |
|
|
141
|
+
| `__BUNDLE_ID__` | 앱 번들 ID (`IOS_BUNDLE_ID`와 같은 값) |
|
|
142
|
+
| `__PROVISIONING_PROFILE_NAME__` | 프로비저닝 프로파일 이름 (`IOS_PROVISIONING_PROFILE_NAME`과 같은 값) |
|
|
143
|
+
|
|
144
|
+
**모노레포와 `ci-gate`**
|
|
145
|
+
|
|
146
|
+
- `--paths flutter=app`처럼 Flutter 하위 폴더를 지정하면 모든 Flutter 워크플로우가 그 폴더(`FLUTTER_PROJECT_DIR`)를 기준으로 동작하고, main push로 도는 배포 워크플로우(`PLAYSTORE`·`IOS-TESTFLIGHT`·`SELFHOSTED`·`FIREBASE`)는 `app/**`가 바뀔 때만 실행됩니다(Spring 등 다른 타입과 같은 `paths` 필터).
|
|
147
|
+
- CI 워크플로우(Flutter·Go·Next·Python·React·Spring NEXUS-CI)는 `push`·`pull_request`에서 항상 실행되고, 첫 job `changes`가 변경 파일을 판별해 나머지 job을 건너뜁니다(건너뛴 job은 Success). 마지막 job `ci-gate`는 항상 실행되어 필수 job이 모두 success 또는 skipped이면 통과하고 failure·cancelled가 하나라도 있으면 실패합니다.
|
|
148
|
+
- 브랜치 보호 규칙의 required status check에는 개별 job이 아니라 **`CI Gate`(`ci-gate`) 하나만** 등록하세요. 경로 필터로 워크플로우 자체를 건너뛰면 required check가 Pending에 머물러 머지가 막히지만, job을 건너뛰는 방식은 그렇지 않기 때문입니다.
|
|
149
|
+
- 워크플로우 `paths` 필터는 태그 push에 적용되지 않습니다(GitHub 문서).
|
|
150
|
+
|
|
151
|
+
**Gemfile** — 스토어 배포 워크플로우(`PLAYSTORE`·`IOS-TESTFLIGHT`·`IOS-TEST-TESTFLIGHT`)는 사용자 `Gemfile`에 `fastlane`이 있으면 그것을 쓰고, 없으면 실행할 때 생성합니다. 마법사는 Gemfile 템플릿을 배포하지 않습니다. fastlane 공식 문서가 권장하는 대로 `Gemfile`(`gem "fastlane"`)과 `Gemfile.lock`을 저장소에 커밋해 두면 버전이 고정되어 재현성이 좋아집니다.
|
|
152
|
+
|
|
78
153
|
### 실행 로그 (`.github/.wizard/logs/`)
|
|
79
154
|
|
|
80
155
|
설치·업데이트·삭제를 실행할 때마다 `.github/.wizard/logs/<시각>-<동작>.log`에 실행 추적이 남습니다. 감지 근거, **파일별 처리 결정과 그 사유**, 치환된 값, 미치환 항목, 등록해야 하는 GitHub Secret이 시간순으로 기록되고, 파일 끝에 결과 요약이 붙습니다.
|
|
@@ -154,6 +229,10 @@ npx project-auto-wizard [옵션]
|
|
|
154
229
|
--main-branch B 릴리스 브랜치 (기본: 감지된 default branch)
|
|
155
230
|
--develop-branch B 개발 브랜치 (기본: develop)
|
|
156
231
|
--deploy-style S 서버 배포 방식: simple | nginx | traefik | none (기본: simple)
|
|
232
|
+
--flutter-env-mode M Flutter 환경변수 방식: dart-define | dotenv (신규 기본: dart-define, 저장값 없는 기존 설치는 dotenv 유지)
|
|
233
|
+
--flutter-store CSV Flutter 스토어 배포 대상: android,ios,none (미지정 시 둘 다 설치)
|
|
234
|
+
--android-deploy-mode M Play Store 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
|
|
235
|
+
--ios-deploy-mode M iOS 배포 모드: store_only | store_prepare | store_submit (기본: store_only)
|
|
157
236
|
--nexus 라이브러리 publish 워크플로우 포함 (Nexus + GitHub Packages)
|
|
158
237
|
--secret-backup Secret 서버 백업 워크플로우 포함
|
|
159
238
|
--semver-auto 커밋 타입 기반 자동 major/minor/patch 승격 (기본: 사용함, --no-semver-auto로 끔)
|
|
@@ -173,8 +252,8 @@ npx project-auto-wizard --mode doctor # 환경 진단 (읽기 전용, 규칙
|
|
|
173
252
|
|
|
174
253
|
| 명령 | 내용 |
|
|
175
254
|
|---|---|
|
|
176
|
-
| `--mode status` | 설치된 버전·타입·브랜치
|
|
177
|
-
| `--mode doctor` | `version.yml` 설치 여부, `gh` CLI 설치/인증 상태, GitHub Actions workflow permissions, `WORKFLOW_PAT` secret 등록 여부, merge commit 허용 설정을 점검합니다. `gh api` 호출을 사용하므로 네트워크 접근이 발생합니다(규칙 기반 점검 — AI 진단 아님) |
|
|
255
|
+
| `--mode status` | 설치된 버전·타입·브랜치 모드·옵션값(Flutter 프로젝트면 환경변수 방식·스토어 배포 대상·배포 모드 포함)과, 설치 시점 대비 사용자가 직접 수정한 워크플로우 파일 목록을 보여줍니다. 네트워크 접근 없음(로컬 파일 비교만) |
|
|
256
|
+
| `--mode doctor` | `version.yml` 설치 여부, `gh` CLI 설치/인증 상태, GitHub Actions workflow permissions, `WORKFLOW_PAT` secret 등록 여부, merge commit 허용 설정을 점검합니다. Flutter 프로젝트에서는 고른 스토어 플랫폼의 필수 파일(`Fastfile`, `ExportOptions.plist` 등)과 `ExportOptions.plist`의 플레이스홀더 잔존 여부도 점검합니다(로컬 파일만 확인, 스토어 시크릿 등록 여부는 점검하지 않음). `gh api` 호출을 사용하므로 네트워크 접근이 발생합니다(규칙 기반 점검 — AI 진단 아님) |
|
|
178
257
|
|
|
179
258
|
`doctor`는 항목마다 **그 설정이 무엇을 담당하는지**를 라벨에 함께 표시하고, 문제가 있는 항목만 `현상 → 그대로 두면 무엇이 안 되는지 → 어디를 눌러 고치는지 → 문서 링크` 순으로 펼쳐 보여줍니다. 정상 항목은 한 줄로 압축됩니다. GitHub 설정 화면에 실제로 표시되는 문자열(`Read and write permissions` 등)은 화면에서 찾을 수 있도록 원문 그대로 출력합니다.
|
|
180
259
|
|
package/package.json
CHANGED
|
@@ -1 +1,24 @@
|
|
|
1
|
-
{
|
|
1
|
+
{
|
|
2
|
+
"0.10.1": [
|
|
3
|
+
{
|
|
4
|
+
"severity": "warning",
|
|
5
|
+
"title": "Flutter SELFHOSTED·TEST-APK가 flutter build를 직접 실행",
|
|
6
|
+
"message": "SELFHOSTED·TEST-APK가 fastlane build 대신 flutter build apk --release를 직접 실행하고 Ruby·fastlane 설치 스텝이 사라집니다. fastlane은 스토어 배포 3종(PLAYSTORE·IOS-TESTFLIGHT·IOS-TEST-TESTFLIGHT)에서만 사용합니다."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"severity": "warning",
|
|
10
|
+
"title": "Flutter 환경변수 기본 방식이 dart-define으로 변경",
|
|
11
|
+
"message": "신규 설치의 기본값이 dart-define(--dart-define-from-file)으로 바뀝니다. 기존 설치는 version.yml에 저장값이 없으면 dotenv(.env 생성)를 유지하며, 바꾸려면 마법사 '수정하기 > 환경변수 방식' 또는 --flutter-env-mode를 쓰세요."
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"severity": "warning",
|
|
15
|
+
"title": "Flutter 워크플로우가 FLUTTER_PROJECT_DIR 기준으로 동작",
|
|
16
|
+
"message": "FIREBASE·SELFHOSTED·CI·TEST-APK·IOS-TEST-TESTFLIGHT도 PLAYSTORE처럼 Flutter 루트(FLUTTER_PROJECT_DIR)에서 동작합니다. Flutter가 하위 폴더에 있는 모노레포는 --paths flutter=<경로>로 지정하세요."
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"severity": "warning",
|
|
20
|
+
"title": "모노레포 CI required check는 ci-gate 하나만 등록",
|
|
21
|
+
"message": "CI 워크플로우(Flutter·Go·Next·Python·React·Spring NEXUS-CI)는 항상 실행되고 변경이 없으면 job을 건너뜁니다. required check로 쓰려면 개별 job이 아닌 CI Gate(ci-gate) 하나만 등록하세요."
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# ===================================================================
|
|
2
|
+
# 이 파일은 사용자 소유입니다. 모드별 동작을 여기서 수정하세요.
|
|
3
|
+
# ===================================================================
|
|
4
|
+
#
|
|
5
|
+
# Google Play 배포용 Fastfile 템플릿입니다.
|
|
6
|
+
# PROJECT-FLUTTER-ANDROID-PLAYSTORE-CICD 워크플로우가 이 파일을 android/fastlane/Fastfile로
|
|
7
|
+
# 복사한 뒤 `bundle exec fastlane deploy_internal`을 실행합니다.
|
|
8
|
+
# project-auto-wizard는 이 파일이 이미 있으면 덮어쓰지 않으므로 자유롭게 수정해도 됩니다.
|
|
9
|
+
#
|
|
10
|
+
# 배포 모드 (워크플로우가 DEPLOY_MODE 환경변수로 전달)
|
|
11
|
+
# ┌───────────────┬────────────┬──────────────────┬──────────────────────────────┐
|
|
12
|
+
# │ DEPLOY_MODE │ track │ release_status │ 동작 │
|
|
13
|
+
# ├───────────────┼────────────┼──────────────────┼──────────────────────────────┤
|
|
14
|
+
# │ store_only │ internal │ completed │ 내부 테스트 트랙에 업로드 │
|
|
15
|
+
# │ store_prepare │ production │ draft │ 프로덕션에 초안으로 업로드 │
|
|
16
|
+
# │ │ │ │ (Play Console에서 직접 출시) │
|
|
17
|
+
# │ store_submit │ production │ completed │ 프로덕션 심사 제출까지 진행 │
|
|
18
|
+
# └───────────────┴────────────┴──────────────────┴──────────────────────────────┘
|
|
19
|
+
# 알 수 없는 값이나 빈 값은 store_only로 처리합니다.
|
|
20
|
+
#
|
|
21
|
+
# 워크플로우가 넘기는 환경변수
|
|
22
|
+
# PACKAGE_NAME 앱 패키지명 (ANDROID_PACKAGE_NAME secrets/variables)
|
|
23
|
+
# AAB_PATH 업로드할 .aab 절대경로
|
|
24
|
+
# GOOGLE_PLAY_JSON_KEY 서비스 계정 JSON 키 파일 경로
|
|
25
|
+
# VERSION_NAME 버전 이름 (Play Console의 릴리스 이름)
|
|
26
|
+
# VERSION_CODE 버전 코드 (변경 이력 파일명과 일치)
|
|
27
|
+
# DEPLOY_MODE 위 표의 배포 모드
|
|
28
|
+
#
|
|
29
|
+
# 변경 이력은 워크플로우가 android/fastlane/metadata/android/ko-KR/changelogs/<VERSION_CODE>.txt
|
|
30
|
+
# 로 만들어 두며, upload_to_play_store가 metadata_path 아래에서 버전 코드로 찾아 업로드합니다.
|
|
31
|
+
|
|
32
|
+
default_platform(:android)
|
|
33
|
+
|
|
34
|
+
platform :android do
|
|
35
|
+
desc "AAB를 Google Play에 업로드합니다 (DEPLOY_MODE: store_only | store_prepare | store_submit)"
|
|
36
|
+
lane :deploy_internal do
|
|
37
|
+
package_name = ENV["PACKAGE_NAME"].to_s.strip
|
|
38
|
+
if package_name.empty?
|
|
39
|
+
UI.user_error!("PACKAGE_NAME이 비어 있습니다. ANDROID_PACKAGE_NAME secrets/variables를 등록하세요. (예: com.example.app)")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
aab_path = ENV["AAB_PATH"].to_s.strip
|
|
43
|
+
json_key = ENV["GOOGLE_PLAY_JSON_KEY"].to_s.strip
|
|
44
|
+
version_name = ENV["VERSION_NAME"].to_s.strip
|
|
45
|
+
version_code = ENV["VERSION_CODE"].to_s.strip
|
|
46
|
+
if aab_path.empty? || json_key.empty? || version_name.empty? || version_code.empty?
|
|
47
|
+
UI.user_error!("AAB_PATH, GOOGLE_PLAY_JSON_KEY, VERSION_NAME, VERSION_CODE 환경변수가 모두 필요합니다. 워크플로우에서 전달하는지 확인하세요.")
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
deploy_mode = ENV["DEPLOY_MODE"].to_s.strip
|
|
51
|
+
track, release_status =
|
|
52
|
+
case deploy_mode
|
|
53
|
+
when "store_prepare"
|
|
54
|
+
["production", "draft"]
|
|
55
|
+
when "store_submit"
|
|
56
|
+
["production", "completed"]
|
|
57
|
+
when "store_only"
|
|
58
|
+
["internal", "completed"]
|
|
59
|
+
else
|
|
60
|
+
UI.important("알 수 없는 DEPLOY_MODE '#{deploy_mode}' 입니다. store_only로 처리합니다.") unless deploy_mode.empty?
|
|
61
|
+
["internal", "completed"]
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# lane은 Fastfile이 있는 android/fastlane 디렉토리에서 실행되므로,
|
|
65
|
+
# 워크플로우가 변경 이력을 만드는 android/fastlane/metadata/android와 같은 경로를 가리킵니다.
|
|
66
|
+
metadata_path = File.expand_path("metadata/android")
|
|
67
|
+
changelog_file = File.join(metadata_path, "ko-KR", "changelogs", "#{version_code}.txt")
|
|
68
|
+
UI.important("변경 이력 파일이 없습니다: #{changelog_file}") unless File.exist?(changelog_file)
|
|
69
|
+
|
|
70
|
+
UI.message("Play 배포: DEPLOY_MODE=#{deploy_mode.inspect} → track=#{track}, release_status=#{release_status}")
|
|
71
|
+
|
|
72
|
+
upload_to_play_store(
|
|
73
|
+
package_name: package_name,
|
|
74
|
+
json_key: json_key,
|
|
75
|
+
aab: aab_path,
|
|
76
|
+
track: track,
|
|
77
|
+
release_status: release_status,
|
|
78
|
+
version_name: version_name,
|
|
79
|
+
metadata_path: metadata_path,
|
|
80
|
+
skip_upload_apk: true,
|
|
81
|
+
skip_upload_metadata: true,
|
|
82
|
+
skip_upload_images: true,
|
|
83
|
+
skip_upload_screenshots: true
|
|
84
|
+
)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<!--
|
|
4
|
+
이 파일은 사용자 소유입니다. 밑줄 두 개로 감싼 자리표시자 3곳을 실제 값으로 바꾼 뒤 커밋하세요.
|
|
5
|
+
|
|
6
|
+
PROJECT-FLUTTER-IOS-TESTFLIGHT / PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT 워크플로우가
|
|
7
|
+
xcodebuild -exportArchive -exportOptionsPlist ExportOptions.plist 로 IPA를 만들 때 사용합니다.
|
|
8
|
+
자리표시자가 남아 있으면 워크플로우가 중단됩니다.
|
|
9
|
+
(이 주석에는 자리표시자를 적지 않았습니다. 값을 채운 뒤에도 남아 있는지 검사하기 때문입니다.)
|
|
10
|
+
|
|
11
|
+
teamID Apple Developer Team ID (10자리, developer.apple.com 계정의 Membership)
|
|
12
|
+
provisioningProfiles 키는 앱 번들 ID (예: com.example.app),
|
|
13
|
+
값은 프로비저닝 프로파일 이름 (GitHub Secret IOS_PROVISIONING_PROFILE_NAME 값과 같게)
|
|
14
|
+
-->
|
|
15
|
+
<plist version="1.0">
|
|
16
|
+
<dict>
|
|
17
|
+
<key>method</key>
|
|
18
|
+
<string>app-store-connect</string>
|
|
19
|
+
<key>teamID</key>
|
|
20
|
+
<string>__TEAM_ID__</string>
|
|
21
|
+
<key>signingStyle</key>
|
|
22
|
+
<string>manual</string>
|
|
23
|
+
<key>signingCertificate</key>
|
|
24
|
+
<string>Apple Distribution</string>
|
|
25
|
+
<key>provisioningProfiles</key>
|
|
26
|
+
<dict>
|
|
27
|
+
<key>__BUNDLE_ID__</key>
|
|
28
|
+
<string>__PROVISIONING_PROFILE_NAME__</string>
|
|
29
|
+
</dict>
|
|
30
|
+
</dict>
|
|
31
|
+
</plist>
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# ===================================================================
|
|
2
|
+
# 이 파일은 사용자 소유입니다. 모드별 동작을 여기서 수정하세요.
|
|
3
|
+
# ===================================================================
|
|
4
|
+
#
|
|
5
|
+
# iOS 배포용 Fastfile 템플릿입니다. Flutter 워크플로우가 IPA를 만든 뒤
|
|
6
|
+
# `cd ios && bundle exec fastlane <lane>`으로 실행합니다.
|
|
7
|
+
# project-auto-wizard는 이 파일이 이미 있으면 덮어쓰지 않으므로 자유롭게 수정해도 됩니다.
|
|
8
|
+
#
|
|
9
|
+
# lane
|
|
10
|
+
# deploy PROJECT-FLUTTER-IOS-TESTFLIGHT 워크플로우 (DEPLOY_MODE에 따라 분기)
|
|
11
|
+
# upload_testflight PROJECT-FLUTTER-IOS-TEST-TESTFLIGHT 워크플로우 (IPA를 TestFlight에 올리기만 함)
|
|
12
|
+
#
|
|
13
|
+
# deploy lane의 배포 모드 (워크플로우가 DEPLOY_MODE 환경변수로 전달)
|
|
14
|
+
# ┌───────────────┬──────────────────────────────────────────────────────────────┐
|
|
15
|
+
# │ DEPLOY_MODE │ 동작 │
|
|
16
|
+
# ├───────────────┼──────────────────────────────────────────────────────────────┤
|
|
17
|
+
# │ store_only │ TestFlight 업로드까지 (upload_to_testflight) │
|
|
18
|
+
# │ store_prepare │ TestFlight 업로드 후, App Store 버전과 메타데이터를 준비 │
|
|
19
|
+
# │ │ (upload_to_app_store, submit_for_review: false). 빌드는 이 │
|
|
20
|
+
# │ │ 단계에서 버전에 연결되지 않고, store_submit이 build_number │
|
|
21
|
+
# │ │ 로 다시 호출될 때 한번에 연결·제출됩니다. │
|
|
22
|
+
# │ store_submit │ store_prepare와 같은 호출이고 심사 제출까지 진행 │
|
|
23
|
+
# │ │ (submit_for_review: true, 이때 빌드가 버전에 연결됩니다) │
|
|
24
|
+
# └───────────────┴──────────────────────────────────────────────────────────────┘
|
|
25
|
+
# 알 수 없는 값이나 빈 값은 store_only로 처리합니다.
|
|
26
|
+
#
|
|
27
|
+
# 워크플로우가 넘기는 환경변수
|
|
28
|
+
# APP_STORE_CONNECT_API_KEY_ID App Store Connect API Key ID
|
|
29
|
+
# APP_STORE_CONNECT_ISSUER_ID App Store Connect Issuer ID
|
|
30
|
+
# API_KEY_PATH AuthKey_XXXX.p8 파일 경로
|
|
31
|
+
# IPA_PATH 업로드할 .ipa 절대경로
|
|
32
|
+
# RELEASE_NOTES TestFlight "What to Test" 문구 (changelog)
|
|
33
|
+
# APP_IDENTIFIER 번들 ID (upload_testflight lane은 없으면 fastlane이 추론하지만,
|
|
34
|
+
# deploy lane의 store_prepare/store_submit은 필수입니다)
|
|
35
|
+
# DEPLOY_MODE 위 표의 배포 모드 (deploy lane만)
|
|
36
|
+
# APP_VERSION, BUILD_NUMBER 앱 버전, 빌드 번호 (deploy lane만)
|
|
37
|
+
# SKIP_WAITING_FOR_BUILD_PROCESSING "true"면 빌드 처리 완료를 기다리지 않음 (store_only만 적용)
|
|
38
|
+
#
|
|
39
|
+
# 참고
|
|
40
|
+
# - store_prepare/store_submit은 App Store 버전에 빌드를 연결해야 하므로 빌드 처리가 끝날 때까지
|
|
41
|
+
# 기다립니다 (SKIP_WAITING_FOR_BUILD_PROCESSING을 무시).
|
|
42
|
+
# - 스크린샷은 올리지 않습니다. 메타데이터는 ios/fastlane/metadata/ 아래에 파일이 있을 때만 올립니다.
|
|
43
|
+
# 심사 제출 시 "What's New" 등 필수 항목은 이 폴더나 App Store Connect에서 미리 채워 두세요.
|
|
44
|
+
# - store_submit에서 수출 규정 오류가 나면 Info.plist에 ITSAppUsesNonExemptEncryption을 지정하거나
|
|
45
|
+
# upload_to_app_store에 submission_information을 추가하세요.
|
|
46
|
+
# - store_submit은 심사 승인 후 자동 출시하지 않습니다 (automatic_release: false).
|
|
47
|
+
|
|
48
|
+
default_platform(:ios)
|
|
49
|
+
|
|
50
|
+
def require_env(name)
|
|
51
|
+
value = ENV[name].to_s.strip
|
|
52
|
+
UI.user_error!("#{name} 환경변수가 비어 있습니다. 워크플로우에서 값을 전달하는지 확인하세요.") if value.empty?
|
|
53
|
+
value
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def load_api_key
|
|
57
|
+
app_store_connect_api_key(
|
|
58
|
+
key_id: require_env("APP_STORE_CONNECT_API_KEY_ID"),
|
|
59
|
+
issuer_id: require_env("APP_STORE_CONNECT_ISSUER_ID"),
|
|
60
|
+
key_filepath: require_env("API_KEY_PATH")
|
|
61
|
+
)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# APP_IDENTIFIER가 있을 때만 옵션에 포함해, 없으면 fastlane 기본 추론에 맡깁니다.
|
|
65
|
+
def app_identifier_option
|
|
66
|
+
app_identifier = ENV["APP_IDENTIFIER"].to_s.strip
|
|
67
|
+
app_identifier.empty? ? {} : { app_identifier: app_identifier }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def upload_ipa_to_testflight(api_key, skip_waiting_for_build_processing)
|
|
71
|
+
options = {
|
|
72
|
+
api_key: api_key,
|
|
73
|
+
ipa: require_env("IPA_PATH"),
|
|
74
|
+
skip_waiting_for_build_processing: skip_waiting_for_build_processing
|
|
75
|
+
}
|
|
76
|
+
release_notes = ENV["RELEASE_NOTES"].to_s.strip
|
|
77
|
+
options[:changelog] = release_notes unless release_notes.empty?
|
|
78
|
+
upload_to_testflight(**options, **app_identifier_option)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
platform :ios do
|
|
82
|
+
desc "IPA를 TestFlight에 업로드합니다 (테스트 빌드용)"
|
|
83
|
+
lane :upload_testflight do
|
|
84
|
+
upload_ipa_to_testflight(load_api_key, false)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
desc "IPA를 업로드하고 DEPLOY_MODE에 따라 TestFlight / 심사 준비 / 심사 제출까지 진행합니다"
|
|
88
|
+
lane :deploy do
|
|
89
|
+
api_key = load_api_key
|
|
90
|
+
deploy_mode = ENV["DEPLOY_MODE"].to_s.strip
|
|
91
|
+
|
|
92
|
+
case deploy_mode
|
|
93
|
+
when "store_prepare", "store_submit"
|
|
94
|
+
UI.message("DEPLOY_MODE=#{deploy_mode}: 빌드 처리 완료까지 기다린 뒤 App Store 버전을 준비합니다.")
|
|
95
|
+
upload_ipa_to_testflight(api_key, false)
|
|
96
|
+
|
|
97
|
+
upload_to_app_store(
|
|
98
|
+
api_key: api_key,
|
|
99
|
+
app_identifier: require_env("APP_IDENTIFIER"),
|
|
100
|
+
app_version: require_env("APP_VERSION"),
|
|
101
|
+
build_number: require_env("BUILD_NUMBER"),
|
|
102
|
+
skip_binary_upload: true,
|
|
103
|
+
skip_screenshots: true,
|
|
104
|
+
skip_metadata: Dir.glob("metadata/*").empty?,
|
|
105
|
+
submit_for_review: deploy_mode == "store_submit",
|
|
106
|
+
automatic_release: false,
|
|
107
|
+
force: true,
|
|
108
|
+
precheck_include_in_app_purchases: false
|
|
109
|
+
)
|
|
110
|
+
when "store_only"
|
|
111
|
+
upload_ipa_to_testflight(api_key, ENV["SKIP_WAITING_FOR_BUILD_PROCESSING"].to_s.strip.downcase == "true")
|
|
112
|
+
else
|
|
113
|
+
UI.important("알 수 없는 DEPLOY_MODE '#{deploy_mode}' 입니다. store_only로 처리합니다.") unless deploy_mode.empty?
|
|
114
|
+
upload_ipa_to_testflight(api_key, ENV["SKIP_WAITING_FOR_BUILD_PROCESSING"].to_s.strip.downcase == "true")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -277,7 +277,7 @@ def classify_commits(lines: list[str]) -> dict:
|
|
|
277
277
|
"""
|
|
278
278
|
커밋 제목 목록을 3단계 규칙으로 분류.
|
|
279
279
|
|
|
280
|
-
1단계:
|
|
280
|
+
1단계: 제목 컨벤션 — "제목 : type : 내용 [URL]"
|
|
281
281
|
2단계: Conventional Commits — "type(scope)!: 내용"
|
|
282
282
|
(perf/style/build/ci → chore 버킷으로 매핑)
|
|
283
283
|
3단계: 위 두 형식에 매칭되지 않으면 "changes" 버킷 (자유 형식)
|
|
@@ -298,7 +298,7 @@ def classify_commits(lines: list[str]) -> dict:
|
|
|
298
298
|
# 1단계가 2단계보다 먼저다 — 트레이드오프: "제목 : feat : 내용" 형식은
|
|
299
299
|
# "feat: ..." Conventional Commits와 겹칠 수 없지만(타입 앞에 제목 필수),
|
|
300
300
|
# 제목이 있는 줄에 " : type : "가 우연히 들어가면 tier-2 해석 기회 없이
|
|
301
|
-
# tier-1로 확정된다.
|
|
301
|
+
# tier-1로 확정된다. 이 컨벤션을 쓰는 레포에서는 이것이 의도된 우선순위다.
|
|
302
302
|
tier1 = _TIER1_RE.match(line)
|
|
303
303
|
if tier1:
|
|
304
304
|
title = tier1.group(1).strip()
|
|
@@ -5,8 +5,8 @@ version_manager.py — general-purpose version management script (stdlib only).
|
|
|
5
5
|
This script is copied into user repos (.github/scripts/) by project-auto-wizard
|
|
6
6
|
and runs standalone on GitHub Actions ubuntu runners (python3, no third-party deps).
|
|
7
7
|
|
|
8
|
-
It is a Python rewrite of the battle-tested bash
|
|
9
|
-
|
|
8
|
+
It is a Python rewrite of the battle-tested bash reference implementation
|
|
9
|
+
(version_manager.sh). Behavioral equivalence with that script is the design goal:
|
|
10
10
|
- version.yml is the single source of truth for `version` and `version_code`.
|
|
11
11
|
- version.yml is edited via line-based regex replacements that preserve all
|
|
12
12
|
comments and formatting (never rewritten wholesale, never parsed with a YAML lib).
|
|
@@ -135,17 +135,17 @@ jobs:
|
|
|
135
135
|
# ============================================
|
|
136
136
|
|
|
137
137
|
# --- ENV_FILE → .env ---
|
|
138
|
-
cat << '
|
|
138
|
+
cat << '__WIZARD_SECRET_CHECK_EOF__' > /tmp/_secret_check
|
|
139
139
|
${{ secrets.ENV_FILE }}
|
|
140
|
-
|
|
140
|
+
__WIZARD_SECRET_CHECK_EOF__
|
|
141
141
|
if [ -s /tmp/_secret_check ] && [ -n "$(tr -d '[:space:]' < /tmp/_secret_check)" ]; then
|
|
142
142
|
echo "ENV_FILE → .env 업로드 중..."
|
|
143
|
-
cat << '
|
|
143
|
+
cat << '__WIZARD_FILE_CONTENT_EOF__' | sudo tee "${BASE_DIR}/.env" > /dev/null
|
|
144
144
|
${{ secrets.ENV_FILE }}
|
|
145
|
-
|
|
146
|
-
cat << '
|
|
145
|
+
__WIZARD_FILE_CONTENT_EOF__
|
|
146
|
+
cat << '__WIZARD_FILE_CONTENT_EOF__' | sudo tee "${BASE_DIR}/${TIMESTAMP}/.env" > /dev/null
|
|
147
147
|
${{ secrets.ENV_FILE }}
|
|
148
|
-
|
|
148
|
+
__WIZARD_FILE_CONTENT_EOF__
|
|
149
149
|
echo ".env 업로드 완료"
|
|
150
150
|
else
|
|
151
151
|
echo "ENV_FILE 스킵 (Secret 미설정)"
|
|
@@ -153,17 +153,17 @@ jobs:
|
|
|
153
153
|
rm -f /tmp/_secret_check
|
|
154
154
|
|
|
155
155
|
# --- APPLICATION_PROD_YML → application-prod.yml ---
|
|
156
|
-
cat << '
|
|
156
|
+
cat << '__WIZARD_SECRET_CHECK_EOF__' > /tmp/_secret_check
|
|
157
157
|
${{ secrets.APPLICATION_PROD_YML }}
|
|
158
|
-
|
|
158
|
+
__WIZARD_SECRET_CHECK_EOF__
|
|
159
159
|
if [ -s /tmp/_secret_check ] && [ -n "$(tr -d '[:space:]' < /tmp/_secret_check)" ]; then
|
|
160
160
|
echo "APPLICATION_PROD_YML → application-prod.yml 업로드 중..."
|
|
161
|
-
cat << '
|
|
161
|
+
cat << '__WIZARD_FILE_CONTENT_EOF__' | sudo tee "${BASE_DIR}/application-prod.yml" > /dev/null
|
|
162
162
|
${{ secrets.APPLICATION_PROD_YML }}
|
|
163
|
-
|
|
164
|
-
cat << '
|
|
163
|
+
__WIZARD_FILE_CONTENT_EOF__
|
|
164
|
+
cat << '__WIZARD_FILE_CONTENT_EOF__' | sudo tee "${BASE_DIR}/${TIMESTAMP}/application-prod.yml" > /dev/null
|
|
165
165
|
${{ secrets.APPLICATION_PROD_YML }}
|
|
166
|
-
|
|
166
|
+
__WIZARD_FILE_CONTENT_EOF__
|
|
167
167
|
echo "application-prod.yml 업로드 완료"
|
|
168
168
|
else
|
|
169
169
|
echo "APPLICATION_PROD_YML 스킵 (Secret 미설정)"
|