mirror of
https://github.com/clockworklabs/SpacetimeDB.git
synced 2026-07-22 18:18:25 -04:00
5e6073eca9
# Description of Changes Add some debugging and retries to this job. # API and ABI breaking changes None # Expected complexity level and risk 1 # Testing hard to test without being in prod 🤷 --------- Co-authored-by: Zeke Foppa <bfops@users.noreply.github.com>
219 lines
8.8 KiB
YAML
219 lines
8.8 KiB
YAML
name: Discord notifications
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- master
|
|
|
|
permissions:
|
|
contents: read
|
|
pull-requests: read
|
|
|
|
jobs:
|
|
resolvePush:
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
is_pr_merge: ${{ steps.resolve.outputs.is_pr_merge }}
|
|
is_external: ${{ steps.resolve.outputs.is_external }}
|
|
pr_author: ${{ steps.resolve.outputs.pr_author }}
|
|
pr_head_ref: ${{ steps.resolve.outputs.pr_head_ref }}
|
|
pr_head_repo: ${{ steps.resolve.outputs.pr_head_repo }}
|
|
pr_number: ${{ steps.resolve.outputs.pr_number }}
|
|
pr_title: ${{ steps.resolve.outputs.pr_title }}
|
|
pr_url: ${{ steps.resolve.outputs.pr_url }}
|
|
steps:
|
|
- name: Resolve pushed commit
|
|
id: resolve
|
|
uses: actions/github-script@v7
|
|
with:
|
|
script: |
|
|
const { owner, repo } = context.repo;
|
|
const sha = context.sha;
|
|
|
|
async function findAssociatedPRs() {
|
|
// It seems that when we do this too promptly after a PR merge then the data isn't there, so we have a retry loop.
|
|
for (let attempt = 1; attempt <= 3; attempt++) {
|
|
core.info('Looking for associated PRs..');
|
|
const prs = await github.paginate(github.rest.repos.listPullRequestsAssociatedWithCommit, {
|
|
owner,
|
|
repo,
|
|
commit_sha: sha,
|
|
});
|
|
|
|
if (prs.length > 0) {
|
|
return prs;
|
|
}
|
|
|
|
core.info('No associated PRs found. Will check again.');
|
|
await new Promise((resolve) => setTimeout(resolve, 30000));
|
|
}
|
|
|
|
return [];
|
|
}
|
|
|
|
const prs = await findAssociatedPRs();
|
|
core.info(`Associated PR info found:`);
|
|
core.info(JSON.stringify(prs, null, 2));
|
|
|
|
if (prs.length === 0) {
|
|
core.info('No associated PRs found. Treating this push as a direct/non-PR push.');
|
|
core.setOutput('is_pr_merge', 'false');
|
|
core.info('Output is_pr_merge=false');
|
|
return;
|
|
}
|
|
if (prs.length > 1) {
|
|
core.info('Multiple associated PRs found. Failing because downstream notification expects exactly one PR.');
|
|
core.setFailed(`Expected exactly one PR associated with ${sha}, found ${prs.length}.`);
|
|
return;
|
|
}
|
|
const pr = prs[0];
|
|
|
|
const headRepo = pr.head?.repo?.full_name || '';
|
|
core.setOutput('is_pr_merge', 'true');
|
|
core.setOutput('is_external', String(headRepo !== `${owner}/${repo}`));
|
|
core.setOutput('pr_author', pr.user?.login || '');
|
|
core.setOutput('pr_head_ref', pr.head?.ref || '');
|
|
core.setOutput('pr_head_repo', headRepo);
|
|
core.setOutput('pr_number', String(pr.number));
|
|
core.setOutput('pr_title', pr.title || '');
|
|
core.setOutput('pr_url', pr.html_url || '');
|
|
|
|
discordNotification:
|
|
needs: resolvePush
|
|
runs-on: ubuntu-latest
|
|
if: needs.resolvePush.outputs.is_pr_merge == 'true'
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
steps:
|
|
- name: Set up GitHub CLI
|
|
run: |
|
|
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo tee /usr/share/keyrings/githubcli-archive-keyring.gpg > /dev/null
|
|
sudo apt-get install -y apt-transport-https
|
|
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list
|
|
sudo apt-get update
|
|
sudo apt-get install -y gh
|
|
|
|
# TODO: Perhaps we should merge this into the public-pr-merge.yml workflow, now that that exists.
|
|
- name: Send Discord notification
|
|
env:
|
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
|
PR_AUTHOR: ${{ needs.resolvePush.outputs.pr_author }}
|
|
PR_HEAD_REF: ${{ needs.resolvePush.outputs.pr_head_ref }}
|
|
PR_HEAD_REPO: ${{ needs.resolvePush.outputs.pr_head_repo }}
|
|
PR_IS_EXTERNAL: ${{ needs.resolvePush.outputs.is_external }}
|
|
PR_TITLE: ${{ needs.resolvePush.outputs.pr_title }}
|
|
PR_NUMBER: ${{ needs.resolvePush.outputs.pr_number }}
|
|
PR_URL: ${{ needs.resolvePush.outputs.pr_url }}
|
|
MENTION_ON_FAILURE: ${{ secrets.DEV_OPS_ROLE_ID }}
|
|
DISCORD_USER_MAP: ${{ secrets.DISCORD_USER_MAP }}
|
|
run: |
|
|
message="PR merged: [(#${PR_NUMBER}) ${PR_TITLE}](<${PR_URL}>)"
|
|
if [[ "${PR_IS_EXTERNAL}" == "true" ]]; then
|
|
message+=$'\n'
|
|
message+="External PR source: ${PR_HEAD_REPO}@${PR_HEAD_REF}"
|
|
fi
|
|
|
|
# Note that anything besides success is treated as a failure (e.g. if the check did not run at all, or if it is still pending).
|
|
FAILED_CHECKS="$(
|
|
gh pr checks "${PR_URL}" \
|
|
--json 'workflow,state,name' |
|
|
jq '.[]
|
|
| select(.workflow != "Discord notifications")
|
|
| select(.state != "SUCCESS" and .state != "NEUTRAL" and .state != "SKIPPED")
|
|
' |
|
|
jq -r '"\(.workflow) / \(.name): \(.state)"'
|
|
)"
|
|
|
|
# Lookup PR author's Discord ID from the provided JSON map (if any)
|
|
author_discord_id="$(
|
|
jq -r \
|
|
--arg u "${PR_AUTHOR}" \
|
|
'.[$u] // empty' \
|
|
<<<"${DISCORD_USER_MAP}"
|
|
)"
|
|
if [ -z "${author_discord_id}" ]; then
|
|
echo "Warning: PR author not found not found in USER_LOOKUP_JSON"
|
|
fi
|
|
|
|
message+=$'\n'
|
|
if [[ -z "${FAILED_CHECKS}" ]]; then
|
|
message+='All checks passed.'
|
|
else
|
|
message+="${FAILED_CHECKS}"
|
|
message+=$'\n'
|
|
# This uses special Discord syntax for pinging a particular role.
|
|
# Note the '&' - this is the difference between pinging a *role* and pinging a *person*.
|
|
if [[ -n "${author_discord_id}" ]]; then
|
|
message+="<@${author_discord_id}> please investigate these failures."
|
|
fi
|
|
message+=$'\n'
|
|
message+="(cc <@&${MENTION_ON_FAILURE}> - Releases may be affected)"
|
|
fi
|
|
# Use `jq` to construct the json data blob in the format required by the webhook.
|
|
data="$(jq --null-input --arg msg "$message" '.content=$msg')"
|
|
curl -X POST -H 'Content-Type: application/json' -d "$data" "${DISCORD_WEBHOOK_URL}"
|
|
|
|
notifyFailure:
|
|
needs:
|
|
- resolvePush
|
|
- discordNotification
|
|
runs-on: ubuntu-latest
|
|
if: ${{ always() && (needs.resolvePush.result == 'failure' || needs.discordNotification.result == 'failure') }}
|
|
steps:
|
|
- name: Send failure notification
|
|
env:
|
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
|
run: |
|
|
message="Discord notification workflow failed."
|
|
message+=$'\n'
|
|
message+="Run: https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
|
data="$(jq --null-input --arg msg "$message" '.content=$msg')"
|
|
curl -X POST -H 'Content-Type: application/json' -d "$data" "${DISCORD_WEBHOOK_URL}"
|
|
|
|
warnDirectPush:
|
|
needs: resolvePush
|
|
runs-on: ubuntu-latest
|
|
if: needs.resolvePush.outputs.is_pr_merge != 'true'
|
|
steps:
|
|
- name: Warn about non-PR push
|
|
env:
|
|
DISCORD_WEBHOOK_URL: ${{ secrets.DISCORD_WEBHOOK_URL }}
|
|
COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
|
|
COMMIT_URL: ${{ github.event.head_commit.url }}
|
|
PUSHER: ${{ github.event.pusher.name }}
|
|
SHA: ${{ github.sha }}
|
|
run: |
|
|
short_sha="${SHA:0:7}"
|
|
subject="$(printf '%s\n' "${COMMIT_MESSAGE}" | head -n 1)"
|
|
message="Warning: push to master was not associated with a merged PR."
|
|
message+=$'\n'
|
|
message+="Commit: [${short_sha}](<${COMMIT_URL}>)"
|
|
message+=$'\n'
|
|
message+="Pusher: ${PUSHER}"
|
|
message+=$'\n'
|
|
message+="Subject: ${subject}"
|
|
data="$(jq --null-input --arg msg "$message" '.content=$msg')"
|
|
curl -X POST -H 'Content-Type: application/json' -d "$data" "${DISCORD_WEBHOOK_URL}"
|
|
|
|
invokePrivate:
|
|
needs: resolvePush
|
|
runs-on: ubuntu-latest
|
|
if: needs.resolvePush.outputs.is_pr_merge == 'true'
|
|
permissions:
|
|
contents: read
|
|
steps:
|
|
- name: Dispatch private merge workflow
|
|
uses: actions/github-script@v7
|
|
with:
|
|
github-token: ${{ secrets.SPACETIMEDB_PRIVATE_TOKEN }}
|
|
script: |
|
|
await github.rest.actions.createWorkflowDispatch({
|
|
owner: 'clockworklabs',
|
|
repo: 'SpacetimeDBPrivate',
|
|
workflow_id: 'public-pr-merge.yml',
|
|
ref: 'master',
|
|
inputs: {
|
|
public_pr_number: '${{ needs.resolvePush.outputs.pr_number }}',
|
|
}
|
|
});
|