Xcode Cloud – 2. 사례 중심 디테일

들어가며…

앞 서 작성한 글에서는 Xcode Cloud 에 관련한 아주 기본적인 설정을 알아보았습니다. 사실 바로 사례 중심의 글을 적을까하다가 리마인드 겸 작성하였습니다.

이번에는 제가 직접 프로젝트에 설정하면서 겪은 사례 중심으로 조금 더 디테일한 설정 방법을 적어보려 합니다.

Package.resolved

현재 제가 담당하고 있는 프로젝트의 경우 여러 Swift Package 들을 automatic resolving 형태로 관리하고 있었습니다. 즉, resolving 후 생성되는 Package.resolved 파일을 SCM에 등록하지 않고 로컬에만 존재하게 했었습니다.

그러다가 Xcode Cloud 를 처음 설정할 때 가장 먼저 만난 이슈는 이 automatic resolving 때문에 발생한 빌드 실패였습니다. 같은 환경 아닌가? 혹시 사용하고 있는 Swift Package 들의 dependency 문제인가 싶어 로그들을 찬찬히 살펴봤습니다만 로컬과 다르지 않은 듯 하였고 로컬에서는 문제없는 것을 확인했습니다.

그러다가 정석대로 Xcode Cloud 문서를 보게 되었는데 거기에는 아래와 같은 구절이 있습니다.

Use Swift package dependencies and Git submodules

Following the best practice for using Swift package dependencies in a CI/CD environment, Xcode Cloud doesn’t use automatic package resolution and instead relies on the Package.resolved file to resolve your dependencies. If you use Swift package dependencies in your project, make sure to include the Package.resolved file in your Git repository and commit any changes to it. Don’t include the file in your .gitignore file. Additionally, make sure the the Package.resolved file resides at $filename.xcodeproj/project.workspace/xcshareddata/swiftpm/Package.resolved.

https://developer.apple.com/documentation/xcode/making-dependencies-available-to-xcode-cloud

요약하자면, Package.resolved 파일은 gitignore 에 등록하지 말고 SCM에 포함되게 하라는 내용입니다.

문서를 조금 더 보다보면 이 이유에 대해서 아래와 같이 서술되어 있습니다.

Use the Expected Version of a Package Dependency

To ensure the CI workflow’s reliability, make sure it uses the appropriate version of package dependencies. Xcode stores the exact version of each package dependency in a file called Package.resolved. The file automatically updates when package requirements in your Xcode project or in the Package.swift manifest file change. Commit this file to your Git repository to ensure it’s always up-to-date on the CI environment to prevent the CI from building your project with unexpected versions of package dependencies.

https://developer.apple.com/documentation/xcode/building-swift-packages-or-apps-that-use-them-in-continuous-integration-workflows

역시 요약하자면, Automatic Resolving 을 이용하면 CI 에서 빌드될 때 SPM으로 관리되는 패키지의 버전이 달라질 수 있고 그렇게 빌드가 되거나 아카이브가 되면 원했던 결과와 정확하지 않기 때문이라고 합니다.

이 Package.resolved 파일의 위치는 [AppName].xcodeproj/project.xcworkspace/xcsharedata/swiftpm/ 에 존재합니다.

Private Repository

프로젝트를 진행하다보면 간혹 Private repository 의 Package를 이용하거나 submodule 로 두거나 할 수 있습니다. 제가 맡은 프로젝트도 프로젝트 외에 딱 하나의 private repository 가 있는데 첫 빌드 때 이 때문에 빌드가 깨졌다고 언급했었습니다.

이 때는 Xcode Cloud 대시보드의 해당 빌드 상세 화면 상단에 노란색 배경의 문구가 나타나는데 포털로 이동하기 버튼을 누르면 쌩뚱맞게도 개발자 포털로 이동해버립니다. 이 때는 AppStore Connect 의 Xcode Cloud 로 이동하셔서 설정 -> 저장소를 가보시면 추가 저장소에 문제의 repository 가 나타날 것입니다.

거기서 권한을 부여해주고 다시 빌드를 하시면 됩니다.

Xcode Cloud settings in AppStore Connect

워크플로 사이에 특정 작업 수행하기

Bitrise 의 경우 여러 워크플로 플러그인을 제공하여 조립하는 것처럼 워크플로를 완성했지만, 앞서 글에서 살펴본 것 처럼 Xcode Cloud 에서는 정해진 워크플로만 설정할 수 있습니다. 대신, 특정 단계 사이에 스크립트를 실행할 수 있도록 하고 있습니다. 이 정도만해도 충분하다고 생각하는거겠죠? 애플답게 말이죠..

모든 단계 사이가 아닌 3 구간에 스크립트를 정의할 수 있는데 아래 이미지처럼 소스코드를 가져온 후, 빌드 전, 빌드 후입니다. (아래 이미지는 https://developer.apple.com/documentation/xcode/writing-custom-build-scripts 에서 확인하실 수 있습니다.)

Execution workflow with scripts

이 스크립트를 실행하도록 하기 위해서는 지켜야 하는 룰이 있습니다. 프로젝트 내에 ci_scripts 이름의 폴더가 존재해야 하고, 단계별로 지정된 스크립트 이름을 사용해야하며, chmod 를 통해 실행 속성을 부여하여야 합니다.

단계 별 스크립트 이름은 아래와 같습니다.

  1. ci_post_clone.sh : Xcode Cloud 에서 소스 코드를 가져온 후
  2. ci_pre_xcodebuild.sh : 소스 코드를 가져와 빌드를 위한 전처리가 끝난 후 xcodebuild 가 수행되기 전
  3. ci_post_xcodebuild.sh : xcodebuild 가 끝난 후

보통 소스코드를 가져온 후에는 필요한 환경을 설정하고, xcodebuild 가 실행되기 전에는 특정 파일의 이동 및 배치 등의 행위가 수행될테고, xcodebuild 가 수행된 이후에는 code coverage 등 보고서 작성을 위한 행위가 수행될 것입니다. 생각해보니 이 정도도 충분하다 싶네요.

기본 쉘은 zsh 로 Xcode 에서 쉘 스크립트 새 파일을 생성하면 bash 로 설정되어 있으니 되도록 수정하세요. 쉘 스크립트를 복잡하게 쓰지 않는 이상 큰 지장은 없습니다만 로그에 보면 경고가 나옵니다.

Shell script for Xcode Cloud

한 가지 더 재밌는 것은,

Xcode Cloud 에서 사용되는 instance는 macOS 입니다. 애플에서는 친절하게도 brew 를 기본제공해주고 있습니다. 애플에서도 이제 표준으로 인정하는 오픈소스 도구인 것 같습니다.

대신, 기본으로 내장되어 있는 brew의 패키지들이 최신화가 되어 있지 않거나 축소된 패키지만을 가지고 있는지 제가 설치하려는 패키지는 제공되고 있지 않아 어쩔 수 없이 brew update 를 했는데 빌드 시간이 확 늘어나네요…

스크립트를 만드셨다고 바로 commit 하고 돌아가라~ 빌면 오류를 만나실 수 있습니다. 앞에서도 언급한 것처럼 꼭 chmod +x ci_* 처럼 추가한 스크립트 파일에 실행 속성을 주시고 commit 하셔야 합니다.

Xcode Cloud 환경

스크립트를 만들고 또 push 해서 로그 확인하고 하다보니 문득 Xcode Cloud 환경이 궁금했습니다.

그래서 macOS 에서 시스템 환경을 확인할 수 있는 명령어 두 개를 넣어서 돌려봤습니다.

system_profiler SPSoftwareDataTypeuname - av 이며 결과는 아래 이미지에서 확인하세요. Xcode Cloud Server Instance 는 macOS 이며, X86_64 환경입니다. (M1인 arm64가 아닌게 의아하네요)

Xcode Cloud Server Instance Environments

LFS 지원

제가 담당하는 프로젝트에서는 용량이 큰 파일이 SCM 이 포함되어 있지 않지만 문서를 살펴보다보니 LFS 는 현재 Xcode Cloud에서 지원하지 않는다고 합니다.

마치며…

하루에 하나씩 적으려다가 제 머리를 믿지 못하여 두 번째 글도 바로 이어 작성했습니다. 글로 적으니 내가 왜 삽질을 그렇게 했을까 자책을 하게 되네요. 특히 첫 번째 Package.resolved 내용처럼 automatic resolving 이 왜 안되는지 의아해하며 삽질을 많이 했던 것 같습니다. 나이 들었으면 메뉴얼부터 숙독하고 실행하는 느긋함을 가져야 할텐데 여전히 일단 해보자 정신이 몸과 정신을 해롭게 많드네요.

다음 연재 글은 1편에서도 예고했다시피 Xcode Cloud 에 danger-swift 를 적용하는 내용입니다. 이를 적용하느라 꼬박 하루가 걸렸던 것 같습니다. 잘 정리해서 작성하도록 할게요.

아래 이미지는 PR 이 올라왔을 때 설정한 조건에 의해 Xcode Cloud 가 빌드 및 테스팅을 마치고 남겨놓은 흔적입니다. (warning은 대부분 리팩토링을 위해 #warning 플래그를 임의로 달아둔거라… 많지만 많진 않습니다.. 쿨럭)

Result of Testing via Xcode Cloud

또 아래 이미지는 Xcode Cloud 가 작업을 끝내고 슬랙에 남겨놓은 흔적입니다.

Slack message when finish testing task via Xcode Cloud

끝.

5 Shares:
답글 남기기

이메일 주소는 공개되지 않습니다.

이 사이트는 스팸을 줄이는 아키스밋을 사용합니다. 댓글이 어떻게 처리되는지 알아보십시오.

You May Also Like