Tuist 배포 환경별 Configuration Setting 하기

Jenny·2023년 12월 1일

TMI : 디프만 프로젝트에서 배포 환경을 DEV, PRD에 따른 서버 URL 및 테스트 환경을 나눠야 하는 기회가 생겨서 Tuist를 통해 배포 환경을 설정할 수 있는 좋은 기회를 얻게 되었다!! :)

⚙️ Configuration

  • DEV,STAG,PROD 등의 배포 환경을 분리할때 Configuration을 활용하여 세팅 합니다.
  • 처음 프로젝트를 생성하게 되면 기본으로 제공되는 ConfigurationDebug, Release입니다.
  • Configuration을 통해 특정 배포 환경에 따른 서버 End Point, Base URL, API KEY, Environment Variable을 다르게 설정 할 수 있습니다.

Tuist 배포 환경 나누기

저희는 서버 Base URLDEV, PRD로 구분되어 있기에 DEV, PRD 배포 환경으로 나눴습니다.

ConfigurationName Setting Code

  • 별도 ConfigurationName+Templates.swift를 추가하여 배포 환경에 따른 네이밍을 설정하는 코드를 추가하였습니다..
  • ConfigurationNameProjectDescription에서 제공되기에 enum에서 설정해놓은 값Computed Property를 활용하여 설정하였습니다.
public enum BuildTarget: String {
    case dev = "DEV"
    case prd = "PRD"
    
    public var configurationName: ConfigurationName {
        return ConfigurationName.configuration(self.rawValue)
    }
    
}

Configuration Setting Code

  • Configuration 역시 ProjectDescription 내부에서 제공되기에 extension을 활용하여 내부에 타입 메서드로 구현된 build 메서드를 사용하여 각 배포 환경에 따라 Configuration을 생성하도록 구현 하였습니다.
extension Configuration {
    public static func build(_ type: BuildTarget, name: String = "") -> Self {
        let buildName = type.rawValue
        switch type {
        case .dev:
            return .debug(
                name: BuildTarget.dev.configurationName,
                xcconfig: .relativeToXCConfig(type: .dev)
            )
        case .prd:
            return .release(
                name: BuildTarget.prd.configurationName,
                xcconfig: .relativeToXCConfig(type: .prd)
            
            )
        }
    }
}

xcconfig File path Setting Code

  • 저희는 Xcode 상에 xcconfig File을 추가해야 하며 각 Configuration 설정을 할때 동시에 xcconfig파일의 경로를 알려줘야 합니다.
  • 저는 Pathextenion을 활용하여 내부에 타입 메서드를 별도로 구현하여 relativeToXCConfig 메서드를 구현하였습니다.
extension Path {
    public static func relativeToXCConfig(type: BuildTarget) -> Self {
        return .relativeToRoot("./14th-team5-iOS/XCConfig/\(type.rawValue.lowercased()).xcconfig")
    }
}

Dependencies Configuration Settings

  • 만약 Tuist에서 third party Library의 의존성을 가져오고 있는 경우에는 Dependencies.swift 파일에서도 Configuration을 추가해야 합니다.
  • 외부 라이브러리에서도 기본적으로 Debug, Release를 Configuration으로 제공되고 있기때문에 실제 저희가 Setting한 Configuration을 매칭 시키지 않을 경우 mismatching configurations 오류가 발생 할 수 있습니다.
let dependencies = Dependencies(
    swiftPackageManager: SwiftPackageManagerDependencies([
        .alamofire,
        .reactorKit,
        .rxSwift,
        .snapkit,
        .then,
        .firebase
    ],baseSettings: .settings(
        configurations: [
            .build(.dev),
            .build(.prd)
        ]
    )
    
    ),
    platforms: [.iOS]
)

Scheme Settings Code

  • Scheme는 Build 될때 어떤 Configuration을 사용할지와 Build Target을 할지를 정의 합니다 때문에 Scheme을 만들어서 배포 환경에 따라 run Action, ConfigurationName등을 설정 해줘야 합니다.
  • Scheme 같은 경우 배포 환경 DEV, PRD 값에 맞게 추가를 해줘야 하기 때문에 배포 환경이 2개가 되면 Scheme도 2개를 추가해줘야 합니다.
  • 저는 Schemeextension을 활용하여 내부에 타입 메서드를 별도로 구현하여 Scheme를 배포 환경에 따라 BuildAction, runAction, archiveAction, profileAction, analyzeAction 등을 세팅하고 생성하는 형식으로 구현 하였습니다.
extension Scheme {
    
    public static func makeScheme(_ type: BuildTarget, name: String) -> Self {
        let buildName = type.rawValue
        switch type {
        case .dev:
            return Scheme(
                name: "\(name)-\(buildName.uppercased())",
                buildAction: BuildAction(targets: ["\(name)"]),
                runAction: .runAction(configuration: type.configurationName),
                archiveAction: .archiveAction(configuration: type.configurationName),
                profileAction: .profileAction(configuration: type.configurationName),
                analyzeAction: .analyzeAction(configuration: type.configurationName)
            )
        case .prd:
            return Scheme(
                name: "\(name)-\(buildName.uppercased())",
                buildAction: BuildAction(targets: ["\(name)"]),
                runAction: .runAction(configuration: type.configurationName),
                archiveAction: .archiveAction(configuration: type.configurationName),
                profileAction: .profileAction(configuration: type.configurationName),
                analyzeAction: .analyzeAction(configuration: type.configurationName)
            )
        }
    }
}

Project에 모든 Code 적용

  • 마지막으로 저희가 생성한, Scheme, Configuration 등을 Project에 추가하면 Tuist Setting은 끝입니다.
extension Project {
    public static func makeApp(name: String, target: [Target]) -> Project {
        return Project(
            name: name,
            settings: .settings(
                configurations: [
                    .build(.dev, name: name),
                    .build(.prd, name: name)
                ]
            ),
            targets: target,
            schemes: [
                .makeScheme(.dev, name: name),
                .makeScheme(.prd, name: name)
            ],
            additionalFiles: [
                "../XCConfig/shared.xcconfig"
            ]
        )
    }
    
    
}

⚒️ xcconfig Setting 작업

  • 저희는 Tuist에 Setting 작업을 진행하였습니다. 이제 마지막으로 dev.xcconfig, prd.xcconfig, shared.xcconfig 파일을 하나씩 만들어 줍니다.
  • 이 모든 파일은 relativeToXCConfig Method 경로에 맞게 설정을 해야하니 참고 해주시기 바랍니다. -> 만약 다르게 설정하고 싶으면 relativeToXCConfig 수정 하시면 됩니다.

shared.xcconfig Setting

OTHER_SWIFT_FLAGS[config=DEV][sdk=*] = $(inherited) -DDEV
OTHER_SWIFT_FLAGS[config=PRD][sdk=*] = $(inherited) -DPRD

prd.xcconfig, dev.xcconfig

#include "../XCConfig/shared.xcconfig"
  • prd.xcconfig 의 #include을 사용한 이유는 shared.xcconfig의 코드를 모두 적용하기 위해서 #include "../XCConfig/shared.xcconfig" 추가 하였습니다. 만약 저 코드를 추가하지 않으면 모든 prd.xcconfig, dev.xcconfig에 추가하기 때문에 가독성 측면상 좋지 않겠죠??

📝 참고 사이트

profile
"Jenny 있게 iOS 개발을 하며 대체 불가능한 인재가 되자"

0개의 댓글