Blessed GitHub Actions.
Composite actions and reusable workflows shared across my repos.
The podman actions mirror the docker/* action interfaces so a workflow can swap between them with minimal changes.
| Action | Purpose | Docker counterpart |
|---|---|---|
podman-build-push |
Build and optionally push an image with podman, with multi-arch, cache, and SBOM support | docker/build-push-action |
podman-login |
Log into a container registry with podman, with ECR auto-detection | docker/login-action |
setup-qemu |
Register QEMU binfmt emulators via tonistiigi/binfmt for cross-platform builds |
docker/setup-qemu-action |
setup-nix |
Install Nix and configure Cachix | none |
| Workflow | Purpose |
|---|---|
docker-build-push.yml |
Build and push with buildx, tagged by docker/metadata-action |
podman-build-push.yml |
Same interface as above, built with podman |
release-please.yml |
Open release PRs and tag releases with release-please |
Releases are tagged vX.Y.Z and a floating vX tag tracks the latest release of each major version.
The examples use @main for brevity; pin to @v1 for the floating major tag, or to @v1.2.3 or a full commit SHA for an exact version.
setup-qemu registers binfmt_misc handlers with sudo podman run --privileged, so it needs sudo and a rootful podman.
GitHub-hosted Ubuntu runners meet both requirements.
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: unmango/actions/setup-qemu@main
- uses: unmango/actions/podman-login@main
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ github.token }}
- uses: unmango/actions/podman-build-push@main
with:
platforms: linux/amd64,linux/arm64
push: 'true'
tags: ghcr.io/${{ github.repository }}:latestpermissions:
contents: read
packages: write
jobs:
image:
uses: unmango/actions/.github/workflows/podman-build-push.yml@main
with:
image: ghcr.io/${{ github.repository }}
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
sbom: ${{ github.event_name != 'pull_request' }}
secrets:
dockerhub_token: ${{ secrets.DOCKERHUB_TOKEN }}release-please.yml runs release-please in simple mode.
It opens a release PR from Conventional Commits, maintains version.txt and CHANGELOG.md, and on merge creates a vX.Y.Z tag and GitHub release.
The tag push runs the build-push workflow, and docker/metadata-action derives the image tags 1.2.3, 1.2, 1, and latest from it.
The workflow needs credentials with contents, pull-requests, and issues write.
issues write covers the autorelease labels release-please puts on its PRs.
Tags created with the default GITHUB_TOKEN do not trigger other workflows, so the image build would never run.
Pass a GitHub App through the app-client-id input and the app-private-key secret, and the workflow mints a token from them.
Commits pushed with an app token are signed.
A personal access token in the token secret is the alternative when app-client-id is empty.
# .github/workflows/release-please.yml
on:
push:
branches: [main]
permissions:
contents: write
pull-requests: write
jobs:
release:
uses: unmango/actions/.github/workflows/release-please.yml@main
with:
app-client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
secrets:
app-private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}# .github/workflows/image.yml
on:
pull_request:
push:
branches: [main]
tags: ['v*']
permissions:
contents: read
packages: write
jobs:
image:
uses: unmango/actions/.github/workflows/podman-build-push.yml@main
with:
image: ghcr.io/${{ github.repository }}
push: ${{ github.event_name != 'pull_request' }}| Event | Image tags |
|---|---|
| Pull request | pr-N |
Push to main |
main, sha-<short> |
Tag v1.2.3 |
1.2.3, 1.2, 1, latest, sha-<short> |
Pass config-file and manifest-file to use a release-please-config.json instead of the simple defaults.
The workflow exposes release_created, tag_name, version, major, minor, patch, and sha as outputs for jobs that need to run only after a release.
✅ supported ·
| Input | Podman | Docker | Notes |
|---|---|---|---|
context |
✅ | ✅ | |
file |
✅ | ✅ | |
platforms |
✅ | ✅ | Multiple platforms build a manifest list; run setup-qemu first |
tags |
✅ | ✅ | |
labels |
✅ | ✅ | |
annotations |
✅ | ✅ | |
build-args |
✅ | ✅ | |
build-contexts |
✅ | ✅ | |
secrets |
✅ | ✅ | Podman takes the id=id,src=path form only |
no-cache |
✅ | ✅ | |
cache-from |
✅ | ✅ | Podman takes a single registry ref or local directory, not buildx type=... syntax, and forces --layers |
cache-to |
✅ | ✅ | Same as cache-from |
pull |
✅ | ✅ | |
network |
✅ | ✅ | |
add-hosts |
✅ | ✅ | |
cgroup-parent |
✅ | ✅ | |
shm-size |
✅ | ✅ | |
ulimit |
✅ | ✅ | |
push |
✅ | ✅ | |
sbom |
✅ | ✅ | Podman requires push and needs syft and cosign on the runner |
provenance |
✅ | No native SLSA provenance generation in buildah or podman | |
ssh |
✅ | No buildkit SSH agent forwarding equivalent | |
no-cache-filters |
✅ | buildah cache invalidation is all-or-nothing | |
allow |
✅ | No buildkit entitlement model | |
attests |
❌ | ✅ | |
builder |
❌ | ✅ | |
call |
❌ | ✅ | |
load |
❌ | ✅ | Podman images are already in the local store after a build |
outputs |
❌ | ✅ | |
secret-envs |
❌ | ✅ | |
secret-files |
❌ | ✅ | Use secrets |
target |
❌ | ✅ | |
github-token |
❌ | ✅ |
| Output | Podman | Docker | Notes |
|---|---|---|---|
imageid |
✅ | ✅ | |
digest |
✅ | ✅ | Podman only sets it when push is true |
metadata |
✅ | ✅ | Podman emits containerimage.imageid, containerimage.digest, and image.tags, a subset of the buildx shape |
Podman boolean inputs are strings ('true' and 'false') because composite actions have no typed inputs.
| Input | Podman | Docker | Notes |
|---|---|---|---|
registry |
✅ | ✅ | |
username |
✅ | ✅ | |
password |
✅ | ✅ | |
ecr |
✅ | ✅ | auto, true, or false; needs aws-actions/configure-aws-credentials first |
logout |
✅ | Composite actions have no post-job hook; no warning is logged |
| Input | Podman | Docker | Notes |
|---|---|---|---|
platforms |
✅ | ✅ | |
image |
✅ | ✅ | |
cache-image |
❌ | ✅ | |
cache-binary |
❌ | ✅ |
| Input | Podman | Docker | Notes |
|---|---|---|---|
image |
✅ | ✅ | |
platforms |
✅ | ✅ | Podman runs setup-qemu when more than one platform is listed |
push |
✅ | ✅ | |
build-args |
✅ | ✅ | |
file |
✅ | ✅ | |
context |
✅ | ✅ | |
dockerhub_token (secret) |
✅ | ✅ | |
secrets-list |
✅ | ❌ | Build secrets in id=id,src=path form |
cache |
✅ | ❌ | none, registry, or local; docker always uses the GHA cache backend |
cache-image |
✅ | ❌ | Registry ref used when cache is registry |
cache-dir |
✅ | ❌ | Directory used when cache is local, persisted with actions/cache |
sbom |
✅ | ❌ | Docker always attaches an SBOM when pushing; podman installs syft and cosign and attaches an SPDX SBOM on request |
provenance |
❌ | Docker always generates provenance when pushing; podman accepts the input and ignores it |
Enter the dev shell with nix develop, or let direnv load it from .envrc.
make check # nix flake check, includes actionlint
make fmt # nix fmt