Git, CocoaPods, Xcode, Shell
[iOS - swift] 2. GitHub Action 사용 방법 (CI/CD)
jake-kim
2021. 12. 5. 23:08
1. GitHub Action 개념, 기능 (CI/CD)
2. GitHub Action 사용 방법 (CI/CD)
GitHub Action으로 할 수 있는 것
- Push 발생되면 아래 단계들이 자동으로 실행
( 1. GitHub Action 개념, 기능 (CI/CD) 에서는 UnitTest까지 진행)- Build
- Unit Test
- Archive
- ipa 생성, Git에 Artifacts 형식으로 업로드 or 앱스토어에 ipa파일 업로드
GitHub Action을 이용한 Archive
- Archive를 하기 위해서는 Certfiicate, Provisioning Profile이 필요한데, 이 정보를 GitHub에도 업로드해주어야 Archive가능
- Edit Scheme 클릭
- Build Configuration 확인 -> 대상이 Release이므로 Distribution Certificate와 Distribution Provisioning Profile 필요
- Distribution Certificate: 애플의 하드웨어에는 신뢰받은 소프트웨어만이 설치가 가능한데, 이 신뢰인증서를 의미
- Distribution Provisioning Profile: 애플에서 앱을 구분하는 App ID정보 + 개발자 신뢰 Certificate + Device 신뢰정보
- 구체적인 개념은 이곳 참고: https://ios-development.tistory.com/246
- 이곳을 참고하여 Distribution 용도의 Certificate, Provisioning Profile 생성
- (아래처럼 기존에 만들어 둔 인증서가 없는 경우)Certificate 생성하기
- App ID 등록하기
- Provisioning Profile 생성
- 만약, Apple Developer에 Distribution인증서가 이미 존재한다면 해당 부분 다운로드
- Provisioning Profile을 만들때는 App Store 클릭
- 생성 완료
- .cer 파일을 두번 클릭하여 활성화 -> Keychain Access 앱 -> 인증서 탭에 활성화된 것 확인
- 활성화된 인증서 -> 오른쪽 마우스 클릭 -> 내보내기 클릭
- .p12파일 내보내기
- 내보내기 하면, 암호입력이 나오는데 이 부분은 나중에 사용되므로 따록 기록
cf) .p12는 1년마다 갱신되는 인증서, .p8은 영구적 사용이 가능
- Xcode에 Provisioning Profile 적용
- Rarget -> Signing & Capabilities -> Release
- Automatically manage signing 체크를 해제
- import profiles -> 다운받은 Profiles을 선택
- Target -> Build Settins에서 Code Signing Identity의 Release에도 적용
깃허브에 업로드할 파일들 Certificate, Profiles을 암호화
- GnuGP 보안 솔루션 이용
- M1 CPU 맥북인 경우 설치
arch -arm64 brew install gnupg2
- intel CPU 맥북인 경우 설치
brew install gnupg2
- M1 CPU 맥북인 경우 설치
cf) M1 CPU 맥북에서 brew install gnupg2로 설치 시, "Cannot install under Rosetta 2 in ARM default prefix" 오류 발생
- certificate와 provisioning profile을 암호화하여 깃허브에 업로드
- 암호화
gpg -c certs.p12
- passphrase도 역시, .p12를 내보낼때 패스워드를 기록했듯이 나중에 사용되므로 따로 기록
- provisioning profile도 동일하게 암호화 (위와 같이 암호 따로 기록해 놓을 것)
- 암호화된 파일 생성 완료
암호화된 certificate, profiles을 깃허브에 업로드하기 위해 필요한 환경변수 설정
- Github -> Settings 탭
- Secrets -> New repository secret 클릭
- 위에서 기록했었던 것들 추가
- CERTS_EXPORT_PWD: .cer파일을 .p12로 내보내기할때 사용된 패스워드
- CERTS_ENCRYPTO_PWD: gpg로 .p12파일을 암호화할때 사용된 패스워드
- PROFILES_ENCRYPTO_PWD: gpg로 provisioning profiles 파일을 암호화할때 사용된 패스워드
- 생성한 3개 secrets 변수
- 암호화된 certificate, profiles을 깃허브에 업로드
- .github하위에 secrets폴더를 만든 후 .gpg파일 저장
ExportOptions.plist 파일 생성
- 원래 xcode에서 Archive하면 생성되는 파일이므로, Archive 시도
- Any iOS Device로 선택
- Xcode > project > Arhive
- Distribution App
- Export 체크 후 Next 연속
- 완료 시 ExportOptions.plist 파일 생성
- Any iOS Device로 선택
- ExportOptions.plist파일을 생성하여, 프로젝트가 존재하는 곳에 복사
- 루트가 아닌 다른곳에 복사할 경우 오류 발생하므로 주의
- 루트가 아닌 다른곳에 복사할 경우 오류 발생하므로 주의
GitHub Action에서 정의한 .yml파일 수정
- .yml 파일에 환경변수를 이용하여 unit 테스트까지 되게끔 수정
- GitHub Action으로 기존에 만들어놓은 .yml파일 오픈
- unit 테스트까지 되게끔 .yml파일 수정
- 만약 cocoapods을 사용하여, .xcworkspace파일이 존재하는 경우, -project부분을 -workspace로 수정 필요
(이부분은 아래 전체 .yml코드에서 주석으로 된 부분 확인)
- 만약 cocoapods을 사용하여, .xcworkspace파일이 존재하는 경우, -project부분을 -workspace로 수정 필요
name: Swift
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: macos-latest
env:
XC_VERSION: ${{ '13.1' }}
XC_PROJECT: ${{ 'ExGithubAction.xcodeproj' }}
XC_SCHEME: ${{ 'ExGithubAction' }}
steps:
- name: Select latest Xcode
run: "sudo xcode-select -s /Applications/Xcode_$XC_VERSION.app"
- uses: actions/checkout@v2
- name: Build
run: echo Hello, world!
- name: Run tests
run: |
xcodebuild test -project "$XC_PROJECT" -scheme "$XC_SCHEME" -destination 'platform=iOS Simulator,name=iPhone 13'
GitHub에서 certificate, provisioning profile 사용되게끔하는 방법
1. GitHub 가상머신에 keychain 생성하는 스텝 추가
- env 추가
KEYCHAIN: ${{ 'test.keychain' }}
- step추가 - .yml파일에 security라는 명령어 사용
- name: Configure Keychain
run: |
security create-keychain -p "" "$KEYCHAIN"
security list-keychains -s "$KEYCHAIN"
security default-keychain -s "$KEYCHAIN"
security unlock-keychain -p "" "$KEYCHAIN"
2. 암호화한 certificate, provisioning profile을 decrypt
- env 추가 (이전에 암호화된 파일 certificate와 profiles와 이 파일들이 복호화 했을때 어디에 저장할지 path 입력)
ENCRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/certs.p12.gpg' }} DECRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/certs.p12' }} # 어디에 복호화 할 것인지 명시 ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/ExGithubAction.mobileprovision.gpg' }} DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/ExGithubAction.mobileprovision' }} # 어디에 복호화 할 것인지 명시
- env 추가 입력 (위 .pgp파일들의 패스워드와 .cet 인증서를 .p12로 내보내기할 때 사용한 패스워드 값)
- github에 입력했던 Setting -> secrets에 입력하면, secrets.{입력한 변수}로 접근
# 주의할점: 다른 env 변수이름은 작은 따옴표를 붙이지만, github의 secrets에 접근할 땐 작은 따옴표 붙이지 않음 CERTS_EXPORT_PWD: ${{ secrets.CERTS_EXPORT_PWD }} CERTS_ENCRYPTION_PWD: ${{ secrets.CERTS_ENCRYPTO_PWD }} PROFILES_ENCRYPTO_PWD: ${{ secrets.PROVISION_ENCRYPTO_PWD }}
- gpg파일을 복호화하여 keychain에 certificates, provisioning profile 저장 스크립트 작성
- gpg의 -d 옵션: dectypt
- gpg의 -o 옵션: output
- 기타 gpg 옵션 참고: https://gnupg.org/documentation/manpage.html
- name : Configure Code Signing run: | gpg -d -o "$DECRYPTED_CERTS_FILE_PATH" --pinentry-mode=loopback --passphrase "$CERTS_ENCRYPTION_PWD" "$ENCRYPTED_CERTS_FILE_PATH" gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$PROFILES_ENCRYPTO_PWD" "$ENCRYPTED_PROVISION_FILE_PATH" security import "$DECRYPTED_CERTS_FILE_PATH" -k "$KEYCHAIN" -P "$CERTS_EXPORT_PWD" -A security set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN" mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles" echo `ls .github/secrets/*.mobileprovision` # 프로파일들을 rename하고 새로만든 디렉토리에 복사 for PROVISION in `ls .github/secrets/*.mobileprovision` do UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)` cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision" done
3. 앱 빌드 스크립트 작성
- env
XC_ARCHIVE_PATH: ${{ 'ExGithubAction.xcarchive' }}
- 빌드
- name: Archive run: | mkdir artifacts xcodebuild archive -project "$XC_PROJECT" -scheme "$XC_SCHEME" -configuration release -archivePath "$XC_ARCHIVE_PATH"
4. Archive와 Export
- env
XC_EXPORT_PATH: ${{ './artifacts' }}
- Archive
- 주의: ExportOptions.plist 파일은 "-archivePath" 없이 그냥 선언해주지 않으면 오류 발생
- name: Export for App Store run: | xcodebuild -exportArchive -archivePath "$XC_ARCHIVE_PATH" -exportOptionsPlist ExportOptions.plist -exportPath "$XC_EXPORT_PATH"
- 주의: ExportOptions.plist 파일은 "-archivePath" 없이 그냥 선언해주지 않으면 오류 발생
5. Artifact 업로드
env: PROJECT_ROOT_PATH: ${{ 'ExGithubAction' }}
...
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: Artifacts
path: ./artifacts
.yml 전체 코드
name: Swift
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: macos-latest
env:
XC_VERSION: ${{ '13.1' }}
XC_PROJECT: ${{ 'ExGithubAction.xcodeproj' }}
XC_SCHEME: ${{ 'ExGithubAction' }}
KEYCHAIN: ${{ 'test.keychain' }} # GitHub가상 머신에 키체인 생성할때의 이름
PROJECT_ROOT_PATH: ${{ 'ExGithubAction' }}
ENCRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/certs.p12.gpg' }}
DECRYPTED_CERTS_FILE_PATH: ${{ '.github/secrets/certs.p12' }} # 어디에 복호화 할 것인지 명시
ENCRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/ExGithubAction.mobileprovision.gpg' }}
DECRYPTED_PROVISION_FILE_PATH: ${{ '.github/secrets/ExGithubAction.mobileprovision' }} # 어디에 복호화 할 것인지 명시
CERTS_EXPORT_PWD: ${{ secrets.CERTS_EXPORT_PWD }}
CERTS_ENCRYPTION_PWD: ${{ secrets.CERTS_ENCRYPTO_PWD }}
PROFILES_ENCRYPTO_PWD: ${{ secrets.PROFILES_ENCRYPTO_PWD }}
XC_ARCHIVE_PATH: ${{ 'ExGithubAction.xcarchive' }}
XC_EXPORT_PATH: ${{ './artifacts' }}
steps:
- name: Select latest Xcode
run: "sudo xcode-select -s /Applications/Xcode_$XC_VERSION.app"
- uses: actions/checkout@v2
- name: Build
run: echo Hello, world!
- name: Run tests
run: |
xcodebuild test -project "$XC_PROJECT" -scheme "$XC_SCHEME" -destination 'platform=iOS Simulator,name=iPhone 13'
- name: Configure Keychain
run: |
security create-keychain -p "" "$KEYCHAIN"
security list-keychains -s "$KEYCHAIN"
security default-keychain -s "$KEYCHAIN"
security unlock-keychain -p "" "$KEYCHAIN"
- name : Configure Code Signing
run: |
gpg -d -o "$DECRYPTED_CERTS_FILE_PATH" --pinentry-mode=loopback --passphrase "$CERTS_ENCRYPTION_PWD" "$ENCRYPTED_CERTS_FILE_PATH"
gpg -d -o "$DECRYPTED_PROVISION_FILE_PATH" --pinentry-mode=loopback --passphrase "$PROFILES_ENCRYPTO_PWD" "$ENCRYPTED_PROVISION_FILE_PATH"
security import "$DECRYPTED_CERTS_FILE_PATH" -k "$KEYCHAIN" -P "$CERTS_EXPORT_PWD" -A
security set-key-partition-list -S apple-tool:,apple: -s -k "" "$KEYCHAIN"
mkdir -p "$HOME/Library/MobileDevice/Provisioning Profiles"
echo `ls .github/secrets/*.mobileprovision`
# 프로파일들을 rename하고 새로만든 디렉토리에 복사
for PROVISION in `ls .github/secrets/*.mobileprovision`
do
UUID=`/usr/libexec/PlistBuddy -c 'Print :UUID' /dev/stdin <<< $(security cms -D -i ./$PROVISION)`
cp "./$PROVISION" "$HOME/Library/MobileDevice/Provisioning Profiles/$UUID.mobileprovision"
done
- name: Archive
run: |
mkdir artifacts
xcodebuild archive -project "$XC_PROJECT" -scheme "$XC_SCHEME" -configuration release -archivePath "$XC_ARCHIVE_PATH"
# Cocoapods을 사용 할 경우
# - name: Archive
# run: |
# pod install --repo-update --clean-install --project-directory="$PROJECT_ROOT_PATH"/
# xcodebuild clean archive -workspace "$XC_WORKSPACE" -scheme "$XC_SCHEME" -configuration release -archivePath "$XC_ARCHIVE"
- name: Export for App Store
run: |
xcodebuild -exportArchive -archivePath "$XC_ARCHIVE_PATH" -exportOptionsPlist ExportOptions.plist -exportPath "$XC_EXPORT_PATH"
- name: Upload Artifact
uses: actions/upload-artifact@v2
with:
name: Artifacts
path: ./artifacts
작성 후 Push하면 Artifacts까지 업로드 완료
- Build
- Unit Test
- Archive
- ipa 생성, Git에 Artifacts 형식으로 업로드 or 앱스토어에 ipa파일 업로드
- artifacts 업로드도 성공
* 전체 소스 코드: https://github.com/JK0369/ExGithubAction
* 참고
- https://medium.com/@karaiskc/archive-and-export-ios-app-with-github-actions-b44f676e4bf9
- https://gnupg.org/documentation/manpage.html