From 659af6a0bac6c8eb9475e94e9deee1cfb097a16c Mon Sep 17 00:00:00 2001 From: Hampus Date: Thu, 2 Jul 2026 07:07:40 +0200 Subject: [PATCH] ci: lock closed discussions --- .../workflows/lock-closed-conversations.yaml | 128 +++++++++++++++++- 1 file changed, 127 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lock-closed-conversations.yaml b/.github/workflows/lock-closed-conversations.yaml index d97340d6d..dc869c956 100644 --- a/.github/workflows/lock-closed-conversations.yaml +++ b/.github/workflows/lock-closed-conversations.yaml @@ -7,6 +7,7 @@ on: pull_request_target: types: - closed + discussion: workflow_dispatch: inputs: dry_run: @@ -21,7 +22,7 @@ on: permissions: {} concurrency: - group: lock-closed-conversations-${{ github.event.issue.number || github.event.pull_request.number || github.run_id }} + group: lock-closed-conversations-${{ github.event.issue.number || github.event.pull_request.number || github.event.discussion.number || github.run_id }} cancel-in-progress: false jobs: @@ -38,6 +39,7 @@ jobs: private-key: ${{ secrets.FLUXER_CI_APP_KEY }} owner: fluxerapp repositories: fluxer + permission-discussions: write permission-issues: write permission-pull-requests: write @@ -47,6 +49,75 @@ jobs: run: | set -euo pipefail + lock_discussion() { + local discussion_id="$1" + + gh api graphql \ + -f id="$discussion_id" \ + -f query=" + mutation(\$id: ID!) { + lockLockable(input: {lockableId: \$id, lockReason: RESOLVED}) { + lockedRecord { + locked + } + } + } + " \ + --silent + } + + owner="${GITHUB_REPOSITORY%/*}" + repository="${GITHUB_REPOSITORY#*/}" + + if [ "$GITHUB_EVENT_NAME" = "discussion" ]; then + number="$(jq -r '.discussion.number // empty' "$GITHUB_EVENT_PATH")" + if [ -z "$number" ]; then + echo "Skipping discussion event; discussion number is unavailable." + exit 0 + fi + + sleep 10 + + discussion="$( + gh api graphql \ + -F owner="$owner" \ + -F name="$repository" \ + -F number="$number" \ + -f query=" + query(\$owner: String!, \$name: String!, \$number: Int!) { + repository(owner: \$owner, name: \$name) { + discussion(number: \$number) { + id + closed + locked + } + } + } + " + )" + discussion_id="$(jq -r '.data.repository.discussion.id // empty' <<<"$discussion")" + closed="$(jq -r '.data.repository.discussion.closed // empty' <<<"$discussion")" + locked="$(jq -r '.data.repository.discussion.locked // empty' <<<"$discussion")" + + if [ -z "$discussion_id" ]; then + echo "Skipping discussion #${number}; discussion is unavailable." + exit 0 + fi + + if [ "$closed" != "true" ]; then + echo "Skipping discussion #${number}; discussion is not closed." + exit 0 + fi + + if [ "$locked" = "true" ]; then + echo "Skipping discussion #${number}; conversation is already locked." + exit 0 + fi + + lock_discussion "$discussion_id" + exit 0 + fi + number="$(jq -r '.issue.number // .pull_request.number' "$GITHUB_EVENT_PATH")" sleep 10 @@ -82,6 +153,7 @@ jobs: private-key: ${{ secrets.FLUXER_CI_APP_KEY }} owner: fluxerapp repositories: fluxer + permission-discussions: write permission-issues: write permission-pull-requests: write @@ -92,6 +164,26 @@ jobs: run: | set -euo pipefail + lock_discussion() { + local discussion_id="$1" + + gh api graphql \ + -f id="$discussion_id" \ + -f query=" + mutation(\$id: ID!) { + lockLockable(input: {lockableId: \$id, lockReason: RESOLVED}) { + lockedRecord { + locked + } + } + } + " \ + --silent + } + + owner="${GITHUB_REPOSITORY%/*}" + repository="${GITHUB_REPOSITORY#*/}" + count=0 while IFS=$'\t' read -r number kind; do count=$((count + 1)) @@ -112,6 +204,40 @@ jobs: --jq '.[] | select(.locked == false) | [.number, (if has("pull_request") then "pull request" else "issue" end)] | @tsv' ) + while IFS=$'\t' read -r discussion_id number; do + count=$((count + 1)) + + if [ "$DRY_RUN" = "true" ]; then + echo "Would lock discussion #${number} as resolved." + continue + fi + + echo "Locking discussion #${number} as resolved." + lock_discussion "$discussion_id" + done < <( + gh api graphql --paginate \ + -F owner="$owner" \ + -F name="$repository" \ + -f query=" + query(\$owner: String!, \$name: String!, \$endCursor: String) { + repository(owner: \$owner, name: \$name) { + discussions(first: 100, after: \$endCursor, states: CLOSED, orderBy: {field: UPDATED_AT, direction: DESC}) { + nodes { + id + number + locked + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + " \ + --jq '.data.repository.discussions.nodes[] | select(.locked == false) | [.id, .number] | @tsv' + ) + if [ "$count" -eq 0 ]; then echo "No unlocked closed conversations found." fi