Skip to content

Instantly share code, notes, and snippets.

@code-yeongyu
Last active November 10, 2022 06:15
Show Gist options
  • Save code-yeongyu/4ce1b027c9ccad78a79a5542c6be4a8b to your computer and use it in GitHub Desktop.
Save code-yeongyu/4ce1b027c9ccad78a79a5542c6be4a8b to your computer and use it in GitHub Desktop.
Open bitbucket with command like gh-cli
#!/usr/bin/env python
import subprocess
import types
from enum import Enum
from typing import Optional
def import_or_install(package: str) -> types.ModuleType:
try:
return __import__(package)
except ImportError:
import pip
pip.main(['install', package])
return __import__(package)
typer = import_or_install('typer')
pyperclip = import_or_install('pyperclip')
def execute(command: str) -> subprocess.CompletedProcess[bytes]:
return subprocess.run(command.split(" "), stdout=subprocess.PIPE)
def convert_git_url_to_bitbucket_url(git_url: str) -> str:
BASE_URL = git_url.split("/")[0:3]
PROJECT_NAME = git_url.split("/")[-2]
REPO_NAME = git_url.split("/")[-1].split(".")[0]
return "/".join(BASE_URL + ["projects", PROJECT_NAME, "repos", REPO_NAME])
def get_bitbucket_url() -> str:
git_url = execute("git remote get-url origin").stdout.decode(
"utf-8").strip()
return convert_git_url_to_bitbucket_url(git_url)
app = typer.Typer()
class RepoActionType(str, Enum):
VIEW = "view"
@app.command()
def repo(type: RepoActionType):
BITBUCKET_URL = get_bitbucket_url()
if type == RepoActionType.VIEW:
execute(f"open {BITBUCKET_URL}")
class PrActionType(str, Enum):
VIEW = "view"
CREATE = "create"
@app.command()
def pr(type: PrActionType,
number: Optional[int] = typer.Argument(None),
base: Optional[str] = typer.Option(
None, help="Base branch 의 이름. 기본 값은 현재 branch 입니다."),
target: str = typer.Option(
"devel", help="Target branch 의 이름. 기본 값은 `devel` 입니다.")):
BITBUCKET_URL = get_bitbucket_url()
if type == PrActionType.VIEW:
command = f"open {BITBUCKET_URL}/pull-requests/"
if number is not None:
command += f"{number}"
execute(command)
elif type == PrActionType.CREATE:
operation_url = f"{BITBUCKET_URL}/pull-requests?create&"
base = base or execute("git branch --show-current").stdout.decode(
"utf-8").strip()
target = target or 'devel'
if base:
operation_url += f"sourceBranch=refs%2Fheads%2F{base}&"
if target:
operation_url += f"targetBranch=refs%2Fheads%2F{target}&"
push_branch_if_not_exists(base)
execute(f"open {operation_url}")
pyperclip.copy(get_pr_template("master"))
def push_branch_if_not_exists(branch_name: str) -> None:
remote = execute("git remote get-url origin").stdout.decode(
"utf-8").strip()
is_branch_exists_in_origin = branch_name in (
execute(f"git ls-remote --heads {remote} {branch_name}").stdout.decode(
"utf-8").strip())
if not is_branch_exists_in_origin:
execute(f"git push -u origin {branch_name}")
def get_pr_template(target_branch: str) -> str:
get_git_log_command = f'git log --pretty=format:%s {target_branch}..'
git_log_raw = execute(get_git_log_command).stdout.decode("utf-8").strip()
git_log = git_log_raw.split("\n")
git_log = ''.join(f"- {log}\n" for log in git_log)
CURRENT_BRANCH_NAME = execute(
'git rev-parse --abbrev-ref HEAD').stdout.decode("utf-8").strip()
template = f'''**커밋 단위로 보시면 리뷰하기 훨씬 편합니다!**
## 배경
- {CURRENT_BRANCH_NAME}
## 작업 내용
{git_log}
## 리뷰 노트'''
return template
if __name__ == "__main__":
app()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment