mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-04-23 04:16:29 +02:00
199bc9d412
Bumps the github-actions group with 2 updates: [actions/ai-inference](https://github.com/actions/ai-inference) and [crate-ci/typos](https://github.com/crate-ci/typos). Updates `actions/ai-inference` from 2.0.4 to 2.0.5 - [Release notes](https://github.com/actions/ai-inference/releases) - [Commits](https://github.com/actions/ai-inference/compare/334892bb203895caaed82ec52d23c1ed9385151e...a6101c89c6feaecc585efdd8d461f18bb7896f20) Updates `crate-ci/typos` from 1.42.0 to 1.42.1 - [Release notes](https://github.com/crate-ci/typos/releases) - [Changelog](https://github.com/crate-ci/typos/blob/master/CHANGELOG.md) - [Commits](https://github.com/crate-ci/typos/compare/bb4666ad77b539a6b4ce4eda7ebb6de553704021...65120634e79d8374d1aa2f27e54baa0c364fff5a) --- updated-dependencies: - dependency-name: actions/ai-inference dependency-version: 2.0.5 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: crate-ci/typos dependency-version: 1.42.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com>
394 lines
16 KiB
YAML
394 lines
16 KiB
YAML
name: Issue & PR Automation
|
|
|
|
on:
|
|
issues:
|
|
types: [opened]
|
|
pull_request:
|
|
types: [opened]
|
|
issue_comment:
|
|
types: [created]
|
|
pull_request_review_comment:
|
|
types: [created]
|
|
|
|
permissions:
|
|
contents: read
|
|
issues: write
|
|
pull-requests: write
|
|
models: read
|
|
id-token: write
|
|
|
|
jobs:
|
|
validate-issue:
|
|
if: github.event_name == 'issues'
|
|
runs-on: ubuntu-latest
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
|
|
|
- name: Get issue templates
|
|
id: get-templates
|
|
run: |
|
|
if [ -f ".github/ISSUE_TEMPLATE/01-bug-report.md" ]; then
|
|
echo "bug-template-exists=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
if [ -f ".github/ISSUE_TEMPLATE/02-feature-request.md" ]; then
|
|
echo "feature-template-exists=true" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Create issue analysis prompt
|
|
id: create-prompt
|
|
env:
|
|
ISSUE_TITLE: ${{ github.event.issue.title }}
|
|
ISSUE_BODY: ${{ github.event.issue.body }}
|
|
ISSUE_LABELS: ${{ join(github.event.issue.labels.*.name, ', ') }}
|
|
run: |
|
|
cat > issue_analysis.txt << EOF
|
|
## Issue Content to Analyze:
|
|
|
|
**Title:** $ISSUE_TITLE
|
|
|
|
**Body:**
|
|
$ISSUE_BODY
|
|
|
|
**Labels:** $ISSUE_LABELS
|
|
EOF
|
|
|
|
- name: Validate issue with AI
|
|
id: validate
|
|
uses: actions/ai-inference@a6101c89c6feaecc585efdd8d461f18bb7896f20 # v2.0.5
|
|
with:
|
|
prompt-file: issue_analysis.txt
|
|
system-prompt: |
|
|
You are an issue validation assistant for Donut Browser, an anti-detect browser.
|
|
|
|
Analyze the provided issue content and determine if it contains sufficient information based on these requirements:
|
|
|
|
**For Bug Reports, the issue should include:**
|
|
1. Clear description of the problem
|
|
2. Steps to reproduce the issue (numbered list preferred)
|
|
3. Expected vs actual behavior
|
|
4. Environment information (OS, browser version, etc.)
|
|
5. Error messages, stack traces, or screenshots if applicable
|
|
|
|
**For Feature Requests, the issue should include:**
|
|
1. Clear description of the requested feature
|
|
2. Use case or problem it solves
|
|
3. Proposed solution or how it should work
|
|
4. Priority level or importance
|
|
|
|
**General Requirements for all issues:**
|
|
1. Descriptive title
|
|
2. Sufficient detail to understand and act upon
|
|
3. Professional tone and clear communication
|
|
|
|
Respond ONLY with valid JSON (no markdown fences). Keep responses concise.
|
|
|
|
JSON structure:
|
|
{
|
|
"is_valid": true|false,
|
|
"issue_type": "bug_report"|"feature_request"|"other",
|
|
"missing_info": ["item1", "item2"],
|
|
"suggestions": ["suggestion1", "suggestion2"],
|
|
"overall_assessment": "One sentence assessment"
|
|
}
|
|
|
|
IMPORTANT CONSTRAINTS:
|
|
- Maximum 3 items in missing_info array
|
|
- Maximum 3 items in suggestions array
|
|
- Each array item must be under 80 characters
|
|
- overall_assessment must be under 100 characters
|
|
- Output ONLY the JSON object, nothing else
|
|
model: gpt-5-mini
|
|
|
|
- name: Check if first-time contributor
|
|
id: check-first-time
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
ISSUE_AUTHOR: ${{ github.event.issue.user.login }}
|
|
run: |
|
|
ISSUE_COUNT=$(gh api "/repos/${{ github.repository }}/issues" \
|
|
--jq "map(select(.user.login == \"$ISSUE_AUTHOR\" and .number != ${{ github.event.issue.number }})) | length" \
|
|
--paginate || echo "0")
|
|
|
|
if [ "$ISSUE_COUNT" = "0" ]; then
|
|
echo "is_first_time=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "is_first_time=false" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Parse validation result and take action
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
RESPONSE_FILE: ${{ steps.validate.outputs.response-file }}
|
|
run: |
|
|
if [ -n "$RESPONSE_FILE" ] && [ -f "$RESPONSE_FILE" ]; then
|
|
RAW_OUTPUT=$(cat "$RESPONSE_FILE")
|
|
else
|
|
echo "::error::Response file not found: $RESPONSE_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
JSON_RESULT=$(printf "%s" "$RAW_OUTPUT" | sed -n '/```json/,/```/p' | sed '1d;$d')
|
|
if [ -z "$JSON_RESULT" ]; then
|
|
JSON_RESULT="$RAW_OUTPUT"
|
|
fi
|
|
|
|
if ! echo "$JSON_RESULT" | jq empty 2>/dev/null; then
|
|
echo "::warning::Invalid JSON in AI response, using fallback"
|
|
JSON_RESULT='{"is_valid":true,"issue_type":"other","missing_info":[],"suggestions":[],"overall_assessment":"Unable to validate automatically"}'
|
|
fi
|
|
|
|
IS_VALID=$(echo "$JSON_RESULT" | jq -r '.is_valid // false')
|
|
ISSUE_TYPE=$(echo "$JSON_RESULT" | jq -r '.issue_type // "other"')
|
|
MISSING_INFO=$(echo "$JSON_RESULT" | jq -r '.missing_info[]? // empty' | sed 's/^/- /')
|
|
SUGGESTIONS=$(echo "$JSON_RESULT" | jq -r '.suggestions[]? // empty' | sed 's/^/- /')
|
|
ASSESSMENT=$(echo "$JSON_RESULT" | jq -r '.overall_assessment // "No assessment provided"')
|
|
|
|
IS_FIRST_TIME="${{ steps.check-first-time.outputs.is_first_time }}"
|
|
GREETING_SECTION=""
|
|
if [ "$IS_FIRST_TIME" = "true" ]; then
|
|
GREETING_SECTION="## 👋 Welcome!\n\nThank you for your first issue ❤️ If this is a feature request, please make sure it is clear what you want, why you want it, and how important it is to you. If you posted a bug report, please make sure it includes as much detail as possible.\n\n---\n\n"
|
|
fi
|
|
|
|
if [ "$IS_VALID" = "false" ]; then
|
|
{
|
|
printf "%b" "$GREETING_SECTION"
|
|
printf "## 🤖 Issue Validation\n\n"
|
|
printf "Thank you for submitting this issue! However, it appears that some required information might be missing to help us better understand and address your concern.\n\n"
|
|
printf "**Issue Type Detected:** \`%s\`\n\n" "$ISSUE_TYPE"
|
|
printf "**Assessment:** %s\n\n" "$ASSESSMENT"
|
|
printf "### 📋 Missing Information:\n%s\n\n" "$MISSING_INFO"
|
|
printf "### 💡 Suggestions for Improvement:\n%s\n\n" "$SUGGESTIONS"
|
|
printf "### 📝 How to Provide Additional Information:\n\n"
|
|
printf "Please edit your original issue description to include the missing information. Here are our issue templates for reference:\n\n"
|
|
printf -- "- **Bug Report Template:** [View Template](.github/ISSUE_TEMPLATE/01-bug-report.md)\n"
|
|
printf -- "- **Feature Request Template:** [View Template](.github/ISSUE_TEMPLATE/02-feature-request.md)\n\n"
|
|
printf "### 🔧 Quick Tips:\n"
|
|
printf -- "- For **bug reports**: Include step-by-step reproduction instructions, your environment details, and any error messages\n"
|
|
printf -- "- For **feature requests**: Describe the use case, expected behavior, and why this feature would be valuable\n"
|
|
printf -- "- Add **screenshots** or **logs** when applicable\n\n"
|
|
printf "Once you have updated the issue with the missing information, feel free to remove this comment or reply to let us know you have made the updates.\n\n"
|
|
printf -- "---\n*This validation was performed automatically to ensure we have all the information needed to help you effectively.*\n"
|
|
} > comment.md
|
|
|
|
gh issue comment ${{ github.event.issue.number }} --body-file comment.md
|
|
gh issue edit ${{ github.event.issue.number }} --add-label "needs-info"
|
|
else
|
|
SUGGESTIONS_SECTION=""
|
|
if [ -n "$SUGGESTIONS" ]; then
|
|
SUGGESTIONS_SECTION=$(printf "### 💡 Suggestions:\n%s\n\n" "$SUGGESTIONS")
|
|
fi
|
|
|
|
{
|
|
printf "%b" "$GREETING_SECTION"
|
|
printf "## 🤖 Issue Validation\n\n"
|
|
printf "**Issue Type Detected:** \`%s\`\n\n" "$ISSUE_TYPE"
|
|
printf "**Assessment:** %s\n\n" "$ASSESSMENT"
|
|
printf "%b" "$SUGGESTIONS_SECTION"
|
|
printf -- "---\n*This validation was performed automatically to help triage issues.*\n"
|
|
} > comment.md
|
|
|
|
gh issue comment ${{ github.event.issue.number }} --body-file comment.md
|
|
|
|
case "$ISSUE_TYPE" in
|
|
"bug_report")
|
|
gh issue edit ${{ github.event.issue.number }} --add-label "bug"
|
|
;;
|
|
"feature_request")
|
|
gh issue edit ${{ github.event.issue.number }} --add-label "enhancement"
|
|
;;
|
|
esac
|
|
fi
|
|
|
|
- name: Run opencode analysis
|
|
uses: anomalyco/opencode/github@latest
|
|
env:
|
|
ZHIPU_API_KEY: ${{ secrets.ZHIPU_API_KEY }}
|
|
with:
|
|
model: zai-coding-plan/glm-4.7
|
|
|
|
- name: Cleanup
|
|
run: rm -f issue_analysis.txt comment.md
|
|
|
|
handle-pr:
|
|
if: github.event_name == 'pull_request' && github.actor != 'dependabot[bot]'
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Check if first-time contributor
|
|
id: check-first-time
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
|
|
run: |
|
|
PR_COUNT=$(gh api "/repos/${{ github.repository }}/pulls?state=all&per_page=100" \
|
|
--jq "[.[] | select(.user.login == \"$PR_AUTHOR\" and .number != ${{ github.event.pull_request.number }})] | length" \
|
|
|| echo "0")
|
|
|
|
if [ "$PR_COUNT" = "0" ]; then
|
|
echo "is_first_time=true" >> $GITHUB_OUTPUT
|
|
else
|
|
echo "is_first_time=false" >> $GITHUB_OUTPUT
|
|
fi
|
|
|
|
- name: Get PR diff
|
|
id: get-diff
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
run: |
|
|
gh pr diff ${{ github.event.pull_request.number }} > pr_diff.txt
|
|
head -c 10000 pr_diff.txt > pr_diff_truncated.txt
|
|
|
|
- name: Create PR analysis prompt
|
|
env:
|
|
PR_TITLE: ${{ github.event.pull_request.title }}
|
|
PR_BODY: ${{ github.event.pull_request.body }}
|
|
run: |
|
|
{
|
|
printf "## Pull Request to Review:\n\n"
|
|
printf "**Title:** %s\n\n" "$PR_TITLE"
|
|
printf "**Description:**\n%s\n\n" "$PR_BODY"
|
|
printf "**Diff:**\n"
|
|
cat pr_diff_truncated.txt
|
|
} > pr_analysis.txt
|
|
|
|
- name: Analyze PR with AI
|
|
id: analyze
|
|
uses: actions/ai-inference@a6101c89c6feaecc585efdd8d461f18bb7896f20 # v2.0.5
|
|
with:
|
|
prompt-file: pr_analysis.txt
|
|
system-prompt: |
|
|
You are a code review assistant for Donut Browser, an open-source anti-detect browser built with Tauri, Next.js, and Rust.
|
|
|
|
Review the provided pull request and provide constructive feedback. Focus on:
|
|
1. Code quality and best practices
|
|
2. Potential bugs or issues
|
|
3. Security concerns (especially important for an anti-detect browser)
|
|
4. Performance implications
|
|
5. Consistency with the project's patterns
|
|
|
|
Respond ONLY with valid JSON (no markdown fences).
|
|
|
|
JSON structure:
|
|
{
|
|
"summary": "Brief 1-2 sentence summary of what this PR does",
|
|
"quality_score": "good"|"needs_work"|"critical_issues",
|
|
"feedback": ["feedback point 1", "feedback point 2"],
|
|
"suggestions": ["suggestion 1", "suggestion 2"],
|
|
"security_notes": ["security note if any"] or []
|
|
}
|
|
|
|
IMPORTANT CONSTRAINTS:
|
|
- Maximum 4 items in feedback array
|
|
- Maximum 3 items in suggestions array
|
|
- Maximum 2 items in security_notes array
|
|
- Each array item must be under 150 characters
|
|
- summary must be under 200 characters
|
|
- Be constructive and helpful, not harsh
|
|
- Output ONLY the JSON object, nothing else
|
|
model: gpt-5-mini
|
|
|
|
- name: Post PR feedback comment
|
|
env:
|
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
RESPONSE_FILE: ${{ steps.analyze.outputs.response-file }}
|
|
run: |
|
|
if [ -n "$RESPONSE_FILE" ] && [ -f "$RESPONSE_FILE" ]; then
|
|
RAW_OUTPUT=$(cat "$RESPONSE_FILE")
|
|
else
|
|
echo "::error::Response file not found"
|
|
exit 1
|
|
fi
|
|
|
|
JSON_RESULT=$(printf "%s" "$RAW_OUTPUT" | sed -n '/```json/,/```/p' | sed '1d;$d')
|
|
if [ -z "$JSON_RESULT" ]; then
|
|
JSON_RESULT="$RAW_OUTPUT"
|
|
fi
|
|
|
|
if ! echo "$JSON_RESULT" | jq empty 2>/dev/null; then
|
|
echo "::warning::Invalid JSON in AI response, using fallback"
|
|
JSON_RESULT='{"summary":"Unable to analyze automatically","quality_score":"good","feedback":[],"suggestions":[],"security_notes":[]}'
|
|
fi
|
|
|
|
SUMMARY=$(echo "$JSON_RESULT" | jq -r '.summary // "No summary"')
|
|
QUALITY=$(echo "$JSON_RESULT" | jq -r '.quality_score // "good"')
|
|
FEEDBACK=$(echo "$JSON_RESULT" | jq -r '.feedback[]? // empty' | sed 's/^/- /')
|
|
SUGGESTIONS=$(echo "$JSON_RESULT" | jq -r '.suggestions[]? // empty' | sed 's/^/- /')
|
|
SECURITY=$(echo "$JSON_RESULT" | jq -r '.security_notes[]? // empty' | sed 's/^/- ⚠️ /')
|
|
|
|
IS_FIRST_TIME="${{ steps.check-first-time.outputs.is_first_time }}"
|
|
|
|
{
|
|
if [ "$IS_FIRST_TIME" = "true" ]; then
|
|
printf "## 👋 Welcome!\n\n"
|
|
printf "Thank you for your first contribution ❤️ A human will review your PR shortly. Make sure that the pipelines are green, so that the PR is considered ready for review and could be merged.\n\n"
|
|
printf -- "---\n\n"
|
|
fi
|
|
|
|
printf "## 🤖 PR Review\n\n"
|
|
printf "**Summary:** %s\n\n" "$SUMMARY"
|
|
|
|
case "$QUALITY" in
|
|
"good")
|
|
printf "**Status:** ✅ Looking good!\n\n"
|
|
;;
|
|
"needs_work")
|
|
printf "**Status:** 🔧 Some improvements suggested\n\n"
|
|
;;
|
|
"critical_issues")
|
|
printf "**Status:** ⚠️ Please address the issues below\n\n"
|
|
;;
|
|
esac
|
|
|
|
if [ -n "$FEEDBACK" ]; then
|
|
printf "### 📝 Feedback:\n%s\n\n" "$FEEDBACK"
|
|
fi
|
|
|
|
if [ -n "$SUGGESTIONS" ]; then
|
|
printf "### 💡 Suggestions:\n%s\n\n" "$SUGGESTIONS"
|
|
fi
|
|
|
|
if [ -n "$SECURITY" ]; then
|
|
printf "### 🔒 Security Notes:\n%s\n\n" "$SECURITY"
|
|
fi
|
|
|
|
printf -- "---\n*This review was performed automatically. A human maintainer will also review your changes.*\n"
|
|
} > comment.md
|
|
|
|
gh pr comment ${{ github.event.pull_request.number }} --body-file comment.md
|
|
|
|
- name: Run opencode analysis
|
|
uses: anomalyco/opencode/github@latest
|
|
env:
|
|
ZHIPU_API_KEY: ${{ secrets.ZHIPU_API_KEY }}
|
|
with:
|
|
model: zai-coding-plan/glm-4.7
|
|
|
|
- name: Cleanup
|
|
run: rm -f pr_diff.txt pr_diff_truncated.txt pr_analysis.txt comment.md
|
|
|
|
opencode-command:
|
|
if: |
|
|
(github.event_name == 'issue_comment' || github.event_name == 'pull_request_review_comment') &&
|
|
(contains(github.event.comment.body, ' /oc') ||
|
|
startsWith(github.event.comment.body, '/oc') ||
|
|
contains(github.event.comment.body, ' /opencode') ||
|
|
startsWith(github.event.comment.body, '/opencode'))
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 #v6.0.1
|
|
|
|
- name: Run opencode
|
|
uses: anomalyco/opencode/github@latest
|
|
env:
|
|
ZHIPU_API_KEY: ${{ secrets.ZHIPU_API_KEY }}
|
|
with:
|
|
model: zai-coding-plan/glm-4.7
|