Skip to content

Commit 0fb84c0

Browse files
Copilotshenxianpeng
andcommitted
Implement GitHub user matching feature for issue #93
Co-authored-by: shenxianpeng <3353385+shenxianpeng@users.noreply.github.com>
1 parent e3634c3 commit 0fb84c0

File tree

1,989 files changed

+137
-330690
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

1,989 files changed

+137
-330690
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
venv/
22
.venv/
3+
test_env/

README.md

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ jobs:
5353
imperative: false
5454
job-summary: true
5555
pr-comments: ${{ github.event_name == 'pull_request' }}
56+
author-name-match-github: false
57+
author-email-match-github: false
5658
```
5759
5860
## Used By
@@ -138,6 +140,21 @@ jobs:
138140
> `pr-comments` is an experimental feature. By default, it's disabled. To use it, you need to set `GITHUB_TOKEN` in the GitHub Action.
139141
>
140142
> This feature currently doesn’t work with forked repositories. For more details, refer to issue [#77](https://github.com/commit-check/commit-check-action/issues/77).
143+
### `author-name-match-github`
144+
145+
- **Description**: check if committer name matches GitHub user profile.
146+
- Default: `false`
147+
148+
> [!IMPORTANT]
149+
> `author-name-match-github` requires `GITHUB_TOKEN` to be set in the GitHub Action to access the GitHub API.
150+
151+
### `author-email-match-github`
152+
153+
- **Description**: check if committer email matches GitHub user profile.
154+
- Default: `false`
155+
156+
> [!IMPORTANT]
157+
> `author-email-match-github` requires `GITHUB_TOKEN` to be set in the GitHub Action to access the GitHub API.
141158

142159
Note: the default rule of above inputs is following [this configuration](https://github.com/commit-check/commit-check/blob/main/.commit-check.yml). If you want to customize, just add your `.commit-check.yml` config file under your repository root directory.
143160

__pycache__/main.cpython-312.pyc

12.3 KB
Binary file not shown.

action.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,14 @@ inputs:
4545
description: post results to the pull request comments
4646
required: false
4747
default: false
48+
author-name-match-github:
49+
description: check if committer name matches GitHub user profile
50+
required: false
51+
default: false
52+
author-email-match-github:
53+
description: check if committer email matches GitHub user profile
54+
required: false
55+
default: false
4856
runs:
4957
using: "composite"
5058
steps:
@@ -84,3 +92,5 @@ runs:
8492
DRY_RUN: ${{ inputs.dry-run }}
8593
JOB_SUMMARY: ${{ inputs.job-summary }}
8694
PR_COMMENTS: ${{ inputs.pr-comments }}
95+
AUTHOR_NAME_MATCH_GITHUB: ${{ inputs.author-name-match-github }}
96+
AUTHOR_EMAIL_MATCH_GITHUB: ${{ inputs.author-email-match-github }}

main.py

Lines changed: 109 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
DRY_RUN = os.getenv("DRY_RUN", "false")
2222
JOB_SUMMARY = os.getenv("JOB_SUMMARY", "false")
2323
PR_COMMENTS = os.getenv("PR_COMMENTS", "false")
24+
AUTHOR_NAME_MATCH_GITHUB = os.getenv("AUTHOR_NAME_MATCH_GITHUB", "false")
25+
AUTHOR_EMAIL_MATCH_GITHUB = os.getenv("AUTHOR_EMAIL_MATCH_GITHUB", "false")
2426
GITHUB_STEP_SUMMARY = os.environ["GITHUB_STEP_SUMMARY"]
2527
GITHUB_TOKEN = os.getenv("GITHUB_TOKEN")
2628
GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY")
@@ -38,7 +40,9 @@ def log_env_vars():
3840
print(f"IMPERATIVE = {IMPERATIVE}")
3941
print(f"DRY_RUN = {DRY_RUN}")
4042
print(f"JOB_SUMMARY = {JOB_SUMMARY}")
41-
print(f"PR_COMMENTS = {PR_COMMENTS}\n")
43+
print(f"PR_COMMENTS = {PR_COMMENTS}")
44+
print(f"AUTHOR_NAME_MATCH_GITHUB = {AUTHOR_NAME_MATCH_GITHUB}")
45+
print(f"AUTHOR_EMAIL_MATCH_GITHUB = {AUTHOR_EMAIL_MATCH_GITHUB}\n")
4246

4347

4448
def run_commit_check() -> int:
@@ -80,13 +84,26 @@ def run_commit_check() -> int:
8084

8185
def read_result_file() -> str | None:
8286
"""Reads the result.txt file and removes ANSI color codes."""
83-
if os.path.getsize("result.txt") > 0:
87+
result_content = ""
88+
89+
# Read commit-check results
90+
if os.path.exists("result.txt") and os.path.getsize("result.txt") > 0:
8491
with open("result.txt", "r") as result_file:
85-
result_text = re.sub(
92+
commit_check_result = re.sub(
8693
r"\x1B\[[0-9;]*[a-zA-Z]", "", result_file.read()
8794
) # Remove ANSI colors
88-
return result_text.rstrip()
89-
return None
95+
result_content += commit_check_result.rstrip()
96+
97+
# Read GitHub user check results
98+
if os.path.exists("github_user_check_result.txt") and os.path.getsize("github_user_check_result.txt") > 0:
99+
with open("github_user_check_result.txt", "r") as github_result_file:
100+
github_check_result = github_result_file.read().rstrip()
101+
if result_content:
102+
result_content += "\n\n" + github_check_result
103+
else:
104+
result_content = github_check_result
105+
106+
return result_content if result_content else None
90107

91108

92109
def add_job_summary() -> int:
@@ -174,6 +191,92 @@ def add_pr_comments() -> int:
174191
return 1
175192

176193

194+
def get_git_committer_info() -> tuple[str, str]:
195+
"""Gets the committer name and email from the latest commit."""
196+
try:
197+
# Get committer name
198+
name_result = subprocess.run(
199+
["git", "log", "-1", "--pretty=format:%cn"],
200+
capture_output=True,
201+
text=True,
202+
check=True
203+
)
204+
committer_name = name_result.stdout.strip()
205+
206+
# Get committer email
207+
email_result = subprocess.run(
208+
["git", "log", "-1", "--pretty=format:%ce"],
209+
capture_output=True,
210+
text=True,
211+
check=True
212+
)
213+
committer_email = email_result.stdout.strip()
214+
215+
return committer_name, committer_email
216+
except subprocess.CalledProcessError as e:
217+
print(f"Error getting git committer info: {e}", file=sys.stderr)
218+
return "", ""
219+
220+
221+
def check_github_user_match() -> int:
222+
"""Checks if committer name and email match GitHub user profile."""
223+
if AUTHOR_NAME_MATCH_GITHUB == "false" and AUTHOR_EMAIL_MATCH_GITHUB == "false":
224+
return 0
225+
226+
try:
227+
token = os.getenv("GITHUB_TOKEN")
228+
if not token:
229+
print("Error: GITHUB_TOKEN is required for GitHub user matching checks", file=sys.stderr)
230+
return 1
231+
232+
# Get committer info from git
233+
committer_name, committer_email = get_git_committer_info()
234+
if not committer_name and not committer_email:
235+
print("Error: Could not retrieve git committer information", file=sys.stderr)
236+
return 1
237+
238+
# Initialize GitHub client
239+
g = Github(token)
240+
user = g.get_user()
241+
242+
errors = []
243+
244+
# Check name if enabled
245+
if AUTHOR_NAME_MATCH_GITHUB == "true":
246+
github_name = user.name or ""
247+
if committer_name != github_name:
248+
errors.append(f"Committer name '{committer_name}' does not match GitHub user name '{github_name}'")
249+
250+
# Check email if enabled
251+
if AUTHOR_EMAIL_MATCH_GITHUB == "true":
252+
github_email = user.email or ""
253+
# Also check against public emails if primary email is private
254+
if committer_email != github_email:
255+
# Check public emails
256+
try:
257+
public_emails = [email.email for email in user.get_emails() if email.verified]
258+
if committer_email not in public_emails:
259+
errors.append(f"Committer email '{committer_email}' does not match any verified GitHub user email")
260+
except Exception:
261+
# If we can't access emails (permissions issue), just check the primary
262+
errors.append(f"Committer email '{committer_email}' does not match GitHub user email '{github_email}'")
263+
264+
if errors:
265+
# Write errors to result file
266+
with open("github_user_check_result.txt", "w") as result_file:
267+
for error in errors:
268+
result_file.write(f"❌ {error}\n")
269+
return 1
270+
271+
return 0
272+
273+
except Exception as e:
274+
print(f"Error checking GitHub user match: {e}", file=sys.stderr)
275+
with open("github_user_check_result.txt", "w") as result_file:
276+
result_file.write(f"❌ Error checking GitHub user match: {e}\n")
277+
return 1
278+
279+
177280
def log_error_and_exit(
178281
failure_title: str, result_text: str | None, ret_code: int
179282
) -> None:
@@ -197,6 +300,7 @@ def main():
197300

198301
# Combine return codes
199302
ret_code = run_commit_check()
303+
ret_code += check_github_user_match()
200304
ret_code += add_job_summary()
201305
ret_code += add_pr_comments()
202306

0 commit comments

Comments
 (0)