From 36c24ef681bd046db785039c9c4c590054f44b6f Mon Sep 17 00:00:00 2001 From: Talisson Costa Date: Fri, 21 Aug 2026 10:42:11 -0300 Subject: [PATCH] chore: notify Slack after frontend production deploy Post to #frontend-deploy once the production deploy succeeds, with the commit, who deployed, and links to production and the Actions run, as a prompt to smoke test. The message is built by a composite action so the API and MCP deploys can reuse it, and jq assembles the payload so values are escaped rather than interpolated into JSON. The job takes no GitHub token permissions beyond reading the repo, does not keep the checkout credentials, and does not fail the run if Slack is unreachable. Co-Authored-By: Claude Opus 5 (1M context) --- .../actions/notify-slack-deploy/action.yml | 88 +++++++++++++++++++ .../workflows/frontend-deploy-production.yml | 26 ++++++ 2 files changed, 114 insertions(+) create mode 100644 .github/actions/notify-slack-deploy/action.yml diff --git a/.github/actions/notify-slack-deploy/action.yml b/.github/actions/notify-slack-deploy/action.yml new file mode 100644 index 000000000000..c673ed55cb3a --- /dev/null +++ b/.github/actions/notify-slack-deploy/action.yml @@ -0,0 +1,88 @@ +name: Notify Slack of a deploy +description: Post a deploy notification to a Slack incoming webhook, prompting a smoke test. + +inputs: + webhook_url: + description: The Slack incoming webhook to post the notification to. + required: true + service: + description: The name of the deployed service, e.g. Frontend. + required: true + app_url: + description: The URL of the deployed application, linked from the notification. + required: true + environment: + description: The environment that was deployed to. + required: false + default: production + +runs: + using: composite + + steps: + - name: Post to Slack + shell: bash + env: + SLACK_WEBHOOK_URL: ${{ inputs.webhook_url }} + SERVICE: ${{ inputs.service }} + APP_URL: ${{ inputs.app_url }} + ENVIRONMENT: ${{ inputs.environment }} + COMMIT_SHA: ${{ github.sha }} + ACTOR: ${{ github.actor }} + WORKFLOW_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} + # jq builds the payload so every value is escaped for us, rather than + # interpolated into a JSON heredoc. + run: | + jq -n \ + --arg service "$SERVICE" \ + --arg environment "$ENVIRONMENT" \ + --arg short_sha "${COMMIT_SHA:0:7}" \ + --arg actor "$ACTOR" \ + --arg app_url "$APP_URL" \ + --arg workflow_url "$WORKFLOW_URL" \ + '($environment | (.[0:1] | ascii_upcase) + .[1:]) as $env_name | + { + # Slack honours username on this webhook but ignores icon_emoji. + # The avatar comes from the icon set on the Slack app itself. + username: "\($service) Deploy", + text: "๐Ÿš€ \($service) deployed to \($environment): smoke test required", + blocks: [ + { + type: "header", + text: { type: "plain_text", text: "๐Ÿš€ \($service) deployed to \($environment)" } + }, + { + type: "section", + text: { + type: "mrkdwn", + text: "๐Ÿงช *\($env_name) smoke test required*\n\nPlease verify the application directly in \($environment)." + } + }, + { + type: "section", + fields: [ + { type: "mrkdwn", text: "*Commit:*\n\($short_sha)" }, + { type: "mrkdwn", text: "*Deployed by:*\n@\($actor)" } + ] + }, + { + type: "actions", + elements: [ + { + type: "button", + text: { type: "plain_text", text: "Open \($env_name)" }, + url: $app_url + }, + { + type: "button", + text: { type: "plain_text", text: "View GitHub Actions" }, + url: $workflow_url + } + ] + } + ] + }' \ + | curl --fail-with-body --connect-timeout 10 --max-time 30 -X POST \ + -H 'Content-Type: application/json' \ + --data @- \ + "$SLACK_WEBHOOK_URL" diff --git a/.github/workflows/frontend-deploy-production.yml b/.github/workflows/frontend-deploy-production.yml index 5f2e1b3f66e7..47e0c2808f6e 100644 --- a/.github/workflows/frontend-deploy-production.yml +++ b/.github/workflows/frontend-deploy-production.yml @@ -79,6 +79,32 @@ jobs: npm_build_environment: prod secrets: inherit + notify-production-smoke-test: + name: Notify Production Smoke Test + needs: deploy-production + if: ${{ needs.deploy-production.result == 'success' }} + runs-on: ubuntu-latest + # Only needs to read the repo to resolve the local action below. + permissions: + contents: read + + steps: + - name: Cloning repo + uses: actions/checkout@fbc6f3992d24b796d5a048ff273f7fcc4a7b6c09 # v5.1.0 + with: + # Nothing runs git after this, so the token need not persist. + persist-credentials: false + + - name: Notify Slack + # The deploy has already succeeded by this point, so a Slack outage or a + # rotated webhook should not fail the run. + continue-on-error: true + uses: ./.github/actions/notify-slack-deploy + with: + webhook_url: ${{ secrets.SLACK_FRONTEND_DEPLOY_WEBHOOK }} + service: Frontend + app_url: https://app.flagsmith.com + deploy-demo: name: Deploy to Vercel Demo needs: run-tests