Mobil CICD-opplevelse: én fastlane-standard for mange mobilapplikasjoner

Mobil CICD-opplevelse: én fastlane-standard for mange mobilapplikasjoner
Jeg vil gjerne snakke om kontinuerlig integrasjon og levering for mobilapper som bruker fastlane. Hvordan vi implementerer CI/CD på alle mobilapplikasjoner, hvordan vi kom dit og hva som skjedde til slutt.

Det er allerede nok materiale på nettverket på verktøyet, som vi så manglet i starten, så jeg vil bevisst ikke beskrive verktøyet i detalj, men vil bare referere til det vi hadde da:

Artikkelen består av to deler:

  • Bakgrunn for fremveksten av mobil CI/CD i selskapet
  • Teknisk løsning for utrulling av CI/CD for N-applikasjoner

Den første delen er mer nostalgi for gamle dager, og den andre er en opplevelse du kan bruke på deg selv.

Slik skjedde det historisk

2015 år

Vi begynte akkurat å utvikle mobilapplikasjoner, så visste vi ingenting om kontinuerlig integrasjon, om DevOps og andre fasjonable ting. Hver applikasjonsoppdatering ble rullet ut av utvikleren selv fra maskinen sin. Og hvis det er ganske enkelt for Android - satt sammen, signert .apk og lastet det opp til Google Developer Console, så for iOS ga det daværende distribusjonsverktøyet via Xcode oss gode kvelder - forsøk på å laste ned arkivet endte ofte med feil og vi måtte prøve på nytt. Det viste seg at den mest avanserte utvikleren ikke skriver kode flere ganger i måneden, men heller slipper applikasjonen.

2016 år

Vi vokste opp, vi hadde allerede tanker om hvordan vi kunne frigjøre utviklere fra en hel dag for en utgivelse, og en annen applikasjon dukket også opp, som bare presset oss mer mot automatisering. Samme år installerte vi Jenkins for første gang og skrev en haug med skumle skript, svært lik de som fastlane viser i dokumentasjonen.

$ 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 "[email protected]" 
-p "PASS_APPLE_ID"

Dessverre er det til nå bare utviklerne våre som har visst hvordan disse skriptene fungerer og hvorfor denne endeløse stabelen med nøkler er nødvendig, og når noe gikk i stykker igjen, fikk de de "nydelige kveldene" for å analysere logger.

2017 år

I år lærte vi at det er noe som heter fastlane. Det var ikke så mye informasjon som det er nå - hvordan starte en, hvordan bruke den. Og selve verktøyet var fortsatt grovt på den tiden: konstante feil skuffet oss bare, og det var vanskelig å tro på den magiske automatiseringen de lovet.

Imidlertid er de viktigste verktøyene inkludert i fastlane-kjernen gym и pilot, vi klarte å starte den.

Skriptene våre har blitt litt forbedret.

$ fastlane gym  —-workspace "Example.xcworkspace" 
                --scheme "AppName" 
                —-buildlog_path "/tmp" 
                -—clean

De har blitt forbedret, om ikke annet fordi ikke alle parameterne som er nødvendige for xcodebuild, må du indikere - gym vil selvstendig forstå hvor og hva som ligger. Og for mer finjustering kan du spesifisere de samme tastene som i xcodebuild, bare navnene på nøklene er klarere.

Denne gangen, takket være treningsstudioet og den innebygde xcpretty-formateren, har byggeloggene blitt mye mer lesbare. Dette begynte å spare tid på å fikse ødelagte sammenstillinger, og noen ganger kunne utgivelsesteamet finne ut av det på egen hånd.

Dessverre, monteringshastighetsmålinger xcodebuild и gym Vi gjorde det ikke, men vi vil stole på dokumentasjonen - opptil 30 % hastighet.

Enkel prosess for alle søknader

År 2018 og nåtid

I 2018 ble prosessen med å bygge og rulle ut applikasjoner fullstendig flyttet til Jenkins, utviklere sluttet å frigi fra maskinene sine, og bare utgivelsesteamet hadde rett til å frigi.

Vi ønsket allerede å forbedre lanseringen av tester og statisk analyse, og skriptene våre vokste og vokste. Vokst og endret seg sammen med søknadene våre. På den tiden var det omtrent 10 applikasjoner. Med tanke på at vi har to plattformer, er det omtrent 20 «levende» skript.

Hver gang vi ønsket å legge til et nytt trinn i skriptet, måtte vi kopiere og lime inn delene i alle shell-skriptene. Kanskje vi kunne ha jobbet mer forsiktig, men ofte endte slike endringer i skrivefeil, som ble til kvelder for utgivelsesteamet for å fikse skript og finne ut hvilken smart fyr som la til denne kommandoen og hva den faktisk gjør. Generelt kan det ikke sies at skriptene for montering for én plattform i det minste var noe like. Selv om de absolutt gjorde det samme.

For å starte en prosess for en ny applikasjon, var det nødvendig å bruke en dag på å velge en "fersk" versjon av disse skriptene, feilsøke den og si at "ja, det fungerer."

Sommeren 2018 så vi nok en gang mot fastlanen i stadig utvikling.

Oppgave #1: oppsummer alle skripttrinn og skriv dem om i Fastfile

Da vi startet, så manusene våre ut som en fotklut bestående av alle trinnene og krykkene i ett skallmanus i Jenkins. Vi har ennå ikke gått over til pipeline og divisjon for trinn.

Vi så på hva vi har og identifiserte 4 trinn som passer til beskrivelsen av CI/CDen vår:

  • bygge - installere avhengigheter, sette sammen arkivet,
  • test – kjører utviklerenhetstester, beregner dekning,
  • sonar - starter alle linters og sender rapporter til SonarQube,
  • distribuere — sende en artefakt til alpha (TestFlight).

Og hvis du ikke går inn i detaljer, og utelater nøklene som brukes i handlinger, får du denne Fastfilen:

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
end

Faktisk viste den første Fastfilen vår seg å være monstrøs, tatt i betraktning noen av krykkene vi fortsatt trengte og antallet parametere vi erstattet:

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: "[email protected]",
  app_identifier: "com.example.app",
  dev_portal_team_id: "TEAM_ID_NUMBER_DEV",
  team_id: "ITS_TEAM_ID")
end

I eksemplet ovenfor er det bare en del av parametrene som vi trenger å spesifisere: disse er byggeparametrene - skjema, konfigurasjon, tildelingsprofilnavn, samt distribusjonsparametere - Apple ID for utviklerkontoen, passord, program-ID og så på. Som en første tilnærming legger vi alle disse nøklene i spesielle filer - Gymfile, Matchfile и Appfile.

Nå i Jenkins kan du kalle korte kommandoer som ikke gjør visningen uskarp og som er lett lesbare for øyet:

# fastlane ios <lane_name>

$ fastlane ios build
$ fastlane ios test
$ fastlane ios run_sonar
$ fastlane ios deploy

Hurra, vi er flinke

Hva fikk du? Tydelige kommandoer for hvert trinn. Ryddet opp i skript, pent ordnet i fastlane-filer. Med glede løp vi til utviklerne og ba dem legge til alt de trengte til depotene deres.

Men vi innså med tiden at vi ville møte de samme vanskelighetene - vi ville fortsatt ha 20 monteringsskript som på en eller annen måte ville begynne å leve sitt eget liv, det ville være vanskeligere å redigere dem, siden skriptene ville flytte til depoter, og vi hadde ikke tilgang der. Og generelt vil det ikke være mulig å løse smerten vår på denne måten.

Mobil CICD-opplevelse: én fastlane-standard for mange mobilapplikasjoner

Oppgave #2: få en enkelt Fastfile for N applikasjoner

Nå ser det ut til at det ikke er så vanskelig å løse problemet - still inn variablene, og la oss gå. Ja, faktisk var det slik problemet ble løst. Men i øyeblikket da vi skrudde opp, hadde vi verken ekspertise på fastlane selv, eller i Ruby, som fastlane er skrevet i, eller nyttige eksempler på nettverket - alle som skrev om fastlane da var begrenset til et eksempel for én applikasjon for én utvikler.

Fastlane kan håndtere miljøvariabler, og vi har allerede prøvd dette ved å sette nøkkelring-passordet:

ENV['KEYCHAIN_PASSWORD']

Etter å ha sett på skriptene våre, identifiserte vi de vanlige delene:

#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
[email protected]
TEAM_ID=ABCD1234
FASTLANE_ITC_TEAM_ID=123456789

Nå, for å begynne å bruke disse nøklene i fastlane-filer, måtte vi finne ut hvordan vi skulle levere dem der. Fastlane har en løsning for dette: laster variabler via dotenv. Dokumentasjonen sier at hvis det er viktig for deg å laste inn nøkler for forskjellige formål, lag flere konfigurasjonsfiler i fastlane-katalogen .env, .env.default, .env.development.

Og så bestemte vi oss for å bruke dette biblioteket litt annerledes. La oss ikke plassere fastlane-skriptene og dens metainformasjon i utviklerens repository, men de unike nøklene til denne applikasjonen i filen .env.appName.

selv Fastfile, Appfile, Matchfile и Gymfile, gjemte vi det i et eget depot. En ekstra fil med passordnøkler fra andre tjenester ble skjult der - .env.
Du kan se et eksempel her.

Mobil CICD-opplevelse: én fastlane-standard for mange mobilapplikasjoner

På CI har ikke samtalen endret seg mye; en konfigurasjonsnøkkel for en spesifikk applikasjon er lagt til:

# 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 appName

Før vi kjører kommandoene, laster vi lageret vårt med skript. Ser ikke så fint ut:

git clone [email protected]/FastlaneCICD.git fastlane_temp

cp ./fastlane_temp/fastlane/* ./fastlane/
cp ./fastlane_temp/fastlane/.env fastlane/.env

Forlot denne løsningen for nå, selv om Fastlane har en løsning for å laste ned Fastfile via handling import_from_git, men det fungerer bare for Fastfile, men ikke for andre filer. Hvis du vil ha "virkelig vakker", kan du skrive din egen action.

Et lignende sett ble laget for Android-applikasjoner og ReactNative, filene er i samme depot, men i forskjellige grener iOS, android и react_native.

Når utgivelsesteamet ønsker å legge til et nytt trinn, registreres endringer i skriptet via MR i git, det er ikke lenger nødvendig å lete etter synderne til ødelagte skript, og generelt, nå må du prøve å bryte det.

Nå er det det helt sikkert

Tidligere brukte vi tid på å vedlikeholde alle skriptene, oppdatere dem og fikse alle konsekvensene av oppdateringer. Det var veldig skuffende da årsakene til feil og nedetid i utgivelser var enkle skrivefeil som var så vanskelige å holde styr på i virvar av skallskript. Nå er slike feil redusert til et minimum. Endringer rulles ut til alle applikasjoner samtidig. Og det tar 15 minutter å sette en ny applikasjon inn i prosessen - sett opp en malpipeline på CI og legg til nøklene til utviklerens repository.

Det ser ut til at poenget med Fastfile for Android og applikasjonssignatur forblir uforklarlig; hvis artikkelen er interessant, vil jeg skrive en fortsettelse. Jeg vil gjerne se dine spørsmål eller forslag "hvordan ville du løse dette problemet" i kommentarene eller på Telegram bashkirova.

Kilde: www.habr.com

Legg til en kommentar