
Saya ingin berbicara tentang integrasi dan pengiriman berkelanjutan untuk aplikasi seluler menggunakan fastlane. Bagaimana kami menerapkan CI/CD di semua aplikasi seluler, bagaimana kami mencapainya, dan apa yang terjadi pada akhirnya.
Sudah ada cukup materi di jaringan tentang alat tersebut, yang pada awalnya sangat kurang kami miliki, jadi saya sengaja tidak akan menjelaskan alat tersebut secara detail, tetapi hanya akan merujuk pada apa yang kami miliki saat itu:
Artikel ini terdiri dari dua bagian:
- Latar belakang munculnya mobile CI/CD di perusahaan
- Solusi teknis untuk meluncurkan CI/CD untuk aplikasi N
Bagian pertama lebih bersifat nostalgia masa lalu, dan bagian kedua adalah pengalaman yang bisa Anda terapkan pada diri sendiri.
Begitulah yang terjadi secara historis
Tahun 2015
Kami baru saja mulai mengembangkan aplikasi seluler, dan kami tidak tahu apa-apa tentang integrasi berkelanjutan, DevOps, atau hal-hal canggih lainnya. Setiap pembaruan aplikasi diluncurkan oleh pengembang sendiri dari mesinnya sendiri. Dan jika untuk Android Sangat sederhana - dikumpulkan, ditandatangani .apk dan mengunggahnya ke Konsol Pengembang Google, lalu untuk iOS, alat distribusi melalui Xcode memberi kami malam yang menyenangkan - upaya untuk mengunduh arsip sering kali berakhir dengan kesalahan dan kami harus mencoba lagi. Ternyata pengembang paling maju tidak menulis kode beberapa kali dalam sebulan, melainkan merilis aplikasinya.
Tahun 2016
Kami tumbuh dewasa, kami sudah memiliki pemikiran tentang cara membebaskan pengembang dari satu hari penuh untuk rilis, dan aplikasi kedua juga muncul, yang hanya mendorong kami lebih ke arah otomatisasi. Pada tahun yang sama, kami menginstal Jenkins untuk pertama kalinya dan menulis sekumpulan skrip menakutkan, sangat mirip dengan yang ditampilkan fastlane dalam dokumentasinya.
$ xcodebuild clean archive -archivePath build/MyApp
-scheme MyApp
$ xcodebuild -exportArchive
-exportFormat ipa
-archivePath "build/MyApp.xcarchive"
-exportPath "build/MyApp.ipa"
-exportProvisioningProfile "ProvisioningProfileName"
$ cd /Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/Frameworks/ITunesSoftwareService.framework/Versions/A/Support/
$ ./altool —upload-app
-f {abs path to your project}/build/{release scheme}.ipa
-u "appleId@example.com"
-p "PASS_APPLE_ID"Sayangnya, hingga saat ini hanya pengembang kami yang mengetahui cara kerja skrip ini dan mengapa tumpukan kunci yang tak ada habisnya ini diperlukan, dan ketika terjadi kerusakan lagi, mereka mendapatkan “malam yang indah” untuk menganalisis log.
Tahun 2017
Tahun ini kita mengetahui bahwa ada yang namanya fastlane. Informasi yang ada saat ini tidak sebanyak yang ada – bagaimana memulainya, bagaimana menggunakannya. Dan alat itu sendiri masih mentah pada saat itu: kesalahan terus-menerus hanya mengecewakan kami dan sulit mempercayai otomatisasi ajaib yang mereka janjikan.
Namun, utilitas utama yang termasuk dalam inti fastlane adalah gym и pilot, kami berhasil memulainya.
Skrip kami telah diperbaiki sedikit.
$ fastlane gym —-workspace "Example.xcworkspace"
--scheme "AppName"
—-buildlog_path "/tmp"
-—cleanMereka telah ditingkatkan, jika hanya karena tidak semua parameter diperlukan xcodebuild, Anda perlu menunjukkan - gym akan secara mandiri memahami di mana dan apa yang ada. Dan untuk penyesuaian lebih lanjut, Anda dapat menentukan kunci yang sama seperti pada xcodebuild, hanya penamaan kuncinya yang lebih jelas.
Kali ini, berkat gym dan pemformat xcpretty bawaan, log build menjadi lebih mudah dibaca. Hal ini mulai menghemat waktu dalam memperbaiki rakitan yang rusak, dan terkadang tim rilis dapat mengatasinya sendiri.
Sayangnya, pengukuran kecepatan perakitan xcodebuild и gym Kami tidak melakukannya, tapi kami percaya pada dokumentasinya - percepatan hingga 30%.
Proses tunggal untuk semua aplikasi
Tahun 2018 dan sekarang
Pada tahun 2018, proses pembuatan dan peluncuran aplikasi sepenuhnya dipindahkan ke Jenkins, pengembang berhenti merilis dari mesin mereka, dan hanya tim rilis yang berhak merilis.
Kami sudah ingin meningkatkan peluncuran pengujian dan analisis statis, dan skrip kami semakin berkembang. Tumbuh dan berubah seiring dengan aplikasi kami. Saat itu ada sekitar 10 aplikasi, mengingat kami memiliki dua platform, itu berarti sekitar 20 skrip “hidup”.
Setiap kali kami ingin menambahkan langkah baru ke skrip, kami harus menyalin-menempelkan potongan tersebut ke semua skrip shell. Mungkin kami bisa bekerja lebih hati-hati, tetapi sering kali perubahan seperti itu berakhir dengan kesalahan ketik, yang berubah menjadi malam bagi tim rilis untuk memperbaiki skrip dan mencari tahu orang pintar mana yang menambahkan perintah ini dan apa sebenarnya fungsinya. Secara umum, tidak dapat dikatakan bahwa skrip perakitan untuk satu platform setidaknya serupa. Meskipun mereka pasti melakukan hal yang sama.
Untuk memulai proses aplikasi baru, diperlukan waktu satu hari untuk memilih versi "segar" dari skrip ini, melakukan debug, dan mengatakan bahwa "ya, berhasil".
Pada musim panas 2018, kami sekali lagi melihat ke arah jalur cepat yang masih berkembang.
Tugas #1: meringkas semua langkah skrip dan menulis ulang di Fastfile
Saat kami memulai, skrip kami tampak seperti alas kaki yang terdiri dari semua langkah dan kruk dalam satu skrip shell di Jenkins. Kami belum beralih ke jalur pipa dan divisi demi tahap.
Kami melihat apa yang kami miliki dan mengidentifikasi 4 langkah yang sesuai dengan deskripsi CI/CD kami:
- build - menginstal dependensi, merakit arsip,
- pengujian — menjalankan pengujian unit pengembang, menghitung cakupan,
- sonar - meluncurkan semua linter dan mengirimkan laporan ke SonarQube,
- deploy — mengirim artefak ke alpha (TestFlight).
Dan jika Anda tidak merincinya, menghilangkan kunci yang digunakan dalam tindakan, Anda akan mendapatkan Fastfile ini:
default_platform(:ios)
platform :ios do
before_all do
unlock
end
desc "Build stage"
lane :build do
match
prepare_build
gym
end
desc "Prepare build stage: carthage and cocoapods"
lane :prepare_build do
pathCartfile = ""
Dir.chdir("..") do
pathCartfile = File.join(Dir.pwd, "/Cartfile")
end
if File.exist?(pathCartfile)
carthage
end
pathPodfile = ""
Dir.chdir("..") do
pathPodfile = File.join(Dir.pwd, "/Podfile")
end
if File.exist?(pathPodfile)
cocoapods
end
end
desc "Test stage"
lane :test do
scan
xcov
end
desc "Sonar stage (after run test!)"
lane :run_sonar do
slather
lizard
swiftlint
sonar
end
desc "Deploy to testflight stage"
lane :deploy do
pilot
end
desc "Unlock keychain"
private_lane :unlock do
pass = ENV['KEYCHAIN_PASSWORD']
unlock_keychain(
password: pass
)
end
endFaktanya, Fastfile pertama kami ternyata sangat buruk, mengingat beberapa kruk yang masih kami perlukan dan jumlah parameter yang kami gantikan:
lane :build do
carthage(
command: "update",
use_binaries: false,
platform: "ios",
cache_builds: true)
cocoapods(
clean: true,
podfile: "./Podfile",
use_bundle_exec: false)
gym(
workspace: "MyApp.xcworkspace",
configuration: "Release",
scheme: "MyApp",
clean: true,
output_directory: "/build",
output_name: "my-app.ipa")
end
lane :deploy do
pilot(
username: "appleId@example.com",
app_identifier: "com.example.app",
dev_portal_team_id: "TEAM_ID_NUMBER_DEV",
team_id: "ITS_TEAM_ID")
endDalam contoh di atas, hanya sebagian parameter yang perlu kita tentukan: ini adalah parameter build - skema, konfigurasi, nama Profil Penyediaan, serta parameter distribusi - ID Apple dari akun pengembang, kata sandi, ID aplikasi, dan sebagainya pada. Sebagai perkiraan pertama, kami memasukkan semua kunci ini ke dalam file khusus - Gymfile, Matchfile и Appfile.
Sekarang di Jenkins Anda dapat memanggil perintah singkat yang tidak mengaburkan pandangan dan mudah dibaca oleh mata:
# fastlane ios <lane_name>
$ fastlane ios build
$ fastlane ios test
$ fastlane ios run_sonar
$ fastlane ios deployHore, kami hebat
Apa yang kamu dapatkan? Hapus perintah untuk setiap langkah. Script sudah dibersihkan, tersusun rapi dalam file fastlane. Bersukacitalah, kami menemui para pengembang meminta mereka untuk menambahkan semua yang mereka butuhkan ke repositori mereka.
Namun kami menyadari pada waktunya bahwa kami akan menghadapi kesulitan yang sama - kami masih memiliki 20 skrip perakitan yang entah bagaimana akan mulai menjalani kehidupannya sendiri, akan lebih sulit untuk mengeditnya, karena skrip akan dipindahkan ke repositori, dan kami tidak memiliki akses ke sana. Dan, secara umum, tidak mungkin mengatasi rasa sakit kita dengan cara ini.

Tugas #2: mendapatkan satu Fastfile untuk N aplikasi
Sekarang tampaknya menyelesaikan masalah tidak terlalu sulit - atur variabelnya, dan ayo. Ya, sebenarnya, begitulah cara masalahnya diselesaikan. Tetapi pada saat kami mengacaukannya, kami tidak memiliki keahlian dalam fastlane itu sendiri, atau di Ruby, di mana fastlane ditulis, atau contoh-contoh berguna di jaringan - setiap orang yang menulis tentang fastlane kemudian dibatasi pada contoh untuk satu aplikasi untuk satu pengembang.
Fastlane dapat menangani variabel lingkungan, dan kami telah mencobanya dengan mengatur kata sandi Rantai Kunci:
ENV['KEYCHAIN_PASSWORD']Setelah melihat skrip kami, kami mengidentifikasi bagian-bagian umum:
#for build, test and deploy
APPLICATION_SCHEME_NAME=appScheme
APPLICATION_PROJECT_NAME=app.xcodeproj
APPLICATION_WORKSPACE_NAME=app.xcworkspace
APPLICATION_NAME=appName
OUTPUT_IPA_NAME=appName.ipa
#app info
APP_BUNDLE_IDENTIFIER=com.example.appName
APPLE_ID=appleID@example.com
TEAM_ID=ABCD1234
FASTLANE_ITC_TEAM_ID=123456789Sekarang, untuk mulai menggunakan kunci ini di file fastlane, kami harus memikirkan cara mengirimkannya ke sana. Fastlane punya solusi untuk ini: . Dokumentasi mengatakan bahwa jika penting bagi Anda untuk memuat kunci untuk tujuan berbeda, buat beberapa file konfigurasi di direktori fastlane .env, .env.default, .env.development.
Dan kemudian kami memutuskan untuk menggunakan perpustakaan ini sedikit berbeda. Mari kita tempatkan di repositori pengembang bukan skrip fastlane dan informasi meta-nya, tetapi kunci unik aplikasi ini di dalam file .env.appName.
Dirinya sendiri Fastfile, Appfile, Matchfile и Gymfile, kami menyembunyikannya di repositori terpisah. File tambahan dengan kunci kata sandi dari layanan lain disembunyikan di sana - .env.
Anda dapat melihat contohnya .

Di CI, panggilannya tidak banyak berubah; kunci konfigurasi untuk aplikasi tertentu telah ditambahkan:
# fastlane ios <lane_name> --env appName
$ fastlane ios build --env appName
$ fastlane ios test --env appName
$ fastlane ios run_sonar --env appName
$ fastlane ios deploy --env appNameSebelum menjalankan perintah, kami memuat repositori kami dengan skrip. Tidak terlihat bagus:
git clone git@repository.com/FastlaneCICD.git fastlane_temp
cp ./fastlane_temp/fastlane/* ./fastlane/
cp ./fastlane_temp/fastlane/.env fastlane/.envTinggalkan solusi ini untuk saat ini, meskipun Fastlane memiliki solusi untuk mengunduh Fastfile melalui import_from_git, tetapi ini hanya berfungsi untuk Fastfile, tetapi tidak untuk file lain. Jika ingin “cantik banget”, Anda bisa menulis sendiri action.
Satu set serupa dibuat untuk Android Untuk aplikasi dan ReactNative, file-file tersebut berada di repositori yang sama, tetapi di cabang yang berbeda. iOS, android и react_native.
Ketika tim rilis ingin menambahkan beberapa langkah baru, perubahan skrip dicatat melalui MR di git, tidak perlu lagi mencari penyebab skrip rusak, dan secara umum, sekarang Anda harus mencoba memecahkannya.
Itu sudah pasti
Sebelumnya, kami menghabiskan waktu memelihara semua skrip, memperbaruinya, dan memperbaiki semua konsekuensi pembaruan. Sangat mengecewakan ketika alasan kesalahan dan downtime dalam rilis adalah kesalahan ketik sederhana yang sangat sulit untuk dilacak dalam skrip shell yang campur aduk. Sekarang kesalahan seperti itu diminimalkan. Perubahan diluncurkan ke semua aplikasi sekaligus. Dan dibutuhkan waktu 15 menit untuk memasukkan aplikasi baru ke dalam proses - menyiapkan pipeline template di CI dan menambahkan kunci ke repositori pengembang.
Tampaknya permasalahan dengan Fastfile masih belum terjelaskan. Android dan tanda tangan aplikasi. Jika artikel ini menarik, saya akan menulis sekuelnya. Saya ingin sekali mendengar pertanyaan atau saran Anda tentang bagaimana Anda akan menyelesaikan masalah ini di kolom komentar atau di Telegram. .
Sumber: www.habr.com
