mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-04-23 20:36:09 +02:00
4ef50672b4
Bumps the github-actions group with 4 updates: [actions/ai-inference](https://github.com/actions/ai-inference), [anomalyco/opencode](https://github.com/anomalyco/opencode), [actions/setup-go](https://github.com/actions/setup-go) and [crate-ci/typos](https://github.com/crate-ci/typos). Updates `actions/ai-inference` from 2.0.6 to 2.0.7 - [Release notes](https://github.com/actions/ai-inference/releases) - [Commits](https://github.com/actions/ai-inference/compare/a380166897b5408b8fb7dddd148142794cb5624a...e09e65981758de8b2fdab13c2bfb7c7d5493b0b6) Updates `anomalyco/opencode` from 1.2.10 to 1.2.15 - [Release notes](https://github.com/anomalyco/opencode/releases) - [Commits](https://github.com/anomalyco/opencode/compare/296250f1b7e1ec992a3a33bee999f5e09a1697d0...799b2623cbb1c0f19e045d87c2c8593e83678bc0) Updates `actions/setup-go` from 5.6.0 to 6.3.0 - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/40f1582b2485089dde7abd97c1529aa768e1baff...4b73464bb391d4059bd26b0524d20df3927bd417) Updates `crate-ci/typos` from 1.43.5 to 1.44.0 - [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/57b11c6b7e54c402ccd9cda953f1072ec4f78e33...631208b7aac2daa8b707f55e7331f9112b0e062d) --- updated-dependencies: - dependency-name: actions/ai-inference dependency-version: 2.0.7 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: anomalyco/opencode dependency-version: 1.2.15 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: github-actions - dependency-name: actions/setup-go dependency-version: 6.3.0 dependency-type: direct:production update-type: version-update:semver-major dependency-group: github-actions - dependency-name: crate-ci/typos dependency-version: 1.44.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: github-actions ... Signed-off-by: dependabot[bot] <support@github.com>
303 lines
12 KiB
YAML
303 lines
12 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: Save issue body to file
|
|
env:
|
|
ISSUE_BODY: ${{ github.event.issue.body }}
|
|
run: printf '%s' "${ISSUE_BODY:-}" > issue_body.txt
|
|
|
|
- name: Validate issue with AI
|
|
id: validate
|
|
uses: actions/ai-inference@e09e65981758de8b2fdab13c2bfb7c7d5493b0b6 # v2.0.7
|
|
with:
|
|
prompt-file: .github/prompts/issue-validation.prompt.yml
|
|
input: |
|
|
issue_title: ${{ github.event.issue.title }}
|
|
issue_labels: ${{ join(github.event.issue.labels.*.name, ', ') }}
|
|
file_input: |
|
|
issue_body: ./issue_body.txt
|
|
max-tokens: 1024
|
|
|
|
- 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 the maintainers 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 the 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 the maintainers know the updates have been made.\n\n"
|
|
printf -- "---\n*This validation was performed automatically to ensure all the information needed to help effectively is provided.*\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@799b2623cbb1c0f19e045d87c2c8593e83678bc0 #v1.2.15
|
|
env:
|
|
ZHIPU_API_KEY: ${{ secrets.ZHIPU_API_KEY }}
|
|
with:
|
|
model: zai-coding-plan/glm-4.7
|
|
|
|
- name: Cleanup
|
|
run: rm -f issue_body.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: Save PR body to file
|
|
env:
|
|
PR_BODY: ${{ github.event.pull_request.body }}
|
|
run: printf '%s' "${PR_BODY:-No description provided}" > pr_body.txt
|
|
|
|
- name: Analyze PR with AI
|
|
id: analyze
|
|
uses: actions/ai-inference@e09e65981758de8b2fdab13c2bfb7c7d5493b0b6 # v2.0.7
|
|
with:
|
|
prompt-file: .github/prompts/pr-review.prompt.yml
|
|
input: |
|
|
pr_title: ${{ github.event.pull_request.title }}
|
|
file_input: |
|
|
pr_body: ./pr_body.txt
|
|
pr_diff: ./pr_diff_truncated.txt
|
|
max-tokens: 1024
|
|
|
|
- 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@799b2623cbb1c0f19e045d87c2c8593e83678bc0 #v1.2.15
|
|
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_body.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@799b2623cbb1c0f19e045d87c2c8593e83678bc0 #v1.2.15
|
|
env:
|
|
ZHIPU_API_KEY: ${{ secrets.ZHIPU_API_KEY }}
|
|
with:
|
|
model: zai-coding-plan/glm-4.7
|