From bbaa214210bccf845deade9207ab381094b78e6d Mon Sep 17 00:00:00 2001 From: sklppy88 <152162806+sklppy88@users.noreply.github.com> Date: Thu, 5 Mar 2026 18:27:14 +0000 Subject: [PATCH] fix(docs): references dispatch claudebox fix wasn't properly dispatching --- docs/README.md | 15 +- docs/bootstrap.sh | 10 +- docs/scripts/check_doc_references.sh | 200 ++++++++++----- docs/scripts/lib/create_doc_update_pr.sh | 2 +- docs/scripts/test_update_doc_references.sh | 150 ------------ docs/scripts/update_doc_references.sh | 267 --------------------- 6 files changed, 150 insertions(+), 494 deletions(-) delete mode 100755 docs/scripts/test_update_doc_references.sh delete mode 100755 docs/scripts/update_doc_references.sh diff --git a/docs/README.md b/docs/README.md index 021092c850cd..eb3a5adabc3e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -570,24 +570,13 @@ Building on the DevRel review automation, the docs CI can analyze PRs and notify - `SLACK_DOC_UPDATE_CHANNEL` - Slack channel for notifications (default: `#devrel`) - `DRY_RUN=1` - Skip Slack notification, just print what would be sent -**Implementation**: The automation is handled by `scripts/update_doc_references.sh`, which runs as part of the docs CI pipeline after `check_doc_references.sh`. +**Implementation**: The automation is handled by `scripts/check_doc_references.sh`, which detects changed references, requests devrel review, sends a Slack notification, and dispatches ClaudeBox — all in a single pass. **Script Architecture**: -- `scripts/update_doc_references.sh` - Main script that orchestrates the workflow +- `scripts/check_doc_references.sh` - Main script that handles detection, review requests, Slack, and ClaudeBox dispatch - `scripts/lib/extract_doc_references.sh` - Shared library for parsing frontmatter references - `scripts/lib/create_doc_update_pr.sh` - (Reserved for future use) PR creation logic -- `scripts/test_update_doc_references.sh` - Local testing helper - -**Local Testing**: - -```bash -# Find a PR with referenced file changes and test -./scripts/test_update_doc_references.sh - -# Test against a specific PR -LOCAL_TEST=1 DRY_RUN=1 ./scripts/update_doc_references.sh 19803 -``` **Limitations**: diff --git a/docs/bootstrap.sh b/docs/bootstrap.sh index c9d57ac900de..815b6aed90bd 100755 --- a/docs/bootstrap.sh +++ b/docs/bootstrap.sh @@ -52,15 +52,14 @@ function test { } function check_references { + if [[ "${GITHUB_EVENT_NAME:-}" != "merge_group" ]]; then + echo "Skipping doc reference check (only runs in merge queue)." + return + fi echo_header "Check doc references" ./scripts/check_doc_references.sh docs || true } -function update_doc_references { - echo_header "Auto-update doc references" - ./scripts/update_doc_references.sh docs || true -} - function build_examples { echo_header "Building examples" (cd examples && ./bootstrap.sh "$@") @@ -72,7 +71,6 @@ case "$cmd" in build_docs test check_references - update_doc_references ;; "") build_examples diff --git a/docs/scripts/check_doc_references.sh b/docs/scripts/check_doc_references.sh index 2bc28a692d98..d01cf42082a8 100755 --- a/docs/scripts/check_doc_references.sh +++ b/docs/scripts/check_doc_references.sh @@ -1,14 +1,15 @@ #!/usr/bin/env bash set -euo pipefail -# check_doc_references - Request devrel review when referenced source files change +# check_doc_references - Request devrel review and dispatch ClaudeBox when referenced source files change # # This script: # 1. Extracts all 'references' fields from documentation markdown frontmatter # 2. Checks if any referenced files were changed in the current PR # 3. Requests AztecProtocol/devrel team as reviewers if files changed and PR is not draft # 4. Sends a Slack message to #devrel-docs-updates showing which changed files are referenced by which docs -# 5. Skips reviewer request if devrel team is already requested or a member has approved +# 5. Dispatches ClaudeBox to analyze changes and update documentation +# 6. Skips reviewer request if devrel team is already requested or a member has approved # # Usage: check_doc_references.sh [pr_number] [docs_dir] # @@ -96,11 +97,13 @@ elif [[ $# -ge 1 ]]; then DOCS_DIR="$1" fi -# Check if gh CLI is available -if ! command -v gh &> /dev/null; then - echo "gh CLI not found. Skipping devrel review check." - exit 0 -fi +# Check required tools +for tool in gh jq; do + if ! command -v "$tool" &> /dev/null; then + echo "$tool not found. Skipping devrel review check." + exit 0 + fi +done # Get the PR number from various sources PR_NUMBER="" @@ -260,85 +263,168 @@ REQUESTED_TEAMS=$(echo "$REVIEW_REQUESTS_JSON" | jq -r '.reviewRequests[]? | sel echo "Requested teams: ${REQUESTED_TEAMS:-none}" +# Determine if devrel review request and Slack notification should be skipped +SKIP_REVIEW=false + if [[ -n "$REQUESTED_TEAMS" ]] && echo "$REQUESTED_TEAMS" | grep -q "devrel"; then - echo "AztecProtocol/devrel team is already a requested reviewer for PR #$PR_NUMBER. Skipping." - exit 0 + echo "AztecProtocol/devrel team is already a requested reviewer for PR #$PR_NUMBER." + SKIP_REVIEW=true fi -# Check if any devrel team member has already approved -echo "Checking if devrel team member has already approved..." -DEVREL_MEMBERS=$(gh api orgs/AztecProtocol/teams/devrel/members --jq '.[].login' 2>/dev/null || echo "") -if [[ -n "$DEVREL_MEMBERS" ]]; then - APPROVERS=$(gh pr view "$PR_NUMBER" --json reviews -q '.reviews[] | select(.state == "APPROVED") | .author.login' 2>/dev/null || echo "") - if [[ -n "$APPROVERS" ]]; then - while IFS= read -r approver; do - if echo "$DEVREL_MEMBERS" | grep -qx "$approver"; then - echo "PR #$PR_NUMBER already approved by devrel team member: $approver. Skipping team review request." - exit 0 - fi - done <<< "$APPROVERS" +if [[ "$SKIP_REVIEW" != "true" ]]; then + # Check if any devrel team member has already approved + echo "Checking if devrel team member has already approved..." + DEVREL_MEMBERS=$(gh api orgs/AztecProtocol/teams/devrel/members --jq '.[].login' 2>/dev/null || echo "") + if [[ -n "$DEVREL_MEMBERS" ]]; then + APPROVERS=$(gh pr view "$PR_NUMBER" --json reviews -q '.reviews[] | select(.state == "APPROVED") | .author.login' 2>/dev/null || echo "") + if [[ -n "$APPROVERS" ]]; then + while IFS= read -r approver; do + if echo "$DEVREL_MEMBERS" | grep -qx "$approver"; then + echo "PR #$PR_NUMBER already approved by devrel team member: $approver." + SKIP_REVIEW=true + break + fi + done <<< "$APPROVERS" + fi fi fi -# Build Slack message with file-to-docs mapping -# Get PR URL for linking +# Get PR URL and title (needed for both Slack and ClaudeBox) PR_URL=$(gh pr view "$PR_NUMBER" --json url -q .url 2>/dev/null || echo "https://github.com/AztecProtocol/aztec-packages/pull/$PR_NUMBER") +PR_TITLE=$(gh pr view "$PR_NUMBER" --json title -q .title 2>/dev/null || echo "") + +# Request devrel review (only if not already done) +if [[ "$SKIP_REVIEW" != "true" ]]; then + echo "Requesting AztecProtocol/devrel team as a reviewer for PR #$PR_NUMBER..." + if gh pr edit "$PR_NUMBER" --add-reviewer AztecProtocol/devrel 2>/dev/null; then + echo "āœ“ Successfully requested AztecProtocol/devrel team as a reviewer." + else + echo "⚠ Failed to request AztecProtocol/devrel team as a reviewer." + fi +else + echo "Skipping reviewer request (already handled)." +fi -SLACK_MESSAGE="šŸ“š *Documentation References Updated*\\n\\nThe following source files changed in <$PR_URL|PR #$PR_NUMBER> are referenced by documentation:\\n" - -# Get unique doc files count +# Build changed references summary (used for both Slack and ClaudeBox) +CHANGED_SUMMARY="" ALL_DOCS="" CHANGED_FILE_COUNT=0 - -# Sort the keys for consistent output SORTED_KEYS=$(for key in "${!FILE_TO_DOCS_MAP[@]}"; do echo "$key"; done | sort) while IFS= read -r changed_file; do [[ -z "$changed_file" ]] && continue CHANGED_FILE_COUNT=$((CHANGED_FILE_COUNT + 1)) - SLACK_MESSAGE="${SLACK_MESSAGE}\\n*\`${changed_file}\`*" - - # Get docs for this file and split by pipe docs="${FILE_TO_DOCS_MAP[$changed_file]}" - - # Convert pipe-separated list to array and iterate IFS='|' read -ra DOC_ARRAY <<< "$docs" + DOC_LIST=$(printf ", %s" "${DOC_ARRAY[@]}") + DOC_LIST="${DOC_LIST:2}" + CHANGED_SUMMARY="${CHANGED_SUMMARY}${changed_file} -> ${DOC_LIST}; " for doc_file in "${DOC_ARRAY[@]}"; do - SLACK_MESSAGE="${SLACK_MESSAGE}\\n • \`${doc_file}\`" - - # Track all unique docs if ! echo "$ALL_DOCS" | grep -qF "$doc_file"; then ALL_DOCS="${ALL_DOCS}${doc_file}\n" fi done done <<< "$SORTED_KEYS" - -# Count unique docs +CHANGED_SUMMARY="${CHANGED_SUMMARY%%; }" DOC_FILE_COUNT=$(echo -e "$ALL_DOCS" | grep -v '^$' | sort -u | wc -l) -SLACK_MESSAGE="${SLACK_MESSAGE}\\n\\n*Summary:* ${CHANGED_FILE_COUNT} changed file(s) referenced by ${DOC_FILE_COUNT} documentation file(s)" - -echo "Requesting AztecProtocol/devrel team as a reviewer for PR #$PR_NUMBER..." +# Dispatch ClaudeBox +echo "Dispatching ClaudeBox workflow..." +CLAUDEBOX_RUNS_URL="https://github.com/AztecProtocol/aztec-packages/actions/workflows/claudebox.yml" +CLAUDEBOX_STATUS="" -# Request AztecProtocol/devrel team as a reviewer -REVIEWER_REQUESTED=false -if gh pr edit "$PR_NUMBER" --add-reviewer AztecProtocol/devrel 2>/dev/null; then - echo "āœ“ Successfully requested AztecProtocol/devrel team as a reviewer." - REVIEWER_REQUESTED=true - SLACK_MESSAGE="${SLACK_MESSAGE}\\n\\n@AztecProtocol/devrel team has been requested for review." +if gh workflow run claudebox.yml \ + -f prompt="PR #$PR_NUMBER ($PR_TITLE) changed source files referenced by documentation. Analyze the changes and update the affected documentation. Changed references: $CHANGED_SUMMARY. Follow the update-doc-references skill (.claude/skills/update-doc-references/SKILL.md)." \ + -f link="$PR_URL"; then + echo "āœ“ ClaudeBox dispatched for PR #$PR_NUMBER." + CLAUDEBOX_STATUS="dispatched" else - echo "⚠ Failed to request AztecProtocol/devrel team as a reviewer. They may need to be added manually." - SLACK_MESSAGE="${SLACK_MESSAGE}\\n\\nāš ļø Failed to automatically add @AztecProtocol/devrel as reviewers. Please add them manually." + echo "⚠ Failed to dispatch ClaudeBox workflow. Manual review may be needed." + CLAUDEBOX_STATUS="failed" fi -# Send Slack notification -echo "Sending Slack notification to #devrel-docs-updates..." -if send_slack_message "$SLACK_MESSAGE"; then - echo "āœ“ Successfully sent Slack notification." +# Send or update Slack notification (one message per PR, updated on each run) +SLACK_CHANNEL="${SLACK_DOC_UPDATE_CHANNEL:-devrel-docs-updates}" +TS="" +CHANNEL_ID="" + +if [[ -n "${SLACK_BOT_TOKEN:-}" ]]; then + # Build the Slack message + NOW=$(date -u '+%Y-%m-%d %H:%M UTC') + SLACK_MESSAGE="šŸ“š *Documentation References Updated*\\n\\nThe following source files changed in <$PR_URL|PR #$PR_NUMBER> are referenced by documentation:\\n" + + while IFS= read -r changed_file; do + [[ -z "$changed_file" ]] && continue + SLACK_MESSAGE="${SLACK_MESSAGE}\\n*\`${changed_file}\`*" + docs="${FILE_TO_DOCS_MAP[$changed_file]}" + IFS='|' read -ra DOC_ARRAY <<< "$docs" + for doc_file in "${DOC_ARRAY[@]}"; do + SLACK_MESSAGE="${SLACK_MESSAGE}\\n • \`${doc_file}\`" + done + done <<< "$SORTED_KEYS" + + SLACK_MESSAGE="${SLACK_MESSAGE}\\n\\n*Summary:* ${CHANGED_FILE_COUNT} changed file(s) referenced by ${DOC_FILE_COUNT} documentation file(s)" + + if [[ "$CLAUDEBOX_STATUS" == "dispatched" ]]; then + SLACK_MESSAGE="${SLACK_MESSAGE}\\n\\n:robot_face: *ClaudeBox dispatched* — <$CLAUDEBOX_RUNS_URL|view workflow runs>\\n_Last updated: ${NOW}_" + else + SLACK_MESSAGE="${SLACK_MESSAGE}\\n\\n:warning: *ClaudeBox dispatch failed* — manual review needed\\n_Last updated: ${NOW}_" + fi + + # Look up channel ID + CHANNEL_ID=$(curl -sS "https://slack.com/api/conversations.list?types=public_channel&limit=200" \ + -H "Authorization: Bearer $SLACK_BOT_TOKEN" | jq -r ".channels[] | select(.name==\"$SLACK_CHANNEL\") | .id" 2>/dev/null || echo "") + + if [[ -n "$CHANNEL_ID" ]]; then + # Search channel history for an existing message about this PR (paginate up to 1000 messages) + EXISTING_TS="" + CURSOR="" + PAGES=0 + while [[ $PAGES -lt 5 ]]; do + PAGES=$((PAGES + 1)) + HISTORY_URL="https://slack.com/api/conversations.history?channel=$CHANNEL_ID&limit=200" + [[ -n "$CURSOR" ]] && HISTORY_URL="${HISTORY_URL}&cursor=$CURSOR" + + HISTORY_RESP=$(curl -sS "$HISTORY_URL" -H "Authorization: Bearer $SLACK_BOT_TOKEN") + + EXISTING_TS=$(echo "$HISTORY_RESP" | \ + jq -r ".messages[]? | select(.text != null and .bot_id != null and (.text | contains(\"PR #$PR_NUMBER\"))) | .ts" 2>/dev/null | head -1 || echo "") + [[ -n "$EXISTING_TS" ]] && break + + CURSOR=$(echo "$HISTORY_RESP" | jq -r '.response_metadata.next_cursor // empty' 2>/dev/null) + [[ -z "$CURSOR" ]] && break + done + + if [[ -n "$EXISTING_TS" ]]; then + # Update existing message + echo "Updating existing Slack message for PR #$PR_NUMBER..." + RESP=$(curl -sS -X POST https://slack.com/api/chat.update \ + -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ + -H "Content-type: application/json" \ + -d "$(jq -n --arg c "$CHANNEL_ID" --arg ts "$EXISTING_TS" --arg t "$SLACK_MESSAGE" \ + '{channel:$c, ts:$ts, text:$t}')") + TS="$EXISTING_TS" + else + # Post new message + echo "Sending Slack notification to #${SLACK_CHANNEL}..." + RESP=$(curl -sS -X POST https://slack.com/api/chat.postMessage \ + -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ + -H "Content-type: application/json" \ + -d "$(jq -n --arg c "$CHANNEL_ID" --arg t "$SLACK_MESSAGE" '{channel:$c, text:$t}')") + TS=$(echo "$RESP" | jq -r '.ts // empty') + fi + + SLACK_OK=$(echo "$RESP" | jq -r '.ok // empty') + if [[ "$SLACK_OK" == "true" ]]; then + echo "āœ“ Slack notification sent/updated successfully." + else + SLACK_ERR=$(echo "$RESP" | jq -r '.error // "unknown error"' 2>/dev/null) + echo "⚠ Slack API error: $SLACK_ERR" >&2 + fi + else + echo "⚠ Could not find Slack channel #$SLACK_CHANNEL" + fi else - echo "⚠ Failed to send Slack notification." >&2 + echo "SLACK_BOT_TOKEN not set, skipping Slack notification" fi - -# Exit successfully even if Slack notification fails (don't block builds) -exit 0 diff --git a/docs/scripts/lib/create_doc_update_pr.sh b/docs/scripts/lib/create_doc_update_pr.sh index 3999d982eb16..d377017e06f4 100755 --- a/docs/scripts/lib/create_doc_update_pr.sh +++ b/docs/scripts/lib/create_doc_update_pr.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # create_doc_update_pr.sh - Create a PR with documentation updates # -# This script is extracted from update_doc_references.sh for future use. +# This script is extracted from check_doc_references.sh for future use. # It handles: # - Creating a branch for doc updates # - Committing changes diff --git a/docs/scripts/test_update_doc_references.sh b/docs/scripts/test_update_doc_references.sh deleted file mode 100755 index 86772a0c177e..000000000000 --- a/docs/scripts/test_update_doc_references.sh +++ /dev/null @@ -1,150 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Test script for update_doc_references.sh -# This script helps test the documentation update workflow locally -# -# Usage: -# ./scripts/test_update_doc_references.sh [pr_number] -# -# If no PR number is provided, it will: -# 1. Find a recent merged PR that changed files referenced in docs -# 2. Simulate testing against that PR - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -REPO_ROOT=$(git rev-parse --show-toplevel) - -# Source shared libraries -source "$SCRIPT_DIR/lib/extract_doc_references.sh" - -cd "$REPO_ROOT/docs" - -echo "=== Documentation Update Test Script ===" -echo "" - -# Check for Anthropic API key -if [[ -z "${ANTHROPIC_API_KEY:-}" ]]; then - echo "WARNING: ANTHROPIC_API_KEY environment variable is not set." - echo "Claude analysis will be skipped. Set the key to test full functionality:" - echo " export ANTHROPIC_API_KEY='your-api-key-here'" - echo "" -fi - -# Check for Claude CLI -if ! command -v claude &> /dev/null; then - echo "WARNING: Claude Code CLI not found." - echo "Install it with: npm install -g @anthropic-ai/claude-code" - echo "" -fi - -# Get PR number -PR_NUMBER="${1:-}" - -if [[ -z "$PR_NUMBER" ]]; then - echo "No PR number provided. Looking for a recent PR with referenced file changes..." - echo "" - - # Extract all referenced files from docs using shared lib - MAPPING_FILE=$(mktemp) - TEMP_FILES_TO_CLEAN=("$MAPPING_FILE") - trap 'rm -f "${TEMP_FILES_TO_CLEAN[@]}"' EXIT - - extract_references_mapping "." "$MAPPING_FILE" - REFERENCED_FILES=$(get_unique_references "$MAPPING_FILE" | head -20) - - echo "Sample referenced files:" - echo "$REFERENCED_FILES" | head -5 - echo "..." - echo "" - - # Find recent merged PRs - echo "Checking recent PRs for changes to referenced files..." - - for pr in $(gh pr list --state merged --limit 20 --json number --jq '.[].number'); do - CHANGED=$(gh pr view "$pr" --json files --jq '.files[].path' 2>/dev/null || echo "") - - # Check if any changed file matches referenced files - while IFS= read -r ref_file; do - [[ -z "$ref_file" ]] && continue - match_pattern="${ref_file%/\*}" - if echo "$CHANGED" | grep -qF "$match_pattern"; then - echo "Found PR #$pr with changes to referenced file: $match_pattern" - PR_NUMBER="$pr" - break 2 - fi - done <<< "$REFERENCED_FILES" - done - - if [[ -z "$PR_NUMBER" ]]; then - echo "" - echo "No recent PR found with changes to referenced files." - echo "" - echo "You can still test by providing a specific PR number:" - echo " ./scripts/test_update_doc_references.sh " - echo "" - echo "Or create a test branch with changes to a referenced file." - exit 0 - fi -fi - -echo "" -echo "Testing with PR #$PR_NUMBER" -echo "" - -# Show PR details -echo "PR Details:" -gh pr view "$PR_NUMBER" --json title,url,state,baseRefName --jq '" Title: \(.title)\n URL: \(.url)\n State: \(.state)\n Base: \(.baseRefName)"' -echo "" - -# Show changed files -echo "Changed files in PR:" -gh pr view "$PR_NUMBER" --json files --jq '.files[].path' | head -10 -echo "" - -# Find which docs reference these files -echo "Checking which docs reference these files..." -CHANGED_FILES=$(gh pr view "$PR_NUMBER" --json files --jq '.files[].path') - -# Use shared library to build mappings -MAPPING_FILE=$(mktemp) -TEMP_FILES_TO_CLEAN+=("$MAPPING_FILE") - -extract_references_mapping "." "$MAPPING_FILE" -build_change_mappings "$MAPPING_FILE" "$CHANGED_FILES" - -if [[ -z "$CHANGED_REFERENCES" ]] || [[ "$CHANGED_REFERENCES" == "\n" ]]; then - echo "" - echo "No documentation files reference the changed files in this PR." - echo "The update script would exit early in this case." - exit 0 -fi - -echo "" -echo "Affected documentation files:" -for doc in "${!DOC_TO_FILES_MAP[@]}"; do - echo " $doc" - echo " References: ${DOC_TO_FILES_MAP[$doc]}" -done - -echo "" -echo "=== Ready to Test ===" -echo "" -echo "To run the update script in DRY_RUN mode (won't send Slack):" -echo "" -echo " LOCAL_TEST=1 DRY_RUN=1 ./scripts/update_doc_references.sh $PR_NUMBER" -echo "" -echo "To run with Slack notification (requires SLACK_BOT_TOKEN):" -echo "" -echo " LOCAL_TEST=1 DRY_RUN=0 ./scripts/update_doc_references.sh $PR_NUMBER" -echo "" - -# Ask if user wants to proceed -read -p "Run in DRY_RUN mode now? [y/N] " -n 1 -r -echo "" - -if [[ $REPLY =~ ^[Yy]$ ]]; then - echo "" - echo "Running update_doc_references.sh in DRY_RUN mode..." - echo "" - LOCAL_TEST=1 DRY_RUN=1 ./scripts/update_doc_references.sh "$PR_NUMBER" -fi diff --git a/docs/scripts/update_doc_references.sh b/docs/scripts/update_doc_references.sh deleted file mode 100755 index fcc40e86f21d..000000000000 --- a/docs/scripts/update_doc_references.sh +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# update_doc_references.sh - Dispatch ClaudeBox when referenced source files change -# -# This script: -# 1. Extracts all 'references' fields from documentation markdown frontmatter -# 2. Checks if any referenced files were changed in the current PR -# 3. Dispatches the ClaudeBox workflow to analyze changes and update docs -# -# Usage: ./update_doc_references.sh [pr_number] [docs_dir] -# -# Environment: -# GITHUB_HEAD_REF - PR branch name (set by GitHub Actions) -# GH_TOKEN - GitHub token for gh CLI (set by GitHub Actions) -# SLACK_BOT_TOKEN - Slack bot token for notifications -# SLACK_DOC_UPDATE_CHANNEL - Slack channel for notifications (default: #devrel-docs-updates) -# CI - Set to 1 in CI environment -# DRY_RUN - Set to 1 to skip dispatch (for testing) -# LOCAL_TEST - Set to 1 to enable local testing mode - -readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -readonly REPO_ROOT=$(git rev-parse --show-toplevel) - -# Source shared libraries -source "$SCRIPT_DIR/lib/extract_doc_references.sh" - -# Cleanup function for temp files -TEMP_FILES=() -cleanup() { - for f in "${TEMP_FILES[@]}"; do - rm -f "$f" - done -} -trap cleanup EXIT - -# Check for local testing mode -LOCAL_TEST="${LOCAL_TEST:-0}" -DRY_RUN="${DRY_RUN:-0}" - -if [[ "${CI:-0}" != "1" ]] && [[ "$LOCAL_TEST" != "1" ]]; then - echo "Not running in CI environment. Skipping automatic doc updates." - echo "" - echo "To test locally, run:" - echo " LOCAL_TEST=1 DRY_RUN=1 ./scripts/update_doc_references.sh " - echo "" - echo "Options:" - echo " LOCAL_TEST=1 - Enable local testing mode" - echo " DRY_RUN=1 - Skip dispatch (just show what would be dispatched)" - echo " pr_number - The PR number to analyze" - exit 0 -fi - -if [[ "$LOCAL_TEST" == "1" ]]; then - echo "Running in LOCAL_TEST mode..." - DRY_RUN="${DRY_RUN:-1}" -fi - -cd "$REPO_ROOT" - -# Parse arguments -PR_NUMBER_ARG="" -DOCS_DIR="docs" - -if [[ $# -ge 1 ]] && [[ "$1" =~ ^[0-9]+$ ]]; then - PR_NUMBER_ARG="$1" - DOCS_DIR="${2:-docs}" -elif [[ $# -ge 1 ]]; then - DOCS_DIR="$1" -fi - -# Check required tools -for tool in gh jq; do - if ! command -v "$tool" &> /dev/null; then - echo "$tool not found. Skipping automatic doc updates." - exit 0 - fi -done - -# Check for Slack token (required unless DRY_RUN) -if [[ -z "${SLACK_BOT_TOKEN:-}" ]] && [[ "$DRY_RUN" != "1" ]]; then - echo "SLACK_BOT_TOKEN not set. Skipping Slack notification." - echo "Set DRY_RUN=1 to test without Slack." - exit 0 -fi - -# Get the PR number from various sources -PR_NUMBER="" -BRANCH="${GITHUB_HEAD_REF:-$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "")}" - -if [[ -n "$PR_NUMBER_ARG" ]]; then - PR_NUMBER="$PR_NUMBER_ARG" - echo "Using provided PR #$PR_NUMBER" -elif [[ -n "$BRANCH" ]] && [[ "$BRANCH" != "HEAD" ]]; then - PR_NUMBER=$(gh pr list --head "$BRANCH" --json number --jq '.[0].number' 2>/dev/null || echo "") - [[ -n "$PR_NUMBER" ]] && echo "Detected PR #$PR_NUMBER from branch $BRANCH" -fi - -if [[ -z "$PR_NUMBER" ]]; then - echo "Not in a PR context. Skipping automatic doc updates." - exit 0 -fi - -echo "Checking for documentation updates needed for PR #$PR_NUMBER..." - -# Check if PR is draft - skip for drafts -IS_DRAFT=$(gh pr view "$PR_NUMBER" --json isDraft -q .isDraft 2>/dev/null || echo "true") -if [[ "$IS_DRAFT" == "true" ]]; then - echo "PR #$PR_NUMBER is a draft. Skipping automatic doc updates." - exit 0 -fi - -# Get PR details for later use -PR_TITLE=$(gh pr view "$PR_NUMBER" --json title -q .title 2>/dev/null || echo "") -PR_URL=$(gh pr view "$PR_NUMBER" --json url -q .url 2>/dev/null || echo "") -PR_AUTHOR=$(gh pr view "$PR_NUMBER" --json author -q .author.login 2>/dev/null || echo "") -BASE_BRANCH=$(gh pr view "$PR_NUMBER" --json baseRefName -q .baseRefName 2>/dev/null || echo "") - -echo "PR Title: $PR_TITLE" -echo "PR URL: $PR_URL" - -# Extract all reference file paths from markdown frontmatter -echo "Extracting references from markdown files in $DOCS_DIR..." - -MAPPING_FILE=$(mktemp) -TEMP_FILES+=("$MAPPING_FILE") - -extract_references_mapping "$DOCS_DIR" "$MAPPING_FILE" - -REFERENCE_FILES=$(get_unique_references "$MAPPING_FILE") - -if [[ -z "$REFERENCE_FILES" ]]; then - echo "No reference files found in documentation frontmatter." - exit 0 -fi - -REF_COUNT=$(echo "$REFERENCE_FILES" | wc -l | tr -d ' ') -echo "Found $REF_COUNT unique referenced file(s)." - -# Get the base branch -if [[ -z "$BASE_BRANCH" ]]; then - echo "Could not determine PR base branch. Skipping automatic doc updates." - exit 0 -fi -echo "PR base branch: $BASE_BRANCH" - -# Fetch and find merge-base -echo "Fetching git history..." -git fetch --deepen=100 2>/dev/null || true - -if ! git fetch --depth=100 origin "$BASE_BRANCH" 2>/dev/null; then - echo "Failed to fetch origin/$BASE_BRANCH. Skipping automatic doc updates." - exit 0 -fi - -MERGE_BASE=$(git merge-base HEAD "origin/$BASE_BRANCH" 2>/dev/null || echo "") -if [[ -z "$MERGE_BASE" ]]; then - git fetch --unshallow 2>/dev/null || true - MERGE_BASE=$(git merge-base HEAD "origin/$BASE_BRANCH" 2>/dev/null || echo "") - if [[ -z "$MERGE_BASE" ]]; then - echo "Could not determine merge-base. Skipping automatic doc updates." - exit 0 - fi -fi -echo "Merge-base: $MERGE_BASE" - -# Get changed files - use different methods for CI vs local testing -if [[ "$LOCAL_TEST" == "1" ]]; then - echo "Fetching changed files from PR #$PR_NUMBER via GitHub API..." - CHANGED_FILES=$(gh pr view "$PR_NUMBER" --json files --jq '.files[].path' 2>/dev/null || echo "") -else - CHANGED_FILES=$(git diff --name-only "$MERGE_BASE"...HEAD 2>/dev/null || echo "") -fi - -if [[ -z "$CHANGED_FILES" ]]; then - echo "No changed files detected in PR. Skipping automatic doc updates." - exit 0 -fi -echo "Found $(echo "$CHANGED_FILES" | wc -l | tr -d ' ') changed file(s) in PR." - -# Build mappings of changed files to docs -build_change_mappings "$MAPPING_FILE" "$CHANGED_FILES" - -if [[ -z "$CHANGED_REFERENCES" ]] || [[ "$CHANGED_REFERENCES" == "\n" ]]; then - echo "No referenced files were changed in this PR. Skipping automatic doc updates." - exit 0 -fi - -echo "" -echo "The following referenced files were changed in this PR:" -echo -e "$CHANGED_REFERENCES" -echo "" - -# Get unique docs that need updating -DOCS_TO_UPDATE=$(for doc in "${!DOC_TO_FILES_MAP[@]}"; do echo "$doc"; done | sort -u) -DOC_COUNT=$(echo "$DOCS_TO_UPDATE" | grep -v '^$' | wc -l | tr -d ' ') - -echo "Found $DOC_COUNT documentation file(s) that may need updates." - -if [[ "$DOC_COUNT" -eq 0 ]]; then - echo "No documentation files need updating." - exit 0 -fi - -# Build a summary of changed references for the prompt -CHANGED_SUMMARY="" -for ref_file in "${!FILE_TO_DOCS_MAP[@]}"; do - IFS='|' read -ra DOCS <<< "${FILE_TO_DOCS_MAP[$ref_file]}" - DOC_LIST=$(printf ", %s" "${DOCS[@]}") - DOC_LIST="${DOC_LIST:2}" # strip leading ", " - CHANGED_SUMMARY="${CHANGED_SUMMARY}${ref_file} -> ${DOC_LIST}; " -done -# Strip trailing "; " -CHANGED_SUMMARY="${CHANGED_SUMMARY%%; }" - -SLACK_CHANNEL="${SLACK_DOC_UPDATE_CHANNEL:-devrel-docs-updates}" - -if [[ "$DRY_RUN" == "1" ]]; then - echo "" - echo "=== DRY_RUN: Would dispatch ClaudeBox ===" - echo "" - echo "Slack channel: $SLACK_CHANNEL" - echo "PR: #$PR_NUMBER ($PR_TITLE)" - echo "Changed references: $CHANGED_SUMMARY" - echo "" - echo "gh workflow run claudebox.yml \\" - echo " -f prompt=\"PR #$PR_NUMBER ($PR_TITLE) changed source files referenced by documentation. Analyze the changes and update the affected documentation. Changed references: $CHANGED_SUMMARY. Follow the update-doc-references skill (.claude/skills/update-doc-references/SKILL.md).\" \\" - echo " -f link=\"\"" - echo "" - echo "=== End of DRY_RUN ===" - exit 0 -fi - -# Post Slack message and capture timestamp for permalink -echo "Posting Slack notification to $SLACK_CHANNEL..." - -SLACK_TEXT=$(printf ':books: Source files referenced by docs changed in <%s|PR #%s>. Dispatching ClaudeBox to analyze.\n\n*Changed references:*\n%s' \ - "$PR_URL" "$PR_NUMBER" "$(for ref_file in "${!FILE_TO_DOCS_MAP[@]}"; do - IFS='|' read -ra DOCS <<< "${FILE_TO_DOCS_MAP[$ref_file]}" - printf '• \x60%s\x60 → ' "$ref_file" - printf '\x60%s\x60, ' "${DOCS[@]}" | sed 's/, $//' - echo "" - done)") - -RESP=$(curl -sS -X POST https://slack.com/api/chat.postMessage \ - -H "Authorization: Bearer $SLACK_BOT_TOKEN" \ - -H "Content-type: application/json" \ - -d "$(jq -n --arg c "$SLACK_CHANNEL" --arg t "$SLACK_TEXT" '{channel:$c, text:$t}')") -echo "Slack response: $RESP" - -TS=$(echo "$RESP" | jq -r '.ts // empty') -CHANNEL_ID=$(echo "$RESP" | jq -r '.channel // empty') - -LINK="" -if [[ -n "$TS" && -n "$CHANNEL_ID" ]]; then - LINK="https://aztecprotocol.slack.com/archives/$CHANNEL_ID/p${TS//./}" -fi - -# Dispatch ClaudeBox -echo "Dispatching ClaudeBox workflow..." - -gh workflow run claudebox.yml \ - -f prompt="PR #$PR_NUMBER ($PR_TITLE) changed source files referenced by documentation. Analyze the changes and update the affected documentation. Changed references: $CHANGED_SUMMARY. Follow the update-doc-references skill (.claude/skills/update-doc-references/SKILL.md)." \ - -f link="${LINK:-$PR_URL}" - -echo "" -echo "Done! ClaudeBox has been dispatched to analyze documentation updates for PR #$PR_NUMBER."