validate-new-issue.yml 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. name: Validate new issue
  2. on:
  3. issues:
  4. types: ["opened"]
  5. jobs:
  6. validate-new-issue:
  7. runs-on: ubuntu-latest
  8. steps:
  9. - uses: actions/checkout@v2
  10. - name: "Validate new issue"
  11. shell: bash
  12. env:
  13. GITHUB_TOKEN: ${{ github.token }}
  14. run: |
  15. issue_number=${{ github.event.issue.number }}
  16. echo "Validating issue #${issue_number}."
  17. # Trust users who belong to the getsentry org.
  18. if gh api "https://api.github.com/orgs/getsentry/members/${{ github.actor }}" >/dev/null 2>&1; then
  19. echo "Skipping validation, because ${{ github.actor }} is a member of the getsentry org."
  20. exit 0
  21. else
  22. echo "${{ github.actor }} is not a member of the getsentry org. 🧐"
  23. fi
  24. # Prep reasons for error message comment.
  25. REASON="your issue does not properly use one of this repo's available issue templates"
  26. REASON_EXACT_MATCH="you created an issue from a template without filling in anything"
  27. REASON_EMPTY="you created an empty issue"
  28. # Definition of valid:
  29. # - not empty (ignoring whitespace)
  30. # - matches a template
  31. # - all the headings are also in this issue
  32. # - extra headings in the issue are fine
  33. # - order doesn't matter
  34. # - case-sensitive tho
  35. # - not an *exact* match for a template (ignoring whitespace)
  36. function extract-headings { { sed 's/\r$//' "$1" | grep '^#' || echo -n ''; } | sort; }
  37. jq -r .issue.body "$GITHUB_EVENT_PATH" > issue
  38. if ! grep -q '[^[:space:]]' issue; then
  39. REASON="${REASON_EMPTY}"
  40. else
  41. extract-headings <(cat issue) > headings-in-issue
  42. for template in $(ls .github/ISSUE_TEMPLATE/*.md 2> /dev/null); do
  43. # Strip front matter. https://stackoverflow.com/a/29292490/14946704
  44. sed -i'' '1{/^---$/!q;};1,/^---$/d' "$template"
  45. extract-headings "$template" > headings-in-template
  46. echo -n "$(basename $template)? "
  47. if [ ! -s headings-in-template ]; then
  48. echo "No headers in template. 🤷"
  49. elif [ -z "$(comm -23 headings-in-template headings-in-issue)" ]; then
  50. echo "Match! 👍 💃"
  51. if diff -Bw "$template" issue > /dev/null; then
  52. echo "... like, an /exact/ match. 😖"
  53. REASON="${REASON_EXACT_MATCH}"
  54. break
  55. else
  56. gh api "/repos/:owner/:repo/issues/${issue_number}/labels" \
  57. -X POST \
  58. --input <(echo '{"labels":["Status: Unrouted"]}')
  59. exit 0
  60. fi
  61. else
  62. echo "No match. 👎"
  63. fi
  64. done
  65. fi
  66. # Failed validation! Close the issue with a comment.
  67. cat << EOF > comment
  68. Sorry, friend. As far as this ol' bot can tell, ${REASON}. Please [try again](https://github.com/${{ github.repository }}/issues/new/choose), if you like. (And if I'm confused, please [let us know](https://github.com/getsentry/.github/issues/new?title=template+enforcer+is+confused&body=${{ github.event.issue.html_url }}). 😬)
  69. ----
  70. [![Did you see the memo about this?](https://user-images.githubusercontent.com/134455/104515469-e04a9c80-55c0-11eb-8e15-ffe9c0b8dd7f.gif)](https://www.youtube.com/watch?v=Fy3rjQGc6lA)
  71. ([log](https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}))
  72. EOF
  73. echo -n "Commented: "
  74. gh issue comment ${{ github.event.issue.number }} --body "$(cat comment)"
  75. gh issue close ${{ github.event.issue.number }}
  76. echo "Closed with: \"${REASON}.\""