Saltar al contenido principal

Publicación automatizada de paquetes en pub.dev

Publica paquetes de Dart en pub.dev directamente desde GitHub Actions.

Puedes automatizar la publicación desde:

Las siguientes secciones explican cómo se configura la publicación automatizada, y cómo puedes personalizar los flujos de publicación según tus preferencias.

Al configurar la publicación automatizada, no necesitas crear un secreto de larga duración que se copie en tu entorno de despliegue automatizado. En su lugar, la autenticación se basa en tokens OpenID-Connect temporales firmados por GitHub Actions (Consulta OIDC para GitHub Actions) o Google Cloud IAM.

Puedes usar claves de cuenta de servicio exportadas para entornos de despliegue donde no esté presente un servicio de identidad. Estas claves de cuenta de servicio exportadas son secretos de larga duración, pueden ser más fáciles de usar en algunos entornos, pero también representan un mayor riesgo si se filtran accidentalmente.

Publicación de paquetes usando GitHub Actions

#

Puedes configurar la publicación automatizada usando GitHub Actions. Esto implica:

  • Habilitar la publicación automatizada en pub.dev, especificando:

    • El repositorio de GitHub y,
    • Un patrón de etiqueta (tag-pattern) que debe coincidir para permitir la publicación.
  • Crear un flujo de trabajo (workflow) de GitHub Actions para publicar en pub.dev.

  • Hacer push de una etiqueta de git (git tag) para la versión que se va a publicar.

Las siguientes secciones describen cómo completar estos pasos.

Configurar la publicación automatizada desde GitHub Actions en pub.dev

#

Para habilitar la publicación automatizada desde GitHub Actions en pub.dev, debes ser:

  • Un uploader del paquete, o,
  • Un administrador (admin) del publicador (si el paquete pertenece a un publicador).

Si tienes permisos suficientes, puedes habilitar la publicación automatizada al:

  1. Navegar a la pestaña Admin (pub.dev/packages/<package>/admin).

  2. Buscar la sección Automated publishing.

  3. Hacer clic en Enable publishing from GitHub Actions, esto te pedirá que especifiques:

    • Un repositorio (<organization>/<repository>, ejemplo: dart-lang/pana),
    • Un patrón de etiqueta (tag-pattern) (una cadena que contiene {{version}}).

El repositorio es el <organization>/<repository> en GitHub. Por ejemplo, si tu repositorio es https://github.com/dart-lang/pana debes especificar dart-lang/pana en el campo del repositorio.

El patrón de etiqueta es una cadena que debe contener {{version}}. Solo se permitirá publicar tu paquete a las GitHub Actions activadas por el push de una etiqueta que coincida con este patrón de etiqueta.

Configuración de la publicación desde GitHub Actions en pub.dev

Ejemplo: un patrón de etiqueta como v{{version}} permite a GitHub Actions (activadas por git tag v1.2.3 && git push v1.2.3) publicar la versión 1.2.3 de tu paquete. Por lo tanto, también es importante que la clave version en pubspec.yaml coincida con este número de versión.

Si tu repositorio contiene múltiples paquetes, dale a cada uno un patrón de etiqueta (tag-pattern) independiente. Considera usar un patrón de etiqueta como nombre_de_mi_paquete-v{{version}} para un paquete llamado nombre_de_mi_paquete.

Configurar un flujo de trabajo (workflow) de GitHub Action para publicar en pub.dev

#

Cuando la publicación automatizada desde GitHub Actions está habilitada en pub.dev, puedes crear un flujo de trabajo (workflow) de GitHub Actions para la publicación. Esto se hace creando un archivo .github/workflows/publish.yml como se muestra a continuación:

yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    # must align with the tag-pattern configured on pub.dev, often just replace
      # {{version}} with [0-9]+.[0-9]+.[0-9]+
    - 'v[0-9]+.[0-9]+.[0-9]+' # tag-pattern on pub.dev: 'v{{version}}'
    # If you prefer tags like '1.2.3', without the 'v' prefix, then use:
    # - '[0-9]+.[0-9]+.[0-9]+' # tag-pattern on pub.dev: '{{version}}'
    # If your repository contains multiple packages consider a pattern like:
    # - 'my_package_name-v[0-9]+.[0-9]+.[0-9]+'

# Publish using the reusable workflow from dart-lang.
jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
    # with:
    #   working-directory: path/to/package/within/repository

Asegúrate de que el patrón en on.push.tags coincida con el patrón de etiqueta especificado en pub.dev. De lo contrario, el flujo de trabajo de GitHub Action no funcionará. Si vas a publicar varios paquetes desde el mismo repositorio, usa un patrón de etiqueta específico por paquete, como nombre_de_mi_paquete-v{{version}} y crea un archivo de flujo de trabajo separado para cada paquete.

El archivo de flujo de trabajo anterior utiliza dart-lang/setup-dart/.github/workflows/publish.yml para publicar el paquete. Este es un flujo de trabajo reutilizable (reusable workflow) que permite al equipo de Dart mantener la lógica de publicación y le permite a pub.dev saber cómo se publicó el paquete. Se recomienda encarecidamente utilizar este flujo de trabajo reutilizable.

Si necesitas código generado en tu paquete, es preferible que guardes este código generado en tu repositorio. Esto simplifica verificar que los archivos publicados en pub.dev coincidan con los archivos de tu repositorio. Si guardar los artefactos generados o construidos en tu repositorio no es viable, puedes crear un flujo de trabajo personalizado siguiendo estas líneas:

yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    - 'v[0-9]+.[0-9]+.[0-9]+' # tag pattern on pub.dev: 'v{{version}'

# Publish using custom workflow
jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: dart-lang/setup-dart@v1
      - name: Install dependencies
        run: dart pub get
      # Here you can insert custom steps you need
      # - run: dart tool/generate-code.dart
      - name: Publish
        run: dart pub publish --force

El flujo de trabajo se autentica en pub.dev utilizando un token OIDC firmado por GitHub temporal, el token se crea y se configura en el paso dart-lang/setup-dart. Para publicar en pub.dev, los pasos siguientes pueden ejecutar dart pub publish --force.

Activar la publicación automatizada desde GitHub Actions

#

Después de configurar la publicación automatizada en pub.dev y crear un flujo de trabajo de GitHub Actions, puedes publicar una nueva versión de tu paquete. Para publicar, haz push de una etiqueta de git (git tag) que coincida con el patrón de etiqueta configurado.

cat pubspec.yaml
yaml
package: my_package_name
version: 1.2.3            # must match the version number used in the git tag
environment:
  sdk: ^2.19.0
git tag v1.2.3          # assuming my tag pattern is: 'v{{version}}'
git push origin v1.2.3  # triggers the action that publishes my package.

Una vez hecho el push, revisa los registros del flujo de trabajo en https://github.com/<organization>/<repository>/actions.

Si la Action no se activó, verifica que el patrón configurado en .github/workflows/publish.yml coincida con la etiqueta de git que se subió. Si la Action falló, los registros pueden contener pistas sobre el motivo del fallo.

Una vez publicado, puedes ver el evento de publicación en el registro de auditoría (audit-log) en pub.dev. La entrada del registro de auditoría debería contener un enlace a la ejecución de GitHub Action que publicó la versión del paquete.

Registro de auditoría después de publicar desde GitHub Actions

Si no te gusta usar la CLI de git para crear etiquetas, puedes crear versiones (releases) en GitHub desde https://github.com/<organization>/<repository>/releases/new. Para obtener más información, consulta la sección sobre gestión de versiones en un repositorio de GitHub.

Reforzar la seguridad con reglas de protección de etiquetas en GitHub

#

Configurar la publicación automatizada desde GitHub Actions permite que cualquier persona que pueda hacer push de una etiqueta a tu repositorio active la publicación en pub.dev. Puedes restringir quién puede hacer push de etiquetas a tu repositorio usando reglas de protección de etiquetas en GitHub.

Al limitar quién puede crear etiquetas que coincidan con tu patrón de etiqueta, puedes limitar quién puede publicar el paquete.

En este momento, las reglas de protección de etiquetas carecen de flexibilidad. Es posible que desees restringir quién puede activar la publicación usando GitHub Deployment Environments, como se describe en la siguiente sección.

Reforzar la seguridad con GitHub Deployment Environments

#

Al configurar la publicación automatizada desde GitHub Actions en pub.dev, puedes requerir un entorno de GitHub Actions (GitHub Actions environment). Para requerir un entorno de GitHub Actions para la publicación debes:

  1. Navegar a la pestaña Admin (pub.dev/packages/<package>/admin).
  2. Buscar la sección Automated publishing.
  3. Hacer clic en Require GitHub Actions environment.
  4. Especificar un nombre de entorno (Environment) (generalmente pub.dev es un buen nombre).

Configurar pub.dev para requerir un entorno de despliegue de GitHub

Cuando se requiere un entorno en pub.dev, GitHub Actions no podrá realizar la publicación a menos que tenga la configuración environment: pub.dev. Por lo tanto, debes:

  1. Crear un entorno con el mismo nombre en GitHub (generalmente pub.dev).
  2. Modificar tu archivo de flujo de trabajo .github/workflows/publish.yml para especificar environment: pub.dev, como se muestra a continuación:
yaml
# .github/workflows/publish.yml
name: Publish to pub.dev

on:
  push:
    tags:
    - 'v[0-9]+.[0-9]+.[0-9]+' # for tags like: 'v1.2.3'

jobs:
  publish:
    permissions:
      id-token: write # Required for authentication using OIDC.
    uses: dart-lang/setup-dart/.github/workflows/publish.yml@v1
    with:
      # Specify the GitHub Action deployment environment.
      environment: pub.dev
      # working-directory: path/to/package/within/repository

El entorno se refleja en el token OIDC temporal firmado por GitHub utilizado para la autenticación en pub.dev. Por lo tanto, un usuario con permiso para hacer push a tu repositorio no puede eludir las reglas de protección de entornos modificando el archivo de flujo de trabajo.

En la configuración del repositorio de GitHub, puedes usar reglas de protección de entornos para configurar revisores requeridos (required reviewers). Si configuras esta opción, GitHub impide que las acciones con el entorno se ejecuten hasta que uno de los revisores requeridos apruebe la ejecución.

GitHub Action esperando la revisión de despliegue

Publicación desde Google Cloud Build

#

Puedes configurar la publicación automatizada desde Google Cloud Build. Esto implica:

  • Registrar un proyecto de Google Cloud (o usar un proyecto existente),
  • Crear una cuenta de servicio para publicar en pub.dev,
  • Habilitar la publicación automatizada en la pestaña admin para el paquete en pub.dev, especificando el correo electrónico de la cuenta de servicio creada para la publicación.
  • Otorgar a la cuenta de servicio predeterminada de Cloud Build permiso para suplantar a la cuenta de servicio creada para la publicación.
  • Crear un archivo cloudbuild.yaml que obtenga un OIDC id_token temporal y lo use para publicar en pub.dev.
  • Configurar un activador (trigger) de Cloud Build para ejecutar los pasos de cloudbuild.yaml en tu proyecto de Google Cloud Build.

Las siguientes secciones describen cómo completar estos pasos.

Crear una cuenta de servicio para la publicación

#

Para publicar en pub.dev, vas a crear una cuenta de servicio a la que se le otorga permiso para publicar tu paquete en pub.dev. Luego vas a otorgar permiso a Cloud Build para suplantar esta cuenta de servicio.

  1. Crear un proyecto en la nube, si no tienes un proyecto existente.

  2. Crea una cuenta de servicio de la siguiente manera:

    gcloud iam service-accounts create pub-dev \
      --description='Service account to be impersonated when publishing to pub.dev' \
      --display-name='pub-dev'
    

    Esto crea una cuenta de servicio llamada pub-dev@$PROJECT_ID.iam.gserviceaccount.com.

  3. Otorgar permiso a la cuenta de servicio para publicar tu paquete.

    Para completar este paso, debes tener permiso de uploader en el paquete o ser un administrador (admin) del publicador propietario del paquete.

    a. Navega a la pestaña Admin (pub.dev/packages/<package>/admin). a. Haz clic en Enable publishing with Google Cloud Service account. a. Escribe el correo electrónico de la cuenta de servicio en el campo Service account email. Creaste esta cuenta en el paso anterior: pub-dev@$PROJECT_ID.iam.gserviceaccount.com

Configuración que permite a la cuenta de servicio publicar en pub.dev

Una vez completado este procedimiento, cualquier persona que pueda suplantar la cuenta de servicio podrá publicar nuevas versiones del paquete. Asegúrate de revisar quién tiene permisos para suplantar la cuenta de servicio y cambiar los permisos en el proyecto de la nube según sea necesario.

Otorgar permiso a Cloud Build para publicar

#

Para publicar desde Cloud Build, debes otorgar a la cuenta de servicio predeterminada de Cloud Build permiso para suplantar la cuenta de servicio creada para la publicación en la sección anterior.

  1. Habilita la IAM Service Account Credentials API en el proyecto en la nube. Los intentos de suplantar una cuenta de servicio fallarán sin esta API.

    # Enable IAM Service Account Credentials API
    gcloud services enable iamcredentials.googleapis.com
    
  2. Encontrar el número del proyecto.

    # The PROJECT_NUMBER can be obtained as follows:
    gcloud projects describe $PROJECT_ID --format='value(projectNumber)'
    
  3. Otorgar el permiso para suplantar la cuenta de servicio de publicación.

    # Grant default cloud
    gcloud iam service-accounts add-iam-policy-binding \
      pub-dev@$PROJECT_ID.iam.gserviceaccount.com \
      --member=serviceAccount:$PROJECT_NUMBER@cloudbuild.gserviceaccount.com \
      --role=roles/iam.serviceAccountTokenCreator
    

Escribir un archivo de configuración de Cloud Build

#

Para publicar desde Cloud Build, debes especificar los pasos para que Cloud Build:

  • Suplante la cuenta de servicio para obtener un token temporal de OIDC.
  • Proporciona el token OIDC temporal a dart pub para su uso al publicar.
  • Llamar a dart pub publish para publicar el paquete.

Los pasos para Google Cloud Build se proporcionan en un archivo cloudbuild.yaml, consulta la documentación del esquema del archivo de configuración de construcción para obtener la documentación completa del formato.

Para publicar en pub.dev desde Google Cloud Build, un archivo cloudbuild.yaml como el siguiente será suficiente:

yaml
# cloudbuild.yaml
steps:
- id: Create temporary token
  name: gcr.io/cloud-builders/gcloud
  volumes:
  - name: temporary-secrets
    path: /secrets
  script: |
    gcloud auth print-identity-token \
      --impersonate-service-account=pub-dev@$PROJECT_ID.iam.gserviceaccount.com \
      --audiences=https://pub.dev \
      --include-email > /secrets/temporary-pub-token.txt
  env:
  - PROJECT_ID=$PROJECT_ID
- id: Publish to pub.dev
  name: dart
  volumes:
  - name: temporary-secrets
    path: /secrets
  script: |
    cat /secrets/temporary-pub-token.txt | dart pub token add https://pub.dev
    dart pub publish --force

El comando gcloud auth print-identity-token crea un id_token de OIDC suplantando la cuenta de servicio especificada. Este id_token está firmado por Google, con una firma que expira en 1 hora. El parámetro audiences le permite saber a pub.dev que es el destinatario previsto del token. La opción --include-email es necesaria para que pub.dev reconozca la cuenta de servicio.

Una vez que se crea el id_token, se escribe en un archivo que reside en un volumen (volume); este mecanismo se utiliza para pasar datos entre pasos. No almacenes el token en /workspace, ya que en /workspace es donde se realiza la descarga (checkout) del repositorio desde el cual deseas publicar. No usar /workspace para almacenar el token reduce el riesgo de que lo incluyas accidentalmente en tu paquete al publicar.

Crear un activador (trigger) de Cloud Build

#

Con las cuentas de servicio configuradas y un archivo cloudbuild.yaml en el repositorio, puedes crear un activador (Cloud Build Trigger) utilizando el panel de console.cloud.google.com. Para crear un activador de construcción, debes conectarte a un repositorio de origen (source repository) y especificar qué eventos deben activar una construcción. Puedes usar GitHub, Cloud Source Repository o una de las otras opciones. Para aprender cómo configurar un activador de Cloud Build, consulta creación y gestión de activadores de construcción.

Para utilizar el archivo cloudbuild.yaml del paso anterior, configura el tipo de activador de Cloud Build como "Configuración de Cloud Build" ubicado en el repositorio en el archivo /cloudbuild.yaml. No especifiques una cuenta de servicio para activar la construcción. En su lugar, querrás usar la cuenta de servicio predeterminada de Cloud Build.

Configuración para el activador

Al configurar tu activador de Cloud Build, considera quién puede activar la construcción, porque activar una construcción podría publicar una nueva versión de tu paquete. Considera permitir únicamente construcciones manuales o usar aprobaciones de Cloud Build para controlar las construcciones, como se describe en la siguiente sección.

Reforzar la seguridad con aprobaciones de Cloud Build

#

Al configurar un activador de Cloud Build, puedes seleccionar la opción requerir aprobación antes de que se ejecute la construcción (require approval before build executes). Si un activador de Cloud Build requiere aprobación, no se ejecutará al activarse. En su lugar, esperará por la aprobación. Esto se puede utilizar para limitar quién puede publicar nuevas versiones de tu paquete.

Habilitar aprobaciones en la configuración del activador de Cloud Build

Solo un usuario con el rol de Aprobador de Cloud Build (Cloud Build Approver) puede otorgar la aprobación. Al otorgar una aprobación, el aprobador puede especificar una URL y un comentario.

Ejecución de Cloud Build esperando aprobación para ejecutarse

También puedes configurar notificaciones para aprobaciones pendientes. Para obtener más información, consulta controlar la construcción mediante aprobación (gate build on approval).

Publicar desde cualquier lugar usando una cuenta de servicio

#

Para permitir la publicación automatizada fuera de GitHub Actions, puedes autenticarte utilizando cuentas de servicio de manera similar a Cloud Build.

Esto usualmente implica:

La sección de Cloud Build describió cómo crear una cuenta de servicio para la publicación. Esto debería proporcionar una cuenta de servicio, como pub-dev@$PROJECT_ID.iam.gserviceaccount.com.

Publicar usando Workload Identity Federation

#

Al ejecutar en un servicio en la nube compatible con OIDC o SAML, puedes suplantar una cuenta de servicio de GCP utilizando Workload Identity Federation. Esto te permite aprovechar los servicios de identidad de tu proveedor de la nube.

Por ejemplo, si estás desplegando en EC2, puedes configurar Workload Identity Federation con AWS, permitiendo que los tokens temporales de AWS del servicio de metadatos de EC2 suplanten a una cuenta de servicio. Para aprender a configurar estos flujos, consulta Workload Identity Federation.

Publicar usando claves de cuenta de servicio exportadas

#

Al ejecutar en un sistema personalizado sin servicios de identidad, puedes exportar claves de cuenta de servicio. Las claves de cuenta de servicio exportadas te permiten autenticarse como dicha cuenta de servicio. Para obtener más información, consulta cómo crear y gestionar claves de cuenta de servicio.

Exportar claves de cuenta de servicio

#
  1. Crear claves de cuenta de servicio exportadas para una cuenta de servicio existente.

    gcloud iam service-accounts keys create key-file.json \
      --iam-account=pub-dev@$PROJECT_ID.iam.gserviceaccount.com
    
  2. Guarda el archivo key-file.json para su uso posterior.

Publicar paquetes usando claves de cuenta de servicio exportadas

#

Para publicar un paquete usando claves de cuenta de servicio exportadas:

  1. Configura gcloud para autenticarse usando key-file.json (creado en el paso anterior).

    gcloud auth activate-service-account --key-file=key-file.json
    
  2. Crea un token temporal para pub.dev y pásalo a dart pub token add https://pub.dev. Para suplantar la cuenta de servicio, incluye la opción --include-email.

    gcloud auth print-identity-token \
      --audiences=https://pub.dev \
      | dart pub token add https://pub.dev
    
  3. Publica usando el token temporal. Agrega la opción --force para omitir la solicitud de yes/no.

    dart pub publish --force