Skip to content

Commit f990588

Browse files
authored
chore: add AI issue triage workflow and structured-field label rules (#4915)
- Add AI triage workflow that flags low-quality issues and requests missing info - Add sync-game-labels script and workflow to maintain game labels from serverlist - Add structured label rules for severity, reproducibility, priority, and scope - Update labeler workflow to support both issues and PRs with dedicated config - Add PR review guidance instructions for maintainers
1 parent d05992d commit f990588

6 files changed

Lines changed: 475 additions & 16 deletions

File tree

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
---
2+
title: "LinuxGSM PR Review Guidance"
3+
applyTo: "**"
4+
description: "Use when reviewing pull requests in LinuxGSM; prioritize regressions, behavior changes, shell safety, and missing tests over style-only feedback."
5+
---
6+
7+
Focus review effort on correctness and operational safety first.
8+
9+
Primary priorities:
10+
11+
- Identify behavior regressions and compatibility risks.
12+
- Flag unsafe shell patterns (`rm -rf`, unquoted vars, unchecked command failures).
13+
- Verify workflow changes do not weaken permissions or secret handling.
14+
- Check for missing tests/validation when logic changes.
15+
- Confirm labels, templates, and automation rules stay internally consistent.
16+
17+
Feedback expectations:
18+
19+
- Give concrete, actionable findings with file and reason.
20+
- Prefer high-signal issues over style nits.
21+
- If no defects are found, state that clearly and mention residual risk areas.
22+
- Suggest minimal, low-risk fixes before proposing broad refactors.
23+
24+
LinuxGSM-specific checks:
25+
26+
- Shell scripts should preserve robust defaults (`set -euo pipefail` where appropriate).
27+
- Label/workflow updates should avoid duplicate or stale taxonomy.
28+
- Automation should fail safe (log and continue for advisory AI; block on true CI errors).
29+
- Keep issue/PR automation rules aligned with templates and existing labels.

.github/labeler.yml

Lines changed: 73 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -69,29 +69,35 @@
6969
"game: Ballistic Overkill":
7070
- "/(Ballistic Overkill)/i"
7171
"game: BATTALION: Legacy":
72-
- "/(BATTALION: Legacy)/i"
72+
- "/(BATTALION: Legacy|Battalion 1944)/i"
7373
"game: Barotrauma":
7474
- "/(Barotrauma)/i"
7575
"game: Counter-Strike: Global Offensive":
7676
- "/(Counter-Strike: Global Offensive|CS:GO|csgo)/i"
7777
"game: Counter-Strike 2":
7878
- "/(Counter-Strike 2|CS2)/i"
7979
"game: Counter-Strike: Source":
80-
- "/(Counter-Strike: Source|CS:S)/i"
80+
- "/(Counter-Strike: Source|Counter Strike: Source|CS:S)/i"
8181
"game: Counter-Strike 1.6":
8282
- "/(Counter-Strike 1.6|Counter Strike 1.6|CS 1.6|cs1.6)/i"
83-
"game: Dayz":
84-
- "/(Dayz)/i"
83+
"game: DayZ":
84+
- "/(DayZ|Dayz)/i"
85+
"game: Deathmatch Classic":
86+
- "/(Deathmatch Classic|Death Match Classic|DMC)/i"
8587
"game: Don't Starve Together":
8688
- "/(Don't Starve Together|Dont Starve Together|DST)/i"
8789
"game: Eco":
8890
- "/(^Eco$)/i"
8991
"game: Factorio":
9092
- "/(Factorio)/i"
91-
"game: Garry's Mod":
93+
"game: Garrys Mod":
9294
- "/(Garry's Mod|Garrys Mod|GMod)/i"
95+
"game: Hurtworld":
96+
- "/(Hurtworld|Hurtword)/i"
97+
"game: Insurgency":
98+
- "/(^Insurgency$|Insurgecy)/i"
9399
"game: Insurgency: Sandstorm":
94-
- "/(Insurgency: Sandstorm|Insurgency)/i"
100+
- "/(Insurgency: Sandstorm)/i"
95101
"game: Killing Floor 2":
96102
- "/(Killing Floor 2|KF2)/i"
97103
"game: Left 4 Dead 2":
@@ -100,18 +106,20 @@
100106
- "/(Minecraft)((?!bedrock).)*$/i"
101107
"game: Minecraft Bedrock":
102108
- "/(Bedrock)/i"
103-
"game: Mumble":
104-
- "/(Mumble)/i"
105109
"game: Project Zomboid":
106110
- "/(Project Zomboid|PZ)/i"
107-
"game: Quake 3":
108-
- "/(Quake 3|Q3A|q3)/i"
111+
"game: Quake 3: Arena":
112+
- "/(Quake 3: Arena|Quake 3|Q3A|q3)/i"
113+
"game: Quake World":
114+
- "/(Quake World|QuakeWorld)/i"
109115
"game: Rising World":
110116
- "/(Rising World)/i"
111117
"game: Satisfactory":
112118
- "/(Satisfactory)/i"
113119
"game: Squad":
114120
- "/(Squad)/i"
121+
"game: Squad 44":
122+
- "/(Squad 44|Post Scriptum)/i"
115123
"game: Starbound":
116124
- "/(Starbound)/i"
117125
"game: Stationeers":
@@ -120,6 +128,8 @@
120128
- "/(Teamspeak 3|ts3)/i"
121129
"game: Rust":
122130
- "/(Rust)/i"
131+
"game: Soldier Of Fortune 2: Gold Edition":
132+
- "/(Soldier Of Fortune 2: Gold Edition|Soldier of Fortune 2)/i"
123133
"game: Unturned":
124134
- "/(Unturned)/i"
125135
"game: Unreal Tournament 99":
@@ -130,6 +140,8 @@
130140
- "/(Unreal Tournament 3|ut3)/i"
131141
"game: Valheim":
132142
- "/(Valheim)/i"
143+
"game: Zombie Master: Reborn":
144+
- "/(Zombie Master: Reborn|Zombie Master Reborn)/i"
133145

134146
# Info
135147
"info: alerts":
@@ -157,6 +169,54 @@
157169
"type: game server request":
158170
- "/(Server Request)/i"
159171
"type: bug":
160-
- "/(bug)/i"
161-
"type: feature request":
162-
- "/(feature)/i"
172+
- "/(\\[bug\\]|bug report|type: bug)/i"
173+
"type: bugfix":
174+
- "/(^fix(\\(.+\\))?:|\\[x\\] Bug fix)/im"
175+
"type: feature":
176+
- "/(feature request|new feature|^feat(\\(.+\\))?:|\\[x\\] New feature)/im"
177+
"type: docs":
178+
- "/(^docs(\\(.+\\))?:|documentation|\\[x\\] Comment update)/im"
179+
"type: refactor":
180+
- "/(^refactor(\\(.+\\))?:|\\[x\\] Refactor)/im"
181+
"type: chore":
182+
- "/(^chore(\\(.+\\))?:|^ci(\\(.+\\))?:)/im"
183+
184+
# Severity (bug reports)
185+
"severity: low":
186+
- "/(severity: low)/i"
187+
"severity: medium":
188+
- "/(severity: medium)/i"
189+
"severity: high":
190+
- "/(severity: high)/i"
191+
"severity: critical":
192+
- "/(severity: critical)/i"
193+
194+
# Reproducibility (bug reports)
195+
"reproducible: always":
196+
- "/(reproducible: always)/i"
197+
"reproducible: sometimes":
198+
- "/(reproducible: sometimes)/i"
199+
"reproducible: unable":
200+
- "/(reproducible: unable)/i"
201+
202+
# Regression (bug reports)
203+
"regression: yes":
204+
- "/(regression: yes)/i"
205+
206+
# Priority (feature requests)
207+
"priority: low":
208+
- "/(priority: low)/i"
209+
"priority: medium":
210+
- "/(priority: medium)/i"
211+
"priority: high":
212+
- "/(priority: high)/i"
213+
214+
# Scope (feature requests)
215+
"scope: single game":
216+
- "/(scope: single game)/i"
217+
"scope: multiple games":
218+
- "/(scope: multiple games)/i"
219+
"scope: all servers":
220+
- "/(scope: all servers)/i"
221+
"scope: documentation":
222+
- "/(scope: documentation)/i"
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/usr/bin/env bash
2+
# sync-game-labels.sh
3+
# Reads lgsm/data/serverlist.csv and ensures a "game: <name>" label exists in
4+
# the GitHub repo for every unique game name. Safe to run multiple times.
5+
#
6+
# Requires: gh CLI authenticated with issues:write scope.
7+
# Usage: .github/scripts/sync-game-labels.sh [OWNER/REPO]
8+
#
9+
# The OWNER/REPO argument is optional; if omitted gh uses the current repo.
10+
11+
set -euo pipefail
12+
13+
REPO="${1:-}"
14+
SERVERLIST="lgsm/data/serverlist.csv"
15+
LABEL_COLOR="5b21b6"
16+
LABEL_PREFIX="game: "
17+
18+
normalize_label() {
19+
printf '%s' "$1" | tr '[:upper:]' '[:lower:]'
20+
}
21+
22+
if [[ ! -f "${SERVERLIST}" ]]; then
23+
echo "ERROR: ${SERVERLIST} not found. Run from the repository root."
24+
exit 1
25+
fi
26+
27+
declare -A EXISTING_COLORS=()
28+
declare -A EXISTING_DESCRIPTIONS=()
29+
declare -A EXISTING_NAMES=()
30+
31+
# Fetch all existing game label metadata once (up to 1000) and cache locally.
32+
echo "Fetching existing labels..."
33+
while IFS=$'\t' read -r NAME COLOR DESCRIPTION; do
34+
[[ -n "${NAME}" ]] || continue
35+
EXISTING_COLORS["${NAME}"]="${COLOR}"
36+
EXISTING_DESCRIPTIONS["${NAME}"]="${DESCRIPTION}"
37+
EXISTING_NAMES["$(normalize_label "${NAME}")"]="${NAME}"
38+
done < <(
39+
gh label list --limit 1000 --json name,color,description ${REPO:+--repo "$REPO"} \
40+
| jq -r '.[] | select(.name | startswith("game: ")) | [.name, .color, (.description // "")] | @tsv'
41+
)
42+
43+
# Parse unique game names from the CSV (column 3, skip header).
44+
mapfile -t GAMES < <(
45+
tail -n +2 "${SERVERLIST}" \
46+
| cut -d',' -f3 \
47+
| sort -u
48+
)
49+
50+
CREATED=0
51+
UPDATED=0
52+
UNCHANGED=0
53+
54+
for GAME in "${GAMES[@]}"; do
55+
LABEL="${LABEL_PREFIX}${GAME}"
56+
DESCRIPTION="Issues related to ${GAME}"
57+
NORMALIZED_LABEL="$(normalize_label "${LABEL}")"
58+
59+
if [[ -v EXISTING_NAMES["${NORMALIZED_LABEL}"] ]]; then
60+
CURRENT_LABEL="${EXISTING_NAMES["${NORMALIZED_LABEL}"]}"
61+
CURRENT_COLOR="${EXISTING_COLORS["${CURRENT_LABEL}"]}"
62+
CURRENT_DESCRIPTION="${EXISTING_DESCRIPTIONS["${CURRENT_LABEL}"]}"
63+
64+
if [[ "${CURRENT_LABEL}" != "${LABEL}" || "${CURRENT_COLOR}" != "${LABEL_COLOR}" || "${CURRENT_DESCRIPTION}" != "${DESCRIPTION}" ]]; then
65+
echo " update ${LABEL}"
66+
gh label edit "${CURRENT_LABEL}" \
67+
--name "${LABEL}" \
68+
--color "${LABEL_COLOR}" \
69+
--description "${DESCRIPTION}" \
70+
${REPO:+--repo "$REPO"}
71+
(( UPDATED++ )) || true
72+
else
73+
echo " ok ${LABEL}"
74+
(( UNCHANGED++ )) || true
75+
fi
76+
else
77+
echo " create ${LABEL}"
78+
gh label create "${LABEL}" \
79+
--color "${LABEL_COLOR}" \
80+
--description "${DESCRIPTION}" \
81+
${REPO:+--repo "$REPO"}
82+
(( CREATED++ )) || true
83+
fi
84+
done
85+
86+
echo ""
87+
echo "Done. Created: ${CREATED} Updated: ${UPDATED} Unchanged: ${UNCHANGED}"

0 commit comments

Comments
 (0)