From ed5a413f0cb8599cbf11e0d16507663a83dbbaf6 Mon Sep 17 00:00:00 2001 From: sandert-k8s Date: Sat, 11 Jul 2026 12:48:44 +0200 Subject: [PATCH 1/4] chore: set version to v0.13 Signed-off-by: sandert-k8s --- config/_default/params.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/config/_default/params.yaml b/config/_default/params.yaml index e4edfce..e37963e 100644 --- a/config/_default/params.yaml +++ b/config/_default/params.yaml @@ -5,17 +5,15 @@ version_menu: "Releases" # The version number for the version of the docs represented in this doc set. # Used in the "version-banner" partial to display a version number for the # current doc set. -version: latest +version: v0.13 url_latest_version: https://projectcapsule.dev archived_version: false versions: - version: v0.13 - url: https://release-0-13.projectcapsule.dev + url: https://projectcapsule.dev - version: v0.12 url: https://release-0-12.projectcapsule.dev - version: v0.11 url: https://release-0-11.projectcapsule.dev - version: v0.10 url: https://release-0-10.projectcapsule.dev -- version: latest - url: https://projectcapsule.dev From 0608c35034053debd6d0aaf3eedd3fe54774f122 Mon Sep 17 00:00:00 2001 From: sandert-k8s Date: Sat, 11 Jul 2026 12:55:04 +0200 Subject: [PATCH 2/4] feat: add automated PRs when new version is added Signed-off-by: sandert-k8s --- .github/workflows/sync-version-switcher.yml | 149 ++++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 .github/workflows/sync-version-switcher.yml diff --git a/.github/workflows/sync-version-switcher.yml b/.github/workflows/sync-version-switcher.yml new file mode 100644 index 0000000..cd1f9f9 --- /dev/null +++ b/.github/workflows/sync-version-switcher.yml @@ -0,0 +1,149 @@ +name: Sync version switcher to release branches +permissions: {} + +# Triggered automatically when the `version:` field in params.yaml changes on +# main (i.e. a new release is cut), or manually for one-off runs. +on: + push: + branches: [main] + paths: ['config/_default/params.yaml'] + workflow_dispatch: + inputs: + version: + description: 'Version label to add (e.g. v0.14)' + required: true + url: + description: 'URL for this version' + required: true + default: 'https://projectcapsule.dev' + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + sync: + name: Sync version switcher + runs-on: ubuntu-latest + permissions: + contents: write + pull-requests: write + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + + - name: Determine version to sync + id: ver + run: | + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "version=${{ inputs.version }}" >> "$GITHUB_OUTPUT" + echo "url=${{ inputs.url }}" >> "$GITHUB_OUTPUT" + else + # Use github.event.before as the reliable baseline for the push. + # HEAD~1 breaks when multiple commits land in a single push. + OLD=$(git show "${{ github.event.before }}":config/_default/params.yaml 2>/dev/null \ + | grep '^version:' | awk '{print $2}' || echo "") + NEW=$(grep '^version:' config/_default/params.yaml | awk '{print $2}') + if [ "$OLD" = "$NEW" ]; then + echo "Version unchanged ($NEW), nothing to sync" + echo "skip=true" >> "$GITHUB_OUTPUT" + exit 0 + fi + echo "version=$NEW" >> "$GITHUB_OUTPUT" + echo "url=$(grep '^url_latest_version:' config/_default/params.yaml | awk '{print $2}')" \ + >> "$GITHUB_OUTPUT" + fi + + - name: Open PRs for all release branches + if: steps.ver.outputs.skip != 'true' + env: + VERSION: ${{ steps.ver.outputs.version }} + URL: ${{ steps.ver.outputs.url }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + # Sanitize version for use in a branch name (e.g. v0.14 -> 0-14) + VERSION_SLUG=$(echo "$VERSION" | sed 's/^v//;s/\./-/g') + + # Find all versioned release branches (release/0.x), skip preview branches + for branch in $(git branch -r | grep -E 'origin/release/[0-9]' | sed 's|.*origin/||'); do + echo "::group::$branch" + git checkout "$branch" + + WORK_BRANCH="chore/add-${VERSION_SLUG}-to-${branch//\//-}" + + # Determine whether to open a new PR or update an existing one + if git ls-remote --exit-code origin "refs/heads/${WORK_BRANCH}" > /dev/null 2>&1; then + PR_ACTION="update" + else + PR_ACTION="create" + fi + + # Create or reset the work branch to the current release branch HEAD + git checkout -B "$WORK_BRANCH" + + python3 - <<'PYEOF' + import os, re + + version = os.environ['VERSION'] + url = os.environ['URL'] + + with open('config/_default/params.yaml') as f: + content = f.read() + + # Repoint any version still pointing to projectcapsule.dev to its + # frozen release subdomain (it was a previous latest, now archived). + def frozen_url(ver): + slug = ver.lstrip('v').replace('.', '-') + return f"https://release-{slug}.projectcapsule.dev" + + content = re.sub( + r'^(- version: (v[\d.]+)\n url: https://projectcapsule\.dev)$', + lambda m: f"- version: {m.group(2)}\n url: {frozen_url(m.group(2))}", + content, + flags=re.MULTILINE, + ) + + # Insert the new version only if not already present (idempotent). + if not re.search(r'^- version: ' + re.escape(version) + r'$', content, re.MULTILINE): + new_entry = f"- version: {version}\n url: {url}\n" + content = re.sub( + r'(^versions:\n)', + r'\g<1>' + new_entry, + content, + flags=re.MULTILINE, + count=1, + ) + + with open('config/_default/params.yaml', 'w') as f: + f.write(content) + PYEOF + + git add config/_default/params.yaml + if git diff --cached --quiet; then + echo "Already in desired state, skipping" + git checkout "$branch" + echo "::endgroup::" + continue + fi + + git commit -m "chore: add ${VERSION} to version switcher" + git push --force-with-lease origin "$WORK_BRANCH" + + if [ "$PR_ACTION" = "create" ]; then + gh pr create \ + --base "$branch" \ + --head "$WORK_BRANCH" \ + --title "chore: add ${VERSION} to version switcher" \ + --body "Automated PR: adds \`${VERSION}\` to the version switcher in the \`${branch}\` release docs. Triggered by: ${{ github.event_name }} (${{ github.sha }})" + echo "Opened PR: ${WORK_BRANCH} -> ${branch}" + else + echo "Updated PR branch: ${WORK_BRANCH}" + fi + + git checkout "$branch" + echo "::endgroup::" + done From e394a826af77da845a535a05c7ea6037f95c6bd8 Mon Sep 17 00:00:00 2001 From: sandert-k8s Date: Sat, 11 Jul 2026 13:10:47 +0200 Subject: [PATCH 3/4] fix: disable cache so version is dynamic Signed-off-by: sandert-k8s --- config/_default/hugo.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/config/_default/hugo.yaml b/config/_default/hugo.yaml index 8727f74..e1b6b16 100644 --- a/config/_default/hugo.yaml +++ b/config/_default/hugo.yaml @@ -173,3 +173,11 @@ menu: url: /project/ pre: weight: 18 + +# Disable the file-system cache for remote resources (resources.GetRemote). +# Hugo's default is maxAge: -1 (never expire), which causes stale Helm index +# responses to persist across Netlify builds. Setting maxAge to 0 forces a +# fresh fetch on every build so chart versions are always current. +caches: + getresource: + maxAge: 0 From f43b25f0bacfef4dcc74fc1d84c0f9a344946421 Mon Sep 17 00:00:00 2001 From: sandert-k8s Date: Sat, 11 Jul 2026 15:26:34 +0200 Subject: [PATCH 4/4] feat: use GitHub API for verified+signoff commits Signed-off-by: sandert-k8s --- .github/workflows/sync-version-switcher.yml | 80 +++++++++++++++------ 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/.github/workflows/sync-version-switcher.yml b/.github/workflows/sync-version-switcher.yml index cd1f9f9..d3ed174 100644 --- a/.github/workflows/sync-version-switcher.yml +++ b/.github/workflows/sync-version-switcher.yml @@ -1,4 +1,4 @@ -name: Sync version switcher to release branches +name: Sync version switcher permissions: {} # Triggered automatically when the `version:` field in params.yaml changes on @@ -62,16 +62,16 @@ jobs: URL: ${{ steps.ver.outputs.url }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - - # Sanitize version for use in a branch name (e.g. v0.14 -> 0-14) VERSION_SLUG=$(echo "$VERSION" | sed 's/^v//;s/\./-/g') + REPO="${GITHUB_REPOSITORY}" + + # Ensure all remote release branches are available locally + git fetch --prune origin # Find all versioned release branches (release/0.x), skip preview branches for branch in $(git branch -r | grep -E 'origin/release/[0-9]' | sed 's|.*origin/||'); do echo "::group::$branch" - git checkout "$branch" + git checkout -B "$branch" "origin/$branch" WORK_BRANCH="chore/add-${VERSION_SLUG}-to-${branch//\//-}" @@ -82,9 +82,6 @@ jobs: PR_ACTION="create" fi - # Create or reset the work branch to the current release branch HEAD - git checkout -B "$WORK_BRANCH" - python3 - <<'PYEOF' import os, re @@ -122,28 +119,69 @@ jobs: f.write(content) PYEOF - git add config/_default/params.yaml - if git diff --cached --quiet; then - echo "Already in desired state, skipping" - git checkout "$branch" + # Check if there are actual changes vs the release branch HEAD + if git diff --quiet HEAD -- config/_default/params.yaml; then + echo "Already in desired state, skipping ${branch}" + git restore config/_default/params.yaml echo "::endgroup::" continue fi - git commit -m "chore: add ${VERSION} to version switcher" - git push --force-with-lease origin "$WORK_BRANCH" - - if [ "$PR_ACTION" = "create" ]; then + # Save desired content to a temp file (preserves trailing newline) + DESIRED_FILE=$(mktemp) + cat config/_default/params.yaml > "$DESIRED_FILE" + git restore config/_default/params.yaml + + # --- API-based commit (GitHub auto-verifies; no GPG key needed) --- + + # Get the release branch HEAD and its tree + BASE_SHA=$(gh api "repos/${REPO}/branches/${branch}" --jq '.commit.sha') + BASE_TREE_SHA=$(gh api "repos/${REPO}/git/commits/${BASE_SHA}" --jq '.tree.sha') + + # Upload the modified file as a blob + CONTENT_B64=$(base64 -w 0 < "$DESIRED_FILE") + rm -f "$DESIRED_FILE" + BLOB_SHA=$(gh api "repos/${REPO}/git/blobs" \ + -f content="$CONTENT_B64" \ + -f encoding="base64" \ + --jq '.sha') + + # Create a new tree with the updated file + NEW_TREE_SHA=$(jq -n \ + --arg base_tree "$BASE_TREE_SHA" \ + --arg blob "$BLOB_SHA" \ + '{base_tree:$base_tree,tree:[{path:"config/_default/params.yaml",mode:"100644",type:"blob",sha:$blob}]}' | \ + gh api "repos/${REPO}/git/trees" --input - --jq '.sha') + + # Build commit message with Signed-off-by for DCO + COMMIT_MSG=$(printf 'chore: add %s to version switcher in %s\n\nSigned-off-by: github-actions[bot] ' \ + "$VERSION" "$branch") + + # Create the commit (GitHub signs API commits automatically → Verified) + NEW_COMMIT_SHA=$(jq -n \ + --arg msg "$COMMIT_MSG" \ + --arg tree "$NEW_TREE_SHA" \ + --arg parent "$BASE_SHA" \ + '{message:$msg,tree:$tree,parents:[$parent]}' | \ + gh api "repos/${REPO}/git/commits" --input - --jq '.sha') + + # Create or force-update the work branch ref + if [ "$PR_ACTION" = "update" ]; then + gh api "repos/${REPO}/git/refs/heads/${WORK_BRANCH}" \ + -X PATCH -f sha="$NEW_COMMIT_SHA" -F force=true + echo "Updated PR branch: ${WORK_BRANCH}" + else + gh api "repos/${REPO}/git/refs" \ + -f ref="refs/heads/${WORK_BRANCH}" \ + -f sha="$NEW_COMMIT_SHA" gh pr create \ + --repo "$REPO" \ --base "$branch" \ --head "$WORK_BRANCH" \ - --title "chore: add ${VERSION} to version switcher" \ + --title "chore: add ${VERSION} to version switcher in ${branch}" \ --body "Automated PR: adds \`${VERSION}\` to the version switcher in the \`${branch}\` release docs. Triggered by: ${{ github.event_name }} (${{ github.sha }})" echo "Opened PR: ${WORK_BRANCH} -> ${branch}" - else - echo "Updated PR branch: ${WORK_BRANCH}" fi - git checkout "$branch" echo "::endgroup::" done