Skip to content

Chart - Release - Pipeline - 1 - Build Dev [8.9] #767

Chart - Release - Pipeline - 1 - Build Dev [8.9]

Chart - Release - Pipeline - 1 - Build Dev [8.9] #767

name: "Chart - Release - Pipeline - 1 - Build Dev"
run-name: >-
Chart - Release - Pipeline - 1 - Build Dev${{ inputs.chart-version != '' && format(' [{0}]', inputs.chart-version) || '' }}
# Builds immutable dev packages for all active chart versions.
# These packages are release-ready (transformations applied) and stored in Harbor
# with unique dev tags for testing. They can be promoted to RC/release by retagging.
#
# Tagging scheme:
# Dev: {version}-dev-{sha} (e.g., 13.4.0-dev-abc1234)
# Rolling: {chart-major}-dev-latest (e.g., 13-dev-latest)
#
# Chart.yaml version is the final release version (e.g., 13.4.0) computed via
# release-please dry-run, making the artifact truly release-ready.
#
# Registry: oci://registry.camunda.cloud/team-distribution/camunda-platform
# Note: Harbor is for internal storage/testing. Public releases go to
# GitHub Releases → helm.camunda.io → Artifact Hub
#
on:
push:
branches:
- main
paths:
- .github/workflows/chart-build-dev.yaml
- charts/camunda-platform-*/**
- "!charts/camunda-platform-*/test/**"
workflow_dispatch:
inputs:
chart-version:
description: |
Specific chart version to build (e.g., "8.8").
Leave empty to build all active versions.
required: false
type: string
orchestration-image-tag:
type: string
required: false
zeebe-image-tag:
type: string
required: false
zeebe-gateway-image-tag:
type: string
required: false
operate-image-tag:
type: string
required: false
tasklist-image-tag:
type: string
required: false
console-image-tag:
type: string
required: false
modeler-image-tag:
type: string
required: false
connectors-image-tag:
type: string
required: false
optimize-image-tag:
type: string
required: false
identity-image-tag:
type: string
required: false
concurrency:
group: ${{ github.workflow }}-${{ inputs.chart-version || 'push' }}
cancel-in-progress: false
env:
CHART_NAME: "camunda-platform"
HARBOR_REGISTRY_HOST: "registry.camunda.cloud"
HARBOR_REGISTRY_PROJECT: "team-distribution"
jobs:
setup:
name: Setup build matrix
runs-on: ubuntu-latest
outputs:
chart-matrix: ${{ steps.matrix.outputs.chart-matrix }}
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
- name: Configure curl and wget
uses: ./.github/actions/setup-curl
- name: Info - ℹ️ Print workflow inputs ℹ️
env:
GITHUB_CONTEXT: ${{ toJson(inputs) }}
run: |
if [[ -n "${INITIAL_CLAIM_VALUE}" ]]; then
echo "::add-mask::${INITIAL_CLAIM_VALUE}"
fi
echo "Workflow Inputs:"
echo "${GITHUB_CONTEXT}" | jq '."extra-values" = "<Check below>"'
echo "Workflow Inputs - Extra Values:"
echo "${GITHUB_CONTEXT}" | jq -r '."extra-values"'
- name: Get chart versions
id: chart-versions
uses: ./.github/actions/get-chart-versions
- name: Build chart matrix
id: matrix
run: |
# Use input version if provided, otherwise use all active versions
if [[ -n "${{ inputs.chart-version }}" ]]; then
versions="${{ inputs.chart-version }}"
else
versions="${{ steps.chart-versions.outputs.active }}"
fi
# Build matrix JSON as single line (required for GITHUB_OUTPUT)
matrix="["
first=true
for version in ${versions}; do
if [[ "${first}" != "true" ]]; then
matrix+=","
fi
first=false
matrix+="{\"name\":\"Helm Chart ${version}\",\"directory\":\"charts/camunda-platform-${version}\",\"version\":\"${version}\"}"
done
matrix+="]"
echo "chart-matrix=${matrix}" >> $GITHUB_OUTPUT
echo "Building charts: ${versions}"
build:
needs: setup
name: Build ${{ matrix.chart.version }}
permissions:
contents: read
id-token: write
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
chart: ${{ fromJson(needs.setup.outputs.chart-matrix) }}
defaults:
run:
shell: bash
working-directory: ${{ matrix.chart.directory }}
env:
CHART_RELEASER_CONFIG_FILE: ".github/config/chart-releaser.yaml"
CHART_DIR: "${{ matrix.chart.directory }}"
CHART_RELEASE_VERSION: "${{ matrix.chart.version }}"
CHART_RELEASE_PACKAGE_FILE: "camunda-platform-${{ matrix.chart.version }}.tgz"
CHART_RELEASE_COSIGN_BUNDLE_FILE: "camunda-platform-${{ matrix.chart.version }}-cosign-bundle.json"
CHART_RELEASE_COSIGN_VERIFY_FILE: "camunda-platform-${{ matrix.chart.version }}-cosign-verify.sh"
CHART_RELEASE_COSIGN_CERTIFICATE_IDENTITY: "https://github.com/${{ github.workflow_ref }}"
CHART_RELEASE_COSIGN_CERTIFICATE_OIDC_ISSUER: "https://token.actions.githubusercontent.com"
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
fetch-depth: 0
- name: Import Vault secrets
id: secrets
uses: hashicorp/vault-action@892a26828f195e65540a40b4768ae4571f51ebfc # v4.0.0
with:
url: ${{ secrets.VAULT_ADDR }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
secrets: |
secret/data/products/distribution/ci HARBOR_REGISTRY_USER;
secret/data/products/distribution/ci HARBOR_REGISTRY_PASSWORD;
exportEnv: true
- name: Install tools
uses: ./.github/actions/install-tool-versions
with:
tools: |
git-cliff
golang
gomplate
helm
oras
yq
- name: Install Cosign
uses: sigstore/cosign-installer@6f9f17788090df1f26f669e9d70d6ae9567deba6 # v4.1.2
- name: Build values-injector
env:
CONSOLE_IMAGE_TAG: ${{ inputs.console-image-tag }}
CONNECTORS_IMAGE_TAG: ${{ inputs.connectors-image-tag }}
IDENTITY_IMAGE_TAG: ${{ inputs.identity-image-tag }}
WEB_MODELER_IMAGE_TAG: ${{ inputs.modeler-image-tag }}
OPTIMIZE_IMAGE_TAG: ${{ inputs.optimize-image-tag }}
ORCHESTRATION_IMAGE_TAG: ${{ inputs.orchestration-image-tag }}
ZEEBE_IMAGE_TAG: ${{ inputs.zeebe-image-tag }}
ZEEBE_GATEWAY_IMAGE_TAG: ${{ inputs.zeebe-gateway-image-tag }}
OPERATE_IMAGE_TAG: ${{ inputs.operate-image-tag }}
TASKLIST_IMAGE_TAG: ${{ inputs.tasklist-image-tag }}
CHART_VERSION: ${{ matrix.chart.version }}
run: |
cd $(git rev-parse --show-toplevel)
cd scripts/values-injector
go build
cd $(git rev-parse --show-toplevel)
./scripts/values-injector/values-injector
- name: Login to Harbor registry
run: |
source "${GITHUB_WORKSPACE}/scripts/harbor-retry.sh"
harbor_login
- name: Set version vars
id: vars
run: |
# Version vars will be set after release-please computes the release version
# For now, just set the short SHA and Camunda version
SHORT_SHA="${GITHUB_SHA::7}"
CAMUNDA_VERSION="${{ matrix.chart.version }}"
echo "SHORT_SHA=${SHORT_SHA}" | tee -a $GITHUB_ENV
echo "CAMUNDA_VERSION=${CAMUNDA_VERSION}" | tee -a $GITHUB_ENV
#
# Compute release version using release-please dry-run
# This ensures the packaged Chart.yaml has the correct version and changelog
# annotations that release-please would compute at release time.
#
- name: Install release-please CLI
run: npm install -g release-please
- name: Compute release version (release-please dry-run)
id: release-please
env:
RELEASE_PLEASE_CONFIG: .github/config/release-please/release-please-config.json
RELEASE_PLEASE_MANIFEST: .github/config/release-please/.release-please-manifest.json
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
# Get current version from Chart.yaml to check if it's a prerelease
CURRENT_VERSION=$(yq '.version' Chart.yaml)
echo "Current version: ${CURRENT_VERSION}"
# Check if current version is a prerelease (alpha, beta, rc)
IS_PRERELEASE=false
if [[ "${CURRENT_VERSION}" =~ -(alpha|beta|rc)([0-9]+)$ ]]; then
PRERELEASE_TYPE="${BASH_REMATCH[1]}"
PRERELEASE_NUM="${BASH_REMATCH[2]}"
BASE_VERSION="${CURRENT_VERSION%%-*}"
# Cross-reference chart-versions.yaml to detect alpha-to-stable transition.
# If Chart.yaml has an alpha suffix but the chart is no longer listed under
# alpha in chart-versions.yaml, this is the first stable release: strip the
# prerelease suffix instead of incrementing it.
CHART_VERSIONS_FILE="$(git rev-parse --show-toplevel)/charts/chart-versions.yaml"
IS_STILL_ALPHA=$(yq ".camundaVersions.alpha[] | select(. == \"${{ matrix.chart.version }}\")" "${CHART_VERSIONS_FILE}")
if [[ -n "${IS_STILL_ALPHA}" ]]; then
IS_PRERELEASE=true
NEXT_PRERELEASE_NUM=$((PRERELEASE_NUM + 1))
RELEASE_VERSION="${BASE_VERSION}-${PRERELEASE_TYPE}${NEXT_PRERELEASE_NUM}"
echo "Prerelease detected: ${PRERELEASE_TYPE}${PRERELEASE_NUM} -> ${PRERELEASE_TYPE}${NEXT_PRERELEASE_NUM}"
else
RELEASE_VERSION="${BASE_VERSION}"
echo "Alpha-to-stable transition detected: ${CURRENT_VERSION} -> ${RELEASE_VERSION}"
fi
echo "RELEASE_VERSION=${RELEASE_VERSION}" | tee -a $GITHUB_ENV
echo "IS_PRERELEASE=${IS_PRERELEASE}" >> $GITHUB_ENV
RELEASE_VERSION_COMPUTED=true
echo "RELEASE_VERSION_COMPUTED=true" >> $GITHUB_ENV
echo "::notice::Computed version: ${RELEASE_VERSION}"
fi
# Run release-please dry-run to get changelog annotations
cd ../..
release-please release-pr \
--token="${GITHUB_TOKEN}" \
--repo-url="${{ github.repository }}" \
--target-branch="main" \
--path="${{ matrix.chart.directory }}" \
--config-file="${RELEASE_PLEASE_CONFIG}" \
--manifest-file="${RELEASE_PLEASE_MANIFEST}" \
--dry-run \
--trace 2>&1 | tee ${{ matrix.chart.directory }}/release-please-trace.log
cd ${{ matrix.chart.directory }}
# For stable releases (not alpha-to-stable transition), extract version from release-please output
if [[ "${IS_PRERELEASE}" != "true" && "${RELEASE_VERSION_COMPUTED}" != "true" ]]; then
RELEASE_VERSION=$(grep -A5 "^+.*version:" release-please-trace.log | head -1 | sed 's/^+.*version:\s*//' || echo "")
if [[ -z "${RELEASE_VERSION}" ]]; then
RELEASE_VERSION=$(grep -oP '"\Q${{ matrix.chart.directory }}\E":\s*"\K[^"]+' release-please-trace.log || echo "")
fi
if [[ -z "${RELEASE_VERSION}" ]]; then
echo "::warning::Could not determine release version from release-please dry-run"
echo "RELEASE_VERSION_COMPUTED=false" >> $GITHUB_ENV
else
echo "RELEASE_VERSION=${RELEASE_VERSION}" | tee -a $GITHUB_ENV
echo "RELEASE_VERSION_COMPUTED=true" >> $GITHUB_ENV
echo "::notice::Computed release version: ${RELEASE_VERSION}"
fi
fi
# Set dev tag version: {release-version}-dev-{sha}
if [[ "${RELEASE_VERSION_COMPUTED}" == "true" || -n "${RELEASE_VERSION}" ]]; then
DEV_TAG="${RELEASE_VERSION}-dev-${SHORT_SHA}"
else
# Fallback to current version if release-please couldn't compute
DEV_TAG="${CURRENT_VERSION}-dev-${SHORT_SHA}"
RELEASE_VERSION="${CURRENT_VERSION}"
echo "RELEASE_VERSION=${RELEASE_VERSION}" | tee -a $GITHUB_ENV
fi
echo "DEV_TAG=${DEV_TAG}" | tee -a $GITHUB_ENV
# Extract chart major version for rolling tag (e.g., 13.4.0 -> 13)
CHART_MAJOR_VERSION="${RELEASE_VERSION%%.*}"
echo "CHART_MAJOR_VERSION=${CHART_MAJOR_VERSION}" | tee -a $GITHUB_ENV
echo "::notice::Dev tag: ${DEV_TAG}, Rolling tag: ${CHART_MAJOR_VERSION}-dev-latest"
- name: Check for image override inputs
id: check-overrides
run: |
# Detect if any image override inputs were provided via workflow_dispatch
# When overrides are present, we must rebuild even if artifact exists
HAS_IMAGE_OVERRIDES=false
OVERRIDES_YAML=""
declare -A OVERRIDE_INPUTS=(
["orchestration"]="${{ inputs.orchestration-image-tag }}"
["zeebe"]="${{ inputs.zeebe-image-tag }}"
["zeebe-gateway"]="${{ inputs.zeebe-gateway-image-tag }}"
["operate"]="${{ inputs.operate-image-tag }}"
["tasklist"]="${{ inputs.tasklist-image-tag }}"
["console"]="${{ inputs.console-image-tag }}"
["modeler"]="${{ inputs.modeler-image-tag }}"
["connectors"]="${{ inputs.connectors-image-tag }}"
["optimize"]="${{ inputs.optimize-image-tag }}"
["identity"]="${{ inputs.identity-image-tag }}"
)
for key in "${!OVERRIDE_INPUTS[@]}"; do
value="${OVERRIDE_INPUTS[$key]}"
if [[ -n "${value}" ]]; then
HAS_IMAGE_OVERRIDES=true
OVERRIDES_YAML+="${key}: ${value}\n"
fi
done
echo "HAS_IMAGE_OVERRIDES=${HAS_IMAGE_OVERRIDES}" | tee -a $GITHUB_ENV
if [[ "${HAS_IMAGE_OVERRIDES}" == "true" ]]; then
echo -e "${OVERRIDES_YAML}" > /tmp/image-overrides.yaml
echo "::notice::Image override inputs detected - will force rebuild if artifact exists"
echo "Overrides:"
cat /tmp/image-overrides.yaml
fi
- name: Check if artifact already exists
id: check-artifact
run: |
source "${GITHUB_WORKSPACE}/scripts/harbor-retry.sh"
# Dev packages are immutable - skip if already exists
# Exception: when image overrides are provided, delete and rebuild
OCI_REGISTRY="${HARBOR_REGISTRY_HOST}/${HARBOR_REGISTRY_PROJECT}"
# Retry helm pull with re-auth to avoid misinterpreting transient 401 as "not found"
# harbor_helm_pull returns: 0=found, 1=not-found/other non-auth error, 2=persistent auth failure
PULL_RC=0
harbor_helm_pull "oci://${OCI_REGISTRY}/${{ env.CHART_NAME }}" \
--version "${DEV_TAG}" --destination /tmp || PULL_RC=$?
if [[ ${PULL_RC} -eq 2 ]]; then
echo "::error::Harbor auth failure checking artifact existence"
exit 1
fi
if [[ ${PULL_RC} -eq 0 ]]; then
if [[ "${HAS_IMAGE_OVERRIDES}" == "true" ]]; then
# Image overrides provided - delete existing artifact to allow rebuild
echo "::notice::Dev package ${DEV_TAG} exists but image overrides provided - deleting to rebuild"
harbor_curl \
-X DELETE "https://${HARBOR_REGISTRY_HOST}/api/v2.0/projects/${HARBOR_REGISTRY_PROJECT}/repositories/${{ env.CHART_NAME }}/artifacts/${DEV_TAG}/tags/${DEV_TAG}" || true
echo "SKIP_BUILD=false" | tee -a $GITHUB_ENV
else
echo "SKIP_BUILD=true" | tee -a $GITHUB_ENV
echo "::notice::Dev package ${DEV_TAG} already exists, skipping build"
fi
else
echo "SKIP_BUILD=false" | tee -a $GITHUB_ENV
fi
- name: Apply Chart.yaml version and changelog from release-please
if: env.SKIP_BUILD == 'false' && env.RELEASE_VERSION_COMPUTED == 'true'
run: |
# Extract the Chart.yaml diff from trace output and apply it
# The trace contains unified diff format for each file
echo "Applying release-please computed changes to Chart.yaml..."
echo "Release version: ${RELEASE_VERSION}"
# Update the version field
yq -i ".version = \"${RELEASE_VERSION}\"" Chart.yaml
# Remove prerelease annotation for stable releases.
# During alpha-to-stable transitions the source Chart.yaml may still
# carry artifacthub.io/prerelease: "true". Strip it so Artifact Hub
# does not label the GA chart as a pre-release.
if [[ "${IS_PRERELEASE}" != "true" ]]; then
yq -i 'del(.annotations."artifacthub.io/prerelease")' Chart.yaml
echo "Removed artifacthub.io/prerelease annotation (stable release)"
fi
# Extract and apply the artifacthub.io/changes annotation from trace
# The trace output contains the full YAML block for the annotation
# Parse the changelog entries from trace output
# Look for lines between artifacthub.io/changes and the next annotation or end of annotations
CHANGELOG_YAML=$(awk '
/^\+.*artifacthub.io\/changes:/ { capture=1; next }
capture && /^\+/ {
line=$0
sub(/^\+[ ]*/, "", line)
print line
}
capture && !/^\+/ { capture=0 }
' release-please-trace.log)
if [[ -n "${CHANGELOG_YAML}" ]]; then
echo "Extracted changelog annotations:"
echo "${CHANGELOG_YAML}"
# Create a temp file with the changelog YAML
echo "${CHANGELOG_YAML}" > /tmp/changelog.yaml
# Update the annotation in Chart.yaml
yq -i '.annotations."artifacthub.io/changes" = load_str("/tmp/changelog.yaml")' Chart.yaml
echo "Applied artifacthub.io/changes annotations"
else
echo "::warning::Could not extract changelog annotations from trace output"
fi
echo "Updated Chart.yaml:"
head -50 Chart.yaml
- name: Add component image versions to Chart.yaml annotations
if: env.SKIP_BUILD == 'false'
run: |
# Extract image tags from values.yaml and add as Chart.yaml annotation
# This makes the artifact self-documenting with exact component versions
get_tag() {
local path=$1
yq -r "${path} // \"N/A\"" values.yaml
}
# Version-specific components (order matches workflow summary)
CAMUNDA_MINOR=$(echo "${{ env.CAMUNDA_VERSION }}" | sed 's/^8\.//')
if [[ ${CAMUNDA_MINOR} -ge 8 ]]; then
# 8.8+ orchestration architecture
IMAGE_VERSIONS=$(cat << YAML
camunda: $(get_tag '.orchestration.image.tag')
managementIdentity: $(get_tag '.identity.image.tag')
optimize: $(get_tag '.optimize.image.tag')
webModeler: $(get_tag '.webModeler.image.tag')
connectors: $(get_tag '.connectors.image.tag')
console: $(get_tag '.console.image.tag')
YAML
)
else
# 8.6-8.7 classic architecture
IMAGE_VERSIONS=$(cat << YAML
zeebe: $(get_tag '.zeebe.image.tag')
operate: $(get_tag '.operate.image.tag')
tasklist: $(get_tag '.tasklist.image.tag')
identity: $(get_tag '.identity.image.tag')
optimize: $(get_tag '.optimize.image.tag')
webModeler: $(get_tag '.webModeler.image.tag')
connectors: $(get_tag '.connectors.image.tag')
console: $(get_tag '.console.image.tag')
YAML
)
fi
# Write to temp file and add annotation
echo "${IMAGE_VERSIONS}" > /tmp/image-versions.yaml
yq -i '.annotations."camunda.io/component-image-versions" = load_str("/tmp/image-versions.yaml")' Chart.yaml
echo "Added camunda.io/component-image-versions annotation:"
yq '.annotations."camunda.io/component-image-versions"' Chart.yaml
- name: Add image overrides annotation to Chart.yaml
if: env.SKIP_BUILD == 'false' && env.HAS_IMAGE_OVERRIDES == 'true'
run: |
# Document which images were manually overridden via workflow_dispatch
# This indicates the artifact cannot be traced to a standard commit's image set
yq -i '.annotations."camunda.io/imageOverrides" = load_str("/tmp/image-overrides.yaml")' Chart.yaml
echo "Added camunda.io/imageOverrides annotation:"
yq '.annotations."camunda.io/imageOverrides"' Chart.yaml
- name: Show computed version info
if: env.SKIP_BUILD == 'false'
run: |
echo "### Version Information"
echo "- Release Version (in Chart.yaml): ${RELEASE_VERSION}"
echo "- Dev Tag: ${DEV_TAG}"
echo "- Rolling Tag: ${CHART_MAJOR_VERSION}-dev-latest"
#
# Apply release transformations (makes artifact release-ready)
#
- name: Remove dev comments
if: env.SKIP_BUILD == 'false'
run: |
target_files=(
values*.yaml
Chart.yaml
)
for target_file in "${target_files[@]}"; do
if [[ -f "${target_file}" ]]; then
sed -i '/# START DEV COMMENT/,/# END DEV COMMENT/d' "${target_file}"
fi
done
echo "Dev comments removed"
- name: Remove badges from README
if: env.SKIP_BUILD == 'false'
run: |
# Clean up badges from readme to avoid showing them in Artifact Hub
sed -ri '/Badge .+/d' "README.md"
echo "Badges removed from README"
- name: Show transformations
if: env.SKIP_BUILD == 'false'
run: |
echo "Applied release transformations:"
git --no-pager diff --stat
- name: Add Helm repos
if: env.SKIP_BUILD == 'false'
run: |
make -C ../.. helm.repos-add
- name: Helm dependency update
if: env.SKIP_BUILD == 'false'
run: |
make -C ../.. helm.dependency-update \
chartPath=${{ matrix.chart.directory }}
#
# Generate release notes
#
- name: Generate RELEASE-NOTES.md
if: env.SKIP_BUILD == 'false'
working-directory: ${{ github.workspace }}
run: |
set -euo pipefail
# Generate release notes using the same script as the release process
bash scripts/generate-release-notes.sh --main ${{ matrix.chart.directory }}
bash scripts/generate-release-notes.sh --footer ${{ matrix.chart.directory }}
# Verify release notes contain actual version matrix content
if ! grep -q "Camunda images:" "${{ matrix.chart.directory }}/RELEASE-NOTES.md"; then
echo "::error::RELEASE-NOTES.md is missing version matrix content - generation failed"
cat ${{ matrix.chart.directory }}/RELEASE-NOTES.md
exit 1
fi
echo "Generated RELEASE-NOTES.md:"
cat ${{ matrix.chart.directory }}/RELEASE-NOTES.md
#
# Package and publish
#
- name: Package Helm chart
if: env.SKIP_BUILD == 'false'
run: |
helm version
# Package WITHOUT --version flag to preserve Chart.yaml version (release version)
# The Chart.yaml already contains the correct release version (e.g., 11.11.3)
helm-cr package ./ --config ../../${{ env.CHART_RELEASER_CONFIG_FILE }}
# The package filename will be based on Chart.yaml version
PACKAGED_FILE=$(ls .cr-release-packages/${{ env.CHART_NAME }}-*.tgz)
echo "Packaged: ${PACKAGED_FILE}"
# Verify Chart.yaml inside has the release version
echo "Verifying packaged Chart.yaml version:"
tar -xzf "${PACKAGED_FILE}" -O ${{ env.CHART_NAME }}/Chart.yaml | grep "^version:"
# Store the package filename for later steps
echo "HELM_PACKAGE=${PACKAGED_FILE}" >> $GITHUB_ENV
- name: Push Helm chart to Harbor
if: env.SKIP_BUILD == 'false'
env:
CR_TOKEN: '${{ secrets.GITHUB_TOKEN }}'
run: |
source "${GITHUB_WORKSPACE}/scripts/harbor-retry.sh"
OCI_REGISTRY="${HARBOR_REGISTRY_HOST}/${HARBOR_REGISTRY_PROJECT}"
# helm push creates OCI tag from Chart.yaml version (the release version)
# We need to retag to our dev tag and add rolling tag
# helm push with retry and re-auth (most common 401 failure point)
harbor_retry "helm push" helm push "${HELM_PACKAGE}" "oci://${OCI_REGISTRY}"
cosign sign-blob -y ${HELM_PACKAGE} \
--bundle ".cr-release-packages/${{ env.CHART_RELEASE_COSIGN_BUNDLE_FILE }}"
CHART_RELEASE_TAG_NAME="camunda-platform-${{ matrix.chart.version }}-${RELEASE_VERSION}"
echo "CHART_RELEASE_TAG_NAME=camunda-platform-${{ matrix.chart.version }}-${RELEASE_VERSION}" >> $GITHUB_ENV
cat .cr-release-packages/${{ env.CHART_RELEASE_COSIGN_BUNDLE_FILE }} | jq
rekor_log_index="$(cat .cr-release-packages/${{ env.CHART_RELEASE_COSIGN_BUNDLE_FILE }} | jq '.rekorBundle.Payload.logIndex')"
echo "CHART_RELEASE_COSIGN_REKOR_LOG_INDEX=${rekor_log_index}" >> $GITHUB_ENV
cat << EOF > ${{ env.CHART_RELEASE_COSIGN_VERIFY_FILE }}
# Rekor.
echo "Rekor record:"
echo "https://search.sigstore.dev/?logIndex=${rekor_log_index}"
# Cosign.
cosign verify-blob ${HELM_PACKAGE} \\
--bundle ".cr-release-packages/${{ env.CHART_RELEASE_COSIGN_BUNDLE_FILE }}" \\
--certificate-identity "${{ env.CHART_RELEASE_COSIGN_CERTIFICATE_IDENTITY }}" \\
--certificate-oidc-issuer "${{ env.CHART_RELEASE_COSIGN_CERTIFICATE_OIDC_ISSUER }}"
EOF
COSIGN_VERIFIED="$(
cosign verify-blob ${HELM_PACKAGE} \
--bundle ".cr-release-packages/${{ env.CHART_RELEASE_COSIGN_BUNDLE_FILE }}" \
--certificate-identity "${{ env.CHART_RELEASE_COSIGN_CERTIFICATE_IDENTITY }}" \
--certificate-oidc-issuer "${{ env.CHART_RELEASE_COSIGN_CERTIFICATE_OIDC_ISSUER }}" 2>&1
)"
echo COSIGN_VERIFIED="${COSIGN_VERIFIED}" >> $GITHUB_ENV
COSIGN_METADATA="$(cat .cr-release-packages/${{ env.CHART_RELEASE_COSIGN_BUNDLE_FILE }} | jq .verificationMaterial.certificate.rawBytes | sed 's/"//g' | base64 -d | openssl x509 -noout -text - )"
# funkiness to preserve newlines
{
echo "COSIGN_METADATA<<EOF"
echo "$COSIGN_METADATA"
echo "EOF"
} >> "$GITHUB_ENV"
# oras push with retry and re-auth
harbor_retry "oras push" \
oras push ${OCI_REGISTRY}/${{ env.CHART_NAME }} .cr-release-packages/${{ env.CHART_RELEASE_COSIGN_BUNDLE_FILE }}
# The helm push created a tag with the release version
PUSHED_TAG="${RELEASE_VERSION}"
echo "Pushed with tag: ${PUSHED_TAG}"
# Get the digest for API operations
DIGEST=$(helm pull "oci://${OCI_REGISTRY}/${{ env.CHART_NAME }}" --version "${PUSHED_TAG}" 2>&1 | grep -oP 'Digest: \K[^\s]+' || \
harbor_curl "https://${HARBOR_REGISTRY_HOST}/api/v2.0/projects/${HARBOR_REGISTRY_PROJECT}/repositories/${{ env.CHART_NAME }}/artifacts/${PUSHED_TAG}" | jq -r '.digest')
echo "Artifact digest: ${DIGEST}"
# Harbor API base URL for this artifact
HARBOR_API="https://${HARBOR_REGISTRY_HOST}/api/v2.0/projects/${HARBOR_REGISTRY_PROJECT}/repositories/${{ env.CHART_NAME }}/artifacts/${DIGEST}/tags"
# Add dev tag: {version}-dev-{sha}
echo "Adding dev tag: ${DEV_TAG}"
harbor_curl -X POST "${HARBOR_API}" \
-H "Content-Type: application/json" \
-d "{\"name\": \"${DEV_TAG}\"}"
# Delete the release version tag (we only want dev tag for now)
echo "Removing release version tag: ${PUSHED_TAG}"
harbor_curl -X DELETE "${HARBOR_API}/${PUSHED_TAG}"
# Add rolling tag: {chart-major}-dev-latest
ROLLING_TAG="${CHART_MAJOR_VERSION}-dev-latest"
echo "Removing existing rolling tag if present: ${ROLLING_TAG}"
harbor_curl \
-X DELETE "https://${HARBOR_REGISTRY_HOST}/api/v2.0/projects/${HARBOR_REGISTRY_PROJECT}/repositories/${{ env.CHART_NAME }}/artifacts/${ROLLING_TAG}/tags/${ROLLING_TAG}" || true
echo "Adding rolling tag: ${ROLLING_TAG}"
harbor_curl -X POST "${HARBOR_API}" \
-H "Content-Type: application/json" \
-d "{\"name\": \"${ROLLING_TAG}\"}"
echo "::notice::Pushed to Harbor with tags: ${DEV_TAG}, ${ROLLING_TAG}"
#
# Summary
#
- name: Add build info to workflow summary
run: |
# Extract key Camunda component versions from values.yaml
# Component structure changed in 8.8:
# - 8.6, 8.7: zeebe, operate, tasklist, identity (separate images)
# - 8.8+: orchestration (single camunda image) + management identity
# Use yq to extract image tags reliably
get_tag() {
local path=$1
yq -r "${path} // \"N/A\"" values.yaml
}
# Components that exist in all versions
IMAGE_CONSOLE=$(get_tag '.console.image.tag')
IMAGE_CONNECTORS=$(get_tag '.connectors.image.tag')
IMAGE_OPTIMIZE=$(get_tag '.optimize.image.tag')
IMAGE_WEBMODELER=$(get_tag '.webModeler.image.tag')
# Version-specific components
CAMUNDA_MINOR=$(echo "${{ env.CAMUNDA_VERSION }}" | sed 's/^8\.//')
if [[ ${CAMUNDA_MINOR} -ge 8 ]]; then
CHART_ARCHITECTURE="orchestration"
IMAGE_CAMUNDA=$(get_tag '.orchestration.image.tag')
IMAGE_MGMT_IDENTITY=$(get_tag '.identity.image.tag')
else
CHART_ARCHITECTURE="classic"
IMAGE_ZEEBE=$(get_tag '.zeebe.image.tag')
IMAGE_OPERATE=$(get_tag '.operate.image.tag')
IMAGE_TASKLIST=$(get_tag '.tasklist.image.tag')
IMAGE_IDENTITY=$(get_tag '.identity.image.tag')
fi
# Set up registry URL for summary
OCI_REGISTRY="${HARBOR_REGISTRY_HOST}/${HARBOR_REGISTRY_PROJECT}"
ROLLING_TAG="${CHART_MAJOR_VERSION}-dev-latest"
if [[ "${{ env.SKIP_BUILD }}" == "true" ]]; then
cat << EOF >> $GITHUB_STEP_SUMMARY
## 📦 Chart Build Skipped (Camunda ${{ env.CAMUNDA_VERSION }})
Dev package already exists for this commit.
- **Dev Tag:** \`${DEV_TAG}\`
- **Camunda Version:** \`${{ env.CAMUNDA_VERSION }}\`
EOF
else
# Build summary based on architecture
if [[ "${CHART_ARCHITECTURE}" == "orchestration" ]]; then
# 8.8+ with orchestration cluster (single camunda image)
cat << EOF >> $GITHUB_STEP_SUMMARY
## 📦 Dev Package Built ✅ (Camunda ${{ env.CAMUNDA_VERSION }})
### Package Info
| Property | Value |
|----------|-------|
| **Registry** | \`oci://${OCI_REGISTRY}\` |
| **Chart** | \`${{ env.CHART_NAME }}\` |
| **Dev Tag** | \`${DEV_TAG}\` |
| **Rolling Tag** | \`${ROLLING_TAG}\` |
| **Release Version (in Chart.yaml)** | \`${RELEASE_VERSION}\` |
| **Camunda Version** | \`${{ env.CAMUNDA_VERSION }}\` |
| **Commit** | [${{ env.SHORT_SHA }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}) |
### 🐳 Image Versions (from values.yaml)
| Component | Version |
|-----------|---------|
| Camunda (Zeebe/Operate/Tasklist/Orch. Identity) | \`${IMAGE_CAMUNDA}\` |
| Management Identity | \`${IMAGE_MGMT_IDENTITY}\` |
| Optimize | \`${IMAGE_OPTIMIZE}\` |
| Web Modeler | \`${IMAGE_WEBMODELER}\` |
| Connectors | \`${IMAGE_CONNECTORS}\` |
| Console | \`${IMAGE_CONSOLE}\` |
> **Note:** Compare these versions with the release train announcement to verify this dev package has the correct versions for release.
### Install (requires Harbor access)
\`\`\`bash
helm registry login ${HARBOR_REGISTRY_HOST}
helm install my-camunda-dev \\
oci://${OCI_REGISTRY}/${{ env.CHART_NAME }} \\
--version ${DEV_TAG}
\`\`\`
### Cosign verified
Verification status: ${COSIGN_VERIFIED}
<details>
<summary>View Cosign metadata</summary>
\`\`\`bash
$(echo "${COSIGN_METADATA}")
\`\`\`
</details>
EOF
else
# 8.6, 8.7 with separate component images
cat << EOF >> $GITHUB_STEP_SUMMARY
## 📦 Dev Package Built ✅ (Camunda ${{ env.CAMUNDA_VERSION }})
### Package Info
| Property | Value |
|----------|-------|
| **Registry** | \`oci://${OCI_REGISTRY}\` |
| **Chart** | \`${{ env.CHART_NAME }}\` |
| **Dev Tag** | \`${DEV_TAG}\` |
| **Rolling Tag** | \`${ROLLING_TAG}\` |
| **Release Version (in Chart.yaml)** | \`${RELEASE_VERSION}\` |
| **Camunda Version** | \`${{ env.CAMUNDA_VERSION }}\` |
| **Commit** | [${{ env.SHORT_SHA }}](${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}) |
### 🐳 Image Versions (from values.yaml)
| Component | Version |
|-----------|---------|
| Zeebe | \`${IMAGE_ZEEBE}\` |
| Operate | \`${IMAGE_OPERATE}\` |
| Tasklist | \`${IMAGE_TASKLIST}\` |
| Identity | \`${IMAGE_IDENTITY}\` |
| Optimize | \`${IMAGE_OPTIMIZE}\` |
| Web Modeler | \`${IMAGE_WEBMODELER}\` |
| Connectors | \`${IMAGE_CONNECTORS}\` |
| Console | \`${IMAGE_CONSOLE}\` |
> **Note:** Compare these versions with the release train announcement to verify this dev package has the correct versions for release.
### Install (requires Harbor access)
\`\`\`bash
helm registry login ${HARBOR_REGISTRY_HOST}
helm install my-camunda-dev \\
oci://${OCI_REGISTRY}/${{ env.CHART_NAME }} \\
--version ${DEV_TAG}
\`\`\`
### Cosign verified
Verification status: ${COSIGN_VERIFIED}
<details>
<summary>View Cosign metadata</summary>
\`\`\`bash
$(echo "${COSIGN_METADATA}")
\`\`\`
</details>
EOF
fi
fi
notify-on-failure:
name: Notify on Failure
needs: [setup, build]
if: failure()
runs-on: ubuntu-latest
steps:
- name: Import Vault secrets
id: secrets
uses: hashicorp/vault-action@892a26828f195e65540a40b4768ae4571f51ebfc # v4.0.0
with:
url: ${{ secrets.VAULT_ADDR }}
method: approle
roleId: ${{ secrets.VAULT_ROLE_ID }}
secretId: ${{ secrets.VAULT_SECRET_ID }}
secrets: |
secret/data/products/distribution/ci SLACK_DISTRO_BOT_WEBHOOK;
exportEnv: false
- name: Send Slack notification
continue-on-error: true
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
with:
webhook: ${{ steps.secrets.outputs.SLACK_DISTRO_BOT_WEBHOOK }}
webhook-type: incoming-webhook
payload: |
blocks:
- type: header
text:
type: plain_text
text: "Chart Dev Build Failed"
emoji: true
- type: section
text:
type: mrkdwn
text: |
<!subteam^S05K9BK6RTK> :rotating_light:
The *Chart Dev Build* pipeline has failed.
*Chart version:* ${{ inputs.chart-version || 'all active versions' }}
*Trigger:* ${{ github.event_name }}
<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View failed workflow>