Skip to content

Commit

Permalink
Merge pull request #171 from ananta/centralize-get-env-vars
Browse files Browse the repository at this point in the history
refactor(get_env_vars): use get_env_vars() for consistent env variable retrieval
  • Loading branch information
zkoppert authored Dec 5, 2023
2 parents c5cb1d2 + b42c5cc commit d80e1c0
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 73 deletions.
93 changes: 93 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
"""A module for managing environment variables used in GitHub metrics calculation.
This module defines a class for encapsulating environment variables and a function to retrieve these variables.
Classes:
EnvVars: Represents the collection of environment variables used in the script.
Functions:
get_env_vars: Retrieves and returns an instance of EnvVars populated with environment variables.
"""
import os
from typing import List


class EnvVars:
# pylint: disable=too-many-instance-attributes
"""
Environment variables
Attributes:
search_query (str): Search query used to filter issues/prs/discussions on GitHub
gh_token (str): GitHub personal access token (PAT) for API authentication
labels_to_measure (List[str]): List of labels to measure how much time the lable is applied
ignore_users (List[str]): List of usernames to ignore when calculating metrics
github_server_url (str): URL of GitHub server (Github.com or Github Enterprise)
hide_author (str): If set, the author's information is hidden in the output
hide_time_to_first_response (str): If set, the time to first response metric is hidden in the output
hide_time_to_close (str): If set, the time to close metric is hidden in the output
hide_time_to_answer (str): If set, the time to answer discussions is hidden in the output
hide_label_metrics (str): If set, the label metrics are hidden in the output
"""
def __init__(self, search_query: str, gh_token: str, labels_to_measure: List[str], ignore_user: List[str],
github_server_url: str, hide_author: str, hide_time_to_first_response: str,
hide_time_to_close: str, hide_time_to_answer: str, hide_label_metrics: str):
self.search_query = search_query
self.gh_token = gh_token
self.labels_to_measure = labels_to_measure
self.ignore_users = ignore_user
self.github_server_url = github_server_url
self.hide_author = hide_author
self.hide_time_to_first_response = hide_time_to_first_response
self.hide_time_to_close = hide_time_to_close
self.hide_time_to_answer = hide_time_to_answer
self.hide_label_metrics = hide_label_metrics


def get_env_vars() -> EnvVars:
"""
Get the environment variables for use in the script.
Returns EnvVars object with all environment variables
"""
search_query = os.getenv("SEARCH_QUERY")
if not search_query:
raise ValueError("SEARCH_QUERY environment variable not set")

gh_token = os.getenv("GH_TOKEN")
if not gh_token:
raise ValueError("GITHUB_TOKEN environment variable not set")

labels_to_measure = os.getenv("LABELS_TO_MEASURE")
if labels_to_measure:
labels_to_measure = labels_to_measure.split(",")
else:
labels_to_measure = []

ignore_users = os.getenv("IGNORE_USERS")
if ignore_users:
ignore_users = ignore_users.split(",")
else:
ignore_users = []

github_server_url = os.getenv("GITHUB_SERVER_URL")

# Hidden columns
hide_author = os.getenv("HIDE_AUTHOR")
hide_time_to_first_response = os.getenv("HIDE_TIME_TO_FIRST_RESPONSE")
hide_time_to_close = os.getenv("HIDE_TIME_TO_CLOSE")
hide_time_to_answer = os.getenv("HIDE_TIME_TO_ANSWER")
hide_label_metrics = os.getenv("HIDE_LABEL_METRICS")

return EnvVars(
search_query,
gh_token,
labels_to_measure,
ignore_users,
github_server_url,
hide_author,
hide_time_to_first_response,
hide_time_to_close,
hide_time_to_answer,
hide_label_metrics
)
57 changes: 15 additions & 42 deletions issue_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
their metrics to a markdown file.
Functions:
get_env_vars() -> tuple[str, str]: Get the environment variables for use
get_env_vars() -> EnvVars: Get the environment variables for use
in the script.
search_issues(search_query: str, github_connection: github3.GitHub)
-> github3.structs.SearchIterator:
Expand All @@ -21,7 +21,6 @@
main(): Run the issue-metrics script.
"""

import os
from os.path import dirname, join
import sys
from typing import List, Union
Expand All @@ -42,32 +41,7 @@
get_stats_time_to_first_response,
measure_time_to_first_response,
)


def get_env_vars() -> tuple[str, str, List[str]]:
"""
Get the environment variables for use in the script.
Returns:
str: the search query used to filter issues, prs, and discussions
str: the github token used to authenticate to github.com
List[str]: a list of users to ignore when calculating metrics
"""
search_query = os.getenv("SEARCH_QUERY")
if not search_query:
raise ValueError("SEARCH_QUERY environment variable not set")

token = os.getenv("GH_TOKEN")
if not token:
raise ValueError("GITHUB_TOKEN environment variable not set")

ignore_users = os.getenv("IGNORE_USERS")
if ignore_users:
ignore_users = ignore_users.split(",")
else:
ignore_users = []

return search_query, token, ignore_users
from config import get_env_vars


def search_issues(
Expand Down Expand Up @@ -123,17 +97,16 @@ def auth_to_github() -> github3.GitHub:
Returns:
github3.GitHub: A github api connection.
"""
if token := os.getenv("GH_TOKEN"):
if not os.getenv("GITHUB_SERVER_URL"):
github_connection = github3.login(token=token)
elif os.getenv("GITHUB_SERVER_URL") == "https://github.com":
github_connection = github3.login(token=token)
else:
github_connection = github3.GitHubEnterprise(
os.getenv("GITHUB_SERVER_URL"), token=token
)
env_vars = get_env_vars()
token = env_vars.gh_token
github_server_url = env_vars.github_server_url

if github_server_url and github_server_url != "https://github.com":
github_connection = github3.GitHubEnterprise(
github_server_url, token=token
)
else:
raise ValueError("GH_TOKEN environment variable not set")
github_connection = github3.login(token=token)

return github_connection # type: ignore

Expand Down Expand Up @@ -269,9 +242,9 @@ def main():

# Get the environment variables for use in the script
env_vars = get_env_vars()
search_query = env_vars[0]
token = env_vars[1]
ignore_users = env_vars[2]
search_query = env_vars.search_query
token = env_vars.gh_token
ignore_users = env_vars.ignore_users

# Get the repository owner and name from the search query
owner = get_owner(search_query)
Expand All @@ -284,7 +257,7 @@ def main():
)

# Determine if there are label to measure
labels = os.environ.get("LABELS_TO_MEASURE")
labels = env_vars.labels_to_measure
if labels:
labels = labels.split(",")
else:
Expand Down
15 changes: 9 additions & 6 deletions markdown_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
Get the columns that are not hidden.
"""

import os
from datetime import timedelta
from typing import List, Union

from classes import IssueWithMetrics
from config import get_env_vars


def get_non_hidden_columns(labels) -> List[str]:
Expand All @@ -43,24 +43,27 @@ def get_non_hidden_columns(labels) -> List[str]:
"""
columns = ["Title", "URL"]

env_vars = get_env_vars()

# Find the number of columns and which are to be hidden
hide_author = os.getenv("HIDE_AUTHOR")
hide_author = env_vars.hide_author
if not hide_author:
columns.append("Author")

hide_time_to_first_response = os.getenv("HIDE_TIME_TO_FIRST_RESPONSE")
hide_time_to_first_response = env_vars.hide_time_to_first_response
if not hide_time_to_first_response:
columns.append("Time to first response")

hide_time_to_close = os.getenv("HIDE_TIME_TO_CLOSE")
hide_time_to_close = env_vars.hide_time_to_close
if not hide_time_to_close:
columns.append("Time to close")

hide_time_to_answer = os.getenv("HIDE_TIME_TO_ANSWER")
hide_time_to_answer = env_vars.hide_time_to_answer
if not hide_time_to_answer:
columns.append("Time to answer")

hide_label_metrics = os.getenv("HIDE_LABEL_METRICS")
hide_label_metrics = env_vars.hide_label_metrics
if not hide_label_metrics and labels:
for label in labels:
columns.append(f"Time spent in {label}")
Expand Down
22 changes: 11 additions & 11 deletions test_issue_metrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ class TestAuthToGithub(unittest.TestCase):
"""Test the auth_to_github function."""

@patch("github3.login")
@patch.dict(os.environ, {"GH_TOKEN": "test_token", "SEARCH_QUERY": "is:open repo:user/repo"})
def test_auth_to_github_with_token(self, mock_login):
"""Test that auth_to_github works with a token.
Expand All @@ -72,21 +73,16 @@ def test_auth_to_github_with_token(self, mock_login):
mock_gh = MagicMock()
mock_login.return_value = mock_gh

# Set up the environment variable
os.environ["GH_TOKEN"] = "test_token"

# Call the function
github_connection = auth_to_github()

# Check the results
self.assertEqual(github_connection, mock_gh)
mock_login.assert_called_once_with(token="test_token")

@patch.dict(os.environ, {}, clear=True)
def test_auth_to_github_no_token(self):
"""Test that auth_to_github raises a ValueError if GH_TOKEN is not set."""
# Unset the GH_TOKEN environment variable
if "GH_TOKEN" in os.environ:
del os.environ["GH_TOKEN"]

# Call auth_to_github and check that it raises a ValueError
with self.assertRaises(ValueError):
Expand All @@ -96,15 +92,17 @@ def test_auth_to_github_no_token(self):
class TestGetEnvVars(unittest.TestCase):
"""Test suite for the get_env_vars function."""

@patch.dict(os.environ, {"GH_TOKEN": "test_token", "SEARCH_QUERY": "is:issue is:open repo:user/repo"})
def test_get_env_vars(self):
"""Test that the function correctly retrieves the environment variables."""
# Set the environment variables
os.environ["SEARCH_QUERY"] = "is:issue is:open repo:org/repo"

# Call the function and check the result
result = get_env_vars()
expected_result = "is:issue is:open repo:org/repo"
self.assertEqual(result[0], expected_result)
search_query = get_env_vars().search_query
gh_token = get_env_vars().gh_token
gh_token_expected_result = "test_token"
search_query_expected_result = "is:issue is:open repo:user/repo"
self.assertEqual(gh_token, gh_token_expected_result)
self.assertEqual(search_query, search_query_expected_result)

def test_get_env_vars_missing_query(self):
"""Test that the function raises a ValueError
Expand Down Expand Up @@ -138,6 +136,7 @@ class TestMain(unittest.TestCase):
os.environ,
{
"SEARCH_QUERY": "is:open repo:user/repo",
"GH_TOKEN": "test_token",
},
)
def test_main(
Expand Down Expand Up @@ -198,6 +197,7 @@ def test_main(
os.environ,
{
"SEARCH_QUERY": "is:open repo:org/repo",
"GH_TOKEN": "test_token",
},
)
def test_main_no_issues_found(
Expand Down
32 changes: 18 additions & 14 deletions test_markdown_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@
from markdown_writer import write_to_markdown


@patch.dict(
os.environ,
{
"SEARCH_QUERY": "is:open repo:user/repo",
"GH_TOKEN": "test_token"
},
)
class TestWriteToMarkdown(unittest.TestCase):
"""Test the write_to_markdown function."""

Expand Down Expand Up @@ -234,23 +241,20 @@ def test_write_to_markdown_no_issues(self):
)


@patch.dict(
os.environ,
{
"SEARCH_QUERY": "is:open repo:user/repo",
"GH_TOKEN": "test_token",
"HIDE_TIME_TO_FIRST_RESPONSE": "True",
"HIDE_TIME_TO_CLOSE": "True",
"HIDE_TIME_TO_ANSWER": "True",
"HIDE_LABEL_METRICS": "True"
},
)
class TestWriteToMarkdownWithEnv(unittest.TestCase):
"""Test the write_to_markdown function with the HIDE* environment variables set."""

def setUp(self):
# Set the HIDE* environment variables to True
os.environ["HIDE_TIME_TO_FIRST_RESPONSE"] = "True"
os.environ["HIDE_TIME_TO_CLOSE"] = "True"
os.environ["HIDE_TIME_TO_ANSWER"] = "True"
os.environ["HIDE_LABEL_METRICS"] = "True"

def tearDown(self):
# Unset the HIDE* environment variables
os.environ.pop("HIDE_TIME_TO_FIRST_RESPONSE")
os.environ.pop("HIDE_TIME_TO_CLOSE")
os.environ.pop("HIDE_TIME_TO_ANSWER")
os.environ.pop("HIDE_LABEL_METRICS")

def test_writes_markdown_file_with_non_hidden_columns_only(self):
"""
Test that write_to_markdown writes the correct
Expand Down

0 comments on commit d80e1c0

Please sign in to comment.