Skip to content
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 84 additions & 6 deletions cherry_picker/cherry_picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,83 @@ class InvalidRepoException(Exception):
pass


class UserPreferences:
SCHEMA = {
"upstream_remote": str,
"pr_remote": str,
"auto_pr": bool,
"push": bool,
}

def __init__(
self,
*,
pr_remote="origin",
upstream_remote=None,
push=True,
auto_pr=True,
):
self.pr_remote = pr_remote
self.upstream_remote = upstream_remote
self.push = push
self.auto_pr = auto_pr

@staticmethod
def get_preferences_path():
return os.path.join(
os.path.expanduser("~"), ".config", "cherry_picker", "preferences.toml"
)

@classmethod
def from_ctx(cls, ctx):
preferences_path = cls.get_preferences_path()
if not os.path.exists(preferences_path):
return cls()

applicable_preferences = cls._get_applicable_preferences(ctx, preferences_path)
kwargs = {}

for preferences in applicable_preferences:
for key, expected_type in cls.SCHEMA.items():
value = preferences.get(key)
if value is None:
continue
if type(value) is not expected_type:
raise ValueError(
f"User preference for {key} is of invalid type ({type(value)},"
f" {expected_type} was expected."
)
kwargs[key] = value

return cls(**kwargs)

@classmethod
def _get_applicable_preferences(cls, ctx, preferences_path):
with open(preferences_path, "rb") as fp:
data = tomllib.load(fp)
applicable_preferences = []

if "global" in data:
global_preferences = data["global"]
applicable_preferences.append(global_preferences)
cls._maybe_append_continue(ctx, applicable_preferences, global_preferences)

cwd = os.getcwd()
if "local" in data and cwd in data["local"]:
local_preferences = data["local"][cwd]
applicable_preferences.append(local_preferences[cwd])
cls._maybe_append_continue(ctx, applicable_preferences, local_preferences)

applicable_preferences.append(ctx.params)

return applicable_preferences

@staticmethod
def _maybe_append_continue(ctx, applicable_preferences, preferences):
if ctx.params["abort"] is False and "--continue" in preferences:
applicable_preferences.append(preferences["--continue"])


class CherryPicker:
ALLOWED_STATES = WORKFLOW_STATES.BACKPORT_PAUSED, WORKFLOW_STATES.UNSET
"""The list of states expected at the start of the app."""
Expand Down Expand Up @@ -715,7 +792,7 @@ def is_mirror(self) -> bool:
"pr_remote",
metavar="REMOTE",
help="git remote to use for PR branches",
default="origin",
default=None,
)
@click.option(
"--upstream-remote",
Expand Down Expand Up @@ -749,14 +826,14 @@ def is_mirror(self) -> bool:
"--push/--no-push",
"push",
is_flag=True,
default=True,
default=None,
help="Changes won't be pushed to remote",
)
@click.option(
"--auto-pr/--no-auto-pr",
"auto_pr",
is_flag=True,
default=True,
default=None,
help=(
"If auto PR is enabled, cherry-picker will automatically open a PR"
" through API if GH_AUTH env var is set, or automatically open the PR"
Expand Down Expand Up @@ -795,16 +872,17 @@ def cherry_pick_cli(
click.echo("\U0001F40D \U0001F352 \u26CF")

chosen_config_path, config = load_config(config_path)
user_preferences = UserPreferences.from_ctx(ctx)

try:
cherry_picker = CherryPicker(
pr_remote,
user_preferences.pr_remote,
commit_sha1,
branches,
upstream_remote=upstream_remote,
dry_run=dry_run,
push=push,
auto_pr=auto_pr,
push=user_preferences.push,
auto_pr=user_preferences.auto_pr,
config=config,
chosen_config_path=chosen_config_path,
)
Expand Down