[misc] Announce tag-pushed releases on the forum (#8265)

* [misc] Announce tag-pushed releases on the forum

Since 0.77 a release is cut by pushing a tag, and goreleaser creates the
GitHub release with GITHUB_TOKEN. Events raised by that token start no
workflow, so the release:published trigger never fires for them and
0.78.0, 0.79.0, 0.80.0, 0.81.0 and 0.81.3 got no forum topic, while
releases published from the UI still did.

Post from the completion of the Release workflow instead, for tag runs
that succeeded and whose release was created by the bot. Release
candidates stay off the forum, and an existing topic with the same title
is left alone so re-running a green Release run does not post twice.

* [misc] Point an empty forum post at the release notes

goreleaser creates the release with an empty body and the notes are
written on the release page afterwards, so the topic would otherwise
hold only its title link. Say where the notes and downloads are.

* [misc] Fail closed in the forum post lookups

Announce stable tags only: every pre-release tag carries a hyphen, so
canaries and release candidates pushed as tags stay off the forum.

A failed release lookup now fails the step instead of passing as "no
release"; only a 404 skips. The duplicate check searches by title rather
than reading the first page of the category, and a failed search stops
the step instead of falling through to a post. Discourse requests
refuse any non-HTTPS redirect and retry transient errors.
This commit is contained in:
Riccardo Manfrin
2026-10-20 10:42:34 +02:00
committed by GitHub
parent 8fef487e42
commit 6989d689cf
+82
View File
@@ -3,9 +3,16 @@ name: Post release topic on Discourse
on:
release:
types: [published]
workflow_run:
workflows: [Release]
types: [completed]
permissions:
contents: read
jobs:
post:
if: github.event_name == 'release'
runs-on: ubuntu-latest
steps:
- uses: roots/discourse-topic-github-release-action@557d74ea05b6cc0c47f555c1d5d28a89d904005b # v1.1.0
@@ -15,3 +22,78 @@ jobs:
discourse-author-username: NetBird
discourse-category: 17
discourse-tags: releases
# goreleaser publishes the release of a pushed tag with GITHUB_TOKEN, and events
# raised by that token start no workflow, so the release event above never fires.
post-tag-release:
if: >-
github.event_name == 'workflow_run' &&
github.event.workflow_run.event == 'push' &&
github.event.workflow_run.conclusion == 'success' &&
startsWith(github.event.workflow_run.head_branch, 'v') &&
!contains(github.event.workflow_run.head_branch, '-')
runs-on: ubuntu-latest
steps:
- name: Post the release topic
env:
GH_TOKEN: ${{ github.token }}
TAG: ${{ github.event.workflow_run.head_branch }}
DISCOURSE_API_KEY: ${{ secrets.DISCOURSE_RELEASES_API_KEY }}
DISCOURSE_URL: https://forum.netbird.io
DISCOURSE_USER: NetBird
DISCOURSE_CATEGORY: "17"
run: |
set -euo pipefail
if ! release=$(gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" 2>gh.err); then
if grep -q 'HTTP 404' gh.err; then
echo "no release for ${TAG}, nothing to announce"
exit 0
fi
cat gh.err >&2
exit 1
fi
# A release a person published already fired the release event above.
author=$(jq -r '.author.login' <<<"$release")
if [ "$author" != "github-actions[bot]" ] || [ "$(jq -r '.draft' <<<"$release")" = "true" ]; then
echo "${TAG} published by ${author}, announced by the release event"
exit 0
fi
# Same title and body as the action above, so both paths read alike.
title="${GITHUB_REPOSITORY#*/} ${TAG} released"
# A re-run of a successful Release run fires this event again. A failed lookup
# stops the step rather than risk a duplicate topic.
search=$(curl -fsS --retry 3 --proto '=https' --proto-redir '=https' -G \
-H "Api-Key: ${DISCOURSE_API_KEY}" \
-H "Api-Username: ${DISCOURSE_USER}" \
"${DISCOURSE_URL}/search.json" \
--data-urlencode "q=\"${title}\" in:title")
existing=$(jq -r --arg t "$title" --argjson c "$DISCOURSE_CATEGORY" \
'[(.topics // [])[] | select(.category_id == $c and (.title | ascii_downcase) == ($t | ascii_downcase))] | length' \
<<<"$search")
if [ "$existing" != "0" ]; then
echo "topic '${title}' already exists"
exit 0
fi
# goreleaser leaves the body empty; the notes are written on the release page afterwards.
url=$(jq -r '.html_url' <<<"$release")
body=$(jq -r '.body // ""' <<<"$release")
if [ -z "${body//[[:space:]]/}" ]; then
body="Release notes and downloads: ${url}"
fi
jq -n \
--arg title "$title" \
--arg raw "$(printf '[%s](%s)\n\n%s' "$title" "$url" "$body")" \
--argjson category "$DISCOURSE_CATEGORY" \
'{title: $title, raw: $raw, category: $category, tags: ["releases"]}' \
| curl -fsS -X POST "${DISCOURSE_URL}/posts.json" \
-H "Api-Key: ${DISCOURSE_API_KEY}" \
-H "Api-Username: ${DISCOURSE_USER}" \
-H "Content-Type: application/json" \
--data @- \
| jq -r '"posted \(env.DISCOURSE_URL)/t/\(.topic_slug)/\(.topic_id)"'