Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 14 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,17 +95,20 @@ This action can be configured to authenticate with GitHub App Installation or Pe

#### Other Configuration Options

| field | required | default | description |
| ------------------- | ----------------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `GH_ENTERPRISE_URL` | False | "" | The `GH_ENTERPRISE_URL` is used to connect to an enterprise server instance of GitHub. github.com users should not enter anything here. |
| `ORGANIZATION` | Required to have `ORGANIZATION` or `REPOSITORY` | | The name of the GitHub organization which you want the contributor information of all repos from. ie. github.com/github would be `github` |
| `REPOSITORY` | Required to have `ORGANIZATION` or `REPOSITORY` | | The name of the repository and organization which you want the contributor information from. ie. `github/contributors` or a comma separated list of multiple repositories `github/contributor,super-linter/super-linter` |
| `START_DATE` | False | Beginning of time | The date from which you want to start gathering contributor information. ie. Aug 1st, 2023 would be `2023-08-01`. |
| `END_DATE` | False | Current Date | The date at which you want to stop gathering contributor information. Must be later than the `START_DATE`. ie. Aug 2nd, 2023 would be `2023-08-02` |
| `SPONSOR_INFO` | False | False | If you want to include sponsor information in the output. This will include the sponsor count and the sponsor URL. This will impact action performance. ie. SPONSOR_INFO = "False" or SPONSOR_INFO = "True" |
| `LINK_TO_PROFILE` | False | True | If you want to link usernames to their GitHub profiles in the output. ie. LINK_TO_PROFILE = "True" or LINK_TO_PROFILE = "False" |
| `OUTPUT_FILENAME` | False | contributors.md | The output filename for the markdown report. ie. OUTPUT_FILENAME = "my-report.md" |
| `SHOW_AVATAR` | False | False | If you want to show profile images in the markdown output. ie. SHOW_AVATAR = "True" or SHOW_AVATAR = "False" |
| field | required | default | description |
| ------------------- | ----------------------------------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `GH_ENTERPRISE_URL` | False | "" | The `GH_ENTERPRISE_URL` is used to connect to an enterprise server instance of GitHub. github.com users should not enter anything here. |
| `ORGANIZATION` | Required to have `ORGANIZATION` or `REPOSITORY` | | The name of the GitHub organization which you want the contributor information of all repos from. ie. github.com/github would be `github` |
| `REPOSITORY` | Required to have `ORGANIZATION` or `REPOSITORY` | | The name of the repository and organization which you want the contributor information from. ie. `github/contributors` or a comma separated list of multiple repositories `github/contributor,super-linter/super-linter` |
| `START_DATE` | False | Beginning of time | The date from which you want to start gathering contributor information. ie. Aug 1st, 2023 would be `2023-08-01`. |
| `END_DATE` | False | Current Date | The date at which you want to stop gathering contributor information. Must be later than the `START_DATE`. ie. Aug 2nd, 2023 would be `2023-08-02` |
| `SPONSOR_INFO` | False | False | If you want to include sponsor information in the output. This will include the sponsor count and the sponsor URL. This will impact action performance. ie. SPONSOR_INFO = "False" or SPONSOR_INFO = "True" |
| `LINK_TO_PROFILE` | False | True | If you want to link usernames to their GitHub profiles in the output. ie. LINK_TO_PROFILE = "True" or LINK_TO_PROFILE = "False" |
| `OUTPUT_FILENAME` | False | contributors.md | The output filename for the markdown report. ie. OUTPUT_FILENAME = "my-report.md" |
| `SHOW_AVATAR` | False | False | If you want to show profile images in the markdown output. ie. SHOW_AVATAR = "True" or SHOW_AVATAR = "False" |
| `SORT_COLUMN` | False | contribution_count| The column you want to sort the table with. Possible values: `username` (column of strings), `contribution_count` (column of integers) or `new_contributor` (column of booleans, whether the given username is a new contributor) |
| `SORT_ORDER` | False | desc | The order the SORT_COLUMN column will be sorted. Possibles values: "asc" for ascending order or "desc" for descending order. |
| `SKIP_SUMMARY` | False | False | If you want to hide the summary with total contributions statistics above the contributors table. ie. SKIP_SUMMARY = "True" or SKIP_SUMMARY = "False" |

**Note**: If `start_date` and `end_date` are specified then the action will determine if the contributor is new. A new contributor is one that has contributed in the date range specified but not before the start date.

Expand Down
8 changes: 8 additions & 0 deletions contributors.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ def main():
link_to_profile,
output_filename,
show_avatar,
sort_column,
sort_order,
skip_summary,
) = env.get_env_vars()

# Auth to GitHub.com
Expand Down Expand Up @@ -86,6 +89,9 @@ def main():
link_to_profile,
ghe,
show_avatar,
sort_column,
sort_order,
skip_summary,
)
json_writer.write_to_json(
filename="contributors.json",
Expand All @@ -96,6 +102,8 @@ def main():
sponsor_info=sponsor_info,
link_to_profile=link_to_profile,
contributors=contributors,
sort_column=sort_column,
sort_order=sort_order,
)


Expand Down
31 changes: 31 additions & 0 deletions env.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import os
import re
from os.path import dirname, join
from typing import List

from dotenv import load_dotenv

Expand Down Expand Up @@ -132,6 +133,19 @@ def validate_output_filename(output_filename: str) -> str:
return filename


def validate_allowed_values(
env_var_name: str, allowed_values: List[str], default: str
) -> str:
"""Check that env variable is contained in a list of defined values or set a default one.
Returns a lowercase value.
"""
allowed_values = [val.strip().lower() for val in allowed_values]
var_to_validate = os.getenv(env_var_name, default).strip().lower()
if var_to_validate in allowed_values:
return var_to_validate
return default.strip().lower()


def get_env_vars(
test: bool = False,
) -> tuple[
Expand All @@ -149,6 +163,9 @@ def get_env_vars(
bool,
str,
bool,
str,
str,
bool,
]:
"""
Get the environment variables for use in the action.
Expand All @@ -169,6 +186,9 @@ def get_env_vars(
end_date (str): The end date to get contributor information to
sponsor_info (str): Whether to get sponsor information on the contributor
link_to_profile (str): Whether to link username to Github profile in markdown output
sort_column (str): The column the table should be sorted by ('username', 'contribution_count' or 'new_contributor'). Case insensitive.
sort_order (str): The sorting order ('asc' or 'desc'). Case insensitive.
skip_summary (str): Whether to print the summary before the table
"""

if not test:
Expand Down Expand Up @@ -222,6 +242,14 @@ def get_env_vars(
repository.strip() for repository in repositories_str.split(",")
]

sort_column = validate_allowed_values(
"SORT_COLUMN",
["username", "contribution_count", "new_contributor"],
"contribution_count",
)
sort_order = validate_allowed_values("SORT_ORDER", ["asc", "desc"], "desc")
skip_summary = get_bool_env_var("SKIP_SUMMARY", False)

return (
organization,
repositories_list,
Expand All @@ -237,4 +265,7 @@ def get_env_vars(
link_to_profile,
output_filename,
show_avatar,
sort_column,
sort_order,
skip_summary,
)
14 changes: 14 additions & 0 deletions json_writer.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""This module contains a function that writes data to a JSON file."""

import json
from operator import attrgetter


def write_to_json(
Expand All @@ -12,6 +13,8 @@ def write_to_json(
repository_list,
sponsor_info,
link_to_profile,
sort_column,
sort_order,
):
"""Write data to a JSON file.

Expand All @@ -24,6 +27,8 @@ def write_to_json(
repository_list (list): A list of repositories for which the contributors are being listed.
sponsor_info (str): A string indicating whether sponsor information should be included.
link_to_profile (str): A string indicating whether a link to the contributor's profile should be included.
sort_column (str): the column to sort the table with ('username', 'contribution_count' or 'new_contributor').
sort_order (str): the order to sort the column with (`asc` or `desc`).

Returns:
None
Expand All @@ -44,6 +49,8 @@ def write_to_json(
# ],
# "sponsor_info": false,
# "link_to_profile": false,
# "sort_column": "contribution_count"
# "sort_order": "desc"
# "contributors": [
# {
# "username": "zkoppert",
Expand All @@ -63,13 +70,20 @@ def write_to_json(
# }
# ]
# }

# Sort the list by chosen column and order
is_reverse = sort_order == "desc"
contributors = sorted(contributors, key=attrgetter(sort_column), reverse=is_reverse)

data = {
"start_date": start_date,
"end_date": end_date,
"organization": organization,
"repository_list": repository_list,
"sponsor_info": sponsor_info,
"link_to_profile": link_to_profile,
"sort_column": sort_column,
"sort_order": sort_order,
"contributors": [contributor.__dict__ for contributor in contributors],
}

Expand Down
37 changes: 33 additions & 4 deletions markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
"""This module contains the functions needed to write the output to markdown files."""

import os
from operator import attrgetter


def _is_truthy(value) -> bool:
Expand All @@ -20,6 +21,9 @@ def write_to_markdown(
sponsor_info,
link_to_profile,
ghe,
sort_column,
sort_order,
skip_summary,
show_avatar=False,
):
"""
Expand Down Expand Up @@ -47,6 +51,10 @@ def write_to_markdown(
link_to_profile (str): True if the user wants the username linked to
Github profile in the report
ghe (str): The GitHub Enterprise instance URL, if applicable.
sort_column (str): the column to sort the table with ('username',
'contribution_count' or 'new_contributor')
sort_order (str): the order to sort the column with (`asc` or `desc`)
skip_summary (str): True if the user wants the summary not to be printed
show_avatar (str): True if the user wants to show profile images in
the report

Expand All @@ -64,6 +72,8 @@ def write_to_markdown(
sponsor_info,
link_to_profile,
ghe,
sort_column,
sort_order,
show_avatar,
)

Expand All @@ -75,7 +85,13 @@ def write_to_markdown(

# Generate the markdown content once
content = generate_markdown_content(
start_date, end_date, organization, repository, table, summary_table
start_date,
end_date,
organization,
repository,
table,
summary_table,
skip_summary,
)

# Write the markdown file
Expand Down Expand Up @@ -104,7 +120,7 @@ def write_to_github_summary(content):


def generate_markdown_content(
start_date, end_date, organization, repository, table, summary_table
start_date, end_date, organization, repository, table, summary_table, skip_summary
):
"""
This function generates markdown content as a string.
Expand All @@ -121,6 +137,7 @@ def generate_markdown_content(
and the total contribution count.
summary_table (str): A string containing a markdown table of the
summary statistics.
skip_summary (str): True if the user wants the summary not to be printed.

Returns:
str: The complete markdown content as a string.
Expand All @@ -134,7 +151,8 @@ def generate_markdown_content(
if repository:
content += f"- Repository: {repository}\n"
content += "\n"
content += summary_table
if not skip_summary:
content += summary_table
content += table
content += (
"\n _this file was generated by the "
Expand Down Expand Up @@ -204,6 +222,8 @@ def get_contributor_table(
sponsor_info,
link_to_profile,
ghe,
sort_column,
sort_order,
show_avatar=False,
):
"""
Expand All @@ -218,6 +238,9 @@ def get_contributor_table(
repository (str): The repository for which the contributors are being listed.
sponsor_info (str): True if the user wants the sponsor_url shown in the report
link_to_profile (str): True if the user wants the username linked to Github profile in the report
sort_column (str): the column to sort the table with ('username',
'contribution_count' or 'new_contributor')
sort_order (str): the order to sort the column with (`asc` or `desc`)
show_avatar (str): True if the user wants to show profile images in the report

Returns:
Expand Down Expand Up @@ -249,7 +272,13 @@ def get_contributor_table(
table = headers
total_contributions = 0

for collaborator in collaborators:
# Sort the list by chosen column and order
is_reverse = sort_order == "desc"
sorted_collaborators = sorted(
collaborators, key=attrgetter(sort_column), reverse=is_reverse
)

for collaborator in sorted_collaborators:
total_contributions += collaborator.contribution_count
username = collaborator.username
contribution_count = collaborator.contribution_count
Expand Down
9 changes: 9 additions & 0 deletions test_contributors.py
Original file line number Diff line number Diff line change
Expand Up @@ -349,6 +349,9 @@ def test_main_runs_under_main_guard(self):
False,
"contributors.md",
False,
"contribution_count",
"desc",
False,
)

mock_auth = MagicMock()
Expand Down Expand Up @@ -423,6 +426,9 @@ def test_main_sets_new_contributor_flag(self):
False,
"contributors.md",
False,
"contribution_count",
"desc",
False,
)
mock_auth_to_github.return_value = MagicMock()
mock_get_all_contributors.side_effect = [[contributor], []]
Expand Down Expand Up @@ -478,6 +484,9 @@ def test_main_fetches_sponsor_info_when_enabled(self):
False,
"contributors.md",
False,
"contribution_count",
"desc",
False,
)
mock_auth_to_github.return_value = MagicMock()
mock_get_all_contributors.return_value = [contributor]
Expand Down
Loading
Loading