Uso de las funciones gratuitas de Github Actions para CI / CD en un proyecto de Flutter

GitHub Actions es una herramienta para automatizar acciones de rutina con un repositorio y ayudarlo a crear un CI / CD para su proyecto.



Los usuarios de GitHub obtienen 2000 minutos al mes para ejecutar acciones de GitHub en la infraestructura del servicio. Aprovechemos bien este tiempo libre.



Doy instrucciones para los desarrolladores de aplicaciones Flutter: cómo ejecutar pruebas y un analizador de código para cada solicitud de extracción usando acciones de GitHub, construir un artefacto e implementarlo para probarlo en Firebase.







Una persona se acostumbra muy rápidamente a las cosas buenas. Y se acostumbra tanto que ni siquiera piensa en el hecho de que no siempre fue así. Como dice la vieja anécdota sobre un hombre y una cabra, la realización de todos los placeres de la vida ocurre en el mismo momento en que uno se ve privado de estos mismos placeres.



Si su proyecto de trabajo está funcionando bien con CI / CD, es una persona afortunada.

Tal vez trabajes en una startup y hayas configurado cuidadosamente todos los pipelines y hooks con tus propias manos.



Puede ser que todo un equipo de DevOps se encargue de su bienestar: cada mes lo hace feliz con nuevas integraciones, tiempo de construcción que se derrite ante nuestros ojos y técnicas avanzadas para implementar ensamblajes en todos los lugares imaginables e inconcebibles.



No importa. Lo principal es que siempre está seguro de que sus ensamblajes son viables y, al mismo tiempo, usted mismo se ahorra muchas tareas rutinarias muy aburridas, cuya idea siempre sumerge a los desarrolladores en la melancolía y el desaliento. Por cierto, me alegrará si escribe en los comentarios ¿cuándo fue la última vez que cambió manualmente el estado de un problema en Jira?



Dejando tu zona de confort



¿Dónde dejan la zona de confort y, lo más importante, por qué? Muchas razones. Un conocido me pidió que lo ayudara a escribir una pequeña aplicación para su propio bar, finalmente encontró el tiempo para implementar un proyecto favorito de sus sueños o decidió lanzar una biblioteca que nació accidentalmente como parte del proyecto. Finalmente, usted y su colega decidieron escribir un pequeño proyecto de muestra para el taller.



Apuesto a que en cualquiera de los escenarios, su inspiración de nuevas tareas interesantes chocará rápidamente con la dura realidad del desarrollo de software en un "entorno sin aire" (sí, en algún momento, necesitará un colector inteligente como el aire).



"CI / CD es difícil ..."



¿Qué te dices a ti mismo en esos momentos? “¡No entiendo esto! ¡Solo estoy escribiendo un teléfono móvil / frontend y no sé nada sobre tu Jenkins! " ¿Y si te dijera que no necesitas saber nada de eso?



Sí, solo necesita poder construir su proyecto usando comandos de consola, y eso es todo. Puede simplificar enormemente su vida, incluso si es un pequeño proyecto personal, y no un monstruo gigante de múltiples módulos que ya es difícil de digerir en un IDE.



Github Actions es tan simple que incluso tu abuela lo configuraría sin mucha dificultad.



Entonces, ¿de qué trata la publicación?



Si todo es tan simple, ¿por qué perder el tiempo leyendo esta obra? Responderé con una lista con viñetas:



  • Flutter. CI . , Flutter- . ,

  • . Github Actions —  . 2 000 ( ). - , .

  • . Flutter Android iOS , - . , , , .



c CI/CD , . . ($).


Github Actions, !



Github Actions es un servicio que le permite automatizar el flujo de trabajo de su repositorio. Cualquier cosa que haga manualmente con su proyecto, aparte de escribir código directamente, puede delegarlo en Acciones de Github. Si prefiere familiarizarse de inmediato con las fuentes primarias, consulte la documentación oficial .



A menudo ni siquiera sabemos lo que necesitamos automatizar. El equipo no tiene tiempo para comprender la API compleja del servicio y luego escribir y depurar la solución desde cero. Marketplace resuelve este problema : allí se publican casi 5 mil Acciones listas para usar que resuelven muchas tareas típicas (por ejemplo, enviar notificaciones sobre eventos en Telegram , analizar fuentes de proyectos para la deuda técnica ,establecer etiquetas en PR dependiendo de los archivos modificados en él ). Malas noticias: muchos de ellos son shareware, con límites de uso bastante estrictos.



El proceso de trabajo



Todo en Github Actions gira en torno a los flujos de trabajo . Cada flujo de trabajo responde a dos preguntas: qué hacer y cuándo hacerlo.



Lo que debe hacer . Aquí hay innumerables opciones: puede construir, probar e implementar sus compilaciones utilizando scripts prefabricados o creados por usted mismo. Obtenga más información sobre la configuración del flujo de trabajo.



Cuándo hacerlo . Puede activar flujos de trabajo en eventos que ocurren en el repositorio. Crear una solicitud de extracción, enviar una etiqueta de confirmación o incluso agregar una nueva estrella a su proyecto. Lista completa de ganchos



Si el flujo de trabajo no debe ejecutarse en un evento, sino en un momento determinado o con una frecuencia determinada, tiene a su disposición la sintaxis cron POSIX .Más sobre eventos regulares



En el repositorio, ya que muchos flujos de trabajo diferentes pueden coexistir al mismo tiempo. Cada flujo de trabajo se describe en un archivo YAML separado, cada uno de los cuales debe almacenarse en el directorio .github / workflows en la raíz de su repositorio. Más información sobre la sintaxis de los flujos de trabajo



Entorno de ejecución



Github Actions ofrece dos opciones para ejecutar sus flujos de trabajo:



  • Github-hosted runners — , . Windows, Linux macOS. , Codemagic, ( ). , , ;

  • Self-hosted runners — , . Github , .



En mi artículo, me centraré en la primera opción. Estamos en el camino más simple posible, ¿verdad?



Configurar el flujo de trabajo básico para Flutter



Antes de comenzar a configurar el flujo de trabajo, debemos acordar dos cosas.



Primero, la función principal del flujo de trabajo será complicar el desglose del código base. El código que no se compila, contiene problemas potenciales o rompe las pruebas no debería ser generalizado.



Segundo: puede haber algunas sutilezas en mi configuración que no serán relevantes para su proyecto. Intentaré explicarlos. Sin embargo, si está utilizando este artículo como guía, pida prestado cuidadosamente.



Finalmente, decidamos qué debe hacer nuestro flujo de trabajo. Necesitamos un plan que nos ayude a avanzar en la dirección correcta.



Paso a paso hasta el montaje terminado



El plan anterior se puede utilizar como una lista de verificación al configurar su propio flujo de trabajo. Tenemos que:



  1. dar al flujo de trabajo un nombre significativo;
  2. indicar en qué evento comenzará nuestro flujo de trabajo;
  3. decidir la máquina con qué configuración se iniciará;
  4. decidir los pasos en los que nuestro flujo de trabajo consistirá:


  • revisa el proyecto,
  • instalar Java;
  • instalar Flutter (como recordará, cada vez que tengamos una instancia limpia a nuestra disposición),
  • descargar paquetes de proyectos,
  • iniciar un analizador estático,
  • ejecutando pruebas,
  • el ensamblaje de construcción en sí,
  • Implemente la compilación en algún lugar donde los probadores puedan obtenerla.


Ahora nuestro trabajo ha adquirido una forma tangible. Pasemos a la implementación.



Cómo se verá nuestro flujo de trabajo al final
— . , , .



name: Flutter PR

on:
 pull_request:
   branches:
     - "dev/sprint-**"
   paths-ignore:
     - "docs/**"
     - "openapi/**"
     - ".vscode/**"

jobs:
 build:
   runs-on: ubuntu-latest
   steps:
     - uses: actions/checkout@v1
     - uses: actions/setup-java@v1
       with:
         java-version: "12.x"

     - uses: subosito/flutter-action@v1
       with:
         channel: "stable"

     - run: sh ./scripts/flutter_pub_get.sh

     - run: sh ./scripts/flutter_analyze.sh

     - run: flutter test

     - run: flutter build apk --release

     - uses: actions/upload-artifact@v1
       with:
         name: APK for QA
         path: build/app/outputs/apk/dev/debug/apk_name.apk

     - name: Upload artifact to Firebase App Distribution
        uses: wzieba/Firebase-Distribution-Github-Action@v1
        with:
          appId: ${{ secrets.FIREBASE_ANDROID_PROD_APP_ID }}
          token: ${{ secrets.FIREBASE_TOKEN }}
          groups: testers
          file: build/app/outputs/apk/dev/debug/apk_name.apk
          debug: true




Nombre



Obviamente, necesitamos nombrar nuestro flujo de trabajo para que el nombre refleje su esencia con la mayor precisión posible. El nombre ( docs ) es lo primero que vemos en la consola de acciones cuando se ejecuta el flujo de trabajo. Por qué nombré mi flujo de trabajo de esa manera, lo descubrirás en un momento.







name: Flutter PR


Evento desencadenante



El bloque "on" ( docs ) nos permite especificar uno o más eventos, tras el registro de los cuales queremos iniciar nuestro flujo de trabajo. Además, algunos de los eventos se pueden ajustar. 



¿Qué evento elegir? Para no perderse un desglose, puede especificar al menos todos los eventos existentes. Entonces el montaje se realizará casi de forma continua, pero ¿queremos esto? No, como en este caso, el límite de nuestro plan de tarifas gratuitas terminará increíblemente rápido. Buscaremos la solución óptima.



Supongamos que nuestro proyecto se adhiere a los acuerdos según los cuales el código no puede insertarse directamente en la rama principal del proyecto, solo mediante la creación de una solicitud de extracción. Es lógico si nuestro flujo de trabajo responderá a la creación de una solicitud de extracción y construirá un proyecto a partir de una base de código modificada:



on: pull_request


$ Esto es suficiente para trabajar, pero la solución aún no es muy óptima. La compilación se activará en cada solicitud de extracción creada. Esto es redundante, ya que solo nos interesan las solicitudes de extracción dirigidas a la rama principal del proyecto. La sintaxis de Github Actions nos permite especificar los nombres (o máscaras) de las ramas que nos interesan.



on:
 pull_request:
   branches:
     - "dev/sprint-**"


$ Y nuevamente estamos buscando formas de optimizar el proceso. Hay archivos que, incluso en teoría, no pueden dañar su proyecto: documentación del proyecto, Swagger, estilo de código general y configuraciones IDE. Afortunadamente, tenemos la capacidad de ignorar dichos archivos mediante la máscara de ruta. Como resultado, el bloque "activado" se verá así:



on:
 pull_request:
   branches:
     - "dev/sprint-**"
   paths-ignore:
     - "docs/**"
     - "drz-swagger/**"
     - ".vscode/**"


Importante : solo haga una solicitud de extracción si está listo para fusionarla. Cada siguiente envío a una solicitud de extracción ya creada reiniciará el flujo de trabajo.

Configuración del trabajo







Finalmente, estamos listos para configurar el trabajo ( docs ). Ahora es el momento de aclarar qué papel juega el trabajo en el flujo de trabajo.



Cada flujo de trabajo debe incluir al menos un trabajo. Es un trabajo que contiene una descripción paso a paso de los pasos que realizamos con nuestro proyecto. El número de trabajos en un flujo de trabajo no está limitado, así como el número de pasos en un trabajo. De forma predeterminada, todos los trabajos se ejecutan en paralelo, a menos que se especifique la dependencia de un trabajo de los resultados de otro. Nuestro proyecto tendrá un solo trabajo que se encargará de construir el proyecto.



Configurando el medio ambiente



Cada vez que el flujo de trabajo se ejecuta en una instancia limpia de máquina virtual. Lo único que podemos elegir es el sistema operativo que se instalará en esta máquina. ¿Qué elegir?



Es tentador elegir macOS, porque estamos planeando crear una aplicación Flutter para las plataformas de destino: Android e iOS. Malas noticias. Un minuto de uso de una instancia con macOS se factura como diez (10 !!!) minutos de uso de una instancia con Ubuntu. En una instancia con Windows, en nuestro caso, no tiene ningún sentido, ya que todavía no será posible ensamblar un ensamblaje de iOS allí, y su tiempo de uso es dos veces más caro que una instancia con Ubuntu. Más sobre facturación



$¿Cómo podemos asegurarnos de que nuestros 2.000 minutos gratuitos no se conviertan en 200? No existe una buena solución. Decidí no construir la compilación en iOS al crear una solicitud de extracción. Esto potencialmente afectará la estabilidad de la compilación de iOS. También hay una opción de compromiso: crear una compilación de iOS en macOS solo cuando se cambia pubspec.yaml o cualquier archivo del directorio / ios ; en otros casos, compila solo una compilación de Android en una instancia con Ubuntu. Esto se puede hacer por analogía con cómo configuramos los archivos de ignorar para el bloque "on" .



jobs:
 build:
   runs-on: ubuntu-latest


Puede ver las especificaciones técnicas , así como una lista del software instalado "listo para usar" . Flutter y Java, desafortunadamente, no están incluidos en esta lista. Deberán instalarse manualmente cada vez que se ejecute el flujo de trabajo.



No tenga prisa por enfadarse. Las acciones listas vendrán a nuestro rescate, las cuales podemos usar en los pasos de nuestro trabajo. Usaremos dos:



  • actions / setup-java : la acción oficial para configurar el entorno Java;

  • subosito / flutter-action es una acción no oficial para descargar e instalar el SDK de Flutter. Ha demostrado su eficacia: le permite hacer lo que necesite, por ejemplo, especificar el canal de marco deseado o cambiar a una versión específica del SDK.



steps:
      - uses: actions/setup-java@v1
        with:
          java-version: "12.x"

      - uses: subosito/flutter-action@v1
        with:
          channel: "stable"


Clonación de un repositorio



Tenemos una instancia limpia de una máquina alquilada a Github durante unos minutos. En el paso anterior, instalamos todo el software necesario en él. Ahora necesitamos clonar el repositorio de origen de nuestro proyecto. Para hacer esto, usaremos una herramienta lista para usar:



  • actions / checkout es la acción oficial para clonar un repositorio con un montón de configuraciones que no necesitaremos en la mayoría de los casos. Dado que el flujo de trabajo se ejecuta directamente en el repositorio que estamos clonando, no necesitamos especificarlo explícitamente.



- uses: actions/checkout@v1


Cargando dependencias



Hasta este momento, no hemos implementado pasos con nuestras propias manos, sino que solo usamos lo que ofrezco acciones listas para usar. Ahora estamos pasando a la implementación de la fase activa de la construcción de nuestro proyecto, por lo que es hora de escribir la implementación del paso usted mismo.



Antes de construir, necesitamos descargar todos los paquetes que se especifican en el bloque de dependencias de nuestro archivo pubspec.yaml, así como todas sus dependencias transitivas. Para hacer esto, Flutter SDK ofrece un comando simple listo para usar flutter pub get. La implementación del paso puede consistir en llamar a un comando de terminal. En este caso, el siguiente paso solo se llamará al completar este comando.



- run: flutter pub get


Si su proyecto tiene una estructura compleja y contiene varios paquetes de dardos que están conectados localmente, enfrentará un problema. Es flutter pub getimposible construir un proyecto sin una llamada explícita para cada uno de estos paquetes. En mi proyecto, dichos paquetes se recopilan en la carpeta / core ubicada en el directorio raíz. A continuación se muestra un script que resuelve este problema. Se describe en el archivo flutter_pub_get.sh en la carpeta / scripts en el mismo directorio raíz.



flutter pub get
cd core
for dir in */ ; do

    echo ${dir}
    cd ${dir}
    pwd
    flutter pub get
    cd ..
    pwd
    if [ "$#" -gt 0 ]; then shift; fi
    # shift
done


Dado que la implementación del paso puede ser cualquier comando de terminal, nada nos impide ejecutar nuestro script de shell.



- run: sh ./scripts/flutter_pub_get.sh


Análisis de código estático



Flutter nos invita a usar un comando integrado flutter analyzepara ejecutar un analizador estático. Esto ayudará a identificar problemas potenciales con nuestra base de código en una etapa temprana: antes de que un error golpee la producción o nuestro código se convierta en un desastre ilegible y sin soporte.



Podríamos haber aprovechado la función lista para usar, pero lamentablemente, el comportamiento predeterminado del equipo flutter analyzetiene una falla que arruina nuestro flujo de trabajo en el momento equivocado. 



Los problemas encontrados por el analizador se clasifican en tres niveles de gravedad: información, advertencia, error. En esta ediciónse describe que incluso si durante el análisis solo se encuentran problemas de la clase de información (y no siempre vale la pena dedicar tiempo a solucionarlos aquí y ahora), el comando devuelve el código "1", como resultado de lo cual su ensamblado fallará.



Sugiero usar el siguiente script como solución temporal. A partir de ahora, el ensamblaje se bloqueará solo si hay problemas con el nivel de error :



OUTPUT="$(flutter analyze)"
echo "$OUTPUT"
echo
if grep -q "error •" echo "$OUTPUT"; then
    echo "flutter analyze found errors"
    exit 1
else
    echo "flutter analyze didn't find any errors"
    exit 0
fi


Ejecutamos el script de shell en el siguiente paso de nuestro flujo de trabajo:



- run: sh ./scripts/flutter_analyze.sh


Ejecutando pruebas



Si tiene pruebas en su proyecto, ¡está en el camino correcto! Para que las pruebas funcionen, no es suficiente escribirlas, deben ejecutarse regularmente para corregir fallas de implementación a tiempo o actualizarlas si es necesario. Por lo tanto, en el siguiente paso, implementaremos



- run: flutter test


Tenga cuidado: las clases de prueba vacías que no contienen pruebas implementadas bloquearán todo el flujo de trabajo. Solo hay una salida: no declare clases de prueba hasta que esté listo para implementar al menos una prueba dentro de ella.



Construir y firmar



Todo el trabajo preparatorio ha terminado. Hemos verificado que lo más probable es que el código no contenga problemas obvios. Ahora pasamos a la etapa más importante: la producción del artefacto. En otras palabras, crearemos el APK.



El conjunto en sí es extremadamente sencillo de implementar. Tenemos a nuestra disposición el comando de terminal flutter build, que es extremadamente configurable y le permite construir un artefacto para un sabor específico, archivo principal, ABI. No cubriremos estos matices en el artículo, así que use indicadores de comando adicionales si es necesario.



- run: flutter build apk --release


Nuestro objetivo es firmar un ensamblaje con una clave de liberación. Y en esta etapa tendremos que resolver el problema de seguridad, porque necesitamos almacenar el almacén de claves de la versión en algún lugar, así como todos sus alias y contraseñas.



Github le permite almacenar de forma segura valores de cadena en un repositorio de secretos dedicado . Los datos disponibles aquí se almacenan en el repositorio correspondiente y se pueden leer mediante programación desde cualquier paso de su flujo de trabajo. Al mismo tiempo, los valores no se pueden ver a través de la interfaz web de Github. Solo se permite borrar o sobrescribir.







Esta parece una buena solución para alias y contraseñas, especialmente si es su propio servicio de seguridad, pero ¿qué pasa con el archivo * .jks en sí? Enviarlo al repositorio no parece una buena idea, incluso si su repositorio es privado. Desafortunadamente, Github no proporciona ninguna forma segura de almacenar archivos, por lo que debe esquivarlo.



Sería bueno representar nuestro archivo de almacén de claves como una cadena. Y es real, solo necesitas codificarlo en base64. Para hacer esto, abra una terminal en el directorio que contiene nuestro archivo * .jks y ejecute el siguiente comando. A continuación, se creará un archivo de texto a partir del cual puede copiar la representación base64 de nuestro almacén de claves, luego ... guárdelo en Github Secrets.



openssl base64 < key_store_filename.jks | tr -d '\n' | tee keystore.jks.base64.txt


Ahora que tenemos todos los componentes necesarios para una firma de ensamblaje exitosa en su lugar, procederemos con la configuración del paso. En el bloque env, declaramos todas las variables de entorno para ese paso en particular. Tomaremos los valores de estas variables de Secrets.



- run: flutter build apk --release
        env:
          STORE_PASSWORD: ${{ secrets.STORE_PASSWORD }}
          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
          KEY_ALIAS: ${{ secrets.KEY_ALIAS }}
          STORE_FILE: ${{ secrets.STORE_FILE }}


En nuestro host de Android, tenemos que describir la configuración del ensamblado de tal manera que podamos firmar el archivo * .apk en CI también, sin perder la capacidad de construir el ensamblado firmado localmente. El archivo keystoreConfig.gradle es responsable de este momento .



Si se encuentra el archivo keystore_release.properties , se sabe que la compilación se produce localmente, lo que significa que puede inicializar todas las propiedades de keystoreConfig simplemente leyéndolas del archivo. De lo contrario, el ensamblaje se lleva a cabo en CI, lo que significa que la única fuente de datos confidenciales son Github Secrets.



ext {
   def releaseKeystorePropsFile = rootProject.file("keystore/keystore_release.properties")
   if (releaseKeystorePropsFile.exists()) {
       println "Start extract release keystore config from keystore_release.properties"
       def keystoreProps = new Properties()
       keystoreProps.load(new FileInputStream(releaseKeystorePropsFile))
       keystoreConfig = [
               storePassword: keystoreProps['storePassword'],
               keyPassword  : keystoreProps['keyPassword'],
               keyAlias     : keystoreProps['keyAlias'],
               storeFile    : keystoreProps['storeFile']
       ]
   } else {
       println "Start extract release keystore config from global vars"
       keystoreConfig = [
               storePassword: "$System.env.STORE_PASSWORD",
               keyPassword  : "$System.env.KEY_PASSWORD",
               keyAlias     : "$System.env.KEY_ALIAS",
               storeFile    : "$System.env.STORE_FILE"
       ]
   }
   println "Extracted keystore config: $keystoreConfig"
}


Y así es como se ve el archivo keystore_release.properties :



storePassword={___}
keyPassword={___}
keyAlias={___}
storeFile=../keystore/keystore.jks


El último paso en el archivo build.gradle de nuestro host de Android es aplicar el archivo keystoreConfig a nuestra configuración de firma de compilación de lanzamiento:



android {
   signingConfigs {
       release {
           apply from: '../keystore/keystoreConfig.gradle'

           keyAlias keystoreConfig.keyAlias
           keyPassword keystoreConfig.keyPassword
           storeFile file(keystoreConfig.storeFile)
           storePassword keystoreConfig.storePassword
       }
   }
}


¡El montaje firmado ya está en nuestras manos! Pero, ¿cómo se lo extiende a sus colegas para que lo prueben?



Descarga



Github Actions le permite configurar la carga de artefactos en casi cualquier herramienta conocida para distribuir ensamblados, pero consideraremos solo dos opciones:



  • Almacenamiento Github: la forma más fácil de cargar ensamblajes en su propio almacenamiento Github, que funciona de inmediato, pero tiene algunas limitaciones;

  • Firebase App Distribution es un servicio del ecosistema de Firebase que reemplazó a Beta por Crashlytics. La integración es un poco más difícil de configurar, pero el servicio en sí es mucho más conveniente de usar.





Github Storage

Github Storage se integra fácilmente a través de la acción oficial. Solo necesita especificar el nombre del ensamblado como lo verán sus colegas en la interfaz web, así como la ruta al archivo * .apk compilado en CI.



- uses: actions/upload-artifact@v1
        with:
          name: APK for QA
          path: build/app/outputs/apk/dev/debug/apk_name.apk


El principal problema es el espacio de almacenamiento limitado. En un plan gratuito, solo se le proporcionan 500 MB. Lo más extraño es que no encontré ninguna forma de borrar manualmente todo el almacenamiento a la vez a través de la interfaz web, así que salí de la situación ... escribiendo un flujo de trabajo separado responsable solo de limpiar el almacenamiento de los artefactos cubiertos de musgo.



El flujo de trabajo se ejecuta todos los días a la 1 a. M. Y elimina todos los artefactos anteriores a una semana:



name: Github Storage clear

on:
  schedule:
    - cron: '0 1 * * *'

jobs:
  remove-old-artifacts:
    runs-on: ubuntu-latest
    timeout-minutes: 10

    steps:
      - name: Remove old artifacts
        uses: c-hive/gha-remove-artifacts@v1
        with:
          age: '1 week'


Distribución de aplicaciones de Firebase

En cuanto a la distribución de aplicaciones de Firebase, utilicé la acción lista para usar wzieba / Firebase-Distribution-Github-Action para integrarme con ella



- name: Upload artifact to Firebase App Distribution
        uses: wzieba/Firebase-Distribution-Github-Action@v1
        with:
          appId: ${{ secrets.FIREBASE_ANDROID_PROD_APP_ID }}
          token: ${{ secrets.FIREBASE_TOKEN }}
          groups: testers
          file: build/app/outputs/apk/dev/debug/apk_name.apk
          debug: true


Para que la acción funcione correctamente, debe pasar parámetros:



  • appId : identificador de la aplicación, que se puede encontrar en la configuración del proyecto de Firebase;







  • token : un token para la autenticación en su proyecto FIrebase, que es necesario para cargar el ensamblado en el servicio. Puede obtener un token solo a través de Firebase CLI, para lo cual puede leer más en la documentación oficial ;

  • archivo : ruta al archivo * .apk compilado en CI;

  • grupos : este parámetro es opcional, pero le permite especificar el alias del grupo de probadores con el que se compartirá automáticamente el ensamblaje cargado.



Lanzamiento y observación



¡Nuestro flujo de trabajo más simple está listo! Todo lo que nos queda por hacer es disparar el evento desencadenante y observar el progreso del flujo de trabajo.



Consejos y palabras de despedida



Ahora puedes disfrutar de todos los beneficios de un simple mecanismo CI / CD en tu proyecto Flutter, independientemente de su tamaño, intensidad de desarrollo o tu billetera.



Finalmente, aquí hay algunos consejos y observaciones que se me ocurrieron mientras trabajaba en este flujo de trabajo:



  • workflow . workflow , , . - . , - workflow , .

  • step’ shell-. workflow . . .

  • Run Duration workflow. workflow , . workflow , step’. . Flutter SDK . — 5-6 .



Todavía hay toneladas de posibles mejoras y mejoras por delante. Escribe en los comentarios tus ideas para mejorar el flujo de trabajo. ¿Qué le falta a usted personalmente? Quizás la implementación de las ideas más interesantes de los lectores constituirá la base del próximo artículo sobre el tema.



Todos los scripts y el flujo de trabajo se pueden encontrar en el repositorio con la aplicación de prueba .



Gracias por su atención.



PD: Nuestro equipo de Surf lanza muchas bibliotecas útiles para Flutter. Los subimos al repositorio de SurfGear .



All Articles