Skip to content

Instantly share code, notes, and snippets.

@huozhi
Last active February 6, 2026 12:38
Show Gist options
  • Select an option

  • Save huozhi/7285c7f0de4456dd2d47ea5bd0da32a6 to your computer and use it in GitHub Desktop.

Select an option

Save huozhi/7285c7f0de4456dd2d47ea5bd0da32a6 to your computer and use it in GitHub Desktop.
copy github pr or issue link to slack
#!/bin/bash
# gh-slack: Generate Slack-formatted links from GitHub PR/issue URLs
# Usage: gh-slack <github-url>
set -e
# Escape special characters for Slack mrkdwn
escape_slack() {
local s="$1"
s="${s//&/&amp;}"
s="${s//</&lt;}"
s="${s//>/&gt;}"
echo "$s"
}
# State to emoji mapping
state_emoji() {
local state="$1"
case "$state" in
draft)
echo ":pr-draft:"
;;
merged)
echo ":merge:"
;;
closed)
echo ":closed:"
;;
open|*)
echo ":pr:"
;;
esac
}
# Parse GitHub URL to extract owner, repo, type (pull/issues), and number
parse_github_url() {
local url="$1"
# Remove trailing slash if present
url="${url%/}"
# Match patterns like:
# https://github.com/owner/repo/pull/123
# https://github.com/owner/repo/issues/123
if [[ "$url" =~ github\.com/([^/]+)/([^/]+)/(pull|issues)/([0-9]+) ]]; then
OWNER="${BASH_REMATCH[1]}"
REPO="${BASH_REMATCH[2]}"
TYPE="${BASH_REMATCH[3]}"
NUMBER="${BASH_REMATCH[4]}"
return 0
fi
return 1
}
# Fetch PR info using gh CLI (returns tab-separated: title, state, isDraft)
fetch_pr_info() {
local owner="$1"
local repo="$2"
local number="$3"
gh pr view "$number" --repo "$owner/$repo" --json title,state,isDraft --jq '[.title, .state, .isDraft] | @tsv' 2>/dev/null
}
# Fetch issue info using gh CLI (returns tab-separated: title, state)
fetch_issue_info() {
local owner="$1"
local repo="$2"
local number="$3"
gh issue view "$number" --repo "$owner/$repo" --json title,state --jq '[.title, .state] | @tsv' 2>/dev/null
}
# Main function
main() {
local url="$1"
if [[ -z "$url" ]]; then
echo "Usage: gh-slack <github-pr-or-issue-url>" >&2
echo "" >&2
echo "Examples:" >&2
echo " gh-slack https://github.com/owner/repo/pull/123" >&2
echo " gh-slack https://github.com/owner/repo/issues/456" >&2
exit 1
fi
# Check if gh CLI is available
if ! command -v gh &> /dev/null; then
echo "Error: gh CLI is not installed. Please install it first:" >&2
echo " brew install gh" >&2
exit 1
fi
# Parse the URL
if ! parse_github_url "$url"; then
echo "Error: Invalid GitHub URL. Expected format:" >&2
echo " https://github.com/owner/repo/pull/123" >&2
echo " https://github.com/owner/repo/issues/123" >&2
exit 1
fi
local title=""
local state=""
local emoji=""
if [[ "$TYPE" == "pull" ]]; then
# Fetch PR info (tab-separated: title, state, isDraft)
local pr_info
pr_info=$(fetch_pr_info "$OWNER" "$REPO" "$NUMBER")
if [[ -z "$pr_info" ]]; then
echo "Error: Could not fetch PR #$NUMBER from $OWNER/$REPO" >&2
exit 1
fi
local pr_state is_draft
IFS=$'\t' read -r title pr_state is_draft <<< "$pr_info"
# Determine state
if [[ "$is_draft" == "true" ]]; then
state="draft"
elif [[ "$pr_state" == "MERGED" ]]; then
state="merged"
elif [[ "$pr_state" == "CLOSED" ]]; then
state="closed"
else
state="open"
fi
else
# Fetch issue info (tab-separated: title, state)
local issue_info
issue_info=$(fetch_issue_info "$OWNER" "$REPO" "$NUMBER")
if [[ -z "$issue_info" ]]; then
echo "Error: Could not fetch issue #$NUMBER from $OWNER/$REPO" >&2
exit 1
fi
local issue_state
IFS=$'\t' read -r title issue_state <<< "$issue_info"
if [[ "$issue_state" == "CLOSED" ]]; then
state="closed"
else
state="open"
fi
fi
# Get emoji for state
emoji=$(state_emoji "$state")
# Escape title for HTML
local escaped_title
escaped_title=$(escape_slack "$title")
# Generate HTML link (for rich text clipboard)
local html_link="$emoji <a href=\"$url\">$escaped_title</a>"
# Generate plain text fallback
local plain_link="$emoji $title — $url"
# Output the plain version
echo "$plain_link"
# Try to copy rich text (HTML) to clipboard on macOS
if [[ "$(uname)" == "Darwin" ]]; then
# Use hexdump approach for reliable HTML clipboard on macOS
local hex_html
hex_html=$(echo -n "$html_link" | hexdump -ve '1/1 "%.2x"')
osascript <<EOF
set the clipboard to {«class HTML»:«data HTML${hex_html}», string:"${plain_link//\"/\\\"}"}
EOF
if [[ $? -ne 0 ]]; then
echo -n "$plain_link" | pbcopy
fi
elif command -v xclip &> /dev/null; then
echo -n "$plain_link" | xclip -selection clipboard
fi
}
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment