From 38e481484edcac485427b0ad8ea595d9cc7a7f16 Mon Sep 17 00:00:00 2001 From: DevContainer User Date: Wed, 25 Feb 2026 13:34:56 +0000 Subject: [PATCH 1/3] feat: switch Helm chart publishing from OCI registry to GitHub Pages Replaces OCI push (oci://ghcr.io/cpfarhood/charts) with GitHub Pages Helm repository at https://cpfarhood.github.io/devcontainer. The release workflow now packages the chart, maintains an index.yaml on the gh-pages branch, and auto-creates the branch on first run. Usage: helm repo add devcontainer https://cpfarhood.github.io/devcontainer Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- .github/workflows/release-unified.yaml | 56 +++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-unified.yaml b/.github/workflows/release-unified.yaml index 0e4dae9..750135e 100644 --- a/.github/workflows/release-unified.yaml +++ b/.github/workflows/release-unified.yaml @@ -107,13 +107,55 @@ jobs: cache-to: type=gha,mode=max platforms: linux/amd64 - - name: Package Helm Chart + - name: Package and Publish Helm Chart to GitHub Pages run: | - helm registry login ghcr.io \ - --username ${{ github.actor }} \ - --password ${{ secrets.GITHUB_TOKEN }} + # Package the chart helm package chart/ - helm push devcontainer-${{ steps.version.outputs.version }}.tgz oci://ghcr.io/cpfarhood/charts + + # Checkout or create gh-pages branch in a temporary directory + git worktree add /tmp/gh-pages gh-pages 2>/dev/null || { + git worktree add --detach /tmp/gh-pages + cd /tmp/gh-pages + git checkout --orphan gh-pages + git rm -rf . 2>/dev/null || true + cat > index.html <<'HTMLEOF' + + + Dev Container Helm Chart Repository + +

Dev Container Helm Chart Repository

+

Add this repository to Helm:

+
helm repo add devcontainer https://cpfarhood.github.io/devcontainer
+

Install the chart:

+
helm install mydev devcontainer/devcontainer --set name=mydev
+ + + HTMLEOF + git add index.html + git commit -m "Initialize gh-pages branch" + git push origin gh-pages + cd - + } + + # Copy packaged chart to gh-pages worktree + cp devcontainer-${{ steps.version.outputs.version }}.tgz /tmp/gh-pages/ + + # Update Helm repo index + cd /tmp/gh-pages + if [ -f index.yaml ]; then + helm repo index . --url https://cpfarhood.github.io/devcontainer --merge index.yaml + else + helm repo index . --url https://cpfarhood.github.io/devcontainer + fi + + # Commit and push + git add index.yaml *.tgz index.html 2>/dev/null || true + git commit -m "Publish chart ${{ steps.version.outputs.version }}" + git push origin gh-pages + cd - + + # Clean up worktree + git worktree remove /tmp/gh-pages - name: Generate Release Notes id: notes @@ -139,7 +181,9 @@ jobs: ### Helm Chart \`\`\`bash - helm install devcontainer oci://ghcr.io/cpfarhood/charts/devcontainer --version ${{ steps.version.outputs.version }} + helm repo add devcontainer https://cpfarhood.github.io/devcontainer + helm repo update + helm install mydev devcontainer/devcontainer --version ${{ steps.version.outputs.version }} --set name=mydev \`\`\` EOF From e99ec65cd92f0f130ec19ef1b07cad0174f47d99 Mon Sep 17 00:00:00 2001 From: DevContainer User Date: Wed, 25 Feb 2026 13:38:03 +0000 Subject: [PATCH 2/3] docs: update all references from OCI registry to GitHub Pages Helm repo Update CLAUDE.md, README.md, and workflows README to reference the new GitHub Pages Helm repository at https://cpfarhood.github.io/devcontainer instead of the old OCI registry at oci://ghcr.io/cpfarhood/charts. Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- .github/workflows/README.md | 2 +- CLAUDE.md | 6 ++++-- README.md | 27 +++++++++++++++++---------- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index b0548b3..74dac2d 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -15,7 +15,7 @@ Use this for all version releases: - ✅ Updates chart version - ✅ Creates git tag - ✅ Builds Docker image with all proper tags -- ✅ Publishes Helm chart to GHCR +- ✅ Publishes Helm chart to GitHub Pages (`https://cpfarhood.github.io/devcontainer`) - ✅ Creates GitHub Release with changelog - ✅ No more `[skip ci]` blocking builds! diff --git a/CLAUDE.md b/CLAUDE.md index 4cd405b..5a6ad66 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -190,14 +190,16 @@ helm install my-devcontainer ./chart -f custom-values.yaml ### CI/CD -- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. For version tags, also creates GitHub Release with Helm chart after Docker build completes. Tags: `latest` (main), semver, branch name, commit SHA. +- **`build-and-push.yaml`** — Builds and pushes to GHCR on every push to `main`, version tags (`v*`), and PRs. Tags: `latest` (main), semver, branch name, commit SHA. +- **`release-unified.yaml`** — Manual release workflow: bumps chart version, builds Docker image, publishes Helm chart to GitHub Pages (`https://cpfarhood.github.io/devcontainer`), and creates GitHub Release. - **`dependabot.yml`** — Weekly updates for GitHub Actions and Docker base image. Image registry: `ghcr.io/cpfarhood/devcontainer` +Helm repo: `https://cpfarhood.github.io/devcontainer` ## Kubernetes Notes -- Deployed via Helm chart (`chart/`), published as OCI artifact to GHCR, reconciled by Flux +- Deployed via Helm chart (`chart/`), published to GitHub Pages Helm repo, reconciled by Flux - Storage class is `ceph-filesystem` by default — change via `storage.className` in values - Resource limits: 1–4 CPU, 2–8Gi memory - Health checks (liveness/readiness probes) on port 5800 diff --git a/README.md b/README.md index 659aa64..1da476f 100644 --- a/README.md +++ b/README.md @@ -14,23 +14,30 @@ A containerized cloud development environment with web-based GUI access, featuri ## Quick Start -### Option A: Quickstart (Recommended) - -For 80% of users, use the simplified quickstart values: +### Option A: Install from Helm Repo (Recommended) ```bash -# Copy and customize the quickstart template +# Add the Helm repository +helm repo add devcontainer https://cpfarhood.github.io/devcontainer +helm repo update + +# Deploy with one command +helm install mydev devcontainer/devcontainer \ + --set name=mydev \ + --set githubRepo=https://github.com/youruser/yourrepo +``` + +### Option B: Install from Source + +```bash +# Clone and customize the quickstart template cp chart/values-quickstart.yaml my-values.yaml +# Edit my-values.yaml to set your name and repository -# Edit my-values.yaml to set your name and repository: -# name: mydev -# githubRepo: https://github.com/youruser/yourrepo - -# Deploy with minimal configuration helm install mydev ./chart -f my-values.yaml ``` -### Option B: One-Command Deploy +### Option C: One-Command from Source ```bash helm install mydev ./chart \ From da40d57e079a4f4fc6b80d74a8312009ba2b2f62 Mon Sep 17 00:00:00 2001 From: DevContainer User Date: Wed, 25 Feb 2026 13:53:58 +0000 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20overhaul=20release=20pipeline=20?= =?UTF-8?q?=E2=80=94=205=20issues=20resolved?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. version input now optional — auto-increment from release_type works 2. replaced deprecated actions/create-release@v1 with gh release create 3. race condition fixed — release commit uses [skip ci], removed fragile github.actor guard from build-and-push.yaml 4. simplified gh-pages publishing — uses clean temp dir + shallow clone instead of convoluted git worktree fallback 5. version parsing strips pre-release suffixes (e.g., 2.0.0-dev → 2.0.0) Generated with [Claude Code](https://claude.ai/code) via [Happy](https://happy.engineering) Co-Authored-By: Claude Co-Authored-By: Happy --- .github/workflows/README.md | 5 +- .github/workflows/build-and-push.yaml | 3 - .github/workflows/release-unified.yaml | 122 +++++++++++-------------- 3 files changed, 56 insertions(+), 74 deletions(-) diff --git a/.github/workflows/README.md b/.github/workflows/README.md index 74dac2d..d8e192b 100644 --- a/.github/workflows/README.md +++ b/.github/workflows/README.md @@ -17,7 +17,6 @@ Use this for all version releases: - ✅ Builds Docker image with all proper tags - ✅ Publishes Helm chart to GitHub Pages (`https://cpfarhood.github.io/devcontainer`) - ✅ Creates GitHub Release with changelog -- ✅ No more `[skip ci]` blocking builds! ### 2️⃣ For Quick Fixes → **Quick Fix Build** Use this for emergency fixes without version changes: @@ -30,8 +29,8 @@ Use this for emergency fixes without version changes: ### 3️⃣ Automatic CI → **Build and Push** Runs automatically on: +- Pushes to `main` (builds and pushes; skipped for release commits via `[skip ci]`) - Pull requests (builds but doesn't push) -- Tags starting with `v*` (builds and pushes) - Manual trigger available ## Workflow Files @@ -90,5 +89,5 @@ gh run watch ### After (Simple! 🎉) - **3 total workflows** (down from 6+) - **1 button** for complete releases -- **No more `[skip ci]`** blocking builds +- Release builds its own Docker image — `[skip ci]` on the version commit prevents duplicate CI builds - **Clear separation** of concerns \ No newline at end of file diff --git a/.github/workflows/build-and-push.yaml b/.github/workflows/build-and-push.yaml index f5ee2ad..20ac734 100644 --- a/.github/workflows/build-and-push.yaml +++ b/.github/workflows/build-and-push.yaml @@ -16,9 +16,6 @@ env: jobs: build-and-push: runs-on: ubuntu-latest - # Skip builds triggered by release-unified.yaml commits (github-actions[bot]) - # to prevent racing with the release workflow's own Docker build - if: github.event_name == 'workflow_dispatch' || github.event_name == 'pull_request' || github.actor != 'github-actions[bot]' permissions: contents: read packages: write diff --git a/.github/workflows/release-unified.yaml b/.github/workflows/release-unified.yaml index 750135e..0a4552c 100644 --- a/.github/workflows/release-unified.yaml +++ b/.github/workflows/release-unified.yaml @@ -4,11 +4,11 @@ on: workflow_dispatch: inputs: version: - description: 'Version to release (e.g., 0.1.25)' - required: true + description: 'Explicit version (e.g., 1.2.3). Leave blank to auto-increment.' + required: false type: string release_type: - description: 'Release type' + description: 'Release type (used when version is blank)' required: true default: 'patch' type: choice @@ -49,37 +49,34 @@ jobs: - name: Determine Version id: version run: | - if [ "${{ github.event.inputs.version }}" != "" ]; then - VERSION="${{ github.event.inputs.version }}" + INPUT_VERSION="${{ github.event.inputs.version }}" + if [ -n "$INPUT_VERSION" ]; then + VERSION="$INPUT_VERSION" else - # Auto-determine next version based on release type + # Auto-increment based on release_type CURRENT=$(grep '^version:' chart/Chart.yaml | awk '{print $2}') - MAJOR=$(echo $CURRENT | cut -d. -f1) - MINOR=$(echo $CURRENT | cut -d. -f2) - PATCH=$(echo $CURRENT | cut -d. -f3) + # Strip any pre-release suffix (e.g., 2.0.0-dev -> 2.0.0) + CURRENT=$(echo "$CURRENT" | sed 's/-.*//') + MAJOR=$(echo "$CURRENT" | cut -d. -f1) + MINOR=$(echo "$CURRENT" | cut -d. -f2) + PATCH=$(echo "$CURRENT" | cut -d. -f3) case "${{ github.event.inputs.release_type }}" in - major) - VERSION="$((MAJOR + 1)).0.0" - ;; - minor) - VERSION="${MAJOR}.$((MINOR + 1)).0" - ;; - patch) - VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" - ;; + major) VERSION="$((MAJOR + 1)).0.0" ;; + minor) VERSION="${MAJOR}.$((MINOR + 1)).0" ;; + patch) VERSION="${MAJOR}.${MINOR}.$((PATCH + 1))" ;; esac fi echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "tag=v${VERSION}" >> $GITHUB_OUTPUT - echo "🚀 Releasing version ${VERSION}" + echo "Releasing version ${VERSION}" - name: Update Chart Version run: | sed -i "s/^version: .*/version: ${{ steps.version.outputs.version }}/" chart/Chart.yaml git add chart/Chart.yaml - git diff --quiet --staged || git commit -m "chore: release version ${{ steps.version.outputs.version }}" + git diff --quiet --staged || git commit -m "chore(release): ${{ steps.version.outputs.version }} [skip ci]" - name: Create and Push Tag run: | @@ -107,18 +104,25 @@ jobs: cache-to: type=gha,mode=max platforms: linux/amd64 - - name: Package and Publish Helm Chart to GitHub Pages + - name: Publish Helm Chart to GitHub Pages run: | - # Package the chart helm package chart/ + CHART_TGZ="devcontainer-${{ steps.version.outputs.version }}.tgz" - # Checkout or create gh-pages branch in a temporary directory - git worktree add /tmp/gh-pages gh-pages 2>/dev/null || { - git worktree add --detach /tmp/gh-pages - cd /tmp/gh-pages - git checkout --orphan gh-pages - git rm -rf . 2>/dev/null || true - cat > index.html <<'HTMLEOF' + # Set up gh-pages in a temporary directory + PAGES_DIR=$(mktemp -d) + if git ls-remote --heads origin gh-pages | grep -q gh-pages; then + # gh-pages exists — shallow clone just that branch + git clone --single-branch --branch gh-pages \ + "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" \ + "$PAGES_DIR" + else + # First time — initialize gh-pages + git init "$PAGES_DIR" + git -C "$PAGES_DIR" checkout --orphan gh-pages + git -C "$PAGES_DIR" remote add origin \ + "https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git" + cat > "$PAGES_DIR/index.html" <<'HTMLEOF' Dev Container Helm Chart Repository @@ -131,45 +135,38 @@ jobs: HTMLEOF - git add index.html - git commit -m "Initialize gh-pages branch" - git push origin gh-pages - cd - - } + fi - # Copy packaged chart to gh-pages worktree - cp devcontainer-${{ steps.version.outputs.version }}.tgz /tmp/gh-pages/ + git -C "$PAGES_DIR" config user.name "github-actions[bot]" + git -C "$PAGES_DIR" config user.email "github-actions[bot]@users.noreply.github.com" - # Update Helm repo index - cd /tmp/gh-pages - if [ -f index.yaml ]; then - helm repo index . --url https://cpfarhood.github.io/devcontainer --merge index.yaml + # Copy chart package and rebuild index + cp "$CHART_TGZ" "$PAGES_DIR/" + if [ -f "$PAGES_DIR/index.yaml" ]; then + helm repo index "$PAGES_DIR" --url https://cpfarhood.github.io/devcontainer --merge "$PAGES_DIR/index.yaml" else - helm repo index . --url https://cpfarhood.github.io/devcontainer + helm repo index "$PAGES_DIR" --url https://cpfarhood.github.io/devcontainer fi # Commit and push - git add index.yaml *.tgz index.html 2>/dev/null || true - git commit -m "Publish chart ${{ steps.version.outputs.version }}" - git push origin gh-pages - cd - + git -C "$PAGES_DIR" add . + git -C "$PAGES_DIR" commit -m "Publish chart ${{ steps.version.outputs.version }}" + git -C "$PAGES_DIR" push origin gh-pages - # Clean up worktree - git worktree remove /tmp/gh-pages - - - name: Generate Release Notes - id: notes + - name: Create GitHub Release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - # Get commits since last tag + # Build release notes PREV_TAG=$(git describe --tags --abbrev=0 HEAD^ 2>/dev/null || echo "") if [ -z "$PREV_TAG" ]; then COMMITS=$(git log --pretty=format:"- %s (%h)" HEAD) else - COMMITS=$(git log --pretty=format:"- %s (%h)" ${PREV_TAG}..HEAD) + COMMITS=$(git log --pretty=format:"- %s (%h)" "${PREV_TAG}..HEAD") fi - cat << EOF > release-notes.md - ## 🚀 Release ${{ steps.version.outputs.version }} + cat > release-notes.md <> $GITHUB_OUTPUT - cat release-notes.md >> $GITHUB_OUTPUT - echo "EOF" >> $GITHUB_OUTPUT - - - name: Create GitHub Release - uses: actions/create-release@v1 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - tag_name: ${{ steps.version.outputs.tag }} - release_name: Release ${{ steps.version.outputs.tag }} - body: ${{ steps.notes.outputs.notes }} - draft: false - prerelease: false \ No newline at end of file + gh release create "${{ steps.version.outputs.tag }}" \ + --title "Release ${{ steps.version.outputs.tag }}" \ + --notes-file release-notes.md