From b266a01526c41841f2ed17c2992b5959ade9fb64 Mon Sep 17 00:00:00 2001 From: hongyi-chen Date: Mon, 18 May 2026 16:36:52 +0000 Subject: [PATCH] Remove obsolete Oz-agent GitHub Actions workflows These workflows depend on a `WARP_API_KEY` org-level secret that isn't exposed to the public `warpdotdev/docs` repo, so they fail on every PR (example: https://github.com/warpdotdev/docs/actions/runs/26031884808). PR review coverage and `@oz-agent` comment responses are now handled by the Oz management webhook flow, making these workflows redundant. Co-Authored-By: Oz --- .github/workflows/respond-to-comment.yml | 249 ----------------------- .github/workflows/review-pr.yml | 196 ------------------ 2 files changed, 445 deletions(-) delete mode 100644 .github/workflows/respond-to-comment.yml delete mode 100644 .github/workflows/review-pr.yml diff --git a/.github/workflows/respond-to-comment.yml b/.github/workflows/respond-to-comment.yml deleted file mode 100644 index 7e4f40b2..00000000 --- a/.github/workflows/respond-to-comment.yml +++ /dev/null @@ -1,249 +0,0 @@ -name: Respond to Comment -on: - issue_comment: - types: - - created - pull_request_review_comment: - types: - - created -jobs: - respond: - runs-on: ubuntu-latest - if: | - contains(github.event.comment.body,'@oz-agent') && - ( - github.event_name == 'pull_request_review_comment' || - (github.event_name == 'issue_comment' && github.event.issue.pull_request) - ) && - github.actor != 'github-actions[bot]' - permissions: - contents: write - pull-requests: write - issues: write - steps: - - name: Check author permissions - uses: actions/github-script@v7 - with: - github-token: ${{ github.token }} - script: | - const { data } = await github.rest.repos.getCollaboratorPermissionLevel({ - owner: context.repo.owner, - repo: context.repo.repo, - username: context.payload.comment.user.login, - }); - if (!['admin', 'write'].includes(data.permission)) { - core.setFailed(`Comment author @${context.payload.comment.user.login} lacks write access (has '${data.permission}')`); - } - - name: Checkout Action - uses: actions/checkout@v4 - - name: Acknowledge Comment - env: - GH_TOKEN: ${{ github.token }} - run: | - COMMENT_ID="${{ github.event.comment.id }}" - REACTION="eyes" - - if [ "${{ github.event_name }}" == "pull_request_review_comment" ]; then - gh api \ - --method POST \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{ github.repository }}/pulls/comments/$COMMENT_ID/reactions \ - -f content="$REACTION" - else - gh api \ - --method POST \ - -H "Accept: application/vnd.github+json" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - /repos/${{ github.repository }}/issues/comments/$COMMENT_ID/reactions \ - -f content="$REACTION" - fi - - name: Checkout PR - env: - GH_TOKEN: ${{ github.token }} - run: | - PR_NUMBER="${{ github.event.issue.number }}" - if [ -z "$PR_NUMBER" ]; then - PR_NUMBER="${{ github.event.pull_request.number }}" - fi - - echo "Checking out PR #$PR_NUMBER" - gh pr checkout "$PR_NUMBER" - - name: Construct Prompt - id: prompt - uses: actions/github-script@v7 - with: - github-token: ${{ github.token }} - script: | - const { owner, repo } = context.repo; - let prNumber; - if (context.eventName === 'issue_comment') { - prNumber = context.payload.issue.number; - } else { - prNumber = context.payload.pull_request.number; - } - - // Fetch PR details to provide full context - const { data: pr } = await github.rest.pulls.get({ - owner, - repo, - pull_number: prNumber, - }); - - // Get the list of files changed in the PR - const { data: files } = await github.rest.pulls.listFiles({ - owner, - repo, - pull_number: prNumber, - }); - - const fileList = files.map(f => f.filename).join(', '); - - const commentBody = context.payload.comment.body; - const author = context.payload.comment.user.login; - - let prompt = `You are an expert software engineer and the Warp Agent. - You are responding to a specific request on a Pull Request. This may involve answering questions, providing explanations, or implementing code changes. - - **Context**: - - **PR Title**: ${pr.title} - - **PR Description**: ${pr.body || 'No description provided.'} - - **Changed Files**: ${fileList} - - **User Request**: "${commentBody}" (from user @${author}) - `; - - if (context.eventName === 'pull_request_review_comment') { - const path = context.payload.comment.path; - const line = context.payload.comment.line; - const diffHunk = context.payload.comment.diff_hunk; - prompt += ` - - **Location**: File '${path}' at line ${line}. - - **Diff Context**: - \`\`\`diff - ${diffHunk} - \`\`\` - `; - prompt += ` - **Instructions**: - 1. Read the file at '${path}' to understand the full context around the line. - `; - } else { - prompt += ` - **Instructions**: - 1. Focus your analysis on the changed files (${fileList}) unless the request explicitly mentions other files. - `; - } - - prompt += `2. Determine if the user is asking a question or requesting code changes. - 3. If asking a question: Answer it based on your analysis of the code and context. - 4. If requesting code changes: Implement them carefully, ensuring correctness and following existing style. - 5. Do not output code diffs in your final message; only provide a clear explanation of what you did or answered. - 6. Format your response in Markdown. - 7. Your output will be posted as a reply to the user. - 8. Do not attempt to stage or commit changes manually. This happens automatically after you complete your response. - `; - - core.setOutput('prompt', prompt); - - name: Run Oz Agent - uses: warpdotdev/oz-agent-action@v1 - env: - GH_TOKEN: ${{ github.token }} - id: agent - with: - prompt: ${{ steps.prompt.outputs.prompt }} - warp_api_key: ${{ secrets.WARP_API_KEY }} - profile: '' - output_format: json - model: '' - name: '' - mcp: '' - - name: Commit and Push Changes - if: success() - env: - GH_TOKEN: ${{ github.token }} - run: | - git config user.name "Warp Agent" - git config user.email "agent@warp.dev" - - if [[ -n $(git status --porcelain) ]]; then - git add . - git commit -m "Warp Agent: Address comment" - git push - else - echo "No changes to commit." - fi - - name: Reply to Comment - if: success() - uses: actions/github-script@v7 - env: - AGENT_OUTPUT: ${{ steps.agent.outputs.agent_output }} - with: - github-token: ${{ github.token }} - script: | - const raw = process.env.AGENT_OUTPUT || ''; - - // Walk JSONL lines and capture the last agent text message, if any. - let lastText = ''; - for (const line of raw.split('\n')) { - const trimmed = line.trim(); - if (!trimmed) continue; - try { - const obj = JSON.parse(trimmed); - if (obj.type === 'agent' && typeof obj.text === 'string') { - lastText = obj.text; - } - } catch (e) { - // Ignore non-JSON lines - } - } - - const content = (lastText || raw || '').trim(); - if (!content) { - core.info('No agent output to reply with.'); - return; - } - - const body = `@${context.payload.comment.user.login}: ${content}`; - const { owner, repo } = context.repo; - - if (context.eventName === 'pull_request_review_comment') { - await github.rest.pulls.createReplyForReviewComment({ - owner, - repo, - pull_number: context.payload.pull_request.number, - comment_id: context.payload.comment.id, - body, - }); - } else { - await github.rest.issues.createComment({ - owner, - repo, - issue_number: context.payload.issue.number, - body, - }); - } - - name: Report Agent Error - if: failure() && steps.agent.outcome == 'failure' - uses: actions/github-script@v7 - with: - github-token: ${{ github.token }} - script: | - const body = `@${context.payload.comment.user.login}: ⚠️ I encountered an error while processing your request. Please check the [workflow run logs] for more details.`; - const { owner, repo } = context.repo; - - if (context.eventName === 'pull_request_review_comment') { - await github.rest.pulls.createReplyForReviewComment({ - owner, - repo, - pull_number: context.payload.pull_request.number, - comment_id: context.payload.comment.id, - body, - }); - } else { - await github.rest.issues.createComment({ - owner, - repo, - issue_number: context.payload.issue.number, - body, - }); - } diff --git a/.github/workflows/review-pr.yml b/.github/workflows/review-pr.yml deleted file mode 100644 index a1dfe1ba..00000000 --- a/.github/workflows/review-pr.yml +++ /dev/null @@ -1,196 +0,0 @@ -name: Auto PR Review - -on: - pull_request: - types: [opened, ready_for_review] - -jobs: - review_pr: - if: github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-latest - permissions: - contents: read - pull-requests: write - issues: write - - steps: - - name: Checkout Repository - uses: actions/checkout@v4 - - - name: Review PR with Warp Agent - uses: warpdotdev/oz-agent-action@v1 - env: - GH_TOKEN: ${{ github.token }} - with: - warp_api_key: ${{ secrets.WARP_API_KEY }} - skill: review-docs-pr - - - name: Post Review - uses: actions/github-script@v7 - if: always() - with: - script: | - const fs = require('fs'); - const { owner, repo } = context.repo; - const prNumber = context.payload.pull_request.number; - const commitSha = context.payload.pull_request.head.sha; - - try { - if (!fs.existsSync('review.json')) { - console.log('No review.json found. Skipping review posting.'); - return; - } - - const reviewContent = fs.readFileSync('review.json', 'utf8'); - - let review; - try { - review = JSON.parse(reviewContent); - } catch (parseError) { - core.warning(`Failed to parse review.json: ${parseError.message}`); - const sanitized = reviewContent.replace(/[\u0000-\u001F]+/g, ' '); - try { - review = JSON.parse(sanitized); - } catch (sanitizedError) { - core.setFailed(`Failed to parse review.json even after sanitizing: ${sanitizedError.message}`); - return; - } - } - - const decodeNewlines = (text) => { - if (typeof text !== 'string') return text; - return text.replace(/\r\n/g, '\n').replace(/\\n/g, '\n'); - }; - - const rawComments = Array.isArray(review.comments) ? review.comments : []; - - // Fetch valid file paths from the PR - const prFiles = await github.paginate( - github.rest.pulls.listFiles, - { owner, repo, pull_number: prNumber } - ); - const validPaths = new Set(prFiles.map(f => f.filename)); - - // Build a map of valid diff line numbers per file and side. - // GitHub's createReview API only accepts line numbers that appear - // in the PR diff; comments targeting other lines cause a 422. - const validLines = new Map(); // key: "path:side" -> Set of line numbers - for (const file of prFiles) { - if (!file.patch) continue; - const rightLines = new Set(); - const leftLines = new Set(); - let oldLine = 0; - let newLine = 0; - for (const raw of file.patch.split('\n')) { - const hunkHeader = raw.match(/^@@ -(?:\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/); - if (hunkHeader) { - const parts = raw.match(/^@@ -(\d+)(?:,\d+)? \+(\d+)(?:,\d+)? @@/); - oldLine = parseInt(parts[1], 10); - newLine = parseInt(parts[2], 10); - continue; - } - if (raw.startsWith('+')) { - rightLines.add(newLine); - newLine++; - } else if (raw.startsWith('-')) { - leftLines.add(oldLine); - oldLine++; - } else { - // Context line — valid on both sides - rightLines.add(newLine); - leftLines.add(oldLine); - newLine++; - oldLine++; - } - } - validLines.set(`${file.filename}:RIGHT`, rightLines); - validLines.set(`${file.filename}:LEFT`, leftLines); - } - - const comments = []; - const displaced = []; // comments whose lines aren't in the diff - - for (const c of rawComments) { - if (!c || typeof c !== 'object') continue; - if (typeof c.body !== 'string' || !c.body.trim()) continue; - if (typeof c.path !== 'string' || !c.path.trim()) continue; - - // Normalize path - const normalizedPath = c.path.trim() - .replace(/^([ab]\/)*/, '') - .replace(/^\.\//, ''); - - if (!validPaths.has(normalizedPath)) { - console.log(`Skipping comment with invalid path: ${c.path} -> ${normalizedPath}`); - continue; - } - - const line = Number(c.line); - if (!Number.isInteger(line) || line <= 0) { - console.log('Skipping comment with invalid line:', c); - continue; - } - - let side = (c.side || 'RIGHT').toString().toUpperCase(); - if (side !== 'LEFT' && side !== 'RIGHT') { - console.log(`Invalid side '${c.side}', defaulting to RIGHT`); - side = 'RIGHT'; - } - - const body = decodeNewlines(c.body); - - // Validate that this line number exists in the diff for this file/side - const key = `${normalizedPath}:${side}`; - const lineSet = validLines.get(key); - if (!lineSet || !lineSet.has(line)) { - console.log(`Comment targets line ${line} (${side}) in ${normalizedPath} which is outside the diff — moving to summary.`); - displaced.push({ path: normalizedPath, line, side, body }); - continue; - } - - comments.push({ path: normalizedPath, line, side, body }); - } - - let summary = typeof review.summary === 'string' ? decodeNewlines(review.summary).trim() : ''; - - // Append displaced comments to the summary so feedback isn't lost - if (displaced.length > 0) { - const extra = displaced.map(d => - `**${d.path}** (line ${d.line}):\n${d.body}` - ).join('\n\n---\n\n'); - const header = '\n\n---\n\n**Additional comments** (targeting lines outside the diff):\n\n'; - summary = summary ? summary + header + extra : header.trimStart() + extra; - } - const hasSummary = summary.length > 0; - - if (!hasSummary && comments.length === 0) { - console.log('No valid summary or inline comments found. Skipping review posting.'); - return; - } - - const payload = { - owner, - repo, - pull_number: prNumber, - commit_id: commitSha, - event: 'COMMENT', - }; - - if (hasSummary) { - payload.body = summary; - } else { - payload.body = 'Automated review by Warp Agent'; - } - - if (comments.length > 0) { - payload.comments = comments; - } - - await github.rest.pulls.createReview(payload); - - console.log('Review posted successfully.'); - - } catch (error) { - console.error('Failed to post review:', error); - core.setFailed(`Failed to post review: ${error.message}`); - }