diff --git a/.gitea/workflows/claude.yml b/.gitea/workflows/claude.yml index 8efb411..3c61009 100644 --- a/.gitea/workflows/claude.yml +++ b/.gitea/workflows/claude.yml @@ -8,9 +8,9 @@ on: jobs: claude-code: - if: | + if: >- (github.event_name == 'issues' && - contains(github.event.issue.labels.*.name, 'claude')) || + contains(toJSON(github.event.issue.labels), 'claude')) || (github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) runs-on: ubuntu-latest @@ -18,74 +18,106 @@ jobs: - name: Checkout uses: actions/checkout@v4 - - name: Configure Git - run: | - git config user.name "Claude Bot" - git config user.email "claude@localhost" - git remote set-url origin http://admin:${{ secrets.GITEA_TOKEN }}@localhost:3000/${{ github.repository }}.git - - - name: Run Claude Code + - name: Run Claude on Issue env: ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GITEA_TOKEN: ${{ secrets.GITEA_TOKEN }} + GIT_TOKEN: ${{ secrets.GIT_TOKEN }} run: | - ISSUE_NUMBER=${{ github.event.issue.number }} - REPO=${{ github.repository }} + set -e - # Get issue details + # Configure git + git config user.name "Claude Bot" + git config user.email "claude@localhost" + git remote set-url origin "http://admin:${GIT_TOKEN}@localhost:3000/${{ github.repository }}.git" + + # Extract issue info + ISSUE_NUMBER="${{ github.event.issue.number }}" ISSUE_TITLE="${{ github.event.issue.title }}" - ISSUE_BODY=$(curl -s "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}" -H "Authorization: token ${GITEA_TOKEN}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('body',''))") + REPO="${{ github.repository }}" - # Get comment if triggered by comment + # Fetch issue body via API + ISSUE_BODY=$(curl -s "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}" \ + -H "Authorization: token ${GIT_TOKEN}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('body',''))") + + # Get comment body if triggered by comment COMMENT_BODY="" if [ "${{ github.event_name }}" = "issue_comment" ]; then - COMMENT_BODY="${{ github.event.comment.body }}" + COMMENT_ID="${{ github.event.comment.id }}" + COMMENT_BODY=$(curl -s "http://localhost:3000/api/v1/repos/${REPO}/issues/comments/${COMMENT_ID}" \ + -H "Authorization: token ${GIT_TOKEN}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('body',''))") fi - # Create branch + # Create working branch BRANCH="claude/issue-${ISSUE_NUMBER}" git checkout -b "${BRANCH}" - # Post a "working on it" comment - curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}/comments" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{"body": "🤖 Claude is working on this issue..."}" + # Post status comment + curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}/comments" \ + -H "Authorization: token ${GIT_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"body\": \"Claude is working on this issue...\"}" - # Run Claude - claude -p "You are working on the repository ${REPO}. + # Build the prompt + PROMPT="You are working on the repository ${REPO}. A Gitea issue needs your attention: Issue #${ISSUE_NUMBER}: ${ISSUE_TITLE} Description: ${ISSUE_BODY} - Additional context: ${COMMENT_BODY} + Additional context from comment: ${COMMENT_BODY} Instructions: - 1. Read and understand the codebase - 2. Implement the requested changes + 1. Read and understand the codebase structure + 2. Implement the requested changes carefully 3. Make sure the code is correct and complete - 4. Commit all changes with a descriptive message + 4. Commit all changes with a descriptive commit message - Work in the current directory. The branch is already created." --allowedTools "Bash,Read,Edit,Write,Glob,Grep" --mcp-config /etc/claude/mcp-gitea.json --max-turns 50 --dangerously-skip-permissions --output-format text > /tmp/claude-output.txt 2>&1 || true + You are on branch ${BRANCH}. Work in the current directory." + # Run Claude Code + claude -p "${PROMPT}" \ + --allowedTools "Bash,Read,Edit,Write,Glob,Grep" \ + --mcp-config /etc/claude/mcp-gitea.json \ + --max-turns 50 \ + --dangerously-skip-permissions \ + --output-format text > /tmp/claude-output.txt 2>&1 || true + + echo "=== Claude Output ===" cat /tmp/claude-output.txt + echo "=== End Output ===" - # Check if there are changes to commit/push - if [ -n "" ] || [ "0" -gt 0 ]; then - git add -A - git diff --cached --quiet || git commit -m "Claude: Address issue #${ISSUE_NUMBER} - ${ISSUE_TITLE}" + # Stage any remaining unstaged changes + git add -A + + # Check if there are changes + if ! git diff --cached --quiet 2>/dev/null || [ "$(git log origin/main..HEAD --oneline 2>/dev/null | wc -l)" -gt 0 ]; then + # Commit if there are staged changes + git diff --cached --quiet 2>/dev/null || git commit -m "Claude: Address issue #${ISSUE_NUMBER} - ${ISSUE_TITLE}" + + # Push git push origin "${BRANCH}" # Create PR - PR_RESPONSE=$(curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/pulls" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{ - "title": "Claude: Fix #${ISSUE_NUMBER} - ${ISSUE_TITLE}", - "body": "Automated PR by Claude Code for issue #${ISSUE_NUMBER}\n\nCloses #${ISSUE_NUMBER}", - "head": "${BRANCH}", - "base": "main" + PR_RESPONSE=$(curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/pulls" \ + -H "Authorization: token ${GIT_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{ + \"title\": \"Claude: Fix #${ISSUE_NUMBER} - ${ISSUE_TITLE}\", + \"body\": \"Automated PR by Claude Code for issue #${ISSUE_NUMBER}\n\nCloses #${ISSUE_NUMBER}\", + \"head\": \"${BRANCH}\", + \"base\": \"main\" }") - PR_URL=$(echo "${PR_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('html_url',''))" 2>/dev/null) + PR_URL=$(echo "${PR_RESPONSE}" | python3 -c "import sys,json; print(json.load(sys.stdin).get('html_url',''))" 2>/dev/null || echo "") - # Comment on issue with PR link - curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}/comments" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{"body": "✅ Claude has created a pull request: ${PR_URL}"}" + # Comment with PR link + curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}/comments" \ + -H "Authorization: token ${GIT_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"body\": \"Claude has created a pull request: ${PR_URL}\"}" else - curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}/comments" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{"body": "Claude reviewed the issue but made no code changes."}" + curl -s -X POST "http://localhost:3000/api/v1/repos/${REPO}/issues/${ISSUE_NUMBER}/comments" \ + -H "Authorization: token ${GIT_TOKEN}" \ + -H "Content-Type: application/json" \ + -d "{\"body\": \"Claude reviewed the issue but made no code changes.\"}" fi