4141 normal builds.
4242 type : string
4343 default : ' '
44+ publish_chart :
45+ description : >-
46+ After the image push, also auto-bump the Helm chart patch version,
47+ commit the update back to this branch, and publish the chart as an
48+ OCI artifact. Skipped automatically on partial builds and override
49+ tags. For non-patch bumps build the chart manually per BUILD.md.
50+ type : boolean
51+ default : false
4452
4553env :
4654 REPO : a0533057932/redis-docs
6573 rs_versions : ${{ steps.matrix.outputs.rs }}
6674 redisvl_versions : ${{ steps.matrix.outputs.redisvl }}
6775 steps :
68- - uses : actions/checkout@v4
76+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
6977
7078 - name : Compute build params
7179 id : meta
@@ -211,7 +219,7 @@ jobs:
211219 permissions :
212220 contents : read
213221 steps :
214- - uses : actions/checkout@v4
222+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
215223 with :
216224 fetch-depth : 0 # full history for Hugo's enableGitInfo
217225
@@ -226,7 +234,7 @@ jobs:
226234
227235 - name : Restore node_modules
228236 id : cache-npm
229- uses : actions/cache@v4
237+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
230238 with :
231239 path : node_modules
232240 key : npm-${{ runner.os }}-${{ hashFiles('package.json', 'package-lock.json') }}
@@ -237,7 +245,7 @@ jobs:
237245
238246 - name : Restore python venv
239247 id : cache-pip
240- uses : actions/cache@v4
248+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
241249 with :
242250 path : ./venv
243251 key : pip-${{ runner.os }}-${{ hashFiles('requirements.txt') }}
@@ -250,7 +258,7 @@ jobs:
250258
251259 - name : Restore examples + data/examples.json
252260 id : cache-examples
253- uses : actions/cache@v4
261+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
254262 with :
255263 path : |
256264 examples
@@ -322,7 +330,7 @@ jobs:
322330
323331 - name : Restore Hugo output cache
324332 id : cache-hugo
325- uses : actions/cache@v4
333+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
326334 with :
327335 path : output
328336 key : hugo-latest-${{ steps.key.outputs.key }}
@@ -343,7 +351,7 @@ jobs:
343351 - name : Stage output as artifact
344352 run : tar -czf /tmp/out.tar.gz output
345353
346- - uses : actions/upload-artifact@v4
354+ - uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
347355 with :
348356 name : build-latest
349357 path : /tmp/out.tar.gz
@@ -375,7 +383,7 @@ jobs:
375383 matrix :
376384 include : ${{ fromJSON(needs.setup.outputs.matrix) }}
377385 steps :
378- - uses : actions/checkout@v4
386+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
379387 with :
380388 fetch-depth : 0
381389
@@ -390,7 +398,7 @@ jobs:
390398
391399 - name : Restore node_modules
392400 id : cache-npm
393- uses : actions/cache@v4
401+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
394402 with :
395403 path : node_modules
396404 key : npm-${{ runner.os }}-${{ hashFiles('package.json', 'package-lock.json') }}
@@ -401,7 +409,7 @@ jobs:
401409
402410 - name : Restore python venv
403411 id : cache-pip
404- uses : actions/cache@v4
412+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
405413 with :
406414 path : ./venv
407415 key : pip-${{ runner.os }}-${{ hashFiles('requirements.txt') }}
@@ -414,7 +422,7 @@ jobs:
414422
415423 - name : Restore examples + data/examples.json
416424 id : cache-examples
417- uses : actions/cache@v4
425+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
418426 with :
419427 path : |
420428 examples
@@ -485,7 +493,7 @@ jobs:
485493
486494 - name : Restore Hugo output cache
487495 id : cache-hugo
488- uses : actions/cache@v4
496+ uses : actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
489497 with :
490498 path : output
491499 key : hugo-${{ matrix.name }}-${{ steps.key.outputs.key }}
@@ -555,7 +563,7 @@ jobs:
555563 done
556564 tar -czf /tmp/out.tar.gz -C /tmp/stage output
557565
558- - uses : actions/upload-artifact@v4
566+ - uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
559567 with :
560568 name : build-${{ matrix.name }}
561569 path : /tmp/out.tar.gz
@@ -572,7 +580,7 @@ jobs:
572580 permissions :
573581 contents : read
574582 steps :
575- - uses : actions/checkout@v4
583+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
576584
577585 - name : Install system deps
578586 run : sudo apt-get install -y --no-install-recommends rsync python3-venv
@@ -582,7 +590,7 @@ jobs:
582590 python3 -m venv /tmp/venv
583591 /tmp/venv/bin/pip install --quiet -r requirements.txt
584592
585- - uses : actions/download-artifact@v4
593+ - uses : actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
586594 with :
587595 path : /tmp/builds
588596 pattern : build-*
@@ -636,7 +644,7 @@ jobs:
636644 tar -czf /tmp/public.tar.gz public
637645 echo "Files: $(find public -type f | wc -l), Size: $(du -sh public | cut -f1)"
638646
639- - uses : actions/upload-artifact@v4
647+ - uses : actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
640648 with :
641649 name : public
642650 path : /tmp/public.tar.gz
@@ -657,13 +665,13 @@ jobs:
657665 permissions :
658666 contents : read
659667 steps :
660- - uses : actions/checkout@v4
668+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
661669 with :
662670 sparse-checkout : |
663671 Dockerfile.runtime
664672 sparse-checkout-cone-mode : false
665673
666- - uses : actions/download-artifact@v4
674+ - uses : actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
667675 with :
668676 name : public
669677 path : /tmp/
@@ -673,21 +681,21 @@ jobs:
673681
674682 - name : Set up QEMU
675683 if : inputs.platforms != 'amd64'
676- uses : docker/setup-qemu-action@v4
684+ uses : docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
677685 with :
678686 platforms : arm64
679687
680- - uses : docker/setup-buildx-action@v4
688+ - uses : docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
681689
682- - uses : docker/login-action@v4
690+ - uses : docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
683691 with :
684692 username : ${{ vars.DOCKERHUB_USERNAME }}
685693 password : ${{ secrets.DOCKERHUB_TOKEN }}
686694
687695 - name : Build & push privileged
688696 id : push_priv
689697 if : inputs.variant != 'unprivileged'
690- uses : docker/build-push-action@v7
698+ uses : docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
691699 with :
692700 context : .
693701 file : Dockerfile.runtime
@@ -703,7 +711,7 @@ jobs:
703711 - name : Build & push unprivileged
704712 id : push_unpriv
705713 if : inputs.variant != 'privileged'
706- uses : docker/build-push-action@v7
714+ uses : docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
707715 with :
708716 context : .
709717 file : Dockerfile.runtime
@@ -794,3 +802,147 @@ jobs:
794802 echo '```'
795803 fi
796804 } >> "$GITHUB_STEP_SUMMARY"
805+
806+ # =========================================================================
807+ # Phase 5: publish_chart — opt-in.
808+ # Order: bump files -> git commit & push -> helm publish to OCI.
809+ # If helm publish fails the bump is already in git; rerun helm push by hand.
810+ # Skipped on partial builds (variant/platforms != both, or tag_override set).
811+ # =========================================================================
812+ publish_chart :
813+ name : 5. Publish Helm chart (opt-in)
814+ needs : [setup, docker]
815+ if : >-
816+ inputs.publish_chart &&
817+ inputs.variant == 'both' &&
818+ inputs.platforms == 'both' &&
819+ inputs.tag_override == ''
820+ runs-on : ubuntu-24.04
821+ permissions :
822+ contents : write
823+ steps :
824+ # Default ref (github.ref) and persist-credentials (true) are what we
825+ # need: git-auto-commit-action reuses the auth header to push back to
826+ # this branch.
827+ - uses : actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
828+
829+ - name : Bump chart files
830+ id : bump
831+ env :
832+ NEW_HASH : ${{ needs.setup.outputs.hash }}
833+ run : |
834+ set -euo pipefail
835+ CHART=helm/redis-docs/Chart.yaml
836+
837+ # NEW_HASH is interpolated into sed below, so it must match the
838+ # setup phase's convention exactly (git rev-parse --short=9). A
839+ # malformed hash here would corrupt every targeted line.
840+ if [[ ! "$NEW_HASH" =~ ^[a-f0-9]{9}$ ]]; then
841+ echo "::error::NEW_HASH '$NEW_HASH' is not 9-char lowercase hex. Setup phase produced an unexpected value."
842+ exit 1
843+ fi
844+
845+ OLD_VERSION=$(grep '^version:' "$CHART" | awk '{print $2}')
846+ OLD_HASH=$(sed -nE 's/^appVersion:[[:space:]]*"([^"]+)".*/\1/p' "$CHART")
847+
848+ # OLD_VERSION drives the patch increment ($((PATCH + 1))), so any
849+ # non-X.Y.Z form crashes the arithmetic mid-bump. Reject early.
850+ if [[ ! "$OLD_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
851+ echo "::error::version '$OLD_VERSION' is not plain X.Y.Z. Pre-release / build-meta suffixes are not auto-bumped — bump manually per BUILD.md step 5."
852+ exit 1
853+ fi
854+
855+ # OLD_HASH is used only for the same-hash skip check; it is no
856+ # longer interpolated into sed, so loose validation suffices.
857+ if [ -z "$OLD_HASH" ]; then
858+ echo "::error::Could not read appVersion from $CHART. Format may have changed."
859+ exit 1
860+ fi
861+
862+ {
863+ echo "old_version=$OLD_VERSION"
864+ echo "old_hash=$OLD_HASH"
865+ } >> "$GITHUB_OUTPUT"
866+
867+ if [ "$OLD_HASH" = "$NEW_HASH" ]; then
868+ echo "appVersion already $NEW_HASH — nothing to publish."
869+ echo "changed=false" >> "$GITHUB_OUTPUT"
870+ exit 0
871+ fi
872+
873+ IFS=. read -r MAJ MIN PATCH <<<"$OLD_VERSION"
874+ NEW_VERSION="$MAJ.$MIN.$((PATCH + 1))"
875+
876+ # Context-aware replacements. Each pattern matches exactly the
877+ # lines BUILD.md step 5 lists, so a stray hex string elsewhere in
878+ # these files (release notes, examples, etc.) can't be corrupted.
879+ sed -i -E "s/^appVersion:[[:space:]]*\"[a-f0-9]+\"/appVersion: \"${NEW_HASH}\"/" "$CHART"
880+ sed -i -E "s/[a-f0-9]+-unprivileged/${NEW_HASH}-unprivileged/g" \
881+ helm/redis-docs/examples/values-openshift-airgapped.yaml \
882+ helm/redis-docs/README.md \
883+ helm/redis-docs/README-he.md
884+ sed -i "s/^version: .*/version: ${NEW_VERSION}/" "$CHART"
885+
886+ {
887+ echo "new_version=$NEW_VERSION"
888+ echo "new_hash=$NEW_HASH"
889+ echo "changed=true"
890+ } >> "$GITHUB_OUTPUT"
891+
892+ # Skip when the bump step short-circuited (changed=false because the
893+ # appVersion was already current). GHA implicitly ANDs success() with
894+ # any step-level `if:` that does not contain a status function — no
895+ # need to repeat it here.
896+ - name : Commit bump
897+ if : steps.bump.outputs.changed == 'true'
898+ uses : stefanzweifel/git-auto-commit-action@04702edda442b2e678b25b537cec683a1493fcb9 # v7.1.0
899+ with :
900+ commit_message : " chore(helm): bump chart ${{ steps.bump.outputs.new_version }}, appVersion ${{ steps.bump.outputs.new_hash }}"
901+ file_pattern : helm/redis-docs/
902+
903+ - name : Publish chart to OCI
904+ if : steps.bump.outputs.changed == 'true'
905+ uses : appany/helm-oci-chart-releaser@d94988c92bed2e09c6113981f15f8bb495d10943 # v0.5.0
906+ with :
907+ name : redis-docs
908+ repository : ${{ vars.DOCKERHUB_USERNAME }}
909+ tag : ${{ steps.bump.outputs.new_version }}
910+ path : helm/redis-docs
911+ registry : registry-1.docker.io
912+ registry_username : ${{ vars.DOCKERHUB_USERNAME }}
913+ registry_password : ${{ secrets.DOCKERHUB_TOKEN }}
914+
915+ - name : Write chart summary
916+ if : always()
917+ env :
918+ STATUS : ${{ job.status }}
919+ CHANGED : ${{ steps.bump.outputs.changed }}
920+ OLD_VERSION : ${{ steps.bump.outputs.old_version }}
921+ NEW_VERSION : ${{ steps.bump.outputs.new_version }}
922+ NEW_HASH : ${{ steps.bump.outputs.new_hash }}
923+ DOCKERHUB_USERNAME : ${{ vars.DOCKERHUB_USERNAME }}
924+ run : |
925+ {
926+ echo ""
927+ echo "## Helm chart publish: \`$STATUS\`"
928+ echo ""
929+ if [ "$STATUS" = "success" ] && [ "$CHANGED" = "true" ]; then
930+ echo "| Field | Value |"
931+ echo "|-------|-------|"
932+ echo "| version | \`$OLD_VERSION\` → \`$NEW_VERSION\` |"
933+ echo "| appVersion | \`$NEW_HASH\` |"
934+ echo "| OCI ref | \`oci://registry-1.docker.io/$DOCKERHUB_USERNAME/redis-docs:$NEW_VERSION\` |"
935+ elif [ "$STATUS" = "success" ]; then
936+ echo "Chart appVersion already up to date — nothing pushed."
937+ elif [ "$CHANGED" = "true" ]; then
938+ echo "⚠️ Bump committed (or attempted) but a later step failed."
939+ echo ""
940+ echo "If \`Commit bump\` succeeded but \`Publish chart\` failed, run manually:"
941+ echo '```bash'
942+ echo "helm package helm/redis-docs/ -d /tmp/"
943+ echo "helm push /tmp/redis-docs-${NEW_VERSION}.tgz oci://registry-1.docker.io/$DOCKERHUB_USERNAME"
944+ echo '```'
945+ else
946+ echo "❌ Bump step failed (validation or sed) — nothing committed, nothing published. See step logs."
947+ fi
948+ } >> "$GITHUB_STEP_SUMMARY"
0 commit comments