From d1b1cbb239a39a09610a722b34e1a5fd96484ed4 Mon Sep 17 00:00:00 2001 From: redpanda-f Date: Fri, 27 Feb 2026 13:14:43 +0000 Subject: [PATCH 1/3] add: notify slack --- .github/workflows/notify-slack.yml | 63 ++++++++++++++++++++++++++++++ 1 file changed, 63 insertions(+) create mode 100644 .github/workflows/notify-slack.yml diff --git a/.github/workflows/notify-slack.yml b/.github/workflows/notify-slack.yml new file mode 100644 index 00000000..516a88fe --- /dev/null +++ b/.github/workflows/notify-slack.yml @@ -0,0 +1,63 @@ +--- +name: Notify Slack + +on: + workflow_run: + workflows: ["CI"] + types: [completed] + +jobs: + notify: + runs-on: ubuntu-latest + steps: + - name: Post Slack notification + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} + SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }} + CI_LOGS_BUCKET: ${{ secrets.CI_LOGS_BUCKET }} + AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} + RUN_ID: ${{ github.event.workflow_run.id }} + RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }} + BRANCH: ${{ github.event.workflow_run.head_branch }} + CONCLUSION: ${{ github.event.workflow_run.conclusion }} + REPO: ${{ github.repository }} + run: | + set -euo pipefail + + BRANCH_S3="${BRANCH//\//-}" + S3_BASE="https://${CI_LOGS_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/runs/${BRANCH_S3}/${RUN_ID}/${RUN_ATTEMPT}" + RUN_URL="https://github.com/${REPO}/actions/runs/${RUN_ID}" + + JOBS=$(gh api "repos/${REPO}/actions/runs/${RUN_ID}/jobs") + + job_conclusion() { echo "$JOBS" | jq -r --arg n "$1" '.jobs[] | select(.name == $n) | .conclusion'; } + job_url() { echo "$JOBS" | jq -r --arg n "$1" '.jobs[] | select(.name == $n) | .html_url'; } + icon() { [ "$1" = "success" ] && echo ":white_check_mark:" || echo ":x:"; } + + FMT_C=$(job_conclusion "fmt-clippy"); FMT_URL=$(job_url "fmt-clippy") + INT_C=$(job_conclusion "integration-test"); INT_URL=$(job_url "integration-test") + OVERALL=$(icon "$CONCLUSION"); FMT=$(icon "$FMT_C"); INT=$(icon "$INT_C") + + ARTIFACT_LINKS="" + for f in setup.log devnet-info.json step_context.json version.txt post_start_status.log; do + ARTIFACT_LINKS="${ARTIFACT_LINKS}• <${S3_BASE}/${f}|${f}>\n" + done + + curl -fsSL -X POST -H 'Content-Type: application/json' \ + --data "$(jq -n \ + --arg ch "$SLACK_CHANNEL" \ + --arg hdr "${OVERALL} *CI <${RUN_URL}|#${RUN_ID}> · \`${BRANCH}\`*" \ + --arg fmt "${FMT} *fmt-clippy* — <${FMT_URL}|view>" \ + --arg int "${INT} *integration-test* — <${INT_URL}|view>" \ + --arg art "$(printf '%b' "$ARTIFACT_LINKS")" \ + '{channel: $ch, blocks: [ + {type: "section", text: {type: "mrkdwn", text: $hdr}}, + {type: "section", fields: [ + {type: "mrkdwn", text: $fmt}, + {type: "mrkdwn", text: $int} + ]}, + {type: "divider"}, + {type: "section", text: {type: "mrkdwn", text: ("*Artifacts*\n" + $art)}} + ]}')" \ + "$SLACK_WEBHOOK_URL" From c38519ae2b1f65ede3165b3c45d90e0cb3c48e23 Mon Sep 17 00:00:00 2001 From: redpanda-f Date: Fri, 27 Feb 2026 13:20:48 +0000 Subject: [PATCH 2/3] add: github action for notify-slack --- .github/actions/notify-slack/action.yml | 115 ++++++++++++++++++++++++ .github/workflows/ci.yml | 18 ++++ .github/workflows/notify-slack.yml | 63 ------------- 3 files changed, 133 insertions(+), 63 deletions(-) create mode 100644 .github/actions/notify-slack/action.yml delete mode 100644 .github/workflows/notify-slack.yml diff --git a/.github/actions/notify-slack/action.yml b/.github/actions/notify-slack/action.yml new file mode 100644 index 00000000..d143a944 --- /dev/null +++ b/.github/actions/notify-slack/action.yml @@ -0,0 +1,115 @@ +--- +name: Notify Slack +description: Post a CI run summary to a Slack channel. + +inputs: + slack_webhook_url: + description: Slack incoming webhook URL. + required: true + slack_channel: + description: Slack channel to post to (e.g. #ci-notifications). + required: true + # Job results — pass needs..result for each job. + # Omit (or leave empty) any job that did not run in the calling workflow. + job_results: + description: > + JSON object mapping job names to their conclusions, e.g. + '{"fmt-clippy":"success","integration-test":"failure"}'. + Any job not present is treated as skipped. + required: true + # S3 artifact links (optional — omit if AWS is not configured). + ci_logs_bucket: + description: S3 bucket name where CI artifacts are stored. + required: false + default: '' + aws_default_region: + description: AWS region used to form the S3 URL. + required: false + default: '' + branch: + description: Branch name (used in S3 path). + required: false + default: ${{ github.head_ref || github.ref_name }} + run_id: + description: GitHub Actions run ID. + required: false + default: ${{ github.run_id }} + run_attempt: + description: GitHub Actions run attempt number. + required: false + default: ${{ github.run_attempt }} + repo: + description: Repository in owner/name format. + required: false + default: ${{ github.repository }} + +runs: + using: composite + steps: + - name: Send notification + shell: bash + env: + SLACK_WEBHOOK_URL: ${{ inputs.slack_webhook_url }} + SLACK_CHANNEL: ${{ inputs.slack_channel }} + JOB_RESULTS: ${{ inputs.job_results }} + CI_LOGS_BUCKET: ${{ inputs.ci_logs_bucket }} + AWS_DEFAULT_REGION: ${{ inputs.aws_default_region }} + BRANCH: ${{ inputs.branch }} + RUN_ID: ${{ inputs.run_id }} + RUN_ATTEMPT: ${{ inputs.run_attempt }} + REPO: ${{ inputs.repo }} + run: | + set -euo pipefail + + RUN_URL="https://github.com/${REPO}/actions/runs/${RUN_ID}" + BRANCH_S3="${BRANCH//\//-}" + + # Determine overall status (failure if any job failed/cancelled) + OVERALL="success" + while IFS= read -r conclusion; do + if [[ "$conclusion" == "failure" || "$conclusion" == "cancelled" ]]; then + OVERALL="failure" + break + fi + done < <(echo "$JOB_RESULTS" | jq -r 'to_entries[].value') + + icon() { [[ "$1" == "success" ]] && echo ":white_check_mark:" || echo ":x:"; } + OVERALL_ICON=$(icon "$OVERALL") + + # Build one bullet per job + JOBS_TEXT="" + while IFS=$'\t' read -r name conclusion; do + JOBS_TEXT="${JOBS_TEXT}• $(icon "$conclusion") ${name}\n" + done < <(echo "$JOB_RESULTS" | jq -r 'to_entries[] | [.key, .value] | @tsv') + + # Build artifact links if S3 is configured + ARTIFACT_TEXT="" + if [[ -n "$CI_LOGS_BUCKET" && -n "$AWS_DEFAULT_REGION" ]]; then + S3_BASE="https://${CI_LOGS_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/runs/${BRANCH_S3}/${RUN_ID}/${RUN_ATTEMPT}" + for f in setup.log devnet-info.json step_context.json version.txt post_start_status.log; do + ARTIFACT_TEXT="${ARTIFACT_TEXT}• <${S3_BASE}/${f}|${f}>\n" + done + fi + + # Assemble blocks + BLOCKS=$(jq -n \ + --arg hdr "${OVERALL_ICON} *CI <${RUN_URL}|#${RUN_ID}> · \`${BRANCH}\`*" \ + --arg jobs "$(printf '%b' "$JOBS_TEXT")" \ + --arg art "$(printf '%b' "$ARTIFACT_TEXT")" \ + --arg ch "$SLACK_CHANNEL" \ + '{ + channel: $ch, + blocks: ( + [ + {type: "section", text: {type: "mrkdwn", text: $hdr}}, + {type: "section", text: {type: "mrkdwn", text: ("*Jobs*\n" + $jobs)}} + ] + + (if $art != "" then [ + {type: "divider"}, + {type: "section", text: {type: "mrkdwn", text: ("*Artifacts*\n" + $art)}} + ] else [] end) + ) + }') + + curl -fsSL -X POST -H 'Content-Type: application/json' \ + --data "$BLOCKS" "$SLACK_WEBHOOK_URL" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eae120c3..b3f33053 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -450,3 +450,21 @@ jobs: run: | echo "Start cluster failed earlier; marking job as failed." >&2 exit 1 + + notify: + runs-on: ubuntu-latest + needs: [fmt-clippy, integration-test] + if: always() + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/notify-slack + with: + slack_webhook_url: ${{ secrets.SLACK_WEBHOOK_URL }} + slack_channel: ${{ secrets.SLACK_CHANNEL }} + ci_logs_bucket: ${{ secrets.CI_LOGS_BUCKET }} + aws_default_region: ${{ secrets.AWS_DEFAULT_REGION }} + job_results: | + { + "fmt-clippy": "${{ needs.fmt-clippy.result }}", + "integration-test": "${{ needs.integration-test.result }}" + } diff --git a/.github/workflows/notify-slack.yml b/.github/workflows/notify-slack.yml deleted file mode 100644 index 516a88fe..00000000 --- a/.github/workflows/notify-slack.yml +++ /dev/null @@ -1,63 +0,0 @@ ---- -name: Notify Slack - -on: - workflow_run: - workflows: ["CI"] - types: [completed] - -jobs: - notify: - runs-on: ubuntu-latest - steps: - - name: Post Slack notification - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }} - SLACK_CHANNEL: ${{ secrets.SLACK_CHANNEL }} - CI_LOGS_BUCKET: ${{ secrets.CI_LOGS_BUCKET }} - AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }} - RUN_ID: ${{ github.event.workflow_run.id }} - RUN_ATTEMPT: ${{ github.event.workflow_run.run_attempt }} - BRANCH: ${{ github.event.workflow_run.head_branch }} - CONCLUSION: ${{ github.event.workflow_run.conclusion }} - REPO: ${{ github.repository }} - run: | - set -euo pipefail - - BRANCH_S3="${BRANCH//\//-}" - S3_BASE="https://${CI_LOGS_BUCKET}.s3.${AWS_DEFAULT_REGION}.amazonaws.com/runs/${BRANCH_S3}/${RUN_ID}/${RUN_ATTEMPT}" - RUN_URL="https://github.com/${REPO}/actions/runs/${RUN_ID}" - - JOBS=$(gh api "repos/${REPO}/actions/runs/${RUN_ID}/jobs") - - job_conclusion() { echo "$JOBS" | jq -r --arg n "$1" '.jobs[] | select(.name == $n) | .conclusion'; } - job_url() { echo "$JOBS" | jq -r --arg n "$1" '.jobs[] | select(.name == $n) | .html_url'; } - icon() { [ "$1" = "success" ] && echo ":white_check_mark:" || echo ":x:"; } - - FMT_C=$(job_conclusion "fmt-clippy"); FMT_URL=$(job_url "fmt-clippy") - INT_C=$(job_conclusion "integration-test"); INT_URL=$(job_url "integration-test") - OVERALL=$(icon "$CONCLUSION"); FMT=$(icon "$FMT_C"); INT=$(icon "$INT_C") - - ARTIFACT_LINKS="" - for f in setup.log devnet-info.json step_context.json version.txt post_start_status.log; do - ARTIFACT_LINKS="${ARTIFACT_LINKS}• <${S3_BASE}/${f}|${f}>\n" - done - - curl -fsSL -X POST -H 'Content-Type: application/json' \ - --data "$(jq -n \ - --arg ch "$SLACK_CHANNEL" \ - --arg hdr "${OVERALL} *CI <${RUN_URL}|#${RUN_ID}> · \`${BRANCH}\`*" \ - --arg fmt "${FMT} *fmt-clippy* — <${FMT_URL}|view>" \ - --arg int "${INT} *integration-test* — <${INT_URL}|view>" \ - --arg art "$(printf '%b' "$ARTIFACT_LINKS")" \ - '{channel: $ch, blocks: [ - {type: "section", text: {type: "mrkdwn", text: $hdr}}, - {type: "section", fields: [ - {type: "mrkdwn", text: $fmt}, - {type: "mrkdwn", text: $int} - ]}, - {type: "divider"}, - {type: "section", text: {type: "mrkdwn", text: ("*Artifacts*\n" + $art)}} - ]}')" \ - "$SLACK_WEBHOOK_URL" From 211b7aea9f99b0453cd24fcd821f096aaa4dcc60 Mon Sep 17 00:00:00 2001 From: RedPanda Date: Fri, 27 Feb 2026 19:42:17 +0530 Subject: [PATCH 3/3] Update .github/workflows/ci.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- .github/workflows/ci.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3f33053..8f972a38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -400,8 +400,12 @@ jobs: BRANCH="${BRANCH//\//-}" S3_PATH="s3://${CI_LOGS_BUCKET}/runs/${BRANCH}/${GITHUB_RUN_ID}/${GITHUB_RUN_ATTEMPT}/" echo "Uploading ~/.foc-devnet/state/latest to ${S3_PATH}" - aws s3 sync ~/.foc-devnet/state/latest "${S3_PATH}" --no-progress || echo "aws s3 sync returned non-zero" - echo "Upload complete: ${S3_PATH}" + if aws s3 sync ~/.foc-devnet/state/latest "${S3_PATH}" --no-progress; then + echo "Upload complete: ${S3_PATH}" + else + echo "ERROR: aws s3 sync failed; logs were not uploaded to S3 at ${S3_PATH}" >&2 + exit 1 + fi # Verify cluster is running correctly - name: "EXEC: {Check cluster status}, independent"