|
| 1 | +name: Release Please |
| 2 | + |
| 3 | +# Release Please maintains one open "release PR" per chart. Merging a chart's PR stamps its |
| 4 | +# changelog, bumps its Chart.yaml, tags `<chart>-vX.Y.Z` and creates the GitHub Release — then the |
| 5 | +# publish job below packages that one chart and pushes it to the Helm repo index and GHCR. |
| 6 | +# |
| 7 | +# Per-chart releases fall out of `packages` in release-please-config.json: Release Please decides |
| 8 | +# what to bump from the FILE PATHS a commit touches, not from the commit scope. A commit touching |
| 9 | +# only charts/ontoserver-indexer opens a release PR for the indexer alone. `separate-pull-requests` |
| 10 | +# keeps them independent so one chart can be released without dragging the others along. |
| 11 | +on: |
| 12 | + push: |
| 13 | + branches: [master] |
| 14 | + workflow_dispatch: |
| 15 | + |
| 16 | +permissions: |
| 17 | + contents: write |
| 18 | + pull-requests: write |
| 19 | + |
| 20 | +# Shares a group with the tag-triggered release.yml: both rewrite index.yaml on gh-pages, and two |
| 21 | +# concurrent runs would clobber each other's entry. |
| 22 | +concurrency: |
| 23 | + group: release-charts |
| 24 | + cancel-in-progress: false |
| 25 | + |
| 26 | +jobs: |
| 27 | + release-please: |
| 28 | + name: Maintain release PRs |
| 29 | + runs-on: ubuntu-latest |
| 30 | + outputs: |
| 31 | + # `paths_released` is a JSON array of the package paths released by this run — the switch the |
| 32 | + # publish job fans out over. |
| 33 | + paths_released: ${{ steps.release.outputs.paths_released }} |
| 34 | + steps: |
| 35 | + - uses: googleapis/release-please-action@v4 |
| 36 | + id: release |
| 37 | + with: |
| 38 | + config-file: release-please-config.json |
| 39 | + manifest-file: .release-please-manifest.json |
| 40 | + |
| 41 | + publish: |
| 42 | + name: Publish ${{ matrix.path }} |
| 43 | + needs: release-please |
| 44 | + if: needs.release-please.outputs.paths_released != '[]' && needs.release-please.outputs.paths_released != '' |
| 45 | + runs-on: ubuntu-latest |
| 46 | + strategy: |
| 47 | + # Serial on purpose: every chart's publish rewrites the same gh-pages index.yaml. |
| 48 | + max-parallel: 1 |
| 49 | + matrix: |
| 50 | + path: ${{ fromJson(needs.release-please.outputs.paths_released) }} |
| 51 | + permissions: |
| 52 | + contents: write |
| 53 | + packages: write |
| 54 | + steps: |
| 55 | + - uses: actions/checkout@v5 |
| 56 | + with: |
| 57 | + fetch-depth: 0 |
| 58 | + |
| 59 | + # Publishing happens here rather than in the tag-triggered release.yml because a tag created |
| 60 | + # with GITHUB_TOKEN does NOT trigger other workflows. release.yml would simply never run for a |
| 61 | + # Release Please tag, and the chart would be tagged and released on GitHub but never appear in |
| 62 | + # the Helm repo index or GHCR — a silent half-release. |
| 63 | + - name: Resolve chart and version |
| 64 | + id: chart |
| 65 | + env: |
| 66 | + PKG_PATH: ${{ matrix.path }} |
| 67 | + run: | |
| 68 | + set -euo pipefail |
| 69 | + chart="$(basename "$PKG_PATH")" |
| 70 | + version="$(python3 -c "import json,sys; print(json.load(open('.release-please-manifest.json'))['$PKG_PATH'])")" |
| 71 | + echo "chart=$chart" >> "$GITHUB_OUTPUT" |
| 72 | + echo "version=$version" >> "$GITHUB_OUTPUT" |
| 73 | + echo "tag=${chart}-v${version}" >> "$GITHUB_OUTPUT" |
| 74 | + echo "Publishing $chart $version" |
| 75 | +
|
| 76 | + # Same gate as release.yml: never publish a chart whose commit did not pass the suites. Here |
| 77 | + # the tests run against the release-PR merge commit in parallel with this workflow, so this |
| 78 | + # almost always waits a few minutes rather than finding a finished run. |
| 79 | + - name: Require successful Unit and Integration test runs |
| 80 | + env: |
| 81 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 82 | + REPO: ${{ github.repository }} |
| 83 | + SHA: ${{ github.sha }} |
| 84 | + run: | |
| 85 | + set -euo pipefail |
| 86 | + query() { |
| 87 | + gh api "repos/${REPO}/actions/runs?head_sha=${SHA}&per_page=100" \ |
| 88 | + --jq "[.workflow_runs[] | select(.name == \"$1\")] | sort_by(.created_at) | last |
| 89 | + | if . == null then \"none none\" else \"\(.status) \(.conclusion // \"pending\")\" end" |
| 90 | + } |
| 91 | + for wf in "Unit Tests" "Integration Tests"; do |
| 92 | + status=""; conclusion="" |
| 93 | + for attempt in $(seq 1 40); do |
| 94 | + read -r status conclusion <<<"$(query "$wf")" |
| 95 | + [[ "$status" == "completed" ]] && break |
| 96 | + echo "'${wf}' is ${status}; waiting (attempt ${attempt}/40)..." |
| 97 | + sleep 30 |
| 98 | + done |
| 99 | + if [[ "$status" != "completed" || "$conclusion" != "success" ]]; then |
| 100 | + echo "::error::'${wf}' for ${SHA} is ${status}/${conclusion}. Refusing to publish. Re-run this workflow once the suites are green." |
| 101 | + exit 1 |
| 102 | + fi |
| 103 | + echo "'${wf}': success" |
| 104 | + done |
| 105 | +
|
| 106 | + - name: Install Helm |
| 107 | + uses: azure/setup-helm@v5.0.1 |
| 108 | + with: |
| 109 | + version: v3.18.4 |
| 110 | + |
| 111 | + - name: Package chart |
| 112 | + run: | |
| 113 | + set -euo pipefail |
| 114 | + helm dependency build "charts/${{ steps.chart.outputs.chart }}" |
| 115 | + mkdir -p .cr-release-packages |
| 116 | + helm package "charts/${{ steps.chart.outputs.chart }}" -d .cr-release-packages |
| 117 | +
|
| 118 | + - name: Attach the package to the GitHub Release |
| 119 | + env: |
| 120 | + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} |
| 121 | + run: | |
| 122 | + gh release upload "${{ steps.chart.outputs.tag }}" \ |
| 123 | + ".cr-release-packages/${{ steps.chart.outputs.chart }}-${{ steps.chart.outputs.version }}.tgz" \ |
| 124 | + --clobber |
| 125 | +
|
| 126 | + - name: Push to GHCR |
| 127 | + run: | |
| 128 | + echo "${{ secrets.GITHUB_TOKEN }}" | helm registry login ghcr.io \ |
| 129 | + --username "${{ github.actor }}" --password-stdin |
| 130 | + helm push \ |
| 131 | + ".cr-release-packages/${{ steps.chart.outputs.chart }}-${{ steps.chart.outputs.version }}.tgz" \ |
| 132 | + "oci://ghcr.io/aehrc/${{ steps.chart.outputs.chart }}-helm" |
| 133 | +
|
| 134 | + # --merge, not a fresh index: index.yaml carries every previously released chart and version, |
| 135 | + # and regenerating it from this one package would delete all of them. |
| 136 | + - name: Update the gh-pages Helm repo index |
| 137 | + env: |
| 138 | + CHART: ${{ steps.chart.outputs.chart }} |
| 139 | + VERSION: ${{ steps.chart.outputs.version }} |
| 140 | + TAG: ${{ steps.chart.outputs.tag }} |
| 141 | + run: | |
| 142 | + set -euo pipefail |
| 143 | + git config user.name "$GITHUB_ACTOR" |
| 144 | + git config user.email "$GITHUB_ACTOR@users.noreply.github.com" |
| 145 | + git fetch origin gh-pages |
| 146 | + git worktree add gh-pages origin/gh-pages |
| 147 | +
|
| 148 | + helm repo index .cr-release-packages \ |
| 149 | + --url "https://github.com/${{ github.repository }}/releases/download/${TAG}" \ |
| 150 | + --merge gh-pages/index.yaml |
| 151 | + mv .cr-release-packages/index.yaml gh-pages/index.yaml |
| 152 | +
|
| 153 | + cp artifacthub-repo.yml gh-pages/artifacthub-repo.yml |
| 154 | + if [ -f gh-pages/index.html ]; then |
| 155 | + sed -i "s|data-chart=\"${CHART}\">[0-9][0-9.]*<|data-chart=\"${CHART}\">${VERSION}<|g" gh-pages/index.html |
| 156 | + fi |
| 157 | +
|
| 158 | + cd gh-pages |
| 159 | + git add index.yaml artifacthub-repo.yml |
| 160 | + [ -f index.html ] && git add index.html |
| 161 | + git diff --staged --quiet || git commit -m "Release ${CHART} ${VERSION} [skip ci]" |
| 162 | + git push origin HEAD:gh-pages |
0 commit comments