hari-huynh commited on
Commit
2848eac
·
2 Parent(s): 04417e3 c8d1c48

Merge branch 'main' of https://huggingface.co/spaces/haihuynh/pr-webhook

Browse files
Files changed (1) hide show
  1. DIFF.md +0 -313
DIFF.md DELETED
@@ -1,313 +0,0 @@
1
- diff --git a/.env b/.env
2
- new file mode 100644
3
- index 0000000..a392d55
4
- --- /dev/null
5
- +++ b/.env
6
- @@ -0,0 +1,3 @@
7
- +WORKSPACE_ID=thuantran_smulie
8
-
9
- diff --git a/.gitignore b/.gitignore
10
- index b24d71e..1a2f934 100644
11
- --- a/.gitignore
12
- +++ b/.gitignore
13
- @@ -48,3 +48,4 @@ Thumbs.db
14
- *.mov
15
- *.wmv
16
-
17
- +.env
18
-
19
- diff --git a/PR.md b/PR.md
20
- new file mode 100644
21
- index 0000000..8416126
22
- --- /dev/null
23
- +++ b/PR.md
24
- @@ -0,0 +1,20 @@
25
- +
26
- +# [pr-code-review] PR #2: Upload change in README.md
27
- +*Change documentation in README.md file*
28
- +
29
- +**🌿 Branch Information:**
30
- +- **Source Branch:** feature/pull-request → **Target Branch:** main
31
- +
32
- +**👤 Người tạo:** Hai Huynh
33
- +
34
- +**📅 Thời gian tạo:** 2024-08-20 14:30:00 +07:00
35
- +
36
- +**👥 Reviewers:**
37
- +None
38
- +
39
- +**🔗 Link Pull Request:** [PR #2: Implement user authentication system](https://bitbucket.org/thuantran_smulie/pr-code-review/pull-requests/2)
40
- +
41
- +---
42
- +
43
- +## 📝 Changelogs:
44
- +
45
-
46
- diff --git a/README.md b/README.md
47
- index c0a0828..f32c700 100644
48
- --- a/README.md
49
- +++ b/README.md
50
- @@ -1 +1,3 @@
51
- -Trigger khi có PR được tạo/thay đổi và gửi tin nhắn về Slack
52
-
53
- +Trigger khi có PR được tạo/thay đổi và gửi tin nhắn về Slack
54
- +Review code và gửi thông tin về Slack
55
- +Gửi báo cáo về Slack
56
- diff --git a/bitbucket-pipelines.yml b/bitbucket-pipelines.yml
57
- index 35d5eb0..7206a5e 100644
58
- --- a/bitbucket-pipelines.yml
59
- +++ b/bitbucket-pipelines.yml
60
- @@ -4,6 +4,42 @@ pipelines:
61
- - step:
62
- name: Build & Test on PR
63
- script:
64
- - - echo "Running build for PR"
65
- - - npm install
66
- - - npm test
67
- + - echo "=== PULL REQUEST INFORMATION ==="
68
- + - echo $BITBUCKET_PR_ID
69
- + - echo "=== BRANCH INFORMATION ==="
70
- + - echo $BITBUCKET_BRANCH
71
- + - echo $BITBUCKET_PR_DESTINATION_BRANCH
72
- + - echo "=== COMMIT INFORMATION ==="
73
- + - echo $BITBUCKET_COMMIT
74
- + - echo "=== REPOSITORY INFORMATION ==="
75
- + - echo $BITBUCKET_REPO_SLUG
76
- + - echo $BITBUCKET_REPO_UUID
77
- + - echo $BITBUCKET_WORKSPACE
78
- + - echo "=== PIPELINE INFORMATION ==="
79
- + - echo $BITBUCKET_PIPELINE_UUID
80
- + - echo $BITBUCKET_BUILD_NUMBER
81
- + - echo $BITBUCKET_STEP_UUID
82
- + - echo $BITBUCKET_STEP_NAME
83
- + - echo $BITBUCKET_STEP_RUN_NUMBER
84
- + - echo "=== ENVIRONMENT VARIABLES ==="
85
- + - echo "All PR-related environment variables:"
86
- + - env | grep BITBUCKET_PR
87
- + - echo "All Bitbucket environment variables:"
88
- + - env | grep BITBUCKET
89
- +
90
- + - step:
91
- + name: Run Python Script
92
- + image: python:3.11
93
- + script:
94
- + - pip install -r requirements.txt
95
- + - echo "=== RUNNING TOOL SCRIPT ==="
96
- +
97
- + - step:
98
- + name: Notify Slack
99
- + script:
100
- + - export MESSAGE="$(cat PR.md)"
101
- + - pipe: atlassian/slack-notify:2.3.1
102
- + variables:
103
- + WEBHOOK_URL: $SLACK_WEBHOOK_URL
104
- + MESSAGE: $MESSAGE
105
-
106
- diff --git a/requirements.txt b/requirements.txt
107
- new file mode 100644
108
- index 0000000..e6442c3
109
- --- /dev/null
110
- +++ b/requirements.txt
111
- @@ -0,0 +1,2 @@
112
- +dotenv
113
- +requests
114
-
115
- diff --git a/tool.py b/tool.py
116
- new file mode 100644
117
- index 0000000..8062704
118
- --- /dev/null
119
- +++ b/tool.py
120
- @@ -0,0 +1,201 @@
121
- +import os
122
- +import json
123
- +import argparse
124
- +from typing import Dict, Any, List, Optional, Tuple
125
- +from dotenv import load_dotenv
126
- +
127
- +import requests
128
- +
129
- +# Set up ENVIRONMENT VARIABLE
130
- +load_dotenv()
131
- +# WORKSPACE_ID = os.getenv("WORKSPACE_ID")
132
- +# BITBUCKET_USERNAME = os.getenv("BITBUCKET_USERNAME")
133
- +DEFAULT_BASE_URL = "https://api.bitbucket.org/2.0"
134
- +
135
- +
136
- +def create_session(username: Optional[str] = None, app_password: Optional[str] = None) -> requests.Session:
137
- + resolved_username = username or os.getenv("BITBUCKET_USERNAME")
138
- +
139
- + if not resolved_username or not resolved_app_password:
140
- + raise ValueError(
141
- + "Missing credentials. Provide --username and --app-password or set env vars "
142
- + )
143
- +
144
- + session = requests.Session()
145
- + session.auth = (resolved_username, resolved_app_password)
146
- + session.headers.update({"Accept": "application/json"})
147
- + return session
148
- +
149
- +
150
- +def _request_json(session: requests.Session, method: str, url: str, params: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
151
- + response = session.request(method, url, params=params, timeout=30)
152
- + response.raise_for_status()
153
- + return response.json()
154
- +
155
- +
156
- +def _paginate_all(session: requests.Session, url: str, params: Optional[Dict[str, Any]] = None) -> List[Dict[str, Any]]:
157
- + """
158
- + Retrieve all pages for Bitbucket v2.0 endpoints that return 'values' and 'next'.
159
- + """
160
- + aggregated_values: List[Dict[str, Any]] = []
161
- + next_url: Optional[str] = url
162
- + query_params: Dict[str, Any] = dict(params or {})
163
- + if "pagelen" not in query_params:
164
- + query_params["pagelen"] = 100
165
- +
166
- + while next_url:
167
- + data = _request_json(session, "GET", next_url, params=query_params if next_url == url else None)
168
- + values = data.get("values", [])
169
- + aggregated_values.extend(values)
170
- + next_url = data.get("next")
171
- + return aggregated_values
172
- +
173
- +
174
- +def get_pull_request_overview(session: requests.Session, workspace: str, repo_slug: str, pr_id: int, base_url: str = DEFAULT_BASE_URL) -> Dict[str, Any]:
175
- + url = f"{base_url}/repositories/{workspace}/{repo_slug}/pullrequests/{pr_id}"
176
- + return _request_json(session, "GET", url)
177
- +
178
- +
179
- +def get_pull_request_commits(session: requests.Session, workspace: str, repo_slug: str, pr_id: int, base_url: str = DEFAULT_BASE_URL) -> List[Dict[str, Any]]:
180
- + url = f"{base_url}/repositories/{workspace}/{repo_slug}/pullrequests/{pr_id}/commits"
181
- + return _paginate_all(session, url)
182
- +
183
- +
184
- +def get_pull_request_comments(session: requests.Session, workspace: str, repo_slug: str, pr_id: int, base_url: str = DEFAULT_BASE_URL) -> List[Dict[str, Any]]:
185
- + url = f"{base_url}/repositories/{workspace}/{repo_slug}/pullrequests/{pr_id}/comments"
186
- + return _paginate_all(session, url)
187
- +
188
- +
189
- +def get_pull_request_activity(session: requests.Session, workspace: str, repo_slug: str, pr_id: int, base_url: str = DEFAULT_BASE_URL) -> List[Dict[str, Any]]:
190
- + url = f"{base_url}/repositories/{workspace}/{repo_slug}/pullrequests/{pr_id}/activity"
191
- + return _paginate_all(session, url)
192
- +
193
- +
194
- +def get_pull_request_diff(session: requests.Session, workspace: str, repo_slug: str, pr_id: int, base_url: str = DEFAULT_BASE_URL) -> str:
195
- + """
196
- + Returns unified diff text for the PR. This endpoint returns text/plain.
197
- + """
198
- + url = f"{base_url}/repositories/{workspace}/{repo_slug}/pullrequests/{pr_id}/diff"
199
- + headers = {"Accept": "text/plain"}
200
- + response = session.get(url, headers=headers, timeout=60)
201
- + response.raise_for_status()
202
- + return response.text
203
- +
204
- +
205
- +def get_pull_request_full_data(
206
- + session: requests.Session,
207
- + workspace: str,
208
- + repo_slug: str,
209
- + pr_id: int,
210
- + include: Optional[List[str]] = None,
211
- + base_url: str = DEFAULT_BASE_URL,
212
- +) -> Dict[str, Any]:
213
- + """
214
- + Fetch a comprehensive view of a Bitbucket Cloud pull request:
215
- + - overview: PR metadata
216
- + - commits: all commits attached to the PR
217
- + - comments: all comments (including inline)
218
- + - activity: all activity events for the PR
219
- + - diff: unified diff text
220
- +
221
- + 'include' can limit which sections to fetch. Valid values: overview, commits, comments, activity, diff.
222
- + """
223
- + sections = ["overview", "commits", "comments", "activity", "diff"]
224
- +
225
- + result: Dict[str, Any] = {}
226
- +
227
- + if "overview" in sections:
228
- + result["overview"] = get_pull_request_overview(session, workspace, repo_slug, pr_id, base_url)
229
- + if "commits" in sections:
230
- + result["commits"] = get_pull_request_commits(session, workspace, repo_slug, pr_id, base_url)
231
- + if "comments" in sections:
232
- + result["comments"] = get_pull_request_comments(session, workspace, repo_slug, pr_id, base_url)
233
- + if "activity" in sections:
234
- + result["activity"] = get_pull_request_activity(session, workspace, repo_slug, pr_id, base_url)
235
- + if "diff" in sections:
236
- + result["diff"] = get_pull_request_diff(session, workspace, repo_slug, pr_id, base_url)
237
- +
238
- + return result
239
- +
240
- +
241
- +def save_md_report(filename, content):
242
- + with open(filename, "w", encoding="utf-8") as f:
243
- + f.write(content)
244
- + print(f"Saved {filename} file")
245
- +
246
- +def main() -> None:
247
- + parser = argparse.ArgumentParser(description="Fetch full details of a Bitbucket Cloud pull request.")
248
- + parser.add_argument("--username", required=True, help="Bitbucket username")
249
- + parser.add_argument("--password", required=True, help="Bitbucket app password")
250
- + parser.add_argument("--workspace", required=True, help="Bitbucket workspace ID or slug")
251
- + parser.add_argument("--repo", required=True, help="Repository slug")
252
- + parser.add_argument("--pr", required=True, type=int, help="Pull request ID")
253
- + # parser.add_argument("--username", help="Bitbucket username (or set BITBUCKET_USERNAME)")
254
- + # parser.add_argument(
255
- + # "--include",
256
- + # nargs="*",
257
- + # choices=["overview", "commits", "comments", "activity", "diff"],
258
- + # help="Sections to include. Default: all",
259
- + # )
260
- + # parser.add_argument("--base-url", default=DEFAULT_BASE_URL, help="Base API URL. Default is Bitbucket Cloud v2.0")
261
- + args = parser.parse_args()
262
- +
263
- + session = create_session(args.username, args.password)
264
- +
265
- + data = get_pull_request_overview(
266
- + session = session,
267
- + workspace = args.workspace,
268
- + repo_slug = args.repo,
269
- + pr_id = args.pr,
270
- + base_url = DEFAULT_BASE_URL
271
- + )
272
- +
273
- + # Lấy các thông tin cần thiết
274
- + title = data["title"]
275
- + description = data["description"]
276
- + source_branch = data["source"]["branch"]["name"]
277
- + destination_branch = data["destination"]["branch"]["name"]
278
- + author = data["author"]["display_name"]
279
- + created_on = data["created_on"]
280
- + reviewers = data.get("reviewers", [])
281
- + reviewer_mentions = " ".join([f"@{r.get('nickname')}" for r in reviewers]) if reviewers else "None"
282
- + pr_link = data["links"]["html"]["href"]
283
- + changelog = data["summary"]["raw"]
284
- +
285
- +
286
- + pr_report = f"""
287
- +# [{args.repo}] PR #{args.pr}: {title}
288
- +*{description}*
289
- +
290
- +**🌿 Branch Information:**
291
- +- **Source Branch:** {source_branch} → **Target Branch:** {destination_branch}
292
- +
293
- +**👤 Người tạo:** {author}
294
- +
295
- +**📅 Thời gian tạo:** 2024-08-20 14:30:00 +07:00
296
- +
297
- +**👥 Reviewers:**
298
- +{reviewer_mentions}
299
- +
300
- +**🔗 Link Pull Request:** [PR #{args.pr}: Implement user authentication system]({pr_link})
301
- +
302
- +---
303
- +
304
- +## 📝 Changelogs:
305
- + """
306
- +
307
- + save_md_report("PR.md", pr_report)
308
- +
309
- +
310
- +if __name__ == "__main__":
311
- + main()
312
- +
313
- +