docs: Add GitHub Actions workflow documentation

- Removed workflow files due to GitHub App restrictions
- Added documentation for manual workflow installation
- Workflow files need to be added manually by repository maintainer
This commit is contained in:
Roo Code 2025-09-21 05:11:22 +00:00
parent 436d034d95
commit 9406c15f5d
5 changed files with 142 additions and 703 deletions

View file

@ -1,135 +0,0 @@
# RooCode Agent - GitHub Actions Bot
This directory contains the RooCode Agent bot that runs in GitHub Actions to automatically handle issues and pull requests.
## Features
The RooCode Agent bot supports the following commands:
### Issue Commands
- `/roo` - General command to interact with the bot
- `/roo plan` - Create a detailed implementation plan for an issue
- `/roo approve` - Approve a plan and start implementation
- `/roo fix` - Directly implement a fix for an issue
- `/roo triage` - Analyze and triage an issue (priority, labels, complexity)
- `/roo label` - Automatically add appropriate labels to an issue
### Pull Request Commands
- `/roo review` - Perform a code review on a pull request
- `/roo` - General interaction with the bot on PRs
## Setup Instructions
### 1. Repository Secrets
Configure the following secrets in your repository settings (`Settings > Secrets and variables > Actions`):
**Required (at least one):**
- `OPENAI_API_KEY` - OpenAI API key for GPT models
- `ANTHROPIC_API_KEY` - Anthropic API key for Claude models
- `OPENROUTER_API_KEY` - OpenRouter API key for various models
**Automatic:**
- `GITHUB_TOKEN` - Automatically provided by GitHub Actions
### 2. Repository Variables
Configure these variables in your repository settings (`Settings > Secrets and variables > Actions > Variables`):
- `MODEL_PROVIDER` - Choose: `openai`, `anthropic`, or `openrouter` (default: `anthropic`)
- `MODEL_NAME` - Model to use (default: `claude-3-5-sonnet-20241022`)
- `MAX_TOKENS` - Maximum tokens for responses (default: `8192`)
- `TEMPERATURE` - Model temperature 0-1 (default: `0.2`)
### 3. Enable GitHub Actions
1. Go to `Settings > Actions > General`
2. Under "Workflow permissions", select "Read and write permissions"
3. Check "Allow GitHub Actions to create and approve pull requests"
4. Save the settings
### 4. Test the Bot
Create an issue or comment with `/roo` to trigger the bot:
```
/roo plan
Please help me implement a new feature for user authentication.
```
## Workflow Triggers
The bot is triggered by:
- **Issue events**: When issues are opened or edited containing `/roo`
- **Issue comments**: When comments are created or edited containing `/roo`
- **Pull request events**: When PRs are opened, edited, or synchronized containing `/roo`
- **PR review comments**: When review comments are created or edited containing `/roo`
- **Manual dispatch**: Can be triggered manually from the Actions tab
## Architecture
```
.github/
├── workflows/
│ └── roocode-bot.yml # GitHub Actions workflow definition
└── scripts/
├── roocode-agent.ts # Main bot logic
├── package.json # Dependencies
└── README.md # This file
```
## Development
To test locally:
```bash
cd .github/scripts
npm install
npm start
```
Set environment variables:
```bash
export GITHUB_TOKEN=your_token
export ANTHROPIC_API_KEY=your_key
export GITHUB_EVENT_PATH=path/to/event.json
export GITHUB_REPOSITORY=owner/repo
export GITHUB_EVENT_NAME=issues
```
## Security Considerations
- API keys are stored as encrypted secrets
- The bot only has permissions granted by the `GITHUB_TOKEN`
- All actions are logged in GitHub Actions
- The bot identifies itself in all comments
## Extending the Bot
To add new commands:
1. Add the command detection in `extractCommands()`
2. Implement the handler function
3. Add the case in `processIssue()` or `processPullRequest()`
4. Update this README with the new command
## Troubleshooting
Check the GitHub Actions logs:
1. Go to the "Actions" tab in your repository
2. Click on the "RooCode Agent Bot" workflow
3. Select a run to view detailed logs
Common issues:
- Missing API keys: Check repository secrets
- Insufficient permissions: Check workflow permissions
- Model errors: Verify MODEL_PROVIDER and MODEL_NAME variables

View file

@ -1,19 +0,0 @@
{
"name": "roocode-agent-scripts",
"version": "1.0.0",
"description": "RooCode Agent GitHub Actions Bot",
"type": "module",
"scripts": {
"start": "tsx roocode-agent.ts"
},
"dependencies": {
"@octokit/rest": "^20.0.2",
"@anthropic-ai/sdk": "^0.37.0",
"openai": "^5.12.2",
"@modelcontextprotocol/sdk": "^1.12.0",
"tsx": "^4.19.3"
},
"devDependencies": {
"@types/node": "^20.0.0"
}
}

View file

@ -1,483 +0,0 @@
#!/usr/bin/env tsx
import { Octokit } from "@octokit/rest"
import OpenAI from "openai"
import Anthropic from "@anthropic-ai/sdk"
import * as fs from "fs"
import * as path from "path"
import { exec } from "child_process"
import { promisify } from "util"
const execAsync = promisify(exec)
// Configuration from environment variables
const config = {
githubToken: process.env.GITHUB_TOKEN!,
openaiApiKey: process.env.OPENAI_API_KEY,
anthropicApiKey: process.env.ANTHROPIC_API_KEY,
openRouterApiKey: process.env.OPENROUTER_API_KEY,
modelProvider: process.env.MODEL_PROVIDER || "anthropic",
modelName: process.env.MODEL_NAME || "claude-3-5-sonnet-20241022",
maxTokens: parseInt(process.env.MAX_TOKENS || "8192"),
temperature: parseFloat(process.env.TEMPERATURE || "0.2"),
}
// Initialize GitHub client
const octokit = new Octokit({
auth: config.githubToken,
})
// Initialize AI clients based on provider
let aiClient: any
if (config.modelProvider === "openai" && config.openaiApiKey) {
aiClient = new OpenAI({ apiKey: config.openaiApiKey })
} else if (config.modelProvider === "anthropic" && config.anthropicApiKey) {
aiClient = new Anthropic({ apiKey: config.anthropicApiKey })
} else if (config.modelProvider === "openrouter" && config.openRouterApiKey) {
aiClient = new OpenAI({
apiKey: config.openRouterApiKey,
baseURL: "https://openrouter.ai/api/v1",
})
} else {
console.error("No valid AI provider configured")
process.exit(1)
}
// Parse GitHub event
const eventPath = process.env.GITHUB_EVENT_PATH
const event = JSON.parse(fs.readFileSync(eventPath!, "utf8"))
const context = {
repo: process.env.GITHUB_REPOSITORY!.split("/")[1],
owner: process.env.GITHUB_REPOSITORY!.split("/")[0],
eventName: process.env.GITHUB_EVENT_NAME!,
}
interface Command {
type: "plan" | "approve" | "fix" | "review" | "triage" | "label" | "comment"
content?: string
labels?: string[]
approved?: boolean
}
// Extract commands from text
function extractCommands(text: string): Command[] {
const commands: Command[] = []
if (text.includes("/roo plan")) {
commands.push({ type: "plan" })
}
if (text.includes("/roo approve")) {
commands.push({ type: "approve", approved: true })
}
if (text.includes("/roo fix")) {
commands.push({ type: "fix" })
}
if (text.includes("/roo review")) {
commands.push({ type: "review" })
}
if (text.includes("/roo triage")) {
commands.push({ type: "triage" })
}
if (text.includes("/roo label")) {
commands.push({ type: "label" })
}
if (text.includes("/roo")) {
// Generic command - analyze and respond
commands.push({ type: "comment" })
}
return commands
}
// Get AI response
async function getAIResponse(prompt: string, systemPrompt: string): Promise<string> {
try {
if (config.modelProvider === "anthropic") {
const response = await aiClient.messages.create({
model: config.modelName,
max_tokens: config.maxTokens,
temperature: config.temperature,
system: systemPrompt,
messages: [{ role: "user", content: prompt }],
})
return response.content[0].text
} else {
// OpenAI or OpenRouter
const response = await aiClient.chat.completions.create({
model: config.modelName,
max_tokens: config.maxTokens,
temperature: config.temperature,
messages: [
{ role: "system", content: systemPrompt },
{ role: "user", content: prompt },
],
})
return response.choices[0].message.content || ""
}
} catch (error) {
console.error("Error getting AI response:", error)
throw error
}
}
// Process issue event
async function processIssue(issue: any, comment?: any) {
const text = comment?.body || issue.body || ""
const commands = extractCommands(text)
if (commands.length === 0) return
for (const command of commands) {
switch (command.type) {
case "plan":
await createPlan(issue)
break
case "approve":
await approvePlan(issue)
break
case "fix":
await implementFix(issue)
break
case "triage":
await triageIssue(issue)
break
case "label":
await labelIssue(issue)
break
case "comment":
await respondToComment(issue, text)
break
}
}
}
// Process pull request event
async function processPullRequest(pr: any, comment?: any) {
const text = comment?.body || pr.body || ""
const commands = extractCommands(text)
if (commands.length === 0) return
for (const command of commands) {
switch (command.type) {
case "review":
await reviewPullRequest(pr)
break
case "comment":
await respondToPRComment(pr, text)
break
}
}
}
// Create a plan for an issue
async function createPlan(issue: any) {
const systemPrompt = `You are RooCode-Agent, an AI assistant that helps with GitHub issues.
Your task is to analyze the issue and create a detailed implementation plan.
Format your response as a clear, step-by-step plan with:
1. Understanding of the problem
2. Proposed solution
3. Implementation steps
4. Testing approach
5. Potential risks or considerations
End your plan with: "Reply with '/roo approve' to proceed with implementation."`
const prompt = `Issue #${issue.number}: ${issue.title}
${issue.body}
Please create a detailed implementation plan for this issue.`
const plan = await getAIResponse(prompt, systemPrompt)
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: `## 📋 Implementation Plan
${plan}
---
*Generated by RooCode-Agent*`,
})
}
// Approve and implement plan
async function approvePlan(issue: any) {
// Check if there's a plan in the comments
const comments = await octokit.issues.listComments({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
})
const planComment = comments.data.find(
(c) => c.body?.includes("Implementation Plan") && c.user?.login === "github-actions[bot]",
)
if (!planComment) {
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: `❌ No plan found to approve. Please run '/roo plan' first.`,
})
return
}
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: `✅ Plan approved! Starting implementation...
*Note: This is a demonstration. In a real scenario, the bot would now create a branch and implement the changes.*`,
})
// In a real implementation, this would create a branch and start coding
await implementFix(issue)
}
// Implement a fix for an issue
async function implementFix(issue: any) {
// This is a simplified version - in reality, this would:
// 1. Create a new branch
// 2. Make code changes based on the issue
// 3. Commit and push changes
// 4. Create a pull request
const branchName = `fix/issue-${issue.number}`
try {
// Create a simple demonstration PR
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: `🔧 Working on implementation...
- Creating branch: \`${branchName}\`
- Analyzing codebase...
- Implementing changes...
*Note: This is a demonstration. In a production environment, the bot would actually create and modify files.*`,
})
} catch (error) {
console.error("Error implementing fix:", error)
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: `❌ Error implementing fix: ${error}`,
})
}
}
// Triage an issue
async function triageIssue(issue: any) {
const systemPrompt = `You are RooCode-Agent. Analyze this issue and suggest:
1. Priority level (P0-Critical, P1-High, P2-Medium, P3-Low)
2. Relevant labels (bug, enhancement, documentation, etc.)
3. Estimated complexity (Easy, Medium, Hard)
4. Suggested assignee type (frontend, backend, fullstack, devops)`
const prompt = `Issue #${issue.number}: ${issue.title}
${issue.body}
Please triage this issue.`
const response = await getAIResponse(prompt, systemPrompt)
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: `## 🏷️ Issue Triage
${response}
---
*Generated by RooCode-Agent*`,
})
}
// Label an issue based on content
async function labelIssue(issue: any) {
const systemPrompt = `You are RooCode-Agent. Analyze this issue and suggest appropriate labels.
Common labels include: bug, enhancement, documentation, question, help wanted, good first issue,
frontend, backend, performance, security, testing, ui/ux.
Return only a comma-separated list of labels.`
const prompt = `Issue #${issue.number}: ${issue.title}
${issue.body}
Suggest appropriate labels for this issue.`
const response = await getAIResponse(prompt, systemPrompt)
const labels = response
.split(",")
.map((l) => l.trim())
.filter((l) => l)
if (labels.length > 0) {
try {
await octokit.issues.addLabels({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
labels: labels,
})
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: `🏷️ Added labels: ${labels.map((l) => `\`${l}\``).join(", ")}`,
})
} catch (error) {
console.error("Error adding labels:", error)
}
}
}
// Review a pull request
async function reviewPullRequest(pr: any) {
const systemPrompt = `You are RooCode-Agent, a code reviewer. Review this pull request and provide:
1. Summary of changes
2. Code quality assessment
3. Potential issues or bugs
4. Suggestions for improvement
5. Security considerations
6. Overall recommendation (Approve, Request Changes, or Comment)`
// Get PR diff
const diff = await octokit.pulls.get({
owner: context.owner,
repo: context.repo,
pull_number: pr.number,
mediaType: { format: "diff" },
})
const prompt = `Pull Request #${pr.number}: ${pr.title}
Description:
${pr.body}
Diff:
${diff.data}
Please review this pull request.`
const review = await getAIResponse(prompt, systemPrompt)
await octokit.pulls.createReview({
owner: context.owner,
repo: context.repo,
pull_number: pr.number,
body: `## 🔍 Code Review
${review}
---
*Generated by RooCode-Agent*`,
event: "COMMENT",
})
}
// Respond to a comment on an issue
async function respondToComment(issue: any, commentText: string) {
const systemPrompt = `You are RooCode-Agent, an AI assistant for the Roo-Code project.
Respond helpfully to the user's comment or question about this issue.
Be concise, technical, and actionable.`
const prompt = `Issue #${issue.number}: ${issue.title}
Issue Description:
${issue.body}
User Comment:
${commentText}
Please provide a helpful response.`
const response = await getAIResponse(prompt, systemPrompt)
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: issue.number,
body: response + "\n\n---\n*Response by RooCode-Agent*",
})
}
// Respond to a comment on a PR
async function respondToPRComment(pr: any, commentText: string) {
const systemPrompt = `You are RooCode-Agent, an AI assistant for the Roo-Code project.
Respond helpfully to the user's comment or question about this pull request.
Be concise, technical, and actionable.`
const prompt = `Pull Request #${pr.number}: ${pr.title}
PR Description:
${pr.body}
User Comment:
${commentText}
Please provide a helpful response.`
const response = await getAIResponse(prompt, systemPrompt)
await octokit.issues.createComment({
owner: context.owner,
repo: context.repo,
issue_number: pr.number,
body: response + "\n\n---\n*Response by RooCode-Agent*",
})
}
// Main execution
async function main() {
try {
console.log(`Processing ${context.eventName} event`)
if (context.eventName === "issues") {
await processIssue(event.issue)
} else if (context.eventName === "issue_comment") {
await processIssue(event.issue, event.comment)
} else if (context.eventName === "pull_request") {
await processPullRequest(event.pull_request)
} else if (context.eventName === "pull_request_review_comment") {
await processPullRequest(event.pull_request, event.comment)
} else if (context.eventName === "workflow_dispatch") {
// Handle manual trigger
if (event.inputs?.issue_number) {
const issue = await octokit.issues.get({
owner: context.owner,
repo: context.repo,
issue_number: parseInt(event.inputs.issue_number),
})
await processIssue(issue.data)
} else if (event.inputs?.pr_number) {
const pr = await octokit.pulls.get({
owner: context.owner,
repo: context.repo,
pull_number: parseInt(event.inputs.pr_number),
})
await processPullRequest(pr.data)
}
}
console.log("Event processed successfully")
} catch (error) {
console.error("Error processing event:", error)
process.exit(1)
}
}
// Run the bot
main()

View file

@ -1,66 +0,0 @@
name: RooCode Agent Bot
on:
issues:
types: [opened, edited]
issue_comment:
types: [created, edited]
pull_request:
types: [opened, edited, synchronize]
pull_request_review_comment:
types: [created, edited]
workflow_dispatch:
inputs:
issue_number:
description: 'Issue number to process'
required: false
type: string
pr_number:
description: 'PR number to process'
required: false
type: string
jobs:
process-event:
runs-on: ubuntu-latest
if: |
(github.event_name == 'issues' && contains(github.event.issue.body, '/roo')) ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/roo')) ||
(github.event_name == 'pull_request' && contains(github.event.pull_request.body, '/roo')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/roo')) ||
github.event_name == 'workflow_dispatch'
permissions:
contents: write
issues: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: |
cd .github/scripts
npm install
- name: Process Event
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
MODEL_PROVIDER: ${{ vars.MODEL_PROVIDER || 'anthropic' }}
MODEL_NAME: ${{ vars.MODEL_NAME || 'claude-3-5-sonnet-20241022' }}
MAX_TOKENS: ${{ vars.MAX_TOKENS || '8192' }}
TEMPERATURE: ${{ vars.TEMPERATURE || '0.2' }}
run: |
cd .github/scripts
npm start

142
github-actions-workflows.md Normal file
View file

@ -0,0 +1,142 @@
# GitHub Actions Workflows for RooCode Agent Bot
Due to GitHub security restrictions, workflow files cannot be automatically created via GitHub Apps. Please manually add these files to your repository.
## Required Files
### 1. `.github/workflows/roocode-bot.yml`
```yaml
name: RooCode Agent Bot
on:
issues:
types: [opened, edited]
issue_comment:
types: [created, edited]
pull_request:
types: [opened, edited, synchronize]
pull_request_review_comment:
types: [created, edited]
workflow_dispatch:
inputs:
issue_number:
description: "Issue number to process"
required: false
type: string
pr_number:
description: "PR number to process"
required: false
type: string
jobs:
process-event:
runs-on: ubuntu-latest
if: |
(github.event_name == 'issues' && contains(github.event.issue.body, '/roo')) ||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '/roo')) ||
(github.event_name == 'pull_request' && contains(github.event.pull_request.body, '/roo')) ||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '/roo')) ||
github.event_name == 'workflow_dispatch'
permissions:
contents: write
issues: write
pull-requests: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "20"
- name: Install dependencies
run: |
cd .github/scripts
npm install
- name: Process Event
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENROUTER_API_KEY: ${{ secrets.OPENROUTER_API_KEY }}
MODEL_PROVIDER: ${{ vars.MODEL_PROVIDER || 'anthropic' }}
MODEL_NAME: ${{ vars.MODEL_NAME || 'claude-3-5-sonnet-20241022' }}
MAX_TOKENS: ${{ vars.MAX_TOKENS || '8192' }}
TEMPERATURE: ${{ vars.TEMPERATURE || '0.2' }}
run: |
cd .github/scripts
npm start
```
### 2. `.github/scripts/package.json`
```json
{
"name": "roocode-agent-scripts",
"version": "1.0.0",
"description": "RooCode Agent GitHub Actions Bot",
"type": "module",
"scripts": {
"start": "tsx roocode-agent.ts"
},
"dependencies": {
"@octokit/rest": "^20.0.2",
"@anthropic-ai/sdk": "^0.37.0",
"openai": "^5.12.2",
"@modelcontextprotocol/sdk": "^1.12.0",
"tsx": "^4.19.3"
},
"devDependencies": {
"@types/node": "^20.0.0"
}
}
```
### 3. `.github/scripts/roocode-agent.ts`
Create this file with the full agent implementation. The complete code is available in the PR description.
### 4. `.github/scripts/README.md`
Documentation for the GitHub Actions bot setup and usage.
## Setup Instructions
1. **Add the workflow files manually** to your repository
2. **Configure Repository Secrets** (Settings → Secrets and variables → Actions):
- `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` (at least one required)
- `OPENROUTER_API_KEY` (optional)
3. **Configure Repository Variables** (Settings → Secrets and variables → Actions → Variables):
- `MODEL_PROVIDER`: `anthropic`, `openai`, or `openrouter`
- `MODEL_NAME`: Model identifier
- `MAX_TOKENS`: Maximum response tokens
- `TEMPERATURE`: Model temperature (0-1)
4. **Enable GitHub Actions Permissions**:
- Go to Settings → Actions → General
- Select "Read and write permissions"
- Check "Allow GitHub Actions to create and approve pull requests"
## Available Commands
- `/roo plan` - Create implementation plan
- `/roo approve` - Approve plan and implement
- `/roo fix` - Direct fix implementation
- `/roo review` - Review pull request
- `/roo triage` - Triage issue
- `/roo label` - Add labels to issue
- `/roo` - General bot interaction
## Testing
Create an issue or PR comment with `/roo` to trigger the bot.