diff --git a/README.md b/README.md index 7241e3a..0d3b86b 100644 --- a/README.md +++ b/README.md @@ -74,9 +74,8 @@ jobs: # [Optional] Allows customizing the pull request title # defaults to 'Update GitHub Action Versions' pull_request_title: 'Pull Request Title' - # [Optional] Do not update actions specified in this input - # You need to add JSON array inside a string. e.g: '["actions/checkout@v2", "actions/cache@v2"]' - # Or, add comma separated values. e.g: 'actions/checkout@v2, actions/cache@v2' + # [Optional] A comma separated string of GitHub Actions to ignore updates for. + # e.g: 'actions/checkout@v2, actions/cache@v2' ignore: 'actions/checkout@v2, actions/cache@v2' # [Optional] If set to 'true', the action will only check for updates and # exit with a non-zero exit code if an update is found and update the build summary with the diff @@ -86,6 +85,12 @@ jobs: # [Optional] Use The Latest Release Tag/Commit SHA or Default Branch Commit SHA to update the actions # options: "release-tag" (default), "release-commit-sha", "default-branch-sha"' update_version_with: 'release-tag' + # [Optional] A comma separated string (usernames) which denotes the users + # that should be added as reviewers to the pull request + pull_request_user_reviewers: "octocat, hubot, other_user" + # [Optional] A comma separated string (team slugs) which denotes the teams + # that should be added as reviewers to the pull request + pull_request_team_reviewers: "justice-league, other_team" ``` ### Important Note: diff --git a/action.yaml b/action.yaml index 783b0f3..435c391 100644 --- a/action.yaml +++ b/action.yaml @@ -36,6 +36,14 @@ inputs: description: 'Use Latest Release Tag/Commit SHA or Default Branch Commit SHA to update. options: "release-tag" (default), "release-commit-sha", "default-branch-sha"' required: false default: 'release-tag' + pull_request_user_reviewers: + description: 'A comma separated string (usernames) which denotes the users that should be added as reviewers to the pull request' + required: false + default: '' + pull_request_team_reviewers: + description: 'A comma separated string (team slugs) which denotes the teams that should be added as reviewers to the pull request' + required: false + default: '' runs: using: 'docker' image: 'Dockerfile' diff --git a/src/config.py b/src/config.py index 7bad5e5..f67abd3 100644 --- a/src/config.py +++ b/src/config.py @@ -40,6 +40,8 @@ class Configuration(NamedTuple): commit_message: str = "Update GitHub Action Versions" ignore_actions: set[str] = set() update_version_with: str = LATEST_RELEASE_TAG + pull_request_user_reviewers: set[str] = set() + pull_request_team_reviewers: set[str] = set() @property def git_commit_author(self) -> str: @@ -70,6 +72,8 @@ def get_user_config(cls, env: Mapping[str, str | None]) -> dict[str, str | None] "commit_message": env.get("INPUT_COMMIT_MESSAGE"), "ignore_actions": env.get("INPUT_IGNORE"), "update_version_with": env.get("INPUT_UPDATE_VERSION_WITH"), + "pull_request_user_reviewers": env.get("INPUT_PULL_REQUEST_USER_REVIEWERS"), + "pull_request_team_reviewers": env.get("INPUT_PULL_REQUEST_TEAM_REVIEWERS"), } return user_config @@ -102,10 +106,22 @@ def clean_ignore_actions(value: Any) -> set[str] | None: ) raise SystemExit(1) elif value and isinstance(value, str): - return {s.strip() for s in value.split(",")} + return {s.strip() for s in value.strip().split(",") if s} else: return None + @staticmethod + def clean_pull_request_user_reviewers(value: Any) -> set[str] | None: + if value and isinstance(value, str): + return {s.strip() for s in value.strip().split(",") if s} + return None + + @staticmethod + def clean_pull_request_team_reviewers(value: Any) -> set[str] | None: + if value and isinstance(value, str): + return {s.strip() for s in value.strip().split(",") if s} + return None + @staticmethod def clean_skip_pull_request(value: Any) -> bool | None: if value in [1, "1", True, "true", "True"]: diff --git a/src/main.py b/src/main.py index 153c8bd..57c256b 100644 --- a/src/main.py +++ b/src/main.py @@ -24,6 +24,7 @@ ) from .utils import ( add_git_diff_to_job_summary, + add_pull_request_reviewers, create_pull_request, display_whats_new, get_request_headers, @@ -139,7 +140,7 @@ def run(self) -> None: self.user_config.git_commit_author, new_branch_name, ) - create_pull_request( + pull_request_number = create_pull_request( self.user_config.pull_request_title, self.env.repository, self.env.base_branch, @@ -147,6 +148,13 @@ def run(self) -> None: pull_request_body, self.user_config.github_token, ) + add_pull_request_reviewers( + self.env.repository, + pull_request_number, + self.user_config.pull_request_user_reviewers, + self.user_config.pull_request_team_reviewers, + self.user_config.github_token, + ) else: add_git_diff_to_job_summary() gha_utils.error( @@ -209,7 +217,7 @@ def _get_latest_version_release(self, action_repository: str) -> dict[str, str]: gha_utils.warning( f"Could not find any release for " - f'"{action_repository}", status code: {response.status_code}' + f'"{action_repository}", GitHub API Response: {response.json()}' ) return {} @@ -237,7 +245,7 @@ def _get_commit_data( gha_utils.warning( f"Could not find commit data for tag/branch {tag_or_branch_name} on " - f'"{action_repository}", status code: {response.status_code}' + f'"{action_repository}", GitHub API Response: {response.json()}' ) return {} @@ -254,7 +262,7 @@ def _get_default_branch_name(self, action_repository: str) -> str | None: gha_utils.warning( f"Could not find default branch for " - f'"{action_repository}", status code: {response.status_code}' + f'"{action_repository}", GitHub API Response: {response.json()}' ) return None @@ -323,7 +331,7 @@ def _get_workflow_paths(self) -> list[str]: gha_utils.error( f"An error occurred while getting workflows for" - f"{self.env.repository}, status code: {response.status_code}" + f"{self.env.repository}, GitHub API Response: {response.json()}" ) raise SystemExit(1) diff --git a/src/utils.py b/src/utils.py index 5402ca2..c5119f5 100644 --- a/src/utils.py +++ b/src/utils.py @@ -24,7 +24,7 @@ def create_pull_request( head_branch_name: str, body: str, github_token: str | None = None, -) -> None: +) -> int: """Create pull request on GitHub""" with gha_utils.group("Create Pull Request"): url = f"https://api.github.com/repos/{repository_name}/pulls" @@ -40,14 +40,61 @@ def create_pull_request( ) if response.status_code == 201: - html_url = response.json()["html_url"] - gha_utils.notice(f"Pull request opened at {html_url} \U0001F389") - else: - gha_utils.error( - f"Could not create a pull request on " - f"{repository_name}, status code: {response.status_code}" + response_data = response.json() + gha_utils.notice( + f"Pull request opened at {response_data['html_url']} \U0001F389" + ) + return response_data["number"] + + gha_utils.error( + f"Could not create a pull request on " + f"{repository_name}, GitHub API Response: {response.json()}" + ) + raise SystemExit(1) + + +def add_pull_request_reviewers( + repository_name: str, + pull_request_number: int, + pull_request_user_reviewers: set[str], + pull_request_team_reviewers: set[str], + github_token: str | None = None, +) -> None: + """Request reviewers for a pull request on GitHub""" + with gha_utils.group(f"Request Reviewers for Pull Request #{pull_request_number}"): + payload = {} + + if pull_request_user_reviewers: + payload["reviewers"] = list(pull_request_user_reviewers) + + if pull_request_team_reviewers: + payload["team_reviewers"] = list(pull_request_team_reviewers) + + if not payload: + gha_utils.echo("No reviewers were requested.") + return + + url = ( + f"https://api.github.com/repos/{repository_name}/pulls" + f"/{pull_request_number}/requested_reviewers" + ) + + response = requests.post( + url, json=payload, headers=get_request_headers(github_token) + ) + + if response.status_code == 201: + gha_utils.notice( + "Requested review from " + f"{pull_request_user_reviewers.union(pull_request_team_reviewers)} " + "\U0001F389" ) - raise SystemExit(1) + return + + gha_utils.error( + f"Could not request reviews on pull request #{pull_request_number} " + f"on {repository_name}, GitHub API Response: {response.json()}" + ) def add_git_diff_to_job_summary() -> None: