mirror of
https://github.com/shipshitdev/skills.git
synced 2026-09-19 06:04:15 +08:00
feat(governance): require board + status + priority + type on every issue
GitHub can't block issue creation on missing fields, so enforce continuously: - .github/workflows/issue-governance.yml — on every issue event, ensure the issue is on the Dev Loop board (#7) and auto-fill any empty field (Status=Backlog, Priority=P2, Type=Task), then label needs-triage + comment so a human sets real values. Idempotent: only writes when a field is empty. Needs PROJECTS_TOKEN (project-scoped PAT) — default GITHUB_TOKEN can't write an org board. - .github/ISSUE_TEMPLATE/ — Feature/Bug/Task forms set the native issue Type and add the issue to the board at creation; blank issues disabled so every issue starts typed + boarded.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
name: Bug report
|
||||
description: Something isn't working
|
||||
type: Bug
|
||||
labels: ["bug"]
|
||||
projects: ["shipshitdev/7"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: what
|
||||
attributes:
|
||||
label: What's wrong
|
||||
description: What did you expect, and what happened instead?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: repro
|
||||
attributes:
|
||||
label: Steps to reproduce
|
||||
description: Minimal steps. Include the skill/command and the agent (Claude Code, Codex, Cursor).
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: context
|
||||
attributes:
|
||||
label: Environment
|
||||
description: OS, agent + version, and anything else relevant.
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
Status and Priority are set on the **Dev Loop** board after creation
|
||||
(auto-defaulted + `needs-triage` if you leave them).
|
||||
@@ -0,0 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Question / discussion
|
||||
url: https://github.com/shipshitdev/skills/discussions
|
||||
about: For open-ended questions, use Discussions. Issues are for tracked work.
|
||||
@@ -0,0 +1,33 @@
|
||||
name: Feature / enhancement
|
||||
description: Propose a new skill, command, or capability
|
||||
type: Feature
|
||||
labels: ["enhancement"]
|
||||
projects: ["shipshitdev/7"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: summary
|
||||
attributes:
|
||||
label: Summary
|
||||
description: What should exist that doesn't yet?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: value
|
||||
attributes:
|
||||
label: Value
|
||||
description: Why is this worth building? Who benefits and how?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: acceptance
|
||||
attributes:
|
||||
label: Acceptance criteria
|
||||
description: How do we know it's done?
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
Status and Priority are set on the **Dev Loop** board after creation
|
||||
(auto-defaulted + `needs-triage` if you leave them). Set the real values
|
||||
and drop the label.
|
||||
@@ -0,0 +1,22 @@
|
||||
name: Task / chore
|
||||
description: Maintenance, refactor, docs, or other tracked work
|
||||
type: Task
|
||||
projects: ["shipshitdev/7"]
|
||||
body:
|
||||
- type: textarea
|
||||
id: what
|
||||
attributes:
|
||||
label: What needs doing
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: why
|
||||
attributes:
|
||||
label: Why / context
|
||||
validations:
|
||||
required: false
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: >
|
||||
Status and Priority are set on the **Dev Loop** board after creation
|
||||
(auto-defaulted + `needs-triage` if you leave them).
|
||||
@@ -0,0 +1,101 @@
|
||||
name: Issue Governance
|
||||
|
||||
# Enforce that every issue always carries the four required fields:
|
||||
# board membership · Status · Priority · Type
|
||||
# GitHub cannot block issue creation on missing fields, so this auto-fills
|
||||
# sane defaults for any empty field and flags the issue `needs-triage` for a
|
||||
# human to set real values. Idempotent: it only writes when a field is empty,
|
||||
# so once an issue is compliant it stops touching it.
|
||||
#
|
||||
# Board writes need a project-scoped PAT — the default GITHUB_TOKEN cannot
|
||||
# read/write an org-owned Projects v2 board. Store it as the PROJECTS_TOKEN
|
||||
# repo secret (same token the dev-loop workflows use).
|
||||
|
||||
on:
|
||||
issues:
|
||||
types: [opened, reopened, transferred, edited, labeled, unlabeled, demilestoned, assigned]
|
||||
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
|
||||
concurrency:
|
||||
group: issue-governance-${{ github.event.issue.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
PROJECT_OWNER: shipshitdev
|
||||
PROJECT_NUMBER: "7" # Dev Loop board
|
||||
DEFAULT_PRIORITY: "P2" # matched against the board's Priority options
|
||||
DEFAULT_TYPE: "Task" # org issue type: Task | Bug | Feature
|
||||
|
||||
jobs:
|
||||
enforce:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Enforce board + status + priority + type
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PROJECTS_TOKEN }}
|
||||
ISSUE: ${{ github.event.issue.number }}
|
||||
REPO: ${{ github.repository }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [ -z "${GH_TOKEN:-}" ]; then
|
||||
echo "::error::PROJECTS_TOKEN secret is not set — cannot read/write the org board. See workflow header."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- resolve board ids ---
|
||||
NODE=$(gh project view "$PROJECT_NUMBER" --owner "$PROJECT_OWNER" --format json | jq -r '.id')
|
||||
FL=$(gh project field-list "$PROJECT_NUMBER" --owner "$PROJECT_OWNER" --format json)
|
||||
SF=$(echo "$FL" | jq -r '.fields[]|select(.name=="Status").id')
|
||||
SB=$(echo "$FL" | jq -r '.fields[]|select(.name=="Status").options[]|select(.name|test("Backlog")).id')
|
||||
PF=$(echo "$FL" | jq -r '.fields[]|select(.name=="Priority").id')
|
||||
PD=$(echo "$FL" | jq -r --arg p "$DEFAULT_PRIORITY" '.fields[]|select(.name=="Priority").options[]|select(.name|test($p)).id')
|
||||
|
||||
IURL=$(gh issue view "$ISSUE" -R "$REPO" --json url -q .url)
|
||||
FLAGS=""
|
||||
|
||||
# --- 1. ensure the issue is on the board ---
|
||||
ITEMS=$(gh project item-list "$PROJECT_NUMBER" --owner "$PROJECT_OWNER" --format json -L 800)
|
||||
ITEM=$(echo "$ITEMS" | jq -r --arg u "$IURL" '.items[]|select(.content.url==$u).id' | head -1)
|
||||
if [ -z "$ITEM" ]; then
|
||||
ITEM=$(gh project item-add "$PROJECT_NUMBER" --owner "$PROJECT_OWNER" --url "$IURL" --format json | jq -r '.id')
|
||||
FLAGS="${FLAGS}added to board; "
|
||||
ITEMS=$(gh project item-list "$PROJECT_NUMBER" --owner "$PROJECT_OWNER" --format json -L 800)
|
||||
fi
|
||||
IV=$(echo "$ITEMS" | jq -r --arg u "$IURL" '.items[]|select(.content.url==$u)')
|
||||
CUR_STATUS=$(echo "$IV" | jq -r '.status // ""')
|
||||
CUR_PRI=$(echo "$IV" | jq -r '.priority // ""')
|
||||
|
||||
# --- 2. Status default ---
|
||||
if [ -z "$CUR_STATUS" ]; then
|
||||
gh project item-edit --id "$ITEM" --project-id "$NODE" --field-id "$SF" --single-select-option-id "$SB"
|
||||
FLAGS="${FLAGS}Status=Backlog; "
|
||||
fi
|
||||
|
||||
# --- 3. Priority default ---
|
||||
if [ -z "$CUR_PRI" ]; then
|
||||
gh project item-edit --id "$ITEM" --project-id "$NODE" --field-id "$PF" --single-select-option-id "$PD"
|
||||
FLAGS="${FLAGS}Priority=${DEFAULT_PRIORITY} (default); "
|
||||
fi
|
||||
|
||||
# --- 4. Type default (native issue type) ---
|
||||
CUR_TYPE=$(gh issue view "$ISSUE" -R "$REPO" --json issueType -q '.issueType.name // ""')
|
||||
if [ -z "$CUR_TYPE" ]; then
|
||||
gh issue edit "$ISSUE" -R "$REPO" --type "$DEFAULT_TYPE"
|
||||
FLAGS="${FLAGS}Type=${DEFAULT_TYPE} (default); "
|
||||
fi
|
||||
|
||||
# --- 5. flag + comment only when something was auto-filled ---
|
||||
if [ -n "$FLAGS" ]; then
|
||||
gh issue edit "$ISSUE" -R "$REPO" --add-label needs-triage || true
|
||||
{
|
||||
echo "🤖 **Issue governance** auto-filled required fields: ${FLAGS%; }."
|
||||
echo ""
|
||||
echo "Set the real values — board **Status**/**Priority** and the issue **Type** — then remove the \`needs-triage\` label."
|
||||
} | gh issue comment "$ISSUE" -R "$REPO" --body-file -
|
||||
echo "Auto-filled: ${FLAGS%; }"
|
||||
else
|
||||
echo "Issue #$ISSUE already compliant — no changes."
|
||||
fi
|
||||
Reference in New Issue
Block a user