From 7db543eee3af73241c4580d25fd4fdb5d5fbc92b Mon Sep 17 00:00:00 2001 From: Goran Dodig Date: Tue, 27 Oct 2026 18:54:59 +0100 Subject: [PATCH 1/2] ci(release): thread Slack release notices under the start notice Result notices reply in the start notice thread via its ts. Failures are also broadcast to the channel. If the start post never happened, thread_ts is null and notices post to the channel as before. --- .github/workflows/publish-to-pypi.yml | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index 57ec82e..f94fb42 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -24,6 +24,9 @@ jobs: runs-on: ubuntu-latest permissions: contents: read + outputs: + # The notify job replies in the start notice's thread. + slack-ts: ${{ steps.slack-start.outputs.ts }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 @@ -34,6 +37,7 @@ jobs: # Non-fatal: Slack being down must not block the release. - name: Notify Slack (start) + id: slack-start if: ${{ vars.SLACK_CHANNEL_ID != '' }} continue-on-error: true uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0 @@ -121,6 +125,13 @@ jobs: if: ${{ !cancelled() && vars.SLACK_CHANNEL_ID != '' }} runs-on: ubuntu-latest + env: + # Notices reply in the start notice's thread, quoted so YAML keeps the ts a + # string. Without a start notice (its post failed or never ran) this is null, + # which the Slack client drops, and they post to the channel. Failures are + # also broadcast to the channel; success stays in the thread. + THREAD_TS: ${{ needs.build.outputs.slack-ts && format('"{0}"', needs.build.outputs.slack-ts) || 'null' }} + steps: - name: Notify Slack (checks failed) if: ${{ needs.pre-publish-checks.result == 'failure' }} @@ -144,6 +155,8 @@ jobs: errors: true payload: | channel: ${{ vars.SLACK_CHANNEL_ID }} + thread_ts: ${{ env.THREAD_TS }} + reply_broadcast: ${{ env.THREAD_TS != 'null' }} text: >- *plain-parser*: Build of `${{ github.ref_name }}` FAILED :x:. Nothing was published to PyPI. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>. @@ -157,6 +170,8 @@ jobs: errors: true payload: | channel: ${{ vars.SLACK_CHANNEL_ID }} + thread_ts: ${{ env.THREAD_TS }} + reply_broadcast: ${{ env.THREAD_TS != 'null' }} text: >- *plain-parser*: Uploading `${{ github.ref_name }}` to the GitHub Release FAILED :x:. Nothing was published to PyPI. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>. @@ -170,6 +185,8 @@ jobs: errors: true payload: | channel: ${{ vars.SLACK_CHANNEL_ID }} + thread_ts: ${{ env.THREAD_TS }} + reply_broadcast: ${{ env.THREAD_TS != 'null' }} text: >- *plain-parser*: Publishing `${{ github.ref_name }}` to PyPI FAILED :x:. See <${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|the run log>. @@ -195,6 +212,7 @@ jobs: errors: true payload: | channel: ${{ vars.SLACK_CHANNEL_ID }} + thread_ts: ${{ env.THREAD_TS }} text: >- *plain-parser*: pre-release `${{ github.ref_name }}` published to PyPI :test_tube:. Normal installs are unaffected — try it with `pip install --pre plain-parser==${{ steps.version.outputs.version }}`. @@ -208,6 +226,7 @@ jobs: errors: true payload: | channel: ${{ vars.SLACK_CHANNEL_ID }} + thread_ts: ${{ env.THREAD_TS }} text: >- *plain-parser*: `${{ github.ref_name }}` published to PyPI :white_check_mark:. Install with `pip install --upgrade plain-parser`. From f53af023bafacb343079967a12bf14a9b82ce14f Mon Sep 17 00:00:00 2001 From: Goran Dodig Date: Thu, 29 Oct 2026 16:44:11 +0100 Subject: [PATCH 2/2] =?UTF-8?q?ci(release):=20add=20a=20=E2=9C=85=20to=20t?= =?UTF-8?q?he=20start=20notice=20on=20success?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Success replies stay in the thread, so a reaction marks the top-level message too. It needs the reactions:write scope on the Slack app. The step is non-fatal until that scope is granted. --- .github/workflows/publish-to-pypi.yml | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/.github/workflows/publish-to-pypi.yml b/.github/workflows/publish-to-pypi.yml index f94fb42..28860e4 100644 --- a/.github/workflows/publish-to-pypi.yml +++ b/.github/workflows/publish-to-pypi.yml @@ -230,3 +230,19 @@ jobs: text: >- *plain-parser*: `${{ github.ref_name }}` published to PyPI :white_check_mark:. Install with `pip install --upgrade plain-parser`. + + # Success also puts a ✅ on the start notice, so the result shows in the + # channel without another message. Needs the app's reactions:write scope. + # Non-fatal: the result is already posted, and a re-run gets already_reacted. + - name: Notify Slack (✅ on the start notice) + if: ${{ needs.publish-to-pypi.result == 'success' && env.THREAD_TS != 'null' }} + continue-on-error: true + uses: slackapi/slack-github-action@dcb1066f776dd043e64d0e8ba94ca15cc7e1875d # v4.0.0 + with: + method: reactions.add + token: ${{ secrets.SLACK_BOT_TOKEN }} + errors: true + payload: | + channel: ${{ vars.SLACK_CHANNEL_ID }} + timestamp: ${{ env.THREAD_TS }} + name: white_check_mark