Skip to content

wordpress 1.0.0 — WordPress on a shared volumeset with bundled MariaDB #428

wordpress 1.0.0 — WordPress on a shared volumeset with bundled MariaDB

wordpress 1.0.0 — WordPress on a shared volumeset with bundled MariaDB #428

name: Validate Helm Charts
on:
pull_request:
branches: [main]
workflow_dispatch:
workflow_call:
inputs:
version_dirs:
description: 'Space-separated version dirs to validate (e.g. "redis/versions/3.0.0 nginx/versions/1.1.1")'
type: string
required: false
default: ''
charts:
description: 'Space-separated template names to validate all versions of'
type: string
required: false
default: ''
concurrency:
group: validate-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.run_id }}
cancel-in-progress: true
jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 20
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Helm
uses: azure/setup-helm@v3
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Determine changed version directories
id: versions
run: |
# When called as a reusable workflow, use the provided inputs directly
if [ -n "${{ inputs.version_dirs }}" ] || [ -n "${{ inputs.charts }}" ]; then
echo "version_dirs=${{ inputs.version_dirs }}" >> $GITHUB_OUTPUT
echo "charts=${{ inputs.charts }}" >> $GITHUB_OUTPUT
exit 0
fi
# Otherwise detect from git diff (pull_request / workflow_dispatch)
if [ "${{ github.event_name }}" = "pull_request" ]; then
base_sha="${{ github.event.pull_request.base.sha }}"
else
base_sha="$(git rev-parse HEAD^)"
fi
version_dirs=$(git diff --name-only "$base_sha" HEAD \
| grep -E '^[^/]+/versions/[^/]+/' \
| sed -E 's|^([^/]+/versions/[^/]+)/.*|\1|' \
| sort -u | tr '\n' ' ')
echo "base_sha=$base_sha" >> $GITHUB_OUTPUT
echo "version_dirs=$version_dirs" >> $GITHUB_OUTPUT
- name: Validate charts
if: steps.versions.outputs.version_dirs != '' || steps.versions.outputs.charts != ''
run: |
base_sha="${{ steps.versions.outputs.base_sha }}"
failed=0
# The OCI registry throttles when several runs pull cpln-common at once.
# Bound each attempt and retry with backoff; a real failure must be visible,
# not swallowed into a step that appears to hang.
helm_dep_update() {
local dir="$1" n=1
while [ "$n" -le 3 ]; do
if timeout 300 helm dependency update "$dir"; then return 0; fi
echo "helm dependency update failed for $dir (attempt $n/3)"
[ "$n" -lt 3 ] && sleep $((n * 15))
n=$((n + 1))
done
return 1
}
validate_version_dir() {
local version_dir="${1%/}"
[ ! -f "$version_dir/Chart.yaml" ] && return
local template=$(echo "$version_dir" | cut -d/ -f1)
local folder_version=$(echo "$version_dir" | cut -d/ -f3)
local version=$(grep '^version:' "$version_dir/Chart.yaml" | awk '{print $2}')
if [ "$version" != "$folder_version" ]; then
echo "FAIL [$template]: Chart.yaml version '$version' does not match folder name '$folder_version'"
failed=1
return
fi
# Library charts cannot be rendered standalone — skip helm template validation
if grep -qE '^\s*type:\s*library' "$version_dir/Chart.yaml"; then
echo "Skipping $template @ $version (library chart)"
return
fi
echo ""
echo "=== Validating $template @ $version ==="
# 1. helm template with default values
# charts with createsGvc:false expect global.cpln.gvc at runtime — pass a dummy value
local creates_gvc=$(grep -E '^\s+createsGvc:' "$version_dir/Chart.yaml" | awk '{print $2}')
local helm_flags=""
if [ "$creates_gvc" = "false" ]; then
helm_flags="--set global.cpln.gvc=validation-gvc"
fi
if ! helm_dep_update "$version_dir"; then
echo "FAIL [$template @ $version]: helm dependency update failed (registry unreachable or throttled)"
failed=1
return
fi
if ! rendered=$(helm template "validation" "$version_dir" $helm_flags 2>&1); then
echo "FAIL [$template @ $version]: helm template failed with default values"
echo "$rendered"
failed=1
return
fi
# 2. Required marketplace tags in rendered output
for tag in 'cpln/marketplace:' 'cpln/marketplace-template:' 'cpln/marketplace-template-version:'; do
if ! echo "$rendered" | grep -q "$tag"; then
echo "FAIL [$template @ $version]: Missing required tag '$tag' in rendered templates"
failed=1
fi
done
if ! echo "$rendered" | grep -q 'cpln/marketplace: "true"'; then
echo "FAIL [$template @ $version]: Tag 'cpln/marketplace' must equal \"true\""
failed=1
fi
# cpln/marketplace-gvc is required when createsGvc is false
if [ "$creates_gvc" = "false" ]; then
if ! echo "$rendered" | grep -q 'cpln/marketplace-gvc:'; then
echo "FAIL [$template @ $version]: Missing required tag 'cpln/marketplace-gvc' (required when createsGvc is false)"
failed=1
fi
fi
# 3. Required Chart.yaml annotations
for annotation in category created lastModified createsGvc; do
if ! grep -qE "^\s+${annotation}:" "$version_dir/Chart.yaml"; then
echo "FAIL [$template @ $version]: Missing annotation '$annotation' in Chart.yaml"
failed=1
fi
done
# 3b. Chart.yaml description. The marketplace card has a fixed height and
# CLIPS a long description mid-sentence (duckdb shipped 39 words and was
# visibly cut off in the UI). Em dashes are punctuation, not words.
local desc=$(sed -n 's/^description:[[:space:]]*//p' "$version_dir/Chart.yaml" | head -1)
if [ -z "$desc" ]; then
echo "FAIL [$template @ $version]: Chart.yaml description is empty - it is the marketplace card's one line"
failed=1
else
local words=$(echo "$desc" | tr ' ' '\n' | grep -vE '^$' | grep -vE '^(\xe2\x80\x94|\xe2\x80\x93|-)$' | wc -l | tr -d ' ')
if [ "$words" -gt 15 ]; then
echo "FAIL [$template @ $version]: description is $words words - the card clips past 15. Say what it IS, not everything it does"
failed=1
fi
if echo "$desc" | grep -qi 'for Control Plane'; then
echo "FAIL [$template @ $version]: description says 'for Control Plane' - every template here is"
failed=1
fi
if echo "$desc" | grep -qiE '^(a |an |the )?helm chart'; then
echo "FAIL [$template @ $version]: description starts 'a Helm chart for...' - say what the software is instead"
failed=1
fi
fi
# 4. New template: require README.md and icon.png at the template root
# (only checked when base_sha is available, i.e. PR / workflow_dispatch)
if [ -n "$base_sha" ]; then
if ! git ls-tree -r "$base_sha" --name-only 2>/dev/null | grep -q "^${template}/versions/"; then
echo "New template detected: $template — checking required files..."
if [ ! -f "$version_dir/README.md" ]; then
echo "FAIL [$template]: Missing README.md (required for new templates)"
failed=1
fi
if [ ! -f "$template/icon.png" ]; then
echo "FAIL [$template]: Missing icon.png (required for new templates)"
failed=1
fi
fi
fi
if [ "$failed" -eq 0 ]; then
echo "OK: $template @ $version"
fi
}
for version_dir in ${{ steps.versions.outputs.version_dirs }}; do
validate_version_dir "$version_dir"
done
for template in ${{ steps.versions.outputs.charts }}; do
for version_dir in "$template"/versions/*/; do
validate_version_dir "$version_dir"
done
done
exit $failed