DocsRecipes
Gate issue forms
Reject malformed issue reports with precise diagnostics for each missing section.
Mission control can help faster when the distress call has coordinates, expected telemetry, and impact.
This is the issue-body version of PR body validation: one issue form doubles as the contract, and CI checks both the issue title and body. Non-engineers get a specific diagnostic [code] for each gap instead of a vague "please fill out the template."
The contract
<!-- mdv: document title title.minWords=3 title.noPlaceholder -->
<!-- mdv: section required minWords=15 noPlaceholder -->
## Summary
What happened, and who is affected?
<!-- mdv: endsection -->
<!-- mdv: section required minWords=15 noPlaceholder -->
## Reproduction / Use-case
What steps, inputs, or workflow make this happen?
<!-- mdv: endsection -->
<!-- mdv: section required minWords=10 noPlaceholder -->
## Expected
What should have happened instead?
<!-- mdv: endsection -->
<!-- mdv: section required minWords=10 noPlaceholder -->
## Impact
How often does this happen, and what does it block?
<!-- mdv: endsection -->The title rules run against the issue title supplied with --title "..."; the section rules run against the issue body.
The GitHub Action
on:
issues:
types: [opened, edited, reopened]
jobs:
validate-issue:
runs-on: ubuntu-latest
permissions:
issues: write
contents: read
steps:
- uses: actions/checkout@v4
- run: npm install -D mediva
- env:
TITLE: ${{ github.event.issue.title }}
BODY: ${{ github.event.issue.body }}
run: |
printf '%s' "$BODY" > /tmp/issue.md
npx mediva check /tmp/issue.md --schema .github/ISSUE_TEMPLATE/bug_report.md --title "$TITLE" > /tmp/mediva.txt 2>&1
- if: failure()
uses: actions/github-script@v7
with:
script: |
const fs = require("fs");
const body = [
"mediva could not validate this issue report:",
"",
"```txt",
fs.readFileSync("/tmp/mediva.txt", "utf8").trim(),
"```"
].join("\n");
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.issue.number,
body
});
core.setFailed("Issue report does not match the template.");The npx mediva check step exits 1 for validation errors, so the job fails after posting the exact section and rule codes.
Variations
- Add a
## Severitysection wrapping achoice oneChecked exactLabelsleaf if reporters must choose exactly one impact level. - Use separate contracts per issue template when bugs, feature requests, and support requests need different sections.