Skip to content

Commit 9733c62

Browse files
github-actions: Add Slack notifications for kernelCI failures
Notify the #linux-kernel Slack channel when the kernelCI pipeline fails on a supported release branch. Successful runs stay silent. Triggers a notification: - build / boot failures - kselftest or LTP execution infrastructure failures - kselftest regressions (>±3 test diff vs baseline) - pre-setup / matrix-setup infra failures Stays silent for: - successful runs - branches whose base is not in VALID_BASES - [skip ci] runs (skip_ci sentinel from pre-setup) - LTP regressions (intentionally not classified — LTP runs informationally per existing pipeline policy: continue-on-error on test-ltp/compare-ltp, no PR-blocking in create-pr) - LTP test failures within tolerance - kselftest pass/fail diffs within ±3 threshold - create-pr failures (avoids noise from branch-name typos, regression-induced skips, transient gh API errors) Implementation: - notify-slack-kernelci.sh follows the create-pr-body-multiarch.sh pattern: named args, lives in .github/scripts/, fetched fresh from main by the calling workflow on each run. - Posts via slackapi/slack-github-action pinned to SHA 45a88b9581bfab2566dc881e2cd66d334e621e2c (v3.0.3) using the org-wide GH_BOT_SLACK_TOKEN secret. - Channel ID stored as repo variable SLACK_CHANNEL_LINUX_KERNEL so the destination can change without code edits. - Message includes mention, failed-stage summary, and branch/commit/PR/run links. Prereqs (already in place): - vars.SLACK_CHANNEL_LINUX_KERNEL set on the repo - GH_BOT_SLACK_TOKEN org secret scoped to kernel-src-tree - Bot user is a member of #linux-kernel
1 parent 1cf6d26 commit 9733c62

2 files changed

Lines changed: 184 additions & 0 deletions

File tree

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
#!/bin/bash
2+
3+
# Builds a Slack chat.postMessage payload for a kernelCI failure and writes
4+
# it to stdout (or to a file via --output). The caller is responsible for
5+
# posting it (e.g. via slackapi/slack-github-action with a bot token).
6+
#
7+
# Usage:
8+
# notify-slack-kernelci.sh \
9+
# --channel-id CHANNEL_ID \
10+
# --base-branch BRANCH --head-ref BRANCH --head-sha SHA \
11+
# --pr-number N --is-pr true|false \
12+
# --repo OWNER/REPO --run-id ID \
13+
# --failed-stages "stage1, stage2, ..." \
14+
# [--mention-id SLACK_USER_ID] \
15+
# [--output PATH]
16+
17+
set -euo pipefail
18+
19+
CHANNEL_ID=""
20+
BASE_BRANCH=""
21+
HEAD_REF=""
22+
HEAD_SHA=""
23+
PR_NUMBER="0"
24+
IS_PR="false"
25+
REPO=""
26+
RUN_ID=""
27+
FAILED_STAGES=""
28+
MENTION_ID=""
29+
OUTPUT=""
30+
31+
while [[ $# -gt 0 ]]; do
32+
case "$1" in
33+
--channel-id) CHANNEL_ID="$2"; shift 2 ;;
34+
--base-branch) BASE_BRANCH="$2"; shift 2 ;;
35+
--head-ref) HEAD_REF="$2"; shift 2 ;;
36+
--head-sha) HEAD_SHA="$2"; shift 2 ;;
37+
--pr-number) PR_NUMBER="$2"; shift 2 ;;
38+
--is-pr) IS_PR="$2"; shift 2 ;;
39+
--repo) REPO="$2"; shift 2 ;;
40+
--run-id) RUN_ID="$2"; shift 2 ;;
41+
--failed-stages) FAILED_STAGES="$2"; shift 2 ;;
42+
--mention-id) MENTION_ID="$2"; shift 2 ;;
43+
--output) OUTPUT="$2"; shift 2 ;;
44+
*) echo "Error: Unknown option: $1" >&2; exit 1 ;;
45+
esac
46+
done
47+
48+
for var in CHANNEL_ID BASE_BRANCH HEAD_REF HEAD_SHA REPO RUN_ID FAILED_STAGES; do
49+
if [ -z "${!var}" ]; then
50+
echo "Error: --${var,,} is required" >&2
51+
exit 1
52+
fi
53+
done
54+
55+
SHORT_SHA="${HEAD_SHA:0:12}"
56+
RUN_URL="https://github.com/$REPO/actions/runs/$RUN_ID"
57+
COMMIT_URL="https://github.com/$REPO/commit/$HEAD_SHA"
58+
59+
MENTION=""
60+
if [ -n "$MENTION_ID" ]; then
61+
MENTION="<@${MENTION_ID}> "
62+
fi
63+
64+
PR_LINE=""
65+
if [ "$IS_PR" = "true" ] && [ "$PR_NUMBER" != "0" ]; then
66+
PR_LINE=$'\n'"*PR:* <https://github.com/$REPO/pull/$PR_NUMBER|#$PR_NUMBER>"
67+
fi
68+
69+
MESSAGE=$(
70+
printf '%s:x: *kernelCI failed on `%s`*\n' "$MENTION" "$BASE_BRANCH"
71+
printf '*Branch:* `%s`\n' "$HEAD_REF"
72+
printf '*Commit:* <%s|%s>' "$COMMIT_URL" "$SHORT_SHA"
73+
printf '%s\n' "$PR_LINE"
74+
printf '*Failed stages:* %s\n' "$FAILED_STAGES"
75+
printf '*Run:* <%s|view logs>' "$RUN_URL"
76+
)
77+
78+
# Build chat.postMessage payload: channel + text. mrkdwn is on by default.
79+
PAYLOAD=$(jq -n \
80+
--arg channel "$CHANNEL_ID" \
81+
--arg text "$MESSAGE" \
82+
'{channel: $channel, text: $text}')
83+
84+
if [ -n "$OUTPUT" ]; then
85+
printf '%s\n' "$PAYLOAD" > "$OUTPUT"
86+
echo "Payload written to $OUTPUT" >&2
87+
else
88+
printf '%s\n' "$PAYLOAD"
89+
fi

.github/workflows/kernel-build-and-test-multiarch.yml

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1605,3 +1605,98 @@ jobs:
16051605
--body-file pr_body.md \
16061606
--label "created-by-kernelci"
16071607
fi
1608+
1609+
notify-slack:
1610+
name: Notify Slack on failure
1611+
runs-on: ubuntu-latest
1612+
needs: [pre-setup, setup, build, boot, test-kselftest, test-ltp, compare-kselftest, compare-ltp, create-pr]
1613+
if: always() && needs.pre-setup.outputs.skip_ci != 'true'
1614+
1615+
steps:
1616+
- name: Resolve base branch and collect failed stages
1617+
id: decide
1618+
env:
1619+
HEAD_REF: ${{ needs.pre-setup.outputs.head_ref }}
1620+
BASE_REF: ${{ needs.pre-setup.outputs.base_ref }}
1621+
KSELFTEST_BASE: ${{ needs.compare-kselftest.outputs.base_branch }}
1622+
LTP_BASE: ${{ needs.compare-ltp.outputs.base_branch }}
1623+
run: |
1624+
# Whitelist must stay in sync with compare-kselftest / compare-ltp jobs
1625+
VALID_BASES="ciqlts9_2 ciqlts9_4 ciqlts8_6 ciqlts9_6 ciq-6.12.y ciq-6.12.y-next ciq-6.18.y ciq-6.18.y-next ciqcbr7_9"
1626+
1627+
BASE_BRANCH="$KSELFTEST_BASE"
1628+
[ -z "$BASE_BRANCH" ] && BASE_BRANCH="$LTP_BASE"
1629+
[ -z "$BASE_BRANCH" ] && BASE_BRANCH="$BASE_REF"
1630+
if [ -z "$BASE_BRANCH" ] && [[ "$HEAD_REF" =~ \{[^}]+\}[_-](.+) ]]; then
1631+
BASE_BRANCH="${BASH_REMATCH[1]}"
1632+
fi
1633+
1634+
if ! echo "$VALID_BASES" | grep -wq "$BASE_BRANCH"; then
1635+
echo "Base '$BASE_BRANCH' not in whitelist — skipping Slack notification"
1636+
echo "should_notify=false" >> $GITHUB_OUTPUT
1637+
exit 0
1638+
fi
1639+
1640+
FAILED_STAGES=()
1641+
[ "${{ needs.pre-setup.result }}" = "failure" ] && FAILED_STAGES+=("infra: pre-setup")
1642+
[ "${{ needs.setup.result }}" = "failure" ] && FAILED_STAGES+=("infra: matrix setup")
1643+
[ "${{ needs.build.result }}" = "failure" ] && FAILED_STAGES+=("build")
1644+
[ "${{ needs.boot.result }}" = "failure" ] && FAILED_STAGES+=("boot")
1645+
[ "${{ needs.test-kselftest.result }}" = "failure" ] && FAILED_STAGES+=("kselftest execution")
1646+
[ "${{ needs.test-ltp.result }}" = "failure" ] && FAILED_STAGES+=("LTP execution (infrastructure)")
1647+
1648+
[ "${{ needs.compare-kselftest.outputs.comparison_status_x86_64 }}" = "failed" ] && FAILED_STAGES+=("kselftest regression (x86_64)")
1649+
[ "${{ needs.compare-kselftest.outputs.comparison_status_aarch64 }}" = "failed" ] && FAILED_STAGES+=("kselftest regression (aarch64)")
1650+
1651+
# LTP regressions are intentionally NOT classified as failures: LTP
1652+
# runs informationally (continue-on-error in test-ltp, no PR-blocking
1653+
# in create-pr). Only LTP infra failures (test-ltp.result == failure
1654+
# above) are notified, since a crashed VM is a real CI problem.
1655+
1656+
if [ ${#FAILED_STAGES[@]} -eq 0 ]; then
1657+
echo "No failures detected — skipping Slack notification"
1658+
echo "should_notify=false" >> $GITHUB_OUTPUT
1659+
exit 0
1660+
fi
1661+
1662+
SUMMARY=$(IFS=", "; echo "${FAILED_STAGES[*]}")
1663+
echo "should_notify=true" >> $GITHUB_OUTPUT
1664+
echo "base_branch=$BASE_BRANCH" >> $GITHUB_OUTPUT
1665+
echo "failed_summary=$SUMMARY" >> $GITHUB_OUTPUT
1666+
1667+
- name: Checkout kernel source
1668+
if: steps.decide.outputs.should_notify == 'true'
1669+
uses: actions/checkout@v4
1670+
with:
1671+
fetch-depth: 1
1672+
1673+
- name: Fetch notification script from main
1674+
if: steps.decide.outputs.should_notify == 'true'
1675+
run: |
1676+
git fetch origin main:main
1677+
git checkout origin/main -- .github/scripts/notify-slack-kernelci.sh
1678+
chmod +x .github/scripts/notify-slack-kernelci.sh
1679+
1680+
- name: Build Slack payload
1681+
if: steps.decide.outputs.should_notify == 'true'
1682+
run: |
1683+
.github/scripts/notify-slack-kernelci.sh \
1684+
--channel-id "${{ vars.SLACK_CHANNEL_LINUX_KERNEL }}" \
1685+
--base-branch "${{ steps.decide.outputs.base_branch }}" \
1686+
--head-ref "${{ needs.pre-setup.outputs.head_ref }}" \
1687+
--head-sha "${{ needs.pre-setup.outputs.head_sha }}" \
1688+
--pr-number "${{ needs.pre-setup.outputs.pr_number }}" \
1689+
--is-pr "${{ needs.pre-setup.outputs.is_pr }}" \
1690+
--repo "${{ github.repository }}" \
1691+
--run-id "${{ github.run_id }}" \
1692+
--failed-stages "${{ steps.decide.outputs.failed_summary }}" \
1693+
--mention-id "U092R1ERDJQ" \
1694+
--output slack_payload.json
1695+
1696+
- name: Post to Slack
1697+
if: steps.decide.outputs.should_notify == 'true'
1698+
uses: slackapi/slack-github-action@45a88b9581bfab2566dc881e2cd66d334e621e2c # v3.0.3
1699+
with:
1700+
method: chat.postMessage
1701+
token: ${{ secrets.GH_BOT_SLACK_TOKEN }}
1702+
payload-file-path: slack_payload.json

0 commit comments

Comments
 (0)