Mobil CICD-upplevelse: en fastlane-standard för många mobila applikationer

Mobil CICD-upplevelse: en fastlane-standard för många mobila applikationer
Jag skulle vilja prata om kontinuerlig integration och leverans för mobilappar som använder fastlane. Hur vi implementerar CI/CD på alla mobila applikationer, hur vi kom dit och vad som hände till slut.

Det finns redan tillräckligt med material på nätverket på verktyget, som vi så saknade i början, så jag kommer medvetet inte att beskriva verktyget i detalj, utan kommer bara att referera till det vi hade då:

Artikeln består av två delar:

  • Bakgrund till framväxten av mobil CI/CD i företaget
  • Teknisk lösning för utrullning av CI/CD för N-applikationer

Den första delen är mer nostalgi för gamla dagar, och den andra är en upplevelse som du kan applicera på dig själv.

Det var så det hände historiskt

År 2015

Vi har precis börjat utveckla mobila applikationer, sedan visste vi ingenting om kontinuerlig integration, om DevOps och andra moderiktiga saker. Varje programuppdatering rullades ut av utvecklaren själv från sin maskin. Och om det är ganska enkelt för Android - monterat, signerat .apk och laddade upp det till Google Developer Console, sedan för iOS gav det dåvarande distributionsverktyget via Xcode oss fantastiska kvällar - försök att ladda ner arkivet slutade ofta i fel och vi var tvungna att försöka igen. Det visade sig att den mest avancerade utvecklaren inte skriver kod flera gånger i månaden, utan snarare släpper applikationen.

År 2016

Vi växte upp, vi hade redan tankar om hur vi skulle frigöra utvecklare från en hel dag för en release, och en andra applikation dök också upp, som bara drev oss mer mot automatisering. Samma år installerade vi Jenkins för första gången och skrev ett gäng läskiga skript, väldigt lika de som fastlane visar i sin dokumentation.

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

Tyvärr har bara våra utvecklare hittills vetat hur dessa skript fungerar och varför denna oändliga hög med nycklar behövs, och när något gick sönder igen fick de "underbara kvällar" för att analysera loggar.

År 2017

I år lärde vi oss att det finns något sådant som fastlane. Det fanns inte så mycket information som det finns nu - hur man startar en, hur man använder den. Och själva verktyget var fortfarande grovt på den tiden: ständiga fel gjorde oss bara besvikna och det var svårt att tro på den magiska automatisering som de lovade.

De viktigaste verktygen som ingår i fastlane-kärnan är dock gym и pilot, vi lyckades starta den.

Våra manus har förbättrats lite.

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

De har förbättrats, om så bara för att inte alla parametrar som behövs för xcodebuildmåste du ange - gym kommer självständigt att förstå var och vad som ligger. Och för mer finjustering kan du ange samma nycklar som i xcodebuild, bara namnet på nycklarna är tydligare.

Den här gången, tack vare gym och den inbyggda xcpretty-formateraren, har byggloggarna blivit mycket mer läsbara. Detta började spara tid på att fixa trasiga sammansättningar, och ibland kunde releaseteamet ta reda på det på egen hand.

Tyvärr, monteringshastighetsmätningar xcodebuild и gym Vi gjorde det inte, men vi litar på dokumentationen - upp till 30 % snabbare.

En enda process för alla applikationer

År 2018 och nu

År 2018 flyttade processen med att bygga och rulla ut applikationer helt till Jenkins, utvecklare slutade släppa från sina maskiner och bara releaseteamet hade rätt att släppa.

Vi ville redan förbättra lanseringen av tester och statisk analys, och våra skript växte och växte. Växte och förändrades tillsammans med våra applikationer. Vid den tiden fanns det cirka 10 applikationer. Med tanke på att vi har två plattformar, är det cirka 20 "levande" skript.

Varje gång vi ville lägga till ett nytt steg i skriptet var vi tvungna att kopiera och klistra in bitarna i alla skalskript. Vi kanske kunde ha arbetat mer noggrant, men ofta slutade sådana ändringar i stavfel, som blev kvällar för releaseteamet för att fixa skript och ta reda på vilken smart kille som lagt till det här kommandot och vad det faktiskt gör. Generellt kan det inte sägas att skripten för montering för en plattform åtminstone var något liknande. Även om de säkert gjorde samma sak.

För att starta en process för en ny applikation var det nödvändigt att spendera en dag för att välja en "färsk" version av dessa skript, felsöka den och säga att "ja, det fungerar."

Sommaren 2018 tittade vi återigen mot den fortfarande utvecklade fastlanen.

Uppgift #1: sammanfatta alla skriptsteg och skriv om dem i Fastfile

När vi började såg våra manus ut som en fotduk som bestod av alla steg och kryckor i ett skalmanus i Jenkins. Vi har ännu inte gått över till pipeline och division för steg.

Vi tittade på vad vi har och identifierade 4 steg som passar beskrivningen av vår CI/CD:

  • bygga - installera beroenden, sätta ihop arkivet,
  • test — köra tester för utvecklarenhet, beräkna täckning,
  • ekolod - startar alla linters och skickar rapporter till SonarQube,
  • deploy — skickar en artefakt till alpha (TestFlight).

Och om du inte går in på detaljer och utelämnar nycklarna som används i åtgärder, får du denna snabbfil:

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

Faktum är att vår första Fastfile visade sig vara monstruös, med tanke på några av de kryckor som vi fortfarande behövde och antalet parametrar som vi bytte ut:

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 exemplet ovan är det bara en del av parametrarna som vi behöver specificera: dessa är byggparametrarna - schema, konfiguration, tilldelningsprofilnamn, såväl som distributionsparametrar - Apple-ID för utvecklarkontot, lösenord, applikations-ID och så på. Som en första uppskattning lägger vi alla dessa nycklar i specialfiler - Gymfile, Matchfile и Appfile.

Nu i Jenkins kan du anropa korta kommandon som inte suddar vyn och som är lätta att läsa för ögat:

# fastlane ios <lane_name>

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

Hurra, vi är bra

Vad fick du? Tydliga kommandon för varje steg. Rensade skript, snyggt ordnade i fastlane-filer. Glada sprang vi till utvecklarna och bad dem lägga till allt de behövde till sina förråd.

Men vi insåg med tiden att vi skulle stöta på samma svårigheter - vi skulle fortfarande ha 20 monteringsskript som på ett eller annat sätt skulle börja leva sina egna liv, det skulle bli svårare att redigera dem, eftersom skripten skulle flytta till arkiv, och vi hade inte tillgång dit. Och i allmänhet kommer det inte att vara möjligt att lösa vår smärta på detta sätt.

Mobil CICD-upplevelse: en fastlane-standard för många mobila applikationer

Uppgift #2: skaffa en enda Fastfile för N applikationer

Nu verkar det som att det inte är så svårt att lösa problemet - ställ in variablerna och låt oss gå. Ja, faktiskt, det var så problemet löstes. Men för tillfället när vi skruvade ihop det hade vi varken expertis i själva fastlane, eller i Ruby, som fastlane står i, eller användbara exempel på nätverket - alla som skrev om fastlane då var begränsade till ett exempel för en applikation för en utvecklare.

Fastlane kan hantera miljövariabler, och vi har redan provat detta genom att ställa in lösenordet för nyckelring:

ENV['KEYCHAIN_PASSWORD']

Efter att ha tittat på våra skript identifierade vi de vanliga delarna:

#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

Nu, för att börja använda dessa nycklar i fastlane-filer, var vi tvungna att ta reda på hur vi skulle leverera dem där. Fastlane har en lösning för detta: ladda variabler via dotenv. Dokumentationen säger att om det är viktigt för dig att ladda nycklar för olika ändamål, skapa flera konfigurationsfiler i fastlane-katalogen .env, .env.default, .env.development.

Och sedan bestämde vi oss för att använda det här biblioteket lite annorlunda. Låt oss inte placera fastlane-skripten och dess metainformation i utvecklarens repository, utan de unika nycklarna för denna applikation i filen .env.appName.

själva Fastfile, Appfile, Matchfile и Gymfile, gömde vi det i ett separat arkiv. En ytterligare fil med lösenordsnycklar från andra tjänster gömdes där - .env.
Du kan se ett exempel här.

Mobil CICD-upplevelse: en fastlane-standard för många mobila applikationer

På CI har samtalet inte förändrats mycket; en konfigurationsnyckel för en specifik applikation har lagts till:

# 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

Innan vi kör kommandona laddar vi vårt arkiv med skript. Ser inte så trevligt ut:

git clone [email protected]/FastlaneCICD.git fastlane_temp

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

Lämnade denna lösning för nu, även om Fastlane har en lösning för att ladda ner Fastfile via handling import_from_git, men det fungerar bara för Fastfile, men inte för andra filer. Om du vill ha "riktigt vacker", kan du skriva din egen action.

En liknande uppsättning gjordes för Android-applikationer och ReactNative, filerna finns i samma arkiv, men i olika grenar iOS, android и react_native.

När releaseteamet vill lägga till något nytt steg, registreras ändringar i skriptet via MR i git, det finns inte längre något behov av att leta efter de skyldiga till trasiga skript, och generellt sett måste du nu försöka bryta det.

Nu är det det säkert

Tidigare ägnade vi tid åt att underhålla alla skript, uppdatera dem och fixa alla konsekvenser av uppdateringar. Det var en stor besvikelse när orsakerna till fel och stillestånd i releaser var enkla stavfel som var så svåra att hålla reda på i virrvarret av skalskript. Nu är sådana fel reducerade till ett minimum. Ändringar rullas ut till alla applikationer på en gång. Och det tar 15 minuter att lägga in en ny applikation i processen - skapa en mallpipeline på CI och lägg till nycklarna till utvecklarens arkiv.

Det verkar som att poängen med Fastfile för Android och applikationssignatur förblir oförklarad; om artikeln är intressant kommer jag att skriva en fortsättning. Jag kommer gärna se dina frågor eller förslag "hur skulle du lösa det här problemet" i kommentarerna eller på Telegram bashkirova.

Källa: will.com

Lägg en kommentar