From 411cfca798a8f59f7af7ec30bac1e2584b68d16a Mon Sep 17 00:00:00 2001 From: Venu Vardhan Reddy Tekula Date: Wed, 4 Feb 2026 00:17:27 -0500 Subject: [PATCH 1/4] feat: add company column to contributor output Include the GitHub profile company in markdown and JSON, and update README examples. Signed-off-by: Venu Vardhan Reddy Tekula --- README.md | 12 ++++---- contributor_stats.py | 8 +++++ contributors.py | 2 ++ markdown.py | 13 ++++---- test_contributor_stats.py | 12 ++++++++ test_contributors.py | 12 ++++++++ test_json_writer.py | 2 ++ test_markdown.py | 63 +++++++++++++++++++++++---------------- 8 files changed, 86 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index 6426370..002ded4 100644 --- a/README.md +++ b/README.md @@ -236,9 +236,9 @@ jobs: | ------------------ | ------------------- | ------------------ | | 1 | 143 | 0% | -| Username | All Time Contribution Count | New Contributor | Commits between 2021-01-01 and 2023-10-10 | -| --------- | --------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| @zkoppert | 143 | False | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-01-01&until=2023-10-10) | +| Username | Company | All Time Contribution Count | New Contributor | Commits between 2021-01-01 and 2023-10-10 | +| --------- | -------- | --------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| @zkoppert | @github | 143 | False | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-01-01&until=2023-10-10) | ``` ## Example Markdown output with no dates supplied @@ -252,9 +252,9 @@ jobs: | ------------------ | ------------------- | ------------------ | | 1 | 1913 | 0% | -| Username | All Time Contribution Count | New Contributor | Sponsor URL | Commits between 2021-09-01 and 2023-09-30 | -| --------- | --------------------------- | --------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| @zkoppert | 1913 | False | [Sponsor Link](https://github.com/sponsors/zkoppert) | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-09-01&until=2023-09-30) | +| Username | Company | All Time Contribution Count | New Contributor | Sponsor URL | Commits between 2021-09-01 and 2023-09-30 | +| --------- | -------- | --------------------------- | --------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| @zkoppert | @github | 1913 | False | [Sponsor Link](https://github.com/sponsors/zkoppert) | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-09-01&until=2023-09-30) | ``` ## GitHub Actions Job Summary diff --git a/contributor_stats.py b/contributor_stats.py index 3b5b8c7..2f3c167 100644 --- a/contributor_stats.py +++ b/contributor_stats.py @@ -3,6 +3,7 @@ # [ # { # "username" : "zkoppert", +# "company" : "@github", # "new_contributor" : "False", # "avatar_url" : "https://avatars.githubusercontent.com/u/29484535?v=4", # "contribution_count" : 1261, @@ -23,6 +24,7 @@ class ContributorStats: Attributes: username (str): The username of the contributor + company (str): The company listed on the contributor's GitHub profile new_contributor (bool): Whether the contributor is new or returning avatar_url (str): The url of the contributor's avatar contribution_count (int): The number of contributions the contributor has made @@ -38,6 +40,7 @@ def __new__(cls, *args, **kwargs): # pylint: disable=unused-argument def __init__( self, username: str, + company: str, new_contributor: bool, avatar_url: str, contribution_count: int, @@ -47,6 +50,7 @@ def __init__( """Initialize the contributor_stats object""" new_contributor = False self.username = username + self.company = company self.new_contributor = new_contributor self.avatar_url = avatar_url self.contribution_count = contribution_count @@ -57,6 +61,7 @@ def __repr__(self) -> str: """Return the representation of the contributor_stats object""" return ( f"contributor_stats(username={self.username}, " + f"company={self.company}, " f"new_contributor={self.new_contributor}, " f"avatar_url={self.avatar_url}, " f"contribution_count={self.contribution_count}, " @@ -68,6 +73,7 @@ def __eq__(self, other) -> bool: """Check if two contributor_stats objects are equal""" return ( self.username == other.username + and self.company == other.company and self.new_contributor == other.new_contributor and self.avatar_url == other.avatar_url and self.contribution_count == other.contribution_count @@ -122,6 +128,8 @@ def merge_contributors(contributors: list) -> list: merged_contributor.new_contributor or contributor.new_contributor ) + if not merged_contributor.company and contributor.company: + merged_contributor.company = contributor.company else: merged_contributors.append(contributor) diff --git a/contributors.py b/contributors.py index 2885f92..de05aa0 100644 --- a/contributors.py +++ b/contributors.py @@ -181,8 +181,10 @@ def get_contributors(repo: object, start_date: str, end_date: str, ghe: str): commit_url = f"{endpoint}/{repo.full_name}/commits?author={user.login}&since={start_date}&until={end_date}" else: commit_url = f"{endpoint}/{repo.full_name}/commits?author={user.login}" + company = getattr(user, "company", "") or "" contributor = contributor_stats.ContributorStats( user.login, + company, False, user.avatar_url, user.contributions_count, diff --git a/markdown.py b/markdown.py index 88db305..185e5bb 100644 --- a/markdown.py +++ b/markdown.py @@ -26,12 +26,12 @@ def write_to_markdown( This function writes a list of collaborators to a markdown file in table format and optionally to GitHub Actions Job Summary if running in a GitHub Actions environment. Each collaborator is represented as a dictionary with keys 'username', - 'contribution_count', 'new_contributor', and 'commits'. + 'company', 'contribution_count', 'new_contributor', and 'commits'. Args: collaborators (list): A list of dictionaries, where each dictionary represents a collaborator. Each dictionary should - have the keys 'username', 'contribution_count', + have the keys 'username', 'company', 'contribution_count', and 'commits'. filename (str): The path of the markdown file to which the table will be written. @@ -167,7 +167,7 @@ def get_summary_table(collaborators, start_date, end_date, total_contributions): Args: collaborators (list): A list of dictionaries, where each dictionary represents a collaborator. - Each dictionary should have the keys 'username', 'contribution_count', and 'commits'. + Each dictionary should have the keys 'username', 'company', 'contribution_count', and 'commits'. start_date (str): The start date of the date range for the contributor list. end_date (str): The end date of the date range for the contributor list. total_contributions (int): The total number of contributions made by all of the contributors. @@ -230,7 +230,7 @@ def get_contributor_table( sponsor_info = _is_truthy(sponsor_info) show_avatar = _is_truthy(show_avatar) link_to_profile = _is_truthy(link_to_profile) - columns = ["Username", "All Time Contribution Count"] + columns = ["Username", "Company", "All Time Contribution Count"] if show_avatar: columns.insert(0, "Avatar") if start_date and end_date: @@ -252,6 +252,7 @@ def get_contributor_table( total_contributions += collaborator.contribution_count username = collaborator.username contribution_count = collaborator.contribution_count + company = collaborator.company.strip() if collaborator.company else "-" if repository: commit_urls = collaborator.commit_url if organization: @@ -275,9 +276,7 @@ def get_contributor_table( else "" ) row += f"{avatar_cell} | " - row += ( - f"{'' if not link_to_profile else '@'}{username} | {contribution_count} |" - ) + row += f"{'' if not link_to_profile else '@'}{username} | {company} | {contribution_count} |" if "New Contributor" in columns: row += f" {new_contributor} |" if "Sponsor URL" in columns: diff --git a/test_contributor_stats.py b/test_contributor_stats.py index 6785655..d9df14e 100644 --- a/test_contributor_stats.py +++ b/test_contributor_stats.py @@ -22,6 +22,7 @@ def setUp(self): """ self.contributor = ContributorStats( "zkoppert", + "@github", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 1261, @@ -34,6 +35,7 @@ def test_init(self): Test the __init__ method of the ContributorStats class. """ self.assertEqual(self.contributor.username, "zkoppert") + self.assertEqual(self.contributor.company, "@github") self.assertFalse(self.contributor.new_contributor) self.assertEqual( self.contributor.avatar_url, @@ -63,6 +65,7 @@ def test_merge_contributors(self): """ contributor1 = ContributorStats( "user1", + "@company1", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 100, @@ -71,6 +74,7 @@ def test_merge_contributors(self): ) contributor2 = ContributorStats( "user2", + "@company2", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 200, @@ -79,6 +83,7 @@ def test_merge_contributors(self): ) contributor3 = ContributorStats( "user1", + "@company1", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 150, @@ -95,6 +100,7 @@ def test_merge_contributors(self): expected_result = [ ContributorStats( "user1", + "@company1", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 250, @@ -103,6 +109,7 @@ def test_merge_contributors(self): ), ContributorStats( "user2", + "@company2", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 200, @@ -123,6 +130,7 @@ def test_is_new_contributor_true(self): returning_contributors = [ ContributorStats( username="user1", + company="", new_contributor=False, avatar_url="https://avatars.githubusercontent.com/u/", contribution_count=100, @@ -131,6 +139,7 @@ def test_is_new_contributor_true(self): ), ContributorStats( username="user2", + company="", new_contributor=False, avatar_url="https://avatars.githubusercontent.com/u/", contribution_count=200, @@ -151,6 +160,7 @@ def test_is_new_contributor_false(self): returning_contributors = [ ContributorStats( username="user1", + company="", new_contributor=False, avatar_url="https://avatars.githubusercontent.com/u/", contribution_count=100, @@ -159,6 +169,7 @@ def test_is_new_contributor_false(self): ), ContributorStats( username="user2", + company="", new_contributor=False, avatar_url="https://avatars.githubusercontent.com/u/", contribution_count=200, @@ -189,6 +200,7 @@ def test_fetch_sponsor_info(self, mock_post): returning_contributors = [ ContributorStats( username=user, + company="", new_contributor=False, avatar_url="https://avatars.githubusercontent.com/u/", contribution_count=100, diff --git a/test_contributors.py b/test_contributors.py index 19ba046..58e2545 100644 --- a/test_contributors.py +++ b/test_contributors.py @@ -23,6 +23,7 @@ def test_get_contributors(self, mock_contributor_stats): mock_user.login = "user" mock_user.avatar_url = "https://avatars.githubusercontent.com/u/12345678?v=4" mock_user.contributions_count = 100 + mock_user.company = "@company" mock_repo.contributors.return_value = [mock_user] mock_repo.full_name = "owner/repo" mock_repo.commits.return_value = iter([object()]) @@ -34,6 +35,7 @@ def test_get_contributors(self, mock_contributor_stats): ) mock_contributor_stats.assert_called_once_with( "user", + "@company", False, "https://avatars.githubusercontent.com/u/12345678?v=4", 100, @@ -54,6 +56,7 @@ def test_get_all_contributors_with_organization(self, mock_get_contributors): mock_get_contributors.return_value = [ ContributorStats( "user", + "@company", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 100, @@ -72,6 +75,7 @@ def test_get_all_contributors_with_organization(self, mock_get_contributors): [ ContributorStats( "user", + "@company", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 200, @@ -93,6 +97,7 @@ def test_get_all_contributors_with_repository(self, mock_get_contributors): mock_get_contributors.return_value = [ ContributorStats( "user", + "@company", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 100, @@ -111,6 +116,7 @@ def test_get_all_contributors_with_repository(self, mock_get_contributors): [ ContributorStats( "user", + "@company", False, "https://avatars.githubusercontent.com/u/29484535?v=4", 100, @@ -133,10 +139,12 @@ def test_get_contributors_skip_users_with_no_commits(self, mock_contributor_stat mock_user.login = "user" mock_user.avatar_url = "https://avatars.githubusercontent.com/u/12345678?v=4" mock_user.contributions_count = 100 + mock_user.company = "@company" mock_user2 = MagicMock() mock_user2.login = "user2" mock_user2.avatar_url = "https://avatars.githubusercontent.com/u/12345679?v=4" mock_user2.contributions_count = 102 + mock_user2.company = "@company2" mock_repo.contributors.return_value = [mock_user, mock_user2] mock_repo.full_name = "owner/repo" @@ -156,6 +164,7 @@ def test_get_contributors_skip_users_with_no_commits(self, mock_contributor_stat ) mock_contributor_stats.assert_called_once_with( "user", + "@company", False, "https://avatars.githubusercontent.com/u/12345678?v=4", 100, @@ -173,6 +182,7 @@ def test_get_contributors_skip_bot(self, mock_contributor_stats): mock_user.login = "[bot]" mock_user.avatar_url = "https://avatars.githubusercontent.com/u/12345678?v=4" mock_user.contributions_count = 100 + mock_user.company = "@company" mock_repo.contributors.return_value = [mock_user] mock_repo.full_name = "owner/repo" @@ -194,6 +204,7 @@ def test_get_contributors_no_commit_end_date(self, mock_contributor_stats): mock_user.login = "user" mock_user.avatar_url = "https://avatars.githubusercontent.com/u/12345678?v=4" mock_user.contributions_count = 100 + mock_user.company = "@company" mock_repo.contributors.return_value = [mock_user] mock_repo.full_name = "owner/repo" @@ -204,6 +215,7 @@ def test_get_contributors_no_commit_end_date(self, mock_contributor_stats): mock_repo.commits.assert_not_called() mock_contributor_stats.assert_called_once_with( "user", + "@company", False, "https://avatars.githubusercontent.com/u/12345678?v=4", 100, diff --git a/test_json_writer.py b/test_json_writer.py index 197e4c3..cc1c3ad 100644 --- a/test_json_writer.py +++ b/test_json_writer.py @@ -24,6 +24,7 @@ def setUp(self): "contributors": [ { "username": "test_user", + "company": "@company", "new_contributor": False, "avatar_url": "https://test_url.com", "contribution_count": 10, @@ -38,6 +39,7 @@ def test_write_to_json(self): contributors = ( ContributorStats( username="test_user", + company="@company", new_contributor=False, avatar_url="https://test_url.com", contribution_count=10, diff --git a/test_markdown.py b/test_markdown.py index 88f21b2..384f521 100644 --- a/test_markdown.py +++ b/test_markdown.py @@ -24,6 +24,7 @@ def test_write_to_markdown( """ person1 = contributor_stats.ContributorStats( "user1", + "@company1", False, "url", 100, @@ -32,6 +33,7 @@ def test_write_to_markdown( ) person2 = contributor_stats.ContributorStats( "user2", + "@company2", False, "url2", 200, @@ -67,11 +69,11 @@ def test_write_to_markdown( "| Total Contributors | Total Contributions | % New Contributors |\n" "| --- | --- | --- |\n" "| 2 | 300 | 50.0% |\n\n" - "| Username | All Time Contribution Count | New Contributor | " + "| Username | Company | All Time Contribution Count | New Contributor | " "Commits between 2023-01-01 and 2023-01-02 |\n" - "| --- | --- | --- | --- |\n" - "| @user1 | 100 | False | commit url |\n" - "| @user2 | 200 | True | commit url2 |\n" + "| --- | --- | --- | --- | --- |\n" + "| @user1 | @company1 | 100 | False | commit url |\n" + "| @user2 | @company2 | 200 | True | commit url2 |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" "(https://github.com/github-community-projects/contributors)_\n" @@ -90,6 +92,7 @@ def test_write_to_markdown_with_sponsors( """ person1 = contributor_stats.ContributorStats( "user1", + "@company1", False, "url", 100, @@ -98,6 +101,7 @@ def test_write_to_markdown_with_sponsors( ) person2 = contributor_stats.ContributorStats( "user2", + "@company2", False, "url2", 200, @@ -133,11 +137,11 @@ def test_write_to_markdown_with_sponsors( "| Total Contributors | Total Contributions | % New Contributors |\n" "| --- | --- | --- |\n" "| 2 | 300 | 50.0% |\n\n" - "| Username | All Time Contribution Count | New Contributor | " + "| Username | Company | All Time Contribution Count | New Contributor | " "Sponsor URL | Commits between 2023-01-01 and 2023-01-02 |\n" - "| --- | --- | --- | --- | --- |\n" - "| @user1 | 100 | False | [Sponsor Link](sponsor_url_1) | commit url |\n" - "| @user2 | 200 | True | not sponsorable | commit url2 |\n" + "| --- | --- | --- | --- | --- | --- |\n" + "| @user1 | @company1 | 100 | False | [Sponsor Link](sponsor_url_1) | commit url |\n" + "| @user2 | @company2 | 200 | True | not sponsorable | commit url2 |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" "(https://github.com/github-community-projects/contributors)_\n" @@ -225,6 +229,7 @@ def test_write_to_markdown_without_link_to_profile( """ person1 = contributor_stats.ContributorStats( "user1", + "@company1", False, "url", 100, @@ -233,6 +238,7 @@ def test_write_to_markdown_without_link_to_profile( ) person2 = contributor_stats.ContributorStats( "user2", + "@company2", False, "url2", 200, @@ -268,11 +274,11 @@ def test_write_to_markdown_without_link_to_profile( "| Total Contributors | Total Contributions | % New Contributors |\n" "| --- | --- | --- |\n" "| 2 | 300 | 50.0% |\n\n" - "| Username | All Time Contribution Count | New Contributor | " + "| Username | Company | All Time Contribution Count | New Contributor | " "Commits between 2023-01-01 and 2023-01-02 |\n" - "| --- | --- | --- | --- |\n" - "| user1 | 100 | False | commit url |\n" - "| user2 | 200 | True | commit url2 |\n" + "| --- | --- | --- | --- | --- |\n" + "| user1 | @company1 | 100 | False | commit url |\n" + "| user2 | @company2 | 200 | True | commit url2 |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" "(https://github.com/github-community-projects/contributors)_\n" @@ -290,6 +296,7 @@ def test_write_to_github_summary( """ person1 = contributor_stats.ContributorStats( "user1", + "@company1", False, "url", 100, @@ -298,6 +305,7 @@ def test_write_to_github_summary( ) person2 = contributor_stats.ContributorStats( "user2", + "@company2", False, "url2", 200, @@ -350,6 +358,7 @@ def test_write_to_markdown_with_organization( """ person1 = contributor_stats.ContributorStats( "user1", + "@company1", False, "url", 100, @@ -358,6 +367,7 @@ def test_write_to_markdown_with_organization( ) person2 = contributor_stats.ContributorStats( "user2", + "@company2", False, "url2", 200, @@ -394,12 +404,12 @@ def test_write_to_markdown_with_organization( "| Total Contributors | Total Contributions | % New Contributors |\n" "| --- | --- | --- |\n" "| 2 | 300 | 50.0% |\n\n" - "| Username | All Time Contribution Count | New Contributor | " + "| Username | Company | All Time Contribution Count | New Contributor | " "Commits between 2023-01-01 and 2023-01-02 |\n" - "| --- | --- | --- | --- |\n" - "| @user1 | 100 | False | " + "| --- | --- | --- | --- | --- |\n" + "| @user1 | @company1 | 100 | False | " "[org1/repo1](https://github.com/org1/repo1/commits?author=user1), |\n" - "| @user2 | 200 | True | " + "| @user2 | @company2 | 200 | True | " "[org2/repo2](https://github.com/org2/repo2/commits?author=user2), " "[org3/repo3](https://github.com/org3/repo3/commits?author=user2), |\n" "\n _this file was generated by the " @@ -442,9 +452,9 @@ def test_write_to_markdown_empty_collaborators( "| Total Contributors | Total Contributions | % New Contributors |\n" "| --- | --- | --- |\n" "| 0 | 0 | 0% |\n\n" - "| Username | All Time Contribution Count | New Contributor | " + "| Username | Company | All Time Contribution Count | New Contributor | " "Commits between 2023-01-01 and 2023-01-02 |\n" - "| --- | --- | --- | --- |\n" + "| --- | --- | --- | --- | --- |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" "(https://github.com/github-community-projects/contributors)_\n" @@ -463,6 +473,7 @@ def test_write_to_markdown_no_dates( """ person1 = contributor_stats.ContributorStats( "user1", + "@company1", False, "url", 100, @@ -471,6 +482,7 @@ def test_write_to_markdown_no_dates( ) person2 = contributor_stats.ContributorStats( "user2", + "@company2", False, "url2", 200, @@ -503,10 +515,10 @@ def test_write_to_markdown_no_dates( "| Total Contributors | Total Contributions |\n" "| --- | --- |\n" "| 2 | 300 |\n\n" - "| Username | All Time Contribution Count | All Commits |\n" - "| --- | --- | --- |\n" - "| @user1 | 100 | commit url |\n" - "| @user2 | 200 | commit url2 |\n" + "| Username | Company | All Time Contribution Count | All Commits |\n" + "| --- | --- | --- | --- |\n" + "| @user1 | @company1 | 100 | commit url |\n" + "| @user2 | @company2 | 200 | commit url2 |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" "(https://github.com/github-community-projects/contributors)_\n" @@ -525,6 +537,7 @@ def test_write_to_markdown_with_ghe( """ person1 = contributor_stats.ContributorStats( "user1", + "@company1", False, "url", 100, @@ -555,10 +568,10 @@ def test_write_to_markdown_with_ghe( "| Total Contributors | Total Contributions | % New Contributors |\n" "| --- | --- | --- |\n" "| 1 | 100 | 0.0% |\n\n" - "| Username | All Time Contribution Count | New Contributor | " + "| Username | Company | All Time Contribution Count | New Contributor | " "Commits between 2023-01-01 and 2023-01-02 |\n" - "| --- | --- | --- | --- |\n" - "| @user1 | 100 | False | " + "| --- | --- | --- | --- | --- |\n" + "| @user1 | @company1 | 100 | False | " "[org1/repo1](https://github.example.com/org1/repo1/commits?author=user1), |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" From c70e4aca1aba4052c78ec8da93fdf05f1985e625 Mon Sep 17 00:00:00 2001 From: Venu Vardhan Reddy Tekula Date: Fri, 6 Feb 2026 21:36:08 -0500 Subject: [PATCH 2/4] test: cover empty company fallback Add a markdown test that expects "-" when company is empty. Signed-off-by: Venu Vardhan Reddy Tekula --- test_markdown.py | 54 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/test_markdown.py b/test_markdown.py index 384f521..7ac370a 100644 --- a/test_markdown.py +++ b/test_markdown.py @@ -217,6 +217,60 @@ def test_write_to_markdown_with_avatars( ) mock_file().write.assert_called_once_with(expected_content) + @patch( + "markdown.os.environ.get", return_value=None + ) # Mock GITHUB_STEP_SUMMARY to None + @patch("builtins.open", new_callable=mock_open) + def test_write_to_markdown_empty_company_falls_back( + self, mock_file, mock_env_get + ): # pylint: disable=unused-argument + """ + Test the write_to_markdown function with an empty company value. + """ + person1 = contributor_stats.ContributorStats( + "user1", + "", + False, + "url", + 100, + "commit url", + "sponsor_url_1", + ) + collaborators = [ + person1, + ] + ghe = "" + + write_to_markdown( + collaborators, + "filename", + "2023-01-01", + "2023-01-02", + None, + "org/repo", + "false", + True, + ghe, + ) + + mock_file.assert_called_once_with("filename", "w", encoding="utf-8") + expected_content = ( + "# Contributors\n\n" + "- Date range for contributor list: 2023-01-01 to 2023-01-02\n" + "- Repository: org/repo\n\n" + "| Total Contributors | Total Contributions | % New Contributors |\n" + "| --- | --- | --- |\n" + "| 1 | 100 | 0.0% |\n\n" + "| Username | Company | All Time Contribution Count | New Contributor | " + "Commits between 2023-01-01 and 2023-01-02 |\n" + "| --- | --- | --- | --- | --- |\n" + "| @user1 | - | 100 | False | commit url |\n" + "\n _this file was generated by the " + "[Contributors GitHub Action]" + "(https://github.com/github/contributors)_\n" + ) + mock_file().write.assert_called_once_with(expected_content) + @patch( "markdown.os.environ.get", return_value=None ) # Mock GITHUB_STEP_SUMMARY to None From 501d048a5ed667dd9e9429d1a9d95951ff31f219 Mon Sep 17 00:00:00 2001 From: Venu Vardhan Reddy Tekula Date: Fri, 6 Feb 2026 23:23:59 -0500 Subject: [PATCH 3/4] docs: clarify contributor object fields Signed-off-by: Venu Vardhan Reddy Tekula --- README.md | 12 ++++++------ markdown.py | 23 ++++++++++++----------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 002ded4..ab8320c 100644 --- a/README.md +++ b/README.md @@ -236,9 +236,9 @@ jobs: | ------------------ | ------------------- | ------------------ | | 1 | 143 | 0% | -| Username | Company | All Time Contribution Count | New Contributor | Commits between 2021-01-01 and 2023-10-10 | -| --------- | -------- | --------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| @zkoppert | @github | 143 | False | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-01-01&until=2023-10-10) | +| Username | Company | All Time Contribution Count | New Contributor | Commits between 2021-01-01 and 2023-10-10 | +| --------- | ------- | --------------------------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| @zkoppert | @github | 143 | False | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-01-01&until=2023-10-10) | ``` ## Example Markdown output with no dates supplied @@ -252,9 +252,9 @@ jobs: | ------------------ | ------------------- | ------------------ | | 1 | 1913 | 0% | -| Username | Company | All Time Contribution Count | New Contributor | Sponsor URL | Commits between 2021-09-01 and 2023-09-30 | -| --------- | -------- | --------------------------- | --------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | -| @zkoppert | @github | 1913 | False | [Sponsor Link](https://github.com/sponsors/zkoppert) | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-09-01&until=2023-09-30) | +| Username | Company | All Time Contribution Count | New Contributor | Sponsor URL | Commits between 2021-09-01 and 2023-09-30 | +| --------- | ------- | --------------------------- | --------------- | ---------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- | +| @zkoppert | @github | 1913 | False | [Sponsor Link](https://github.com/sponsors/zkoppert) | [super-linter/super-linter](https://github.com/super-linter/super-linter/commits?author=zkoppert&since=2021-09-01&until=2023-09-30) | ``` ## GitHub Actions Job Summary diff --git a/markdown.py b/markdown.py index 185e5bb..2222153 100644 --- a/markdown.py +++ b/markdown.py @@ -25,14 +25,13 @@ def write_to_markdown( """ This function writes a list of collaborators to a markdown file in table format and optionally to GitHub Actions Job Summary if running in a GitHub Actions environment. - Each collaborator is represented as a dictionary with keys 'username', - 'company', 'contribution_count', 'new_contributor', and 'commits'. + Each collaborator is represented as a ContributorStats object with fields + 'username', 'company', 'contribution_count', 'new_contributor', and 'commit_url'. Args: - collaborators (list): A list of dictionaries, where each dictionary - represents a collaborator. Each dictionary should - have the keys 'username', 'company', 'contribution_count', - and 'commits'. + collaborators (list): A list of ContributorStats objects. Each object should + have the fields 'username', 'company', 'contribution_count', + 'new_contributor', and 'commit_url'. filename (str): The path of the markdown file to which the table will be written. start_date (str): The start date of the date range for the contributor @@ -166,8 +165,9 @@ def get_summary_table(collaborators, start_date, end_date, total_contributions): This function returns a string containing a markdown table of the summary statistics. Args: - collaborators (list): A list of dictionaries, where each dictionary represents a collaborator. - Each dictionary should have the keys 'username', 'company', 'contribution_count', and 'commits'. + collaborators (list): A list of ContributorStats objects. + Each object should have the fields 'username', 'company', + 'contribution_count', and 'new_contributor'. start_date (str): The start date of the date range for the contributor list. end_date (str): The end date of the date range for the contributor list. total_contributions (int): The total number of contributions made by all of the contributors. @@ -212,8 +212,9 @@ def get_contributor_table( This function returns a string containing a markdown table of the contributors and the total contribution count. Args: - collaborators (list): A list of dictionaries, where each dictionary represents a collaborator. - Each dictionary should have the keys 'username', 'contribution_count', and 'commits'. + collaborators (list): A list of ContributorStats objects. + Each object should have the fields 'username', 'company', + 'contribution_count', 'commit_url', and 'new_contributor'. start_date (str): The start date of the date range for the contributor list. end_date (str): The end date of the date range for the contributor list. organization (str): The organization for which the contributors are being listed. @@ -252,7 +253,7 @@ def get_contributor_table( total_contributions += collaborator.contribution_count username = collaborator.username contribution_count = collaborator.contribution_count - company = collaborator.company.strip() if collaborator.company else "-" + company = collaborator.company or "-" if repository: commit_urls = collaborator.commit_url if organization: From 440e06e4eeefea3100a8ace51864cb17c15492c6 Mon Sep 17 00:00:00 2001 From: Zack Koppert Date: Tue, 24 Feb 2026 14:28:43 -0800 Subject: [PATCH 4/4] fix: update tests for company column in ContributorStats - Add missing 'company' positional arg to ContributorStats in tests - Update test_repr expected output to include company field - Add Company column to avatar test expected markdown output - Fix repo URL in empty-company fallback test Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test_contributor_stats.py | 2 ++ test_contributors.py | 3 +++ test_markdown.py | 12 +++++++----- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/test_contributor_stats.py b/test_contributor_stats.py index d9df14e..62b1375 100644 --- a/test_contributor_stats.py +++ b/test_contributor_stats.py @@ -51,6 +51,7 @@ def test_repr(self): """Test the __repr__ method includes key fields.""" expected = ( "contributor_stats(username=zkoppert, " + "company=@github, " "new_contributor=False, " "avatar_url=https://avatars.githubusercontent.com/u/29484535?v=4, " "contribution_count=1261, " @@ -249,6 +250,7 @@ def test_fetch_sponsor_info_raises_on_error(self, mock_post): contributors = [ ContributorStats( username="user1", + company="", new_contributor=False, avatar_url="https://avatars.githubusercontent.com/u/", contribution_count=100, diff --git a/test_contributors.py b/test_contributors.py index 58e2545..c4b19d4 100644 --- a/test_contributors.py +++ b/test_contributors.py @@ -323,6 +323,7 @@ def test_main_sets_new_contributor_flag(self): """Test main sets new_contributor when start/end dates are provided.""" contributor = ContributorStats( "user1", + "", False, "https://avatars.githubusercontent.com/u/1", 10, @@ -373,6 +374,7 @@ def test_main_fetches_sponsor_info_when_enabled(self): """Test main fetches sponsor information when sponsor_info is enabled.""" contributor = ContributorStats( "user1", + "", False, "https://avatars.githubusercontent.com/u/1", 10, @@ -381,6 +383,7 @@ def test_main_fetches_sponsor_info_when_enabled(self): ) sponsored_contributor = ContributorStats( "user1", + "", False, "https://avatars.githubusercontent.com/u/1", 10, diff --git a/test_markdown.py b/test_markdown.py index 7ac370a..5b038bd 100644 --- a/test_markdown.py +++ b/test_markdown.py @@ -160,6 +160,7 @@ def test_write_to_markdown_with_avatars( """ person1 = contributor_stats.ContributorStats( "user1", + "", False, "https://avatars.example.com/user1.png", 100, @@ -168,6 +169,7 @@ def test_write_to_markdown_with_avatars( ) person2 = contributor_stats.ContributorStats( "user2", + "", False, "https://avatars.example.com/user2.png", 200, @@ -204,13 +206,13 @@ def test_write_to_markdown_with_avatars( "| Total Contributors | Total Contributions | % New Contributors |\n" "| --- | --- | --- |\n" "| 2 | 300 | 50.0% |\n\n" - "| Avatar | Username | All Time Contribution Count | New Contributor | " + "| Avatar | Username | Company | All Time Contribution Count | New Contributor | " "Commits between 2023-01-01 and 2023-01-02 |\n" - "| --- | --- | --- | --- | --- |\n" + "| --- | --- | --- | --- | --- | --- |\n" '| | ' - "@user1 | 100 | False | commit url |\n" + "@user1 | - | 100 | False | commit url |\n" '| | ' - "@user2 | 200 | True | commit url2 |\n" + "@user2 | - | 200 | True | commit url2 |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" "(https://github.com/github-community-projects/contributors)_\n" @@ -267,7 +269,7 @@ def test_write_to_markdown_empty_company_falls_back( "| @user1 | - | 100 | False | commit url |\n" "\n _this file was generated by the " "[Contributors GitHub Action]" - "(https://github.com/github/contributors)_\n" + "(https://github.com/github-community-projects/contributors)_\n" ) mock_file().write.assert_called_once_with(expected_content)