Testowanie i deploy aplikacji na iOS z GitHub Actions
Github podzielił się z użytkownikami Github Actions zeszłego lata. Dzięki temu narzędziu możesz analizować, budować, testować i deploy’ować swoje projekty na dowolnej platformie, w dowolnym języku i dowolnej chmurze.
Naszym celem jest zautomatyzowanie budowania, testowania i deployment projektu iOS bez konieczności korzystania z zewnętrznych narzędzi poza Github Actions. Dlatego nie będziemy używać Travisa, Jenkinsa, Circle Ci, Fastlane, App Center ani żadnego innego narzędzia CI/CD.
Zaczynajmy
Przejdziemy przez następujące kroki:
- Tworzenie i uruchamianie workflow w Github Actions;
- Testowanie i deploy aplikacji na iOS.
Zaczniemy od aplikacji na iOS, którą opracowałem w moim artykule na Medium. Użyj tego jako instrukcji do stworzenia aplikacji na iOS. Możesz ją pobrać tutaj.
Pamiętaj, że niektóre polecenia mogą się różnić od tych, których użyjemy tutaj, w przypadku, gdy będziesz bazować na innym projekcie.
Katalog główny projektu iOS
Zanim zaczniemy testować i deploy’ować aplikację na iOS, musimy porozmawiać o naszym workflow i jego wyzwalaniu.
Workflow (przepływ pracy) to konfigurowalny zautomatyzowany proces składający się z co najmniej jednego zadania. Aby zdefiniować konfigurację workflow, musisz utworzyć plik YAML.
Przepływ pracy może być odpalany z pull requesta lub pushowania do określonej lub dowolnej gałęzi. Można go również wywołać za pomocą tagów, zaplanować lub użyć innych sposobów. Workflow musi mieć co najmniej jedno zadanie. Zadanie zawiera zestaw kroków wykonujących poszczególne mniejszezadania i kroki, które mogą uruchamiać polecenia lub używać akcji. Te tzw. akcje mogą być udostępniane i używane przez społeczność GitHuba.
Testowanie
Aby zautomatyzować nasz proces testowania, musimy utworzyć katalog .github/workflows/
w katalogu głównym naszego repozytorium, aby przechowywać nasz forkflow. Następnie tworzymy plik YAML, aby skonfigurować nasz workflow.
Dla uproszczenia podzielę się ostatnią częścią tej konfiguracji, a następnie wyjaśnię jej składowe. ?
#!/bin/bash
set -eo pipefail
xcodebuild -workspace Calculator.xcworkspace \
-scheme Calculator\ iOS \
-destination platform=iOS\ Simulator,OS=13.3,name=iPhone\ 11 \
clean test | xcpretty
#!/bin/bash
set -eo pipefail
cd Calculator-package; swift test --parallel; cd ..
name: Testing
on:
pull_request:
branches:
- master
jobs:
test:
name: Testing Swift Package and iOS app
runs-on: macOS-latest
steps:
- name: Checkout repository
uses: actions/checkout@v1
- name: Force XCode 11.3
run: sudo xcode-select -switch /Applications/Xcode_11.3.app
- name: Testing Swift package
run: exec ./.github/scripts/test_swift_package.sh
- name: Testing iOS app
run: exec ./.github/scripts/test_app.sh
Proces testowania
Mamy więc plik workflow o nazwie Testing.yml
i dwa wykonywalne skrypty powłoki o nazwach test_app.sh
i test_swift_package.sh
jako nasze akcje. Są one przechowywane w katalogu .github/scripts
.
Nasz plik workflow ma nazwę Testing i będzie odpalany w każdym pull request’cie do utworzonej gałęzi master
za każdym razem, gdy PR zostanie zaktualizowany. Ten plik ma tylko jedno zadanie, które działa w najnowszej wersji macOS (możesz użyć dowolnego obrazu) i zawiera cztery kroki.
Pierwszym jest sprawdzenie repozytorium (każde zadanie musi to wykonać, aby uzyskać dostęp do repo). Drugi krok wymusza użycie XCode 11.3 i dwóch ostatnich kroków do wykonania po jednym skrypcie, który testuje nasz pakiet Swift i naszą aplikację na iOS.
Deployment
Aby wdrożyć aplikację na iOS w Testflight, musimy najpierw wykonać następujące kroki:
- Utwórz certyfikat dystrybucyjny i tzw. provisioning profile do dystrybucji w App Store.
- Utwórz hasło do aplikacji.
- Zainstaluj GPG i zaszyfruj nasz provisioning profile oraz certyfikat podpisu.
- Utwórz trzy sekrety w naszym repozytorium (jeden z hasłem aplikacji Apple ID, drugi z nazwą użytkownika Apple ID i inny z hasłem do odszyfrowania zaszyfrowanych plików).
Aby utworzyć certyfikat dystrybucyjny, musimy zalogować się do Apple Developer, wybrać Certificates, Identifiers & Profiles. Kliknij sekcję Certificates, a następnie przycisk +, aby dodać nowy certyfikat. W tym przypadku wybieramy opcję iOS Distribution, wybieramy plik CSR i klikamy Continue.
Aby utworzyć provisioning profile, musimy zalogować się do Apple Developer, wybrać Certificates, Identifiers & Profiles. Kliknij sekcję Profiles, a następnie przycisk +, aby dodać nowy profil. W tym przypadku wybieramy opcję App Store w sekcji Distribution. Następnie wybieramy App ID naszej aplikacji i właśnie utworzony certyfikat, a na koniec nadajemy nazwę temu profilowi.
Aby utworzyć hasło aplikacji, musimy zalogować się do AppleID i kliknąć Generate password w hasłach aplikacji w sekcji Security.
Aby zainstalować GPG, musimy otworzyć Terminal i wpisać brew install gpg
. Po zainstalowaniu GPG mamy gotowy provisioning profile i wyeksportowany certyfikat keychain zapisany na komputerze. Zaszyfrujemy te pliki, wykonując następujące czynności:
gpg --symmetric --cipher-algo AES256 YOUR_CERTIFICATE.p12
gpg --symmetric --cipher-algo AES256 YOUR_PROFILE.mobileprovision
Aby zaszyfrować provisioning profile i certyfikat, musimy wpisać hasło. Użyj tego samego w obydwu miejscach, aby uprościć proces odszyfrowywania (w sytuacji produkcyjnej prawdopodobnie lepiej byłoby je rozdzielić, aby zwiększyć bezpieczeństwo).
Gdy obydwa polecenia się zakończą, wygenerowane zostaną dwa pliki: YOUR_CERTIFICATE.gpg
i YOUR_PROFILE.gpg
. Musimy przesłać je do naszego repozytorium w katalogu .github/secrets
.
Aby utworzyć trzy sekrety, których będziemy potrzebować w naszym procesie deploymentu, przejdź do strony głównej repozytorium na GitHubie, kliknij Settings i dalej w Secrets, znajdujące się na lewym pasku bocznym. W tym przypadku tworzymy trzy sekrety za pomocą: IOS_KEYS
(wartość to hasło do odszyfrowania plików, które zaszyfrowaliśmy), APPLIED_USERNAME
(wartość to nazwa użytkownika umożliwiająca dostęp do konta AppleID) i APPLEID_PASSWORD
(wartość to hasło aplikacji wygenerowane dla Ciebie przez Apple) jako nasze klucze.
Teraz, gdy mamy już wszystko ustawione, musimy utworzyć nowy workflow, tak jak zrobiliśmy to w procesie testowania. Chociaż można również utworzyć nowe zadanie w poprzednim workflow. To zależy wyłącznie od Ciebie.
Ten workflow będzie wyzwalany przy każdym pushowaniu do gałęzi master
, więc w zasadzie tylko po merge’owaniu pull requesta (ta gałąź jest chroniona).
Ten workflow będzie miał sześć kroków:
- Sprawdzenie repozytorium
- Instalacja gpg
- Odszyfruj certyfikat i provisioning profile
- Zarchiwizuj aplikację
- Eksportuj aplikację
- Zrób deploy aplikacji
Teraz podzielę się ostatnim elementem tej konfiguracji, a następnie wyjaśnię jego składowe.
#!/bin/bash
set -eo pipefail
xcodebuild -workspace Calculator.xcworkspace \
-scheme Calculator\ iOS \
-sdk iphoneos \
-configuration AppStoreDistribution \
-archivePath $PWD/build/Calculator.xcarchive \
clean archive | xcpretty
#!/bin/sh
set -eo pipefail
gpg --quiet --batch --yes --decrypt --passphrase="$IOS_KEYS" --output ./.github/secrets/match_AppStore_comtiagosantocalculatorIOS.mobileprovision.mobileprovision ./.github/secrets/match_AppStore_comtiagosantocalculatorIOS.mobileprovision.gpg
gpg --quiet --batch --yes --decrypt --passphrase="$IOS_KEYS" --output ./.github/secrets/Certificates.p12 ./.github/secrets/Certificates.p12.gpg
mkdir -p ~/Library/MobileDevice/Provisioning\ Profiles
cp ./.github/secrets/match_AppStore_comtiagosantocalculatorIOS.mobileprovision.mobileprovision ~/Library/MobileDevice/Provisioning\ Profiles/match_AppStore_comtiagosantocalculatorIOS.mobileprovision.mobileprovision
security create-keychain -p "" build.keychain
security import ./.github/secrets/Certificates.p12 -t agg -k ~/Library/Keychains/build.keychain -P "" -A
security list-keychains -s ~/Library/Keychains/build.keychain
security default-keychain -s ~/Library/Keychains/build.keychain
security unlock-keychain -p "" ~/Library/Keychains/build.keychain
security set-key-partition-list -S apple-tool:,apple: -s -k "" ~/Library/Keychains/build.keychain
name: Deploying
on:
push:
branches:
- master
jobs:
deploy:
name: Deploying to Testflight
runs-on: macOS-latest
steps:
- name: Checkout repository
uses: actions/checkout@v1
- name: Install gpg
run: brew install gnupg
- name: Setup provisioning profile
env:
IOS_KEYS: ${{ secrets.IOS_KEYS }}
run: ./.github/secrets/decrypt_secrets.sh
- name: Archiving project
env:
PR_NUMBER: $(jq --raw-output .pull_request.number "$GITHUB_EVENT_PATH")
run: ./.github/scripts/archive_app.sh
- name: Exporting .ipa
run: ./.github/scripts/export_ipa.sh
- name: Publishing app
if: success()
env:
APPLEID_USERNAME: ${{ secrets.APPLEID_USERNAME }}
APPLEID_PASSWORD: ${{ secrets.APPLEID_PASSWORD }}
run: ./.github/scripts/publish_testflight.sh
#!/bin/bash
set -eo pipefail
xcodebuild -archivePath $PWD/build/Calculator.xcarchive \
-exportOptionsPlist Calculator-iOS/Calculator\ iOS/exportOptions.plist \
-exportPath $PWD/build \
-allowProvisioningUpdates \
-exportArchive | xcpretty
#!/bin/bash
set -eo pipefail
xcrun altool --upload-app -t ios -f build/Calculator\ iOS.ipa -u "$APPLEID_USERNAME" -p "$APPLEID_PASSWORD" --verbose
Proces deploymentu
Mamy więc nasz workflow o nazwie Deploying.yml
i cztery wykonywalne skrypty powłoki o nazwach decrypt_secrets.sh
, archive_app.sh
, export_ipa.sh
i publish_testflight.sh
jako nasze akcje. Ustawiliśmy również zmienne środowiskowe z naszymi sekretami, a jeden z nich z numerem pull requesta.
Decrypt_secrets.sh
to jedyny plik skryptowy przechowywany w katalogu .github/secrets
. Ten plik tworzy tymczasowy keychain i odszyfrowuje zaszyfrowane pliki do certyfikatu i provisioning profile, który utworzyliśmy wcześniej. Jest to konieczne, aby zarchiwizować i opublikować naszą aplikację.
Wszystkie inne skrypty są bardzo proste. Jedyna rzecz, którą musimy zrobić, to stworzyć plik exportOptions.plist
i dodać go do projektu, abyśmy mogli wyeksportować plik ipa.
Pamiętaj, że Apple nie zaakceptuje tego przykładu, który właśnie opracowaliśmy, ponieważ ta aplikacja nie ma ikony iOS, która jest obowiązkowa.
I voila! Teraz nasz proces testowania i deploymentu jest zautomatyzowany dzięki Github Actions. Możesz pobrać ten tutorial tutaj.
Dzięki za czytanie!
Oryginał tekstu w języku angielskim przeczytasz tutaj.