Docker Build and Push
docker-build-push@1.0.0 Template Build a container image, push it to any registry, and pass the pinned digest to the next job.
Start from it
flightstack template use docker-build-push What it does
docker build then docker push every tag to Artifact Registry, GHCR, Docker Hub, ECR or your own registry, logging in from the credentials the agent holds. Emits imageRef (image@sha256 digest) so a deploy job ships exactly the bytes that were built.
Inputs
-
imagestring required - Image name without a tag, e.g. us-central1-docker.pkg.dev/my-project/containers/api or ghcr.io/acme/api.
-
tagsarray - Tags to apply and push. Defaults to the short commit SHA.
-
contextstring default. - Build context directory.
-
dockerfilestring defaultDockerfile - Path to the Dockerfile, relative to the repo root.
-
platformstring - Target platform, e.g. linux/amd64. Set it when building on an Apple Silicon agent for an amd64 host like Cloud Run.
-
buildArgsobject - Build arguments (--build-arg). Visible in image history - never a secret.
-
pushboolean defaulttrue - Push after building. Off builds only, e.g. to check a Dockerfile on pull requests.
-
loginauto | none defaultauto autologs in using REGISTRY_USERNAME/REGISTRY_PASSWORD when set, GITHUB_TOKEN for ghcr.io, gcloud for *.pkg.dev and gcr.io, and the AWS CLI for ECR.nonerelies on the agent's existing docker login.
Definition
name: Docker Build and Push
description: >-
Build a container image and push it to any registry - Artifact Registry,
GHCR, Docker Hub, ECR or your own - and hand the pinned image digest to the
next job.
triggers:
- type: push
branches: [main]
jobs:
image:
name: Build image
type: plugin/docker-build-push
with:
image: us-central1-docker.pkg.dev/my-project/containers/api
tags:
- "${{ context.commitShort }}"
- latest
plugin:
name: docker-build-push
displayName: Docker Build and Push
description: >-
`docker build` then `docker push` every tag, logging in to the registry
from the credentials the agent holds. Emits `imageRef` (image@sha256
digest) so a deploy job ships exactly the bytes that were built.
category: build
supportedPlatforms:
- linux
- macos
parameters:
type: object
properties:
image:
type: string
description: >-
Image name without a tag, e.g.
us-central1-docker.pkg.dev/my-project/containers/api or ghcr.io/acme/api.
tags:
type: array
description: Tags to apply and push. Defaults to the short commit SHA.
context:
type: string
default: "."
description: Build context directory.
dockerfile:
type: string
default: Dockerfile
description: Path to the Dockerfile, relative to the repo root.
platform:
type: string
default: ""
description: >-
Target platform, e.g. linux/amd64. Set it when building on an Apple
Silicon agent for an amd64 host like Cloud Run.
buildArgs:
type: object
description: Build arguments (--build-arg). Visible in image history - never a secret.
push:
type: boolean
default: true
description: Push after building. Off builds only, e.g. to check a Dockerfile on pull requests.
login:
type: string
enum: [auto, none]
default: auto
description: >-
`auto` logs in using REGISTRY_USERNAME/REGISTRY_PASSWORD when set,
GITHUB_TOKEN for ghcr.io, gcloud for *.pkg.dev and gcr.io, and the AWS
CLI for ECR. `none` relies on the agent's existing docker login.
required: [image]
script: |
set -euo pipefail
if ! command -v docker >/dev/null 2>&1; then
echo "docker is not installed on this agent." >&2
exit 1
fi
image="{{image}}"
registry="${image%%/*}"
case "$registry" in
*.*|*:*|localhost) ;;
*) registry="docker.io" ;;
esac
if [ "{{login}}" = "auto" ] && [ "{{push}}" = "true" ]; then
if [ -n "${REGISTRY_USERNAME:-}" ] && [ -n "${REGISTRY_PASSWORD:-}" ]; then
echo "--- docker login $registry (REGISTRY_USERNAME)"
printf '%s' "$REGISTRY_PASSWORD" | docker login "$registry" --username "$REGISTRY_USERNAME" --password-stdin
else
case "$registry" in
ghcr.io)
if [ -n "${GITHUB_TOKEN:-}" ]; then
echo "--- docker login ghcr.io (GITHUB_TOKEN)"
printf '%s' "$GITHUB_TOKEN" | docker login ghcr.io --username "${GITHUB_ACTOR:-flightstack}" --password-stdin
fi
;;
*.pkg.dev|gcr.io|*.gcr.io)
if [ -n "${GOOGLE_APPLICATION_CREDENTIALS:-}" ] && command -v gcloud >/dev/null 2>&1; then
gcloud auth activate-service-account --key-file "$GOOGLE_APPLICATION_CREDENTIALS" --quiet
fi
echo "--- gcloud auth configure-docker $registry"
gcloud auth configure-docker "$registry" --quiet
;;
*.dkr.ecr.*.amazonaws.com)
region="$(echo "$registry" | cut -d. -f4)"
echo "--- docker login ECR ($region)"
aws ecr get-login-password --region "$region" | docker login "$registry" --username AWS --password-stdin
;;
esac
fi
fi
tags=()
{{#each tags}}
tags+=("{{this}}")
{{/each}}
if [ "${#tags[@]}" -eq 0 ]; then
tags=("$(git rev-parse --short HEAD)")
fi
args=(build --file "{{dockerfile}}")
platform="{{platform}}"
if [ -n "$platform" ]; then args+=(--platform "$platform"); fi
{{#each buildArgs}}
args+=(--build-arg "{{@key}}={{this}}")
{{/each}}
for t in "${tags[@]}"; do args+=(--tag "$image:$t"); done
args+=("{{context}}")
echo "--- docker ${args[*]}"
docker "${args[@]}"
first="$image:${tags[0]}"
fs-output image "$image"
fs-output tag "${tags[0]}"
if [ "{{push}}" != "true" ]; then
echo "push is off - built $first only"
fs-output imageRef "$first"
exit 0
fi
digest=""
for t in "${tags[@]}"; do
echo "--- docker push $image:$t"
out="$(docker push "$image:$t" 2>&1 | tee /dev/stderr)"
d="$(printf '%s\n' "$out" | sed -n 's/.*digest: \(sha256:[0-9a-f]*\).*/\1/p' | tail -1)"
if [ -n "$d" ]; then digest="$d"; fi
done
if [ -z "$digest" ]; then
echo "Pushed, but could not read the digest from docker push output; falling back to the tag." >&2
fs-output imageRef "$first"
else
echo "pushed $image@$digest"
fs-output digest "$digest"
fs-output imageRef "$image@$digest"
fi