Add release bot#77
Conversation
There was a problem hiding this comment.
Pull request overview
Adds an automated “release bot” GitHub Actions workflow to manage release PR creation/updates, version bumping, and post-merge publishing/tagging, while cleaning up older Helm publishing automation.
Changes:
- Introduces
.github/workflows/release-bot.ymlto generate/update a release PR (changelog, Chart.yaml version/appVersion, README updates) and, on merge, tag + publish chart to GHCR + create a GitHub release. - Removes the manual Helm publishing workflow (
.github/workflows/publish-helm-charts.yml). - Minor README formatting fix; adds an empty
test.txt.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| README.md | Minor formatting adjustment in Quick Start section. |
| .github/workflows/release-bot.yml | New release automation workflow (release PR generation + tagging + Helm publish + GitHub release). |
| .github/workflows/publish-helm-charts.yml | Deletes the old manual Helm publishing workflow in favor of the new bot. |
| test.txt | Adds an empty file (no functional impact). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| BEGIN { skip = 0 } | ||
| /<!-- release-bot:start -->/ { | ||
| print "" | ||
| while ((getline line < "CHANGELOG_SECTION.md") > 0) print line | ||
| print "" | ||
| skip = 1 | ||
| next | ||
| } | ||
| /<!-- release-bot:end -->/ { | ||
| skip = 0 | ||
| next | ||
| } | ||
| skip == 0 { print } |
There was a problem hiding this comment.
The changelog update logic replaces everything between <!-- release-bot:start --> and <!-- release-bot:end --> with only the newly generated CHANGELOG_SECTION.md. On subsequent releases this will overwrite (and effectively delete) previously generated release sections, so CHANGELOG.md will only ever contain the latest release in that region. Consider prepending the new section while preserving the existing content between the markers (e.g., insert CHANGELOG_SECTION.md immediately after the start marker and then keep the old in-marker content below it).
| BEGIN { skip = 0 } | |
| /<!-- release-bot:start -->/ { | |
| print "" | |
| while ((getline line < "CHANGELOG_SECTION.md") > 0) print line | |
| print "" | |
| skip = 1 | |
| next | |
| } | |
| /<!-- release-bot:end -->/ { | |
| skip = 0 | |
| next | |
| } | |
| skip == 0 { print } | |
| BEGIN { | |
| in_section = 0 | |
| preserved = "" | |
| new_section = "" | |
| while ((getline line < "CHANGELOG_SECTION.md") > 0) { | |
| new_section = new_section line ORS | |
| } | |
| close("CHANGELOG_SECTION.md") | |
| } | |
| /<!-- release-bot:start -->/ { | |
| print "" | |
| printf "%s", new_section | |
| print "" | |
| in_section = 1 | |
| next | |
| } | |
| /<!-- release-bot:end -->/ { | |
| if (preserved != "") { | |
| printf "%s", preserved | |
| print "" | |
| } | |
| in_section = 0 | |
| next | |
| } | |
| in_section { | |
| preserved = preserved $0 ORS | |
| next | |
| } | |
| { print } |
|
|
||
| jobs: | ||
| prepare-release-pr: | ||
| if: "${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && !contains(github.event.head_commit.message, 'chore(release): v')) }}" |
There was a problem hiding this comment.
The push-trigger guard excludes commits containing chore(release): v, but the workflow creates commits with chore(release): prepare v.... If the release PR is merged using a strategy that preserves commit messages (e.g., rebase/merge), the next push to main may not be filtered and could immediately open another release PR and bump again. Align the filter with the actual commit message/prefix used by the bot (or switch to filtering by branch/PR metadata instead of commit message).
| if: "${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && !contains(github.event.head_commit.message, 'chore(release): v')) }}" | |
| if: "${{ github.event_name == 'workflow_dispatch' || (github.event_name == 'push' && !startsWith(github.event.head_commit.message, 'chore(release): prepare v')) }}" |
| TABLE_ROW="| ${OPENCLOUD_VERSION} | ${NEXT_VERSION} |" | ||
| if ! grep -Fq "$TABLE_ROW" README.md; then | ||
| awk -v row="$TABLE_ROW" ' | ||
| { | ||
| if ($0 ~ /^\|[-]+\|[-]+\|$/) { | ||
| print row | ||
| } | ||
| } | ||
| ' README.md > README.new.md | ||
| mv README.new.md README.md | ||
| fi | ||
|
|
There was a problem hiding this comment.
The version-table update injects a brand-new row immediately after the table separator line. In the current README the version table groups multiple chart versions per OpenCloud version (e.g., 4.1.0 and 5.0.2 rows), so this automation will create duplicate OpenCloud-version rows and also change the ordering by always inserting at the top. Consider updating the existing row for OPENCLOUD_VERSION (append NEXT_VERSION to the chart-version cell) and only inserting a new row when that OpenCloud version is not present, ideally preserving the table's ordering.
| TABLE_ROW="| ${OPENCLOUD_VERSION} | ${NEXT_VERSION} |" | |
| if ! grep -Fq "$TABLE_ROW" README.md; then | |
| awk -v row="$TABLE_ROW" ' | |
| { | |
| if ($0 ~ /^\|[-]+\|[-]+\|$/) { | |
| print row | |
| } | |
| } | |
| ' README.md > README.new.md | |
| mv README.new.md README.md | |
| fi | |
| awk -v opencloud_version="${OPENCLOUD_VERSION}" -v next_version="${NEXT_VERSION}" ' | |
| function trim(value) { | |
| gsub(/^[[:space:]]+|[[:space:]]+$/, "", value) | |
| return value | |
| } | |
| function contains_version(list, version, items, i, n) { | |
| n = split(list, items, /,[[:space:]]*/) | |
| for (i = 1; i <= n; i++) { | |
| if (trim(items[i]) == version) { | |
| return 1 | |
| } | |
| } | |
| return 0 | |
| } | |
| function append_version(list, version) { | |
| list = trim(list) | |
| if (list == "") { | |
| return version | |
| } | |
| if (contains_version(list, version)) { | |
| return list | |
| } | |
| return list ", " version | |
| } | |
| function emit_new_row() { | |
| print "| " opencloud_version " | " next_version " |" | |
| } | |
| BEGIN { | |
| in_version_table = 0 | |
| saw_separator = 0 | |
| updated_row = 0 | |
| inserted_row = 0 | |
| } | |
| { | |
| if (saw_separator && in_version_table && $0 !~ /^[[:space:]]*\|/) { | |
| if (!updated_row && !inserted_row) { | |
| emit_new_row() | |
| inserted_row = 1 | |
| } | |
| in_version_table = 0 | |
| } | |
| if ($0 ~ /^[[:space:]]*\|[[:space:]:-]+(\|[[:space:]:-]+)+\|[[:space:]]*$/ && !saw_separator) { | |
| saw_separator = 1 | |
| in_version_table = 1 | |
| next | |
| } | |
| if (in_version_table && $0 ~ /^[[:space:]]*\|.*\|[[:space:]]*$/) { | |
| split($0, cols, /\|/) | |
| if (trim(cols[2]) == opencloud_version) { | |
| chart_versions = append_version(cols[3], next_version) | |
| print "| " opencloud_version " | " chart_versions " |" | |
| updated_row = 1 | |
| next | |
| } | |
| } | |
| } | |
| END { | |
| if (saw_separator && in_version_table && !updated_row && !inserted_row) { | |
| emit_new_row() | |
| } | |
| } | |
| ' README.md > README.new.md | |
| mv README.new.md README.md |
The bot automatically opens and updates a release PR from changes pushed to main, generates a structured changelog with linked pull requests, bumps the Helm chart version, updates release-related docs, and, once that release PR is merged, creates the git tag, publishes the Helm chart to GHCR, and creates the GitHub release.