Skip to content

vp-patterns/publish-charts #195

vp-patterns/publish-charts

vp-patterns/publish-charts #195

# This workflow is expected to be run by the git workflow of the remote
# chart whenever a new target is pushed:
# gh workflow run publish-charts.yml --repo mbaldessari/charts-test --ref main \
# -f SOURCE_TAG="v0.0.1" -f SOURCE_REPO="mbaldessari/helm-chart-test"
name: vp-patterns/publish-charts
on:
workflow_dispatch:
inputs:
SOURCE_TAG:
required: true
description: The tag of the helm chart repo to build
SOURCE_REPO:
required: true
description: The helm chart repo
SOURCE_BRANCH_OVERRIDE:
required: false
description: If specified, checks out the head of this branch rather than the commit tagged by SOURCE_TAG
default: ""
TEMPLATE_DIR:
required: false
description: Directory containing the helm chart (relative to repo root). If not specified, will auto-detect Chart.yaml location
default: ""
ADDITIONAL_HELM_REPOS:
required: false
description: Additional helm repositories to add (JSON format, e.g. '[{"name":"myrepo","url":"https://example.com/charts"}]')
default: ""
env:
SOURCE_TAG: "${{ inputs.SOURCE_TAG }}"
SOURCE_REPO: "${{ inputs.SOURCE_REPO }}"
SOURCE_BRANCH_OVERRIDE: "${{ inputs.SOURCE_BRANCH_OVERRIDE }}"
TEMPLATE_DIR: "${{ inputs.TEMPLATE_DIR }}"
ADDITIONAL_HELM_REPOS: "${{ inputs.ADDITIONAL_HELM_REPOS }}"
UMBRELLA_REPO: "validatedpatterns/helm-charts"
ASSETS_BASE_URL: "https://github.com/validatedpatterns/helm-charts/releases/download/main/"
LEGACY_QUAY_BASE_URL: "oci://quay.io/hybridcloudpatterns"
QUAY_BASE_URL: "oci://quay.io/validatedpatterns"
jobs:
update-charts:
if: ${{ inputs.SOURCE_TAG }}
runs-on: ubuntu-latest
permissions: write-all
steps:
- name: Install Helm
uses: azure/setup-helm@v4
with:
version: v3.12.1
- name: Clone remote helm repo
env:
SOURCE_BRANCH_OVERRIDE: ${{ inputs.SOURCE_BRANCH_OVERRIDE }}
run: |-
set -e
if [ -n "${SOURCE_BRANCH_OVERRIDE}" ]; then
git clone "https://github.com/${SOURCE_REPO}.git" \
--branch "${SOURCE_BRANCH_OVERRIDE}" --single-branch helm-repo
else
git clone "https://github.com/${SOURCE_REPO}.git" \
--branch "${SOURCE_TAG}" --single-branch helm-repo
fi
- name: Handle chart dependencies
shell: bash
env:
TEMPLATE_DIR: ${{ env.TEMPLATE_DIR }}
ADDITIONAL_HELM_REPOS: ${{ env.ADDITIONAL_HELM_REPOS }}
run: |-
set -euo pipefail
cd helm-repo
# Determine the chart directory - check if TEMPLATE_DIR is provided or use default
if [ -n "${TEMPLATE_DIR}" ]; then
CHART_DIR="${TEMPLATE_DIR}"
else
# If no TEMPLATE_DIR specified, look for Chart.yaml in common locations
if [ -f "Chart.yaml" ]; then
CHART_DIR="."
elif [ -f "chart/Chart.yaml" ]; then
CHART_DIR="chart"
elif [ -f "helm/Chart.yaml" ]; then
CHART_DIR="helm"
else
echo "Could not find Chart.yaml file. Please specify TEMPLATE_DIR input."
exit 1
fi
fi
cd "${CHART_DIR}"
# Check if Chart.yaml exists and has dependencies
if [ -f "Chart.yaml" ]; then
echo "Found Chart.yaml in ${CHART_DIR}"
cat Chart.yaml
# Check if dependencies section exists in Chart.yaml
if yq -e '.dependencies' Chart.yaml > /dev/null 2>&1; then
echo "Dependencies found in Chart.yaml. Processing dependencies..."
# Create a temporary file to track if repositories were added
repo_added_flag=$(mktemp)
echo "false" > "$repo_added_flag"
# Extract repository URLs from dependencies and add them as helm repositories
echo "Discovering repositories from Chart.yaml dependencies..."
yq -r '.dependencies[]? | select(.repository) | .repository' Chart.yaml | sort -u | while read -r repo_url; do
if [ -n "$repo_url" ] && [[ "$repo_url" == http* ]]; then
# Convert URL to repository name by removing protocol and common prefixes
repo_name=$(echo "$repo_url" | sed 's|^https\?://||' | sed 's|^www\.||' | sed 's|/$||')
echo "Adding repository: $repo_name -> $repo_url"
if helm repo add "$repo_name" "$repo_url"; then
echo "true" > "$repo_added_flag"
else
echo "Failed to add repository $repo_name, continuing..."
fi
fi
done
# Add additional helm repositories if specified
if [ -n "${ADDITIONAL_HELM_REPOS}" ] && [ "${ADDITIONAL_HELM_REPOS}" != "[]" ] && [ "${ADDITIONAL_HELM_REPOS}" != "" ]; then
echo "Adding additional helm repositories..."
echo "${ADDITIONAL_HELM_REPOS}" | yq -r '.[] | "helm repo add " + .name + " " + .url' | while read -r cmd; do
echo "Running: $cmd"
if eval "$cmd"; then
echo "true" > "$repo_added_flag"
else
echo "Failed to add repository, continuing..."
fi
done
fi
# Update repositories only if any were added
repos_added=$(cat "$repo_added_flag")
rm -f "$repo_added_flag"
if [ "$repos_added" = "true" ]; then
echo "Updating helm repositories..."
helm repo update
else
echo "No repositories were added, skipping helm repo update"
fi
# Check if dependencies are already present
update_needed=false
if [ -d "charts" ]; then
echo "Charts directory exists, checking for missing dependencies..."
# Get list of required dependencies from Chart.yaml
required_deps=$(yq -r '.dependencies[]? | .name + "-" + .version' Chart.yaml 2>/dev/null || true)
if [ -n "$required_deps" ]; then
echo "Required dependencies:"
echo "$required_deps"
# Check each required dependency
for dep in $required_deps; do
dep_name=$(echo "$dep" | cut -d'-' -f1)
# Look for chart files that match the dependency name
if ! ls charts/"${dep_name}"-*.tgz >/dev/null 2>&1; then
echo "Missing dependency chart: $dep_name"
update_needed=true
break
else
echo "Found existing chart for: $dep_name"
fi
done
else
echo "No specific dependencies found, will update to be safe"
update_needed=true
fi
else
echo "Charts directory does not exist, dependencies update needed"
update_needed=true
fi
# Update dependencies only if needed
if [ "$update_needed" = true ]; then
echo "Updating dependencies..."
helm dependency update
# Verify dependencies were downloaded
if [ -d "charts" ]; then
echo "Dependencies successfully downloaded:"
ls -la charts/
else
echo "Warning: charts directory not created. Dependencies might not be needed or failed to download."
fi
else
echo "All dependencies are already present, skipping dependency update"
echo "Existing charts:"
ls -la charts/
fi
else
echo "No dependencies found in Chart.yaml"
fi
else
echo "Chart.yaml not found in ${CHART_DIR}"
exit 1
fi
- name: Package the helm chart
shell: bash
env:
TEMPLATE_DIR: ${{ env.TEMPLATE_DIR }}
run: |-
set -euo pipefail
cd helm-repo
# Determine the chart directory - same logic as dependency handling
if [ -n "${TEMPLATE_DIR}" ]; then
CHART_DIR="${TEMPLATE_DIR}"
else
# If no TEMPLATE_DIR specified, look for Chart.yaml in common locations
if [ -f "Chart.yaml" ]; then
CHART_DIR="."
elif [ -f "chart/Chart.yaml" ]; then
CHART_DIR="chart"
elif [ -f "helm/Chart.yaml" ]; then
CHART_DIR="helm"
else
echo "Could not find Chart.yaml file. Please specify TEMPLATE_DIR input."
exit 1
fi
fi
# Package the chart
helm package "${CHART_DIR}"
# Read chart metadata from the determined chart directory
CHART_NAME=$(yq -r '.name' "${CHART_DIR}/Chart.yaml")
CHART_VERSION=$(yq -r '.version' "${CHART_DIR}/Chart.yaml")
CHART_TGZ="${CHART_NAME}-${CHART_VERSION}.tgz"
# Move chart to parent dir
mv ${CHART_TGZ} ..
echo "CHART_NAME=${CHART_NAME}" >> $GITHUB_ENV
echo "CHART_VERSION=${CHART_VERSION}" >> $GITHUB_ENV
echo "CHART_TGZ=${CHART_TGZ}" >> $GITHUB_ENV
# - name: Sign the chart
# shell: bash
# env:
# GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
# run: |-
# set -euo pipefail
# echo ${{ secrets.GPG_SECRET_SUBKEY }} | base64 -d | gpg --batch --import
# echo ${{ secrets.GPG_PUBLIC_KEY }} | base64 -d | gpg --batch --import
# # Needed because helm verify only supports old format
# gpg --export >~/.gnupg/pubring.gpg
# pip install git+https://gitlab.com/mbaldessari/helm-sign.git@couple-of-fixes
# helm-sign ${{ env.CHART_TGZ }}
# helm verify ${{ env.CHART_TGZ }}
- name: Upload helm package as a release asset
uses: svenstaro/upload-release-action@v2
with:
repo_token: ${{ secrets.GITHUB_TOKEN }}
file: ${{ env.CHART_TGZ }}
asset_name: ${{ env.CHART_TGZ }}
tag: ${{ github.ref }}
body: "${{ env.CHART_NAME }} Released ${{ env.CHART_VERSION }}"
overwrite: true
# - name: Upload helm package signature as a release asset
# uses: svenstaro/upload-release-action@v2
# with:
# repo_token: ${{ secrets.GITHUB_TOKEN }}
# file: ${{ env.CHART_TGZ }}.prov
# asset_name: ${{ env.CHART_TGZ }}.prov
# tag: ${{ github.ref }}
# body: "${{ env.CHART_NAME }} Released ${{ env.CHART_VERSION }}"
# overwrite: true
# Uploaded to https://github.com/validatedpatterns/helm-charts/releases/download/main/test-0.0.1.tgz
# This step fetches all assets and places them in the current folder
# The reason for doing this is that it makes things fully idempotent and we do not need
# to rely on the --merge feature when generating the index
# While this probably does not scale all too well it should be fine for our not too large
# helm repo
- name: Fetch all assets locally
env:
GH_TOKEN: ${{ github.token }}
run: |-
set -e
for i in $(gh api repos/${UMBRELLA_REPO}/releases/latest | jq -r ".assets[].browser_download_url"); do
curl -O -L "${i}"
done
- name: Update the helm index.yaml file
run: |-
set -e
helm repo index --url "${ASSETS_BASE_URL}" .
# FIXME(bandini): this is for debugging only
cat index.yaml
- name: Checkout code to git-repo folder
uses: actions/checkout@v6
with:
# Full git history is needed to get a proper list of changed files within `super-linter`
fetch-depth: 0
path: git-repo
- name: Commit to gh-pages
run: |-
set -e
cd git-repo
git config user.name "${{ github.actor }}"
git config user.email "${{ github.actor }}@users.noreply.github.com"
git checkout gh-pages
# This copies the newly generated index.yaml to the git repo
cp -fv ../index.yaml .
# Copy index.tpl from the main branch which is where it lives
git checkout origin/main index.tpl
# Install index.html generator
helm plugin install https://github.com/halkeye/helm-repo-html
helm repo-html
ls -l index.html
git add index.yaml index.html
git commit -m "Updated ${{ env.CHART_NAME }}-${{ env.CHART_VERSION }}"
git push origin gh-pages
- name: Push the chart to legacy and new quay repos
run: |-
set -e
helm registry login -u="${{ secrets.LEGACY_QUAY_USERNAME }}" -p="${{ secrets.LEGACY_QUAY_PASSWORD }}" quay.io
helm push "${{ env.CHART_TGZ }}" "${LEGACY_QUAY_BASE_URL}"
helm registry login -u="${{ secrets.QUAY_USERNAME }}" -p="${{ secrets.QUAY_PASSWORD }}" quay.io
helm push "${{ env.CHART_TGZ }}" "${QUAY_BASE_URL}"