Experiență CICD mobilă: un standard fastlane pentru multe aplicații mobile

Experiență CICD mobilă: un standard fastlane pentru multe aplicații mobile
Aș dori să vorbesc despre integrarea și livrarea continuă pentru aplicațiile mobile care folosesc Fastlane. Cum implementăm CI/CD pe toate aplicațiile mobile, cum am ajuns acolo și ce s-a întâmplat în cele din urmă.

Există deja suficient material în rețea despre instrument, care ne-a lipsit atât de mult la început, așa că în mod deliberat nu voi descrie instrumentul în detaliu, ci mă voi referi doar la ceea ce aveam atunci:

Articolul constă din două părți:

  • Contextul apariției CI/CD-ului mobil în companie
  • Soluție tehnică pentru lansarea CI/CD pentru aplicații N

Prima parte este mai mult nostalgie pentru vremurile de demult, iar a doua este o experiență pe care o poți aplica și tu însuți.

Așa s-a întâmplat istoric

Anul 2015

Tocmai am început să dezvoltăm aplicații mobile, apoi nu știam nimic despre integrarea continuă, despre DevOps și alte lucruri la modă. Fiecare actualizare a aplicației a fost lansată de dezvoltator însuși de pe computerul său. Și dacă pentru Android este destul de simplu - asamblat, semnat .apk și l-am încărcat în Google Developer Console, apoi pentru iOS instrumentul de distribuție de atunci prin Xcode ne-a lăsat cu seri grozave - încercările de descărcare a arhivei se terminau adesea cu erori și a trebuit să încercăm din nou. S-a dovedit că cel mai avansat dezvoltator nu scrie cod de mai multe ori pe lună, ci mai degrabă lansează aplicația.

Anul 2016

Am crescut, ne-am gândit deja cum să eliberăm dezvoltatorii de o zi întreagă pentru o lansare și a apărut și o a doua aplicație, care doar ne-a împins mai mult către automatizare. În același an, am instalat Jenkins pentru prima dată și am scris o grămadă de scripturi înfricoșătoare, foarte asemănătoare cu cele pe care fastlane le arată în documentația sa.

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

Din păcate, până acum doar dezvoltatorii noștri știau cum funcționează aceste scripturi și de ce este nevoie de acest teanc nesfârșit de chei, iar când ceva s-a spart din nou, au primit „serile superbe” pentru analiza jurnalelor.

Anul 2017

Anul acesta am aflat că există așa ceva ca Fastlane. Nu existau atât de multe informații ca acum - cum să porniți una, cum să o folosiți. Și instrumentul în sine era încă grosier la acea vreme: erorile constante nu ne dezamăgeau decât și era greu de crezut în automatizarea magică pe care o promiteau.

Cu toate acestea, principalele utilități incluse în nucleul Fastlane sunt gym и pilot, am reușit să-l pornim.

Scripturile noastre au fost puțin îmbunătățite.

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

Ele au fost îmbunătățite, fie și numai pentru că nu toți parametrii necesari pentru xcodebuild, trebuie să indicați - gym va înțelege în mod independent unde și ce se află. Și pentru o reglare mai fină, puteți specifica aceleași taste ca în xcodebuild, doar denumirea cheilor este mai clară.

De data aceasta, datorită sala de gimnastică și formatatorului xcpretty încorporat, jurnalele de construcție au devenit mult mai lizibile. Acest lucru a început să economisească timp la repararea ansamblurilor defecte și, uneori, echipa de lansare și-a putut da seama singură.

Din păcate, măsurătorile vitezei de asamblare xcodebuild и gym Nu am făcut-o, dar vom avea încredere în documentație - accelerare de până la 30%.

Proces unic pentru toate aplicațiile

Anul 2018 și în prezent

Până în 2018, procesul de construire și lansare a aplicațiilor s-a mutat complet la Jenkins, dezvoltatorii au încetat să mai lanseze de pe mașinile lor și doar echipa de lansare avea dreptul să le lanseze.

Ne doream deja să îmbunătățim lansarea de teste și analize statice, iar scripturile noastre au crescut și au crescut. A crescut și s-a schimbat odată cu aplicațiile noastre. La acea vreme, existau aproximativ 10 aplicații, având în vedere că avem două platforme, adică aproximativ 20 de scripturi „vii”.

De fiecare dată când doream să adăugăm un nou pas la script, trebuia să copiam-lipim piesele în toate scripturile shell. Poate că am fi putut lucra cu mai multă atenție, dar de multe ori astfel de modificări s-au terminat cu greșeli de scriere, care s-au transformat în seri pentru echipa de lansare pentru a repara scripturile și a afla ce tip inteligent a adăugat această comandă și ce face de fapt. În general, nu se poate spune că scripturile de asamblare pentru o platformă au fost cel puțin oarecum similare. Deși cu siguranță au făcut același lucru.

Pentru a începe un proces pentru o nouă aplicație, a fost necesar să petreceți o zi pentru a selecta o versiune „proaspătă” a acestor scripturi, a o depana și a spune că „da, funcționează”.

În vara anului 2018, ne-am uitat din nou către linia rapidă în curs de dezvoltare.

Sarcina #1: rezumați toți pașii de script și rescrieți-i în Fastfile

Când am început, scripturile noastre arătau ca o cârpă formată din toți pașii și cârjele într-un singur script shell în Jenkins. Încă nu am trecut la conductă și împărțirea pe etape.

Ne-am uitat la ceea ce avem și am identificat 4 pași care se potrivesc cu descrierea CI/CD-ului nostru:

  • build - instalarea dependențelor, asamblarea arhivei,
  • test — rularea testelor unitare pentru dezvoltatori, calculul acoperirii,
  • sonar - lansează toate linterurile și trimite rapoarte către SonarQube,
  • implementare — trimiterea unui artefact către alpha (TestFlight).

Și dacă nu intrați în detalii, omițând cheile folosite în acțiuni, veți obține acest 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

De fapt, primul nostru Fastfile s-a dovedit a fi monstruos, având în vedere câteva dintre cârjele de care mai aveam nevoie și numărul de parametri pe care i-am înlocuit:

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

În exemplul de mai sus, doar o parte din parametrii pe care trebuie să îi specificăm: aceștia sunt parametrii de compilare - schema, configurația, numele profilului de furnizare, precum și parametrii de distribuție - ID-ul Apple al contului de dezvoltator, parola, ID-ul aplicației etc. pe. Ca o primă aproximare, punem toate aceste chei în fișiere speciale - Gymfile, Matchfile и Appfile.

Acum, în Jenkins, puteți apela comenzi scurte care nu estompează vederea și sunt ușor de citit cu ochiul:

# fastlane ios <lane_name>

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

Ura, suntem grozavi

Ce ai primit? Comenzi clare pentru fiecare pas. Scripturi curățate, ordonate în fișiere fastlane. Bucurându-ne, am alergat la dezvoltatori, cerându-le să adauge tot ce au nevoie în arhivele lor.

Dar ne-am dat seama în timp că vom întâmpina aceleași dificultăți - vom avea totuși 20 de scripturi de asamblare care ar începe într-un fel sau altul să-și trăiască propria viață, ar fi mai dificil să le editam, deoarece script-urile s-ar muta în depozite, iar noi nu aveam acces acolo. Și, în general, nu va fi posibil să ne rezolvăm durerea în acest fel.

Experiență CICD mobilă: un standard fastlane pentru multe aplicații mobile

Sarcina #2: obțineți un singur Fastfile pentru N aplicații

Acum se pare că rezolvarea problemei nu este atât de dificilă - setați variabilele și să mergem. Da, de fapt, așa a fost rezolvată problema. Dar în momentul în care o dădeam, nu aveam nici experiență în fastlane în sine, nici în Ruby, în care este scris fastlane, nici exemple utile în rețea - toți cei care scriau despre fastlane atunci se limitau la un exemplu pentru o aplicație. pentru un dezvoltator.

Fastlane poate gestiona variabilele de mediu și am încercat deja acest lucru setând parola Keychain:

ENV['KEYCHAIN_PASSWORD']

După ce ne-am uitat la scripturile noastre, am identificat părțile comune:

#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

Acum, pentru a începe să folosim aceste chei în fișierele Fastlane, a trebuit să ne dăm seama cum să le livrăm acolo. Fastlane are o soluție pentru asta: încărcarea variabilelor prin dotenv. Documentația spune că, dacă este important pentru dvs. să încărcați chei pentru diferite scopuri, creați mai multe fișiere de configurare în directorul Fastlane .env, .env.default, .env.development.

Și apoi am decis să folosim această bibliotecă puțin diferit. Să plasăm în depozitul dezvoltatorilor nu scripturile fastlane și meta informațiile sale, ci cheile unice ale acestei aplicații în fișier .env.appName.

se Fastfile, Appfile, Matchfile и Gymfile, l-am ascuns într-un depozit separat. Un fișier suplimentar cu chei de parolă de la alte servicii a fost ascuns acolo - .env.
Puteți vedea un exemplu aici.

Experiență CICD mobilă: un standard fastlane pentru multe aplicații mobile

Pe CI, apelul nu s-a schimbat prea mult; a fost adăugată o cheie de configurare pentru o anumită aplicație:

# 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

Înainte de a rula comenzile, încărcăm depozitul nostru cu scripturi. nu arata asa frumos:

git clone [email protected]/FastlaneCICD.git fastlane_temp

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

Am lăsat această soluție pentru moment, deși Fastlane are o soluție pentru descărcarea Fastfile prin intermediul acțiune import_from_git, dar funcționează numai pentru Fastfile, dar nu și pentru alte fișiere. Dacă vrei „cu adevărat frumos”, poți să-l scrii pe al tău action.

Un set similar a fost realizat pentru aplicațiile Android și ReactNative, fișierele sunt în același depozit, dar în ramuri diferite iOS, android и react_native.

Când echipa de lansare dorește să adauge un pas nou, modificările în script sunt înregistrate prin MR în git, nu mai este nevoie să cauți vinovații de scripturi sparte și, în general, acum trebuie să încerci să-l spargi.

Acum asta e cu siguranță

Anterior, am petrecut timp întreținând toate scripturile, actualizându-le și reparând toate consecințele actualizărilor. A fost foarte dezamăgitor când motivele erorilor și timpilor de nefuncționare în versiuni au fost simple greșeli de scriere, care erau atât de greu de urmărit în amestecul de scripturi shell. Acum astfel de erori sunt reduse la minimum. Modificările sunt implementate simultan în toate aplicațiile. Și este nevoie de 15 minute pentru a introduce o nouă aplicație în proces - configurați o conductă de șablon pe CI și adăugați cheile la depozitul dezvoltatorului.

Se pare că punctul cu Fastfile pentru Android și semnătura aplicației rămâne neexplicat; dacă articolul este interesant, voi scrie o continuare. Voi fi bucuros să văd întrebările sau sugestiile dumneavoastră „cum ați rezolva această problemă” în comentarii sau pe Telegram bashkirova.

Sursa: www.habr.com

Adauga un comentariu