Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions .github/workflows/shared-docker-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
name: Shared Docker Release

on:
workflow_call:
inputs:
runs-on:
description: "The runner to use for the job (must be a Linux runner; this workflow uses Docker buildx)"
required: false
default: "ubuntu-latest"
type: string
image-name:
description: "Full GHCR image name, e.g. ghcr.io/cloudoperators/myapp"
required: true
type: string
dockerfile:
description: "Path to the Dockerfile"
required: false
default: "Dockerfile"
type: string
context:
description: "Docker build context path"
required: false
default: "."
type: string
platforms:
description: "Comma-separated list of target platforms"
required: false
default: "linux/amd64,linux/arm64"
type: string
environment:
description: "GitHub environment name to use for this job (e.g. release), for environment protection rules and scoped secrets"
required: false
default: ""
type: string
secrets:
registry-token:
description: "Token to authenticate to GHCR; falls back to GITHUB_TOKEN if not provided"
required: false

jobs:
docker-release:
runs-on: ${{ inputs.runs-on }}
environment: ${{ inputs.environment != '' && inputs.environment || null }}
permissions:
contents: read
packages: write
steps:
- name: Validate inputs
env:
IMAGE_NAME: ${{ inputs.image-name }}
run: |
if [ "$RUNNER_OS" != "Linux" ]; then
echo "ERROR: this workflow requires a Linux runner (uses Docker buildx); got: $RUNNER_OS"
exit 1
fi
case "$IMAGE_NAME" in
ghcr.io/*) ;;
*) echo "ERROR: image-name must start with 'ghcr.io/' (got: '$IMAGE_NAME')"; exit 1 ;;
esac

- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up QEMU
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v3

- name: Log in to container registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.registry-token != '' && secrets.registry-token || secrets.GITHUB_TOKEN }}

- name: Extract Docker metadata
id: meta
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v5
with:
images: ${{ inputs.image-name }}
flavor: |
latest=false
tags: |
type=semver,pattern={{version}}
type=semver,pattern=v{{version}}
type=semver,pattern=v{{major}}.{{minor}}
type=semver,pattern=v{{major}}
type=raw,value=latest,enable={{is_default_branch}}
type=sha,format=long

- name: Build and push Docker image
uses: docker/build-push-action@14487ce63c7a62a4a324b0bfb37086795e31c6c1 # v6
with:
context: ${{ inputs.context }}
file: ${{ inputs.dockerfile }}
platforms: ${{ inputs.platforms }}
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
71 changes: 71 additions & 0 deletions .github/workflows/shared-goreleaser.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Shared GoReleaser

on:
workflow_call:
inputs:
runs-on:
description: "The runner to use for the job (must be a Linux runner)"
required: false
default: "ubuntu-latest"
type: string
goreleaser-version:
description: "GoReleaser version constraint passed to goreleaser-action (e.g. '~> v2')"
required: false
default: "~> v2"
type: string
goreleaser-config:
description: "Path to .goreleaser.yaml config file; leave empty to use GoReleaser's default discovery"
required: false
default: ""
type: string
go-version-file:
description: "Path to the go.mod file used by setup-go"
required: false
default: "go.mod"
type: string
environment:
description: "GitHub environment name to use for this job (e.g. release), for environment protection rules and scoped secrets"
required: false
default: ""
type: string
secrets:
release-token:
description: "Token used for GoReleaser GitHub Release creation; falls back to GITHUB_TOKEN if not provided"
required: false

jobs:
goreleaser:
runs-on: ${{ inputs.runs-on }}
environment: ${{ inputs.environment != '' && inputs.environment || null }}
concurrency:
group: goreleaser-${{ github.repository }}-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: write
steps:
- name: Validate inputs
run: |
if [ "$RUNNER_OS" != "Linux" ]; then
echo "ERROR: this workflow requires a Linux runner; got: $RUNNER_OS"
exit 1
fi

- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
with:
fetch-depth: 0

- name: Set up Go
uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
with:
go-version-file: ${{ inputs.go-version-file }}
cache: true

- name: Run GoReleaser
uses: goreleaser/goreleaser-action@e435ccd777264be153ace6237001ef4d979d3a7a # v6
with:
distribution: goreleaser
version: ${{ inputs.goreleaser-version }}
args: release --clean${{ inputs.goreleaser-config != '' && format(' --config {0}', inputs.goreleaser-config) || '' }}
env:
GITHUB_TOKEN: ${{ secrets.release-token != '' && secrets.release-token || secrets.GITHUB_TOKEN }}
138 changes: 138 additions & 0 deletions .github/workflows/shared-helm-release.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
name: Shared Helm Release

on:
workflow_call:
inputs:
runs-on:
description: "The runner to use for the job (must be a Linux runner)"
required: false
default: "ubuntu-latest"
type: string
registry:
description: "Container registry hostname"
required: false
default: "ghcr.io"
type: string
chart-dir:
description: "Path to the chart directory containing Chart.yaml (e.g. charts/myapp)"
required: true
type: string
chart-name:
description: "Chart name used for the OCI duplicate-version check (must match the name field in Chart.yaml)"
required: true
type: string
helm-version:
description: "Helm CLI version to install"
required: false
default: "v3.17.0"
type: string
run-dependency-update:
description: "Run helm dependency update before packaging"
required: false
default: false
type: boolean
allow-existing:
description: "When true, exit 0 instead of failing if the chart version already exists in the registry. Useful when not all charts in a batch have changed."
required: false
default: false
type: boolean
environment:
description: "GitHub environment name to use for this job (e.g. release), for environment protection rules and scoped secrets"
required: false
default: ""
type: string
secrets:
registry-token:
description: "Token to authenticate to the container registry; falls back to GITHUB_TOKEN if not provided"
required: false

jobs:
helm-release:
runs-on: ${{ inputs.runs-on }}
environment: ${{ inputs.environment != '' && inputs.environment || null }}
concurrency:
group: helm-release-${{ github.repository }}-${{ inputs.chart-name }}-${{ github.ref }}
cancel-in-progress: false
permissions:
contents: read
packages: write
steps:
- name: Validate inputs
env:
CHART_DIR: ${{ inputs.chart-dir }}
run: |
if [ "$RUNNER_OS" != "Linux" ]; then
echo "ERROR: this workflow requires a Linux runner; got: $RUNNER_OS"
exit 1
fi
if [ -z "$CHART_DIR" ]; then
echo "ERROR: chart-dir is required"
exit 1
fi

- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set up Helm
uses: azure/setup-helm@9bc31f4ebc9c6b171d7bfbaa5d006ae7abdb4310 # v5.0.1
with:
version: ${{ inputs.helm-version }}

- name: Log in to container registry
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: ${{ inputs.registry }}
username: ${{ github.actor }}
password: ${{ secrets.registry-token != '' && secrets.registry-token || secrets.GITHUB_TOKEN }}

- name: Validate chart and check for duplicate version
id: chart-check
env:
CHART_DIR: ${{ inputs.chart-dir }}
CHART_NAME: ${{ inputs.chart-name }}
REGISTRY: ${{ inputs.registry }}
ALLOW_EXISTING: ${{ inputs.allow-existing }}
run: |
if [ ! -f "${CHART_DIR}/Chart.yaml" ]; then
echo "ERROR: chart-dir '${CHART_DIR}' does not contain Chart.yaml"
exit 1
fi
CHART_VERSION=$(helm show chart "${CHART_DIR}" | grep -E '^version:' | head -1 | sed 's/^version:[[:space:]]*//' | tr -d '[:space:]')
if ! echo "$CHART_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+'; then
echo "ERROR: could not parse semver from chart metadata (got: '$CHART_VERSION')"
exit 1
fi
echo "chart_version=${CHART_VERSION}" >> "$GITHUB_OUTPUT"
PULL_STDERR=$(helm pull "oci://${REGISTRY}/${{ github.repository }}/charts/${CHART_NAME}" --version "${CHART_VERSION}" 2>&1 >/dev/null) && PULL_EXIT=0 || PULL_EXIT=$?
if [ "$PULL_EXIT" -eq 0 ]; then
if [ "$ALLOW_EXISTING" = "true" ]; then
echo "Chart ${CHART_NAME}:${CHART_VERSION} already exists in OCI registry — skipping (allow-existing=true)"
echo "skip=true" >> "$GITHUB_OUTPUT"
else
echo "ERROR: chart ${CHART_NAME}:${CHART_VERSION} already exists in OCI registry — bump Chart.yaml version before pushing"
exit 1
fi
elif echo "$PULL_STDERR" | grep -qiE 'not found|does not exist|manifest unknown|tag does not exist'; then
: # version absent — proceed with push
else
echo "ERROR: helm pull failed with an unexpected error (auth/network/transport issue):"
echo "$PULL_STDERR"
exit 1
fi

- name: Run helm dependency update
if: inputs.run-dependency-update == true && steps.chart-check.outputs.skip != 'true'
env:
CHART_DIR: ${{ inputs.chart-dir }}
run: helm dependency update "$CHART_DIR"

- name: Package and push Helm chart
if: steps.chart-check.outputs.skip != 'true'
env:
CHART_DIR: ${{ inputs.chart-dir }}
CHART_NAME: ${{ inputs.chart-name }}
CHART_VERSION: ${{ steps.chart-check.outputs.chart_version }}
REGISTRY: ${{ inputs.registry }}
run: |
helm package "$CHART_DIR"
helm push "${CHART_NAME}-${CHART_VERSION}.tgz" "oci://${REGISTRY}/${{ github.repository }}/charts/"
33 changes: 28 additions & 5 deletions .github/workflows/shared-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ on:
required: false
default: false
type: boolean
chart-only:
description: "Bump Chart.yaml version only (skip appVersion, tag as helm-chart-vX.Y.Z, skip GitHub Release). Use for chart-only releases that do not involve a new app binary."
Comment thread
onuryilmaz marked this conversation as resolved.
required: false
default: false
type: boolean
dispatch-greenhouse-extensions:
description: "Trigger a repository_dispatch event on cloudoperators/greenhouse-extensions after release"
required: false
Expand Down Expand Up @@ -79,14 +84,26 @@ jobs:
env:
MAKEFILE_PATH: ${{ inputs.makefile-path }}
CHART_PATH: ${{ inputs.chart-path }}
CHART_ONLY: ${{ inputs.chart-only }}
run: |
if [ "$RUNNER_OS" != "Linux" ]; then
echo "ERROR: this workflow requires a Linux runner (uses GNU sed); got: $RUNNER_OS"
exit 1
fi
if [ -z "$MAKEFILE_PATH" ] && [ -z "$CHART_PATH" ]; then
echo "ERROR: at least one of makefile-path or chart-path is required for version computation"
exit 1
if [ "$CHART_ONLY" = "true" ]; then
if [ -z "$CHART_PATH" ]; then
echo "ERROR: chart-path is required when chart-only is true"
exit 1
fi
if [ -n "$MAKEFILE_PATH" ]; then
echo "ERROR: makefile-path must not be set when chart-only is true — chart-only mode reads and writes Chart.yaml only"
exit 1
fi
else
if [ -z "$MAKEFILE_PATH" ] && [ -z "$CHART_PATH" ]; then
echo "ERROR: at least one of makefile-path or chart-path is required for version computation"
exit 1
fi
fi
if [ -n "$MAKEFILE_PATH" ] && [ ! -f "$MAKEFILE_PATH" ]; then
echo "ERROR: makefile-path '$MAKEFILE_PATH' does not exist"
Expand Down Expand Up @@ -174,7 +191,7 @@ jobs:
sed -i "s/^version:.*/version: ${NEW_VERSION}/" "$CHART_PATH"

- name: Update Chart.yaml appVersion
if: inputs.chart-path != '' && inputs.bump-chart-app-version == true
if: inputs.chart-path != '' && inputs.bump-chart-app-version == true && inputs.chart-only == false
env:
NEW_VERSION: ${{ steps.version.outputs.new }}
CHART_PATH: ${{ inputs.chart-path }}
Expand All @@ -193,10 +210,16 @@ jobs:
if [ -n "$MAKEFILE_PATH" ]; then git add "$MAKEFILE_PATH"; fi
if [ -n "$CHART_PATH" ]; then git add "$CHART_PATH"; fi
git commit -m "chore: bump version to ${NEW_VERSION}"
git tag -a "v${NEW_VERSION}" -m "Release v${NEW_VERSION}"
if [ "${{ inputs.chart-only }}" = "true" ]; then
TAG="helm-chart-v${NEW_VERSION}"
else
TAG="v${NEW_VERSION}"
fi
git tag -a "$TAG" -m "Release $TAG"
git push origin "$DEFAULT_BRANCH" --follow-tags

- name: Create GitHub release
if: inputs.chart-only == false
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
with:
github-token: ${{ secrets.release-token }}
Expand Down
Loading
Loading