on: issues: types: [edited] name: Close issues when the "ticked without reading" checkbox is checked permissions: issues: write jobs: detect-and-close: runs-on: ubuntu-latest steps: - name: Detect checked "ticked without reading" checkbox and close env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} OWNER: ${{ github.repository_owner }} REPO: ${{ github.event.repository.name }} ISSUE_NUMBER: ${{ github.event.issue.number }} ISSUE_BODY: ${{ toJson(github.event.issue.body) }} ISSUE_USER: ${{ github.event.issue.user.login }} run: | set -euo pipefail # Normalize the JSON-encoded body into plain text BODY=$(printf '%s' "$ISSUE_BODY" | sed -E 's/^"(.*)"$/\1/' | sed 's/\\"/"/g' | sed 's/\\n/\n/g') echo "Checking issue #${ISSUE_NUMBER} for the target checked checkbox..." # Match a checked markdown checkbox followed by the exact label text (case-insensitive). # Example matching line: "- [x] I've ticked the checkboxes without reading their contents" if printf '%s' "$BODY" | grep -Eiq '\[x\].*I'"'"'ve ticked the checkboxes without reading their contents'; then echo "Target checkbox is checked. Proceeding to comment and close the issue." # GraphQL query (single-line string to avoid YAML/heredoc quoting issues) QUERY='query($owner: String!, $name: String!, $number: Int!) { repository(owner: $owner, name: $name) { issue(number: $number) { id } } }' GET_ID_PAYLOAD=$(jq -n --arg q "$QUERY" --arg owner "$OWNER" --arg name "$REPO" --argjson number "$ISSUE_NUMBER" '{query:$q, variables:{owner:$owner, name:$name, number:$number}}') RES=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" -H "Content-Type: application/json" -d "$GET_ID_PAYLOAD" https://api.github.com/graphql) ISSUE_ID=$(printf '%s' "$RES" | jq -r '.data.repository.issue.id // empty') if [ -z "$ISSUE_ID" ]; then echo "Failed to get issue id from GraphQL response:" printf '%s\n' "$RES" exit 1 fi echo "Issue node id: $ISSUE_ID" # Prepare the comment body (English) and mention the issue author COMMENT_BODY="Hi @${ISSUE_USER} — I noticed you checked \"I've ticked the checkboxes without reading their contents\" in the issue template. To help others assist you effectively, please read the template and provide the requested diagnostic information (Step 2 & Step 3). I will close this issue now (stateReason=NOT_PLANNED). If you update the issue with the required information, we can re-evaluate. Thank you!" # addComment mutation MUT_ADD_COMMENT='mutation($id: ID!, $body: String!) { addComment(input: {subjectId: $id, body: $body}) { clientMutationId } }' ADD_COMMENT_PAYLOAD=$(jq -n --arg q "$MUT_ADD_COMMENT" --arg id "$ISSUE_ID" --arg body "$COMMENT_BODY" '{query:$q, variables:{id:$id, body:$body}}') RES_COMMENT=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" -H "Content-Type: application/json" -d "$ADD_COMMENT_PAYLOAD" https://api.github.com/graphql) ERR_COMMENT=$(printf '%s' "$RES_COMMENT" | jq -r '.errors[]?.message // empty') if [ -n "$ERR_COMMENT" ]; then echo "addComment error: $ERR_COMMENT" printf '%s\n' "$RES_COMMENT" exit 1 fi echo "Comment posted." # updateIssue mutation to close with NOT_PLANNED MUT_UPDATE_ISSUE='mutation($id: ID!) { updateIssue(input: {id: $id, state: CLOSED, stateReason: NOT_PLANNED}) { issue { number } } }' UPDATE_PAYLOAD=$(jq -n --arg q "$MUT_UPDATE_ISSUE" --arg id "$ISSUE_ID" '{query:$q, variables:{id:$id}}') RES_UPDATE=$(curl -s -H "Authorization: Bearer $GITHUB_TOKEN" -H "Content-Type: application/json" -d "$UPDATE_PAYLOAD" https://api.github.com/graphql) ERR_UPDATE=$(printf '%s' "$RES_UPDATE" | jq -r '.errors[]?.message // empty') if [ -n "$ERR_UPDATE" ]; then echo "updateIssue error: $ERR_UPDATE" printf '%s\n' "$RES_UPDATE" exit 1 fi echo "Issue closed with reason NOT_PLANNED." else echo "Checkbox not present/checked. Nothing to do." fi