From 8f3629143a37e9d2fbe97827eaf520962506add3 Mon Sep 17 00:00:00 2001 From: psadi Date: Mon, 12 Feb 2024 04:15:45 +0530 Subject: [PATCH] chore: maintainance refactor --- .vscode/settings.json | 6 +- bb/__init__.py | 11 +- bb/__version__.py | 2 +- bb/auth/__init__.py | 46 ++--- bb/pr/__init__.py | 98 +++++----- bb/pr/copy.py | 5 +- bb/pr/create.py | 20 +- bb/pr/delete.py | 10 +- bb/pr/diff.py | 12 +- bb/pr/list.py | 17 +- bb/pr/merge.py | 53 ++---- bb/pr/review.py | 12 +- bb/pr/view.py | 8 +- bb/repo/__init__.py | 61 +++---- bb/repo/archive.py | 8 +- bb/repo/create.py | 8 +- bb/repo/delete.py | 7 +- bb/utils/api.py | 405 ++++++++++++++++++----------------------- bb/utils/helper.py | 75 ++++++++ bb/utils/ini.py | 7 +- bb/utils/request.py | 12 +- bb/utils/validate.py | 50 ----- config.ini | 2 +- pdm.lock | 133 +++++--------- pyproject.toml | 13 +- requirements.txt | 19 +- tests/test_api.py | 67 +++---- tests/test_helper.py | 44 +++++ tests/test_request.py | 6 +- tests/test_validate.py | 7 - 30 files changed, 552 insertions(+), 672 deletions(-) create mode 100755 bb/utils/helper.py delete mode 100755 bb/utils/validate.py create mode 100644 tests/test_helper.py delete mode 100644 tests/test_validate.py diff --git a/.vscode/settings.json b/.vscode/settings.json index 46d23b4..9d12205 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,5 @@ { "python.autoComplete.extraPaths": ["__pypackages__/3.11/lib"], - "python.analysis.extraPaths": [ - "__pypackages__/3.11/lib" - ], - "python.analysis.typeCheckingMode": "basic" + "python.analysis.extraPaths": ["__pypackages__/3.11/lib"], + "python.analysis.typeCheckingMode": "off" } diff --git a/bb/__init__.py b/bb/__init__.py index aae5452..927785f 100755 --- a/bb/__init__.py +++ b/bb/__init__.py @@ -5,21 +5,20 @@ import typer -from bb import __version__ +from bb.__version__ import __version__ as version from bb.auth import _auth from bb.pr import _pr from bb.repo import _repo +from bb.utils.helper import state from bb.utils.richprint import console -from bb.utils.validate import state def version_callback(value: bool) -> None: """ - returns the docstring of the current module (`__doc__`) - and exits the program. + Prints the version of bb and exits the program. """ if value: - console.print(f"bb version: {__version__.__version__}") + console.print(f"bb version: {version}") raise typer.Exit(code=0) @@ -47,7 +46,7 @@ def callback( version: bool = typer.Option(None, "--version", callback=version_callback), ): """ - Work seamlessly with Bitbucket from the command line. + Entry point for the bb CLI. Handles global flags like --verbose and --version. """ if verbose: state["verbose"] = True diff --git a/bb/__version__.py b/bb/__version__.py index 9505500..6f4f262 100755 --- a/bb/__version__.py +++ b/bb/__version__.py @@ -4,4 +4,4 @@ Sets the packge version, picked dynamically by the utility and pyproject """ -__version__ = "0.5.6" +__version__ = "0.5.7" diff --git a/bb/auth/__init__.py b/bb/auth/__init__.py index 2249a5c..f97e36d 100755 --- a/bb/auth/__init__.py +++ b/bb/auth/__init__.py @@ -6,9 +6,9 @@ import typer -from bb.utils.ini import BB_CONFIG_FILE, _setup, is_config_present, parse -from bb.utils.richprint import console, traceback_to_console -from bb.utils.validate import error_tip, state, validate_config +from bb.utils.helper import error_handler, validate_config +from bb.utils.ini import BB_CONFIG_FILE, auth_setup, is_config_present, parse +from bb.utils.richprint import console _auth: typer.Typer = typer.Typer(add_completion=False, no_args_is_help=True) bold_red: str = "bold red" @@ -17,13 +17,15 @@ @_auth.command() def setup() -> None: """Configure bbcli to work with bitbucket""" - try: + + @error_handler + def _setup() -> None: if is_config_present(): console.print( "Configuration file found, Run 'bb auth status' for more information" ) else: - _setup( + auth_setup( typer.prompt( "> bitbucket_host", ), @@ -34,33 +36,30 @@ def setup() -> None: f"Configuration written at '{BB_CONFIG_FILE}'," + "Please re-run 'bb auth test' to validate" ) - except Exception as err: - console.print(f"ERROR: {err}", style=bold_red) - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _setup() @_auth.command() def test() -> None: """Test configuration & connection""" - try: + + @error_handler + def _test() -> None: validate_config() - except Exception as err: - console.print(f"ERROR: {err}", style=bold_red) - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _test() @_auth.command() def status(token: bool = typer.Option(False, help="Display auth token")) -> None: """View authentication config status""" - try: + + @error_handler + def _status(token: bool) -> None: if not is_config_present(): raise ValueError("Configuration missing, run 'bb auth setup'") + hcm: str = "[bold green]:heavy_check_mark:[/bold green]" console.print( f"{hcm} Configuration found at [bold cyan]{BB_CONFIG_FILE}[/bold cyan]" @@ -70,10 +69,5 @@ def status(token: bool = typer.Option(False, help="Display auth token")) -> None f"{hcm} Will connect to [bold]{bitbucket_host}[/bold] as [bold]{username}[/bold]" ) console.print(f"{hcm} Token: {_token if token else '*' * len(_token)}") - except Exception as err: - console.print(f"ERROR: {err}", style=bold_red) - if state["verbose"]: - traceback_to_console() - else: - error_tip() - typer.Exit(code=1) + + _status(token) diff --git a/bb/pr/__init__.py b/bb/pr/__init__.py index 967228d..0041866 100755 --- a/bb/pr/__init__.py +++ b/bb/pr/__init__.py @@ -17,8 +17,7 @@ from bb.pr.review import review_pull_request from bb.pr.view import view_pull_request from bb.utils.cmnd import is_git_repo -from bb.utils.richprint import console, traceback_to_console -from bb.utils.validate import error_tip, state, validate_input +from bb.utils.helper import error_handler, validate_input _pr: typer.Typer = typer.Typer(add_completion=False, no_args_is_help=True) bold_red: str = "bold red" @@ -37,18 +36,17 @@ def create( ), ) -> None: """Create a pull request""" - try: + + @error_handler + def _create(target: str, yes: bool, diff: bool, rebase: bool) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) target = validate_input(target, "Target branch", "Target branch cannot be none") create_pull_request(target, yes, diff, rebase) - except Exception as err: - console.print(f"ERROR: {err}", style=bold_red) - error_tip() - if state["verbose"]: - traceback_to_console() + + _create(target, yes, diff, rebase) @_pr.command() @@ -58,7 +56,9 @@ def delete( diff: bool = typer.Option(False, help="show diff before deleting pull request"), ) -> None: """Delete pull requests""" - try: + + @error_handler + def _delete(id: str, yes: bool, diff: bool) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) @@ -68,11 +68,8 @@ def delete( "Id's cannot be empty", ).split(",") delete_pull_request(_id, yes, diff) - except Exception as err: - console.print(f"ERROR: {err}", style=bold_red) - error_tip() - if state["verbose"]: - traceback_to_console() + + _delete(id, yes, diff) class Role(str, Enum): @@ -94,17 +91,15 @@ def list( ), ) -> None: """List pull requests in a repository""" - try: + + @error_handler + def _list(role: str, all: bool) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) list_pull_request(role, all) - except Exception as err: - console.print(f"ERROR: {err}", style=f"{bold_red}") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _list(role, all) class Action(str, Enum): @@ -122,9 +117,12 @@ def review( action: Action = Action.NONE, ) -> None: """Add a review to a pull request""" - try: + + @error_handler + def _review(id: str, action: Action) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) + _id: str = validate_input(id, "Pull request id to review", id_cannot_be_none) action_value: str = "none" if action == Action.NONE else action.value action: str = validate_input( @@ -133,12 +131,8 @@ def review( "action cannot be none", ) review_pull_request(_id, action) - except Exception as err: - console.print(f"ERROR: {err}", style=f"{bold_red}") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _review(id, action) @_pr.command() @@ -153,17 +147,15 @@ def merge( yes: bool = typer.Option(False, help=skip_prompt), ) -> None: """Merge a pull request""" - try: + + @error_handler + def _merge(id: str, delete_source_branch: bool, rebase: bool, yes: bool) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) _id: str = validate_input(id, "Pull request id to merge", id_cannot_be_none) merge_pull_request(_id, delete_source_branch, rebase, yes) - except Exception as err: - console.print(f"ERROR: {err}", style=f"{bold_red}") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _merge(id, delete_source_branch, rebase, yes) @_pr.command() @@ -171,36 +163,32 @@ def diff( id: str = typer.Option("", help="pull request number to show diff"), ) -> None: """View changes in a pull request""" - try: + + @error_handler + def _diff(id: str) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) _id: str = validate_input( id, "Pull request number to show diff", id_cannot_be_none ) show_diff(_id) - except Exception as err: - console.print(f"ERROR: {err}", style=f"{bold_red}") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _diff(id) @_pr.command() def copy(id: str = typer.Option("", help="pull request number to copy")) -> None: """Copy pull request url to clipboard""" - try: + + @error_handler + def _copy(id: str) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) _id: str = validate_input(id, "Pull request number to copy", id_cannot_be_none) copy_pull_request(_id) - except Exception as err: - console.print(f"ERROR: {err}", style=f"{bold_red}") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _copy(id) @_pr.command() @@ -209,14 +197,12 @@ def view( web: Optional[bool] = typer.Option(False, help="view pull request in browser"), ) -> None: """View a pull request""" - try: + + @error_handler + def _view(id: str, web: Optional[bool]) -> None: if not is_git_repo(): raise ValueError(not_a_git_repo) _id = validate_input(id, "Pull request id to view", id_cannot_be_none) view_pull_request(_id, web) - except Exception as err: - console.print(f"ERROR: {err}", style=f"{bold_red}") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _view(id, web) diff --git a/bb/pr/copy.py b/bb/pr/copy.py index c92d3c3..2ec7438 100755 --- a/bb/pr/copy.py +++ b/bb/pr/copy.py @@ -5,7 +5,8 @@ clipboard """ -from bb.utils import api, cmnd, ini, request, richprint +from bb.utils import cmnd, ini, request, richprint +from bb.utils.api import bitbucket_api def copy_pull_request(_id: str) -> None: @@ -21,7 +22,7 @@ def copy_pull_request(_id: str) -> None: username, token, bitbucket_host = ini.parse() project, repository = cmnd.base_repo() url: str = request.get( - api.pull_request_info(bitbucket_host, project, repository, _id), + bitbucket_api.pull_request_info(bitbucket_host, project, repository, _id), username, token, )[1]["links"]["self"][0]["href"] diff --git a/bb/pr/create.py b/bb/pr/create.py index ef13d51..4db4609 100755 --- a/bb/pr/create.py +++ b/bb/pr/create.py @@ -11,7 +11,8 @@ from typer import confirm from bb.pr.diff import show_diff -from bb.utils import api, cmnd, ini, request, richprint +from bb.utils import cmnd, ini, request, richprint +from bb.utils.api import bitbucket_api def gather_facts( @@ -26,23 +27,16 @@ def gather_facts( repository """ - username, token, bitbucket_host = ini.parse() with richprint.live_progress(f"Gathering facts on '{repository}' ..."): repo_id = None - for repo in request.get( - api.get_repo_info(bitbucket_host, project), username, token - )[1]["values"]: + for repo in request.get(bitbucket_api.get_repo_info(project))[1]["values"]: if repo["name"] == repository: repo_id = repo["id"] reviewers = [] if repo_id is not None: for dict_item in request.get( - api.default_reviewers( - bitbucket_host, project, repo_id, from_branch, target - ), - username, - token, + bitbucket_api.default_reviewers(project, repo_id, from_branch, target), )[1]: reviewers.extend( {"user": {"name": dict_item[key]}} @@ -96,8 +90,8 @@ def create_pull_request(target: str, yes: bool, diff: bool, rebase: bool) -> Non if yes or confirm("Proceed"): with richprint.live_progress("Creating Pull Request ..."): - url = api.pull_request_create(bitbucket_host, project, repository) - body = api.pull_request_body( + url = bitbucket_api.pull_request_create(project, repository) + body = bitbucket_api.pull_request_body( title_and_description, from_branch, repository, @@ -105,7 +99,7 @@ def create_pull_request(target: str, yes: bool, diff: bool, rebase: bool) -> Non target, reviewers, ) - pull_request = request.post(url, username, token, body) + pull_request = request.post(url, body) if pull_request[0] == 201: richprint.console.print( diff --git a/bb/pr/delete.py b/bb/pr/delete.py index 26f9ce9..75e3241 100755 --- a/bb/pr/delete.py +++ b/bb/pr/delete.py @@ -9,20 +9,20 @@ from typer import confirm from bb.pr.diff import show_diff -from bb.utils import api, cmnd, ini, request, richprint +from bb.utils import cmnd, request, richprint +from bb.utils.api import bitbucket_api def delete_pull_request(_id: list, yes: bool, diff: bool) -> None: """ Delete pull request(s) by ID """ - username, token, bitbucket_host = ini.parse() project, repository = cmnd.base_repo() for _no in _id: with richprint.live_progress(f"Fetching info on {_no} ..."): - url = api.pull_request_info(bitbucket_host, project, repository, _no) - pull_request_info = request.get(url, username, token) + url = bitbucket_api.pull_request_info(project, repository, _no) + pull_request_info = request.get(url) table = richprint.table( [("SUMMARY", "bold yellow"), ("DESCRIPTION", "#FFFFFF")], @@ -51,7 +51,7 @@ def delete_pull_request(_id: list, yes: bool, diff: bool) -> None: if yes or confirm("Proceed"): with richprint.live_progress("Deleting Pull Request ..."): body = json.dumps({"version": int(pull_request_info[1]["version"])}) - pull_request = request.delete(url, username, token, body) + pull_request = request.delete(url, body) if pull_request != 204: raise ValueError("Cannot delete pull request, Response<204>") diff --git a/bb/pr/diff.py b/bb/pr/diff.py index 6d63bfb..86771ff 100755 --- a/bb/pr/diff.py +++ b/bb/pr/diff.py @@ -5,7 +5,8 @@ TODO: show the diff contents for each file """ -from bb.utils import api, cmnd, ini, request, richprint +from bb.utils import cmnd, request, richprint +from bb.utils.api import bitbucket_api def show_diff(_id: str) -> None: @@ -13,19 +14,14 @@ def show_diff(_id: str) -> None: Display the diff from remote pull request to the console applicable for create and delete actions """ - username, token, bitbucket_host = ini.parse() project, repository = cmnd.base_repo() with richprint.live_progress("Fetching Contents from Pull Request ..."): response = request.get( - api.pull_request_difference(bitbucket_host, project, repository, _id), - username, - token, + bitbucket_api.pull_request_difference(project, repository, _id), )[1] pr_info = request.get( - api.pull_request_info(bitbucket_host, project, repository, _id), - username, - token, + bitbucket_api.pull_request_info(project, repository, _id), )[1] header = [ diff --git a/bb/pr/list.py b/bb/pr/list.py index e67e6b4..fe9cfb7 100755 --- a/bb/pr/list.py +++ b/bb/pr/list.py @@ -6,10 +6,15 @@ or all repos """ -from bb.utils import api, cmnd, ini, request, richprint +from typing import Dict, List, Tuple +from bb.utils import cmnd, ini, request, richprint +from bb.utils.api import bitbucket_api -def to_richprint(repo_name: str, pr_repo_dict: dict) -> None: + +def to_richprint( + repo_name: str, pr_repo_dict: Dict[str, Dict[str, List[Tuple[str, str]]]] +) -> None: """ This function takes in a repository name, a dictionary of pull requests, and a header dictionary and prints the data to the console @@ -18,7 +23,7 @@ def to_richprint(repo_name: str, pr_repo_dict: dict) -> None: richprint.render_tree(repo_name, status, data) -def state_check(_input) -> str: +def state_check(_input: str) -> str: """state to rich print mapping for table""" state: dict = { "CLEAN": f"[bold green]{_input}[/bold green]", @@ -110,12 +115,12 @@ def list_pull_request(role: str, _all: bool) -> None: """ username, token, bitbucket_host = ini.parse() project, repository = cmnd.base_repo() - request_url = api.current_pull_request(bitbucket_host, project, repository) + request_url = bitbucket_api.current_pull_request(project, repository) if role != "current": - request_url = api.pull_request_viewer(bitbucket_host, role) + request_url = bitbucket_api.pull_request_viewer(role) with richprint.live_progress(f"Fetching Pull Requests ({role}) ... ") as live: - role_info: list = request.get(request_url, username, token) + role_info: list = request.get(request_url) repo_dict = construct_repo_dict(role_info) live.update(richprint.console.print("DONE", style="bold green")) diff --git a/bb/pr/merge.py b/bb/pr/merge.py index db45014..705c941 100755 --- a/bb/pr/merge.py +++ b/bb/pr/merge.py @@ -9,7 +9,8 @@ from rich import print_json from typer import confirm -from bb.utils import api, cmnd, ini, request, richprint +from bb.utils import cmnd, request, richprint +from bb.utils.api import bitbucket_api BOLD_RED = "bold red" @@ -23,15 +24,12 @@ def pr_source_branch_delete_check( """ checks is the source branch is ok to be deleted if requested """ - username, token, bitbucket_host = ini.parse() if ( len( request.get( - api.pr_source_branch_delete_check( - bitbucket_host, project, repository, _id, delete_source_branch + bitbucket_api.pr_source_branch_delete_check( + project, repository, _id, delete_source_branch ), - username, - token, )[1] ) != 0 @@ -46,11 +44,8 @@ def validate_pr_source_branch_delete_check( validates the pull request source branch and check for conflitcts or vetos """ with richprint.live_progress(f"Validating Merge for '{_id}' ... ") as live: - username, token, bitbucket_host = ini.parse() validation_response = request.get( - api.validate_merge(bitbucket_host, project, repository, _id), - username, - token, + bitbucket_api.validate_merge(project, repository, _id), ) if ( validation_response[1]["canMerge"] is True @@ -69,11 +64,8 @@ def validate_automerge_conditions(project: str, repository: str, _id: str) -> tu with richprint.live_progress( f"Checking for '{repository}' auto-merge conditions ... " ): - username, token, bitbucket_host = ini.parse() pr_info = request.get( - api.pull_request_info(bitbucket_host, project, repository, _id), - username, - token, + bitbucket_api.pull_request_info(project, repository, _id), )[1] from_branch, target_branch, version = ( pr_info["fromRef"]["displayId"], @@ -83,9 +75,7 @@ def validate_automerge_conditions(project: str, repository: str, _id: str) -> tu return ( pr_info, request.get( - api.get_merge_info(bitbucket_host, project, repository, target_branch), - username, - token, + bitbucket_api.get_merge_info(project, repository, target_branch), )[1], from_branch, target_branch, @@ -120,30 +110,22 @@ def show_merge_stats(pr_merge_response, from_branch, target_branch) -> None: def rebase_pr(project: str, repository: str, _id: str, version: int): """perform rebase in source branch on bitbucket""" - username, token, bitbucket_host = ini.parse() request.post( - api.pr_rebase(bitbucket_host, project, repository, _id, version)[1], - username, - token, - api.pr_rebase(bitbucket_host, project, repository, _id, version)[0], + bitbucket_api.pr_rebase(project, repository, _id, version)[1], + bitbucket_api.pr_rebase(project, repository, _id, version)[0], ) def delete_branch(project, repository, _id, from_branch, target_branch): """delete source branch in bitbucket and local git repository""" with richprint.live_progress(f"Deleting Source Ref '{from_branch}'... ") as live: - username, token, bitbucket_host = ini.parse() request.post( - api.pr_cleanup(bitbucket_host, project, repository, _id), - username, - token, - api.pr_cleanup_body(True), + bitbucket_api.pr_cleanup(project, repository, _id), + bitbucket_api.pr_cleanup_body(True), ) request.delete( - api.delete_branch(bitbucket_host, project, repository, from_branch)[1], - username, - token, - api.delete_branch(bitbucket_host, project, repository, from_branch)[0], + bitbucket_api.delete_branch(project, repository, from_branch)[1], + bitbucket_api.delete_branch(project, repository, from_branch)[0], ) live.update(richprint.console.print("DONE", style="green")) @@ -155,13 +137,12 @@ def merge_pr( live, project: str, repository: str, _id: str, branches_and_version: tuple ) -> None: """perform pull request merge""" - username, token, bitbucket_host = ini.parse() from_branch, target_branch, version = branches_and_version pr_merge_response = request.post( - f"{api.validate_merge(bitbucket_host, project, repository, _id)}?avatarSize=32&version={version}", - username, - token, - api.pr_merge_body(project, repository, _id, from_branch, target_branch), + f"{bitbucket_api.validate_merge(project, repository, _id)}?avatarSize=32&version={version}", + bitbucket_api.pr_merge_body( + project, repository, _id, from_branch, target_branch + ), ) if pr_merge_response[0] == 200 and pr_merge_response[1]["state"] == "MERGED": live.update(richprint.console.print("MERGED", style="green")) diff --git a/bb/pr/review.py b/bb/pr/review.py index d24b3e1..7ad5de0 100755 --- a/bb/pr/review.py +++ b/bb/pr/review.py @@ -8,9 +8,8 @@ import json from time import sleep -from bb.utils.api import action_pull_request, whoami +from bb.utils.api import bitbucket_api from bb.utils.cmnd import base_repo -from bb.utils.ini import parse from bb.utils.request import get, put from bb.utils.richprint import console, live_progress @@ -20,7 +19,6 @@ def review_pull_request(target: int, action: str) -> None: It takes a target (pull request number) and an action (approve, unapprove, needs_work) and then performs the action on the pull request """ - username, token, bitbucket_host = parse() action_mapper = { "approve": ["APPROVED", "Approving", "green"], @@ -31,13 +29,13 @@ def review_pull_request(target: int, action: str) -> None: with live_progress( f"{action_mapper[action][1]} pull request '{target}' ... " ) as live: - user_id = get(whoami(bitbucket_host), username, token) + user_id = get(bitbucket_api.whoami()) project, repository = base_repo() - action_data = action_pull_request( - bitbucket_host, project, repository, target, user_id[1] + action_data = bitbucket_api.action_pull_request( + project, repository, target, user_id[1] ) body = json.dumps({"status": action_mapper[action][0]}) - put(action_data, username, token, body) + put(action_data, body) sleep(0.4) live.update( console.print(f"{action_mapper[action][0]}", style=action_mapper[action][2]) diff --git a/bb/pr/view.py b/bb/pr/view.py index 612808d..b7941f2 100755 --- a/bb/pr/view.py +++ b/bb/pr/view.py @@ -6,9 +6,8 @@ import webbrowser -from bb.utils.api import pull_request_info +from bb.utils.api import bitbucket_api from bb.utils.cmnd import base_repo -from bb.utils.ini import parse from bb.utils.request import get from bb.utils.richprint import console, live_progress, table @@ -16,11 +15,8 @@ def view_pull_request(_id: str, web: bool) -> None: """view a pull request in terminal or in a browser""" with live_progress(f"Fetching info on pr #{_id} ... ") as live: - username, token, bitbucket_host = parse() project, repository = base_repo() - url = get( - pull_request_info(bitbucket_host, project, repository, _id), username, token - ) + url = get(bitbucket_api.pull_request_info(project, repository, _id)) live.update(console.print("DONE", style="bold green")) if web: diff --git a/bb/repo/__init__.py b/bb/repo/__init__.py index 98cd0be..05d18c2 100755 --- a/bb/repo/__init__.py +++ b/bb/repo/__init__.py @@ -10,9 +10,9 @@ from bb.repo.create import create_repository from bb.repo.delete import delete_repository from bb.utils.cmnd import clone_repo +from bb.utils.helper import error_handler, validate_input from bb.utils.ini import parse -from bb.utils.richprint import console, traceback_to_console -from bb.utils.validate import error_tip, state, validate_input +from bb.utils.richprint import console _repo = Typer(add_completion=True, no_args_is_help=True) @@ -22,18 +22,17 @@ def clone( name: str = Argument(..., help="repository name, Format: project/repository"), ) -> None: """Clone a BitBucket repository locally""" - try: + + @error_handler + def _clone(name): name = validate_input( name, "project/repository to clone", "repository can't be none" ) + console.print(f"Cloning '{name}' into '{name.split('/')[1]}'...") clone_repo(name, parse()[2]) - except Exception as err: - console.print(f"ERROR: {err}", style="bold red") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + + _clone(name) @_repo.command() @@ -42,18 +41,15 @@ def delete( repo: str = Option("", help="repository name to delete"), ) -> None: "Delete a Bitbucket repository" - try: + + @error_handler + def _delete(project, repo): project = validate_input(project, "Project name", "project can't be none") repo = validate_input(repo, "Repository Name", "repository can't be none") delete_repository(project, repo) - except Exception as err: - console.print(f"ERROR: {err}", style="bold red") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + _delete(project, repo) @_repo.command() @@ -62,18 +58,15 @@ def archive( repo: str = Option("", help="repository name to archive"), ) -> None: "Archive a Bitbucket repository" - try: + + @error_handler + def _archive(project, repo): project = validate_input(project, "Project name", "project can't be none") repo = validate_input(repo, "Repository Name", "repository can't be none") archive_repository(project, repo, True) - except Exception as err: - console.print(f"ERROR: {err}", style="bold red") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + _archive(project, repo) @_repo.command() @@ -82,18 +75,15 @@ def unarchive( repo: str = Option("", help="repository name to unarchive"), ) -> None: "Unarchive a Bitbucket repository" - try: + + @error_handler + def _unarchive(project, repo): project = validate_input(project, "Project name", "project can't be none") repo = validate_input(repo, "Repository Name", "repository can't be none") archive_repository(project, repo, False) - except Exception as err: - console.print(f"ERROR: {err}", style="bold red") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + _unarchive(project, repo) @_repo.command() @@ -104,15 +94,12 @@ def create( default_branch: str = Option("master", help="Set default branch "), ) -> None: """Create a Bitbucket repository""" - try: + + @error_handler + def _create(project, repo, forkable, default_branch): project = validate_input(project, "Project name", "project can't be none") repo = validate_input(repo, "Repository Name", "repository can't be none") create_repository(project, repo, forkable, default_branch) - except Exception as err: - console.print(f"ERROR: {err}", style="bold red") - if state["verbose"]: - traceback_to_console() - else: - error_tip() + _create(project, repo, forkable, default_branch) diff --git a/bb/repo/archive.py b/bb/repo/archive.py index 539d259..83eb6cc 100644 --- a/bb/repo/archive.py +++ b/bb/repo/archive.py @@ -7,8 +7,7 @@ from typer import Exit, confirm -from bb.utils.api import delete_repo -from bb.utils.ini import parse +from bb.utils.api import bitbucket_api from bb.utils.request import put from bb.utils.richprint import console, live_progress @@ -19,14 +18,11 @@ def archive_repository(project: str, repo: str, archive: bool) -> None: ): raise Exit(code=1) - username, token, bitbucket_host = parse() with live_progress( f"{'Archiving' if archive else 'Unarchiving' } Repository '{project}/{repo}' ... " ) as live: request = put( - delete_repo(bitbucket_host, project, repo), - username, - token, + bitbucket_api.delete_repo(project, repo), json.dumps({"archived": archive}), # type: ignore ) diff --git a/bb/repo/create.py b/bb/repo/create.py index 4ece83b..7926e0e 100644 --- a/bb/repo/create.py +++ b/bb/repo/create.py @@ -2,8 +2,7 @@ import json -from bb.utils.api import create_repo -from bb.utils.ini import parse +from bb.utils.api import bitbucket_api from bb.utils.request import post from bb.utils.richprint import console, live_progress @@ -11,12 +10,9 @@ def create_repository( project: str, repo: str, forkable: bool, default_branch: str ) -> None: - username, token, bitbucket_host = parse() with live_progress(f"Creating '{project}/{repo}' Repository ... ") as live: request = post( - create_repo(bitbucket_host, project, repo), - username, - token, + bitbucket_api.create_repo(project, repo), json.dumps( { "name": repo, diff --git a/bb/repo/delete.py b/bb/repo/delete.py index 6553de6..6c90916 100644 --- a/bb/repo/delete.py +++ b/bb/repo/delete.py @@ -6,8 +6,7 @@ from typer import Exit, confirm, prompt -from bb.utils.api import delete_repo -from bb.utils.ini import parse +from bb.utils.api import bitbucket_api from bb.utils.request import delete as delete_request from bb.utils.richprint import console, live_progress @@ -31,10 +30,10 @@ def delete_repository(project: str, repo: str) -> None: ): raise Exit(code=1) - username, token, bitbucket_host = parse() with live_progress(f"Deleting Repository '{project}/{repo}' ... ") as live: request = delete_request( - delete_repo(bitbucket_host, project, repo), username, token, {} + bitbucket_api.delete_repo(project, repo), + {}, ) if request == 202: diff --git a/bb/utils/api.py b/bb/utils/api.py index 31a02ed..3f7ff06 100755 --- a/bb/utils/api.py +++ b/bb/utils/api.py @@ -1,240 +1,181 @@ # -*- coding: utf-8 -*- """ - bb.utils.api - contains the api model for bitbuket server + bb.utils.api - contains the API model for Bitbucket server """ import json - -def test(bitbucket_host: str) -> str: - """ - >his function returns a string that is the API endpoint for the user's inbox - """ - return f"{bitbucket_host}/rest/api/latest/inbox/pull-requests/count" - - -def pull_request_create(bitbucket_host: str, project: str, repository: str) -> str: - """ - It returns the pull request API to create pull requests - """ - return f"{bitbucket_host}/rest/api/1.0/projects/{project}/repos/{repository}/pull-requests" - - -def get_repo_info(bitbucket_host: str, project: str) -> str: - """ - Returns the project repository information - """ - return ( - f"{bitbucket_host}/rest/api/latest/projects/{project}/repos?start=0&limit=10000" - ) - - -def default_reviewers( - bitbucket_host: str, project: str, repo_id: str, from_branch: str, target: str -) -> str: - """ - Returns the api to validate default reviewrs in a repository - """ - reviewer_query = f"avatarSize=32&sourceRepoId={repo_id}&sourceRefId=refs%2Fheads%2F{from_branch.replace('/','%2F')}&targetRepoId={repo_id}&targetRefId=refs%2Fheads%2F{target.replace('/','%2F')}" - return f"{bitbucket_host}/rest/default-reviewers/latest/projects/{project}/repos/repository/reviewers?{reviewer_query}" - - -def pull_request_body( - title_and_description: str, - from_branch: str, - repository: str, - project: str, - target: str, - reviewers: list, -) -> str: - """ - It creates a pull request from the branch `from_branch` to the branch `target` in the repository - `repository` in the project `project` with the title and description `title_and_description` and the - reviewers `reviewers` - """ - return json.dumps( - { - "title": title_and_description[0], - "description": title_and_description[1], - "state": "OPEN", - "open": "true", - "closed": "false", - "fromRef": { - "id": f"refs/heads/{from_branch}", - "repository": { - "slug": repository, - "name": repository, - "project": {"key": project}, +from bb.utils.ini import is_config_present, parse + + +class BitbucketAPI: + def __init__(self, bitbucket_host: str): + self.bitbucket_host = bitbucket_host + + def _api_url(self, path: str) -> str: + return f"{self.bitbucket_host}{path}" + + def test(self) -> str: + return self._api_url("/rest/api/latest/inbox/pull-requests/count") + + def pull_request_create(self, project: str, repository: str) -> str: + return self._api_url( + f"/rest/api/1.0/projects/{project}/repos/{repository}/pull-requests" + ) + + def get_repo_info(self, project: str) -> str: + return self._api_url( + f"/rest/api/latest/projects/{project}/repos?start=0&limit=10000" + ) + + def default_reviewers( + self, project: str, repo_id: str, from_branch: str, target: str + ) -> str: + reviewer_query = f"avatarSize=32&sourceRepoId={repo_id}&sourceRefId=refs%2Fheads%2F{from_branch.replace('/','%2F')}&targetRepoId={repo_id}&targetRefId=refs%2Fheads%2F{target.replace('/','%2F')}" + return self._api_url( + f"/rest/default-reviewers/latest/projects/{project}/repos/repository/reviewers?{reviewer_query}" + ) + + def pull_request_body( + self, + title_and_description: str, + from_branch: str, + repository: str, + project: str, + target: str, + reviewers: list, + ) -> str: + return json.dumps( + { + "title": title_and_description[0], + "description": title_and_description[1], + "state": "OPEN", + "open": "true", + "closed": "false", + "fromRef": { + "id": f"refs/heads/{from_branch}", + "repository": { + "slug": repository, + "name": repository, + "project": {"key": project}, + }, }, - }, - "toRef": { - "id": f"refs/heads/{target}", - "repository": { - "slug": repository, - "name": repository, - "project": {"key": project}, + "toRef": { + "id": f"refs/heads/{target}", + "repository": { + "slug": repository, + "name": repository, + "project": {"key": project}, + }, }, - }, - "locked": "false", - "reviewers": reviewers, - } - ) - - -def pull_request_difference( - bitbucket_host: str, project: str, repository: str, pr_number: str -) -> str: - """ - Returns the diff API to check in a given pull request - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{pr_number}/changes?start=0&limit=1000&changeScope=unreviewed" - - -def pull_request_info( - bitbucket_host: str, project: str, repository: str, _id: str -) -> str: - """ - It returns a URL for a Bitbucket pull request - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{_id}" - - -def pull_request_viewer(bitbucket_host: str, role: str) -> str: - """ - It returns the api for either reviewer or author role. - """ - return f"{bitbucket_host}/rest/api/latest/inbox/pull-requests?role={role}&avatarSize=64" - - -def current_pull_request(bitbucket_host: str, project: str, repository: str) -> str: - """ - It returns the URL of the current pull request - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos/{repository}/pull-requests" - - -def whoami(bitbucket_host: str) -> str: - """ - It returns a string of who the current user is - """ - return f"{bitbucket_host}/plugins/servlet/applinks/whoami" - - -def action_pull_request( - bitbucket_host: str, project: str, repository: str, target: int, user_id: str -) -> str: - """ - Returns a URL to the Bitbucket API endpoint for a pull request participant - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{target}/participants/{user_id}?avatarSize=32" - - -def pr_source_branch_delete_check( - bitbucket_host: str, - project: str, - repository: str, - _id: str, - delete_source_branch: str, -) -> str: - """ - It takes in a Bitbucket host, project, repository, pull request ID, - and a boolean value for whether or not to delete the source branch, - and returns a URL that can be used to check if the source branch can be deleted. - """ - return f"{bitbucket_host}/rest/pull-request-cleanup/latest/projects/{project}/repos/{repository}/pull-requests/{_id}?deleteSourceRef={delete_source_branch}&retargetDependents={delete_source_branch}" - - -def validate_merge(bitbucket_host: str, project: str, repository: str, _id: str) -> str: - """ - It takes a Bitbucket host, a project, a repository, and a pull request ID, and returns a URL that - can be used to validate the merge of the pull request - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{_id}/merge" - - -def merge_config(bitbucket_host: str, project: str, repository: str) -> str: - """ - It takes a Bitbucket host, a project, and a repository and returns a URL for the pull request - settings of that repository - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos/{repository}/settings/pull-requests" - - -def get_merge_info( - bitbucket_host: str, project: str, repository: str, target_branch -) -> str: - """ - This function returns the URL for the Bitbucket API endpoint that will return the merge info for a - given branch - """ - return f"{bitbucket_host}/rest/branch-utils/latest/projects/{project}/repos/{repository}/automerge/path/refs/heads/{target_branch}" - - -def pr_merge_body( - project: str, repository: str, _id: str, from_branch: str, target_branch: str -) -> str: - """ - It takes the project, repository, pull request id, from branch, and target branch and returns a JSON - object that contains the message to be used when merging the pull request - """ - return json.dumps( - { - "autoSubject": False, - "message": f"Merge pull request #{_id} in {project}/{repository} from {from_branch} to {target_branch}", - } - ) - - -def pr_cleanup(bitbucket_host: str, project: str, repository: str, _id: str) -> str: - """ - It returns a URL for the Bitbucket REST API endpoint for the pull request cleanup plugin - """ - return f"{bitbucket_host}/rest/pull-request-cleanup/latest/projects/{project}/repos/{repository}/pull-requests/{_id}" - - -def pr_cleanup_body(delete_source_branch: bool) -> str: - """ - It returns a dictionary that contains a JSON string that contains a dictionary that contains a - boolean - """ - return json.dumps( - {"deleteSourceRef": delete_source_branch, "retargetDependents": True} - ) - - -def pr_rebase( - bitbucket_host: str, project: str, repository: str, _id: str, version: int -) -> list: - """ - It returns a list of two elements, the first being a JSON string, and the second being a URL - """ - return [ - json.dumps({"version": version}), - f"{bitbucket_host}/rest/git/latest/projects/{project}/repos/{repository}/pull-requests/{_id}/rebase", - ] - - -def delete_branch( - bitbucket_host: str, project: str, repository: str, source_branch: str -) -> list: - """ - provides the payload the the body to delete a branch in bitbucket - """ - return [ - json.dumps({"name": f"{source_branch}"}), - f"{bitbucket_host}/rest/branch-utils/latest/projects/{project}/repos/{repository}/branches", - ] - - -def delete_repo(bitbucket_host: str, project: str, repo: str) -> str: - """ - provides the payload to delete a repo - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos/{repo}" - - -def create_repo(bitbucket_host: str, project: str, repo: str) -> str: - """ - provides the payload to create a repo - """ - return f"{bitbucket_host}/rest/api/latest/projects/{project}/repos" + "locked": "false", + "reviewers": reviewers, + } + ) + + def pull_request_difference( + self, project: str, repository: str, pr_number: str + ) -> str: + return self._api_url( + f"/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{pr_number}/changes?start=0&limit=1000&changeScope=unreviewed" + ) + + def pull_request_info(self, project: str, repository: str, _id: str) -> str: + return self._api_url( + f"/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{_id}" + ) + + def pull_request_viewer(self, role: str) -> str: + return self._api_url( + f"/rest/api/latest/inbox/pull-requests?role={role}&avatarSize=64" + ) + + def current_pull_request(self, project: str, repository: str) -> str: + return self._api_url( + f"/rest/api/latest/projects/{project}/repos/{repository}/pull-requests" + ) + + def whoami(self) -> str: + return self._api_url("/plugins/servlet/applinks/whoami") + + def action_pull_request( + self, project: str, repository: str, target: int, user_id: str + ) -> str: + return self._api_url( + f"/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{target}/participants/{user_id}?avatarSize=32" + ) + + def pr_source_branch_delete_check( + self, project: str, repository: str, _id: str, delete_source_branch: str + ) -> str: + return self._api_url( + f"/rest/pull-request-cleanup/latest/projects/{project}/repos/{repository}/pull-requests/{_id}?deleteSourceRef={delete_source_branch}&retargetDependents={delete_source_branch}" + ) + + def validate_merge(self, project: str, repository: str, _id: str) -> str: + return self._api_url( + f"/rest/api/latest/projects/{project}/repos/{repository}/pull-requests/{_id}/merge" + ) + + def merge_config(self, project: str, repository: str) -> str: + return self._api_url( + f"/rest/api/latest/projects/{project}/repos/{repository}/settings/pull-requests" + ) + + def get_merge_info(self, project: str, repository: str, target_branch: str) -> str: + return self._api_url( + f"/rest/branch-utils/latest/projects/{project}/repos/{repository}/automerge/path/refs/heads/{target_branch}" + ) + + def pr_merge_body( + self, + project: str, + repository: str, + _id: str, + from_branch: str, + target_branch: str, + ) -> str: + return json.dumps( + { + "autoSubject": False, + "message": f"Merge pull request #{_id} in {project}/{repository} from {from_branch} to {target_branch}", + } + ) + + def pr_cleanup(self, project: str, repository: str, _id: str) -> str: + return self._api_url( + f"/rest/pull-request-cleanup/latest/projects/{project}/repos/{repository}/pull-requests/{_id}" + ) + + def pr_cleanup_body(self, delete_retarget: bool) -> str: + return json.dumps( + { + "deleteSourceRef": delete_retarget, + "retargetDependents": delete_retarget, + } + ) + + def pr_rebase(self, project: str, repository: str, _id: str, version: int) -> list: + return [ + json.dumps({"version": version}), + self._api_url( + f"/rest/git/latest/projects/{project}/repos/{repository}/pull-requests/{_id}/rebase" + ), + ] + + def delete_branch(self, project: str, repository: str, source_branch: str) -> list: + return [ + json.dumps({"name": f"{source_branch}"}), + self._api_url( + f"/rest/branch-utils/latest/projects/{project}/repos/{repository}/branches" + ), + ] + + def delete_repo(self, project: str, repo: str) -> str: + return self._api_url(f"/rest/api/latest/projects/{project}/repos/{repo}") + + def create_repo(self, project: str, repo: str) -> str: + return self._api_url(f"/rest/api/latest/projects/{project}/repos") + + +bitbucket_api = BitbucketAPI(parse()[2]) if is_config_present() else None diff --git a/bb/utils/helper.py b/bb/utils/helper.py new file mode 100755 index 0000000..ba0210a --- /dev/null +++ b/bb/utils/helper.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- + +""" +utils.validate - consists of validation functions +""" + +from typing import Any, Callable, Dict + +from typer import Exit, prompt + +from bb.utils import request, richprint +from bb.utils.api import bitbucket_api + +state: Dict[str, Any] = {"verbose": False} + + +def validate_config() -> None: + """ + calls the `api.test` function, If the response code is not 200, + prints exception and return non-zero exit code + """ + try: + message = "Validating connection... " + with richprint.live_progress(message) as live: + response = request.get(bitbucket_api.test()) + if response[0] == 200: + live.update(richprint.console.print("OK", style="bold green")) + except Exception as err: + raise ValueError(err) from err + + +def validate_input(_input: Any, expected: str, error: str) -> str: + """ + validates the input, raise the error if the value is not as expected + """ + + def checker(): + if not isinstance(_input, (str)): + raise ValueError(error) + + if _input is None or _input.lower() == "none": + raise ValueError(error) + + checker() + + if not _input: + _input: str = prompt(f"? {expected}") + checker() + + return _input + + +def error_tip() -> None: + """ + reusable error message across mainstream commands + """ + richprint.console.print( + "\n💻 Try running 'bb --verbose [OPTIONS] COMMAND [ARGS]' to debug", + style="dim white", + ) + + +def error_handler(func: Callable) -> Callable: + def wrapper(*args, **kwargs): + try: + func(*args, **kwargs) + except Exception as err: + richprint.console.print(f"ERROR: {err}", style="bold red") + if state["verbose"]: + richprint.traceback_to_console() + else: + error_tip() + Exit(code=1) + + return wrapper diff --git a/bb/utils/ini.py b/bb/utils/ini.py index 5ab41d8..097e1cb 100755 --- a/bb/utils/ini.py +++ b/bb/utils/ini.py @@ -8,9 +8,10 @@ import configparser import os from pathlib import Path +from typing import List, Tuple -def config_path() -> tuple[str, str]: +def config_path() -> Tuple[str, str]: """ Returns the path to the directory and file where the application's config file should be located. @@ -31,7 +32,7 @@ def is_config_present() -> bool: return os.path.isfile(BB_CONFIG_FILE) -def _setup(bitbucket_host: str, username: str, token: str) -> None: +def auth_setup(bitbucket_host: str, username: str, token: str) -> None: """ It creates a config file with the given parameters. """ @@ -56,7 +57,7 @@ def _setup(bitbucket_host: str, username: str, token: str) -> None: ini.write(w_alt.open("w", encoding="utf-8")) -def parse() -> list: +def parse() -> List[str]: """ It returns the configuration present in .alt file in home directory """ diff --git a/bb/utils/request.py b/bb/utils/request.py index 620a895..8174a1b 100755 --- a/bb/utils/request.py +++ b/bb/utils/request.py @@ -9,10 +9,14 @@ import httpx +from bb.utils.ini import is_config_present, parse from bb.utils.richprint import str_print content_type: str = "application/json;charset=UTF-8" +if is_config_present(): + username, token, _ = parse() + def http_response_definitions(status_code: int) -> str: """ @@ -24,7 +28,7 @@ def http_response_definitions(status_code: int) -> str: return "Unknown Status Code" -def get(url: str, username: str, token: str) -> list: +def get(url: str) -> list[int, dict]: """ It makes a get request to the url, with the username and token as authentication. """ @@ -47,7 +51,7 @@ def get(url: str, username: str, token: str) -> list: return [request.status_code, data] -def post(url: str, username: str, token: str, body: dict) -> list: +def post(url: str, body: dict) -> list[int, dict]: """ This function makes a POST request to the specified URL, using the specified username and token for authentication, and the specified body as the request body @@ -71,7 +75,7 @@ def post(url: str, username: str, token: str, body: dict) -> list: return [request.status_code, json_data] -def put(url: str, username: str, token: str, body: dict) -> list: +def put(url: str, body: dict) -> list[int, dict]: """ This function makes a PUT request to the specified URL with the specified username and token and returns the status code @@ -94,7 +98,7 @@ def put(url: str, username: str, token: str, body: dict) -> list: return [request.status_code, request.json()] -def delete(url: str, username: str, token: str, body: dict) -> int: +def delete(url: str, body: dict) -> int: """ This function sends a DELETE request to the specified URL with the specified username and token, and returns the HTTP status code diff --git a/bb/utils/validate.py b/bb/utils/validate.py deleted file mode 100755 index f39d082..0000000 --- a/bb/utils/validate.py +++ /dev/null @@ -1,50 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -utils.validate - consists of validation functions -""" - -from typer import prompt - -from bb.utils import api, ini, request, richprint - -state: dict = {"verbose": False} - - -def validate_config(): - """ - calls the `api.test` function, If the response code is not 200, - prints exception and return non-zero exit code - """ - try: - username, token, bitbucket_host = ini.parse() - message = f"Validating connection with '{bitbucket_host}'... " - with richprint.live_progress(message) as live: - response = request.get(api.test(bitbucket_host), username, token) - if response[0] == 200: - live.update(richprint.console.print("OK", style="bold green")) - except Exception as err: - raise ValueError(err) from err - - -def validate_input(_input: any, expected: str, error: str) -> str: - """ - validates the input, raise the error if the value is not as expected - """ - if not _input: - _input: str = prompt(f"? {expected}") - - if _input is None or _input.lower() == "none": - raise ValueError(error) - - return _input - - -def error_tip() -> None: - """ - reusable error message across mainstream commands - """ - richprint.console.print( - "\n💻 Try running 'bb --verbose [OPTIONS] COMMAND [ARGS]' to debug", - style="dim white", - ) diff --git a/config.ini b/config.ini index 260d380..41fda7b 100755 --- a/config.ini +++ b/config.ini @@ -1,4 +1,4 @@ [auth] -bitbucket_host = http://localhost:7990 +bitbucket_host = http://localhost username = xxxxxxxx token = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx diff --git a/pdm.lock b/pdm.lock index fc8ee6a..fbd729c 100755 --- a/pdm.lock +++ b/pdm.lock @@ -23,29 +23,28 @@ files = [ [[package]] name = "bandit" -version = "1.7.6" +version = "1.7.7" requires_python = ">=3.8" summary = "Security oriented static analyser for python code." dependencies = [ - "GitPython>=3.1.30", "PyYAML>=5.3.1", "colorama>=0.3.9; platform_system == \"Windows\"", "rich", "stevedore>=1.20.0", ] files = [ - {file = "bandit-1.7.6-py3-none-any.whl", hash = "sha256:36da17c67fc87579a5d20c323c8d0b1643a890a2b93f00b3d1229966624694ff"}, - {file = "bandit-1.7.6.tar.gz", hash = "sha256:72ce7bc9741374d96fb2f1c9a8960829885f1243ffde743de70a19cee353e8f3"}, + {file = "bandit-1.7.7-py3-none-any.whl", hash = "sha256:17e60786a7ea3c9ec84569fd5aee09936d116cb0cb43151023258340dbffb7ed"}, + {file = "bandit-1.7.7.tar.gz", hash = "sha256:527906bec6088cb499aae31bc962864b4e77569e9d529ee51df3a93b4b8ab28a"}, ] [[package]] name = "cachetools" -version = "5.3.1" +version = "5.3.2" requires_python = ">=3.7" summary = "Extensible memoizing collections and decorators" files = [ - {file = "cachetools-5.3.1-py3-none-any.whl", hash = "sha256:95ef631eeaea14ba2e36f06437f36463aac3a096799e876ee55e5cdccb102590"}, - {file = "cachetools-5.3.1.tar.gz", hash = "sha256:dce83f2d9b4e1f732a8cd44af8e8fab2dbe46201467fc98b3ef8f269092bf62b"}, + {file = "cachetools-5.3.2-py3-none-any.whl", hash = "sha256:861f35a13a451f94e301ce2bec7cac63e881232ccce7ed67fab9b5df4d3beaa1"}, + {file = "cachetools-5.3.2.tar.gz", hash = "sha256:086ee420196f7b2ab9ca2db2520aca326318b68fe5ba8bc4d49cca91add450f2"}, ] [[package]] @@ -243,32 +242,6 @@ files = [ {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, ] -[[package]] -name = "gitdb" -version = "4.0.10" -requires_python = ">=3.7" -summary = "Git Object Database" -dependencies = [ - "smmap<6,>=3.0.1", -] -files = [ - {file = "gitdb-4.0.10-py3-none-any.whl", hash = "sha256:c286cf298426064079ed96a9e4a9d39e7f3e9bf15ba60701e95f5492f28415c7"}, - {file = "gitdb-4.0.10.tar.gz", hash = "sha256:6eb990b69df4e15bad899ea868dc46572c3f75339735663b81de79b06f17eb9a"}, -] - -[[package]] -name = "gitpython" -version = "3.1.31" -requires_python = ">=3.7" -summary = "GitPython is a Python library used to interact with Git repositories" -dependencies = [ - "gitdb<5,>=4.0.1", -] -files = [ - {file = "GitPython-3.1.31-py3-none-any.whl", hash = "sha256:f04893614f6aa713a60cbbe1e6a97403ef633103cdd0ef5eb6efe0deb98dbe8d"}, - {file = "GitPython-3.1.31.tar.gz", hash = "sha256:8ce3bcf69adfdf7c7d503e78fd3b1c492af782d58893b650adb2ac8912ddd573"}, -] - [[package]] name = "h11" version = "0.14.0" @@ -355,12 +328,12 @@ files = [ [[package]] name = "packaging" -version = "23.1" +version = "23.2" requires_python = ">=3.7" summary = "Core utilities for Python packages" files = [ - {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, - {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, ] [[package]] @@ -375,12 +348,12 @@ files = [ [[package]] name = "platformdirs" -version = "3.10.0" -requires_python = ">=3.7" +version = "4.2.0" +requires_python = ">=3.8" summary = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." files = [ - {file = "platformdirs-3.10.0-py3-none-any.whl", hash = "sha256:d7c24979f292f916dc9cbf8648319032f551ea8c49a4c9bf2fb556a02070ec1d"}, - {file = "platformdirs-3.10.0.tar.gz", hash = "sha256:b45696dab2d7cc691a3226759c0d3b00c47c8b6e293d96f6436f733303f77f6d"}, + {file = "platformdirs-4.2.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, + {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, ] [[package]] @@ -419,20 +392,20 @@ files = [ [[package]] name = "pytest" -version = "7.4.4" -requires_python = ">=3.7" +version = "8.0.1" +requires_python = ">=3.8" summary = "pytest: simple powerful testing with Python" dependencies = [ "colorama; sys_platform == \"win32\"", "exceptiongroup>=1.0.0rc8; python_version < \"3.11\"", "iniconfig", "packaging", - "pluggy<2.0,>=0.12", + "pluggy<2.0,>=1.3.0", "tomli>=1.0.0; python_version < \"3.11\"", ] files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.0.1-py3-none-any.whl", hash = "sha256:3e4f16fe1c0a9dc9d9389161c127c3edc5d810c38d6793042fb81d9f48a59fca"}, + {file = "pytest-8.0.1.tar.gz", hash = "sha256:267f6563751877d772019b13aacbe4e860d73fe8f651f28112e9ac37de7513ae"}, ] [[package]] @@ -508,27 +481,27 @@ files = [ [[package]] name = "ruff" -version = "0.1.11" +version = "0.2.2" requires_python = ">=3.7" summary = "An extremely fast Python linter and code formatter, written in Rust." files = [ - {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a7f772696b4cdc0a3b2e527fc3c7ccc41cdcb98f5c80fdd4f2b8c50eb1458196"}, - {file = "ruff-0.1.11-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:934832f6ed9b34a7d5feea58972635c2039c7a3b434fe5ba2ce015064cb6e955"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ea0d3e950e394c4b332bcdd112aa566010a9f9c95814844a7468325290aabfd9"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9bd4025b9c5b429a48280785a2b71d479798a69f5c2919e7d274c5f4b32c3607"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1ad00662305dcb1e987f5ec214d31f7d6a062cae3e74c1cbccef15afd96611d"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:4b077ce83f47dd6bea1991af08b140e8b8339f0ba8cb9b7a484c30ebab18a23f"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c4a88efecec23c37b11076fe676e15c6cdb1271a38f2b415e381e87fe4517f18"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5b25093dad3b055667730a9b491129c42d45e11cdb7043b702e97125bcec48a1"}, - {file = "ruff-0.1.11-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:231d8fb11b2cc7c0366a326a66dafc6ad449d7fcdbc268497ee47e1334f66f77"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:09c415716884950080921dd6237767e52e227e397e2008e2bed410117679975b"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0f58948c6d212a6b8d41cd59e349751018797ce1727f961c2fa755ad6208ba45"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_i686.whl", hash = "sha256:190a566c8f766c37074d99640cd9ca3da11d8deae2deae7c9505e68a4a30f740"}, - {file = "ruff-0.1.11-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6464289bd67b2344d2a5d9158d5eb81025258f169e69a46b741b396ffb0cda95"}, - {file = "ruff-0.1.11-py3-none-win32.whl", hash = "sha256:9b8f397902f92bc2e70fb6bebfa2139008dc72ae5177e66c383fa5426cb0bf2c"}, - {file = "ruff-0.1.11-py3-none-win_amd64.whl", hash = "sha256:eb85ee287b11f901037a6683b2374bb0ec82928c5cbc984f575d0437979c521a"}, - {file = "ruff-0.1.11-py3-none-win_arm64.whl", hash = "sha256:97ce4d752f964ba559c7023a86e5f8e97f026d511e48013987623915431c7ea9"}, - {file = "ruff-0.1.11.tar.gz", hash = "sha256:f9d4d88cb6eeb4dfe20f9f0519bd2eaba8119bde87c3d5065c541dbae2b5a2cb"}, + {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:0a9efb032855ffb3c21f6405751d5e147b0c6b631e3ca3f6b20f917572b97eb6"}, + {file = "ruff-0.2.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:d450b7fbff85913f866a5384d8912710936e2b96da74541c82c1b458472ddb39"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ecd46e3106850a5c26aee114e562c329f9a1fbe9e4821b008c4404f64ff9ce73"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e22676a5b875bd72acd3d11d5fa9075d3a5f53b877fe7b4793e4673499318ba"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1695700d1e25a99d28f7a1636d85bafcc5030bba9d0578c0781ba1790dbcf51c"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:b0c232af3d0bd8f521806223723456ffebf8e323bd1e4e82b0befb20ba18388e"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f63d96494eeec2fc70d909393bcd76c69f35334cdbd9e20d089fb3f0640216ca"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6a61ea0ff048e06de273b2e45bd72629f470f5da8f71daf09fe481278b175001"}, + {file = "ruff-0.2.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5e1439c8f407e4f356470e54cdecdca1bd5439a0673792dbe34a2b0a551a2fe3"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:940de32dc8853eba0f67f7198b3e79bc6ba95c2edbfdfac2144c8235114d6726"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0c126da55c38dd917621552ab430213bdb3273bb10ddb67bc4b761989210eb6e"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:3b65494f7e4bed2e74110dac1f0d17dc8e1f42faaa784e7c58a98e335ec83d7e"}, + {file = "ruff-0.2.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1ec49be4fe6ddac0503833f3ed8930528e26d1e60ad35c2446da372d16651ce9"}, + {file = "ruff-0.2.2-py3-none-win32.whl", hash = "sha256:d920499b576f6c68295bc04e7b17b6544d9d05f196bb3aac4358792ef6f34325"}, + {file = "ruff-0.2.2-py3-none-win_amd64.whl", hash = "sha256:cc9a91ae137d687f43a44c900e5d95e9617cb37d4c989e462980ba27039d239d"}, + {file = "ruff-0.2.2-py3-none-win_arm64.whl", hash = "sha256:c9d15fc41e6054bfc7200478720570078f0b41c9ae4f010bcc16bd6f4d1aacdd"}, + {file = "ruff-0.2.2.tar.gz", hash = "sha256:e62ed7f36b3068a30ba39193a14274cd706bc486fad521276458022f7bccb31d"}, ] [[package]] @@ -541,16 +514,6 @@ files = [ {file = "shellingham-1.5.0.post1.tar.gz", hash = "sha256:823bc5fb5c34d60f285b624e7264f4dda254bc803a3774a147bf99c0e3004a28"}, ] -[[package]] -name = "smmap" -version = "5.0.0" -requires_python = ">=3.6" -summary = "A pure Python implementation of a sliding window memory map manager" -files = [ - {file = "smmap-5.0.0-py3-none-any.whl", hash = "sha256:2aba19d6a040e78d8b09de5c57e96207b09ed71d8e55ce0959eeee6c8e190d94"}, - {file = "smmap-5.0.0.tar.gz", hash = "sha256:c840e62059cd3be204b0c9c9f74be2c09d5648eddd4580d9314c3ecde0b30936"}, -] - [[package]] name = "sniffio" version = "1.3.0" @@ -586,24 +549,24 @@ files = [ [[package]] name = "tox" -version = "4.11.4" +version = "4.13.0" requires_python = ">=3.8" summary = "tox is a generic virtualenv management and test command line tool" dependencies = [ - "cachetools>=5.3.1", + "cachetools>=5.3.2", "chardet>=5.2", "colorama>=0.4.6", - "filelock>=3.12.3", - "packaging>=23.1", - "platformdirs>=3.10", + "filelock>=3.13.1", + "packaging>=23.2", + "platformdirs>=4.1", "pluggy>=1.3", "pyproject-api>=1.6.1", "tomli>=2.0.1; python_version < \"3.11\"", - "virtualenv>=20.24.3", + "virtualenv>=20.25", ] files = [ - {file = "tox-4.11.4-py3-none-any.whl", hash = "sha256:2adb83d68f27116812b69aa36676a8d6a52249cb0d173649de0e7d0c2e3e7229"}, - {file = "tox-4.11.4.tar.gz", hash = "sha256:73a7240778fabf305aeb05ab8ea26e575e042ab5a18d71d0ed13e343a51d6ce1"}, + {file = "tox-4.13.0-py3-none-any.whl", hash = "sha256:1143c7e2489c68026a55d3d4ae84c02c449f073b28e62f80e3e440a3b72a4afa"}, + {file = "tox-4.13.0.tar.gz", hash = "sha256:dd789a554c16c4b532924ba393c92fc8991323c4b3d466712bfecc8c9b9f24f7"}, ] [[package]] @@ -663,15 +626,15 @@ files = [ [[package]] name = "virtualenv" -version = "20.24.5" +version = "20.25.0" requires_python = ">=3.7" summary = "Virtual Python Environment builder" dependencies = [ "distlib<1,>=0.3.7", "filelock<4,>=3.12.2", - "platformdirs<4,>=3.9.1", + "platformdirs<5,>=3.9.1", ] files = [ - {file = "virtualenv-20.24.5-py3-none-any.whl", hash = "sha256:b80039f280f4919c77b30f1c23294ae357c4c8701042086e3fc005963e4e537b"}, - {file = "virtualenv-20.24.5.tar.gz", hash = "sha256:e8361967f6da6fbdf1426483bfe9fca8287c242ac0bc30429905721cefbff752"}, + {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, + {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, ] diff --git a/pyproject.toml b/pyproject.toml index 8a0d0be..32a0b19 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,16 +2,11 @@ name = "bb" dynamic = ["version"] description = "Work seamlessly with BitBucket from the command line." -authors = [ - {name = "psadi", email = "adithya3494@gmail.com"}, -] -dependencies = [ - "typer[all]>=0.7.0", - "httpx>=0.24.0", -] +authors = [{ name = "psadi", email = "ps.adithya@icloud.com" }] +dependencies = ["typer[all]>=0.7.0", "httpx>=0.24.0"] requires-python = ">=3.8" readme = "README.md" -license = {text = "MIT"} +license = { text = "MIT" } [project.scripts] bb = "bb:_bb" @@ -53,4 +48,4 @@ line-ending = "auto" extend-select = ["I"] [tool.bandit] -skips = ["B404","B603","B607"] +skips = ["B404", "B603", "B607"] diff --git a/requirements.txt b/requirements.txt index d4f51ca..c829ba0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,8 +2,8 @@ # Please do not edit it manually. anyio==3.6.2 -bandit==1.7.6 -cachetools==5.3.1 +bandit==1.7.7 +cachetools==5.3.2 certifi==2022.12.7 chardet==5.2.0 click==8.1.3 @@ -12,8 +12,6 @@ coverage==7.2.5 distlib==0.3.7 exceptiongroup==1.1.1; python_version < "3.11" filelock==3.13.1 -gitdb==4.0.10 -GitPython==3.1.31 h11==0.14.0 httpcore==1.0.2 httpx==0.26.0 @@ -21,24 +19,23 @@ idna==3.4 iniconfig==2.0.0 markdown-it-py==2.2.0 mdurl==0.1.2 -packaging==23.1 +packaging==23.2 pbr==5.11.1 -platformdirs==3.10.0 +platformdirs==4.2.0 pluggy==1.3.0 pygments==2.15.1 pyproject-api==1.6.1 -pytest==7.4.4 +pytest==8.0.1 pytest-cov==4.1.0 PyYAML==6.0 rich==13.3.5 -ruff==0.1.11 +ruff==0.2.2 shellingham==1.5.0.post1 -smmap==5.0.0 sniffio==1.3.0 stevedore==3.5.2 tomli==2.0.1; python_version < "3.11" -tox==4.11.4 +tox==4.13.0 tox-pdm==0.7.2 typer==0.9.0 typing-extensions==4.7.1 -virtualenv==20.24.5 +virtualenv==20.25.0 diff --git a/tests/test_api.py b/tests/test_api.py index b2bf449..77c5408 100755 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -4,13 +4,13 @@ from props import Api -from bb.utils import api +from bb.utils.api import bitbucket_api property = Api() def test_test(): - test = api.test(property.bitbucket_host) + test = bitbucket_api.test() assert ( test == f"{property.bitbucket_host}/rest/api/latest/inbox/pull-requests/count" ) @@ -18,8 +18,8 @@ def test_test(): def test_pull_request_create(): - pull_request_create = api.pull_request_create( - property.bitbucket_host, property.project, property.repository + pull_request_create = bitbucket_api.pull_request_create( + property.project, property.repository ) assert ( pull_request_create @@ -29,7 +29,7 @@ def test_pull_request_create(): def test_get_repo_info(): - get_repo_info = api.get_repo_info(property.bitbucket_host, property.project) + get_repo_info = bitbucket_api.get_repo_info(property.project) assert ( get_repo_info == f"{property.bitbucket_host}/rest/api/latest/projects/{property.project}/repos?start=0&limit=10000" @@ -38,8 +38,7 @@ def test_get_repo_info(): def test_default_reviewers(): - default_reviewers = api.default_reviewers( - property.bitbucket_host, + default_reviewers = bitbucket_api.default_reviewers( property.project, property.repo_id, property.from_branch, @@ -62,7 +61,7 @@ def test_default_reviewers(): def test_pull_request_body(): - pull_request_body = api.pull_request_body( + pull_request_body = bitbucket_api.pull_request_body( property.title_and_description, property.from_branch, property.repository, @@ -103,8 +102,8 @@ def test_pull_request_body(): def test_pull_request_difference(): - pull_request_difference = api.pull_request_difference( - property.bitbucket_host, property.project, property.repository, property.pr_no + pull_request_difference = bitbucket_api.pull_request_difference( + property.project, property.repository, property.pr_no ) assert ( @@ -116,8 +115,8 @@ def test_pull_request_difference(): def test_pull_request_info(): - pull_request_info = api.pull_request_info( - property.bitbucket_host, property.project, property.repository, property.pr_no + pull_request_info = bitbucket_api.pull_request_info( + property.project, property.repository, property.pr_no ) assert ( @@ -129,9 +128,7 @@ def test_pull_request_info(): def test_pull_request_viewer(): - pull_request_viewer = api.pull_request_viewer( - property.bitbucket_host, property.role - ) + pull_request_viewer = bitbucket_api.pull_request_viewer(property.role) assert ( pull_request_viewer @@ -142,8 +139,8 @@ def test_pull_request_viewer(): def test_current_pull_request(): - current_pull_request = api.current_pull_request( - property.bitbucket_host, property.project, property.repository + current_pull_request = bitbucket_api.current_pull_request( + property.project, property.repository ) assert ( @@ -155,15 +152,14 @@ def test_current_pull_request(): def test_whoami(): - whoami = api.whoami(property.bitbucket_host) + whoami = bitbucket_api.whoami() assert whoami == f"{property.bitbucket_host}/plugins/servlet/applinks/whoami" assert isinstance(whoami, str) def test_action_pull_request(): - action_pull_request = api.action_pull_request( - property.bitbucket_host, + action_pull_request = bitbucket_api.action_pull_request( property.project, property.repository, property.target, @@ -178,8 +174,7 @@ def test_action_pull_request(): def test_pr_source_branch_delete_check(): - pr_source_branch_delete_check = api.pr_source_branch_delete_check( - property.bitbucket_host, + pr_source_branch_delete_check = bitbucket_api.pr_source_branch_delete_check( property.project, property.repository, property.pr_no, @@ -194,8 +189,8 @@ def test_pr_source_branch_delete_check(): def test_validate_merge(): - validate_merge = api.validate_merge( - property.bitbucket_host, property.project, property.repository, property.pr_no + validate_merge = bitbucket_api.validate_merge( + property.project, property.repository, property.pr_no ) assert ( validate_merge @@ -205,9 +200,7 @@ def test_validate_merge(): def test_merge_config(): - merge_config = api.merge_config( - property.bitbucket_host, property.project, property.repository - ) + merge_config = bitbucket_api.merge_config(property.project, property.repository) assert ( merge_config @@ -217,8 +210,8 @@ def test_merge_config(): def test_get_merge_info(): - get_merge_info = api.get_merge_info( - property.bitbucket_host, property.project, property.repository, property.target + get_merge_info = bitbucket_api.get_merge_info( + property.project, property.repository, property.target ) assert ( get_merge_info @@ -228,7 +221,7 @@ def test_get_merge_info(): def test_pr_merge_body(): - pr_merge_body = api.pr_merge_body( + pr_merge_body = bitbucket_api.pr_merge_body( property.project, property.repository, property.pr_no, @@ -247,8 +240,8 @@ def test_pr_merge_body(): def test_pr_cleanup(): - pr_cleanup = api.pr_cleanup( - property.bitbucket_host, property.project, property.repository, property.pr_no + pr_cleanup = bitbucket_api.pr_cleanup( + property.project, property.repository, property.pr_no ) assert ( pr_cleanup @@ -259,17 +252,16 @@ def test_pr_cleanup(): def test_pr_cleanup_body(): for prop in property.delete_source_branch: - pr_cleanup_body = api.pr_cleanup_body(prop) + pr_cleanup_body = bitbucket_api.pr_cleanup_body(prop) assert isinstance(prop, bool) assert pr_cleanup_body == json.dumps( - {"deleteSourceRef": prop, "retargetDependents": True} + {"deleteSourceRef": prop, "retargetDependents": prop} ) assert isinstance(pr_cleanup_body, str) def test_pr_rebase(): - pr_rebase = api.pr_rebase( - property.bitbucket_host, + pr_rebase = bitbucket_api.pr_rebase( property.project, property.repository, property.pr_no, @@ -284,8 +276,7 @@ def test_pr_rebase(): def test_delete_branch(): - delete_branch = api.delete_branch( - property.bitbucket_host, + delete_branch = bitbucket_api.delete_branch( property.project, property.repository, property.from_branch, diff --git a/tests/test_helper.py b/tests/test_helper.py new file mode 100644 index 0000000..fe4deab --- /dev/null +++ b/tests/test_helper.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- +import pytest + +from bb.utils.helper import validate_input + + +def test_validate_input(): + # Test case 1: Valid input + assert validate_input("hello", "Enter a string", "Invalid input") == "hello" + + # Test case 2: Invalid input + with pytest.raises(ValueError, match="Invalid input"): + validate_input(123, "Enter a string", "Invalid input") + + # Test case 3: Empty input + # with pytest.raises(ValueError, match="Invalid input"): + # validate_input("", "Enter a string", "Invalid input") + + # Test case 4: None input + with pytest.raises(ValueError, match="Invalid input"): + validate_input(None, "Enter a string", "Invalid input") + + # Test case 5: Valid input with different prompt and error message + assert ( + validate_input("test", "Enter another string", "Different error message") + == "test" + ) + + # Test case 6: Input with leading and trailing spaces + assert validate_input(" hello ", "Enter a string", "Invalid input") == " hello " + + # Test case 7: Input with special characters + assert validate_input("@#$$%", "Enter a string", "Invalid input") == "@#$$%" + + # Test case 8: Numeric string input + assert validate_input("12345", "Enter a string", "Invalid input") == "12345" + + # Test case 9: Input is a boolean + with pytest.raises(ValueError, match="Invalid input"): + validate_input(True, "Enter a string", "Invalid input") + + # Test case 10: Input is a list + with pytest.raises(ValueError, match="Invalid input"): + validate_input(["hello"], "Enter a string", "Invalid input") diff --git a/tests/test_request.py b/tests/test_request.py index e62ea5a..fb01bc7 100644 --- a/tests/test_request.py +++ b/tests/test_request.py @@ -28,18 +28,18 @@ def test_post_error(): url = "https://example.com" data = {"key": "value"} with pytest.raises(ValueError): - post(url, "username", "password", data) + post(url, data) # def test_put_error(): # url = "https://example.com" # data = {"key": "value"} # with pytest.raises(ValueError): -# put(url, "username", "password", data) +# put(url, data) def test_delete_error(): url = "https://example.com" data = {"key": "value"} with pytest.raises(ValueError): - delete(url, "username", "password", data) + delete(url, data) diff --git a/tests/test_validate.py b/tests/test_validate.py deleted file mode 100644 index 486c4a8..0000000 --- a/tests/test_validate.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- -from bb.utils.validate import validate_input - - -def test_validate_input(): - # Test case 1: Valid input - assert validate_input("hello", "Enter a string", "Invalid input") == "hello"