mirror of
https://github.com/meshtastic/firmware.git
synced 2026-01-29 21:22:03 +00:00
* Add GitHub workflows for issue completeness, duplicate detection, onboarding, and contribution quality checks * Fix indentation * Refactor GitHub workflows for issue handling * Consolidate to two triage workflows * Update .github/workflows/models_pr_triage.yml Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
139 lines
7.3 KiB
YAML
139 lines
7.3 KiB
YAML
name: PR Triage (Models)
|
|
|
|
on:
|
|
pull_request_target:
|
|
types: [opened]
|
|
|
|
permissions:
|
|
pull-requests: write
|
|
issues: write
|
|
models: read
|
|
|
|
concurrency:
|
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
|
cancel-in-progress: true
|
|
|
|
jobs:
|
|
triage:
|
|
if: ${{ github.repository == 'meshtastic/firmware' && github.event.pull_request.user.type != 'Bot' }}
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
# Step 1: Check if PR already has automation/type labels (skip if so)
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
- name: Check existing labels
|
|
uses: actions/github-script@v8
|
|
id: check-labels
|
|
with:
|
|
script: |
|
|
const skipLabels = new Set(['automation']);
|
|
const typeLabels = new Set(['bugfix', 'hardware-support', 'enhancement', 'dependencies', 'submodules', 'github_actions', 'trunk', 'cleanup']);
|
|
const prLabels = context.payload.pull_request.labels.map(l => l.name);
|
|
|
|
const shouldSkipAll = prLabels.some(l => skipLabels.has(l));
|
|
const hasTypeLabel = prLabels.some(l => typeLabels.has(l));
|
|
|
|
core.setOutput('skip_all', shouldSkipAll ? 'true' : 'false');
|
|
core.setOutput('has_type_label', hasTypeLabel ? 'true' : 'false');
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
# Step 2: Quality check (spam/AI-slop detection)
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
- name: Detect spam or low-quality content
|
|
if: steps.check-labels.outputs.skip_all != 'true'
|
|
uses: actions/ai-inference@v2
|
|
id: quality
|
|
continue-on-error: true
|
|
with:
|
|
max-tokens: 20
|
|
prompt: |
|
|
Is this GitHub pull request spam, AI-generated slop, or low quality?
|
|
|
|
Title: ${{ github.event.pull_request.title }}
|
|
Body: ${{ github.event.pull_request.body }}
|
|
|
|
Respond with exactly one of: spam, ai-generated, needs-review, ok
|
|
system-prompt: You detect spam and low-quality contributions. Be conservative - only flag obvious spam or AI slop.
|
|
model: openai/gpt-4o-mini
|
|
|
|
- name: Apply quality label if needed
|
|
if: steps.check-labels.outputs.skip_all != 'true' && steps.quality.outputs.response != '' && steps.quality.outputs.response != 'ok'
|
|
uses: actions/github-script@v8
|
|
id: quality-label
|
|
env:
|
|
QUALITY_LABEL: ${{ steps.quality.outputs.response }}
|
|
with:
|
|
script: |
|
|
const label = (process.env.QUALITY_LABEL || '').trim().toLowerCase();
|
|
const labelMeta = {
|
|
'spam': { color: 'd73a4a', description: 'Possible spam' },
|
|
'ai-generated': { color: 'fbca04', description: 'Possible AI-generated low-quality content' },
|
|
'needs-review': { color: 'f9d0c4', description: 'Needs human review' },
|
|
};
|
|
const meta = labelMeta[label];
|
|
if (!meta) return;
|
|
|
|
// Ensure label exists
|
|
try {
|
|
await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
|
|
} catch (e) {
|
|
if (e.status !== 404) throw e;
|
|
await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
|
|
}
|
|
|
|
// Apply label
|
|
await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: [label] });
|
|
|
|
core.setOutput('is_spam', 'true');
|
|
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
# Step 3: Auto-label PR type (bugfix/hardware-support/enhancement)
|
|
# ─────────────────────────────────────────────────────────────────────────
|
|
- name: Classify PR for labeling
|
|
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && (steps.quality.outputs.response == 'ok' || steps.quality.outputs.response == '')
|
|
uses: actions/ai-inference@v2
|
|
id: classify
|
|
continue-on-error: true
|
|
with:
|
|
max-tokens: 30
|
|
prompt: |
|
|
Classify this pull request into exactly one category.
|
|
|
|
Return exactly one of: bugfix, hardware-support, enhancement
|
|
|
|
Use bugfix if it fixes a bug, crash, or incorrect behavior.
|
|
Use hardware-support if it adds or improves support for a specific hardware device/variant.
|
|
Use enhancement if it adds a new feature, improves performance, or refactors code.
|
|
|
|
Title: ${{ github.event.pull_request.title }}
|
|
Body: ${{ github.event.pull_request.body }}
|
|
system-prompt: You classify pull requests into categories. Be conservative and pick the most appropriate single label.
|
|
model: openai/gpt-4o-mini
|
|
|
|
- name: Apply type label
|
|
if: steps.check-labels.outputs.skip_all != 'true' && steps.check-labels.outputs.has_type_label != 'true' && steps.classify.outputs.response != ''
|
|
uses: actions/github-script@v8
|
|
env:
|
|
TYPE_LABEL: ${{ steps.classify.outputs.response }}
|
|
with:
|
|
script: |
|
|
const label = (process.env.TYPE_LABEL || '').trim().toLowerCase();
|
|
const labelMeta = {
|
|
'bugfix': { color: 'd73a4a', description: 'Bug fix' },
|
|
'hardware-support': { color: '0e8a16', description: 'Hardware support addition or improvement' },
|
|
'enhancement': { color: 'a2eeef', description: 'New feature or enhancement' },
|
|
};
|
|
const meta = labelMeta[label];
|
|
if (!meta) return;
|
|
|
|
// Ensure label exists
|
|
try {
|
|
await github.rest.issues.getLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label });
|
|
} catch (e) {
|
|
if (e.status !== 404) throw e;
|
|
await github.rest.issues.createLabel({ owner: context.repo.owner, repo: context.repo.repo, name: label, color: meta.color, description: meta.description });
|
|
}
|
|
|
|
// Apply label
|
|
await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: context.payload.pull_request.number, labels: [label] });
|