Experiencia CICD móbil: un estándar de liña rápida para moitas aplicacións móbiles

Experiencia CICD móbil: un estándar de liña rápida para moitas aplicacións móbiles
Gustaríame falar sobre a integración e entrega continuas de aplicacións móbiles que usan Fastlane. Como implementamos CI/CD en todas as aplicacións móbiles, como chegamos alí e que pasou ao final.

Xa hai material suficiente na rede sobre a ferramenta, que tanto nos faltaba ao principio, polo que non vou describir a ferramenta en detalle deliberadamente, senón que só me referirei ao que tiñamos entón:

O artigo consta de dúas partes:

  • Antecedentes da aparición do CI/CD móbil na empresa
  • Solución técnica para implementar CI/CD para aplicacións N

A primeira parte é máis nostalxia dos vellos tempos, e a segunda é unha experiencia que podes aplicar a ti mesmo.

Así aconteceu historicamente

Ano 2015

Acabamos de comezar a desenvolver aplicacións móbiles, entón non sabiamos nada sobre a integración continua, sobre DevOps e outras cousas de moda. Cada actualización da aplicación foi lanzada polo propio desenvolvedor desde a súa máquina. E se para Android é bastante sinxelo: montado, asinado .apk e subiuno á Consola de desenvolvedores de Google, despois para iOS a ferramenta de distribución daquela a través de Xcode deixounos grandes noites: os intentos de descargar o arquivo a miúdo terminaban en erros e tivemos que tentalo de novo. Resultou que o programador máis avanzado non escribe código varias veces ao mes, senón que libera a aplicación.

Ano 2016

Crecemos, xa tiñamos pensamentos sobre como liberar aos desenvolvedores dun día enteiro para un lanzamento, e tamén apareceu unha segunda aplicación, que só nos impulsou máis cara á automatización. Ese mesmo ano, instalamos Jenkins por primeira vez e escribimos un montón de guións de medo, moi similares aos que mostra Fastlane na súa documentación.

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

Desafortunadamente, ata agora só os nosos desenvolvedores sabían como funcionan estes scripts e por que se necesita esta pila interminable de claves, e cando algo volveu romper, tiñan as "noites fermosas" para analizar os rexistros.

Ano 2017

Este ano decatámonos de que existe un fastlane. Non había tanta información como a que hai agora: como comezar un, como usalo. E a ferramenta en si aínda era tosca naquel momento: os erros constantes só nos decepcionaban e era difícil crer na automatización máxica que prometían.

Non obstante, as principais utilidades incluídas no núcleo fastlane son gym и pilot, conseguimos comezalo.

Os nosos guións melloráronse un pouco.

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

Melloráronse, aínda que só porque non todos os parámetros necesarios para xcodebuild, debe indicar - gym entenderá de forma independente onde e que está. E para máis axustes, podes especificar as mesmas teclas que en xcodebuild, só o nome das teclas é máis claro.

Esta vez, grazas ao ximnasio e ao formateador xcpretty incorporado, os rexistros de compilación fixéronse moito máis lexibles. Isto comezou a aforrar tempo na reparación de conxuntos rotos e, ás veces, o equipo de lanzamento podía resolvelo por si mesmo.

Desafortunadamente, as medidas de velocidade de montaxe xcodebuild и gym Non o fixemos, pero confiaremos na documentación, ata un 30 % de aceleración.

Proceso único para todas as solicitudes

Ano 2018 e presente

En 2018, o proceso de creación e implementación de aplicacións trasladouse por completo a Jenkins, os desenvolvedores deixaron de lanzar as súas máquinas e só o equipo de lanzamento tiña dereito a liberar.

Xa queriamos mellorar o lanzamento de probas e análises estáticas, e os nosos guións creceron e creceron. Creceron e mudaron xunto coas nosas aplicacións. Nese momento había unhas aplicacións 10. Tendo en conta que temos dúas plataformas, son uns 20 scripts "vivos".

Cada vez que queriamos engadir un novo paso ao guión, tiñamos que copiar e pegar as pezas en todos os guións de shell. Quizais puidésemos traballar con máis coidado, pero moitas veces estes cambios terminaban en erros tipográficos, que se convertían en noites para que o equipo de lanzamento arranxase guións e descubrase que tipo intelixente engadiu este comando e que fai realmente. En xeral, non se pode dicir que os guións para a montaxe dunha plataforma fosen polo menos algo similares. Aínda que certamente fixeron o mesmo.

Para iniciar un proceso para unha nova aplicación, foi necesario pasar un día para seleccionar unha versión "nueva" destes scripts, depurala e dicir que "si, funciona".

No verán de 2018, miramos de novo cara á vía rápida aínda en desenvolvemento.

Tarefa n.º 1: resume todos os pasos do guión e reescribilos en Fastfile

Cando comezamos, os nosos guións parecían un pano composto por todos os pasos e muletas nun guión de shell en Jenkins. Aínda non cambiamos ao gasoduto e á división por etapas.

Observamos o que temos e identificamos 4 pasos que se axustan á descrición do noso CI/CD:

  • construír - instalar dependencias, montar o arquivo,
  • proba: realizar probas unitarias de desenvolvedores, calcular a cobertura,
  • sonar: inicia todos os linters e envía informes a SonarQube,
  • implementar: enviar un artefacto a alpha (TestFlight).

E se non entras en detalles, omitindo as claves utilizadas nas accións, obterás este ficheiro rápido:

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 feito, o noso primeiro Fastfile resultou monstruoso, tendo en conta algunhas das muletas que aínda necesitabamos e o número de parámetros que substituímos:

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

No exemplo anterior, só hai que especificar parte dos parámetros: estes son os parámetros de compilación: esquema, configuración, nomes de perfil de aprovisionamento, así como parámetros de distribución: ID de Apple da conta do programador, contrasinal, ID da aplicación, etc. on. Como primeira aproximación, poñemos todas estas claves en ficheiros especiais - Gymfile, Matchfile и Appfile.

Agora en Jenkins podes chamar comandos curtos que non desenfocan a vista e son facilmente lexibles a simple vista:

# fastlane ios <lane_name>

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

Vaia, estamos xenial

Que conseguiches? Comandos claros para cada paso. Scripts limpos, ordenados en ficheiros fastlane. Alegrándonos, fomos cara aos desenvolvedores pedíndolles que engadan todo o que necesitaban aos seus repositorios.

Pero co tempo decatámonos de que atopariamos as mesmas dificultades: aínda teríamos 20 guións de montaxe que dunha ou outra forma comezarían a vivir a súa propia vida, sería máis difícil editalos, xa que os guións pasarían a repositorios. e alí non tiñamos acceso. E, en xeral, non será posible resolver a nosa dor deste xeito.

Experiencia CICD móbil: un estándar de liña rápida para moitas aplicacións móbiles

Tarefa #2: obter un único Fastfile para N aplicacións

Agora parece que resolver o problema non é tan difícil: establece as variables e imos. Si, de feito, así foi como se solucionou o problema. Pero no momento en que o fotuamos, non tiñamos coñecementos en fastlane en si, nin en Ruby, no que se escribe fastlane, nin exemplos útiles na rede: todos os que escribiron sobre fastlane entón limitáronse a un exemplo para unha aplicación para un desenvolvedor.

Fastlane pode xestionar variables de ambiente, e xa o intentamos establecendo o contrasinal do Keychain:

ENV['KEYCHAIN_PASSWORD']

Despois de mirar os nosos guións, identificamos as partes comúns:

#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

Agora, para comezar a usar estas claves nos ficheiros de fastlane, tivemos que descubrir como entregalas alí. Fastlane ten unha solución para isto: cargando variables mediante dotenv. A documentación di que se é importante que cargues claves para diferentes propósitos, cree varios ficheiros de configuración no directorio fastlane .env, .env.default, .env.development.

E entón decidimos usar esta biblioteca dun xeito un pouco diferente. Coloquemos no repositorio dos desenvolvedores non os scripts de fastlane e a súa metainformación, senón as claves únicas desta aplicación no ficheiro .env.appName.

Sami Fastfile, Appfile, Matchfile и Gymfile, ocultámolo nun repositorio separado. Alí ocultouse un ficheiro adicional con claves de contrasinal doutros servizos: .env.
Podes ver un exemplo aquí.

Experiencia CICD móbil: un estándar de liña rápida para moitas aplicacións móbiles

En CI, a chamada non cambiou moito; engadiuse unha clave de configuración para unha aplicación específica:

# 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

Antes de executar os comandos, cargamos o noso repositorio con scripts. Non se ve tan ben:

git clone [email protected]/FastlaneCICD.git fastlane_temp

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

Deixou esta solución por agora, aínda que Fastlane ten unha solución para descargar Fastfile a través acción import_from_git, pero só funciona para Fastfile, pero non para outros ficheiros. Se queres "realmente fermoso", podes escribir o teu action.

Fíxose un conxunto similar para aplicacións de Android e ReactNative, os ficheiros están no mesmo repositorio, pero en ramas diferentes iOS, android и react_native.

Cando o equipo de lanzamento quere engadir algún novo paso, os cambios no guión grávanse a través de MR en git, xa non hai que buscar os culpables dos guións rotos e, en xeral, agora tes que tentar rompelo.

Agora iso é todo seguro

Anteriormente, pasamos tempo mantendo todos os scripts, actualizándoos e corrixindo todas as consecuencias das actualizacións. Foi moi decepcionante cando os motivos dos erros e do tempo de inactividade nos lanzamentos eran simples erros de dixitación que eran tan difíciles de seguir no revolto de scripts de shell. Agora tales erros redúcense ao mínimo. Os cambios aplícanse a todas as aplicacións á vez. E leva 15 minutos poñer unha nova aplicación no proceso: configura unha canalización de modelos en CI e engade as claves ao repositorio do programador.

Parece que o punto con Fastfile para Android e a sinatura da aplicación segue sen explicar; se o artigo é interesante, escribirei unha continuación. Estarei encantado de ver as túas preguntas ou suxestións "como resolverías este problema" nos comentarios ou en Telegram bashkirova.

Fonte: www.habr.com

Engadir un comentario