ci: run on our own lane, not GitHub's (#14)

This repo had seven GitHub workflows. Three of them -- dev.yaml, release.yaml
and versioned_release.yaml -- built THE SAME two images, ghcr.io/hanzoai/s3-csi
and ghcr.io/hanzoai/s3-mount. Three builders on one commit is three chances to
publish something nobody asked for, and no single place that says what this repo
produces.

Now there is one: the repo-root hanzo.yml, which platform.hanzo.ai reads and the
hanzoai/ci reusable gates from, exactly as hanzoai/cloud does it.

.github/workflows is gone entirely. The pipelines that carry their own weight --
the kind integration suite and the two helm chart jobs -- moved to
.hanzo/workflows unchanged; they keep runs-on: ubuntu-latest because our
git-runner registers that label itself
(ubuntu-latest:docker://catthehacker/ubuntu:act-24.04), so the same line now
means our runner instead of GitHub's. prepare_release.yaml is dropped: bumping a
dependency and cutting a tag is the platform's job, not a workflow's.

Co-authored-by: hanzo-dev <[email protected]>
This commit is contained in:
2026-07-27 23:04:14 -07:00
committed by GitHub
co-authored by hanzo-dev
parent 37aab4e185
commit 4ea323487b
9 changed files with 45 additions and 515 deletions
-115
View File
@@ -1,115 +0,0 @@
name: dev Docker images
on:
push:
branches: [master]
# Build on PR
pull_request:
# Allow trigger for external PRs
workflow_dispatch:
permissions:
contents: read
packages: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Docker meta (csi-driver)
id: docker_meta_csi
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/hanzoai/s3-csi
tags: |
type=raw,value=dev
flavor: |
latest=true
labels: |
org.opencontainers.image.title=s3-csi
org.opencontainers.image.description=S3 is a distributed storage system for blobs, objects, files, and data lake, to store and serve billions of files fast!
org.opencontainers.image.vendor=Chris Lu
- name: Docker meta (mount-service)
id: docker_meta_mount
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/hanzoai/s3-mount
tags: |
type=raw,value=dev
flavor: |
latest=true
labels: |
org.opencontainers.image.title=s3-mount
org.opencontainers.image.description=S3 CSI mount helper service
org.opencontainers.image.vendor=Chris Lu
- name: Fetch history
run: git fetch --prune --unshallow
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "[email protected]"
- name: Get the current tag name
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" | sed 's/\//_/g' >> $GITHUB_ENV
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
with:
buildkitd-flags: "--debug"
# GHCR, not Docker Hub. This fork inherited a login as the upstream
# author, so every build failed with "unauthorized: incorrect username or
# password" — we do not have, and should not want, chrislusf's Docker Hub
# token. GITHUB_TOKEN can push to this org's own registry, so the image
# publishes with no secret to provision.
- name: Login to GHCR
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build csi-driver image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
file: ./cmd/s3-csi-driver/Dockerfile
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta_csi.outputs.tags }}
labels: ${{ steps.docker_meta_csi.outputs.labels }}
- name: Build mount-service image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
file: ./cmd/s3-mount/Dockerfile
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta_mount.outputs.tags }}
labels: ${{ steps.docker_meta_mount.outputs.labels }}
helm:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Helm check
uses: igabaydulin/[email protected]
env:
CHART_LOCATION: ./deploy/helm/s3-csi
CHART_VALUES: ./deploy/helm/s3-csi/values.yaml
-197
View File
@@ -1,197 +0,0 @@
name: Prepare release
# Automates the manual release steps:
# 1. (optional) go get -u github.com/s3/s3 + go mod tidy
# and sync the Dockerfile S3_COMMIT pins
# 2. bump `version` (chart) and `appVersion` in the Helm Chart.yaml
# 3. run the build + tests
# 4. commit the changes to master
# 5. push the `v<appVersion>` tag and create the GitHub release
#
# Creating the release fans out to the existing workflows:
# - versioned_release.yaml builds & pushes the Docker images (on `push: tags`)
# - helm_release.yaml publishes the Helm chart (on `release: published`)
#
# IMPORTANT: events triggered by the default GITHUB_TOKEN do NOT start other
# workflows. To have the tag/release automatically kick off the Docker and Helm
# workflows, add a repo secret `RELEASE_PAT` (a fine-grained or classic PAT with
# `contents: write`). Without it the release is still created, but you must
# re-run those two workflows manually (both support workflow_dispatch).
on:
workflow_dispatch:
inputs:
app_version:
description: 'App version, e.g. v1.4.21 (leave empty to auto-bump appVersion using "bump")'
required: false
type: string
bump:
description: 'Semver part to bump for appVersion (when empty above) and the chart version'
required: true
default: 'patch'
type: choice
options:
- patch
- minor
- major
update_s3:
description: 'Run "go get -u github.com/s3/s3" + go mod tidy'
required: false
default: true
type: boolean
dry_run:
description: 'Compute and show changes, but do not commit, tag, or release'
required: false
default: false
type: boolean
permissions:
contents: write
jobs:
prepare-release:
runs-on: ubuntu-latest
env:
CHART: deploy/helm/s3-csi/Chart.yaml
steps:
- name: Checkout master
uses: actions/checkout@v4
with:
ref: master
fetch-depth: 0
# Use a PAT if available so the resulting tag/release triggers the
# Docker (versioned_release.yaml) and Helm (helm_release.yaml) workflows.
token: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }}
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version-file: go.mod
- name: Configure Git
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
- name: Update S3 dependency
if: ${{ inputs.update_s3 }}
run: |
OLD=$(grep 'github.com/s3/s3 ' go.mod | grep -v module | awk '{print $2}')
go get -u github.com/s3/s3@latest
go mod tidy
NEW=$(grep 'github.com/s3/s3 ' go.mod | grep -v module | awk '{print $2}')
echo "S3_OLD=$OLD" >> "$GITHUB_ENV"
echo "S3_NEW=$NEW" >> "$GITHUB_ENV"
echo "S3: $OLD -> $NEW"
# Keep the Dockerfile commit pins in sync with go.mod (mirrors sync-s3.yaml).
COMMIT=$(echo "$NEW" | sed 's/.*-//')
sed -i "s/^ARG S3_COMMIT=.*/ARG S3_COMMIT=$COMMIT/" cmd/s3-mount/Dockerfile
sed -i "s/^ARG S3_COMMIT=.*/ARG S3_COMMIT=$COMMIT/" cmd/s3-mount/Dockerfile.dev
grep "ARG S3_COMMIT=" cmd/s3-mount/Dockerfile cmd/s3-mount/Dockerfile.dev
- name: Compute new versions
id: versions
run: |
set -euo pipefail
bump_semver() {
local version="$1" level="$2" major minor patch
IFS='.' read -r major minor patch <<< "$version"
case "$level" in
major) major=$((major + 1)); minor=0; patch=0 ;;
minor) minor=$((minor + 1)); patch=0 ;;
patch) patch=$((patch + 1)) ;;
*) echo "unknown bump level: $level" >&2; exit 1 ;;
esac
echo "${major}.${minor}.${patch}"
}
CUR_CHART=$(grep '^version:' "$CHART" | awk '{print $2}')
CUR_APP=$(grep '^appVersion:' "$CHART" | awk '{print $2}')
echo "Current chart version: $CUR_CHART"
echo "Current app version: $CUR_APP"
# App version: explicit input wins, otherwise bump the current appVersion.
INPUT_APP="${{ inputs.app_version }}"
if [ -n "$INPUT_APP" ]; then
case "$INPUT_APP" in v*) NEW_APP="$INPUT_APP" ;; *) NEW_APP="v$INPUT_APP" ;; esac
else
NEW_APP="v$(bump_semver "${CUR_APP#v}" "${{ inputs.bump }}")"
fi
NEW_CHART="$(bump_semver "$CUR_CHART" "${{ inputs.bump }}")"
if [ "$NEW_APP" = "$CUR_APP" ]; then
echo "::error::New app version $NEW_APP equals current; pick a different app_version or bump." >&2
exit 1
fi
echo "New chart version: $NEW_CHART"
echo "New app version: $NEW_APP"
{
echo "new_chart=$NEW_CHART"
echo "new_app=$NEW_APP"
echo "tag=$NEW_APP"
} >> "$GITHUB_OUTPUT"
- name: Update Chart.yaml
run: |
sed -i "s/^version:.*/version: ${{ steps.versions.outputs.new_chart }}/" "$CHART"
sed -i "s/^appVersion:.*/appVersion: ${{ steps.versions.outputs.new_app }}/" "$CHART"
echo "----- Chart.yaml -----"
cat "$CHART"
- name: Build and test
run: |
go build ./...
go test ./...
- name: Show diff
run: git --no-pager diff --stat
- name: Commit, tag, and release
if: ${{ !inputs.dry_run }}
env:
GH_TOKEN: ${{ secrets.RELEASE_PAT || secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
TAG="${{ steps.versions.outputs.tag }}"
APP_NO_V="${TAG#v}"
if git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null || \
git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then
echo "::error::Tag ${TAG} already exists." >&2
exit 1
fi
git add -A
git commit -m "${APP_NO_V}"
git push origin master
# Push the tag with git so the `push: tags` trigger fires
# (versioned_release.yaml). Creating the tag via the release API would
# only emit a `create` event, which that workflow does not listen for.
git tag "$TAG"
git push origin "$TAG"
NOTES="Helm chart \`${{ steps.versions.outputs.new_chart }}\`, app version \`${TAG}\`."
if [ -n "${S3_NEW:-}" ] && [ "${S3_OLD:-}" != "${S3_NEW:-}" ]; then
NOTES="${NOTES}"$'\n\n'"S3 dependency: \`${S3_OLD}\` → \`${S3_NEW}\`"
NOTES="${NOTES}"$'\n'"https://github.com/s3/s3/compare/${S3_OLD}...${S3_NEW}"
fi
# Create the release from the tag just pushed; fires `release: published`
# (helm_release.yaml). --verify-tag ensures we reuse the existing tag.
gh release create "$TAG" \
--title "$TAG" \
--notes "$NOTES" \
--verify-tag
- name: Dry run summary
if: ${{ inputs.dry_run }}
run: |
echo "DRY RUN — no commit/tag/release created."
echo "Would tag: ${{ steps.versions.outputs.tag }}"
echo "Chart version: ${{ steps.versions.outputs.new_chart }}"
echo "App version: ${{ steps.versions.outputs.new_app }}"
-101
View File
@@ -1,101 +0,0 @@
name: Build & release Docker images
on:
push:
tags:
- 'v*'
# Build on PR
pull_request:
# Allow trigger for external PRs
workflow_dispatch:
permissions:
contents: read
packages: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Docker meta (csi-driver)
id: docker_meta_csi
uses: docker/metadata-action@v3
with:
images: |
ghcr.io/hanzoai/s3-csi
tags: |
type=raw,value=latest
flavor: |
latest=true
labels: |
org.opencontainers.image.title=s3-csi
org.opencontainers.image.description=S3 is a distributed storage system for blobs, objects, files, and data lake, to store and serve billions of files fast!
org.opencontainers.image.vendor=Chris Lu
- name: Docker meta (mount-service)
id: docker_meta_mount
uses: docker/metadata-action@v3
with:
images: |
ghcr.io/hanzoai/s3-mount
tags: |
type=raw,value=latest
flavor: |
latest=true
labels: |
org.opencontainers.image.title=s3-mount
org.opencontainers.image.description=S3 CSI mount helper service
org.opencontainers.image.vendor=Chris Lu
- name: Fetch history
run: git fetch --prune --unshallow
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "[email protected]"
- name: Get the current tag name
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" | sed 's/\//_/g' >> $GITHUB_ENV
- name: Setup QEMU
uses: docker/setup-qemu-action@v1
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v1
with:
buildkitd-flags: "--debug"
- name: Login to GHCR
# if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build csi-driver image
# if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: docker/build-push-action@v2
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
file: ./cmd/s3-csi-driver/Dockerfile
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta_csi.outputs.tags }}
labels: ${{ steps.docker_meta_csi.outputs.labels }}
- name: Build mount-service image
uses: docker/build-push-action@v2
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
file: ./cmd/s3-mount/Dockerfile
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta_mount.outputs.tags }}
labels: ${{ steps.docker_meta_mount.outputs.labels }}
-102
View File
@@ -1,102 +0,0 @@
name: Build & release Docker images
on:
push:
tags:
- 'v*'
# Build on PR
pull_request:
# Allow trigger for external PRs
workflow_dispatch:
permissions:
contents: read
packages: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Docker meta (csi-driver)
id: docker_meta_csi
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/hanzoai/s3-csi
tags: |
type=ref,event=tag
flavor: |
latest=false
labels: |
org.opencontainers.image.title=s3-csi
org.opencontainers.image.description=S3 is a distributed storage system for blobs, objects, files, and data lake, to store and serve billions of files fast!
org.opencontainers.image.vendor=Chris Lu
- name: Docker meta (mount-service)
id: docker_meta_mount
uses: docker/metadata-action@v5
with:
images: |
ghcr.io/hanzoai/s3-mount
tags: |
type=ref,event=tag
flavor: |
latest=false
labels: |
org.opencontainers.image.title=s3-mount
org.opencontainers.image.description=S3 CSI mount helper service
org.opencontainers.image.vendor=Chris Lu
- name: Fetch history
run: git fetch --prune --unshallow
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "[email protected]"
- name: Get the current tag name
run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" | sed 's/\//_/g' >> $GITHUB_ENV
- name: Setup QEMU
uses: docker/setup-qemu-action@v3
- name: Setup Docker Buildx
uses: docker/setup-buildx-action@v3
with:
buildkitd-flags: "--debug"
- name: Login to GHCR
# Skip for PRs where secrets are not available
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build csi-driver image
# if: ${{ startsWith(github.ref, 'refs/tags/') }}
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
file: ./cmd/s3-csi-driver/Dockerfile
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta_csi.outputs.tags }}
labels: ${{ steps.docker_meta_csi.outputs.labels }}
- name: Build mount-service image
uses: docker/build-push-action@v6
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
file: ./cmd/s3-mount/Dockerfile
platforms: linux/amd64, linux/arm, linux/arm64, linux/386
tags: ${{ steps.docker_meta_mount.outputs.tags }}
labels: ${{ steps.docker_meta_mount.outputs.labels }}
+18
View File
@@ -0,0 +1,18 @@
name: CI/CD
# The ONE pipeline for s3-csi, on our own runners against git.hanzo.ai.
#
# THE LAW: this repo has no .github/workflows. Everything that gates, builds or
# deploys lives here, and every real detail lives in the repo-root hanzo.yml so
# platform.hanzo.ai reads the same declaration this pipeline does.
on:
push:
branches: [main]
pull_request:
workflow_dispatch:
concurrency:
group: cicd-${{ github.ref }}
cancel-in-progress: true
jobs:
gate:
uses: hanzoai/ci/.hanzo/workflows/build.yml@v2
secrets: inherit
+27
View File
@@ -0,0 +1,27 @@
# Canonical CI config for hanzoai/s3-csi — read by the hanzoai/ci reusable
# (.hanzo/workflows/cicd.yml) and by platform.hanzo.ai. One file, one place.
#
# This replaces three GitHub workflows that each built THE SAME two images
# (dev.yaml, release.yaml, versioned_release.yaml). Three builders on one commit
# is three chances to publish something nobody asked for; the images: block below
# is the single declaration of what this repo produces.
images:
- name: s3-csi
context: .
dockerfile: cmd/s3-csi-driver/Dockerfile
repo: ghcr.io/hanzoai/s3-csi
- name: s3-mount
context: .
dockerfile: cmd/s3-mount/Dockerfile
repo: ghcr.io/hanzoai/s3-mount
test:
- name: go
# The driver's storage path talks ZAP to the filer; keep it building and its
# unit tests honest before anything is published.
run: |
set -e
export GOPRIVATE='github.com/hanzoai/*' GOWORK=off
go vet ./...
go test ./...