88 types : [opened, reopened, synchronize, closed]
99 release :
1010 types : [published]
11+ # uncomment if you also want issues events
12+ # issues:
13+ # types: [opened, reopened, closed, edited, labeled, unlabeled]
1114 workflow_dispatch :
1215 inputs :
1316 text :
1922 parse_mode :
2023 description : " Telegram parse mode (plain|MarkdownV2|HTML)"
2124 required : false
22- default : " plain "
25+ default : " HTML "
2326
2427concurrency :
2528 group : telegram-${{ github.ref }}-${{ github.event_name }}
2629 cancel-in-progress : false
2730
31+ permissions :
32+ contents : read
33+
2834jobs :
2935 notify :
3036 runs-on : ubuntu-latest
31- environment : SANDBOX
37+ environment : SANDBOX # uses TG_BOT_TOKEN and TG_CHAT_ID secrets
3238
3339 steps :
3440 - name : Check out (for commit list)
3541 uses : actions/checkout@v4
3642 with :
37- fetch-depth : 0
43+ fetch-depth : 50
3844
39- - name : Build message
45+ - name : Build message (HTML)
4046 id : msg
4147 shell : bash
4248 env :
@@ -60,52 +66,84 @@ jobs:
6066 REL_NAME : ${{ github.event.release.name }}
6167 REL_URL : ${{ github.event.release.html_url }}
6268
69+ ISSUE_NUM : ${{ github.event.issue.number }}
70+ ISSUE_TITLE : ${{ github.event.issue.title }}
71+ ISSUE_URL : ${{ github.event.issue.html_url }}
72+ ISSUE_ACTION : ${{ github.event.action }}
73+
6374 DISPATCH_TEXT : ${{ github.event.inputs.text }}
6475 run : |
6576 set -euo pipefail
6677
67- msg_header() {
68- printf '📣 %s\nRepo: %s\nBy: %s\nRef: %s\nRun: %s\n' \
69- "$1" "$REPO" "$ACTOR" "$REF_NAME" "$RUN_URL"
78+ # minimal HTML escaper for Telegram
79+ esc() { sed -e 's/&/\&/g' -e 's/</\</g' -e 's/>/\>/g'; }
80+
81+ header() {
82+ printf '<b>📣 %s</b>\nRepo: <a href="%s">%s</a>\nBy: %s\nRef: <code>%s</code>\nRun: <a href="%s">view run</a>\n\n' \
83+ "$(printf '%s' "$1" | esc)" "$REPO_URL" "$REPO" \
84+ "$(printf '%s' "$ACTOR" | esc)" "$(printf '%s' "$REF_NAME" | esc)" "$RUN_URL"
7085 }
7186
87+ MESSAGE=""
88+
7289 if [[ "$EVENT" == "workflow_dispatch" ]]; then
73- MESSAGE="$(msg_header "Manual notification")"$ '\n\n'" ${DISPATCH_TEXT:- }"
90+ MESSAGE="$(header "Manual notification")${DISPATCH_TEXT:+$ '\n' ${DISPATCH_TEXT} }"
7491
7592 elif [[ "$EVENT" == "push" ]]; then
7693 BEFORE="${GIT_BEFORE:-}"
7794 AFTER="$GIT_SHA"
78- if [[ -z "$BEFORE" || "$BEFORE" =~ ^0+$ ]]; then
79- COMMITS="$(git log --pretty=format:'- %s (%h) by %an' "$AFTER" -n 10 || true)"
95+ mapfile -t LINES < <(
96+ if [[ -z "$BEFORE" || "$BEFORE" =~ ^0+$ ]]; then
97+ git log -n 10 --pretty=format:'%s%x1f%h%x1f%an%x1f%H' "$AFTER" || true
98+ else
99+ git log --pretty=format:'%s%x1f%h%x1f%an%x1f%H' "$BEFORE..$AFTER" | head -n 10 || true
100+ fi
101+ )
102+ COMMITS_HTML=""
103+ if [[ ${#LINES[@]} -eq 0 ]]; then
104+ COMMITS_HTML="- (no commit messages found)"
80105 else
81- COMMITS="$(git log --pretty=format:'- %s (%h) by %an' "$BEFORE..$AFTER" | head -n 10 || true)"
106+ COMMIT_BASE="${REPO_URL}/commit"
107+ for row in "${LINES[@]}"; do
108+ IFS=$'\x1f' read -r subj short author full <<<"$row"
109+ subj_esc="$(printf '%s' "$subj" | esc)"
110+ author_esc="$(printf '%s' "$author" | esc)"
111+ COMMITS_HTML+="- <a href=\"${COMMIT_BASE}/${full}\">${subj_esc}</a> (<code>${short}</code>) by ${author_esc}\n"
112+ done
82113 fi
83- [[ -z "${COMMITS:-}" ]] && COMMITS="- (no commit messages found)"
84-
85- MESSAGE="$(msg_header "New push detected")"$'\n'"Last changes:"$'\n'"$COMMITS"$'\n\n'"Repo: $REPO_URL"
114+ MESSAGE="$(header "New push detected")Last changes:\n${COMMITS_HTML}\n\nRepo: <a href=\"${REPO_URL}\">${REPO_URL}</a>"
86115
87116 elif [[ "$EVENT" == "pull_request" ]]; then
88117 if [[ "$PR_ACTION" == "closed" ]]; then
89- if [[ "${PR_MERGED}" == "true" ]]; then
90- STATUS="PR merged ✅"
91- else
92- STATUS="PR closed ❌"
93- fi
118+ [[ "${PR_MERGED}" == "true" ]] && STATUS="PR merged ✅" || STATUS="PR closed ❌"
94119 else
95120 STATUS="PR updated ✏️"
96121 fi
97- MESSAGE="$(msg_header "$STATUS")"$'\n'" #${PR_NUMBER}: ${PR_TITLE}"$'\n'" ${PR_URL}"
122+ MESSAGE="$(header "$STATUS")#${PR_NUMBER}: $(printf '%s' "$PR_TITLE" | esc)\n ${PR_URL}"
98123
99124 elif [[ "$EVENT" == "release" ]]; then
100125 NAME="${REL_NAME:-$REL_TAG}"
101- MESSAGE="$(msg_header "Release published 🏷️")"$'\n'"Tag: ${REL_TAG}"$'\n'"Name: ${NAME}"$'\n'"${REL_URL}"
126+ MESSAGE="$(header "Release published 🏷️")Tag: $(printf '%s' "$REL_TAG" | esc)\nName: $(printf '%s' "$NAME" | esc)\n${REL_URL}"
127+
128+ elif [[ "$EVENT" == "issues" ]]; then
129+ TITLE_ESC="$(printf '%s' "$ISSUE_TITLE" | esc)"
130+ case "$ISSUE_ACTION" in
131+ opened) STATUS="Issue opened 🐞" ;;
132+ reopened) STATUS="Issue reopened ♻️" ;;
133+ closed) STATUS="Issue closed ✅" ;;
134+ edited) STATUS="Issue edited ✏️" ;;
135+ labeled) STATUS="Issue labeled 🏷️" ;;
136+ unlabeled)STATUS="Issue unlabeled 🏷️" ;;
137+ *) STATUS="Issue update 📌" ;;
138+ esac
139+ MESSAGE="$(header "$STATUS")#${ISSUE_NUM}: ${TITLE_ESC}\n${ISSUE_URL}"
102140
103141 else
104- MESSAGE="$(msg_header "Event: $EVENT")"
142+ MESSAGE="$(header "Event: $EVENT")"
105143 fi
106144
107145 {
108- echo "text<<' EOF' "
146+ echo "text<<EOF"
109147 echo "$MESSAGE"
110148 echo "EOF"
111149 } >> "$GITHUB_OUTPUT"
@@ -127,7 +165,7 @@ jobs:
127165 exit 1
128166 fi
129167
130- case "${PARSE_MODE:-plain }" in
168+ case "${PARSE_MODE:-HTML }" in
131169 MarkdownV2|HTML) PMODE="$PARSE_MODE" ;;
132170 *) PMODE="" ;;
133171 esac
@@ -142,7 +180,6 @@ jobs:
142180
143181 curl -sS -X POST "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMessage" \
144182 -H 'Content-Type: application/json' \
145- -d "$PAYLOAD" \
146- | jq -e '.ok == true' >/dev/null
183+ -d "$PAYLOAD" | jq -e '.ok == true' >/dev/null
147184
148185 echo "✅ Message sent to Telegram."
0 commit comments