MeDiVa
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

.github/ISSUE_TEMPLATE/bug_report.md
<!-- mdv: document title title.minWords=3 title.noPlaceholder -->
<!-- mdv: block required minWords=15 noPlaceholder -->
## Summary

What happened, and who is affected?
<!-- mdv: endblock -->

<!-- mdv: block required minWords=15 noPlaceholder -->
## Reproduction / Use-case

What steps, inputs, or workflow make this happen?
<!-- mdv: endblock -->

<!-- mdv: block required minWords=10 noPlaceholder -->
## Expected

What should have happened instead?
<!-- mdv: endblock -->

<!-- mdv: block required minWords=10 noPlaceholder -->
## Impact

How often does this happen, and what does it block?
<!-- mdv: endblock -->

The title rules run against the issue title supplied with --title "..."; the block rules run against the issue body.

The GitHub Action

.github/workflows/issues.yml
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 choice oneChecked exactLabels block for severity if reporters must choose exactly one impact level.
  • Use separate contracts per issue template when bugs, feature requests, and support requests need different sections.

On this page