Skip to content

feat(wik-webservice): improve support for ListenerSet #49

feat(wik-webservice): improve support for ListenerSet

feat(wik-webservice): improve support for ListenerSet #49

Workflow file for this run

name: Release Charts
on:
push:
branches:
- main
paths:
- 'charts/**'
workflow_dispatch:
inputs:
chart:
description: 'Chart to release (e.g., wik-webservice). Leave empty for auto-detect.'
required: false
type: string
force:
description: 'Force release even if version exists'
required: false
type: boolean
default: false
concurrency:
group: release-${{ github.ref }}
cancel-in-progress: false
env:
GHCR_REGISTRY: ghcr.io
GHCR_REPO: wikodit/charts
jobs:
detect-changes:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
has_changes: ${{ steps.set-matrix.outputs.has_changes }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set up Helm
uses: azure/setup-helm@v5
with:
version: v3.19.4
- name: Set up chart-testing
uses: helm/chart-testing-action@v2.8.0
- name: Detect charts to release
id: set-matrix
run: |
if [[ -n "${{ inputs.chart }}" ]]; then
# Manual trigger with specific chart
CHARTS='["${{ inputs.chart }}"]'
else
# For push events, compare with the commit before the push
if [[ "${{ github.event_name }}" == "push" ]]; then
BEFORE_SHA="${{ github.event.before }}"
if [[ "$BEFORE_SHA" == "0000000000000000000000000000000000000000" ]]; then
# Initial push, check all charts
changed=$(ls -d charts/*/ 2>/dev/null | xargs -I{} basename {} || echo "")
else
changed=$(git diff --name-only "$BEFORE_SHA" HEAD -- charts/ | grep -oP 'charts/\K[^/]+' | sort -u || echo "")
fi
else
# For other events (workflow_dispatch without chart input)
changed=$(git diff --name-only origin/main HEAD -- charts/ 2>/dev/null | grep -oP 'charts/\K[^/]+' | sort -u || echo "")
fi
if [[ -n "$changed" ]]; then
CHARTS=$(echo "$changed" | jq -R -s -c 'split("\n") | map(select(. != ""))')
else
CHARTS='[]'
fi
fi
echo "Detected charts: $CHARTS"
if [[ "$CHARTS" == "[]" ]]; then
echo "has_changes=false" >> "$GITHUB_OUTPUT"
echo "matrix={\"chart\":[]}" >> "$GITHUB_OUTPUT"
else
echo "has_changes=true" >> "$GITHUB_OUTPUT"
echo "matrix={\"chart\":$CHARTS}" >> "$GITHUB_OUTPUT"
fi
release:
runs-on: ubuntu-latest
needs: detect-changes
if: needs.detect-changes.outputs.has_changes == 'true'
permissions:
contents: write
packages: write
id-token: write # Required for cosign keyless signing
strategy:
fail-fast: false
max-parallel: 1 # Serialize releases to avoid conflicts
matrix: ${{ fromJson(needs.detect-changes.outputs.matrix) }}
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Set up Helm
uses: azure/setup-helm@v5
with:
version: v3.19.4
- name: Install cosign
uses: sigstore/cosign-installer@v4.1.0
- name: Install yq
uses: mikefarah/yq@v4
- name: Determine version bump from conventional commits
id: version-bump
run: |
CHART_PATH="charts/${{ matrix.chart }}"
CHART_NAME=$(yq '.name' "${CHART_PATH}/Chart.yaml")
# Get the last release tag for this chart
LAST_TAG=$(git tag --list "${CHART_NAME}-v*" --sort=-version:refname | head -n1 || echo "")
if [[ -z "$LAST_TAG" ]]; then
# No previous release, get all commits for this chart
echo "No previous release found for ${CHART_NAME}"
COMMITS=$(git log --oneline --no-merges -- "${CHART_PATH}")
CURRENT_VERSION="0.0.0"
else
echo "Last release: ${LAST_TAG}"
COMMITS=$(git log --oneline --no-merges "${LAST_TAG}..HEAD" -- "${CHART_PATH}")
# Extract version from tag (chart-name-vX.Y.Z -> X.Y.Z)
CURRENT_VERSION=$(echo "$LAST_TAG" | sed "s/${CHART_NAME}-v//")
fi
echo "Current version: ${CURRENT_VERSION}"
echo "Commits since last release:"
echo "$COMMITS"
# Determine bump type from conventional commits
BUMP_TYPE="none"
# Check for breaking changes (BREAKING CHANGE in body or ! after type)
if echo "$COMMITS" | grep -qiE '(BREAKING CHANGE|^[a-z]+!:|!)'; then
BUMP_TYPE="major"
# Check for features
elif echo "$COMMITS" | grep -qiE '^[a-f0-9]+ feat'; then
BUMP_TYPE="minor"
# Check for fixes or performance improvements
elif echo "$COMMITS" | grep -qiE '^[a-f0-9]+ (fix|perf)'; then
BUMP_TYPE="patch"
fi
echo "Bump type: ${BUMP_TYPE}"
if [[ "$BUMP_TYPE" == "none" ]]; then
echo "::notice::No releasable commits found (need feat, fix, or perf). Skipping automatic release."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "skip=false" >> "$GITHUB_OUTPUT"
# Calculate new version
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT_VERSION"
case "$BUMP_TYPE" in
major)
NEW_VERSION="$((MAJOR + 1)).0.0"
;;
minor)
NEW_VERSION="${MAJOR}.$((MINOR + 1)).0"
;;
patch)
NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))"
;;
esac
echo "New version: ${NEW_VERSION}"
echo "bump_type=${BUMP_TYPE}" >> "$GITHUB_OUTPUT"
echo "current_version=${CURRENT_VERSION}" >> "$GITHUB_OUTPUT"
echo "new_version=${NEW_VERSION}" >> "$GITHUB_OUTPUT"
- name: Update Chart.yaml version
if: steps.version-bump.outputs.skip != 'true'
id: update-version
run: |
CHART_PATH="charts/${{ matrix.chart }}"
NEW_VERSION="${{ steps.version-bump.outputs.new_version }}"
# Update version and appVersion in Chart.yaml
yq -i ".version = \"${NEW_VERSION}\"" "${CHART_PATH}/Chart.yaml"
yq -i ".appVersion = \"${NEW_VERSION}\"" "${CHART_PATH}/Chart.yaml"
echo "Updated Chart.yaml to version ${NEW_VERSION}"
cat "${CHART_PATH}/Chart.yaml"
- name: Get chart info
if: steps.version-bump.outputs.skip != 'true'
id: chart-info
run: |
CHART_PATH="charts/${{ matrix.chart }}"
if [[ ! -f "${CHART_PATH}/Chart.yaml" ]]; then
echo "::error::Chart.yaml not found at ${CHART_PATH}"
exit 1
fi
VERSION=$(yq '.version' "${CHART_PATH}/Chart.yaml")
NAME=$(yq '.name' "${CHART_PATH}/Chart.yaml")
APP_VERSION=$(yq '.appVersion // "unknown"' "${CHART_PATH}/Chart.yaml")
echo "name=${NAME}" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
echo "app_version=${APP_VERSION}" >> "$GITHUB_OUTPUT"
echo "path=${CHART_PATH}" >> "$GITHUB_OUTPUT"
echo "tag=${NAME}-v${VERSION}" >> "$GITHUB_OUTPUT"
echo "Chart: ${NAME}"
echo "Version: ${VERSION}"
echo "App Version: ${APP_VERSION}"
- name: Check if version already released
if: steps.version-bump.outputs.skip != 'true'
id: check-version
run: |
TAG="${{ steps.chart-info.outputs.tag }}"
if git rev-parse "refs/tags/${TAG}" >/dev/null 2>&1; then
if [[ "${{ inputs.force }}" == "true" ]]; then
echo "WARNING: Tag ${TAG} exists but force=true, continuing..."
echo "exists=true" >> "$GITHUB_OUTPUT"
else
echo "::error::Tag ${TAG} already exists. Bump the version in Chart.yaml or use force=true."
exit 1
fi
else
echo "exists=false" >> "$GITHUB_OUTPUT"
fi
- name: Update dependencies
if: steps.version-bump.outputs.skip != 'true'
run: |
helm dependency update "${{ steps.chart-info.outputs.path }}" || true
- name: Regenerate README
if: steps.version-bump.outputs.skip != 'true'
run: |
# Install helm-docs
HELM_DOCS_VERSION="1.14.2"
wget -O helm-docs.tar.gz "https://github.com/norwoodj/helm-docs/releases/download/v${HELM_DOCS_VERSION}/helm-docs_${HELM_DOCS_VERSION}_Linux_x86_64.tar.gz"
tar xzf helm-docs.tar.gz
sudo mv helm-docs /usr/local/bin/
# Regenerate README for this chart
helm-docs --chart-search-root "${{ steps.chart-info.outputs.path }}" --template-files README.md.gotmpl
echo "Regenerated README for ${{ steps.chart-info.outputs.name }}"
- name: Generate CHANGELOG
if: steps.version-bump.outputs.skip != 'true'
id: changelog
run: |
# Install git-chglog
CHGLOG_VERSION="0.15.4"
wget -O git-chglog.tar.gz "https://github.com/git-chglog/git-chglog/releases/download/v${CHGLOG_VERSION}/git-chglog_${CHGLOG_VERSION}_linux_amd64.tar.gz"
tar xzf git-chglog.tar.gz
sudo mv git-chglog /usr/local/bin/
CHANGELOG_PATH="${{ steps.chart-info.outputs.path }}/CHANGELOG.md"
NEW_TAG="${{ steps.chart-info.outputs.name }}-v${{ steps.chart-info.outputs.version }}"
# Create temporary tag for git-chglog
git tag "$NEW_TAG"
# Generate full changelog for this chart (all versions, only this chart's commits)
git-chglog --config .chglog/config.yml --output "$CHANGELOG_PATH" --tag-filter-pattern "${{ steps.chart-info.outputs.name }}-v.*" --path "${{ steps.chart-info.outputs.path }}"
# Remove temporary tag (GitHub release will create it)
git tag -d "$NEW_TAG"
echo "Generated CHANGELOG for ${{ steps.chart-info.outputs.name }}"
# Extract changelog for release body
CHANGELOG_CONTENT=$(cat "$CHANGELOG_PATH" | head -100)
echo "changelog<<EOF" >> "$GITHUB_OUTPUT"
echo "$CHANGELOG_CONTENT" >> "$GITHUB_OUTPUT"
echo "EOF" >> "$GITHUB_OUTPUT"
- name: Package chart
if: steps.version-bump.outputs.skip != 'true'
run: |
mkdir -p .packaged
helm package "${{ steps.chart-info.outputs.path }}" -d .packaged/
echo "Packaged: .packaged/${{ steps.chart-info.outputs.name }}-${{ steps.chart-info.outputs.version }}.tgz"
- name: Login to GHCR
if: steps.version-bump.outputs.skip != 'true'
run: |
echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ${{ env.GHCR_REGISTRY }} \
-u ${{ github.actor }} --password-stdin
- name: Push to GHCR
if: steps.version-bump.outputs.skip != 'true'
id: push-ghcr
run: |
PACKAGE=".packaged/${{ steps.chart-info.outputs.name }}-${{ steps.chart-info.outputs.version }}.tgz"
helm push "${PACKAGE}" oci://${{ env.GHCR_REGISTRY }}/${{ env.GHCR_REPO }}
# Get the digest
DIGEST=$(crane digest ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_REPO }}/${{ steps.chart-info.outputs.name }}:${{ steps.chart-info.outputs.version }} 2>/dev/null || echo "")
echo "digest=${DIGEST}" >> "$GITHUB_OUTPUT"
echo "Pushed to GHCR"
env:
COSIGN_EXPERIMENTAL: "true"
- name: Sign chart in GHCR (keyless)
if: steps.version-bump.outputs.skip != 'true'
env:
COSIGN_EXPERIMENTAL: "1"
run: |
IMAGE="${{ env.GHCR_REGISTRY }}/${{ env.GHCR_REPO }}/${{ steps.chart-info.outputs.name }}:${{ steps.chart-info.outputs.version }}"
# Authenticate with GHCR for Cosign
echo "${{ secrets.GITHUB_TOKEN }}" | cosign login ${{ env.GHCR_REGISTRY }} \
-u ${{ github.actor }} --password-stdin
cosign sign --yes "${IMAGE}"
echo "Signed ${IMAGE}"
- name: Login to Harbor
if: steps.version-bump.outputs.skip != 'true' && vars.HARBOR_REGISTRY != ''
run: |
echo "${{ secrets.HARBOR_PASSWORD }}" | helm registry login ${{ vars.HARBOR_REGISTRY }} \
-u "${{ secrets.HARBOR_USERNAME }}" --password-stdin
- name: Push to Harbor
if: steps.version-bump.outputs.skip != 'true' && vars.HARBOR_REGISTRY != ''
run: |
PACKAGE=".packaged/${{ steps.chart-info.outputs.name }}-${{ steps.chart-info.outputs.version }}.tgz"
HARBOR_REPO="${{ vars.HARBOR_REGISTRY }}/${{ vars.HARBOR_PROJECT || 'library' }}"
helm push "${PACKAGE}" oci://${HARBOR_REPO}
echo "Pushed to Harbor"
- name: Sign chart in Harbor (keyless)
if: steps.version-bump.outputs.skip != 'true' && vars.HARBOR_REGISTRY != ''
continue-on-error: true
env:
COSIGN_EXPERIMENTAL: "1"
run: |
IMAGE="${{ vars.HARBOR_REGISTRY }}/${{ vars.HARBOR_PROJECT || 'library' }}/${{ steps.chart-info.outputs.name }}:${{ steps.chart-info.outputs.version }}"
# Authenticate with Harbor for Cosign
echo "${{ secrets.HARBOR_PASSWORD }}" | cosign login ${{ vars.HARBOR_REGISTRY }} \
-u "${{ secrets.HARBOR_USERNAME }}" --password-stdin
cosign sign --yes "${IMAGE}"
echo "Signed ${IMAGE}"
- name: Generate SBOM
if: steps.version-bump.outputs.skip != 'true'
run: |
# Generate SBOM for the chart
PACKAGE=".packaged/${{ steps.chart-info.outputs.name }}-${{ steps.chart-info.outputs.version }}.tgz"
# Create a simple SBOM (for more comprehensive SBOM, use syft)
cat > ".packaged/${{ steps.chart-info.outputs.name }}-${{ steps.chart-info.outputs.version }}.sbom.json" <<EOF
{
"bomFormat": "CycloneDX",
"specVersion": "1.4",
"version": 1,
"metadata": {
"timestamp": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
"component": {
"type": "application",
"name": "${{ steps.chart-info.outputs.name }}",
"version": "${{ steps.chart-info.outputs.version }}",
"purl": "pkg:helm/${{ env.GHCR_REPO }}/${{ steps.chart-info.outputs.name }}@${{ steps.chart-info.outputs.version }}"
}
},
"components": []
}
EOF
echo "Generated SBOM"
- name: Create GitHub Release
if: steps.version-bump.outputs.skip != 'true'
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.chart-info.outputs.tag }}
name: "${{ steps.chart-info.outputs.name }} v${{ steps.chart-info.outputs.version }}"
body: |
## Helm Chart Release
**Chart**: `${{ steps.chart-info.outputs.name }}`
**Version**: `${{ steps.chart-info.outputs.version }}`
**App Version**: `${{ steps.chart-info.outputs.app_version }}`
### Installation
```bash
# From GHCR (OCI)
helm install ${{ steps.chart-info.outputs.name }} oci://${{ env.GHCR_REGISTRY }}/${{ env.GHCR_REPO }}/${{ steps.chart-info.outputs.name }} --version ${{ steps.chart-info.outputs.version }}
```
### Signature Verification
```bash
cosign verify ${{ env.GHCR_REGISTRY }}/${{ env.GHCR_REPO }}/${{ steps.chart-info.outputs.name }}:${{ steps.chart-info.outputs.version }} \
--certificate-identity-regexp='https://github.com/${{ github.repository }}' \
--certificate-oidc-issuer='https://token.actions.githubusercontent.com'
```
---
${{ steps.changelog.outputs.changelog }}
files: |
.packaged/${{ steps.chart-info.outputs.name }}-${{ steps.chart-info.outputs.version }}.tgz
.packaged/${{ steps.chart-info.outputs.name }}-${{ steps.chart-info.outputs.version }}.sbom.json
generate_release_notes: false
make_latest: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Commit CHANGELOG
if: success() && steps.version-bump.outputs.skip != 'true'
run: |
# Configure git
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
# Show what files were modified
echo "Modified files:"
git status --short
# Add all changes from this chart (including Chart.lock from dependency update)
git add "${{ steps.chart-info.outputs.path }}/"
# Check if there are changes to commit
if git diff --staged --quiet; then
echo "No changes to commit"
else
git commit -m "chore(${{ steps.chart-info.outputs.name }}): release v${{ steps.chart-info.outputs.version }} [skip ci]" \
-m "Bump version from ${{ steps.version-bump.outputs.current_version }} to ${{ steps.version-bump.outputs.new_version }}" \
-m "Update CHANGELOG.md"
# Fetch and rebase (discard any untracked/modified files outside chart)
git checkout -- . || true
git clean -fd || true
git fetch origin main
git rebase origin/main
# Push changes
git push https://github-actions:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git main
echo "Version bump and CHANGELOG committed and pushed"
fi
- name: Summary
if: steps.version-bump.outputs.skip != 'true'
run: |
cat >> "$GITHUB_STEP_SUMMARY" <<EOF
## Release Summary
| Property | Value |
|----------|-------|
| Chart | \`${{ steps.chart-info.outputs.name }}\` |
| Previous Version | \`${{ steps.version-bump.outputs.current_version }}\` |
| New Version | \`${{ steps.chart-info.outputs.version }}\` |
| Bump Type | \`${{ steps.version-bump.outputs.bump_type }}\` |
| GHCR | \`${{ env.GHCR_REGISTRY }}/${{ env.GHCR_REPO }}/${{ steps.chart-info.outputs.name }}:${{ steps.chart-info.outputs.version }}\` |
| GitHub Release | [${{ steps.chart-info.outputs.tag }}](${{ github.server_url }}/${{ github.repository }}/releases/tag/${{ steps.chart-info.outputs.tag }}) |
| Signed | Keyless (Sigstore) |
EOF