Acerca de GitHub Packages con GitHub Actions
GitHub Actions te ayuda a automatizar tus flujos de trabajo de desarrollo de software en el mismo lugar en el que almacenas código y colaboras con informes de problemas y solicitudes de extracción. Puedes escribir tareas individuales, llamadas acciones, y combinarlas para crear un flujo de trabajo personalizado. Con GitHub Actions puedes crear capacidades de integración continua (CI, por sus siglas en inglés) de extremo a extremo y de funcionamiento continuo (CD, por sus siglas en inglés) directamente en tu repositorio. Para más información, consulta "Escritura de flujos de trabajo".
Puedes ampliar las capacidades de CI y CD de tu repositorio publicando o instalando paquetes como parte de tu flujo de trabajo.
Autenticación en registros de paquetes con permisos detallados
Algunos registros de GitHub Packages admiten permisos detallados. Esto significa que puedes elegir permitir que los paquetes se limiten a un usuario o una organización, o bien que estén vinculados a un repositorio. Para obtener la lista de registros que admiten permisos granulares, consulta "Acerca de los permisos para los Paquetes de GitHub".
Para los registros que admiten permisos detallados, si en el flujo de trabajo de GitHub Actions se usa un personal access token para autenticarse en un registro, se recomienda encarecidamente actualizar el flujo de trabajo para usar GITHUB_TOKEN
. Para obtener orientación sobre la actualización de tus flujos de trabajo que se autentican en un registro con un personal access token, consulta "Publicar e instalar un paquete con GitHub Actions".
Nota: La capacidad de los flujos de trabajo de GitHub Actions para eliminar y restaurar paquetes mediante la API de REST está actualmente en versión preliminar pública y está sujeta a cambios.
Puede usar un GITHUB_TOKEN
en un flujo de trabajo de GitHub Actions para eliminar o restaurar un paquete mediante la API de REST, si el token tiene el permiso admin
para el paquete. A los repositorios que publican paquetes mediante un flujo de trabajo y a los repositorios que se han conectado explícitamente a los paquetes se les concede automáticamente el permiso admin
para los paquetes del repositorio.
Para obtener más información sobre GITHUB_TOKEN
, consulta "Autenticación automática de tokens". Para obtener más información sobre los procedimientos recomendados al usar un registro en acciones, consulta "Fortalecimiento de seguridad para GitHub Actions".
Autenticación en registros de paquetes con permisos del ámbito del repositorio
Algunos registros de GitHub Packages solo admiten permisos del ámbito del repositorio y no admiten permisos detallados. Para obtener una lista de estos registros, consulta "Acerca de los permisos para los Paquetes de GitHub".
Si quieres que el flujo de trabajo tenga acceso a un registro de GitHub Packages que no admita permisos detallados, recomendamos el uso del GITHUB_TOKEN
que GitHub Enterprise Cloud crea automáticamente para el repositorio al habilitar GitHub Actions. Debes establecer los permisos para este token de acceso en el archivo del flujo de trabajo a fin de conceder acceso de lectura al ámbito contents
y acceso de escritura al ámbito packages
. En el caso de las bifurcaciones, a GITHUB_TOKEN
se le concede acceso de lectura para el repositorio primario. Para obtener más información, vea «Autenticación automática de tokens».
Puede hacer referencia al elemento GITHUB_TOKEN
en el archivo de flujo de trabajo mediante el contexto ${{ secrets.GITHUB_TOKEN }}
. Para obtener más información, vea «Autenticación automática de tokens».
Acerca de los permisos y el acceso a los paquetes
Paquetes cuyo ámbito son los usuarios o las organizaciones
Los registros que admiten permisos detallados permiten a los usuarios crear y administrar paquetes como recursos independientes en el nivel de la organización. Los paquetes pueden limitarse a una organización o a una cuenta personal, y puedes personalizar el acceso para cada uno de tus paquetes independientemente de los permisos del repositorio.
Todos los flujos de trabajo que acceden a los registros que admiten permisos detallados deben usar GITHUB_TOKEN
en lugar de un personal access token. Para más información sobre los procedimientos recomendados de seguridad, consulta "Fortalecimiento de seguridad para GitHub Actions".
Paquetes cuyo ámbito son los repositorios
Cuando habilitas las Acciones de GitHub, GitHub instala una App GitHub en tu repositorio. El secreto GITHUB_TOKEN
es un token de acceso de instalación de aplicación de GitHub. Puedes utilizar el token de acceso a la instalación para autenticarte en nombre de la GitHub App instalada en tu repositorio. Los permisos del token están limitados al repositorio que contiene tu flujo de trabajo. Para obtener más información, vea «Autenticación automática de tokens».
GitHub Packages permite insertar y extraer paquetes mediante el GITHUB_TOKEN
disponible para un flujo de trabajo de GitHub Actions.
Configuración de acceso y permisos predeterminados para los paquetes que se modifican a través de los flujos de trabajo
En el caso de los paquetes en registros que admiten permisos granulares, cuando creas, instalas, modificas o borras un paquete a través de un flujo de trabajo, hay algunos permisos y configuraciones de acceso predeterminados que se utilizan para garantizar que los administradores tengan acceso al flujo de trabajo. También puedes ajustar esta configuración de acceso. Para obtener la lista de registros que admiten permisos granulares, consulta "Acerca de los permisos para los Paquetes de GitHub".
Por ejemplo, si un flujo de trabajo crea de forma predeterminada un paquete mediante GITHUB_TOKEN
, después:
- El paquete hereda la visibilidad y el modelo de permisos del repositorio donde se ejecuta el flujo de trabajo.
- Los administradores de repositorio donde se ejecuta el flujo de trabajo se convierten en los administradores del paquete una vez que este se cree.
Estos son más ejemplos de cómo funcionan los permisos predeterminados para los flujos de trabajo que administran paquetes.
Tarea de flujo de trabajo de GitHub Actions | Permisos y acceso predeterminado |
---|---|
Descargar un paquete existente | - Si el paquete es público, cualquier flujo de trabajo que se ejecute en cualquier repositorio podrá descargarlo. - Si el paquete es interno, todos los flujos de trabajo que se ejecuten en un repositorio que pertenezca a la cuenta de empresa podrán descargarlo. En el caso de las organizaciones propiedad de la empresa, puede leer cualquier repositorio de la empresa. - Si el paquete es privado, solo los flujos de trabajo que se ejecutan en repositorios a los que se les concede permiso de lectura en ese paquete pueden descargarlo. Si concedes a un repositorio público acceso a paquetes privados, es posible que las bifurcaciones del repositorio puedan acceder a los paquetes privados. |
Cargar una versión nueva a un paquete existente | - Si el paquete es privado, interno, o público, solo los flujos de trabajo que se ejecuten en repositorios que tengan el permiso de escritura en dicho paquete podrán cargar versiones nuevas de este. |
Eliminar un paquete o versiones de un paquete | - Si el paquete es privado, interno o público, solo los flujos de trabajo que se ejecuten en los repositorios a los que se les otorga permiso de administrador podrán borrar las versiones existentes del paquete. |
También puedes ajustar el acceso a los paquetes de forma más granular o ajustar el comportamiento de algunos de los permisos predeterminados. Para obtener más información, vea «Configurar la visibilidad y el control de accesos de un paquete».
Publicar un paquete mediante una acción
Puedes utilizar GitHub Actions para publicar paquetes automáticamente como parte de tu flujo de integración contínua (IC). Este acercamiento a los despliegues contínuos (DC) te permite automatizar la creación de nuevas versiones de los paquetes si el código cumple con tus estándares de calidad. Por ejemplo, podrías crear un flujo de trabajo que ejecute pruebas de IC cada vez que un desarrollador suba código a alguna rama en particular. Si estas pruyebas pasan, el flujo de trabajo puede publicar una versión nueva del paquete en el GitHub Packages.
Los pasos de configuración varían de acuerdo con el cliente del paquete. Para información general sobre cómo configurar un flujo de trabajo para GitHub Actions, consulta "Escritura de flujos de trabajo".
El siguiente ejemplo ilustra cómo puedes utilizar las GitHub Actions para crear y probar tu app y luego crear una imagen de Docker automáticamente y publicarla en el GitHub Packages. La configuración pertinente se explica en el código. Para obtener detalles completos sobre cada elemento de un flujo de trabajo, consulta "Sintaxis del flujo de trabajo para Acciones de GitHub".
Crea un archivo de flujo de trabajo en el repositorio (por ejemplo, .github/workflows/deploy-image.yml
) y agrega el código YAML siguiente.
Note
- Este flujo de trabajo usa acciones que no están certificadas por GitHub. Las proporciona un tercero y se rigen por los términos de servicio independientes, la directiva de privacidad y la documentación de soporte técnico.
- GitHub recomienda las acciones de anclaje a un SHA de confirmación. Para obtener una versión más reciente, debes actualizar el SHA. También puedes hacer referencia a una etiqueta o rama, pero la acción puede cambiar sin ninguna advertencia.
# name: Create and publish a Docker image # Configures this workflow to run every time a change is pushed to the branch called `release`. on: push: branches: ['release'] # Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds. env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} # There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu. jobs: build-and-push-image: runs-on: ubuntu-latest # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. permissions: contents: read packages: write attestations: write id-token: write # steps: - name: Checkout repository uses: actions/checkout@v4 # Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here. - name: Log in to the Container registry uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - name: Extract metadata (tags, labels) for Docker id: meta uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} # This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages. # It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository. # It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step. - name: Build and push Docker image id: push uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 with: context: . push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} # This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)." - name: Generate artifact attestation uses: actions/attest-build-provenance@v1 with: subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}} subject-digest: ${{ steps.push.outputs.digest }} push-to-registry: true
name: Create and publish a Docker image
on:
push:
branches: ['release']
Configures this workflow to run every time a change is pushed to the branch called release
.
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
jobs:
build-and-push-image:
runs-on: ubuntu-latest
There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
permissions:
contents: read
packages: write
attestations: write
id-token: write
Sets the permissions granted to the GITHUB_TOKEN
for the actions in this job.
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
Uses the docker/login-action
action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
This step uses docker/metadata-action to extract tags and labels that will be applied to the specified image. The id
"meta" allows the output of this step to be referenced in a subsequent step. The images
value provides the base name for the tags and labels.
- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
This step uses the docker/build-push-action
action to build the image, based on your repository's Dockerfile
. If the build succeeds, it pushes the image to GitHub Packages.
It uses the context
parameter to define the build's context as the set of files located in the specified path. For more information, see "Usage" in the README of the docker/build-push-action
repository.
It uses the tags
and labels
parameters to tag and label the image with the output from the "meta" step.
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "Uso de atestaciones de artefactos para establecer la procedencia de las compilaciones."
#
name: Create and publish a Docker image
# Configures this workflow to run every time a change is pushed to the branch called `release`.
on:
push:
branches: ['release']
# Defines two custom environment variables for the workflow. These are used for the Container registry domain, and a name for the Docker image that this workflow builds.
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
# There is a single job in this workflow. It's configured to run on the latest available version of Ubuntu.
jobs:
build-and-push-image:
runs-on: ubuntu-latest
# Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job.
permissions:
contents: read
packages: write
attestations: write
id-token: write
#
steps:
- name: Checkout repository
uses: actions/checkout@v4
# Uses the `docker/login-action` action to log in to the Container registry registry using the account and password that will publish the packages. Once published, the packages are scoped to the account defined here.
- name: Log in to the Container registry
uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
# This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels.
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
# This step uses the `docker/build-push-action` action to build the image, based on your repository's `Dockerfile`. If the build succeeds, it pushes the image to GitHub Packages.
# It uses the `context` parameter to define the build's context as the set of files located in the specified path. For more information, see "[Usage](https://github.com/docker/build-push-action#usage)" in the README of the `docker/build-push-action` repository.
# It uses the `tags` and `labels` parameters to tag and label the image with the output from the "meta" step.
- name: Build and push Docker image
id: push
uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# This step generates an artifact attestation for the image, which is an unforgeable statement about where and how it was built. It increases supply chain security for people who consume the image. For more information, see "[AUTOTITLE](/actions/security-guides/using-artifact-attestations-to-establish-provenance-for-builds)."
- name: Generate artifact attestation
uses: actions/attest-build-provenance@v1
with:
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME}}
subject-digest: ${{ steps.push.outputs.digest }}
push-to-registry: true
Este flujo de trabajo nuevo se ejecutará automáticamente cada vez que inserte un cambio en una rama denominada release
en el repositorio. Puede ver el progreso en la pestaña Acciones.
Unos minutos después de que se complete el flujo de trabajo, el paquete nuevo podrá visualizarse en tu repositorio. Para buscar los paquetes disponibles, consulta "Visualizar paquetes".
Instalar un paquete mediante una acción
Puedes instalar paquetes como parte de tu flujo de CI mediante GitHub Actions. Por ejemplo, podrías configurar un flujo de trabajo para que cada vez que un programador suba código a una solicitud de extracción, el flujo de trabajo resuelva las dependencias al descargar e instalar paquetes alojados por el GitHub Packages. Luego, el flujo de trabajo puede ejecutar pruebas de CI que requieran las dependencias.
Para instalar paquetes hospedados por GitHub Packages mediante GitHub Actions se necesita una configuración mínima o autenticación adicional cuando se usa un GITHUB_TOKEN
. La transferencia de datos también es gratuita cuando una acción instala un paquete. Para obtener más información, consulta "Acerca de la facturación para GitHub Packages".
Los pasos de configuración varían de acuerdo con el cliente del paquete. Para información general sobre cómo configurar un flujo de trabajo para GitHub Actions, consulta "Escritura de flujos de trabajo".
Actualización de un flujo de trabajo que accede a un registro mediante un personal access token
GitHub Packages admite el GITHUB_TOKEN
para una autenticación más fácil y segura en los flujos de trabajo. Si usas un registro que admite permisos detallados y en el flujo de trabajo se usa un personal access token para autenticarse en el registro, se recomienda encarecidamente actualizar el flujo de trabajo para usar el GITHUB_TOKEN
.
Para obtener más información sobre GITHUB_TOKEN
, consulta "Autenticación automática de tokens".
Al usar GITHUB_TOKEN
en lugar de un personal access token (classic) con el ámbito repo
, aumenta la seguridad del repositorio, ya que no es necesario usar un personal access token de larga duración que ofrezca acceso innecesario al repositorio donde se ejecuta el flujo de trabajo. Para más información sobre los procedimientos recomendados de seguridad, consulta "Fortalecimiento de seguridad para GitHub Actions".
-
Navega a la página de llegada de tu paquete.
-
Para asegurarte de que tu paquete tenga acceso a tu flujo de trabajo, debes agregar el repositorio donde se almacena el flujo de trabajo a tu paquete. En "Administrar el acceso a Acciones", az clic en Agregar repositorio y busca el repositorio que quieras agregar.
Nota: La adición de un repositorio al paquete mediante el botón Agregar repositorio en "Administrar el acceso a acciones" en la configuración del paquete no es lo mismo que conectar el paquete a un repositorio. Para obtener más información, vea «Configurar la visibilidad y el control de accesos de un paquete» y «Conectar un repositorio a un paquete».
Por ejemplo, este flujo de trabajo publica una imagen de Docker en el Container registry y usa ${{ secrets.GITHUB_TOKEN }}
para autenticarse. Para obtener más información, consulta "Configuración de compilaciones automatizadas" en la documentación de Docker.
# name: Demo Push # This workflow runs when any of the following occur: # - A push is made to a branch called `main` or `seed` # - A tag starting with "v" is created # - A pull request is created or updated on: push: branches: - main - seed tags: - v* pull_request: # This creates an environment variable called `IMAGE_NAME ` with the value `ghtoken_product_demo`. env: IMAGE_NAME: ghtoken_product_demo # jobs: # This pushes the image to GitHub Packages. push: runs-on: ubuntu-latest permissions: packages: write contents: read # steps: - uses: actions/checkout@v4 - name: Build image run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}" - name: Log in to registry run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin # - name: Push image run: | IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME # This changes all uppercase characters to lowercase. IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') # This strips the git ref prefix from the version. VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') # This strips the "v" prefix from the tag name. [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') # This uses the Docker `latest` tag convention. [ "$VERSION" == "main" ] && VERSION=latest echo IMAGE_ID=$IMAGE_ID echo VERSION=$VERSION docker tag $IMAGE_NAME $IMAGE_ID:$VERSION docker push $IMAGE_ID:$VERSION
name: Demo Push
on:
push:
branches:
- main
- seed
tags:
- v*
pull_request:
This workflow runs when any of the following occur:
- A push is made to a branch called
main
orseed
- A tag starting with "v" is created
- A pull request is created or updated
env:
IMAGE_NAME: ghtoken_product_demo
This creates an environment variable called IMAGE_NAME
with the value ghtoken_product_demo
.
jobs:
push:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
This pushes the image to GitHub Packages.
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
- name: Push image
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
This changes all uppercase characters to lowercase.
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
This strips the git ref prefix from the version.
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
This strips the "v" prefix from the tag name.
[ "$VERSION" == "main" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION
This uses the Docker latest
tag convention.
#
name: Demo Push
# This workflow runs when any of the following occur:
# - A push is made to a branch called `main` or `seed`
# - A tag starting with "v" is created
# - A pull request is created or updated
on:
push:
branches:
- main
- seed
tags:
- v*
pull_request:
# This creates an environment variable called `IMAGE_NAME ` with the value `ghtoken_product_demo`.
env:
IMAGE_NAME: ghtoken_product_demo
#
jobs:
# This pushes the image to GitHub Packages.
push:
runs-on: ubuntu-latest
permissions:
packages: write
contents: read
#
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build . --file Dockerfile --tag $IMAGE_NAME --label "runnumber=${GITHUB_RUN_ID}"
- name: Log in to registry
run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin
#
- name: Push image
run: |
IMAGE_ID=ghcr.io/${{ github.repository_owner }}/$IMAGE_NAME
# This changes all uppercase characters to lowercase.
IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]')
# This strips the git ref prefix from the version.
VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,')
# This strips the "v" prefix from the tag name.
[[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//')
# This uses the Docker `latest` tag convention.
[ "$VERSION" == "main" ] && VERSION=latest
echo IMAGE_ID=$IMAGE_ID
echo VERSION=$VERSION
docker tag $IMAGE_NAME $IMAGE_ID:$VERSION
docker push $IMAGE_ID:$VERSION