Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
6467f8b
♻️ :: (#343) test ci
leejh08 Dec 30, 2025
50dbede
♻️ :: (#343) xcode cloud log
leejh08 Dec 30, 2025
10d6b13
♻️ :: (#343) ci post clone 파일 제거
leejh08 Dec 30, 2025
62d00b1
♻️ :: (#343) CI, CD 추가
leejh08 Dec 30, 2025
26f1e0a
♻️ :: (#343) ci 수정
leejh08 Dec 30, 2025
65bc384
♻️ :: (#343) tuist ci error
leejh08 Dec 30, 2025
62cb540
♻️ :: (#343) ci mac os version error
leejh08 Dec 30, 2025
0d22b53
♻️ :: (#343) tuist install -> fetch
leejh08 Dec 30, 2025
907690b
♻️ :: (#343) fastlane 경로 수정
leejh08 Dec 30, 2025
f3e2118
♻️ :: (#343) fastfile 절대경로 설정
leejh08 Dec 30, 2025
7502b01
♻️ :: (#343) Simulator destination
leejh08 Dec 30, 2025
58afbf4
♻️ :: (#343) SDK 방식으로 빌드 수정
leejh08 Dec 30, 2025
22ab67d
♻️ :: (#343) iOS 시뮬 설치
leejh08 Dec 30, 2025
0a71a02
♻️ :: (#343) Ci 테스트 제거
leejh08 Dec 30, 2025
26ff490
♻️ :: (#343) 단계 최소화
leejh08 Dec 30, 2025
f5ee08c
♻️ :: (#343) Tuist build 사용
leejh08 Dec 30, 2025
d550ce9
♻️ :: (#343) tuist 프로젝트 경로 이동
leejh08 Dec 30, 2025
ab8b736
♻️ :: (#343) 프로비저닝 세팅
leejh08 Jan 1, 2026
cd308bd
♻️ :: Move fastlane to private submodule for security
leejh08 Jan 1, 2026
dce9ed4
🔧 :: Update fastlane submodule (remove unnecessary files)
leejh08 Jan 1, 2026
7275db6
🔧 :: Update fastlane submodule (remove report.xml)
leejh08 Jan 1, 2026
5fd6605
🔧 :: Setup GitHub Actions workflows for CI/CD
leejh08 Jan 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
94 changes: 94 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
name: CI/CD Pipeline

on:
push:
branches: [ develop ]
pull_request:
branches: [ develop ]

jobs:
build-and-test:
runs-on: macos-15

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup XCConfig Files
run: |
echo "${{ secrets.XCCONFIG_BASE64 }}" | base64 --decode | tar -xz

- name: Setup Firebase Config Files
run: |
mkdir -p Projects/App/Resources/Firebase
echo "${{ secrets.GOOGLE_SERVICE_DEV_INFO }}" > Projects/App/Resources/Firebase/GoogleService-Dev-Info.plist
echo "${{ secrets.GOOGLE_SERVICE_STAGE_INFO }}" > Projects/App/Resources/Firebase/GoogleService-Stage-Info.plist
echo "${{ secrets.GOOGLE_SERVICE_PROD_INFO }}" > Projects/App/Resources/Firebase/GoogleService-Prod-Info.plist

- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '16.2'

- name: Install iOS Simulator
run: |
sudo xcrun simctl list runtimes
xcodebuild -downloadPlatform iOS || true

- name: Cache SPM
uses: actions/cache@v4
with:
path: |
.build
~/Library/Developer/Xcode/DerivedData/**/SourcePackages
key: ${{ runner.os }}-spm-${{ hashFiles('**/Package.resolved') }}
restore-keys: |
${{ runner.os }}-spm-

- name: Install mise
uses: jdx/mise-action@v2
with:
install: true

- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: '3.2'
bundler-cache: true

- name: Install dependencies
run: |
bundle install

- name: Generate Xcode project with Tuist
run: |
mise exec -- tuist fetch
mise exec -- tuist generate
env:
TUIST_CI: "1"

- name: Verify workspace exists
run: |
ls -la *.xcworkspace
echo "Workspace found!"

- name: Run Fastlane CI
run: |
bundle exec fastlane ci
env:
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Fastlane 실행에 필요한 환경 변수가 누락되었습니다.

fastlane/AppfileAPPLE_IDTEAM_ID 환경 변수를 요구하지만, 워크플로우에 이러한 변수가 설정되어 있지 않습니다. 테스트와 빌드가 실패할 수 있습니다.

🔎 제안된 수정

GitHub Secrets에 자격증명을 저장하고 워크플로우에서 참조하세요:

     - name: Run Fastlane CI
       run: |
         bundle exec fastlane ci
       env:
+        APPLE_ID: ${{ secrets.APPLE_ID }}
+        TEAM_ID: ${{ secrets.TEAM_ID }}
         FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120

GitHub 저장소 설정에서 다음 Secrets을 추가해야 합니다:

  • APPLE_ID: Apple Developer 계정 이메일
  • TEAM_ID: Apple Developer Team ID
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Run Fastlane CI
run: |
bundle exec fastlane ci
env:
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
- name: Run Fastlane CI
run: |
bundle exec fastlane ci
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
TEAM_ID: ${{ secrets.TEAM_ID }}
FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 120
🤖 Prompt for AI Agents
In .github/workflows/ci.yml around lines 53 to 57, the Fastlane job runs without
providing required environment variables (APPLE_ID and TEAM_ID) needed by
fastlane/Appfile; add references to GitHub Secrets for these values in the job's
env block (e.g., set APPLE_ID: ${{ secrets.APPLE_ID }} and TEAM_ID: ${{
secrets.TEAM_ID }}), ensure the repository has those Secrets configured, and
keep FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT as-is.


- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: test-results
path: test_output/
retention-days: 30

- name: Upload code coverage
if: success()
uses: codecov/codecov-action@v4
with:
files: test_output/**/*.xcresult
fail_ci_if_error: false
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

codecov-action v4 xcresult bundles support xcode

💡 Result:

Short answer: codecov-action v4 does not natively ingest .xcresult bundles — you must convert them to a supported coverage format (e.g., Cobertura/XML or lcov) and then upload with the v4 uploader/action. [1][2][3]

Details and options:

  • codecov-action v4 uses the Codecov CLI/uploader to perform uploads; the uploader expects standard coverage files (gcov, cobertura, lcov, etc.). It does not directly parse .xcresult bundles. Use the action to upload the converted files. [1][3]
  • Common approaches:
    • Convert .xcresult → Cobertura (or lcov) with a tool like xcresultparser (or use xccov/xccov-to-json + a converter) and then point codecov-action at the generated XML/coverage files. Codecov’s blog documents using xcresultparser for pre-conversion. [2]
    • Ensure the converted report is produced on the macOS runner (xcodebuild -resultBundlePath ...), then pass the report path(s) to the action (files/plugins/report_type as needed). [1][2]

If you want, tell me your CI workflow (macOS runner, Xcode version, how you produce .xcresult) and I’ll give an exact example workflow snippet to convert and upload.


.xcresult 번들을 지원되는 형식으로 변환하세요.

codecov-action v4는 .xcresult 번들을 직접 처리하지 않습니다. Codecov 업로더는 표준 커버리지 형식(Cobertura, lcov, gcov 등)만 지원하므로, 업로드 전에 .xcresult를 변환해야 합니다. xcresultparser 또는 유사한 도구를 사용하여 .xcresult를 Cobertura XML 형식으로 변환한 후, 변환된 파일을 업로드하도록 워크플로우를 수정하세요.

🤖 Prompt for AI Agents
.github/workflows/ci.yml around lines 67-72: the workflow currently passes
.xcresult bundles directly to codecov-action v4 which doesn't accept .xcresult;
add a prior step to convert test_output/**/*.xcresult to a supported coverage
format (e.g., Cobertura XML) using a tool like xcresultparser or an
xccov-to-cobertura converter, then update the Upload code coverage step to point
to the generated Cobertura XML files (e.g., test_output/**/*.cobertura.xml) and
keep fail_ci_if_error: false; ensure the conversion step runs on the same runner
and produces files matched by the codecov upload pattern.

18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -72,5 +72,23 @@ Tuist/Dependencies
### Tuist cache ###
Tuist/Cache/

### Secrets (handled via GitHub Secrets in CI) ###
XCConfig/
Projects/App/Resources/Firebase/

### Fastlane ###
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
fastlane/.env
test_output/
*.ipa
*.dSYM.zip
*.mobileprovision

### Ruby/Bundler ###
.bundle/
vendor/bundle/
Gemfile.lock
.claude/
7 changes: 7 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
source "https://rubygems.org"

gem "fastlane", "~> 2.230.0"
gem "cocoapods", "~> 1.15"

plugins_path = File.join(File.dirname(__FILE__), 'fastlane', 'Pluginfile')
eval_gemfile(plugins_path) if File.exist?(plugins_path)
49 changes: 49 additions & 0 deletions Scripts/print-github-secrets.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#!/bin/bash

# GitHub Secrets 설정을 위한 모든 내용 출력 스크립트
# XCConfig 및 Firebase 설정 파일 내용을 출력

echo "========================================="
echo "GitHub Secrets 설정을 위한 파일 내용"
echo "총 4개의 Secret이 필요합니다"
echo "========================================="
echo ""

echo "=== 1. XCCONFIG_BASE64 ==="
echo "이 내용을 전체 복사하여 GitHub Secret 'XCCONFIG_BASE64'에 추가하세요"
echo "---"
tar -czf - XCConfig | base64
echo ""
echo ""

echo "=== 2. GOOGLE_SERVICE_DEV_INFO ==="
echo "이 내용을 전체 복사하여 GitHub Secret 'GOOGLE_SERVICE_DEV_INFO'에 추가하세요"
echo "---"
cat Projects/App/Resources/Firebase/GoogleService-Dev-Info.plist
echo ""
echo ""

echo "=== 3. GOOGLE_SERVICE_STAGE_INFO ==="
echo "이 내용을 전체 복사하여 GitHub Secret 'GOOGLE_SERVICE_STAGE_INFO'에 추가하세요"
echo "---"
cat Projects/App/Resources/Firebase/GoogleService-Stage-Info.plist
echo ""
echo ""

echo "=== 4. GOOGLE_SERVICE_PROD_INFO ==="
echo "이 내용을 전체 복사하여 GitHub Secret 'GOOGLE_SERVICE_PROD_INFO'에 추가하세요"
echo "---"
cat Projects/App/Resources/Firebase/GoogleService-Prod-Info.plist
echo ""
echo ""

echo "========================================="
echo "다음 단계:"
echo "1. GitHub 저장소 → Settings → Secrets and variables → Actions"
echo "2. New repository secret 클릭"
echo "3. 위 4개 내용을 각각 복사하여 추가"
echo " - XCCONFIG_BASE64"
echo " - GOOGLE_SERVICE_DEV_INFO"
echo " - GOOGLE_SERVICE_STAGE_INFO"
echo " - GOOGLE_SERVICE_PROD_INFO"
echo "========================================="
22 changes: 0 additions & 22 deletions ci_scripts/ci_post_clone.sh

This file was deleted.

10 changes: 10 additions & 0 deletions fastlane/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# Apple Developer Account
APPLE_ID=your_apple_id@example.com

# Team ID (from Apple Developer Portal)
TEAM_ID=YOUR_TEAM_ID

# App Store Connect API Key (Optional, for better automation)
# APP_STORE_CONNECT_API_KEY_ID=
# APP_STORE_CONNECT_API_ISSUER_ID=
# APP_STORE_CONNECT_API_KEY_PATH=
7 changes: 7 additions & 0 deletions fastlane/Appfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
app_identifier("com.team.return.JOBIS-DSM-iOS")
apple_id(ENV["APPLE_ID"])
team_id(ENV["TEAM_ID"])

for_platform :ios do
app_identifier("com.team.return.JOBIS-DSM-iOS")
end
86 changes: 86 additions & 0 deletions fastlane/Fastfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
default_platform(:ios)

# Get project root directory
PROJECT_ROOT = File.expand_path("..", __dir__)
WORKSPACE_PATH = File.join(PROJECT_ROOT, "JOBIS-DSM-iOS-v2.xcworkspace")
TEST_OUTPUT_PATH = File.join(PROJECT_ROOT, "test_output")
XCODEPROJ_PATH = File.join(PROJECT_ROOT, "Projects/App/JOBIS-DSM-iOS-v2.xcodeproj")

platform :ios do

desc "Run tests"
lane :test do
run_tests(
workspace: WORKSPACE_PATH,
scheme: "JOBIS-DSM-iOS-v2-DEV",
destination: "platform=iOS Simulator,name=iPhone 16",
code_coverage: true,
result_bundle: true,
output_directory: TEST_OUTPUT_PATH,
clean: true
)
end

desc "Build for development"
lane :build_dev do
sh("xcodebuild",
"-workspace", WORKSPACE_PATH,
"-scheme", "JOBIS-DSM-iOS-v2-DEV",
"-configuration", "DEV",
"-sdk", "iphonesimulator",
"clean", "build",
"-skipPackagePluginValidation",
"CODE_SIGNING_ALLOWED=NO"
)
end

desc "Build for staging"
lane :build_stage do
xcodebuild(
workspace: WORKSPACE_PATH,
scheme: "JOBIS-DSM-iOS-v2-STAGE",
configuration: "STAGE",
sdk: "iphonesimulator",
destination: "platform=iOS Simulator,OS=latest,name=Any iOS Simulator Device",
clean: true,
build: true,
xcargs: "-skipPackagePluginValidation"
)
end

desc "Build for production"
lane :build_prod do
build_app(
workspace: WORKSPACE_PATH,
scheme: "JOBIS-DSM-iOS-v2-PROD",
configuration: "PROD",
export_method: "app-store",
clean: true
)
end

desc "Run SwiftLint"
lane :lint do
swiftlint(
mode: :lint,
executable: "Pods/SwiftLint/swiftlint",
config_file: ".swiftlint.yml",
raise_if_swiftlint_error: true
)
end
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check SwiftLint installation method

echo "=== Checking Podfile for SwiftLint ==="
if [ -f "Podfile" ]; then
  rg -n "SwiftLint" Podfile || echo "SwiftLint not found in Podfile"
else
  echo "Podfile not found"
fi

echo ""
echo "=== Checking Package.swift for SwiftLint ==="
if [ -f "Package.swift" ]; then
  rg -n -i "swiftlint" Package.swift || echo "SwiftLint not found in Package.swift"
else
  echo "Package.swift not found"
fi

echo ""
echo "=== Checking for SwiftLint in Pods directory ==="
if [ -d "Pods" ]; then
  ls -la Pods/ | grep -i swift || echo "No SwiftLint directory found in Pods"
else
  echo "Pods directory not found"
fi

echo ""
echo "=== Checking for .tuist-relation or tuist files ==="
if [ -f ".tuist-relation" ]; then
  echo ".tuist-relation exists"
fi
if [ -d "Tuist" ]; then
  find Tuist -name "*.swift" -type f | head -20
fi

echo ""
echo "=== Checking Gemfile for SwiftLint ==="
if [ -f "Gemfile" ]; then
  rg -n "swiftlint" Gemfile || echo "SwiftLint not found in Gemfile"
fi

Repository: Team-return/JOBIS-DSM-iOS-v2

Length of output: 725


🏁 Script executed:

#!/bin/bash
# Check Tuist configuration for SwiftLint

echo "=== Checking Tuist/Dependencies.swift for SwiftLint ==="
cat Tuist/Dependencies.swift

echo ""
echo "=== Searching entire Tuist directory for SwiftLint ==="
rg -r -n "SwiftLint\|swiftlint" Tuist/

echo ""
echo "=== Checking Fastfile for all references ==="
cat fastlane/Fastfile

Repository: Team-return/JOBIS-DSM-iOS-v2

Length of output: 4896


🏁 Script executed:

#!/bin/bash
# Check for SwiftLint configuration and installation methods

echo "=== Checking for .swiftlint.yml ==="
if [ -f ".swiftlint.yml" ]; then
  wc -l .swiftlint.yml
  head -20 .swiftlint.yml
else
  echo ".swiftlint.yml not found"
fi

echo ""
echo "=== Checking for CI configuration files ==="
if [ -d ".github/workflows" ]; then
  ls -la .github/workflows/
  echo ""
  echo "=== Checking GitHub Actions for SwiftLint ==="
  rg -n "swiftlint\|SwiftLint" .github/workflows/
fi

if [ -f ".gitlab-ci.yml" ]; then
  echo "=== GitLab CI config found ==="
  rg -n "swiftlint\|SwiftLint" .gitlab-ci.yml
fi

echo ""
echo "=== Searching for any SwiftLint installation mentions ==="
rg -n "swiftlint\|SwiftLint\|brew install" . --type sh --type yml --type yaml 2>/dev/null | head -20

echo ""
echo "=== Checking for Homebrew references in project ==="
find . -name "Brewfile" -o -name "*.sh" | head -10 | xargs grep -l "brew" 2>/dev/null

Repository: Team-return/JOBIS-DSM-iOS-v2

Length of output: 756


🏁 Script executed:

#!/bin/bash
# Check SwiftLint installation and configuration

echo "=== Checking .github/workflows/swiftlint.yml ==="
cat .github/workflows/swiftlint.yml

echo ""
echo "=== Checking Scripts/SwiftLintRunScript.sh ==="
cat ./Scripts/SwiftLintRunScript.sh

echo ""
echo "=== Checking if .swiftlint.yml should exist ==="
find . -name ".swiftlint*" -o -name "swiftlint*" | grep -v ".git" | grep -v "node_modules"

Repository: Team-return/JOBIS-DSM-iOS-v2

Length of output: 1470


SwiftLint 실행 파일 경로와 설정 파일 경로를 수정하세요.

Fastfile의 lint lane에서 SwiftLint 실행 파일 경로가 Pods/SwiftLint/swiftlint로 잘못 지정되어 있습니다. 프로젝트는 CocoaPods를 사용하지 않으며 Homebrew를 통해 SwiftLint를 설치합니다. 또한 설정 파일 경로도 .swiftlint.yml로 되어 있으나, 실제 파일은 ./Scripts/.swiftlint.yml에 위치합니다.

다음과 같이 수정하세요:

  • executable: "swiftlint" (PATH에서 찾음, Homebrew 설치 가정)
  • config_file: "./Scripts/.swiftlint.yml" (실제 파일 위치)

현재 설정으로는 lint lane 실행 시 파일을 찾을 수 없어 실패합니다.

🤖 Prompt for AI Agents
fastlane/Fastfile around lines 59 to 67: the lint lane currently references a
CocoaPods-installed SwiftLint binary and the wrong config path; change
executable to "swiftlint" (use PATH/Homebrew) and change config_file to
"./Scripts/.swiftlint.yml" so Fastlane invokes the correct system-installed
binary and the actual configuration file location.


desc "Deploy to TestFlight"
lane :beta do
increment_build_number(xcodeproj: XCODEPROJ_PATH)
build_prod
upload_to_testflight(
skip_waiting_for_build_processing: true
)
end

desc "CI Build and Test"
lane :ci do
build_dev
# test - 시뮬레이터 설정 후 활성화
end
end
Loading