diff --git a/.github/linters/.isort.cfg b/.github/linters/.isort.cfg index c76db01..81e7324 100644 --- a/.github/linters/.isort.cfg +++ b/.github/linters/.isort.cfg @@ -1,2 +1,3 @@ -[isort] +[settings] profile = black +known_first_party = auth,dependabot_file,env,evergreen,exceptions diff --git a/.github/workflows/super-linter.yaml b/.github/workflows/super-linter.yaml index 97df767..a01db26 100644 --- a/.github/workflows/super-linter.yaml +++ b/.github/workflows/super-linter.yaml @@ -41,7 +41,7 @@ jobs: run: | uv sync --frozen - name: Lint Code Base - uses: super-linter/super-linter@4ce20838b8ab83717e78138c5b3a1407148e0918 # v8.7.0 + uses: super-linter/super-linter@2da136927bd4a73596db63044b504547c62cb854 # v9.0.0 env: DEFAULT_BRANCH: main GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile b/Dockerfile index 13def6c..255d6e7 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,7 +16,7 @@ RUN uv sync --frozen --no-dev --no-editable \ # Add a simple healthcheck to satisfy container scanners HEALTHCHECK --interval=30s --timeout=10s --start-period=10s --retries=3 \ - CMD python3 -c "import os,sys; sys.exit(0 if os.path.exists('/action/workspace/evergreen.py') else 1)" + CMD ["python3", "-c", "import os,sys; sys.exit(0 if os.path.exists('/action/workspace/evergreen.py') else 1)"] ENV PYTHONUNBUFFERED=1 ENV UV_LINK_MODE=copy diff --git a/auth.py b/auth.py index c3daf5d..6c5ba34 100644 --- a/auth.py +++ b/auth.py @@ -1,8 +1,9 @@ """This is the module that contains functions related to authenticating to GitHub with a personal access token.""" -import env from github import Auth, Github, GithubException, GithubIntegration +import env + def auth_to_github( token: str, diff --git a/dependabot_file.py b/dependabot_file.py index 8e8c814..5b16379 100644 --- a/dependabot_file.py +++ b/dependabot_file.py @@ -6,10 +6,11 @@ from collections.abc import Mapping import ruamel.yaml -from exceptions import OptionalFileNotFoundError, check_optional_file from github import UnknownObjectException from ruamel.yaml.scalarstring import SingleQuotedScalarString +from exceptions import OptionalFileNotFoundError, check_optional_file + # Define data structure for dependabot.yaml data = { "version": 2, @@ -67,7 +68,9 @@ def validate_cooldown_config(cooldown): ValueError: if the cooldown configuration is invalid """ if not isinstance(cooldown, Mapping): - raise ValueError("Cooldown configuration must be a mapping") + raise ValueError( # noqa: TRY004 - callers catch ValueError + "Cooldown configuration must be a mapping" + ) unknown_keys = set(cooldown.keys()) - VALID_COOLDOWN_KEYS if unknown_keys: @@ -109,7 +112,9 @@ def validate_cooldown_config(cooldown): ) for item in items: if not isinstance(item, str): - raise ValueError(f"Cooldown '{list_key}' items must be strings") + raise ValueError( # noqa: TRY004 - callers catch ValueError + f"Cooldown '{list_key}' items must be strings" + ) def make_dependabot_config( diff --git a/env.py b/env.py index 7d1a8ab..d71b45d 100644 --- a/env.py +++ b/env.py @@ -276,7 +276,7 @@ def get_env_vars( "Here's an example of the code:" ), } - body = body = default_bodies[follow_up_type] + body = default_bodies[follow_up_type] commit_message = os.getenv("COMMIT_MESSAGE") if commit_message: @@ -313,7 +313,7 @@ def get_env_vars( "FILTER_VISIBILITY environment variable not 'public', 'private', or 'internal'" ) filter_visibility_set.add(visibility.strip().lower()) - filter_visibility_list = sorted(list(filter_visibility_set)) + filter_visibility_list = sorted(filter_visibility_set) else: filter_visibility_list = sorted(["public", "private", "internal"]) # all diff --git a/evergreen.py b/evergreen.py index 200d374..64fd83d 100644 --- a/evergreen.py +++ b/evergreen.py @@ -3,15 +3,16 @@ import io import sys import uuid -from datetime import datetime +from datetime import datetime, timezone -import auth -import env import requests import ruamel.yaml +from github import UnknownObjectException + +import auth +import env from dependabot_file import build_dependabot_file, validate_cooldown_config from exceptions import OptionalFileNotFoundError, check_optional_file -from github import UnknownObjectException def main(): # pragma: no cover @@ -211,13 +212,15 @@ def main(): # pragma: no cover continue # Get dependabot security updates enabled if possible - if config.enable_security_updates: - if not is_dependabot_security_updates_enabled( + if ( + config.enable_security_updates + and not is_dependabot_security_updates_enabled( + config.ghe, config.ghe_api_url, repo.owner.login, repo.name, token + ) + ): + enable_dependabot_security_updates( config.ghe, config.ghe_api_url, repo.owner.login, repo.name, token - ): - enable_dependabot_security_updates( - config.ghe, config.ghe_api_url, repo.owner.login, repo.name, token - ) + ) if config.follow_up_type == "issue": skip = check_pending_issues_for_duplicates(config.title, repo) @@ -294,8 +297,8 @@ def main(): # pragma: no cover print("\tFailed to create pull request. Check write permissions.") continue - print(f"Done. {str(count_eligible)} repositories were eligible.") - print(f"{str(count_prs_created)} pull requests were created.") + print(f"Done. {count_eligible!s} repositories were eligible.") + print(f"{count_prs_created!s} pull requests were created.") # Append the summary content to the GitHub step summary file append_to_github_summary(summary_content) @@ -305,14 +308,14 @@ def is_repo_created_date_before( ): """Check if the repository was created before the created_after_date""" if isinstance(repo_created_at, datetime): - repo_created_at_date = repo_created_at.replace(tzinfo=None) + repo_created_at_date = repo_created_at.replace(tzinfo=timezone.utc) else: repo_created_at_date = datetime.fromisoformat(repo_created_at).replace( - tzinfo=None + tzinfo=timezone.utc ) return created_after_date and repo_created_at_date < datetime.strptime( created_after_date, "%Y-%m-%d" - ) + ).replace(tzinfo=timezone.utc) def is_dependabot_security_updates_enabled(ghe, ghe_api_url, owner, repo, access_token): diff --git a/test_auth.py b/test_auth.py index 4393bf4..b16a381 100644 --- a/test_auth.py +++ b/test_auth.py @@ -3,9 +3,10 @@ import unittest from unittest.mock import MagicMock, patch -import auth from github import GithubException +import auth + class TestAuth(unittest.TestCase): """ diff --git a/test_cooldown.py b/test_cooldown.py index 30b7a57..b560561 100644 --- a/test_cooldown.py +++ b/test_cooldown.py @@ -2,9 +2,10 @@ import unittest -from dependabot_file import validate_cooldown_config from ruamel.yaml import YAML +from dependabot_file import validate_cooldown_config + class TestValidateCooldownConfig(unittest.TestCase): """Test the validate_cooldown_config function.""" diff --git a/test_dependabot_file.py b/test_dependabot_file.py index f3f5285..b971ea5 100644 --- a/test_dependabot_file.py +++ b/test_dependabot_file.py @@ -7,9 +7,10 @@ from unittest.mock import MagicMock, patch import ruamel.yaml -from dependabot_file import add_existing_ecosystem_to_exempt_list, build_dependabot_file from github import UnknownObjectException +from dependabot_file import add_existing_ecosystem_to_exempt_list, build_dependabot_file + yaml = ruamel.yaml.YAML() @@ -492,7 +493,7 @@ def test_build_dependabot_file_with_terraform_without_files(self): repo = MagicMock() # Test absence of Terraform files - repo.get_contents.side_effect = lambda path: [] if path == "/" else [] + repo.get_contents.side_effect = lambda path: [] result = build_dependabot_file( repo, False, [], {}, None, "weekly", "", [], None ) diff --git a/test_evergreen.py b/test_evergreen.py index 93342ff..9781d40 100644 --- a/test_evergreen.py +++ b/test_evergreen.py @@ -7,6 +7,8 @@ from unittest.mock import MagicMock, patch import requests +from github import UnknownObjectException + from evergreen import ( append_to_github_summary, check_existing_config, @@ -22,7 +24,6 @@ is_repo_created_date_before, link_item_to_project, ) -from github import UnknownObjectException class TestDependabotSecurityUpdates(unittest.TestCase): diff --git a/test_exceptions.py b/test_exceptions.py index 709fd9d..7400fcb 100644 --- a/test_exceptions.py +++ b/test_exceptions.py @@ -3,9 +3,10 @@ import unittest from unittest.mock import Mock -from exceptions import OptionalFileNotFoundError, check_optional_file from github import UnknownObjectException +from exceptions import OptionalFileNotFoundError, check_optional_file + class TestOptionalFileNotFoundError(unittest.TestCase): """Test the OptionalFileNotFoundError exception.""" @@ -31,7 +32,7 @@ def test_can_catch_as_unknown_object_exception(self): raise OptionalFileNotFoundError(status=404, data="Not Found") except UnknownObjectException as e: self.assertIsInstance(e, OptionalFileNotFoundError) - except Exception: # pylint: disable=broad-exception-caught + except Exception: # noqa: BLE001 # pylint: disable=broad-exception-caught self.fail( "OptionalFileNotFoundError should be catchable as UnknownObjectException" ) @@ -42,7 +43,7 @@ def test_can_catch_specifically(self): raise OptionalFileNotFoundError(status=404, data="Not Found") except OptionalFileNotFoundError as e: self.assertIsInstance(e, OptionalFileNotFoundError) - except Exception: # pylint: disable=broad-exception-caught + except Exception: # noqa: BLE001 # pylint: disable=broad-exception-caught self.fail("OptionalFileNotFoundError should be catchable specifically") def test_optional_file_not_found_error_properties(self): @@ -106,7 +107,7 @@ def test_check_optional_file_can_catch_as_unknown_object_exception(self): check_optional_file(mock_repo, "missing.yml") except UnknownObjectException as e: self.assertIsInstance(e, OptionalFileNotFoundError) - except Exception: # pylint: disable=broad-exception-caught + except Exception: # noqa: BLE001 # pylint: disable=broad-exception-caught self.fail( "Should be able to catch OptionalFileNotFoundError as UnknownObjectException" )