Mobilní CICD zážitek: jeden rychlý standard pro mnoho mobilních aplikací

Mobilní CICD zážitek: jeden rychlý standard pro mnoho mobilních aplikací
Chtěl bych mluvit o nepřetržité integraci a poskytování mobilních aplikací pomocí fastlane. Jak implementujeme CI/CD do všech mobilních aplikací, jak jsme se k tomu dostali a co se nakonec stalo.

Na nástroji je již na síti dostatek materiálu, který nám na začátku tak chyběl, takže nástroj schválně nebudu podrobně popisovat, ale pouze odkážu na to, co jsme tehdy měli:

Článek se skládá ze dvou částí:

  • Pozadí vzniku mobilního CI/CD ve společnosti
  • Technické řešení pro zavedení CI/CD pro N-aplikace

První část je spíše nostalgie po starých časech a druhá je zkušenost, kterou na sebe můžete aplikovat.

Tak se to historicky stalo

Rok 2015

Právě jsme začali vyvíjet mobilní aplikace, pak jsme nevěděli nic o průběžné integraci, o DevOps a dalších módních věcech. Každou aktualizaci aplikace spustil sám vývojář ze svého stroje. A pokud je to pro Android docela jednoduché - sestavené, podepsané .apk a nahráli ho do Google Developer Console, pro iOS nám pak tehdejší distribuční nástroj přes Xcode zanechal skvělé večery – pokusy o stažení archivu často končily chybami a museli jsme to zkoušet znovu. Ukázalo se, že nejpokročilejší vývojář nepíše kód několikrát do měsíce, ale aplikaci vydává.

Rok 2016

Vyrostli jsme, už jsme měli myšlenky na to, jak osvobodit vývojáře z celého dne na vydání a objevila se i druhá aplikace, která nás jen více posunula k automatizaci. Ten samý rok jsme poprvé nainstalovali Jenkinse a napsali spoustu děsivých skriptů, velmi podobných těm, které fastlane ukazuje ve své dokumentaci.

$ 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"

Bohužel až doteď věděli jen naši vývojáři, jak tyto skripty fungují a proč je potřeba tato nekonečná hromada klíčů, a když se zase něco pokazilo, dostali „nádherné večery“ na analýzu protokolů.

Rok 2017

Letos jsme se dozvěděli, že existuje něco jako fastlane. Nebylo tolik informací jako nyní – jak je začít, jak je používat. A samotný nástroj byl v té době ještě hrubý: neustálé chyby nás jen zklamaly a bylo těžké uvěřit v magickou automatizaci, kterou slibovaly.

Nicméně hlavní utility zahrnuté v jádru fastlane jsou gym и pilot, podařilo se nám to nastartovat.

Naše skripty byly trochu vylepšeny.

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

Byly vylepšeny, už jen proto, že ne všechny potřebné parametry xcodebuild, musíte uvést - gym nezávisle pochopí, kde a co leží. A pro přesnější doladění můžete zadat stejné klíče jako v xcodebuild, pouze pojmenování kláves je přehlednější.

Tentokrát se díky posilovně a vestavěnému formátovači xcpretty staly protokoly sestavení mnohem čitelnější. To začalo šetřit čas na opravování rozbitých sestav a někdy na to mohl uvolňovací tým přijít sám.

Bohužel měření rychlosti montáže xcodebuild и gym Neudělali jsme to, ale budeme důvěřovat dokumentaci – až 30% zrychlení.

Jediný proces pro všechny aplikace

Rok 2018 a současnost

V roce 2018 se proces vytváření a zavádění aplikací zcela přesunul do Jenkins, vývojáři přestali vydávat ze svých strojů a právo vydávat měl pouze tým pro vydání.

Už jsme chtěli zlepšit spouštění testů a statické analýzy a naše skripty rostly a rostly. Rostl a měnil se spolu s našimi aplikacemi. V té době bylo aplikací asi 10. Když uvážíme, že máme dvě platformy, je to asi 20 „živých“ skriptů.

Pokaždé, když jsme chtěli do skriptu přidat nový krok, museli jsme kousky zkopírovat a vložit do všech skriptů shellu. Možná jsme mohli pracovat opatrněji, ale často takové změny končily překlepy, které se proměnily ve večery, kdy tým pro vydání opravoval skripty a zjišťoval, který chytrák přidal tento příkaz a co vlastně dělá. Obecně se nedá říci, že by skripty pro sestavení pro jednu platformu byly alespoň trochu podobné. I když určitě udělali to samé.

Aby bylo možné zahájit proces pro novou aplikaci, bylo nutné strávit den výběrem „čerstvé“ verze těchto skriptů, odladit ji a říci, že „ano, funguje“.

V létě 2018 jsme se opět podívali na stále se rozvíjející fastlane.

Úkol č. 1: shrňte všechny kroky skriptu a přepište je do Fastfile

Když jsme začínali, naše skripty vypadaly jako šátek skládající se ze všech kroků a berlí v jednom skriptu v Jenkins. Ještě jsme nepřešli na potrubí a rozdělení podle etap.

Podívali jsme se na to, co máme, a identifikovali jsme 4 kroky, které odpovídají popisu našeho CI/CD:

  • build - instalace závislostí, sestavení archivu,
  • test — spuštění testů vývojářských jednotek, výpočet pokrytí,
  • sonar - spouští všechny lintry a odesílá zprávy do SonarQube,
  • deploy — odeslání artefaktu do alfy (TestFlight).

A pokud nezajdete do podrobností a vynecháte klíče používané v akcích, získáte tento Fastfile:

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

Ve skutečnosti se náš první Fastfile ukázal jako monstrózní, vezmeme-li v úvahu některé berličky, které jsme stále potřebovali, a množství parametrů, které jsme nahradili:

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

Ve výše uvedeném příkladu je pouze část parametrů, které musíme zadat: jedná se o parametry sestavení - schéma, konfigurace, názvy profilů poskytování a také distribuční parametry - Apple ID účtu vývojáře, heslo, ID aplikace atd. na. Jako první aproximaci jsme všechny tyto klíče vložili do speciálních souborů - Gymfile, Matchfile и Appfile.

Nyní v Jenkins můžete volat krátké příkazy, které nerozmazávají pohled a jsou snadno čitelné okem:

# fastlane ios <lane_name>

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

Hurá, máme se skvěle

Co jsi dostal? Jasné příkazy pro každý krok. Vyčištěné skripty, úhledně uspořádané do rychlých souborů. S radostí jsme běželi za vývojáři a požádali je, aby do svých úložišť přidali vše, co potřebují.

Časem jsme si ale uvědomili, že se setkáme se stejnými potížemi – stále budeme mít 20 skriptů sestavení, které by tak či onak začaly žít svým vlastním životem, bylo by obtížnější je upravovat, protože by se skripty přesunuly do repozitářů, a neměli jsme tam přístup. A obecně, takto nebude možné naši bolest vyřešit.

Mobilní CICD zážitek: jeden rychlý standard pro mnoho mobilních aplikací

Úkol #2: získejte jeden Fastfile pro N aplikací

Nyní se zdá, že řešení problému není tak obtížné - nastavte proměnné a jdeme na to. Ano, ve skutečnosti se tím problém vyřešil. Ale ve chvíli, kdy jsme to podělali, jsme neměli ani odborné znalosti v oblasti fastlane, ani v Ruby, ve kterém se fastlane píše, ani užitečné příklady na síti - každý, kdo tehdy psal o fastlane, byl omezen na příklad pro jednu aplikaci pro jeden vývojář.

Fastlane si poradí s proměnnými prostředí a už jsme to vyzkoušeli nastavením hesla Keychain:

ENV['KEYCHAIN_PASSWORD']

Po zhlédnutí našich skriptů jsme identifikovali společné části:

#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

Nyní, abychom mohli začít používat tyto klíče v souborech fastlane, museli jsme přijít na to, jak je tam doručit. Fastlane má na to řešení: načítání proměnných přes dotenv. Dokumentace říká, že pokud je pro vás důležité načíst klíče pro různé účely, vytvořte několik konfiguračních souborů v adresáři fastlane .env, .env.default, .env.development.

A pak jsme se rozhodli tuto knihovnu využít trochu jinak. Neumístěme do úložiště vývojářů rychlé skripty a jejich metainformace, ale jedinečné klíče této aplikace v souboru .env.appName.

Sami Fastfile, Appfile, Matchfile и Gymfile, schovali jsme jej do samostatného úložiště. Byl tam skrytý další soubor s klíči hesel z jiných služeb - .env.
Můžete vidět příklad zde.

Mobilní CICD zážitek: jeden rychlý standard pro mnoho mobilních aplikací

Na CI se volání příliš nezměnilo, byl přidán konfigurační klíč pro konkrétní aplikaci:

# 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

Před spuštěním příkazů načteme naše úložiště skripty. Nevypadá to moc hezky:

git clone [email protected]/FastlaneCICD.git fastlane_temp

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

Toto řešení prozatím opustilo, ačkoli Fastlane má řešení pro stahování Fastfile přes akce import_from_git, ale funguje pouze pro Fastfile, ale ne pro ostatní soubory. Pokud chcete „opravdu krásné“, můžete si napsat vlastní action.

Podobná sada byla vytvořena pro Android aplikace a ReactNative, soubory jsou ve stejném úložišti, ale v různých větvích iOS, android и react_native.

Když chce release team přidat nějaký nový krok, změny ve skriptu se zaznamenávají přes MR v git, už není třeba hledat viníky nefunkčních skriptů a obecně, teď se to musíte pokusit rozbít.

Teď je to jisté

Dříve jsme trávili čas údržbou všech skriptů, jejich aktualizací a opravou všech důsledků aktualizací. Bylo velkým zklamáním, když důvodem chyb a výpadků ve vydáních byly jednoduché překlepy, které bylo tak těžké udržet ve změti skriptů shellu. Nyní jsou tyto chyby omezeny na minimum. Změny jsou zaváděny do všech aplikací najednou. A vložení nové aplikace do procesu trvá 15 minut – nastavte kanál šablon na CI a přidejte klíče do úložiště vývojáře.

Zdá se, že pointa s Fastfile pro Android a podpisem aplikace zůstává nevysvětlena, pokud bude článek zajímavý, napíšu pokračování. Rád uvidím vaše dotazy nebo návrhy „jak byste tento problém vyřešili“ v komentářích nebo na Telegramu Baškirová.

Zdroj: www.habr.com

Přidat komentář