Skip to content
Merged
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
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,16 +95,17 @@ 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-community-projects/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" |
| 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" |

**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
2 changes: 2 additions & 0 deletions contributors.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def main():
sponsor_info,
link_to_profile,
output_filename,
show_avatar,
) = env.get_env_vars()

# Auth to GitHub.com
Expand Down Expand Up @@ -84,6 +85,7 @@ def main():
sponsor_info,
link_to_profile,
ghe,
show_avatar,
)
json_writer.write_to_json(
filename="contributors.json",
Expand Down
38 changes: 27 additions & 11 deletions env.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,27 @@ def validate_date_range(start_date: str, end_date: str) -> None:
)


def validate_output_filename(output_filename: str) -> str:
"""Validate OUTPUT_FILENAME and return a safe filename."""
if not output_filename:
return "contributors.md"

filename = output_filename.strip()
if not filename:
return "contributors.md"

if os.path.isabs(filename):
raise ValueError("OUTPUT_FILENAME must be a filename only, not a path")

if "/" in filename or "\\" in filename:
raise ValueError("OUTPUT_FILENAME must be a filename only, not a path")

if not re.fullmatch(r"[A-Za-z0-9._-]+", filename):
raise ValueError("OUTPUT_FILENAME contains invalid characters")

return filename


def get_env_vars(
test: bool = False,
) -> tuple[
Expand All @@ -117,6 +138,7 @@ def get_env_vars(
bool,
bool,
str,
bool,
]:
"""
Get the environment variables for use in the action.
Expand All @@ -137,7 +159,6 @@ 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
output_filename (str): The output filename for the markdown report
"""

if not test:
Expand Down Expand Up @@ -179,16 +200,10 @@ def get_env_vars(

sponsor_info = get_bool_env_var("SPONSOR_INFO", False)
link_to_profile = get_bool_env_var("LINK_TO_PROFILE", False)
output_filename = os.getenv("OUTPUT_FILENAME", "").strip() or "contributors.md"
if not re.match(r"^[a-zA-Z0-9_\-\.]+$", output_filename):
raise ValueError(
"OUTPUT_FILENAME must contain only alphanumeric characters, "
"hyphens, underscores, and dots"
)
if output_filename != os.path.basename(output_filename):
raise ValueError(
"OUTPUT_FILENAME must be a simple filename without path separators"
)
output_filename = validate_output_filename(
os.getenv("OUTPUT_FILENAME", "contributors.md")
)
show_avatar = get_bool_env_var("SHOW_AVATAR", False)

# Separate repositories_str into a list based on the comma separator
repositories_list = []
Expand All @@ -211,4 +226,5 @@ def get_env_vars(
sponsor_info,
link_to_profile,
output_filename,
show_avatar,
)
31 changes: 28 additions & 3 deletions markdown.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@
import os


def _is_truthy(value) -> bool:
if isinstance(value, str):
return value.strip().lower() == "true"
return value is True


def write_to_markdown(
collaborators,
filename,
Expand All @@ -14,6 +20,7 @@ def write_to_markdown(
sponsor_info,
link_to_profile,
ghe,
show_avatar=False,
):
"""
This function writes a list of collaborators to a markdown file in table format
Expand All @@ -40,6 +47,8 @@ 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.
show_avatar (str): True if the user wants to show profile images in
the report

Returns:
None
Expand All @@ -55,6 +64,7 @@ def write_to_markdown(
sponsor_info,
link_to_profile,
ghe,
show_avatar,
)

# Put together the summary table including # of new contributions,
Expand Down Expand Up @@ -196,6 +206,7 @@ def get_contributor_table(
sponsor_info,
link_to_profile,
ghe,
show_avatar=False,
):
"""
This function returns a string containing a markdown table of the contributors and the total contribution count.
Expand All @@ -209,16 +220,22 @@ 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
show_avatar (str): True if the user wants to show profile images in the report

Returns:
table (str): A string containing a markdown table of the contributors and the total contribution count.
total_contributions (int): The total number of contributions made by all of the contributors.

"""
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"]
if show_avatar:
columns.insert(0, "Avatar")
if start_date and end_date:
columns += ["New Contributor"]
if sponsor_info == "true":
if sponsor_info:
columns += ["Sponsor URL"]
if start_date and end_date:
columns += [f"Commits between {start_date} and {end_date}"]
Expand Down Expand Up @@ -250,8 +267,16 @@ def get_contributor_table(
commit_urls += f"{url}, "
new_contributor = collaborator.new_contributor

row = (
f"| {'' if not link_to_profile else '@'}{username} | {contribution_count} |"
row = "| "
if show_avatar:
avatar_cell = (
f'<img src="{collaborator.avatar_url}" width="32" height="32" />'
if collaborator.avatar_url
else ""
)
row += f"{avatar_cell} | "
row += (
f"{'' if not link_to_profile else '@'}{username} | {contribution_count} |"
)
if "New Contributor" in columns:
row += f" {new_contributor} |"
Expand Down
3 changes: 3 additions & 0 deletions test_contributors.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,7 @@ def test_main_runs_under_main_guard(self):
False,
False,
"contributors.md",
False,
)

mock_auth = MagicMock()
Expand Down Expand Up @@ -346,6 +347,7 @@ def test_main_sets_new_contributor_flag(self):
False,
False,
"contributors.md",
False,
)
mock_auth_to_github.return_value = MagicMock()
mock_get_all_contributors.side_effect = [[contributor], []]
Expand Down Expand Up @@ -401,6 +403,7 @@ def test_main_fetches_sponsor_info_when_enabled(self):
"true",
False,
"contributors.md",
False,
)
mock_auth_to_github.return_value = MagicMock()
mock_get_all_contributors.return_value = [contributor]
Expand Down
Loading
Loading