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 = "", "" 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