diff --git a/README.md b/README.md index bca8e30..957b33a 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,8 @@ This action can be configured to authenticate with GitHub App Installation or Pe | `ENABLE_SECURITY_UPDATES` | False | true | If set to true, Evergreen will enable [Dependabot security updates](https://docs.github.com/en/code-security/dependabot/dependabot-security-updates/configuring-dependabot-security-updates) on target repositories. Note that the GitHub token needs to have the `administration:write` permission on every repository in scope to successfully enable security updates. | | `EXEMPT_ECOSYSTEMS` | False | "" | A list of [package ecosystems](https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#package-ecosystem) to exempt from the generated dependabot configuration. To ignore ecosystems set this to one or more of `bundler`,`cargo`, `composer`, `pip`, `docker`, `npm`, `gomod`, `mix`, `nuget`, `github-actions` and `terraform`. ex: if you don't want Dependabot to update Dockerfiles and Github Actions you can set this to `docker,github-actions`. | | `REPO_SPECIFIC_EXEMPTIONS` | False | "" | A list of repositories that should be exempt from specific package ecosystems similar to EXEMPT_ECOSYSTEMS but those apply to all repositories. ex: `org1/repo1:docker,github-actions;org1/repo2:pip` would set exempt_ecosystems for `org1/repo1` to be `['docker', 'github-actions']`, and for `org1/repo2` it would be `['pip']`, while for every other repository evaluated, it would be set by the env variable `EXEMPT_ECOSYSTEMS`. NOTE: If you want specific exemptions to be added on top of the already specified global exemptions, you need to add the global exemptions to each repo specific exemption. | +| `SCHEDULE` | False | 'weekly' | Schedule interval by which to check for dependency updates via Dependabot. Allowed values are 'daily', 'weekly', or 'monthly' | +| `SCHEDULE_DAY` | False | '' | Scheduled day by which to check for dependency updates via Dependabot. Allowed values are days of the week full names (i.e., 'monday') | ### Example workflows diff --git a/dependabot_file.py b/dependabot_file.py index d0b406f..3d280f0 100644 --- a/dependabot_file.py +++ b/dependabot_file.py @@ -4,7 +4,9 @@ import yaml -def make_dependabot_config(ecosystem, group_dependencies, indent) -> str: +def make_dependabot_config( + ecosystem, group_dependencies, indent, schedule, schedule_day +) -> str: """ Make the dependabot configuration for a specific package ecosystem @@ -12,15 +14,23 @@ def make_dependabot_config(ecosystem, group_dependencies, indent) -> str: ecosystem: the package ecosystem to make the dependabot configuration for group_dependencies: whether to group dependencies in the dependabot.yml file indent: the number of spaces to indent the dependabot configuration ex: " " + schedule: the schedule to run dependabot ex: "daily" + schedule_day: the day of the week to run dependabot ex: "monday" if schedule is "daily" Returns: str: the dependabot configuration for the package ecosystem """ + schedule_day_line = "" + if schedule_day: + schedule_day_line += f""" +{indent}{indent}{indent}day: '{schedule_day}'""" + dependabot_config = f"""{indent}- package-ecosystem: '{ecosystem}' {indent}{indent}directory: '/' {indent}{indent}schedule: -{indent}{indent}{indent}interval: 'weekly' +{indent}{indent}{indent}interval: '{schedule}'{schedule_day_line} """ + if group_dependencies: dependabot_config += f"""{indent}{indent}groups: {indent}{indent}{indent}production-dependencies: @@ -37,6 +47,8 @@ def build_dependabot_file( exempt_ecosystems, repo_specific_exemptions, existing_config, + schedule, + schedule_day, ) -> str | None: """ Build the dependabot.yml file for a repo based on the repo contents @@ -47,6 +59,8 @@ def build_dependabot_file( exempt_ecosystems: the list of ecosystems to ignore repo_specific_exemptions: the list of ecosystems to ignore for a specific repo existing_config: the existing dependabot configuration file or None if it doesn't exist + schedule: the schedule to run dependabot ex: "daily" + schedule_day: the day of the week to run dependabot ex: "monday" if schedule is "daily" Returns: str: the dependabot.yml file for the repo @@ -126,7 +140,7 @@ def build_dependabot_file( if repo.file_contents(file): package_managers_found[manager] = True dependabot_file += make_dependabot_config( - manager, group_dependencies, indent + manager, group_dependencies, indent, schedule, schedule_day ) break except github3.exceptions.NotFoundError: @@ -139,7 +153,7 @@ def build_dependabot_file( if file[0].endswith(".tf"): package_managers_found["terraform"] = True dependabot_file += make_dependabot_config( - "terraform", group_dependencies, indent + "terraform", group_dependencies, indent, schedule, schedule_day ) break except github3.exceptions.NotFoundError: @@ -150,7 +164,11 @@ def build_dependabot_file( if file[0].endswith(".yml") or file[0].endswith(".yaml"): package_managers_found["github-actions"] = True dependabot_file += make_dependabot_config( - "github-actions", group_dependencies, indent + "github-actions", + group_dependencies, + indent, + schedule, + schedule_day, ) break except github3.exceptions.NotFoundError: diff --git a/env.py b/env.py index 05053a8..4facb77 100644 --- a/env.py +++ b/env.py @@ -90,7 +90,9 @@ def parse_repo_specific_exemptions(repo_specific_exemptions_str: str) -> dict: return exemptions_dict -def get_env_vars(test: bool = False) -> tuple[ +def get_env_vars( + test: bool = False, +) -> tuple[ str | None, list[str], int | None, @@ -113,6 +115,8 @@ def get_env_vars(test: bool = False) -> tuple[ list[str], bool | None, dict, + str, + str, ]: """ Get the environment variables for use in the action. @@ -142,6 +146,8 @@ def get_env_vars(test: bool = False) -> tuple[ exempt_ecosystems_list (list[str]): A list of package ecosystems to exempt from the action update_existing (bool): Whether to update existing dependabot configuration files repo_specific_exemptions (dict): A dictionary of per repository ecosystem exemptions + schedule (str): The schedule to run the action on + schedule_day (str): The day of the week to run the action on if schedule is daily """ if not test: @@ -288,6 +294,36 @@ def get_env_vars(test: bool = False) -> tuple[ repo_specific_exemptions_str ) + schedule = os.getenv("SCHEDULE", "").strip().lower() + if schedule and schedule not in ["daily", "weekly", "monthly"]: + raise ValueError( + "SCHEDULE environment variable not 'daily', 'weekly', or 'monthly'" + ) + if not schedule: + schedule = "weekly" + schedule_day = os.getenv("SCHEDULE_DAY", "").strip().lower() + if schedule != "weekly" and schedule_day: + raise ValueError( + "SCHEDULE_DAY environment variable not needed when SCHEDULE is not 'weekly'" + ) + if ( + schedule == "weekly" + and schedule_day + and schedule_day + not in [ + "monday", + "tuesday", + "wednesday", + "thursday", + "friday", + "saturday", + "sunday", + ] + ): + raise ValueError( + "SCHEDULE_DAY environment variable not 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', or 'sunday'" + ) + return ( organization, repositories_list, @@ -311,4 +347,6 @@ def get_env_vars(test: bool = False) -> tuple[ exempt_ecosystems_list, update_existing, repo_specific_exemptions, + schedule, + schedule_day, ) diff --git a/evergreen.py b/evergreen.py index f5b5e6a..ba64f49 100644 --- a/evergreen.py +++ b/evergreen.py @@ -37,6 +37,8 @@ def main(): # pragma: no cover exempt_ecosystems, update_existing, repo_specific_exemptions, + schedule, + schedule_day, ) = env.get_env_vars() # Auth to GitHub.com or GHE @@ -110,6 +112,8 @@ def main(): # pragma: no cover exempt_ecosystems, repo_specific_exemptions, existing_config, + schedule, + schedule_day, ) if dependabot_file is None: diff --git a/test_dependabot_file.py b/test_dependabot_file.py index 9c4e427..fc078fe 100644 --- a/test_dependabot_file.py +++ b/test_dependabot_file.py @@ -20,9 +20,30 @@ def test_not_found_error(self): response.status_code = 404 repo.file_contents.side_effect = github3.exceptions.NotFoundError(resp=response) - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "", "") self.assertEqual(result, None) + def test_build_dependabot_file_with_schedule_day(self): + """Test that the dependabot.yml file is built correctly with weekly schedule day""" + repo = MagicMock() + filename_list = ["Gemfile", "Gemfile.lock"] + + for filename in filename_list: + repo.file_contents.side_effect = lambda f, filename=filename: f == filename + expected_result = """--- +version: 2 +updates: + - package-ecosystem: 'bundler' + directory: '/' + schedule: + interval: 'weekly' + day: 'tuesday' +""" + result = build_dependabot_file( + repo, False, [], {}, None, "weekly", "tuesday" + ) + self.assertEqual(result, expected_result) + def test_build_dependabot_file_with_bundler(self): """Test that the dependabot.yml file is built correctly with bundler""" repo = MagicMock() @@ -38,7 +59,7 @@ def test_build_dependabot_file_with_bundler(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_existing_config_bundler_no_update(self): @@ -51,7 +72,9 @@ def test_build_dependabot_file_with_existing_config_bundler_no_update(self): existing_config = MagicMock() existing_config.decoded = b'---\nversion: 2\nupdates:\n - package-ecosystem: "bundler"\n\ directory: "/"\n schedule:\n interval: "weekly"\n commit-message:\n prefix: "chore(deps)"\n' - result = build_dependabot_file(repo, False, [], {}, existing_config) + result = build_dependabot_file( + repo, False, [], {}, existing_config, "weekly", "" + ) self.assertEqual(result, expected_result) def test_build_dependabot_file_with_2_space_indent_existing_config_bundler_with_update( @@ -80,7 +103,9 @@ def test_build_dependabot_file_with_2_space_indent_existing_config_bundler_with_ existing_config = MagicMock() existing_config.decoded = b'---\nversion: 2\nupdates:\n - package-ecosystem: "pip"\n directory: "/"\n\ schedule:\n interval: "weekly"\n commit-message:\n prefix: "chore(deps)"\n' - result = build_dependabot_file(repo, False, [], {}, existing_config) + result = build_dependabot_file( + repo, False, [], {}, existing_config, "weekly", "" + ) self.assertEqual(result, expected_result) def test_build_dependabot_file_with_weird_space_indent_existing_config_bundler_with_update( @@ -95,7 +120,9 @@ def test_build_dependabot_file_with_weird_space_indent_existing_config_bundler_w existing_config = MagicMock() existing_config.decoded = b'---\nversion: 2\nupdates:\n- package-ecosystem: "pip"\n directory: "/"\n\ schedule:\n interval: "weekly"\n commit-message:\n prefix: "chore(deps)"\n' - result = build_dependabot_file(repo, False, [], {}, existing_config) + result = build_dependabot_file( + repo, False, [], {}, existing_config, "weekly", "" + ) self.assertEqual(result, None) def test_build_dependabot_file_with_npm(self): @@ -113,7 +140,7 @@ def test_build_dependabot_file_with_npm(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_pip(self): @@ -137,7 +164,7 @@ def test_build_dependabot_file_with_pip(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_cargo(self): @@ -158,7 +185,7 @@ def test_build_dependabot_file_with_cargo(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_gomod(self): @@ -174,7 +201,7 @@ def test_build_dependabot_file_with_gomod(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_composer(self): @@ -195,7 +222,7 @@ def test_build_dependabot_file_with_composer(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_hex(self): @@ -216,7 +243,7 @@ def test_build_dependabot_file_with_hex(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_nuget(self): @@ -232,7 +259,7 @@ def test_build_dependabot_file_with_nuget(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_docker(self): @@ -248,7 +275,7 @@ def test_build_dependabot_file_with_docker(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_terraform_with_files(self): @@ -269,7 +296,7 @@ def test_build_dependabot_file_with_terraform_with_files(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_terraform_without_files(self): @@ -281,7 +308,7 @@ def test_build_dependabot_file_with_terraform_without_files(self): # Test absence of Terraform files repo.directory_contents.side_effect = lambda path: [] if path == "/" else [] - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertIsNone(result) # Test empty repository @@ -290,7 +317,7 @@ def test_build_dependabot_file_with_terraform_without_files(self): repo.directory_contents.side_effect = github3.exceptions.NotFoundError( resp=response ) - result = build_dependabot_file(repo, False, [], {}, None) + result = build_dependabot_file(repo, False, [], {}, None, "weekly", "") self.assertIsNone(result) def test_build_dependabot_file_with_github_actions(self): @@ -311,7 +338,7 @@ def test_build_dependabot_file_with_github_actions(self): schedule: interval: 'weekly' """ - result = build_dependabot_file(repo, False, [], None, None) + result = build_dependabot_file(repo, False, [], None, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_github_actions_without_files(self): @@ -324,7 +351,7 @@ def test_build_dependabot_file_with_github_actions_without_files(self): resp=response ) - result = build_dependabot_file(repo, False, [], None, None) + result = build_dependabot_file(repo, False, [], None, None, "weekly", "") self.assertEqual(result, None) def test_build_dependabot_file_with_groups(self): @@ -345,7 +372,7 @@ def test_build_dependabot_file_with_groups(self): development-dependencies: dependency-type: 'development' """ - result = build_dependabot_file(repo, True, [], {}, None) + result = build_dependabot_file(repo, True, [], {}, None, "weekly", "") self.assertEqual(result, expected_result) def test_build_dependabot_file_with_exempt_ecosystems(self): @@ -353,7 +380,7 @@ def test_build_dependabot_file_with_exempt_ecosystems(self): repo = MagicMock() repo.file_contents.side_effect = lambda filename: filename == "Dockerfile" - result = build_dependabot_file(repo, False, ["docker"], {}, None) + result = build_dependabot_file(repo, False, ["docker"], {}, None, "weekly", "") self.assertEqual(result, None) def test_build_dependabot_file_with_repo_specific_exempt_ecosystems(self): @@ -362,7 +389,9 @@ def test_build_dependabot_file_with_repo_specific_exempt_ecosystems(self): repo.full_name = "test/test" repo.file_contents.side_effect = lambda filename: filename == "Dockerfile" - result = build_dependabot_file(repo, False, [], {"test/test": ["docker"]}, None) + result = build_dependabot_file( + repo, False, [], {"test/test": ["docker"]}, None, "weekly", "" + ) self.assertEqual(result, None) def test_add_existing_ecosystem_to_exempt_list(self): @@ -401,7 +430,13 @@ def test_build_dependabot_file_for_multiple_repos_with_few_existing_config(self) directory: "/"\n schedule:\n interval: "weekly"\n commit-message:\n prefix: "chore(deps)"\n' exempt_ecosystems = [] result = build_dependabot_file( - existing_config_repo, False, exempt_ecosystems, {}, existing_config + existing_config_repo, + False, + exempt_ecosystems, + {}, + existing_config, + "weekly", + "", ) self.assertEqual(result, None) @@ -420,7 +455,7 @@ def test_build_dependabot_file_for_multiple_repos_with_few_existing_config(self) interval: 'weekly' """ result = build_dependabot_file( - no_existing_config_repo, False, exempt_ecosystems, {}, None + no_existing_config_repo, False, exempt_ecosystems, {}, None, "weekly", "" ) self.assertEqual(result, expected_result) @@ -440,7 +475,9 @@ def test_check_multiple_repos_with_no_dependabot_config(self): interval: 'weekly' """ exempt_ecosystems = [] - result = build_dependabot_file(mock_repo_1, False, exempt_ecosystems, {}, None) + result = build_dependabot_file( + mock_repo_1, False, exempt_ecosystems, {}, None, "weekly", "" + ) self.assertEqual(result, expected_result) no_existing_config_repo = MagicMock() @@ -458,7 +495,7 @@ def test_check_multiple_repos_with_no_dependabot_config(self): interval: 'weekly' """ result = build_dependabot_file( - no_existing_config_repo, False, exempt_ecosystems, {}, None + no_existing_config_repo, False, exempt_ecosystems, {}, None, "weekly", "" ) self.assertEqual(result, expected_result) diff --git a/test_env.py b/test_env.py index 5a918b1..9036a9a 100644 --- a/test_env.py +++ b/test_env.py @@ -1,3 +1,5 @@ +# pylint: disable=too-many-public-methods + """Test the get_env_vars function""" import os @@ -29,6 +31,8 @@ def setUp(self): "TYPE", "UPDATE_EXISTING", "REPO_SPECIFIC_EXEMPTIONS", + "SCHEDULE", + "SCHEDULE_DAY", ] for key in env_keys: if key in os.environ: @@ -75,6 +79,8 @@ def test_get_env_vars_with_org(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -124,6 +130,8 @@ def test_get_env_vars_with_org_and_repo_specific_exemptions(self): "repo1": ["gomod"], "repo2": ["docker", "gomod"], }, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -230,6 +238,8 @@ def test_get_env_vars_with_repos(self): "org1/repo1": ["docker"], "org2/repo2": ["gomod"], }, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -269,6 +279,8 @@ def test_get_env_vars_optional_values(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -309,6 +321,8 @@ def test_get_env_vars_with_update_existing(self): [], # exempt_ecosystems True, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -363,6 +377,8 @@ def test_get_env_vars_auth_with_github_app_installation(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -425,6 +441,8 @@ def test_get_env_vars_with_repos_no_dry_run(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -465,6 +483,8 @@ def test_get_env_vars_with_repos_disabled_security_updates(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -506,6 +526,8 @@ def test_get_env_vars_with_repos_filter_visibility_multiple_values(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -547,6 +569,8 @@ def test_get_env_vars_with_repos_filter_visibility_single_value(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -618,6 +642,8 @@ def test_get_env_vars_with_repos_filter_visibility_no_duplicates(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -660,6 +686,8 @@ def test_get_env_vars_with_repos_exempt_ecosystems(self): ["gomod", "docker"], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -701,6 +729,8 @@ def test_get_env_vars_with_no_batch_size(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -743,6 +773,8 @@ def test_get_env_vars_with_batch_size(self): [], # exempt_ecosystems False, # update_existing {}, # repo_specific_exemptions + "weekly", # schedule + "", # schedule_day ) result = get_env_vars(True) self.assertEqual(result, expected_result) @@ -789,7 +821,7 @@ def test_get_env_vars_with_invalid_batch_size_str(self): clear=True, ) def test_get_env_vars_with_badly_formatted_created_after_date(self): - """Test that""" + """Test that badly formatted CREATED_AFTER_DATE throws exception""" with self.assertRaises(ValueError) as context_manager: get_env_vars(True) the_exception = context_manager.exception @@ -798,6 +830,45 @@ def test_get_env_vars_with_badly_formatted_created_after_date(self): "CREATED_AFTER_DATE '20200101' environment variable not in YYYY-MM-DD", ) + @patch.dict( + os.environ, + { + "ORGANIZATION": "my_organization", + "GH_TOKEN": "my_token", + "SCHEDULE": "annually", + }, + clear=True, + ) + def test_get_env_vars_with_bad_schedule_choice(self): + """Test that bad schedule choice throws exception""" + with self.assertRaises(ValueError) as context_manager: + get_env_vars(True) + the_exception = context_manager.exception + self.assertEqual( + str(the_exception), + "SCHEDULE environment variable not 'daily', 'weekly', or 'monthly'", + ) + + @patch.dict( + os.environ, + { + "ORGANIZATION": "my_organization", + "GH_TOKEN": "my_token", + "SCHEDULE": "weekly", + "SCHEDULE_DAY": "thorsday", + }, + clear=True, + ) + def test_get_env_vars_with_bad_schedule_day_choice(self): + """Test that bad schedule day choice throws exception""" + with self.assertRaises(ValueError) as context_manager: + get_env_vars(True) + the_exception = context_manager.exception + self.assertEqual( + str(the_exception), + "SCHEDULE_DAY environment variable not 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', or 'sunday'", + ) + if __name__ == "__main__": unittest.main()