Skip to content

chore: bump actions/upload-artifact from 5 to 7 in /.github/actions/time-compilation #311

chore: bump actions/upload-artifact from 5 to 7 in /.github/actions/time-compilation

chore: bump actions/upload-artifact from 5 to 7 in /.github/actions/time-compilation #311

Workflow file for this run

# Generated by tend 0.0.18. Regenerate with: uvx tend@latest init
#
# Do not edit this file directly — it will be overwritten on regeneration.
# To customize behavior, edit the relevant skill (for example,
# `running-tend`) in this repo's .claude/skills/ directory, or open an issue at
# https://github.com/max-sixty/tend/issues for changes that need to
# happen upstream in the tend-ci-runner plugin.
name: tend-mention
on:
issues:
types: [edited]
issue_comment:
types: [created, edited]
# Works for same-repo PRs only; secrets unavailable on fork PRs (no _target variant exists)
pull_request_review:
types: [submitted]
# `created` is intentionally absent. Modern GitHub fires *both*
# pull_request_review and pull_request_review_comment for every newly-created
# inline comment (the standalone POST /pulls/PR/comments endpoint, the
# /replies endpoint, the "Add single comment" UI button, and reviews
# submitted with inline comments — all empirically verified). Subscribing to
# `created` would produce a duplicate workflow run that collides on the
# tend-mention-handle-PR concurrency group, with the loser cancelled and
# posted as a CANCELLED check_run on the PR head SHA — which renders the
# PR's statusCheckRollup as FAILURE even though the bot did its job from the
# sibling run. Edits have no sibling event (review submissions don't fire on
# edits), so we still need to listen for `edited` to catch edit-to-summon
# ("@bot" added to an existing comment after the fact).
pull_request_review_comment:
types: [edited]
jobs:
verify:
# Filter out fork PRs for review events — secrets are unavailable there
# (no _target variant exists). The notifications workflow polls for these.
# Skip comments on `tend-outage` issues: the action's Report-failure step
# auto-comments on those when Claude invocation fails, and without this
# guard those comments re-trigger tend-mention during a persistent outage
# (e.g. Anthropic 401), producing a self-sustaining ~1 run/minute loop
# until the outage clears. The prompt's self-loop guard can't help here
# because the model never executes — the action fails before Claude starts.
if: |
(github.event_name == 'issues' &&
contains(github.event.issue.body, '@prql-bot')) ||
(github.event_name == 'issue_comment' &&
!contains(github.event.issue.labels.*.name, 'tend-outage')) ||
(github.event_name == 'pull_request_review_comment' &&
github.event.pull_request.head.repo.full_name == github.repository) ||
(github.event_name == 'pull_request_review' &&
github.event.pull_request.head.repo.full_name == github.repository)
runs-on: ubuntu-24.04
outputs:
should_run: ${{ steps.check.outputs.should_run }}
steps:
- name: Verify bot engagement
id: check
run: |
# Mentions always run
if [ "$EVENT_NAME" = "issues" ]; then
echo "should_run=true" >> "$GITHUB_OUTPUT"
exit 0
fi
if [ -n "$COMMENT_BODY" ] && printf '%s\n' "$COMMENT_BODY" | grep -qF '@prql-bot'; then
echo "should_run=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# pull_request_review payloads include review.body (checked above)
# but NOT the bodies of inline comments attached to the review.
# Fetch them so a first-contact @-mention inside an inline comment
# is detected on PRs where the bot has no prior engagement.
if [ "$EVENT_NAME" = "pull_request_review" ] && [ -n "$REVIEW_ID" ]; then
if gh api --paginate "repos/$GITHUB_REPOSITORY/pulls/$EVENT_PR_NUMBER/reviews/$REVIEW_ID/comments" \
--jq '.[].body' | grep -qF '@prql-bot'; then
echo "should_run=true" >> "$GITHUB_OUTPUT"
exit 0
fi
fi
# Non-mention: check bot engagement
if [ "$EVENT_NAME" = "issue_comment" ]; then
ISSUE_NUMBER="$ISSUE_OR_PR_NUMBER"
if [ -z "$PR_URL" ]; then
if [ "$ISSUE_AUTHOR" = "prql-bot" ]; then
echo "should_run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
if printf '%s\n' "$ISSUE_BODY" | grep -qF '@prql-bot'; then
echo "should_run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
BOT_COMMENTS=$(gh api --paginate "repos/$GITHUB_REPOSITORY/issues/$ISSUE_NUMBER/comments" \
--jq '[.[] | select(.user.login == "prql-bot")] | length')
if [ "$BOT_COMMENTS" -gt "0" ]; then
echo "should_run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
echo "should_run=false" >> "$GITHUB_OUTPUT"; exit 0
fi
PR_NUMBER="$ISSUE_NUMBER"
else
PR_NUMBER="$EVENT_PR_NUMBER"
fi
PR_AUTHOR=$(gh pr view "$PR_NUMBER" --repo "$GITHUB_REPOSITORY" --json author --jq '.author.login')
if [ "$PR_AUTHOR" = "prql-bot" ]; then
echo "should_run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
BOT_REVIEWS=$(gh api --paginate "repos/$GITHUB_REPOSITORY/pulls/$PR_NUMBER/reviews" \
--jq '[.[] | select(.user.login == "prql-bot")] | length')
if [ "$BOT_REVIEWS" -gt "0" ]; then
echo "should_run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
BOT_COMMENTS=$(gh api --paginate "repos/$GITHUB_REPOSITORY/issues/$PR_NUMBER/comments" \
--jq '[.[] | select(.user.login == "prql-bot")] | length')
if [ "$BOT_COMMENTS" -gt "0" ]; then
echo "should_run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
echo "should_run=false" >> "$GITHUB_OUTPUT"
env:
GITHUB_TOKEN: ${{ secrets.PRQL_BOT_GITHUB_TOKEN }}
EVENT_NAME: ${{ github.event_name }}
COMMENT_BODY: ${{ github.event.comment.body || github.event.review.body }}
ISSUE_BODY: ${{ github.event.issue.body }}
ISSUE_OR_PR_NUMBER: ${{ github.event.issue.number }}
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
PR_URL: ${{ github.event.issue.pull_request.url }}
EVENT_PR_NUMBER: ${{ github.event.pull_request.number }}
REVIEW_ID: ${{ github.event.review.id }}
- name: React to mention
if: |
steps.check.outputs.should_run == 'true'
&& github.event.comment
&& contains(github.event.comment.body, '@prql-bot')
run: |
gh api "repos/$REPO/issues/comments/$COMMENT_ID/reactions" -f content=eyes 2>/dev/null || \
gh api "repos/$REPO/pulls/comments/$COMMENT_ID/reactions" -f content=eyes 2>/dev/null || true
env:
REPO: ${{ github.repository }}
COMMENT_ID: ${{ github.event.comment.id }}
GITHUB_TOKEN: ${{ secrets.PRQL_BOT_GITHUB_TOKEN }}
handle:
needs: verify
if: needs.verify.outputs.should_run == 'true'
concurrency:
group: ${{ github.workflow }}-handle-${{ github.event.issue.number || github.event.pull_request.number }}
cancel-in-progress: false
runs-on: ubuntu-24.04
permissions:
contents: write
pull-requests: write
id-token: write
actions: read
issues: write
steps:
- uses: actions/checkout@v6
with:
fetch-depth: 0
fetch-tags: true
token: ${{ secrets.PRQL_BOT_GITHUB_TOKEN }}
- uses: ./.github/actions/tend-setup
- name: Check out PR branch
if: |
(github.event_name == 'issue_comment' && github.event.issue.pull_request.url != '') ||
github.event_name == 'pull_request_review_comment' ||
github.event_name == 'pull_request_review'
run: |
PR_STATE=$(gh pr view "$PR_NUMBER" --json state --jq '.state')
if [ "$PR_STATE" = "OPEN" ]; then
gh pr checkout "$PR_NUMBER"
else
echo "::warning::PR is $PR_STATE — staying on default branch"
fi
env:
GITHUB_TOKEN: ${{ secrets.PRQL_BOT_GITHUB_TOKEN }}
PR_NUMBER: ${{ github.event_name == 'issue_comment' && github.event.issue.number || github.event.pull_request.number }}
- name: Compute queue delay
id: delay
run: |
if [ -z "$EVENT_TS" ]; then
echo "seconds=" >> "$GITHUB_OUTPUT"
exit 0
fi
event_epoch=$(date -d "$EVENT_TS" +%s)
echo "seconds=$(( $(date +%s) - event_epoch ))" >> "$GITHUB_OUTPUT"
env:
EVENT_TS: ${{ github.event.comment.created_at || github.event.review.submitted_at || github.event.issue.updated_at }}
- uses: max-sixty/tend@v1
with:
github_token: ${{ secrets.PRQL_BOT_GITHUB_TOKEN }}
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
bot_name: prql-bot
model: opus
prompt: >-
${{ steps.delay.outputs.seconds
&& format('This job started {0}s after the triggering event (over ~40s means it was queued). ',
steps.delay.outputs.seconds) || '' }}Before acting,
check recent comments: exit silently if the bot already responded
to the trigger; handle any other unaddressed comments too.
${{ github.event_name == 'issues'
&& format('An issue was updated with a mention of you ({0}). Read it and respond.', github.event.issue.html_url)
|| (github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@prql-bot')
&& format('You were mentioned in an inline review comment on PR #{0} ({1}, comment ID {2}). Read the full context, then respond. If changes are requested, make them, commit, and push.', (github.event_name == 'issue_comment' && github.event.issue.number || github.event.pull_request.number), github.event.comment.html_url, github.event.comment.id))
|| (github.event_name == 'pull_request_review_comment'
&& format('An inline review comment was posted on a PR where you previously participated (PR #{0}, {1}, comment ID {2}). Read the full context. Only respond if the comment is directed at you or requests changes.', (github.event_name == 'issue_comment' && github.event.issue.number || github.event.pull_request.number), github.event.comment.html_url, github.event.comment.id))
|| (github.event_name == 'pull_request_review' && contains(github.event.review.body, '@prql-bot')
&& format('A review was submitted on PR #{0} that mentions you ({1}, review ID {2}). Read the review and full context, then respond. If changes were requested, make them, commit, and push.', github.event.pull_request.number, github.event.review.html_url, github.event.review.id))
|| (github.event_name == 'pull_request_review'
&& format('A review was submitted on a PR where you previously participated (PR #{0}, {1}, review ID {2}). Read the review and full context. If the review requests changes or asks questions, respond appropriately. If the review approves or is between humans, exit silently.', github.event.pull_request.number, github.event.review.html_url, github.event.review.id))
|| (contains(github.event.comment.body, '@prql-bot')
&& format('You were mentioned in a comment ({0}). Read the full context and respond. If changes are requested, make them, commit, and push.', github.event.comment.html_url))
|| format('A user commented on an issue/PR where you previously participated ({0}). Read the full context. Only respond if the comment is directed at you, asks a question you can help with, or requests changes you can make. If the conversation is between other participants, exit silently.', github.event.comment.html_url)
}}