From 56d2d45363693ca6774dd417f41fdb4bda009867 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Wed, 2 Sep 2026 18:32:38 +0200 Subject: [PATCH 1/4] Added reusable Slack CI notification workflow Extracted the Slack notification PoC from ibexa/admin-ui#1999 into a reusable workflow, so every Cohesivo package repository can consume it from a thin, byte-identical workflow_run-triggered caller instead of copying ~40 lines with a per-repository needs list. The run conclusion comes from the workflow_run event, which aggregates all jobs of the notified run. Success notifications are governed by the send-success-notification input: 'auto' (default) notifies only when a human dispatched the run, replacing the PoC's dispatch input, which a workflow_run payload cannot carry. Co-Authored-By: Claude Fable 5 --- .github/workflows/notify-slack-ci.yml | 67 +++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 .github/workflows/notify-slack-ci.yml diff --git a/.github/workflows/notify-slack-ci.yml b/.github/workflows/notify-slack-ci.yml new file mode 100644 index 0000000..1e55512 --- /dev/null +++ b/.github/workflows/notify-slack-ci.yml @@ -0,0 +1,67 @@ +name: Notify Slack about CI results + +# Reusable Slack notification for CI workflows. Call it from a thin +# `workflow_run`-triggered workflow on each repository's default branch: +# +# on: +# workflow_run: +# workflows: ["Backend CI"] +# types: [completed] +# jobs: +# notify: +# uses: ibexa/gh-workflows/.github/workflows/notify-slack-ci.yml@main +# secrets: inherit + +on: + workflow_call: + inputs: + send-success-notification: + description: "Notify on success: 'true', 'false', or 'auto' (only when a human dispatched the run)" + type: string + default: "auto" + secrets: + SLACK_PHP_BACKEND_CI_WEBHOOK_URL: + description: "Incoming webhook of the target Slack channel (org-level secret, satisfied by 'secrets: inherit')" + required: true + +jobs: + notify: + name: Notify Slack + runs-on: "ubuntu-26.04" + if: github.event.workflow_run.event == 'workflow_dispatch' + steps: + - name: Decide whether to notify + id: decision + env: + CONCLUSION: ${{ github.event.workflow_run.conclusion }} + ACTOR: ${{ github.event.workflow_run.triggering_actor.login }} + SEND_SUCCESS: ${{ inputs.send-success-notification }} + run: | + if [ "$CONCLUSION" != "success" ]; then + # Failures (and cancellations) are always reported + notify=true + elif [ "$SEND_SUCCESS" = "auto" ]; then + # Successes are reported only for human-dispatched runs, + # so a bot dispatcher does not spam green builds + if [[ "$ACTOR" == *'[bot]' ]]; then + notify=false + else + notify=true + fi + else + notify="$SEND_SUCCESS" + fi + echo "notify=$notify" >> "$GITHUB_OUTPUT" + + - name: Send Slack notification + if: steps.decision.outputs.notify == 'true' + uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3 + with: + webhook: ${{ secrets.SLACK_PHP_BACKEND_CI_WEBHOOK_URL }} + webhook-type: incoming-webhook + payload: | + blocks: + - type: "section" + text: + type: "mrkdwn" + text: "${{ github.event.workflow_run.conclusion == 'success' && '✅' || '❌' }} ${{ github.event.workflow_run.name }} *${{ github.repository }}*:*${{ github.event.workflow_run.head_branch }}* (${{ github.event.workflow_run.triggering_actor.login }}) | <${{ github.event.workflow_run.html_url }}|Details>" From ec48de2ffeb456068709771510dd6e20194463e7 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Mon, 7 Sep 2026 17:15:50 +0200 Subject: [PATCH 2/4] Reported failures of scheduled CI runs A workflow_run payload reports 'schedule' for a CI run started by cron, which the previous condition rejected, so such a run notified about nothing at all - not even a failure. Repositories are free to put a schedule trigger on their CI workflow, so accept that event too. Scheduled runs must not report successes under 'auto', though: nobody is waiting for them, exactly like the nightly bot dispatcher. The 'auto' branch therefore now requires a human AND a workflow_dispatch, rather than only a non-bot actor. Co-Authored-By: Claude Fable 5 --- .github/workflows/notify-slack-ci.yml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/notify-slack-ci.yml b/.github/workflows/notify-slack-ci.yml index 1e55512..691f2ff 100644 --- a/.github/workflows/notify-slack-ci.yml +++ b/.github/workflows/notify-slack-ci.yml @@ -28,12 +28,15 @@ jobs: notify: name: Notify Slack runs-on: "ubuntu-26.04" - if: github.event.workflow_run.event == 'workflow_dispatch' + # Only deliberately started runs are reported. Push and pull request + # runs are watched by their authors and would flood the channel. + if: contains(fromJSON('["workflow_dispatch", "schedule"]'), github.event.workflow_run.event) steps: - name: Decide whether to notify id: decision env: CONCLUSION: ${{ github.event.workflow_run.conclusion }} + EVENT: ${{ github.event.workflow_run.event }} ACTOR: ${{ github.event.workflow_run.triggering_actor.login }} SEND_SUCCESS: ${{ inputs.send-success-notification }} run: | @@ -41,12 +44,14 @@ jobs: # Failures (and cancellations) are always reported notify=true elif [ "$SEND_SUCCESS" = "auto" ]; then - # Successes are reported only for human-dispatched runs, - # so a bot dispatcher does not spam green builds - if [[ "$ACTOR" == *'[bot]' ]]; then - notify=false - else + # Successes are reported only to whoever asked for the run + # in person. Scheduled runs have nobody waiting for them, + # and a bot dispatcher is not reading the channel either, + # so in both cases green builds stay silent. + if [ "$EVENT" = "workflow_dispatch" ] && [[ "$ACTOR" != *'[bot]' ]]; then notify=true + else + notify=false fi else notify="$SEND_SUCCESS" From 2cdd6d9038a07e9dc670f5e872ba84d3cf18e308 Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Mon, 7 Sep 2026 17:15:50 +0200 Subject: [PATCH 3/4] Failed the notification job when Slack rejects the call The Slack action defaults to errors: false, which downgrades a rejected call to a warning and leaves the step green. A webhook revoked in Slack or a rotated secret would then silence CI notifications across every repository consuming this workflow, with nothing to show it. The job runs on workflow_run, so a red notification cannot affect the conclusion of the CI run it reports on. Co-Authored-By: Claude Fable 5 --- .github/workflows/notify-slack-ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/notify-slack-ci.yml b/.github/workflows/notify-slack-ci.yml index 691f2ff..db9b31f 100644 --- a/.github/workflows/notify-slack-ci.yml +++ b/.github/workflows/notify-slack-ci.yml @@ -64,6 +64,10 @@ jobs: with: webhook: ${{ secrets.SLACK_PHP_BACKEND_CI_WEBHOOK_URL }} webhook-type: incoming-webhook + # Fail the job when Slack rejects the call. Left at the + # default of false, a revoked webhook would silence every + # notification while these runs stayed green. + errors: true payload: | blocks: - type: "section" From eb032aca67d65567a4e74b61cb0fa0858fa49a4c Mon Sep 17 00:00:00 2001 From: Andrew Longosz Date: Mon, 7 Sep 2026 17:30:25 +0200 Subject: [PATCH 4/4] Stopped passing the send-success-notification input to CI The input cannot survive the trip: a workflow_run payload carries no dispatch inputs, so the reusable notification takes the flag through workflow_call from the thin caller instead. Passing it here only worked because ibexa/admin-ui happens to declare it, being the one repository still carrying the inline notification PoC. Every repository that gains a plain workflow_dispatch trigger would be dispatched with an input it does not declare, and the API rejects that with a 422. Co-Authored-By: Claude Fable 5 --- .github/workflows/nightly-backend-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/nightly-backend-ci.yml b/.github/workflows/nightly-backend-ci.yml index b5cad6b..ff417b9 100644 --- a/.github/workflows/nightly-backend-ci.yml +++ b/.github/workflows/nightly-backend-ci.yml @@ -35,7 +35,6 @@ jobs: run: | gh api --method POST \ "/repos/${{ matrix.repository }}/actions/workflows/backend-ci.yaml/dispatches" \ - -f ref="${{ matrix.branch }}" \ - -f "inputs[send-success-notification]=false" + -f ref="${{ matrix.branch }}" env: GITHUB_TOKEN: ${{ steps.generate_token.outputs.token }}