mirror of
https://github.com/lukaszraczylo/helm-charts.git
synced 2026-10-14 05:48:34 +00:00
Fail the release when a chart has an invalid artifacthub.io/changes kind or fails helm lint. Rebuild the README chart table from index.yaml after each release.
200 lines
7.6 KiB
YAML
200 lines
7.6 KiB
YAML
name: Release Chart
|
|
|
|
on:
|
|
repository_dispatch:
|
|
types: [release-chart]
|
|
workflow_dispatch:
|
|
inputs:
|
|
chart_name:
|
|
description: 'Chart name (e.g., jobs-manager)'
|
|
required: true
|
|
type: string
|
|
version:
|
|
description: 'Chart version (e.g., 0.0.36)'
|
|
required: true
|
|
type: string
|
|
source_repo:
|
|
description: 'Source repository (e.g., lukaszraczylo/jobs-manager-operator)'
|
|
required: true
|
|
type: string
|
|
chart_path:
|
|
description: 'Path to chart in source repo (e.g., charts/jobs-manager-operator)'
|
|
required: true
|
|
type: string
|
|
|
|
permissions:
|
|
contents: write
|
|
|
|
jobs:
|
|
release:
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Parse inputs
|
|
id: inputs
|
|
run: |
|
|
# Handle both repository_dispatch and workflow_dispatch
|
|
if [ "${{ github.event_name }}" = "repository_dispatch" ]; then
|
|
echo "chart_name=${{ github.event.client_payload.chart_name }}" >> $GITHUB_OUTPUT
|
|
echo "version=${{ github.event.client_payload.version }}" >> $GITHUB_OUTPUT
|
|
echo "source_repo=${{ github.event.client_payload.source_repo }}" >> $GITHUB_OUTPUT
|
|
echo "chart_path=${{ github.event.client_payload.chart_path }}" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "chart_name=${{ inputs.chart_name }}" >> $GITHUB_OUTPUT
|
|
echo "version=${{ inputs.version }}" >> $GITHUB_OUTPUT
|
|
echo "source_repo=${{ inputs.source_repo }}" >> $GITHUB_OUTPUT
|
|
echo "chart_path=${{ inputs.chart_path }}" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Checkout helm-charts repo (gh-pages)
|
|
uses: actions/checkout@v4
|
|
with:
|
|
ref: gh-pages
|
|
fetch-depth: 0
|
|
submodules: false
|
|
|
|
- name: Clean up any leftover source-repo
|
|
run: |
|
|
rm -rf source-repo
|
|
# Remove from git index if it exists as submodule
|
|
git rm -rf --cached source-repo 2>/dev/null || true
|
|
|
|
- name: Checkout source repo
|
|
uses: actions/checkout@v4
|
|
with:
|
|
repository: ${{ steps.inputs.outputs.source_repo }}
|
|
ref: v${{ steps.inputs.outputs.version }}
|
|
path: source-repo
|
|
|
|
- name: Setup Helm
|
|
uses: azure/setup-helm@v4
|
|
with:
|
|
version: v3.14.0
|
|
|
|
- name: Ensure PyYAML
|
|
run: python3 -c "import yaml" 2>/dev/null || sudo apt-get install -y -qq python3-yaml
|
|
|
|
- name: Lint chart
|
|
env:
|
|
CHART_PATH: ${{ steps.inputs.outputs.chart_path }}
|
|
run: |
|
|
python3 - <<'PY'
|
|
import os, sys, yaml
|
|
|
|
VALID_KINDS = {"added", "changed", "deprecated", "removed", "fixed", "security"}
|
|
chart_dir = os.path.join("source-repo", os.environ["CHART_PATH"])
|
|
with open(os.path.join(chart_dir, "Chart.yaml")) as f:
|
|
chart = yaml.safe_load(f)
|
|
|
|
raw = (chart.get("annotations") or {}).get("artifacthub.io/changes")
|
|
errors = []
|
|
if raw:
|
|
changes = yaml.safe_load(raw)
|
|
if not isinstance(changes, list):
|
|
errors.append("artifacthub.io/changes must be a list")
|
|
else:
|
|
for i, change in enumerate(changes):
|
|
if not isinstance(change, dict):
|
|
errors.append(f"change {i}: must be a mapping")
|
|
continue
|
|
if change.get("kind") not in VALID_KINDS:
|
|
errors.append(f"change {i}: invalid kind {change.get('kind')!r}")
|
|
if not change.get("description"):
|
|
errors.append(f"change {i}: missing description")
|
|
for e in errors:
|
|
print(f"::error file={chart_dir}/Chart.yaml::{e}")
|
|
if errors:
|
|
print(f"Valid kinds: {', '.join(sorted(VALID_KINDS))}")
|
|
sys.exit(1)
|
|
PY
|
|
helm lint "source-repo/${CHART_PATH}"
|
|
|
|
- name: Package and release chart
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
CHART_NAME="${{ steps.inputs.outputs.chart_name }}"
|
|
VERSION="${{ steps.inputs.outputs.version }}"
|
|
CHART_PATH="${{ steps.inputs.outputs.chart_path }}"
|
|
|
|
echo "Releasing ${CHART_NAME} version ${VERSION}"
|
|
|
|
# Update chart version in source
|
|
sed -i "s/^version:.*/version: ${VERSION}/" "source-repo/${CHART_PATH}/Chart.yaml"
|
|
sed -i "s/^appVersion:.*/appVersion: \"${VERSION}\"/" "source-repo/${CHART_PATH}/Chart.yaml"
|
|
|
|
# Update values.yaml tag if it exists
|
|
if grep -q "tag:" "source-repo/${CHART_PATH}/values.yaml" 2>/dev/null; then
|
|
sed -i "s/tag:.*/tag: \"${VERSION}\"/" "source-repo/${CHART_PATH}/values.yaml"
|
|
fi
|
|
|
|
# Package the chart
|
|
mkdir -p /tmp/helm-packages
|
|
helm package "source-repo/${CHART_PATH}" -d /tmp/helm-packages/
|
|
|
|
CHART_FILE="/tmp/helm-packages/${CHART_NAME}-${VERSION}.tgz"
|
|
|
|
# Create GitHub release with chart attached
|
|
gh release create "${CHART_NAME}-${VERSION}" \
|
|
"${CHART_FILE}" \
|
|
--title "${CHART_NAME}-${VERSION}" \
|
|
--notes "Release ${CHART_NAME} Helm chart version ${VERSION}"
|
|
|
|
# Copy to packages directory
|
|
cp "${CHART_FILE}" charts/packages/
|
|
|
|
# Copy updated chart source to local charts directory
|
|
DEST_DIR="charts/${CHART_PATH##*/}"
|
|
mkdir -p "${DEST_DIR}"
|
|
cp -R "source-repo/${CHART_PATH}/"* "${DEST_DIR}/"
|
|
|
|
# Update index.yaml with correct GitHub Releases URL
|
|
helm repo index /tmp/helm-packages/ \
|
|
--url "https://github.com/lukaszraczylo/helm-charts/releases/download/${CHART_NAME}-${VERSION}" \
|
|
--merge index.yaml
|
|
|
|
cp /tmp/helm-packages/index.yaml index.yaml
|
|
|
|
- name: Update README chart table
|
|
run: |
|
|
python3 - <<'PY'
|
|
import re, yaml
|
|
|
|
START, END = "<!-- CHARTS_START -->", "<!-- CHARTS_END -->"
|
|
with open("index.yaml") as f:
|
|
entries = yaml.safe_load(f)["entries"]
|
|
|
|
def first_sentence(text):
|
|
text = " ".join((text or "").split())
|
|
m = re.match(r"(.+?[.!?])(\s|$)", text)
|
|
return (m.group(1) if m else text).rstrip(".")
|
|
|
|
rows = ["| Chart | Description |", "| ----- | ----------- |"]
|
|
for name in sorted(entries):
|
|
latest = max(entries[name], key=lambda e: e["created"])
|
|
link = (latest.get("sources") or [latest.get("home")])[0]
|
|
desc = first_sentence(latest.get("description")).replace("|", "\\|")
|
|
rows.append(f"| [{name}]({link}) | {desc} |")
|
|
|
|
with open("README.md") as f:
|
|
readme = f.read()
|
|
if START not in readme or END not in readme:
|
|
raise SystemExit(f"README.md is missing the {START} / {END} markers")
|
|
head, rest = readme.split(START, 1)
|
|
_, tail = rest.split(END, 1)
|
|
with open("README.md", "w") as f:
|
|
f.write(head + START + "\n\n" + "\n".join(rows) + "\n\n" + END + tail)
|
|
PY
|
|
|
|
- name: Commit and push to gh-pages
|
|
run: |
|
|
# Remove source-repo before committing (it's a temp checkout)
|
|
rm -rf source-repo
|
|
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
|
|
# Only add specific paths, not source-repo
|
|
git add charts/ index.yaml README.md
|
|
git diff --staged --quiet || git commit -m "Release ${{ steps.inputs.outputs.chart_name }} ${{ steps.inputs.outputs.version }}"
|
|
git push origin gh-pages
|