Skip to content

Commit c5bfee2

Browse files
committed
chore: New PR announcement GH Action.
Add a new GH Action to announce to specific Slack channel every PR that is opened, reopened, and review_requested. Signed-off-by: Paulo Vital <paulo.vital@ibm.com>
1 parent b607941 commit c5bfee2

2 files changed

Lines changed: 192 additions & 0 deletions

File tree

Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
#!/usr/bin/env python3
2+
"""
3+
GitHub Actions script to send Slack notifications for new pull requests.
4+
"""
5+
6+
import os
7+
import sys
8+
from typing import Tuple
9+
10+
import httpx
11+
12+
13+
def send_slack_message(
14+
slack_webhook_service_id: str, slack_token: str, slack_channel_id: str, message: str
15+
) -> bool:
16+
"""Send a message to Slack channel."""
17+
18+
url = f"https://hooks.slack.com/services/T{slack_channel_id}/B{slack_webhook_service_id}/{slack_token}"
19+
20+
headers = {
21+
"Content-Type": "application/json",
22+
}
23+
24+
data = {"text": message}
25+
26+
try:
27+
with httpx.Client() as client:
28+
response = client.post(url, headers=headers, json=data)
29+
response.raise_for_status()
30+
31+
result = response.json()
32+
if result.get("ok"):
33+
print("✅ Slack message sent successfully")
34+
return True
35+
else:
36+
print(f"❌ Slack API error: {result.get('error', 'Unknown error')}")
37+
return False
38+
39+
except httpx.HTTPError as e:
40+
print(f"❌ Request error: {e}")
41+
return False
42+
43+
44+
def ensure_environment_variables_are_present() -> (
45+
Tuple[str, str, str, str, str, str, str, str]
46+
):
47+
"""
48+
Ensures that all necessary environment variables are present for the application to run.
49+
50+
This function checks for the presence of required environment variables related to Slack bot token,
51+
Pull Request (PR) details, and repository name. It also validates that the Slack channel is set.
52+
53+
Raises:
54+
SystemExit: If any of the required environment variables are missing.
55+
56+
Returns:
57+
A tuple containing the values of the following environment variables:
58+
- SLACK_BOT_TOKEN: The token for the Slack bot.
59+
- SLACK_CHANNEL: The Slack channel where notifications will be posted.
60+
- SLACK_SERVICE_ID: The ID of the Slack service.
61+
- PR_NUMBER: The number of the Pull Request.
62+
- PR_TITLE: The title of the Pull Request.
63+
- PR_URL: The URL of the Pull Request.
64+
- PR_AUTHOR: The author of the Pull Request.
65+
- REPO_NAME: The name of the repository.
66+
"""
67+
# Get environment variables
68+
slack_token = os.getenv("SLACK_BOT_TOKEN")
69+
slack_channel = os.getenv("SLACK_CHANNEL")
70+
slack_service_id = os.getenv("SLACK_SERVICE_ID")
71+
pr_number = os.getenv("PR_NUMBER")
72+
pr_title = os.getenv("PR_TITLE")
73+
pr_url = os.getenv("PR_URL")
74+
pr_author = os.getenv("PR_AUTHOR")
75+
repo_name = os.getenv("REPO_NAME")
76+
77+
# Validate required environment variables
78+
if not slack_token:
79+
print("❌ SLACK_BOT_TOKEN environment variable is required")
80+
sys.exit(1)
81+
82+
if not slack_channel:
83+
print("❌ SLACK_CHANNEL environment variable is required")
84+
sys.exit(1)
85+
86+
if not slack_service_id:
87+
print("❌ SLACK_SERVICE_ID environment variable is required")
88+
sys.exit(1)
89+
90+
if not all([pr_number, pr_title, pr_url, pr_author, repo_name]):
91+
print(
92+
"❌ Missing required PR information (PR_NUMBER, PR_TITLE, PR_URL, PR_AUTHOR, REPO_NAME)"
93+
)
94+
sys.exit(1)
95+
96+
# Since we're validating these variables, we can assert they're not None
97+
assert pr_number is not None
98+
assert pr_title is not None
99+
assert pr_url is not None
100+
assert pr_author is not None
101+
assert repo_name is not None
102+
103+
return (
104+
slack_token,
105+
slack_channel,
106+
slack_service_id,
107+
pr_number,
108+
pr_title,
109+
pr_url,
110+
pr_author,
111+
repo_name,
112+
)
113+
114+
115+
def main() -> None:
116+
"""Main function to process PR and send Slack notification."""
117+
118+
(
119+
slack_token,
120+
slack_channel,
121+
slack_service_id,
122+
pr_number,
123+
pr_title,
124+
pr_url,
125+
pr_author,
126+
repo_name,
127+
) = ensure_environment_variables_are_present()
128+
129+
print(f"Processing PR #{pr_number}")
130+
131+
# Create Slack message
132+
message = (
133+
f":mega: Oyez! Oyez! Oyez!\n"
134+
f"Hello Team. Please, review this opened PR #{pr_number} in {repo_name}\n"
135+
f"*{pr_title}* by @{pr_author}\n"
136+
f"pull-request-opened: {pr_url}"
137+
)
138+
139+
# Send to Slack
140+
success = send_slack_message(slack_service_id, slack_token, slack_channel, message)
141+
142+
if not success:
143+
sys.exit(1)
144+
145+
print("✅ Process completed successfully")
146+
147+
148+
if __name__ == "__main__":
149+
main()
150+
151+
# Made with Bob
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: PR Slack Notification
2+
3+
permissions:
4+
contents: read
5+
pull-requests: read
6+
7+
on:
8+
pull_request:
9+
types: [opened, reopened, review_requested]
10+
11+
jobs:
12+
notify-slack:
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- name: Checkout code
17+
uses: actions/checkout@v4
18+
with:
19+
fetch-depth: 0 # Fetch all history to access commit messages
20+
21+
- name: Set up Python
22+
uses: actions/setup-python@v4
23+
with:
24+
python-version: '3.13'
25+
26+
- name: Install dependencies
27+
run: |
28+
pip install httpx
29+
30+
- name: Send Slack notification
31+
env:
32+
SLACK_BOT_TOKEN: ${{ secrets.RUPY_PR_ANNOUNCEMENT_TOKEN }}
33+
SLACK_CHANNEL_ID_RELEASES: ${{ secrets.RUPY_PR_ANNOUNCEMENT_CHANNEL_ID }}
34+
SLACK_BOT_SERVICE_ID: ${{ secrets.RUPY_TOWN_CRIER_SERVICE_ID }}
35+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
36+
PR_NUMBER: ${{ github.event.number }}
37+
PR_TITLE: ${{ github.event.pull_request.title }}
38+
PR_URL: ${{ github.event.pull_request.html_url }}
39+
PR_AUTHOR: ${{ github.event.pull_request.user.login }}
40+
REPO_NAME: ${{ github.repository }}
41+
run: python .github/scripts/slack_notify.py

0 commit comments

Comments
 (0)