1+ # .github/workflows/telegram-notifier.yml
12name : Telegram Notifier
23
34on :
89 types : [opened, reopened, synchronize, closed]
910 release :
1011 types : [published]
11- # issues:
12- # types: [opened, reopened, closed, edited, labeled, unlabeled]
1312 workflow_dispatch :
1413 inputs :
1514 text :
16- description : " Message to send to Telegram "
15+ description : " Message to send"
1716 required : true
17+ title :
18+ description : " Optional manual title (default: 📣 Manual)"
19+ required : false
20+ default : " 📣 Manual"
1821 chat_id :
19- description : " Optional: override TG_CHAT_ID (e.g. @Channel or numeric id)"
22+ description : " Override TG_CHAT_ID (e.g. @Channel or numeric id)"
2023 required : false
2124
25+ permissions :
26+ contents : read
27+
2228concurrency :
2329 group : telegram-${{ github.ref }}-${{ github.event_name }}
2430 cancel-in-progress : false
2531
26- permissions :
27- contents : read
28-
2932jobs :
3033 notify :
3134 runs-on : ubuntu-latest
32- environment : SANDBOX # TG_BOT_TOKEN + TG_CHAT_ID
35+ environment : SANDBOX # must contain secrets TG_BOT_TOKEN and TG_CHAT_ID
36+
3337 steps :
34- - name : Checkout (for commit list )
38+ - name : Checkout (for commit log )
3539 uses : actions/checkout@v4
3640 with :
3741 fetch-depth : 50
@@ -60,16 +64,12 @@ jobs:
6064 REL_NAME : ${{ github.event.release.name }}
6165 REL_URL : ${{ github.event.release.html_url }}
6266
63- ISSUE_NUM : ${{ github.event.issue.number }}
64- ISSUE_TITLE : ${{ github.event.issue.title }}
65- ISSUE_URL : ${{ github.event.issue.html_url }}
66- ISSUE_ACTION : ${{ github.event.action }}
67-
68- DISPATCH_TEXT : ${{ github.event.inputs.text }}
67+ WD_TEXT : ${{ github.event.inputs.text }}
68+ WD_TITLE : ${{ github.event.inputs.title }}
6969 run : |
7070 set -euo pipefail
7171
72- # MarkdownV2 escaper for Telegram
72+ # Telegram MarkdownV2 escaper
7373 mde() {
7474 sed -e 's/\\/\\\\/g' \
7575 -e 's/_/\\_/g' -e 's/*/\\*/g' -e 's/\[/\\[/g' -e 's/]/\\]/g' \
@@ -79,78 +79,63 @@ jobs:
7979 -e 's/\./\\./g' -e 's/!/\\!/g'
8080 }
8181
82- header_plain() { # shared header for non-manual events
83- printf '📣 %s\nRepo: %s\nBy: %s\nRef: %s\nRun: %s\n' \
84- "$(printf '%s' "$1")" "$REPO" "$ACTOR" "$REF_NAME" "$RUN_URL"
82+ header() {
83+ printf '%s\nRepo: %s\nBy: %s\nRef: %s\nRun: %s\n' \
84+ "$(printf '%s' "$1")" \
85+ "$(printf '%s' "$REPO" | mde)" \
86+ "$(printf '%s' "$ACTOR" | mde)" \
87+ "$(printf '%s' "$REF_NAME" | mde)" \
88+ "$(printf '%s' "$RUN_URL" | mde)"
8589 }
8690
8791 MESSAGE=""
8892
8993 if [[ "$EVENT" == "workflow_dispatch" ]]; then
90- # --- Minimal manual notification (what you asked) ---
91- # 📣 Manual
92- # By: <actor>
93- # Run: <url>
94- # <your message>
95- MSG_ESC="$(printf '%s' "${DISPATCH_TEXT:-}" | mde)"
96- HEADER="📣 Manual\nBy: $(printf '%s' "$ACTOR" | mde)\nRun: $(printf '%s' "$RUN_URL" | mde)\n\n"
97- MESSAGE="${HEADER}${MSG_ESC}"
94+ TITLE="${WD_TITLE:-📣 Manual}"
95+ # Minimal manual card: Title + By + Run + your text
96+ MESSAGE="$(header "$(printf '%s' "$TITLE" | mde)")"
97+ MSG_ESC="$(printf '%s' "${WD_TEXT:-}" | mde)"
98+ MESSAGE="${MESSAGE}\n${MSG_ESC}"
9899
99100 elif [[ "$EVENT" == "push" ]]; then
100101 BEFORE="${GIT_BEFORE:-}"
101102 AFTER="$GIT_SHA"
103+
102104 if [[ -z "$BEFORE" || "$BEFORE" =~ ^0+$ ]]; then
103- mapfile -t LINES < <(git log -n 10 --pretty=format:'%s%x1f%h%x1f%H ' "$AFTER" || true)
105+ mapfile -t LINES < <(git log -n 10 --pretty=format:'%s%x1f%h%x1f%an ' "$AFTER" || true)
104106 else
105- mapfile -t LINES < <(git log --pretty=format:'%s%x1f%h%x1f%H ' "$BEFORE..$AFTER" | head -n 10 || true)
107+ mapfile -t LINES < <(git log --pretty=format:'%s%x1f%h%x1f%an ' "$BEFORE..$AFTER" | head -n 10 || true)
106108 fi
107109
108110 COMMITS_TXT=""
109111 if [[ ${#LINES[@]} -eq 0 ]]; then
110112 COMMITS_TXT="- (no commit messages found)"
111113 else
112- ACTOR_URL="https://github.com/${ACTOR}"
113114 for row in "${LINES[@]}"; do
114- IFS=$'\x1f' read -r subj short full <<<"$row"
115- subj_esc="$(printf '%s' "$subj" | mde)"
116- COMMITS_TXT+="- ${subj_esc} (${short}) by $(printf '%s' "$ACTOR_URL" | mde)\n"
115+ IFS=$'\x1f' read -r subj short author <<<"$row"
116+ COMMITS_TXT+="- $(printf '%s' "$subj" | mde) ($(printf '%s' "$short" | mde)) by $(printf '%s' "$author" | mde)\n"
117117 done
118118 fi
119119
120- MESSAGE="$(header_plain 'Last 10 commits')"
121- MESSAGE="${MESSAGE}\n${COMMITS_TXT}\nRepo: ${REPO_URL}"
120+ MESSAGE="$(header '📣 Last 10 commits')\n${COMMITS_TXT}\nRepo: $(printf '%s' "$REPO_URL" | mde)"
122121
123122 elif [[ "$EVENT" == "pull_request" ]]; then
124123 if [[ "$PR_ACTION" == "closed" ]]; then
125124 [[ "${PR_MERGED}" == "true" ]] && STATUS="PR merged ✅" || STATUS="PR closed ❌"
126125 else
127126 STATUS="PR updated ✏️"
128127 fi
129- TITLE_ESC="$(printf '%s' "$PR_TITLE" | mde)"
130- MESSAGE="$(header_plain "$STATUS")\n#${PR_NUMBER}: ${TITLE_ESC}\n${PR_URL}"
128+ MESSAGE="$(header "$(printf '%s' "$STATUS" | mde)")\n#${PR_NUMBER}: $(printf '%s' "$PR_TITLE" | mde)\n$(printf '%s' "$PR_URL" | mde)"
131129
132130 elif [[ "$EVENT" == "release" ]]; then
133131 NAME="${REL_NAME:-$REL_TAG}"
134- MESSAGE="$(header_plain 'Release published 🏷️')\nTag: $(printf '%s' "$REL_TAG" | mde)\nName: $(printf '%s' "$NAME" | mde)\n${REL_URL}"
135-
136- elif [[ "$EVENT" == "issues" ]]; then
137- case "$ISSUE_ACTION" in
138- opened) STATUS="Issue opened 🐞" ;;
139- reopened) STATUS="Issue reopened ♻️" ;;
140- closed) STATUS="Issue closed ✅" ;;
141- edited) STATUS="Issue edited ✏️" ;;
142- labeled) STATUS="Issue labeled 🏷️" ;;
143- unlabeled)STATUS="Issue unlabeled 🏷️" ;;
144- *) STATUS="Issue update 📌" ;;
145- esac
146- TITLE_ESC="$(printf '%s' "$ISSUE_TITLE" | mde)"
147- MESSAGE="$(header_plain "$STATUS")\n#${ISSUE_NUM}: ${TITLE_ESC}\n${ISSUE_URL}"
132+ MESSAGE="$(header 'Release published 🏷️')\nTag: $(printf '%s' "$REL_TAG" | mde)\nName: $(printf '%s' "$NAME" | mde)\n$(printf '%s' "$REL_URL" | mde)"
148133
149134 else
150- MESSAGE="$(header_plain "Event: $EVENT")"
135+ MESSAGE="$(header "Event: $(printf '%s' "$ EVENT" | mde) ")"
151136 fi
152137
153- # write multi-line output safely
138+ # Safe multi-line output (no stray EOF problems)
154139 {
155140 printf 'text<<MSGEOF\n'
156141 printf '%s\n' "$MESSAGE"
@@ -169,7 +154,6 @@ jobs:
169154 CHAT_ID="${OVERRIDE_CHAT_ID:-$TG_CHAT_ID_DEFAULT}"
170155 [[ -n "${TG_BOT_TOKEN:-}" && -n "${CHAT_ID:-}" ]] || { echo "Missing TG secrets"; exit 1; }
171156
172- # Send as MarkdownV2 (we already escaped)
173157 curl -sS -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
174158 -H 'Content-Type: application/json' \
175159 -d "$(jq -n \
0 commit comments