Last active
June 6, 2025 07:29
-
-
Save indigoviolet/deed12de2e90fea05ecc39252ab9bb9e to your computer and use it in GitHub Desktop.
Label all issues in a repo that I'm subscribed to
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Script to find all issues in a repository that a user is subscribed to and add a label | |
# Check if gum is installed | |
if ! command -v gum &> /dev/null; then | |
echo "Error: gum is not installed. Install it with:" | |
echo " brew install gum" | |
echo " or visit: https://github.com/charmbracelet/gum" | |
exit 1 | |
fi | |
# Parse command line arguments | |
DRY_RUN=false | |
if [[ "$1" == "--dry-run" ]]; then | |
DRY_RUN=true | |
shift | |
fi | |
# Check if required arguments are provided | |
if [ $# -lt 3 ]; then | |
echo "Usage: $0 [--dry-run] <owner/repo> <username> <label>" | |
echo "Example: $0 octocat/hello-world octocat subscribed" | |
echo " $0 --dry-run octocat/hello-world octocat subscribed" | |
exit 1 | |
fi | |
REPO=$1 | |
USERNAME=$2 | |
LABEL=$3 | |
OWNER=$(echo $REPO | cut -d'/' -f1) | |
REPO_NAME=$(echo $REPO | cut -d'/' -f2) | |
# Display configuration | |
echo | |
gum style --foreground 212 --bold "GitHub Issue Tagger" | |
echo | |
gum style --foreground 240 "Repository: $REPO" | |
gum style --foreground 240 "Username: $USERNAME" | |
gum style --foreground 240 "Label: $LABEL" | |
if [ "$DRY_RUN" = "true" ]; then | |
gum style --foreground 220 "Mode: DRY RUN" | |
else | |
gum style --foreground 120 "Mode: LIVE" | |
fi | |
echo | |
# Check if the label exists (skip in dry-run mode) | |
if [ "$DRY_RUN" = "false" ]; then | |
echo "Checking if label exists..." | |
LABEL_CHECK=$(gh label list -R "$REPO" --limit 1000 --json name -q ".[].name" | grep -x "$LABEL" || echo "") | |
if [ -z "$LABEL_CHECK" ]; then | |
gum style --foreground 220 "Label '$LABEL' not found." | |
if gum confirm "Create it?"; then | |
echo "Creating label..." | |
gh label create "$LABEL" -R "$REPO" --color "0366d6" --description "User is subscribed to this issue" | |
gum style --foreground 120 "✓ Label created" | |
else | |
exit 1 | |
fi | |
else | |
gum style --foreground 120 "✓ Label exists" | |
fi | |
fi | |
# Get label ID | |
if [ "$DRY_RUN" = "false" ]; then | |
echo "Getting label ID..." | |
LABEL_ID=$(gh api "/repos/$REPO/labels/$LABEL" --jq '.node_id' 2>/dev/null) | |
if [ -z "$LABEL_ID" ]; then | |
# Try URL-encoding the label name | |
ENCODED_LABEL=$(echo -n "$LABEL" | jq -sRr @uri) | |
LABEL_ID=$(gh api "/repos/$REPO/labels/$ENCODED_LABEL" --jq '.node_id' 2>/dev/null) | |
fi | |
if [ -z "$LABEL_ID" ]; then | |
gum style --foreground 196 "Failed to get label ID" | |
gum style --foreground 240 "Trying alternate method..." | |
# Try using GraphQL as fallback | |
LABEL_ID=$(gh api graphql -f query='query($owner: String!, $repo: String!, $label: String!) { | |
repository(owner: $owner, name: $repo) { | |
label(name: $label) { | |
id | |
} | |
} | |
}' -f owner="$OWNER" -f repo="$REPO_NAME" -f label="$LABEL" --jq '.data.repository.label.id' 2>/dev/null) | |
if [ -z "$LABEL_ID" ]; then | |
gum style --foreground 196 "Still failed to get label ID" | |
exit 1 | |
fi | |
fi | |
gum style --foreground 120 "✓ Got label ID: ${LABEL_ID:0:20}..." | |
fi | |
# GraphQL query | |
QUERY='query($owner: String!, $repo: String!, $cursor: String) { | |
repository(owner: $owner, name: $repo) { | |
issues(first: 100, states: OPEN, after: $cursor) { | |
pageInfo { | |
hasNextPage | |
endCursor | |
} | |
nodes { | |
number | |
title | |
id | |
viewerSubscription | |
author { login } | |
assignees(first: 10) { nodes { login } } | |
participants(first: 50) { nodes { login } } | |
} | |
} | |
} | |
}' | |
# Arrays to store results | |
declare -a SUBSCRIBED_IDS | |
declare -a SUBSCRIBED_INFO | |
TOTAL=0 | |
CURSOR="" | |
HAS_MORE=true | |
# Fetch issues | |
echo "Scanning issues..." | |
while [ "$HAS_MORE" = "true" ]; do | |
echo -ne "\rProcessing issues... Total: $TOTAL" | |
if [ -z "$CURSOR" ]; then | |
RESPONSE=$(gh api graphql -f query="$QUERY" -f owner="$OWNER" -f repo="$REPO_NAME") | |
else | |
RESPONSE=$(gh api graphql -f query="$QUERY" -f owner="$OWNER" -f repo="$REPO_NAME" -f cursor="$CURSOR") | |
fi | |
# Parse response | |
HAS_MORE=$(echo "$RESPONSE" | jq -r '.data.repository.issues.pageInfo.hasNextPage') | |
CURSOR=$(echo "$RESPONSE" | jq -r '.data.repository.issues.pageInfo.endCursor') | |
# Process each issue | |
while IFS= read -r issue; do | |
NUMBER=$(echo "$issue" | jq -r '.number') | |
TITLE=$(echo "$issue" | jq -r '.title') | |
ID=$(echo "$issue" | jq -r '.id') | |
VIEWER_SUB=$(echo "$issue" | jq -r '.viewerSubscription') | |
AUTHOR=$(echo "$issue" | jq -r '.author.login // ""') | |
((TOTAL++)) | |
# Check if subscribed | |
IS_SUBSCRIBED=false | |
if [ "$VIEWER_SUB" = "SUBSCRIBED" ]; then | |
IS_SUBSCRIBED=true | |
elif [ "$AUTHOR" = "$USERNAME" ]; then | |
IS_SUBSCRIBED=true | |
else | |
# Check assignees | |
if echo "$issue" | jq -e ".assignees.nodes[] | select(.login == \"$USERNAME\")" >/dev/null 2>&1; then | |
IS_SUBSCRIBED=true | |
fi | |
# Check participants | |
if [ "$IS_SUBSCRIBED" = "false" ]; then | |
if echo "$issue" | jq -e ".participants.nodes[] | select(.login == \"$USERNAME\")" >/dev/null 2>&1; then | |
IS_SUBSCRIBED=true | |
fi | |
fi | |
fi | |
if [ "$IS_SUBSCRIBED" = "true" ]; then | |
SUBSCRIBED_IDS+=("$ID") | |
SUBSCRIBED_INFO+=("#$NUMBER: $TITLE") | |
fi | |
done < <(echo "$RESPONSE" | jq -c '.data.repository.issues.nodes[]') | |
done | |
echo # New line after progress | |
# Display results | |
echo | |
gum style --foreground 120 "Found ${#SUBSCRIBED_IDS[@]} subscribed issues out of $TOTAL total" | |
if [ ${#SUBSCRIBED_INFO[@]} -gt 0 ]; then | |
echo | |
for info in "${SUBSCRIBED_INFO[@]}"; do | |
gum style --foreground 240 " • $info" | |
done | |
fi | |
# Add labels | |
if [ ${#SUBSCRIBED_IDS[@]} -gt 0 ] && [ "$DRY_RUN" = "false" ]; then | |
echo | |
if gum confirm "Add label to ${#SUBSCRIBED_IDS[@]} issues?"; then | |
echo | |
SUCCESS=0 | |
for i in "${!SUBSCRIBED_IDS[@]}"; do | |
ID="${SUBSCRIBED_IDS[$i]}" | |
INFO="${SUBSCRIBED_INFO[$i]}" | |
MUTATION='mutation($id: ID!, $labelIds: [ID!]!) { | |
addLabelsToLabelable(input: {labelableId: $id, labelIds: $labelIds}) { | |
clientMutationId | |
} | |
}' | |
# Create the labelIds JSON array properly | |
if gh api graphql -f query="$MUTATION" -f id="$ID" -f "labelIds[]=$LABEL_ID" >/dev/null 2>&1; then | |
gum style --foreground 120 " ✓ Tagged: $INFO" | |
((SUCCESS++)) | |
else | |
# Try to debug the error | |
ERROR=$(gh api graphql -f query="$MUTATION" -f id="$ID" -f "labelIds[]=$LABEL_ID" 2>&1) | |
gum style --foreground 196 " ✗ Failed: $INFO" | |
if [[ "$ERROR" == *"was already present"* ]]; then | |
gum style --foreground 240 " (Label already exists on issue)" | |
fi | |
fi | |
done | |
echo | |
gum style --foreground 120 "Successfully tagged $SUCCESS issues" | |
fi | |
elif [ "$DRY_RUN" = "true" ] && [ ${#SUBSCRIBED_IDS[@]} -gt 0 ]; then | |
echo | |
gum style --foreground 220 "DRY RUN: Would tag ${#SUBSCRIBED_IDS[@]} issues" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment