diff --git a/.github/workflows/auto-close-issue.yml b/.github/workflows/auto-close-issue.yml new file mode 100644 index 000000000..e6bb394f8 --- /dev/null +++ b/.github/workflows/auto-close-issue.yml @@ -0,0 +1,104 @@ +on: + issues: + types: [edited] + +name: Close issues when the "ticked without reading" checkbox is checked + +permissions: + issues: write + +jobs: + detect-and-close: + name: Detect checkbox and close + runs-on: ubuntu-latest + steps: + - name: Check for the "ticked without reading" checkbox and close if present + 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: get the issue node id + read -r -d '' QUERY_GET_ID <<'GRAPHQL' +query($owner: String!, $name: String!, $number: Int!) { + repository(owner: $owner, name: $name) { + issue(number: $number) { + id + } + } +} +GRAPHQL + + GET_ID_PAYLOAD=$(jq -n --arg q "$QUERY_GET_ID" --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) and then reopen or resubmit the issue. 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 + read -r -d '' MUT_ADD_COMMENT <<'GRAPHQL' +mutation($id: ID!, $body: String!) { + addComment(input: {subjectId: $id, body: $body}) { + clientMutationId + } +} +GRAPHQL + + 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 + read -r -d '' MUT_UPDATE_ISSUE <<'GRAPHQL' +mutation($id: ID!) { + updateIssue(input: {id: $id, state: CLOSED, stateReason: NOT_PLANNED}) { + issue { + number + } + } +} +GRAPHQL + + 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