mirror of
https://github.com/ModernRelay/omnigraph.git
synced 2026-07-12 03:12:11 +02:00
Some checks failed
CI / Classify Changes (push) Has been cancelled
CI / Check AGENTS.md Links (push) Has been cancelled
CI / Container Entrypoint (push) Has been cancelled
Release Edge / Prepare edge release (push) Has been cancelled
CI / Test Workspace (push) Has been cancelled
CI / Test omnigraph-server --features aws (push) Has been cancelled
CI / RustFS S3 Integration (cli) (push) Has been cancelled
CI / RustFS S3 Integration (cluster) (push) Has been cancelled
CI / RustFS S3 Integration (engine) (push) Has been cancelled
CI / RustFS S3 Integration (failpoints) (push) Has been cancelled
CI / RustFS S3 Integration (server) (push) Has been cancelled
Release Edge / Build edge omnigraph-linux-arm64 (push) Has been cancelled
Release Edge / Build edge omnigraph-linux-x86_64 (push) Has been cancelled
Release Edge / Build edge omnigraph-macos-arm64 (push) Has been cancelled
Release Edge / Build edge omnigraph-windows-x86_64 (push) Has been cancelled
Release Edge / Smoke Windows installer (push) Has been cancelled
* feat(ci): publish omnigraph-server image to Docker Hub alongside GHCR Docker Hub (docker.io/modernrelay/omnigraph-server) becomes the primary anonymous-pull distribution channel; the step no-ops when the DOCKERHUB_* secrets are unset so forks and the GHCR-only path keep working. Same latest-tag policy as GHCR (real tag pushes only, never dispatch backfills). Docs updated in the same PR (ci.md, deployment.md). * review fixes: preserve digest summary on Hub failure, tolerate unprefixed RepoDigests - Docker Hub push is continue-on-error with an explicit fail-gate AFTER the digest report, so a Hub failure still fails the run but can no longer suppress the summary for the already-pushed GHCR image. - RepoDigests may store Hub images without the docker.io/ prefix depending on Docker version; the digest grep now accepts both forms.
152 lines
6.3 KiB
YAML
152 lines
6.3 KiB
YAML
name: Publish container image
|
|
|
|
# Build and publish the omnigraph-server container image to GHCR so
|
|
# downstream deployments can pull it without building from source.
|
|
#
|
|
# Kept separate from release.yml on purpose: an image-publish failure must
|
|
# not block the binary release / Homebrew chain, and a manual backfill of an
|
|
# old tag must not re-run the four-platform release matrix.
|
|
#
|
|
# Triggers (same dual pattern as release.yml):
|
|
# - push of a v* tag (normal release)
|
|
# - workflow_dispatch with an explicit `tag` (publish an image for a past
|
|
# tag; resolves the same `${{ inputs.tag || github.ref_name }}`)
|
|
#
|
|
# The binaries are compiled inside a rust:1-bookworm container, NOT on the
|
|
# runner host: the Dockerfile's runtime base is debian bookworm-slim
|
|
# (glibc 2.36), and binaries built on ubuntu-latest (glibc 2.39) do not run
|
|
# there. Builder and runtime must share the same distro release.
|
|
|
|
on:
|
|
push:
|
|
tags:
|
|
- "v*"
|
|
workflow_dispatch:
|
|
inputs:
|
|
tag:
|
|
description: "Tag to publish an image for (e.g. v0.8.1). Required for manual dispatches."
|
|
required: true
|
|
type: string
|
|
|
|
jobs:
|
|
publish_image:
|
|
name: Build and push image
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
env:
|
|
RELEASE_TAG: ${{ inputs.tag || github.ref_name }}
|
|
steps:
|
|
# The dispatch `tag` input is free-form; without this guard a dispatcher
|
|
# could pass a branch name or SHA and publish non-release code under a
|
|
# release-looking image tag. Require an existing v* tag ref.
|
|
- name: Validate dispatch tag
|
|
if: github.event_name == 'workflow_dispatch'
|
|
env:
|
|
GH_TOKEN: ${{ github.token }}
|
|
run: |
|
|
[[ "${RELEASE_TAG}" == v* ]] \
|
|
|| { echo "tag must be a v* release tag, got: ${RELEASE_TAG}" >&2; exit 1; }
|
|
gh api "repos/${GITHUB_REPOSITORY}/git/ref/tags/${RELEASE_TAG}" >/dev/null \
|
|
|| { echo "no such tag: ${RELEASE_TAG}" >&2; exit 1; }
|
|
|
|
- name: Checkout source
|
|
uses: actions/checkout@v5.0.1
|
|
with:
|
|
# Fully qualified so a branch of the same name can never shadow the tag.
|
|
ref: refs/tags/${{ env.RELEASE_TAG }}
|
|
|
|
- name: Build release binaries (bookworm builder)
|
|
run: |
|
|
docker run --rm -v "$PWD:/work" -w /work rust:1-bookworm bash -euxc '
|
|
apt-get update
|
|
apt-get install -y --no-install-recommends protobuf-compiler libprotobuf-dev
|
|
# --features omnigraph-server/aws: include the AWS Secrets Manager
|
|
# bearer-token source so one public image serves both token modes.
|
|
cargo build --release --locked -p omnigraph-cli -p omnigraph-server --features omnigraph-server/aws
|
|
'
|
|
|
|
- name: Log in to GHCR
|
|
run: |
|
|
echo "${{ secrets.GITHUB_TOKEN }}" \
|
|
| docker login ghcr.io --username "${{ github.actor }}" --password-stdin
|
|
|
|
- name: Build and push image
|
|
run: |
|
|
owner="${GITHUB_REPOSITORY_OWNER,,}"
|
|
image="ghcr.io/${owner}/omnigraph-server"
|
|
docker build -t "${image}:${RELEASE_TAG}" .
|
|
docker push "${image}:${RELEASE_TAG}"
|
|
|
|
# Move `latest` only on real tag pushes — a dispatch backfill of an
|
|
# old tag must not repoint `latest` at it.
|
|
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
|
|
docker tag "${image}:${RELEASE_TAG}" "${image}:latest"
|
|
docker push "${image}:latest"
|
|
fi
|
|
|
|
# Docker Hub is the primary public distribution channel (anonymous pulls
|
|
# for deployments). Skipped when the DOCKERHUB_* secrets are not
|
|
# configured, so forks and the GHCR-only path keep working. With an org
|
|
# access token, DOCKERHUB_USERNAME is the ORG name — which is also the
|
|
# image namespace.
|
|
# continue-on-error so a Hub failure can't suppress the digest summary
|
|
# for the already-pushed GHCR image; the fail-gate step below still
|
|
# fails the run afterwards.
|
|
- name: Push to Docker Hub
|
|
id: dockerhub
|
|
continue-on-error: true
|
|
env:
|
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
run: |
|
|
if [[ -z "${DOCKERHUB_USERNAME}" || -z "${DOCKERHUB_TOKEN}" ]]; then
|
|
echo "DOCKERHUB_* secrets not configured; skipping Docker Hub publish."
|
|
exit 0
|
|
fi
|
|
owner="${GITHUB_REPOSITORY_OWNER,,}"
|
|
ghcr_image="ghcr.io/${owner}/omnigraph-server"
|
|
hub_image="docker.io/${DOCKERHUB_USERNAME}/omnigraph-server"
|
|
|
|
echo "${DOCKERHUB_TOKEN}" \
|
|
| docker login docker.io --username "${DOCKERHUB_USERNAME}" --password-stdin
|
|
|
|
docker tag "${ghcr_image}:${RELEASE_TAG}" "${hub_image}:${RELEASE_TAG}"
|
|
docker push "${hub_image}:${RELEASE_TAG}"
|
|
|
|
# Same `latest` policy as GHCR: real tag pushes only, never backfills.
|
|
if [[ "${GITHUB_EVENT_NAME}" == "push" ]]; then
|
|
docker tag "${ghcr_image}:${RELEASE_TAG}" "${hub_image}:latest"
|
|
docker push "${hub_image}:latest"
|
|
fi
|
|
|
|
- name: Report pinned digests
|
|
env:
|
|
DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
run: |
|
|
owner="${GITHUB_REPOSITORY_OWNER,,}"
|
|
{
|
|
echo "## Container image published"
|
|
echo
|
|
echo '```'
|
|
for image in "ghcr.io/${owner}/omnigraph-server" \
|
|
${DOCKERHUB_USERNAME:+"docker.io/${DOCKERHUB_USERNAME}/omnigraph-server"}; do
|
|
echo "${image}:${RELEASE_TAG}"
|
|
# RepoDigests may store Hub images with or without the
|
|
# docker.io/ prefix depending on the Docker version.
|
|
docker inspect --format='{{range .RepoDigests}}{{.}}{{"\n"}}{{end}}' \
|
|
"${image}:${RELEASE_TAG}" | grep -E "^(docker\.io/)?${image#docker.io/}@" || true
|
|
done
|
|
echo '```'
|
|
echo
|
|
echo "Pin deployments to the digest form."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
# The summary above always runs; a Docker Hub failure still fails the
|
|
# run here so operators notice.
|
|
- name: Fail if Docker Hub push failed
|
|
if: steps.dockerhub.outcome == 'failure'
|
|
run: |
|
|
echo "Docker Hub push failed (GHCR image was pushed; see summary)." >&2
|
|
exit 1
|