Skip to content

Commit

Permalink
feat: create helm chart repository in gh-pages (#1931)
Browse files Browse the repository at this point in the history
try with helm index.yaml (@kromanow94)

find all helm chart releases and put to index.yaml (@kromanow94)

add chart description and version (@kromanow94)

add bash script for helm repo index.yaml generation from releases (@kromanow94)

script doesnt need token, rm unused python version, move to hack/, run from publish-helm gha workflow

push changes

remove unused py file

create clean branch for gh-pages

dont delete the script we need

typo

typo

gh-pages html

remove debug logs

git fetch

if statement wasnt working

copy needed files from hack to .tmp to use in empty gh-pages

debug

debug

cleanup debug logs

remove test file

fix: token not needed to install helm

fix: change trigger to release published
  • Loading branch information
patrickleet authored Nov 22, 2024
1 parent dc2f488 commit c5e5285
Show file tree
Hide file tree
Showing 4 changed files with 279 additions and 0 deletions.
71 changes: 71 additions & 0 deletions .github/workflows/publish-helm.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
name: Publish Helm Charts

on:
release:
types: [published]

jobs:
release:

permissions:
contents: write

runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Install Helm
uses: azure/setup-helm@v4

- name: Install Helm HTML Plugin
run: helm plugin install https://github.com/halkeye/helm-repo-html

- name: Build Helm Chart Repo index.yaml
run: |
# this script from main will be gone on gh-pages branch,
# so lets stash it away in a temp directory in the directory above this one
mkdir ../.tmp
mv hack/find_helm_chart_releases_and_create_helm_index.sh ../.tmp/
mv hack/gh-pages.tmpl ../.tmp/
PAGES_BRANCH="gh-pages"
git fetch --all --tags
if git show-ref --verify --quiet refs/heads/$PAGES_BRANCH || git ls-remote --exit-code --heads origin $PAGES_BRANCH; then
# Branch exists
git checkout $PAGES_BRANCH
echo "Checked out existing branch '$PAGES_BRANCH'"
else
# Branch does not exist
git symbolic-ref HEAD refs/heads/$PAGES_BRANCH
rm .git/index
git clean -fdx
echo ".tmp/" > .gitignore
echo "Created and checked out new branch '$PAGES_BRANCH'"
fi
mv ../.tmp ./
.tmp/find_helm_chart_releases_and_create_helm_index.sh
helm repo-html -t .tmp/gh-pages.tmpl
if output=$(git status --porcelain) && [ -z "$output" ]; then
# Working directory clean
echo "No changes to commit"
else
# Uncommitted changes
echo "Changes detected"
git status
echo "Committing..."
git config --local user.email "github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add -A
git commit -m "update helm chart repository index.yaml"
git push origin gh-pages
fi
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,3 +80,6 @@ tags
.vscode/*
.history
# End of https://www.gitignore.io/api/go,vim,emacs,visualstudiocode

charts/
.tmp/
97 changes: 97 additions & 0 deletions hack/find_helm_chart_releases_and_create_helm_index.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
#!/bin/bash
set -e

# GitHub Repository and API token
REPO="knative/operator"
CHART_NAME="knative-operator"

# GitHub API URL for releases
GITHUB_API="https://api.github.com/repos/$REPO/releases"

# Create an empty index.yaml file with 2-space indentation
cat > index.yaml <<EOF
apiVersion: v1
entries:
$CHART_NAME:
EOF

# Function to fetch all releases and filter .tgz files
fetch_tgz_assets() {
echo "Fetching release assets from GitHub API..." >&2

# Get response from GitHub API
response=$(curl "$GITHUB_API")

# Check if the response is valid JSON
if ! echo "$response" | jq 1>/dev/null 2>&1; then
echo "(fetch_tgz_assets) Error: The response is not valid JSON. Here's the raw response:" >&2
echo "$response" >&2
exit 1
fi

# Parse the response using jq to get the list of .tgz files
echo "$response" | jq -c '.[] | .assets[] | select(.name | test("'$CHART_NAME'-(v?\\d+\\.\\d+\\.\\d+)\\.tgz")) | {url: .browser_download_url, name: .name, published: .updated_at}'
}

# Function to process each .tgz file and append chart metadata to index.yaml
process_tgz() {
local url=$1
local name=$2
local published=$3

echo "Processing $name from $url" >&2

# Download the .tgz file
curl -L -s -o "$name" "$url"

# Extract the Chart.yaml and values.yaml
tar -xf "$name" "$CHART_NAME/Chart.yaml" "$CHART_NAME/values.yaml"

# Parse description from Chart.yaml
DESCRIPTION=$(yq -r '.description' $CHART_NAME/Chart.yaml)

# Parse version from Chart.yaml (used as appVersion)
CHART_VERSION="$(yq -r '.version' $CHART_NAME/Chart.yaml)"

# Calculate the SHA-256 digest
DIGEST=$(sha256sum "$name" | cut -d' ' -f1)

# Append the chart metadata under the existing $CHART_NAME key
cat >> index.yaml <<EOF
- name: "$CHART_NAME"
apiVersion: v2
version: "v$CHART_VERSION"
appVersion: "$CHART_VERSION"
description: "$DESCRIPTION"
created: "$published"
urls:
- "$url"
digest: "$DIGEST"
EOF

# Cleanup
rm -f "$name"
rm -f $CHART_NAME/Chart.yaml $CHART_NAME/values.yaml
}

# Fetch all .tgz assets
tgz_assets=$(fetch_tgz_assets)

# Loop through all the assets and process them
echo "$tgz_assets" | while read -r asset; do
# Check if each asset is valid JSON
if ! echo "$asset" | jq '.' > /dev/null 2>&1; then
echo "Error: Invalid JSON in asset line. Here's the raw asset line:" >&2
echo "$asset" >&2
continue
fi

# Parse fields from the asset JSON
url=$(echo "$asset" | jq -r '.url')
name=$(echo "$asset" | jq -r '.name' | sed 's/.tgz$//') # Strip ".tgz" from name
published=$(echo "$asset" | jq -r '.published')

process_tgz "$url" "$name" "$published"
done

echo "index.yaml generated successfully!"
108 changes: 108 additions & 0 deletions hack/gh-pages.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Helm Charts - Knative</title>
<style>
body {
font-family: Arial, sans-serif;
background-color: #f4f6f8;
color: #2c3e50;
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
}
.container {
max-width: 900px;
width: 100%;
}
h1 {
font-size: 28px;
color: #333;
font-weight: bold;
margin-bottom: 20px;
}
.usage, .chart-list {
background: #fff;
padding: 20px;
border-radius: 10px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
margin-bottom: 20px;
}
.usage-code {
background: #333;
color: #fff;
padding: 12px;
border-radius: 5px;
font-family: "Courier New", monospace;
display: block;
font-size: 14px;
}
.chart-item {
margin-bottom: 20px;
padding: 15px;
border: 1px solid #ddd;
border-radius: 8px;
}
.chart-item h2 {
font-size: 18px;
margin: 0;
color: #007d9c;
}
.chart-item a {
color: #007d9c;
text-decoration: none;
font-weight: 500;
}
.chart-versions {
font-size: 14px;
color: #555;
margin-top: 5px;
}
.version-label {
font-weight: bold;
color: #333;
}
.chart-description {
font-size: 14px;
color: #777;
margin-top: 4px;
}
</style>
</head>
<body>

<div class="container">
<h1>Helm Charts</h1>

<div class="usage">
<h2>Usage</h2>
<code class="usage-code">
helm repo add knative-operator https://knative.github.io/operator<br/>
helm show values knative-operator/knative-operator
</code>
</div>

<div class="chart-list">
<h2>Charts</h2>

{{range $entriesKey, $chartEntries := .Entries }}
{{range $chartKey, $chart := $chartEntries }}
<div class="chart-item">
<h2><a href="{{ (index $chart.Urls 0) }}" title="{{ (index $chart.Urls 0) }}">{{ $chart.Name }}</a></h2>
<div class="chart-versions">
<span class="version-label">Chart Version:</span> {{ $chart.Version }} |
<span class="version-label">App Version:</span> {{ $chart.AppVersion }}
</div>
<p class="chart-description">{{ $chart.Description }}</p>
</div>
{{end}}
{{end}}

</div>
</div>

</body>
</html>

0 comments on commit c5e5285

Please sign in to comment.