diff --git a/docs/commands/deploy.md b/docs/commands/deploy.md index 5242bda0..0421440d 100644 --- a/docs/commands/deploy.md +++ b/docs/commands/deploy.md @@ -120,14 +120,15 @@ gitopscli deploy \ ## Usage ``` usage: gitopscli deploy [-h] --file FILE --values VALUES - [--single-commit [SINGLE_COMMIT]] --username USERNAME + [--single-commit [SINGLE_COMMIT]] + [--commit-message COMMIT_MESSAGE] --username USERNAME --password PASSWORD [--git-user GIT_USER] [--git-email GIT_EMAIL] --organisation ORGANISATION --repository-name REPOSITORY_NAME [--git-provider GIT_PROVIDER] [--git-provider-url GIT_PROVIDER_URL] [--create-pr [CREATE_PR]] [--auto-merge [AUTO_MERGE]] - [-v [VERBOSE]] + [--merge-method MERGE_METHOD] [-v [VERBOSE]] optional arguments: -h, --help show this help message and exit @@ -136,6 +137,8 @@ optional arguments: desired value as value --single-commit [SINGLE_COMMIT] Create only single commit for all updates + --commit-message COMMIT_MESSAGE + Specify exact commit message of deployment commit --username USERNAME Git username (alternative: GITOPSCLI_USERNAME env variable) --password PASSWORD Git password or token (alternative: GITOPSCLI_PASSWORD @@ -157,6 +160,9 @@ optional arguments: --auto-merge [AUTO_MERGE] Automatically merge the created PR (only valid with --create-pr) + --merge-method MERGE_METHOD + Merge Method (e.g., 'squash', 'rebase', 'merge') + (default: merge) -v [VERBOSE], --verbose [VERBOSE] Verbose exception logging ``` diff --git a/gitopscli/cliparser.py b/gitopscli/cliparser.py index 5907ad9b..0cc8b30f 100644 --- a/gitopscli/cliparser.py +++ b/gitopscli/cliparser.py @@ -99,6 +99,12 @@ def __create_deploy_parser() -> ArgumentParser: const=True, default=False, ) + parser.add_argument( + "--merge-method", + help="Merge Method (e.g., 'squash', 'rebase', 'merge') (default: merge)", + type=str, + default="merge", + ) __add_verbose_arg(parser) return parser diff --git a/gitopscli/commands/deploy.py b/gitopscli/commands/deploy.py index f14116da..691d243c 100644 --- a/gitopscli/commands/deploy.py +++ b/gitopscli/commands/deploy.py @@ -1,7 +1,7 @@ import logging import uuid from dataclasses import dataclass -from typing import Any, Dict, Optional, Tuple +from typing import Any, Dict, Optional, Tuple, Literal from gitopscli.git_api import GitApiConfig, GitRepo, GitRepoApi, GitRepoApiFactory from gitopscli.io_api.yaml_util import update_yaml_file, yaml_dump, YAMLException from gitopscli.gitops_exception import GitOpsException @@ -25,6 +25,7 @@ class Args(GitApiConfig): create_pr: bool auto_merge: bool + merge_method: Literal["squash", "rebase", "merge"] = "merge" def __init__(self, args: Args) -> None: self.__args = args @@ -50,7 +51,7 @@ def execute(self) -> None: pr_id = git_repo_api.create_pull_request_to_default_branch(pr_branch, title, description).pr_id if self.__args.auto_merge: - git_repo_api.merge_pull_request(pr_id) + git_repo_api.merge_pull_request(pr_id, self.__args.merge_method) git_repo_api.delete_branch(pr_branch) def __create_git_repo_api(self) -> GitRepoApi: diff --git a/gitopscli/git_api/bitbucket_git_repo_api_adapter.py b/gitopscli/git_api/bitbucket_git_repo_api_adapter.py index 163bf6c3..4c8cf7b9 100644 --- a/gitopscli/git_api/bitbucket_git_repo_api_adapter.py +++ b/gitopscli/git_api/bitbucket_git_repo_api_adapter.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Literal import requests from atlassian import Bitbucket @@ -74,7 +74,7 @@ def create_pull_request( raise GitOpsException(pull_request["errors"][0]["message"]) return GitRepoApi.PullRequestIdAndUrl(pr_id=pull_request["id"], url=pull_request["links"]["self"][0]["href"]) - def merge_pull_request(self, pr_id: int) -> None: + def merge_pull_request(self, pr_id: int, merge_method: Literal["squash", "rebase", "merge"] = "merge") -> None: pull_request = self.__bitbucket.get_pullrequest(self.__organisation, self.__repository_name, pr_id) self.__bitbucket.merge_pull_request( self.__organisation, self.__repository_name, pull_request["id"], pull_request["version"] diff --git a/gitopscli/git_api/git_repo_api.py b/gitopscli/git_api/git_repo_api.py index 87104aa1..bbc31015 100644 --- a/gitopscli/git_api/git_repo_api.py +++ b/gitopscli/git_api/git_repo_api.py @@ -1,5 +1,5 @@ from abc import ABCMeta, abstractmethod -from typing import NamedTuple, Optional +from typing import NamedTuple, Optional, Literal class GitRepoApi(metaclass=ABCMeta): @@ -32,7 +32,7 @@ def create_pull_request( ... @abstractmethod - def merge_pull_request(self, pr_id: int) -> None: + def merge_pull_request(self, pr_id: int, merge_method: Literal["squash", "rebase", "merge"] = "merge") -> None: ... @abstractmethod diff --git a/gitopscli/git_api/git_repo_api_logging_proxy.py b/gitopscli/git_api/git_repo_api_logging_proxy.py index b9086f0f..d248e845 100644 --- a/gitopscli/git_api/git_repo_api_logging_proxy.py +++ b/gitopscli/git_api/git_repo_api_logging_proxy.py @@ -1,5 +1,5 @@ import logging -from typing import Optional +from typing import Optional, Literal from .git_repo_api import GitRepoApi @@ -28,9 +28,9 @@ def create_pull_request( logging.info("Creating pull request from '%s' to '%s' with title: %s", from_branch, to_branch, title) return self.__api.create_pull_request(from_branch, to_branch, title, description) - def merge_pull_request(self, pr_id: int) -> None: + def merge_pull_request(self, pr_id: int, merge_method: Literal["squash", "rebase", "merge"] = "merge") -> None: logging.info("Merging pull request %s", pr_id) - self.__api.merge_pull_request(pr_id) + self.__api.merge_pull_request(pr_id, merge_method=merge_method) def add_pull_request_comment(self, pr_id: int, text: str, parent_id: Optional[int] = None) -> None: if parent_id: diff --git a/gitopscli/git_api/github_git_repo_api_adapter.py b/gitopscli/git_api/github_git_repo_api_adapter.py index e3ad9cda..0269cccd 100644 --- a/gitopscli/git_api/github_git_repo_api_adapter.py +++ b/gitopscli/git_api/github_git_repo_api_adapter.py @@ -1,5 +1,14 @@ -from typing import Optional -from github import Github, UnknownObjectException, BadCredentialsException, GitRef, PullRequest, Repository +from typing import Optional, Literal + +from github import ( + Github, + UnknownObjectException, + BadCredentialsException, + GitRef, + PullRequest, + Repository, +) + from gitopscli.gitops_exception import GitOpsException from .git_repo_api import GitRepoApi @@ -36,9 +45,9 @@ def create_pull_request( pull_request = repo.create_pull(title=title, body=description, head=from_branch, base=to_branch) return GitRepoApi.PullRequestIdAndUrl(pr_id=pull_request.number, url=pull_request.html_url) - def merge_pull_request(self, pr_id: int) -> None: + def merge_pull_request(self, pr_id: int, merge_method: Literal["squash", "rebase", "merge"] = "merge") -> None: pull_request = self.__get_pull_request(pr_id) - pull_request.merge() + pull_request.merge(merge_method=merge_method) def add_pull_request_comment(self, pr_id: int, text: str, parent_id: Optional[int] = None) -> None: pull_request = self.__get_pull_request(pr_id) diff --git a/gitopscli/git_api/gitlab_git_repo_api_adapter.py b/gitopscli/git_api/gitlab_git_repo_api_adapter.py index 5d660449..1916a235 100644 --- a/gitopscli/git_api/gitlab_git_repo_api_adapter.py +++ b/gitopscli/git_api/gitlab_git_repo_api_adapter.py @@ -1,4 +1,4 @@ -from typing import Optional +from typing import Optional, Literal import logging import time import requests @@ -59,12 +59,15 @@ def create_pull_request( ) return GitRepoApi.PullRequestIdAndUrl(pr_id=merge_request.iid, url=merge_request.web_url) - def merge_pull_request(self, pr_id: int) -> None: + def merge_pull_request(self, pr_id: int, merge_method: Literal["squash", "rebase", "merge"] = "merge") -> None: merge_request = self.__project.mergerequests.get(pr_id) max_retries = MAX_MERGE_RETRIES while max_retries > 0: try: + if merge_method == "rebase": + merge_request.rebase() + return merge_request.merge() return except gitlab.exceptions.GitlabMRClosedError as ex: diff --git a/tests/commands/test_deploy.py b/tests/commands/test_deploy.py index 5452b896..c0acfa3f 100644 --- a/tests/commands/test_deploy.py +++ b/tests/commands/test_deploy.py @@ -194,7 +194,7 @@ def test_create_pr_and_merge_happy_flow(self): "Updated values in test/file.yml", "Updated 2 values in `test/file.yml`:\n```yaml\na.b.c: foo\na.b.d: bar\n```\n", ), - call.GitRepoApi.merge_pull_request(42), + call.GitRepoApi.merge_pull_request(42, "merge"), call.GitRepoApi.delete_branch("gitopscli-deploy-b973b5bb"), ] diff --git a/tests/git_api/test_git_repo_api_logging_proxy.py b/tests/git_api/test_git_repo_api_logging_proxy.py index 0a900eb6..f1180f1c 100644 --- a/tests/git_api/test_git_repo_api_logging_proxy.py +++ b/tests/git_api/test_git_repo_api_logging_proxy.py @@ -74,7 +74,7 @@ def test_create_pull_request_to_default_branch(self, logging_mock): @patch("gitopscli.git_api.git_repo_api_logging_proxy.logging") def test_merge_pull_request(self, logging_mock): self.__testee.merge_pull_request(pr_id=42) - self.__mock_repo_api.merge_pull_request.assert_called_once_with(42) + self.__mock_repo_api.merge_pull_request.assert_called_once_with(42, merge_method="merge") logging_mock.info.assert_called_once_with( "Merging pull request %s", 42, ) diff --git a/tests/test_cliparser.py b/tests/test_cliparser.py index 5b254ee8..f88b12ee 100644 --- a/tests/test_cliparser.py +++ b/tests/test_cliparser.py @@ -284,7 +284,7 @@ [--git-provider GIT_PROVIDER] [--git-provider-url GIT_PROVIDER_URL] [--create-pr [CREATE_PR]] [--auto-merge [AUTO_MERGE]] - [-v [VERBOSE]] + [--merge-method MERGE_METHOD] [-v [VERBOSE]] gitopscli deploy: error: the following arguments are required: --file, --values, --username, --password, --organisation, --repository-name """ @@ -298,7 +298,7 @@ [--git-provider GIT_PROVIDER] [--git-provider-url GIT_PROVIDER_URL] [--create-pr [CREATE_PR]] [--auto-merge [AUTO_MERGE]] - [-v [VERBOSE]] + [--merge-method MERGE_METHOD] [-v [VERBOSE]] optional arguments: -h, --help show this help message and exit @@ -330,6 +330,9 @@ --auto-merge [AUTO_MERGE] Automatically merge the created PR (only valid with --create-pr) + --merge-method MERGE_METHOD + Merge Method (e.g., 'squash', 'rebase', 'merge') + (default: merge) -v [VERBOSE], --verbose [VERBOSE] Verbose exception logging """