Skip to content

Conversation

@gnksbm
Copy link
Contributor

@gnksbm gnksbm commented Apr 6, 2025

작업내용

Tuist

  • 버전 마이그레이션(3 -> 4)
  • 선언형으로 작성할 수 있도록 변경

새로운 모듈 추가

  • Firebase 래핑 모듈 구현
    • SPM 패키지를 직접 의존하는 방식에서 캐시하여 사용하는 방식으로 수정하였습니다.
    • Firebase 모듈을 static 하게 사용해야 하기 때문에 래핑 모듈 Implement(구현체)를 staticFramework로 구현하여 앱 상단에서 단독으로 의존하도록 구현하였습니다.
    • 래핑 모듈 Interface는 dynamicFramework로 구현하여 필요한 곳에서 의존하도록 구현하였습니다.

자동화 커멘드 수정(Makefile, Fastfile)

  • 인증과 배포를 관리하는 Fastfile에 너무 많은 기능이 포함되어 있어 프로젝트 관리 커멘드는 Makefile로 이동하였습니다.
  • 변경된 커멘드
    • make init(fastlane setpj에서 변경)
      • 캐싱 업데이트가 필요할 때 사용
      • reset 성격으로 사용
    • make gen(tuist generate 래핑)
      • 프로젝트 구성 파일이 변경되었을 때 사용
    • make getig(fastlane getig에서 변경)
      • ignore 파일 업데이트가 필요할 때 사용
    • make update_tuist
      • 기존 설치된 Tuist 3버전을 제거하고 4를 호환하기 위한 커멘드를 추가하였습니다. 최초 한번만 실행하면 되며 여러번 실행하였을 때의 방어 로직 또한 포함되어 있습니다.

리뷰요청

  • @isakatty
  • @MUKER-WON
  • Tuist 관련 세부사항을 적기엔 너무 큰 범위의 변화라서 전체적으로 살펴보시고 이해가 안가는 부분이 있다면 음성으로 설명되는게 좋을 것 같아요.
  • 잘못된 변화를 찾는다면 코멘트 달아주시면 감사하겠습니다.

관련 이슈

close #319

Summary by CodeRabbit

  • 신규 기능

    • 앱, 샘플 앱, 위젯, 유닛 테스트, 피처 등 다양한 타겟 및 스킴을 선언적으로 구성할 수 있는 빌더 및 프로토콜 기반 환경 플러그인 도입
    • Info.plist, 스크립트, 타겟 의존성, SPM 및 XCFramework 의존성 선언을 위한 확장 및 빌더 추가
    • 프로젝트 컴포넌트 및 타겟 컴포넌트 빌더 도입으로 프로젝트 구성의 선언성과 재사용성 향상
    • Swift Result Builder 활용한 타입 및 타겟 구성 빌더 추가
  • 개선 및 리팩터

    • Makefile 구조 개선 및 자동화 타겟 추가(초기화, 토큰 선택, Tuist 업데이트 등)
    • GitHub Actions 워크플로우에서 Tuist 설치 및 초기화 방식 개선(mise 도구 활용)
    • 프로젝트 환경 상수 및 공통 확장 정리
    • 기존 InfoPlist, Scheme, Scripts 관련 확장 및 헬퍼 파일 제거로 코드 정리
  • 기능 제거

    • 기존 DependencyPlugin 및 InfoPlist, Scheme, Scripts 관련 확장 및 헬퍼 파일 삭제
    • 더 이상 사용하지 않는 .tuist-version 파일 제거
  • 문서화

    • 주요 신규 파일 및 프로토콜, 빌더에 대한 코드 수준 설명 및 구조화

이제 더욱 선언적이고 유연한 프로젝트 구성과 자동화가 가능합니다.

@gnksbm gnksbm requested review from MUKER-WON and isakatty April 6, 2025 09:51
@gnksbm gnksbm self-assigned this Apr 6, 2025
@MUKER-WON
Copy link
Contributor

추후에 코멘트는 정리해서 다시 리뷰하겠습니다 고생하셨습니다 :)

@isakatty isakatty marked this pull request as draft June 25, 2025 13:55
Copy link
Contributor

@isakatty isakatty left a comment

Choose a reason for hiding this comment

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

확인했습니다!

@isakatty isakatty marked this pull request as ready for review June 25, 2025 13:56
@coderabbitai
Copy link

coderabbitai bot commented Jun 25, 2025

"""

Walkthrough

이 변경사항은 Tuist 버전 3.28.0에서 4.33.0으로의 마이그레이션을 중심으로, 플러그인 구조와 의존성 선언 방식을 대대적으로 개편하고, Makefile, GitHub Actions 워크플로, Info.plist 및 Scheme 관련 빌더, 결과 빌더, 공통 유틸리티 등 프로젝트 환경 구성을 전면적으로 재구성합니다. 기존의 플러그인 및 의존성 헬퍼 파일은 삭제되고, 새로운 빌더 및 프로토콜 기반 구조로 대체되었습니다.

Changes

파일/경로 그룹 변경 요약
.github/workflows/pull_request_test.yml, .github/workflows/upload_testflight.yml Tuist 설치 및 사용 방식을 mise 기반으로 변경, tuist 관련 명령 및 fetch/clean 제거, make init 추가
.tuist-version Tuist 버전 파일 삭제 (3.28.0 → mise 관리로 이전)
Makefile 타겟 재구성, init/fetch/gen 등 신규 타겟 및 자동화 추가, 기존 clean_xcode 등 일부 타겟 명칭 변경
Plugins/DependencyPlugin/… DependencyPlugin 전체 및 관련 헬퍼, 의존성 선언 파일 일괄 삭제
Plugins/EnvironmentPlugin/Plugin.swift @preconcurrency 속성 추가
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/… InfoPlist, Target, Scheme, Script 등 빌더 및 프로토콜 기반 구조 신설, 다양한 신규 타입 및 빌더 도입
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Builder/… ProjectComponentBuilder, TargetBuilder, TargetComponentBuilder 등 결과 빌더 도입
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Foundation/… TypeBuilder, TypeNameContains 등 공통 유틸리티 및 프로토콜 추가
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Common.swift ProjectDescription 모듈 재익스포트용 파일 추가
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Environment.swift 상수 및 확장 정리, 불필요한 static 확장/프로퍼티 제거
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/InfoPlist.swift InfoPlist 관련 확장 및 static 구성 삭제
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Scheme.swift Scheme 확장 및 static 팩토리 메서드 삭제
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Scripts.swift TargetScript 확장 및 SwiftLint 스크립트 static 삭제

Sequence Diagram(s)

sequenceDiagram
    participant Developer
    participant Makefile
    participant mise
    participant Tuist
    participant ProjectBuilder

    Developer->>Makefile: make init
    Makefile->>mise: mise install [email protected]
    Makefile->>mise: mise use -g [email protected]
    Makefile->>Tuist: tuist install / generate
    Makefile->>ProjectBuilder: 빌더 기반 프로젝트 구성
    ProjectBuilder-->>Makefile: targets, schemes 등 생성
Loading

Assessment against linked issues

Objective Addressed Explanation
Tuist 파일 변경된 문법 형태로 수정 (#319)
의존성 구성 방식 수정 (#319)
Plugin 제거 (#319)
Makefile, Fastlane, Github Action 수정 (#319)

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
UIKitInfoPlist.swift, WhereMyBusInfoPlist.swift (신규 InfoPlist 빌더 파일 추가) WhereMyBusInfoPlist.swift는 현재 구현 내용이 없으나, 마이그레이션 목적에 부합하므로 out-of-scope로 판단하지 않음.

Poem

🐰
Tuist가 변신했어요,
플러그인들 안녕, 빌더들 어서 와요!
Makefile도 새 옷 입고,
워크플로도 척척 바뀌었죠.
의존성도 깔끔하게,
프로젝트는 더 단단하게!
Hop, hop, hop—코드가 춤을 춰요!

"""


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (13)
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/InfoPlistBuildable/InfoPlist/WhereMyBusInfoPlist.swift (1)

1-17: 구현이 누락된 파일입니다.

이 파일은 헤더 주석과 Foundation import만 포함하고 있으며 실제 구현이 없습니다. InfoPlistBuildable 프로토콜을 구현하는 WhereMyBusInfoPlist 구조체나 클래스가 필요한 것으로 보입니다.

WhereMyBusInfoPlist의 구현이 의도적으로 누락된 것인지 확인해 주세요. 만약 구현이 필요하다면 InfoPlistBuildable 프로토콜을 구현하는 코드를 추가하시겠습니까?

 import Foundation
-
-
-
-
-
-
-
-
-
+
+public struct WhereMyBusInfoPlist: InfoPlistBuildable {
+    public func buildInfoPlist() -> InfoPlist {
+        // TODO: WhereMyBus 앱에 특화된 Info.plist 구성 구현
+        return .default
+    }
+}
.github/workflows/pull_request_test.yml (1)

34-44: mise를 사용한 Tuist 설치 방식이 우수합니다.

직접적인 curl 설치 대신 mise 도구를 사용하는 것은 더 체계적이고 재현 가능한 개발 환경을 제공합니다. make init을 통한 프로젝트 초기화도 일관성 있는 접근법입니다.

하지만 YAML 포맷팅 문제를 수정해야 합니다:

-                    
-      - name: Mise
+      - name: Mise
       uses: jdx/mise-action@v2

       - name: Install Tuist
-        run: mise install [email protected]
- 
+        run: mise install [email protected]
+
       - name: Tuist version
-        run: mise use -g [email protected]
-        
+        run: mise use -g [email protected]
+
       - name: Setup Project
-        run: make init
-                
+        run: make init
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetScriptBuildable/TargetScriptBuildable.swift (1)

8-10: 프로토콜 설계가 간결하고 명확합니다.

TargetScriptBuildable 프로토콜은 빌더 패턴의 일부로서 타겟 스크립트 구성 요소들을 통합하는 명확한 인터페이스를 제공합니다. 단일 메서드 요구사항으로 구성되어 구현이 간단합니다.

더 나은 개발자 경험을 위해 문서 주석을 추가하는 것을 고려해보세요:

+/// 타겟 스크립트를 빌드할 수 있는 컴포넌트들을 위한 프로토콜
 public protocol TargetScriptBuildable {
+    /// 이 컴포넌트에서 제공하는 타겟 스크립트들을 반환합니다.
+    /// - Returns: 빌드 과정에서 실행될 TargetScript 배열
     func buildTargetScript() -> [TargetScript]
 }
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Foundation/TypeBuilder.swift (1)

8-8: 불필요한 import 제거 검토

이 파일에서 Foundation 타입을 사용하지 않으므로 import Foundation이 필요하지 않을 수 있습니다.

-import Foundation
-
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/InfoPlistBuildable/InfoPlist/UIKitInfoPlist.swift (1)

8-8: 불필요한 import 검토

이 파일에서 Foundation의 특정 타입을 직접 사용하지 않으므로 import가 필요하지 않을 수 있습니다. ProjectDescription.Plist.Value는 ProjectDescription 모듈에서 제공됩니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/BundleIDSuffixTarget.swift (1)

11-11: 번들 ID 생성 로직 최적화 제안

현재 배열을 생성한 후 joined(separator:)를 사용하고 있는데, 단순한 문자열 보간이 더 효율적일 수 있습니다.

다음과 같이 개선할 수 있습니다:

-    var bundleId: String { [.bundleID, name].joined(separator: ".") }
+    var bundleId: String { "\(.bundleID).\(name)" }
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/App.swift (2)

13-13: Bundle ID 설정의 유연성 부족

bundleId.bundleID로 하드코딩되어 있어서 앱별로 다른 Bundle ID를 사용해야 하는 경우 유연성이 부족할 수 있습니다.

Bundle ID를 초기화 시점에 설정할 수 있도록 개선하는 것을 고려해보세요:

-public let bundleId: String = .bundleID
+public let bundleId: String

public init(
    name: String,
+    bundleId: String = .bundleID,
    @TargetComponentBuilder dependencies builder: () -> TargetComponentBuilder
) {
    let builder = builder()
    self.name = name
+    self.bundleId = bundleId
    self.dependencies = builder.buildTargetDependency()
    self.scripts = builder.buildTargetScript()
    self.infoPlist = builder.buildInfoPlist()
}

18-18: Debug 설정 하드코딩 재검토

settings.appDebug로 하드코딩되어 있어서 Release 빌드나 다른 설정이 필요한 경우 제한적일 수 있습니다.

설정을 더 유연하게 만드는 것을 고려해보세요:

-public let settings: Settings? = .appDebug
+public let settings: Settings?

public init(
    name: String,
+    settings: Settings? = .appDebug,
    @TargetComponentBuilder dependencies builder: () -> TargetComponentBuilder
) {
    let builder = builder()
    self.name = name
+    self.settings = settings
    // ... rest of initialization
}
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/AppScheme.swift (1)

25-37: Firebase 디버그 설정의 유연성 고려

Firebase 디버그 로깅이 모든 앱에서 필요하지 않을 수 있으므로, 이를 선택적으로 설정할 수 있도록 하는 것을 고려해보세요.

Firebase 디버그 설정을 선택적으로 만드는 방법:

public struct AppScheme: SchemeBuildable {
    public let name: String
+    public let enableFirebaseDebug: Bool
    
    // ... other properties ...
    
    public var runAction: RunAction? {
+        let launchArgs = enableFirebaseDebug ? [
+            .launchArgument(
+                name: "-FIRDebugEnabled",
+                isEnabled: true
+            )
+        ] : []
+        
        .runAction(
            configuration: .debug,
-            arguments: .arguments(
-                launchArguments: [
-                    .launchArgument(
-                        name: "-FIRDebugEnabled",
-                        isEnabled: true
-                    )
-                ]
-            )
+            arguments: launchArgs.isEmpty ? nil : .arguments(launchArguments: launchArgs)
        )
    }
    
-    public init(name: String) {
+    public init(name: String, enableFirebaseDebug: Bool = true) {
        self.name = name
+        self.enableFirebaseDebug = enableFirebaseDebug
    }
}
Makefile (1)

9-24: getig 타겟 길이 단축을 권장합니다.

getig 타겟의 본문이 권장 길이(5줄)를 초과합니다(15줄). 가독성과 유지보수성을 위해 별도 셸 스크립트로 분리하는 것을 고려해보세요.

-getig:
-	@echo "Select config source:"
-	@echo " 1) global"
-	@echo " 2) local"
-	@read -p "Enter choice [1 or 2]: " choice; \
-	if [ "$$choice" = "1" ]; then \
-	  echo "Using GITHUB_ACCESS_TOKEN from global config"; \
-	  GITHUB_ACCESS_TOKEN=$$(git config --global user.password); \
-	elif [ "$$choice" = "2" ]; then \
-	  echo "Using GITHUB_ACCESS_TOKEN from local config"; \
-	  GITHUB_ACCESS_TOKEN=$$(git config user.password); \
-	else \
-	  echo "Invalid choice: $$choice. Aborting..."; \
-	  exit 1; \
-	fi; \
-	$(MAKE) download-privates token=$$GITHUB_ACCESS_TOKEN
+getig:
+	sh ./Scripts/get_github_token.sh
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Builder/TargetBuilder.swift (1)

28-33: 가변 인자 표현식 처리 개선 고려.

가변 인자(...)를 사용한 buildExpression 메서드는 올바르게 구현되었지만, 빈 배열이 전달될 경우의 처리를 명시적으로 고려해보세요.

public static func buildExpression(_ expression: TargetBuilder...) -> TargetBuilder {
+    guard !expression.isEmpty else { return .init() }
    .init(
        dependencyBuildable: expression.flatMap { $0.dependencyBuildable },
        targetBuildable: expression.flatMap { $0.targetBuildable }
    )
}
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/ProjectComponentBuilder.swift (1)

49-55: 중복된 map 연산 최적화 고려.

가변 인자와 배열 버전의 buildExpression 메서드에서 동일한 map 연산을 수행합니다. 공통 함수로 추출하여 중복을 제거할 수 있습니다.

+private static func buildTargets(from buildables: [TargetBuildable]) -> [Target] {
+    buildables.map { $0.buildTarget() }
+}
+
public static func buildExpression(_ expression: TargetBuildable...) -> ProjectComponentBuilder {
-    .init(targets: expression.map { $0.buildTarget() })
+    .init(targets: buildTargets(from: Array(expression)))
}

public static func buildExpression(_ expression: [TargetBuildable]) -> ProjectComponentBuilder {
-    .init(targets: expression.map { $0.buildTarget() })
+    .init(targets: buildTargets(from: expression))
}
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Builder/TargetComponentBuilder.swift (1)

31-37: 가변 인자 flatMap 연산 성능 검토.

세 개의 flatMap 연산을 동시에 수행하고 있습니다. 큰 배열의 경우 성능 영향을 고려해보세요.

성능이 중요한 경우 단일 순회로 최적화할 수 있습니다:

static func buildExpression(_ expression: TargetComponentBuilder...) -> TargetComponentBuilder {
-    .init(
-        dependencyBuildables: expression.flatMap { $0.dependencyBuildables },
-        targetScriptBuildables: expression.flatMap { $0.targetScriptBuildables },
-        infoPlistBuildables: expression.flatMap { $0.infoPlistBuildables }
-    )
+    expression.reduce(.init()) { result, builder in
+        .init(
+            dependencyBuildables: result.dependencyBuildables + builder.dependencyBuildables,
+            targetScriptBuildables: result.targetScriptBuildables + builder.targetScriptBuildables,
+            infoPlistBuildables: result.infoPlistBuildables + builder.infoPlistBuildables
+        )
+    }
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d728b8 and f5c2aa1.

📒 Files selected for processing (48)
  • .github/workflows/pull_request_test.yml (1 hunks)
  • .github/workflows/upload_testflight.yml (1 hunks)
  • .tuist-version (0 hunks)
  • Makefile (2 hunks)
  • Plugins/DependencyPlugin/Plugin.swift (0 hunks)
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Feature.swift (0 hunks)
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Module.swift (0 hunks)
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+ThirdPartyExternal.swift (0 hunks)
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+ThirdPartyRemote.swift (0 hunks)
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Depondency+ThirdPartyXCFramework.swift (0 hunks)
  • Plugins/EnvironmentPlugin/Plugin.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/InfoPlistBuildable/InfoPlist/UIKitInfoPlist.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/InfoPlistBuildable/InfoPlist/WhereMyBusInfoPlist.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/InfoPlistBuildable/InfoPlistBuildable.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/ProjectComponentBuilder.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/AppScheme.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/SampleAppScheme.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/UITestsScheme.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/UnitTestsScheme.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/SchemeBuildable.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/App.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/Feature.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/SampleApp.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/UnitTests.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/WidgetExtension.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetBuildable.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/AppExtensionTarget.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/BundleIDSuffixTarget.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/FrameworkTarget.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/ImplementTarget.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/InterfaceTarget.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/TestingTarget.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/TestsTarget.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependency/LocalDependency.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependency/SPMDependency.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependency/XCFrameworkDependency.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependencyBuildable.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetScriptBuildable/PreTargetScriptBuildable.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetScriptBuildable/TargetScriptBuildable.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Builder/TargetBuilder.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Builder/TargetComponentBuilder.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Common.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Environment.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Foundation/TypeBuilder.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Foundation/TypeNameContains.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/InfoPlist.swift (0 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Scheme.swift (0 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Scripts.swift (0 hunks)
💤 Files with no reviewable changes (10)
  • .tuist-version
  • Plugins/DependencyPlugin/Plugin.swift
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+ThirdPartyExternal.swift
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+ThirdPartyRemote.swift
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Scripts.swift
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Feature.swift
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Dependency+Module.swift
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Scheme.swift
  • Plugins/DependencyPlugin/ProjectDescriptionHelpers/Depondency+ThirdPartyXCFramework.swift
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/InfoPlist.swift
🧰 Additional context used
🪛 YAMLlint (1.37.1)
.github/workflows/pull_request_test.yml

[error] 33-33: trailing spaces

(trailing-spaces)


[error] 39-39: trailing spaces

(trailing-spaces)


[error] 42-42: trailing spaces

(trailing-spaces)


[error] 45-45: trailing spaces

(trailing-spaces)

.github/workflows/upload_testflight.yml

[error] 42-42: trailing spaces

(trailing-spaces)


[error] 48-48: trailing spaces

(trailing-spaces)


[error] 51-51: trailing spaces

(trailing-spaces)


[error] 54-54: trailing spaces

(trailing-spaces)

🪛 checkmake (0.2.2)
Makefile

[warning] 9-9: Target body for "getig" exceeds allowed length of 5 (15).

(maxbodylength)

🔇 Additional comments (47)
Plugins/EnvironmentPlugin/Plugin.swift (1)

9-9: @preconcurrency 추가가 적절합니다.

Tuist 4.x 버전으로 마이그레이션하면서 ProjectDescription 모듈에 대한 동시성 검사를 비활성화하는 것은 올바른 접근입니다. 이는 컴파일러 경고를 방지하고 Tuist의 내부 구현과의 호환성을 보장합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Common.swift (1)

8-8: @_exported import 사용이 적절합니다.

Common.swift를 통해 ProjectDescription을 재내보내는 것은 EnvironmentPlugin 내의 다른 파일들에서 일관되게 ProjectDescription에 접근할 수 있게 해주는 좋은 패턴입니다. 이는 import 문의 중복을 줄이고 코드 가독성을 향상시킵니다.

.github/workflows/upload_testflight.yml (1)

43-54: Tuist 4.33.0 마이그레이션이 잘 구현되었습니다

mise를 사용한 Tuist 버전 관리와 make init 명령어로의 통합이 PR 목표와 일치합니다. 이 방식은 버전 관리를 더 체계적으로 만들고 프로젝트 설정을 단순화합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependencyBuildable.swift (1)

8-16: 프로토콜 설계가 우수합니다

TargetDependencyBuildable 프로토콜과 TargetDependency의 기본 구현이 깔끔하고 논리적입니다. 이 설계는 타겟 의존성 구축을 위한 통일된 인터페이스를 제공하며, 더 큰 모듈화 및 빌더 패턴 리팩터링의 일부로 잘 설계되었습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Foundation/TypeBuilder.swift (1)

10-15: 제네릭 결과 빌더 구현이 우수합니다

TypeBuilder는 깔끔하고 재사용 가능한 제네릭 결과 빌더입니다. Swift의 결과 빌더 패턴을 올바르게 따르고 있으며, 다양한 타입의 컴포넌트를 선언적으로 집계할 수 있는 기반을 제공합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/InfoPlistBuildable/InfoPlist/UIKitInfoPlist.swift (1)

10-30: 표준 UIKit Info.plist 구성이 잘 구현되었습니다

Scene Delegate 기반의 현대적인 iOS 앱 구성과 표준적인 설정들이 올바르게 정의되어 있습니다. $(PRODUCT_MODULE_NAME) 변수 사용도 적절합니다.

참고: 현재 세로 방향만 지원하도록 설정되어 있는데, 필요에 따라 다른 방향도 지원할 수 있도록 확장 가능한 구조로 만드는 것을 고려해볼 수 있습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/TestingTarget.swift (1)

8-12: 테스팅 타겟 프로토콜이 깔끔하게 구현되었습니다

TestingTarget 프로토콜과 기본 소스 패턴 구현이 간결하고 적절합니다. "Testing/**" 패턴은 테스트 파일 구성을 위한 합리적인 규칙이며, 최소한의 인터페이스로 명확한 목적을 달성합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/BundleIDSuffixTarget.swift (1)

8-8: 프로토콜 정의가 깔끔합니다

단일 책임 원칙을 잘 따르고 있으며, TargetBuildable을 상속하여 타겟 빌드 관련 기능을 확장하는 구조가 적절합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/AppExtensionTarget.swift (1)

8-12: 앱 확장 타겟 프로토콜이 잘 설계되었습니다

BundleIDSuffixTarget을 상속하여 번들 ID 생성 기능을 재사용하면서, 앱 확장 특화 기능(.appExtension product)을 제공하는 구조가 적절합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/InterfaceTarget.swift (1)

8-8: 다중 프로토콜 상속이 적절합니다

BundleIDSuffixTarget과 LocalDependency를 모두 상속하여 프레임워크 인터페이스 타겟에 필요한 기능들을 조합한 설계가 좋습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/TestsTarget.swift (2)

8-11: 테스트 타겟 프로토콜 구조가 좋습니다

TargetBuildable을 상속하고 기본 소스 경로(Tests/**)를 제공하는 설계가 적절합니다.


22-26: ```shell
#!/bin/bash
set -e

echo "1) 리포지토리 루트에서 'XCConfig' 디렉터리 검색:"
fd -t d XCConfig || echo " → XCConfig 디렉터리가 없습니다."

echo
echo "2) 'XCConfig' 디렉터리 내부 파일 목록:"
fd XCConfig/ || echo " → XCConfig 디렉터리 내부에 파일이 없습니다."

echo
echo "3) 전체 리포지토리에서 '.xcconfig' 파일 검색:"
rg -n --color never ".xcconfig" || echo " → '.xcconfig' 파일이 없습니다."


</details>
<details>
<summary>Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependency/SPMDependency.swift (1)</summary>

`8-16`: **SPM 의존성 프로토콜이 잘 설계되었습니다**

TargetDependencyBuildable과 TypeNameContains를 조합하여 SPM 패키지 의존성을 효과적으로 추상화하고 있습니다. 기본 구현에서 `.external(name: targetName)`을 반환하는 방식도 직관적이고 적절합니다.

</details>
<details>
<summary>Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/SampleAppScheme.swift (1)</summary>

`8-21`: **LGTM! 깔끔한 SchemeBuildable 구현입니다.**

새로운 프로토콜 기반 아키텍처에 잘 맞는 구현이며, 네이밍 규칙과 빌드 액션 설정이 적절합니다.

</details>
<details>
<summary>Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/ImplementTarget.swift (2)</summary>

`8-8`: **프로토콜 조합이 잘 설계되었습니다.**

`BundleIDSuffixTarget`과 `LocalDependency`를 조합한 설계가 깔끔하며, 재사용성이 높습니다.

---

`10-13`: **기본 설정값 확인이 필요합니다.**

기본 소스 패턴 `"Sources/**"`은 적절하지만, `.frameworkDebug` 설정이 모든 구현 타겟에 적합한지 확인해보세요.


다음 스크립트로 다른 타겟들의 설정을 확인해보겠습니다:

```shell
#!/bin/bash
# 다른 타겟 설정들과 비교하여 .frameworkDebug가 적절한지 확인
rg -A 3 -B 3 "\.framework" --type swift
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/UnitTestsScheme.swift (1)

8-30: 코드 커버리지가 포함된 완전한 유닛 테스트 스킴 구현입니다.

테스트 액션에 코드 커버리지 설정이 포함되어 있어 테스트 품질 관리에 도움이 될 것입니다. 구현이 체계적이고 완전합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependency/LocalDependency.swift (1)

8-16: 로컬 의존성 관리를 위한 깔끔한 프로토콜 설계입니다.

프로토콜 제약 조건(LocalDependency & TargetBuildable)을 통한 타입 안전성 확보와 기본 구현 제공이 우수합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Environment.swift (1)

16-17: String 확장 통합이 잘 이루어졌습니다.

중복된 확장들을 하나로 통합하여 코드 가독성이 개선되었으며, 새로운 프로토콜 기반 아키텍처와 잘 맞습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetDependencyBuildable/TargetDependency/XCFrameworkDependency.swift (1)

8-17: 프로토콜 설계가 깔끔하고 일관성 있습니다.

XCFramework 의존성을 위한 프로토콜 설계가 잘 되어 있고, 기본 구현이 적절합니다. 경로 구성과 주석도 명확합니다.

 public extension XCFrameworkDependency {
     func buildTargetDependency() -> [TargetDependency] {
-        [.xcframework(path: .relativeToRoot("Frameworks/\(frameworkName).xcframework"))]
+        [.xcframework(path: .relativeToRoot("Frameworks/\(frameworkName).xcframework"))]
     }
 }
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/UITestsScheme.swift (1)

8-30: UI 테스트 스킴 구성이 적절합니다.

UI 테스트를 위한 스킴 설정이 올바르게 구성되어 있습니다. 특히 코드 커버리지 활성화와 적절한 타겟 의존성 설정이 좋습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/FrameworkTarget.swift (1)

8-21: 프레임워크 타겟을 위한 공통 설정이 잘 구성되었습니다.

SwiftLint 스크립트의 기본 설정과 타겟 의존성 경로 구성이 적절합니다. 프로토콜 기반 설계로 재사용성이 높습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/SampleApp.swift (1)

8-28: 샘플 앱 타겟 구성이 일관성 있게 설계되었습니다.

TargetComponentBuilder를 사용한 선언적 의존성 구성과 번들 ID 구성이 적절합니다. 데모 앱을 위한 설정들이 잘 정의되어 있습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/UnitTests.swift (1)

8-27: 유닛 테스트 타겟 구현이 깔끔하고 일관성 있습니다.

TestsTarget 프로토콜을 활용한 구현과 TargetComponentBuilder를 통한 의존성 구성이 다른 타겟들과 일관된 패턴을 따르고 있습니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/App.swift (1)

20-22: Entitlements 파일 경로 가정 검증 필요

앱 이름을 기반으로 entitlements 파일 경로를 생성하고 있는데, 해당 파일이 실제로 존재하는지 확인이 필요합니다.

Entitlements 파일의 존재 여부를 확인하세요:

#!/bin/bash
# Description: Check if entitlements files exist for apps using this pattern

# Find all Project.swift files that might use the App struct
fd -e swift -x grep -l "App(" {} \; | while read -r file; do
    echo "Checking project file: $file"
    # Extract app names from the file (simplified pattern)
    grep -o 'App(name: "[^"]*"' "$file" | sed 's/App(name: "//' | sed 's/"//' | while read -r app_name; do
        entitlements_file="${app_name}.entitlements"
        if [ -f "$entitlements_file" ]; then
            echo "✓ Found: $entitlements_file"
        else
            echo "✗ Missing: $entitlements_file"
        fi
    done
done
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/AppScheme.swift (1)

15-24: 테스트 타겟 명명 규칙 가정

테스트 타겟 이름을 "\(name)Tests"로 가정하고 있는데, 프로젝트의 모든 앱이 이 명명 규칙을 따르는지 확인이 필요합니다.

프로젝트 내 테스트 타겟들의 명명 규칙을 확인하세요:

#!/bin/bash
# Description: Check test target naming conventions in the project

# Find all test targets in project files
rg -A 3 -B 1 'product.*\.unitTests|\.uiTests' --type swift | grep -E 'name:|product:' | head -20

# Also check for any existing test schemes
fd -e swift -x grep -l "TestAction\|Tests" {} \; | head -10
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/SchemeBuildable.swift (1)

8-43: 잘 설계된 프로토콜 구조

SchemeBuildable 프로토콜이 잘 설계되었습니다. 적절한 기본값 제공과 유연한 오버라이드 가능성을 갖추고 있습니다. 특히 run action은 debug, archive action은 release 설정을 기본값으로 하는 것이 적절합니다.

프로토콜에 대한 문서화를 추가하는 것을 고려해보세요:

+/// Protocol for building Tuist Scheme configurations
+/// Provides default implementations for common scheme actions
public protocol SchemeBuildable {
    // ... existing code ...
}
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Foundation/TypeNameContains.swift (2)

16-26: 조건부 확장의 우수한 설계

각 프로토콜 컨텍스트에 맞는 적절한 프로퍼티 이름을 제공하는 조건부 확장이 잘 설계되었습니다. SPMDependencytargetName, XCFrameworkDependencyframeworkName, TargetBuildablename으로 각각의 용도에 맞게 명명되었습니다.


12-14: 타입 이름 추출 방법의 안정성 검증

String(describing: type(of: self))를 사용한 타입 이름 추출이 모든 경우에 예상된 결과를 제공하는지 확인이 필요합니다. 특히 제네릭 타입이나 중첩 타입의 경우 예상과 다른 문자열이 반환될 수 있습니다.

타입 이름 추출이 올바르게 작동하는지 테스트해보세요:

#!/bin/bash
# Description: Find usage of TypeNameContains protocol and verify type names

# Find all types that conform to TypeNameContains
ast-grep --pattern $'$_: TypeNameContains'

# Find usage of typeName, targetName, frameworkName properties
rg -A 2 -B 2 'typeName|targetName|frameworkName' --type swift
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetScriptBuildable/PreTargetScriptBuildable.swift (1)

8-51: 잘 설계된 프로토콜입니다!

PreTargetScriptBuildable 프로토콜이 매우 잘 구성되어 있습니다. 합리적인 기본값 제공, 명확한 속성 분리, 그리고 buildTargetScript() 메서드에서 모든 속성을 올바르게 매핑하고 있습니다.

Makefile (2)

1-7: 새로운 복합 타겟들이 잘 구성되어 있습니다.

init, fetch, gen 타겟들이 논리적으로 잘 연결되어 있고, Tuist 4 마이그레이션에 적합한 명령어들을 사용하고 있습니다.


36-37: update_tuist 타겟이 적절하게 구현되었습니다.

Tuist 버전 업데이트를 별도 스크립트로 위임하는 방식이 적절합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/WidgetExtension.swift (1)

8-55: 위젯 확장 타겟이 잘 구현되었습니다.

WidgetExtension 구조체가 AppExtensionTarget 프로토콜을 올바르게 준수하고 있으며, 리소스 구성, 권한 설정, 빌드 설정이 위젯 개발에 적합하게 구성되어 있습니다. TargetComponentBuilder를 사용한 선언적 구성도 적절합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetBuildable.swift (1)

8-81: 핵심 TargetBuildable 프로토콜이 훌륭하게 설계되었습니다.

포괄적인 속성 정의, 합리적인 기본값 제공, 그리고 buildTarget() 메서드에서 모든 속성을 올바르게 매핑하는 등 새로운 모듈형 타겟 시스템의 견고한 기반을 제공합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/Target/Feature.swift (1)

8-35: Feature 타겟이 깔끔하게 구현되었습니다.

ImplementTarget 프로토콜을 적절히 준수하고, hasResource 플래그를 통한 조건부 리소스 처리, 그리고 정적 프레임워크 제품 타입 사용이 모듈형 아키텍처에 적합합니다. 빌더 패턴 활용도 우수합니다.

Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Builder/TargetBuilder.swift (3)

8-20: Result builder 구조체 정의가 올바릅니다.

@resultBuilder 속성과 함께 적절한 프로퍼티 선언 및 초기화가 구현되어 있습니다. 불변 프로퍼티(let)를 사용하여 타입 안전성을 보장하고 있습니다.


24-26: 빈 블록 처리가 적절합니다.

buildBlock() 메서드가 빈 초기화를 올바르게 반환하여 빈 builder 블록을 처리합니다.


53-59: ```shell
#!/bin/bash

Search for the resultBuilder annotation for TargetBuilder

rg -n "@resultBuilder" --type swift


</details>
<details>
<summary>Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/ProjectComponentBuilder.swift (3)</summary>

`8-36`: **Result builder 핵심 구현이 올바릅니다.**

타겟과 스킴을 집계하는 기본적인 result builder 메서드들이 올바르게 구현되어 있습니다. 부분 블록 결합 로직도 적절합니다.

---

`72-89`: **Project 초기화 확장이 잘 설계되었습니다.**

Builder 패턴을 활용한 declarative한 프로젝트 초기화 방식이 매우 깔끔합니다. 기본값들도 적절히 설정되어 있습니다.

---

`39-41`: **TargetBuilder 변환에서 에러 처리 고려.**

`buildTarget()` 메서드 호출이 실패할 수 있는 경우를 고려해야 합니다. 해당 메서드가 예외를 던질 수 있는지 확인해주세요.


`buildTarget()` 메서드의 구현을 확인해보겠습니다:

```shell
#!/bin/bash
# buildTarget 메서드 구현 확인
ast-grep --pattern 'func buildTarget() -> Target {
  $$$
}'
Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Builder/TargetComponentBuilder.swift (3)

8-23: 다중 buildable 타입 관리가 잘 구조화되어 있습니다.

세 가지 다른 buildable 타입을 명확히 분리하여 관리하는 구조가 깔끔합니다. 초기화 메서드도 적절한 기본값을 제공합니다.


90-92: buildInfoPlist 메서드에서 배열 확장 메서드 사용.

infoPlistBuildables.buildInfoPlist() 호출에서 배열의 확장 메서드를 사용하고 있는 것 같습니다. 해당 확장이 구현되어 있는지 확인해주세요.

배열의 buildInfoPlist 확장 메서드 구현을 확인해보겠습니다:

#!/bin/bash
# 배열의 buildInfoPlist 확장 메서드 확인
rg -A 5 "extension.*Array.*InfoPlist" --type swift

85-93: ```shell
#!/bin/bash

InfoPlistBuildable 프로토콜 정의와 구현체 재검증

rg "protocol[[:space:]]+InfoPlistBuildable" -n
rg "extension[[:space:]]+.*:.*InfoPlistBuildable" -n


</details>
<details>
<summary>Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/InfoPlistBuildable/InfoPlistBuildable.swift (3)</summary>

`10-12`: **프로토콜 설계가 깔끔하고 목적에 부합합니다.**

`InfoPlistBuildable` 프로토콜의 설계가 단순하고 명확합니다. `dictionary` 프로퍼티를 통해 Info.plist 데이터를 제공하는 방식이 Tuist 4의 선언적 스타일에 잘 맞습니다.

---

`14-18`: **기본 구현이 적절합니다.**

프로토콜 확장을 통한 기본 구현이 깔끔하며, `InfoPlist.dictionary()` 생성자를 활용한 방식이 ProjectDescription API와 잘 맞습니다.

---

`20-26`: **Array 확장의 병합 로직을 검토해보세요.**

Array 확장이 여러 `InfoPlistBuildable` 항목을 병합할 수 있게 하는 것은 좋은 아이디어입니다. 다만 병합 전략에서 `{ _, new in new }`를 사용하여 나중 값이 이전 값을 덮어쓰는 방식이 의도한 동작인지 확인해보세요.

예를 들어, 같은 키를 가진 두 Info.plist 항목이 있을 때:
- 첫 번째: `["CFBundleVersion": "1.0"]`
- 두 번째: `["CFBundleVersion": "2.0"]`

현재 구현에서는 "2.0"이 최종 값이 됩니다. 이것이 의도한 동작이라면 문제없지만, 경우에 따라서는 명시적인 충돌 해결 로직이 필요할 수 있습니다.



충돌 시나리오를 테스트해보려면 다음 스크립트를 실행해보세요:

```shell
#!/bin/bash
# 설명: InfoPlistBuildable을 사용하는 다른 파일들에서 병합 로직이 어떻게 활용되는지 확인

# InfoPlistBuildable을 구현하는 구조체들을 찾아보기
ast-grep --pattern $'struct $_ {
  $$$
} 

extension $_ : InfoPlistBuildable {
  $$$
}'

# Array<InfoPlistBuildable>이 사용되는 곳 찾기
rg -A 5 "InfoPlistBuildable.*\[\]|\[.*InfoPlistBuildable.*\]"

uses: swift-actions/setup-swift@v2
with:
swift-version: "5.10"

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

공백 문자 제거 필요

YAML 파일의 여러 줄에서 후행 공백이 감지되었습니다. 이는 린팅 도구에서 오류로 표시됩니다.

다음 diff를 적용하여 후행 공백을 제거하세요:

-            
+
-        run: mise install [email protected]
+        run: mise install [email protected]
- 
+
-        run: mise use -g [email protected]
+        run: mise use -g [email protected]
-        
+
-        run: make init
+        run: make init
-        
+

Also applies to: 48-48, 51-51, 54-54

🧰 Tools
🪛 YAMLlint (1.37.1)

[error] 42-42: trailing spaces

(trailing-spaces)

🤖 Prompt for AI Agents
In .github/workflows/upload_testflight.yml at lines 42, 48, 51, and 54, there
are trailing whitespace characters that cause linting errors. Remove all
trailing spaces at the end of these lines to comply with YAML formatting
standards and avoid linting issues.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🔭 Outside diff range comments (1)
Makefile (1)

29-37: clean 대상의 ** 글로브는 기본 셸에서 동작하지 않을 수 있음

/bin/sh(make 기본 셸)에서는 globstar 옵션이 꺼져 있어 ** 패턴이 재귀 확장되지 않습니다.
불필요한 패턴을 여럿 나열하기보다 find 를 이용하면 OS와 셸 설정에 독립적입니다.

-clean:
-	rm -rf **/**/**/*.xcodeproj
-	rm -rf **/**/*.xcodeproj
-	rm -rf **/*.xcodeproj
-	rm -rf *.xcworkspace
-	rm -rf **/**/**/Derived/
-	rm -rf **/**/Derived/
-	rm -rf **/Derived/
-	rm -rf Derived/
+clean:
+	@echo "Removing *.xcodeproj, *.xcworkspace, DerivedData…" ;\
+	find . -name "*.xcodeproj" -prune -exec rm -rf {} + ;\
+	find . -name "*.xcworkspace" -prune -exec rm -rf {} + ;\
+	find . -type d -name "DerivedData" -prune -exec rm -rf {} +
🧹 Nitpick comments (1)
Makefile (1)

39-41: update_tuist 대상: 스크립트 실패 시 Make가 성공으로 종료될 수 있음

sh ./Scripts/update_tuist.sh 내부에서 오류가 발생해도 set -e가 없으면 Make는 성공(exit 0)으로 판단합니다.
스크립트 선두에 set -euo pipefail 추가하거나, Make 쪽을 다음과 같이 수정해 오류 전파를 확실히 해주세요.

-update_tuist:
-	sh ./Scripts/update_tuist.sh
+update_tuist:
+	bash -euo pipefail ./Scripts/update_tuist.sh
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5c2aa1 and dd5ba0b.

📒 Files selected for processing (3)
  • Makefile (2 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/AppScheme.swift (1 hunks)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/InterfaceTarget.swift (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/TargetBuildable/TargetInterface/InterfaceTarget.swift
  • Plugins/EnvironmentPlugin/ProjectDescriptionHelpers/Buildable/SchemeBuildable/Scheme/AppScheme.swift
🧰 Additional context used
🪛 checkmake (0.2.2)
Makefile

[warning] 12-12: Target body for "getig" exceeds allowed length of 5 (15).

(maxbodylength)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build_test
🔇 Additional comments (1)
Makefile (1)

48-50: clean_xcode_cache의 전면 삭제는 위험 – 사용자 확인 또는 경로 제한 권장

~/Library/Developer/Xcode/DerivedData/* 전체를 지우면 다른 Xcode 프로젝트의 캐시까지 모두 삭제됩니다.
CLI 툴에서 예상치 못한 데이터 손실을 방지하려면

  • 경로를 현재 프로젝트 전용 하위 폴더로 한정
  • read -p "…[y/N]" 확인 절차 추가
  • 또는 xcodebuild -deleteDerivedData 사용

등을 고려해 주세요.

Makefile Outdated
Comment on lines 12 to 27
getig:
@echo "Git 토큰을 어디서 불러올까요?"
@echo " 1) global"
@echo " 2) local"
@read -p "Enter choice [1 or 2]: " choice; \
if [ "$$choice" = "1" ]; then \
echo "Using GITHUB_ACCESS_TOKEN from global config"; \
GITHUB_ACCESS_TOKEN=$$(git config --global user.password); \
elif [ "$$choice" = "2" ]; then \
echo "Using GITHUB_ACCESS_TOKEN from local config"; \
GITHUB_ACCESS_TOKEN=$$(git config user.password); \
else \
echo "Invalid choice: $$choice. Aborting..."; \
exit 1; \
fi; \
$(MAKE) download-privates token=$$GITHUB_ACCESS_TOKEN
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

getig 대상의 상호작용·보안·유지보수 문제

  1. CI/자동화 환경에서 read 프롬프트가 블로킹되어 흐름이 중단됩니다.
  2. 토큰을 git config user.password에 저장‧불러오는 방식은 평문 노출 위험이 큽니다.
  3. 토큰이 비어 있을 때의 예외 처리(404/401)에 대한 방어 로직이 없습니다.
  4. 본문 길이가 15 줄로 checkmake 경고(maxbodylength=5)에 걸립니다.

반드시 스크립트(예: Scripts/get_token.sh)로 분리하고,
무조건 비대화(non-interactive) 방식 + 필수 입력 검증 + 최소 권한 토큰 사용으로 교체하시길 권장합니다.

-getig:
-	@echo "Git 토큰을 어디서 불러올까요?"
-	@echo " 1) global"
-	@echo " 2) local"
-	@read -p "Enter choice [1 or 2]: " choice; \
-	if [ "$$choice" = "1" ]; then \
-	  GITHUB_ACCESS_TOKEN=$$(git config --global user.password); \
-	elif [ "$$choice" = "2" ]; then \
-	  GITHUB_ACCESS_TOKEN=$$(git config user.password); \
-	else \
-	  echo "Invalid choice: $$choice. Aborting..."; \
-	  exit 1; \
-	fi; \
-	$(MAKE) download-privates token=$$GITHUB_ACCESS_TOKEN
+getig:
+	@./Scripts/get_token.sh | xargs -I{} $(MAKE) --no-print-directory download-privates token="{}"
🧰 Tools
🪛 checkmake (0.2.2)

[warning] 12-12: Target body for "getig" exceeds allowed length of 5 (15).

(maxbodylength)

🤖 Prompt for AI Agents
In the Makefile from lines 12 to 27, the getig target uses an interactive read
prompt which blocks CI/automation, stores tokens insecurely in git config, lacks
validation for empty tokens, and is too long. To fix this, move the token
retrieval logic into a separate script (e.g., Scripts/get_token.sh) that
operates non-interactively, validates the presence of a token input, uses
environment variables or secure vaults for token storage instead of git config,
and ensure the token has minimal required permissions. Then update the Makefile
to call this script and pass the token securely to the download-privates target.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
Makefile (1)

9-16: sign 타겟: 토큰 평문 저장 및 과도한 바디 길이 문제 재발

git config user.password(혹은 global) 에 토큰을 그대로 저장‧재사용하는 방식은 여전히 평문 노출 위험이 있습니다.
또한 7 라인으로 checkmake maxbodylength=5 경고가 반복됩니다. 이미 지난 리뷰에서 동일 지적이 있었으니 스크립트 분리 + 최소 권한 토큰 + 비대화·비노출 방식으로 교체하시기 바랍니다.

-sign:
-	@GIT_TOKEN=$$(git config user.password || git config --global user.password); \
-	if [ -z "$$GIT_TOKEN" ]; then \
-		echo "❌ Git token not found."; \
-		exit 1; \
-	fi; \
-	$(MAKE) download-privates token=$$GIT_TOKEN && \
-	fastlane sync
+sign:
+	@$(eval GIT_TOKEN := $(shell ./Scripts/get_token.sh))
+	$(MAKE) --no-print-directory download-privates token="$(GIT_TOKEN)" && \
+	fastlane sync

Scripts/get_token.sh

  1. 환경변수·시크릿 매니저 우선
  2. 없으면 fail fast
  3. stdout 로 토큰만 출력
    으로 작성하면 됩니다.
    이렇게 하면 CI 블로킹·보안·checkmake 경고를 한 번에 해결할 수 있습니다.
🧹 Nitpick comments (1)
Makefile (1)

18-26: clean 타겟: 글로브 패턴이 과도하게 중복됨

**/**/**/*.xcodeproj**/*.xcodeproj 하나면 충분하며,
rm -rf 다중 호출은 I/O 비용만 증가시킵니다. find 한 번으로 처리하거나 xargs 병렬 삭제를 고려해 주세요.

-clean:
-	rm -rf **/**/**/*.xcodeproj
-	rm -rf **/**/*.xcodeproj
-	rm -rf **/*.xcodeproj
+clean:
+	find . -name '*.xcodeproj' -prune -exec rm -rf {} +

실수로 불필요한 상위 디렉터리까지 지우지 않도록 -depth 2 등 범위를 명시하면 더 안전합니다.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between dd5ba0b and 848db28.

📒 Files selected for processing (1)
  • Makefile (2 hunks)
🧰 Additional context used
🪛 checkmake (0.2.2)
Makefile

[warning] 9-9: Target body for "sign" exceeds allowed length of 5 (7).

(maxbodylength)

⏰ Context from checks skipped due to timeout of 90000ms (1)
  • GitHub Check: build_test
🔇 Additional comments (1)
Makefile (1)

28-29: update_tuist 스크립트 실행 권한 확인 필요

sh ./Scripts/update_tuist.sh 호출 전, CI 환경에서 실행 권한이 보장되지 않으면 permission denied 가 발생할 수 있습니다.
chmod +x 를 저장소에 커밋하거나, 여기서 bash -e 로 직접 실행하도록 수정하는 것을 권장합니다.

Comment on lines +43 to 46
@echo "📥 Downloading $(3) to $(1)"
mkdir -p $(1)
curl -H "Authorization: token $(2)" -o $(1)/$(3) $(BASE_URL)/$(3)
curl -sS -H "Authorization: token $(2)" -o $(1)/$(3) $(BASE_URL)/$(3)
endef
Copy link

@coderabbitai coderabbitai bot Jun 25, 2025

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

❓ Verification inconclusive

curl 호출 시 프로세스 리스트에 토큰 노출 가능

curl -H "Authorization: token $(2)" 방식은 실행 중인 프로세스 목록에 토큰이 그대로 찍힐 수 있습니다.
--header @"$(tmpfile)" 패턴이나 GITHUB_TOKEN 환경변수를 활용해 헤더 파일/환경변수로 우회하면 노출을 막을 수 있습니다.

-	curl -sS -H "Authorization: token $(2)" -o $(1)/$(3) $(BASE_URL)/$(3)
+	@echo "Authorization: token $(2)" > /tmp/.gh_hdr_$$
+	curl -sS -H @/tmp/.gh_hdr_$$ -o $(1)/$(3) $(BASE_URL)/$(3)
+	rm -f /tmp/.gh_hdr_$$

혹은:

	curl -sS -H "Authorization: token $(GITHUB_TOKEN)" ...

처럼 토큰을 환경변수로 전달하고, Make 호출부에서 export GITHUB_TOKEN=... 로 주입하는 방법도 고려해 보세요.


curl 호출 시 프로세스 리스트에 토큰 노출 가능

curl -H "Authorization: token $(2)" 방식은 실행 중인 프로세스 목록에 토큰이 그대로 찍힐 수 있습니다.
--header @"$(tmpfile)" 패턴이나 GITHUB_TOKEN 환경변수를 활용해 헤더 파일/환경변수로 우회하면 노출을 막을 수 있습니다.

-	curl -sS -H "Authorization: token $(2)" -o $(1)/$(3) $(BASE_URL)/$(3)
+	@echo "Authorization: token $(2)" > /tmp/.gh_hdr_$$
+	curl -sS -H @/tmp/.gh_hdr_$$ -o $(1)/$(3) $(BASE_URL)/$(3)
+	rm -f /tmp/.gh_hdr_$$

혹은:

	curl -sS -H "Authorization: token $(GITHUB_TOKEN)" ...

처럼 토큰을 환경변수로 전달하고, Make 호출부에서 export GITHUB_TOKEN=... 로 주입하는 방법도 고려해 보세요.

🤖 Prompt for AI Agents
In the Makefile around lines 43 to 46, the curl command includes the
authorization token directly in the command line, which can expose the token in
the process list. To fix this, avoid passing the token as a command argument;
instead, store the header in a temporary file and use curl's --header @file
option, or pass the token via an environment variable like GITHUB_TOKEN and
reference it in the curl command header. Also, ensure the token is exported in
the environment before running the Makefile.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@MUKER-WON @isakatty 귀찮아서 나중에 다시 볼게요..ㅋㅋ

Copy link

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

@gnksbm
Copy link
Contributor Author

gnksbm commented Jun 25, 2025

@MUKER-WON @isakatty
추가된 작업은 커밋별로 확인 권장드리고 아래 간단한 요약도 참고 부탁드려요~

수정사항 간단 요약

  1. make sign 커멘드를 추가하였고 ignore 갱신과 인증서 갱신을 동시에 수행합니다.
  2. 빌드 오류가 발생해 몇가지 수정하였습니다.
  3. 파베 로깅이 너무 많이 남는 것이 개발에 불편함이 있을 것으로 예상되어 최소화하였습니다.
  4. FCM 토큰 로직에 문제가 있어 수정하였습니다.
  5. 로띠 의존성이 중복으로 발생하여 임시 수정하였고 추후 재정비 예정입니다.

@gnksbm gnksbm merged commit 32faeb0 into dev Jun 25, 2025
2 checks passed
@gnksbm gnksbm deleted the fix/#319 branch June 25, 2025 16:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Setting] Tuist 버전 마이그레이션

4 participants