ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Tuist의 Configuration 설정하기
    Tuist 2023. 5. 18. 14:06

    안녕하세요. 그린입니다🍏

    이번 포스팅에서는 Tuist의 Configuration을 알아보고 각 개발 환경을 분리하여 설정해보도록 하겠습니다🙌

     

    들어가기 전 필요 개발 환경 체크

    기본적으로 프로젝트는 DEBUG와 RELEASE의 flag 즉, build configuration을 가지게 되는데요.

    각자 만들고 있는 프로젝트의 성향에 따라 다르겠지만 여기서 QA configuration도 추가하여 사용될 수 있습니다.

    실제 저는 총 3개의 configuration을 설정하는데요.

    하나는 내부 개발의 배포를 위한 DEV, 또 하나는 실제 프로덕트 출시 전 QA를 위한 QA, 마지막으로 실제 상용 배포를 위한 RELEASE로 나눌 수 있습니다.

     

    자, 그럼 이 3개의 configuration을 Tuist를 통해 어떻게 각 배포 환경을 줄 수 있는지 같이 해보시죠🕺🏻

     

    Tuist를 통해 Configuration 설정하기

    먼저 앱을 구성하는 모듈이 되는 프로젝트 타겟 설정에서 아래와 같이 QA / DEBUG / RELASE의 configuration을 설정해줍니다.

    let project = Project.make(
      name: "GREENUI",
      targets: [
        .make(
          name: "GREENUI",
          product: .framework,
          bundleId: "com.green.GREENUI",
          sources: ["Sources/**"],
          resources: ["Resources//**"],
          dependencies: [
          ]
        )
      ],
      // 요 부분에서 설정
      settings: .settings(
        configurations: [
          .debug(name: .debug),
          .debug(name: "QA"),
          .release(name: .release)
        ]
      )
    )

    기본적으로 debug와 release는 제공되지만 QA / STAGE / DEV와 같이 이 외 별도로 필요한 빌드 설정은 직접 넣어줍니다.

     

    그 다음으로 실제 총 관여할 앱 프로젝트에서 configuration을 주기전 Dependency에서도 설정이 필요하기에 한번 해볼까요?

     

    만약 외부 라이브러리를 사용하고 있다면 Dependecies 파일에서도 configuration을 설정해줘야 합니다.

    그 이유는 외부 라이브러리들은 기본적으로 DEBUG / RELEASE의 configuration만 설정되어 있기에 실제 QA configuration을 부여해주지 않으면 아래와 같이 해당 라이브러리가 가진 configuration은 DEBUG / RELASE인데 우리 앱 프로젝트에서는 QA까지 총 3개를 사용하고 있어 미스매칭이 되고 있다는 오류가 납니다.

    Warning: The project 'Get' has missing or mismatching configurations. It has [Debug (debug), Release (release)], other projects have [DEBUG(debug), QA(debug), RELEASE(release)]

     

    그렇기에 이 설정도 아래와 같이 해줘야 해요!

     

    import ProjectDescription
    import ProjectDescriptionHelpers
    
    let dependencies = Dependencies(
      swiftPackageManager: SwiftPackageManagerDependencies(
        [
          ...
          .remote(
            url: "https://github.com/firebase/firebase-ios-sdk.git",
            requirement: .exact("10.0.0")
          ),
          .remote(
            url: "https://github.com/airbnb/lottie-spm.git",
            requirement: .exact("4.1.3")
          ),
          .remote(
            url: "https://github.com/AppsFlyerSDK/AppsFlyerFramework.git",
            requirement: .exact("6.5.0")
          ),
          .remote(
            url: "https://github.com/kean/Get.git",
            requirement: .exact("2.1.1")
          ),
          ...
        ],
        // 요 부분에서 마찬가지로 설정
        baseSettings: .settings(
          configurations: [
            .debug(name: .debug),
            .debug(name: "QA"),
            .release(name: .release)
          ]
        )
      ),
      platforms: [.iOS]
    )

    SPM의 baseSettings 옵션을 활용해 동일하게 configuration을 설정해줍니다.

     

    마지막으로 최종적인 앱의 프로젝트 파일을 건드려 볼까요?

     

    아래와 같이 Project 파일을 실제 배포환경에 맞게 Dev / QA / PROD로 구성할 수 있습니다.

    let project = Project.make(
      name: "GREENAPP",
      targets: [
      
        // QA 타겟
        .make(
          name: "QA-GREENAPP",
          product: .app,
          bundleId: "com.green.qa",
          infoPlist: .file(path: .relativeToRoot("GREENAPP/Info.plist")),
          sources: ["Sources/**"],
          entitlements: .relativeToRoot("GREENAPP/Resources/QA/GREENAPP.entitlements"),
          dependencies: [
          ],
          settings: .settings(
            configurations: [
              .debug(name: "QA", xcconfig: "./xcconfigs/green.qa.xcconfig")
            ]
          )
        )
        
        // DEV 타겟
        .make(
          name: "DEV-GREENAPP",
          product: .app,
          bundleId: "com.green.dev",
          infoPlist: .file(path: .relativeToRoot("GREENAPP/Info.plist")),
          sources: ["Sources/**"],
          entitlements: .relativeToRoot("GREENAPP/Resources/DEV/GREENAPP.entitlements"),
          dependencies: [
          ],
          settings: .settings(
            configurations: [
              .debug(name: .debug, xcconfig: "./xcconfigs/green.dev.xcconfig")
            ]
          )
        )
        
        // PROD 타겟
        .make(
          name: "PROD-GREENAPP",
          product: .app,
          bundleId: "com.green.prod",
          infoPlist: .file(path: .relativeToRoot("GREENAPP/Info.plist")),
          sources: ["Sources/**"],
          entitlements: .relativeToRoot("GREENAPP/Resources/PROD/GREENAPP.entitlements"),
          dependencies: [
          ],
          settings: .settings(
            configurations: [
              .debug(name: .release, xcconfig: "./xcconfigs/green.prod.xcconfig")
            ]
          )
        )
      ],
      
      // 해당 Project configuration 설정
      settings: .settings(
        configurations: [
          .debug(name: .debug),
          .debug(name: "QA"),
          .release(name: .release)
        ]
      ),
      additionalFiles: [
        "./xcconfigs/green.shared.xcconfig"
      ]
    )

    이런식으로 각 배포환경에 맞게 타겟을 분리하고 해당 타겟에서 사용할 수 있는 configuration을 담아줍니다.

    그리고 해당 프로젝트 전체적으로 configuration을 Debug / QA / Release를 구성해주면 됩니다.

     

    여기서 마지막으로 짚어보면서 설정해야할 부분이 있어요🙋🏻
    바로 xcconfig 부분입니다.

     

    실제 xcconfig 파일은 해당 프로젝트 내 경로에 만들어주고 각 qa / dev / prod로 분리하여 configuration 별로 해당하는 빌드 설정을 해주는 용도로 사용됩니다.

    즉, 아래와 같이 우선적으로 xcconfig 파일을 만듭니다.

     

    여기서 shared.xcconfig 파일에는 releas/qa/dev 공통적으로 들어갈 설정을 넣어줍니다.

    MARKETING_VERSION=2.3.0
    CURRENT_PROJECT_VERSION=135
    DEVELOPMENT_TEAM=BLABLA
    마켓팅 버전 및 빌드 넘버 그리고 해당 앱의 개발팀 ID 값이 들어갈 수 있겠죠?

     

    그 다음으로 각 release/qa/debug에 각자 configuration 설정을 위해 아래와 같은 코드를 매칭하여 추가해줍니다.

    #include "./green.shared.xcconfig"
    
    // dev.xcconfig에서 추가
    OTHER_SWIFT_FLAGS[config=DEBUG][sdk=*] = $(inherited) -DDEBUG
    
    // qa.xcconfig에서 추가
    OTHER_SWIFT_FLAGS[config=QA][sdk=*] = $(inherited) -DQA
    
    // prod.xcconfig에서 추가
    OTHER_SWIFT_FLAGS[config=RELEASE][sdk=*] = $(inherited) -DRELEASE

    각 배포 환경별로 Swift Flag를 심어주는 역할을 해줍니다.

     

    그럼 이제 모든게 끝났습니다!

     

    실제로 하나 더 나아가서 Workspace를 만들때 Dev / QA / Prod configuration으로 스킴을 분리하고 사용할 수 있음으로 아래와 같이 Workspace 설정을 구현해줍니다.

     

    import ProjectDescription
    
    let workspace = Workspace(
      name: "GREEN",
      projects: [
        "GREENAPP",
        "GREENUI",
      ],
      schemes: [
        Scheme(
          name: "Prod-GREEN",
          buildAction: .buildAction(targets: [.project(path: "./GREENAPP", target: "Prod-GREENAPP")]),
          runAction: .runAction(configuration: .release),
          archiveAction: .archiveAction(configuration: .release),
          profileAction: .profileAction(configuration: .release),
          analyzeAction: .analyzeAction(configuration: .release)
        ),
        Scheme(
          name: "Dev-GREEN",
          buildAction: .buildAction(targets: [.project(path: "./GREENAPP", target: "Dev-GREENAPP")]),
          runAction: .runAction(configuration: .debug),
          archiveAction: .archiveAction(configuration: .debug),
          profileAction: .profileAction(configuration: .debug),
          analyzeAction: .analyzeAction(configuration: .debug)
        ),
        Scheme(
          name: "QA-GREEN",
          buildAction: .buildAction(targets: [.project(path: "./GREENAPP", target: "QA-GREENAPP")]),
          runAction: .runAction(configuration: "QA"),
          archiveAction: .archiveAction(configuration: "QA"),
          profileAction: .profileAction(configuration: "QA"),
          analyzeAction: .analyzeAction(configuration: "QA")
        ),
      ],
      generationOptions: .options(autogeneratedWorkspaceSchemes: .disabled)
    )

     

    요렇게 흐름순으로 구성을 해준다면 실제 스킴별로 테스트 및 배포를 보다 수월하게 할 수 있게 되며 목적에 따라 분리가 명확해집니다😃

     

    마무리

    각 배포 환경별 빌드 설정은 프로덕트를 만들다 보면 꼭 필요한 부분인데 이또한 Tuist를 통해 아주 쉽게 설정할 수 있는걸 알아본 좋은 경험이였습니다🙌

Designed by Tistory.