Skip to content

Commit d2bea41

Browse files
authored
refactor: replace get_env_vars() tuple with frozen EvergreenConfig dataclass (#525)
* refactor: replace get_env_vars() 30-element tuple with frozen EvergreenConfig dataclass ## What Replace the 30-element tuple returned by get_env_vars() with a frozen dataclass EvergreenConfig. Updated evergreen.py main() to use config.attribute access instead of tuple destructuring, and converted all 20 expected_result tuples in test_env.py to use named EvergreenConfig construction. Includes the ghe_api_url field from PR #524. ## Why The 30-element tuple was fragile — adding/removing fields required counting positions across 20+ tests, and positional access like result[8] was unreadable. Named attribute access eliminates these problems and makes future field additions trivial. ## Notes - This is a pure refactor with no behavior change. All 173 tests pass with identical coverage. - The dataclass uses frozen=True for immutability, matching the previous tuple's semantics. - pylint disable for too-many-instance-attributes is necessary since the config genuinely has 30 fields. - Rebased on main after PR #524 merge to include ghe_api_url field. Signed-off-by: jmeridth <jmeridth@gmail.com> * fix: tighten type annotations for bool fields that never return None ## What Changed group_dependencies, enable_security_updates, and update_existing from bool | None to bool in the EvergreenConfig dataclass. ## Why get_bool_env_var() always returns bool, never None. The overly permissive annotations were carried over from the old tuple type hints. Signed-off-by: jmeridth <jmeridth@gmail.com> * fix: tighten search_query and repo_specific_exemptions type annotations ## What Changed search_query from str | None to str, and repo_specific_exemptions from bare dict to dict[str, list[str]] in EvergreenConfig. ## Why search_query always comes from os.getenv(..., "").strip() which never returns None. repo_specific_exemptions is built by parse_repo_specific_exemptions() which always returns dict[str, list[str]]. The tighter annotations improve IDE hints and mypy coverage. Signed-off-by: jmeridth <jmeridth@gmail.com> --------- Signed-off-by: jmeridth <jmeridth@gmail.com>
1 parent 26faf5b commit d2bea41

File tree

3 files changed

+887
-875
lines changed

3 files changed

+887
-875
lines changed

env.py

Lines changed: 71 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import os
66
import re
7+
from dataclasses import dataclass
78
from os.path import dirname, join
89

910
from dotenv import load_dotenv
@@ -45,6 +46,42 @@
4546
]
4647

4748

49+
@dataclass(frozen=True)
50+
class EvergreenConfig: # pylint: disable=too-many-instance-attributes
51+
"""Configuration for the Evergreen action, parsed from environment variables."""
52+
53+
organization: str | None
54+
repository_list: list[str]
55+
search_query: str
56+
gh_app_id: int | None
57+
gh_app_installation_id: int | None
58+
gh_app_private_key_bytes: bytes
59+
gh_app_enterprise_only: bool
60+
token: str
61+
ghe: str
62+
ghe_api_url: str
63+
exempt_repositories_list: list[str]
64+
follow_up_type: str
65+
title: str
66+
body: str
67+
created_after_date: str
68+
dry_run: bool
69+
commit_message: str
70+
project_id: str | None
71+
group_dependencies: bool
72+
filter_visibility: list[str]
73+
batch_size: int | None
74+
enable_security_updates: bool
75+
exempt_ecosystems: list[str]
76+
update_existing: bool
77+
repo_specific_exemptions: dict[str, list[str]]
78+
schedule: str
79+
schedule_day: str
80+
team_name: str | None
81+
labels: list[str]
82+
dependabot_config_file: str | None
83+
84+
4885
def get_api_endpoint(ghe: str, ghe_api_url: str) -> str:
4986
"""Return the GitHub API endpoint URL.
5087
@@ -134,74 +171,15 @@ def parse_repo_specific_exemptions(repo_specific_exemptions_str: str) -> dict:
134171

135172
def get_env_vars(
136173
test: bool = False,
137-
) -> tuple[
138-
str | None,
139-
list[str],
140-
str | None,
141-
int | None,
142-
int | None,
143-
bytes,
144-
bool,
145-
str,
146-
str,
147-
list[str],
148-
str,
149-
str,
150-
str,
151-
str,
152-
bool,
153-
str,
154-
str | None,
155-
bool | None,
156-
list[str] | None,
157-
int | None,
158-
bool | None,
159-
list[str],
160-
bool | None,
161-
dict,
162-
str,
163-
str,
164-
str | None,
165-
list[str],
166-
str | None,
167-
str,
168-
]:
174+
) -> EvergreenConfig:
169175
"""
170176
Get the environment variables for use in the action.
171177
172178
Args:
173-
None
179+
test: If True, skip loading from .env file.
174180
175181
Returns:
176-
organization (str): The organization to search for repositories in
177-
repository_list (list[str]): A list of repositories to search for
178-
search_query (str): A search query string to filter repositories by
179-
gh_app_id (int | None): The GitHub App ID to use for authentication
180-
gh_app_installation_id (int | None): The GitHub App Installation ID to use for authentication
181-
gh_app_private_key_bytes (bytes): The GitHub App Private Key as bytes to use for authentication
182-
gh_app_enterprise_only (bool): Set this to true if the GH APP is created on GHE and needs to communicate with GHE api only
183-
token (str): The GitHub token to use for authentication
184-
ghe (str): The GitHub Enterprise URL to use for authentication
185-
exempt_repositories_list (list[str]): A list of repositories to exempt from the action
186-
follow_up_type (str): The type of follow up to open (issue or pull)
187-
title (str): The title of the follow up
188-
body (str): The body of the follow up
189-
created_after_date (str): The date to filter repositories by
190-
dry_run (bool): Whether or not to actually open issues/pull requests
191-
commit_message (str): The commit message of the follow up
192-
group_dependencies (bool): Whether to group dependencies in the dependabot.yml file
193-
filter_visibility (list[str]): Run the action only on repositories with the specified listed visibility
194-
batch_size (int): The max number of repositories in scope
195-
enable_security_updates (bool): Whether to enable security updates in target repositories
196-
exempt_ecosystems_list (list[str]): A list of package ecosystems to exempt from the action
197-
update_existing (bool): Whether to update existing dependabot configuration files
198-
repo_specific_exemptions (dict): A dictionary of per repository ecosystem exemptions
199-
schedule (str): The schedule to run the action on
200-
schedule_day (str): The day of the week to run the action on if schedule is daily
201-
team_name (str): The team to search for repositories in
202-
labels (list[str]): A list of labels to be added to dependabot configuration
203-
dependabot_config_file (str): Dependabot extra configuration file location path
204-
ghe_api_url (str): The full GitHub Enterprise API endpoint URL override
182+
EvergreenConfig: A frozen dataclass containing all configuration values.
205183
"""
206184

207185
if not test: # pragma: no cover
@@ -404,35 +382,35 @@ def get_env_vars(
404382
f"No dependabot extra configuration found. Please create one in {dependabot_config_file}"
405383
)
406384

407-
return (
408-
organization,
409-
repositories_list,
410-
search_query,
411-
gh_app_id,
412-
gh_app_installation_id,
413-
gh_app_private_key_bytes,
414-
gh_app_enterprise_only,
415-
token,
416-
ghe,
417-
exempt_repositories_list,
418-
follow_up_type,
419-
title,
420-
body,
421-
created_after_date,
422-
dry_run_bool,
423-
commit_message,
424-
project_id,
425-
group_dependencies_bool,
426-
filter_visibility_list,
427-
batch_size,
428-
enable_security_updates_bool,
429-
exempt_ecosystems_list,
430-
update_existing,
431-
repo_specific_exemptions,
432-
schedule,
433-
schedule_day,
434-
team_name,
435-
labels_list,
436-
dependabot_config_file,
437-
ghe_api_url,
385+
return EvergreenConfig(
386+
organization=organization,
387+
repository_list=repositories_list,
388+
search_query=search_query,
389+
gh_app_id=gh_app_id,
390+
gh_app_installation_id=gh_app_installation_id,
391+
gh_app_private_key_bytes=gh_app_private_key_bytes,
392+
gh_app_enterprise_only=gh_app_enterprise_only,
393+
token=token,
394+
ghe=ghe,
395+
ghe_api_url=ghe_api_url,
396+
exempt_repositories_list=exempt_repositories_list,
397+
follow_up_type=follow_up_type,
398+
title=title,
399+
body=body,
400+
created_after_date=created_after_date,
401+
dry_run=dry_run_bool,
402+
commit_message=commit_message,
403+
project_id=project_id,
404+
group_dependencies=group_dependencies_bool,
405+
filter_visibility=filter_visibility_list,
406+
batch_size=batch_size,
407+
enable_security_updates=enable_security_updates_bool,
408+
exempt_ecosystems=exempt_ecosystems_list,
409+
update_existing=update_existing,
410+
repo_specific_exemptions=repo_specific_exemptions,
411+
schedule=schedule,
412+
schedule_day=schedule_day,
413+
team_name=team_name,
414+
labels=labels_list,
415+
dependabot_config_file=dependabot_config_file,
438416
)

0 commit comments

Comments
 (0)