pygitgo 1.2.0__tar.gz → 1.2.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. {pygitgo-1.2.0/src/pygitgo.egg-info → pygitgo-1.2.1}/PKG-INFO +1 -1
  2. {pygitgo-1.2.0 → pygitgo-1.2.1}/pyproject.toml +1 -1
  3. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/auth/ssh_utils.py +5 -1
  4. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/commands/git_operations.py +28 -4
  5. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/commands/jump.py +1 -2
  6. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/commands/state.py +14 -11
  7. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/main.py +18 -6
  8. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/utils/config.py +3 -1
  9. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/utils/executor.py +13 -7
  10. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/utils/setup.py +1 -1
  11. {pygitgo-1.2.0 → pygitgo-1.2.1/src/pygitgo.egg-info}/PKG-INFO +1 -1
  12. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo.egg-info/SOURCES.txt +2 -0
  13. pygitgo-1.2.1/tests/test_config.py +99 -0
  14. {pygitgo-1.2.0 → pygitgo-1.2.1}/tests/test_git_operations.py +31 -1
  15. {pygitgo-1.2.0 → pygitgo-1.2.1}/tests/test_jump.py +13 -18
  16. {pygitgo-1.2.0 → pygitgo-1.2.1}/tests/test_main.py +2 -1
  17. pygitgo-1.2.1/tests/test_setup.py +55 -0
  18. {pygitgo-1.2.0 → pygitgo-1.2.1}/tests/test_state.py +8 -9
  19. {pygitgo-1.2.0 → pygitgo-1.2.1}/LICENSE +0 -0
  20. {pygitgo-1.2.0 → pygitgo-1.2.1}/README.md +0 -0
  21. {pygitgo-1.2.0 → pygitgo-1.2.1}/setup.cfg +0 -0
  22. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/__init__.py +0 -0
  23. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/auth/__init__.py +0 -0
  24. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/auth/account.py +1 -1
  25. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/auth/manager.py +1 -1
  26. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/commands/__init__.py +0 -0
  27. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/exceptions.py +0 -0
  28. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/utils/__init__.py +0 -0
  29. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/utils/colors.py +0 -0
  30. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo/utils/platform_utils.py +0 -0
  31. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo.egg-info/dependency_links.txt +0 -0
  32. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo.egg-info/entry_points.txt +0 -0
  33. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo.egg-info/requires.txt +0 -0
  34. {pygitgo-1.2.0 → pygitgo-1.2.1}/src/pygitgo.egg-info/top_level.txt +0 -0
  35. {pygitgo-1.2.0 → pygitgo-1.2.1}/tests/test_platform.py +0 -0
  36. {pygitgo-1.2.0 → pygitgo-1.2.1}/tests/test_url_validator.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygitgo
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: GitGo CLI - Your Fast Git Companion. Simplifies git push, link, stash, and user management.
5
5
  Author: Huerte
6
6
  License: GPL-3.0-or-later
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pygitgo"
7
- version = "1.2.0"
7
+ version = "1.2.1"
8
8
  description = "GitGo CLI - Your Fast Git Companion. Simplifies git push, link, stash, and user management."
9
9
  readme = "README.md"
10
10
  license = {text = "GPL-3.0-or-later"}
@@ -1,5 +1,5 @@
1
- from pygitgo.utils.executor import run_command
2
1
  from pygitgo.utils.colors import info, success, warning, error
2
+ from pygitgo.utils.executor import run_command
3
3
  from pygitgo.utils import platform_utils
4
4
  from pathlib import Path
5
5
  import subprocess
@@ -35,11 +35,15 @@ def ensure_github_known_host():
35
35
  def check_connection():
36
36
  ensure_github_known_host()
37
37
  result = run_command(["ssh", "-T", "git@github.com"], allow_fail=True, return_complete=True)
38
+ if not hasattr(result, "stderr") or not result.stderr:
39
+ return False
38
40
  return "successfully authenticated" in result.stderr
39
41
 
40
42
  def get_github_username():
41
43
 
42
44
  result = run_command(["ssh", "-T", "git@github.com"], allow_fail=True, return_complete=True)
45
+ if not hasattr(result, "stderr") or not result.stderr:
46
+ return None
43
47
  output = result.stderr
44
48
 
45
49
  if "Hi " in output and "!" in output:
@@ -2,11 +2,18 @@ from pygitgo.auth.ssh_utils import convert_https_to_ssh, is_ssh_url, check_conne
2
2
  from pygitgo.utils.colors import info, success, warning, error
3
3
  from pygitgo.utils.executor import run_command
4
4
  from pygitgo.utils.config import get_config
5
+ from argparse import Namespace
5
6
  import subprocess
6
7
  import sys
7
8
  import os
8
9
 
9
10
 
11
+ def get_status_content():
12
+ status = run_command(["git", "status", "--porcelain"], allow_fail=True)
13
+ if isinstance(status, subprocess.CalledProcessError) or not status.strip():
14
+ sys.exit(1)
15
+ return status
16
+
10
17
  def get_current_branch():
11
18
  branch = run_command(["git", "branch", "--show-current"]).strip()
12
19
  if not branch:
@@ -26,8 +33,17 @@ def is_branch_exist(branch):
26
33
 
27
34
 
28
35
  def git_new_branch(branch):
29
- run_command(["git", "checkout", "-b", branch], loading_msg=f"Creating branch '{branch}'...")
30
- success(f"\nBranch '{branch}' created.\n")
36
+ result = run_command(["git", "checkout", "-b", branch], loading_msg=f"Creating branch '{branch}'...")
37
+ if isinstance(result, subprocess.CalledProcessError):
38
+ error(f"Failed to create branch '{branch}'! It may already exist.")
39
+ choice = input("\nWould you like to jump to the existing branch instead? (y/n): ").strip().lower()
40
+ if choice == "y":
41
+ from pygitgo.commands.jump import jump_operation
42
+ jump_operation(Namespace(branch=branch))
43
+ else:
44
+ sys.exit(1)
45
+ else:
46
+ success(f"\nBranch '{branch}' created.\n")
31
47
 
32
48
  return branch
33
49
 
@@ -136,8 +152,16 @@ def git_push(branch):
136
152
  if ssh_url:
137
153
  run_command(["git", "remote", "set-url", "origin", ssh_url], loading_msg="Converting remote from HTTPS to SSH for secure push...")
138
154
  success(f"Remote updated to: {ssh_url}")
139
-
140
- run_command(["git", "push", "-u", "origin", branch], loading_msg=f"Pushing to remote branch '{branch}'...")
155
+
156
+ try:
157
+ run_command(["git", "push", "-u", "origin", branch], loading_msg=f"Pushing to remote branch '{branch}'...")
158
+ except (subprocess.CalledProcessError, OSError) as e:
159
+ error("Failed to push to remote repository!")
160
+ warning("Please check your network connection, remote URL, and authentication.")
161
+ if "rebase in progress" in str(e):
162
+ handle_rebase()
163
+ else:
164
+ sys.exit(1)
141
165
 
142
166
 
143
167
  def handle_rebase():
@@ -1,9 +1,8 @@
1
1
  from pygitgo.commands.git_operations import (
2
2
  is_branch_exist, get_current_branch, git_new_branch, get_main_branch
3
3
  )
4
- from pygitgo.utils.executor import run_command
5
- from pygitgo.commands.state import *
6
4
  from pygitgo.utils.colors import warning, info, success, error
5
+ from pygitgo.utils.executor import run_command
7
6
  import subprocess
8
7
  import sys
9
8
 
@@ -1,5 +1,5 @@
1
- from pygitgo.utils.executor import run_command
2
1
  from pygitgo.utils.colors import info, highlight, error, warning, success
2
+ from pygitgo.utils.executor import run_command
3
3
  import sys
4
4
 
5
5
 
@@ -59,20 +59,19 @@ def display_save_states():
59
59
 
60
60
 
61
61
  def is_number(value):
62
- try:
63
- float(value)
64
- return True
65
- except ValueError:
66
- return False
62
+ val = str(value).strip()
63
+ if val.startswith('-'):
64
+ return val[1:].isdigit()
65
+ return val.isdigit()
67
66
 
68
67
  def validate_state_id(state_id, save_states):
69
68
  if not is_number(state_id):
70
69
  error("\nInvalid input. Please enter a valid state ID.\n")
71
70
  return False
72
- elif (int(float(state_id)) - 1) < 0:
71
+ elif (int(state_id) - 1) < 0:
73
72
  error("\nState ID cannot be '0' or negative. Please enter a valid state ID.\n")
74
73
  return False
75
- elif (int(float(state_id)) - 1) >= len(save_states):
74
+ elif (int(state_id) - 1) >= len(save_states):
76
75
  error("\nState ID out of range. Please enter a valid state ID.\n")
77
76
  return False
78
77
  return True
@@ -124,9 +123,13 @@ def save_state(state_name=None):
124
123
  if not state_name:
125
124
  state_name = "Auto-Save"
126
125
 
127
- run_command(["git", "stash", "push", "-m", state_name])
128
-
129
- success(f"\nState '{state_name}' saved successfully.\n")
126
+ output = run_command(["git", "stash", "push", "-m", state_name], allow_fail=True)
127
+ if isinstance(output, Exception):
128
+ error(f"\nFailed to save state '{state_name}'.\n")
129
+ elif "No local changes to save" in output:
130
+ warning("\nNo local changes to save.\n")
131
+ else:
132
+ success(f"\nState '{state_name}' saved successfully.\n")
130
133
 
131
134
 
132
135
  def delete_state(identifier=None):
@@ -1,18 +1,17 @@
1
- from pygitgo.auth.ssh_utils import ensure_github_known_host
2
1
  from pygitgo.commands.git_operations import (
3
2
  git_new_branch, git_commit, git_init, add_remote_origin,
4
- confirm_remote_link, create_main_branch, check_and_sync_branch,
5
- git_push, handle_rebase, get_current_branch, is_branch_exist
3
+ confirm_remote_link, git_push, get_current_branch, is_branch_exist
6
4
  )
7
- from pygitgo.utils.colors import info, success, warning, error, highlight
5
+ from pygitgo.utils.colors import info, success, warning, error
8
6
  from pygitgo.utils.config import get_config, config_operation
7
+ from pygitgo.exceptions import GitCommandError, GitGoError
9
8
  from pygitgo.utils.setup import ensure_first_run_setup
10
9
  from pygitgo.commands.state import state_operations
11
10
  from pygitgo.commands.jump import jump_operation
12
11
  from pygitgo.utils.executor import run_command
13
12
  from pygitgo.auth.manager import login, logout
14
13
  from pygitgo.auth.account import get_user
15
- from pygitgo.exceptions import GitGoError
14
+ from argparse import Namespace
16
15
  import subprocess
17
16
  import argparse
18
17
  import sys
@@ -109,11 +108,24 @@ def push_operation(args):
109
108
  if branch and not message and not is_branch_exist(branch):
110
109
  message = branch
111
110
  branch = get_current_branch()
111
+ info(f"No branch name provided. Using current branch: '{branch}'\n")
112
+
113
+ elif branch and is_branch_exist(branch):
114
+ current_branch = get_current_branch()
115
+ if current_branch != branch:
116
+ warning(f"You are currently on branch '{current_branch}', not '{branch}'.")
117
+ user_choice = input(f"Do you want to switch to branch '{branch}'? (y/n): ").lower()
118
+ if user_choice != 'y':
119
+ error("\nPush aborted to prevent committing to the wrong branch.\n")
120
+ sys.exit(1)
121
+ jump_operation(Namespace(branch=branch))
122
+
112
123
  elif not branch:
113
124
  branch = get_current_branch()
114
125
 
115
126
  if not message:
116
127
  message = get_config("default-message", "New Project Update")
128
+ info(f"No commit message provided. Using default: '{message}'\n")
117
129
 
118
130
  commit_made = git_commit(message)
119
131
 
@@ -129,7 +141,7 @@ def push_operation(args):
129
141
  info("\nWorking tree is clean and everything is up to date.")
130
142
  warning("Make some changes first before using GitGo to commit and push.")
131
143
  return
132
- except:
144
+ except (GitCommandError, Exception):
133
145
  warning("\nNo changes to commit. Cannot verify remote status.")
134
146
  warning("Make some changes first or check your git remote configuration.")
135
147
  return
@@ -51,4 +51,6 @@ def config_operation(args):
51
51
  if current_value:
52
52
  info(f"\n{key} is currently set to: '{current_value}'\n")
53
53
  else:
54
- warning(f"\n{key} is not currently set.\n")
54
+ warning(f"\n{key} is not currently set.\n")
55
+
56
+
@@ -1,8 +1,8 @@
1
- import subprocess
2
- import sys
3
- import os
4
1
  from pygitgo.utils.colors import error, info, success, warning
5
2
  from pygitgo.exceptions import GitCommandError
3
+ from yaspin import yaspin
4
+ import subprocess
5
+ import os
6
6
 
7
7
 
8
8
  def run_command(command, allow_fail=False, return_complete=False, loading_msg=None):
@@ -15,7 +15,6 @@ def run_command(command, allow_fail=False, return_complete=False, loading_msg=No
15
15
  :param loading_msg: if provided, show a yaspin spinner with this message
16
16
  :raises GitCommandError: when the command fails and allow_fail is False
17
17
  """
18
- from yaspin import yaspin
19
18
 
20
19
  spinner = yaspin(text=loading_msg, color="cyan") if loading_msg else None
21
20
 
@@ -34,11 +33,18 @@ def run_command(command, allow_fail=False, return_complete=False, loading_msg=No
34
33
  spinner.ok("✔")
35
34
 
36
35
  return result if return_complete else result.stdout.strip()
37
- except subprocess.CalledProcessError as e:
36
+ except (subprocess.CalledProcessError, OSError) as e:
38
37
  if spinner:
39
38
  spinner.fail("✖")
40
39
 
41
- stderr = e.stderr.strip() if e.stderr else ""
40
+ stderr = ""
41
+ returncode = 1
42
+
43
+ if isinstance(e, subprocess.CalledProcessError):
44
+ stderr = e.stderr.strip() if e.stderr else ""
45
+ returncode = e.returncode
46
+ else:
47
+ stderr = f"Command not found or execution failed: {str(e)}"
42
48
 
43
49
  if "detected dubious ownership" in stderr:
44
50
  error(f"\nSECURITY ALERT: {stderr}")
@@ -68,4 +74,4 @@ def run_command(command, allow_fail=False, return_complete=False, loading_msg=No
68
74
  if allow_fail:
69
75
  return e
70
76
 
71
- raise GitCommandError(command, stderr=stderr, returncode=e.returncode)
77
+ raise GitCommandError(command, stderr=stderr, returncode=returncode)
@@ -19,7 +19,7 @@ def ensure_first_run_setup():
19
19
 
20
20
  is_initialized = get_config("initialized", fallback_value="false")
21
21
 
22
- if not is_initialized:
22
+ if is_initialized == "false":
23
23
  info("\nInitializing GitGo network settings for the first time... please wait.")
24
24
  ensure_github_known_host()
25
25
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pygitgo
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: GitGo CLI - Your Fast Git Companion. Simplifies git push, link, stash, and user management.
5
5
  Author: Huerte
6
6
  License: GPL-3.0-or-later
@@ -24,9 +24,11 @@ src/pygitgo/utils/config.py
24
24
  src/pygitgo/utils/executor.py
25
25
  src/pygitgo/utils/platform_utils.py
26
26
  src/pygitgo/utils/setup.py
27
+ tests/test_config.py
27
28
  tests/test_git_operations.py
28
29
  tests/test_jump.py
29
30
  tests/test_main.py
30
31
  tests/test_platform.py
32
+ tests/test_setup.py
31
33
  tests/test_state.py
32
34
  tests/test_url_validator.py
@@ -0,0 +1,99 @@
1
+ from pygitgo.utils.config import get_config, set_config, config_operation
2
+ from conftest import capture_system_exit_code
3
+ from argparse import Namespace
4
+ import subprocess
5
+
6
+
7
+ def test_get_config_fallback(mocker):
8
+ fake_run = mocker.patch('pygitgo.utils.config.run_command', return_value="")
9
+
10
+ fallback_value = "false"
11
+
12
+ result = get_config("default-key", fallback_value)
13
+ assert result == fallback_value
14
+
15
+ def test_get_config_ok(mocker):
16
+ fake_run = mocker.patch('pygitgo.utils.config.run_command', return_value="true")
17
+
18
+ fallback_value = "false"
19
+
20
+ result = get_config("default-key", fallback_value)
21
+ assert result != fallback_value
22
+
23
+ def test_set_config_fallback(mocker):
24
+ fake_run = mocker.patch('pygitgo.utils.config.run_command', return_value=subprocess.CalledProcessError(1, 'git'))
25
+ fake_error = mocker.patch('pygitgo.utils.config.error')
26
+
27
+ key = 'default-key'
28
+
29
+ result = set_config(key, 'true')
30
+ assert result == False
31
+
32
+ fake_error.assert_called_with(f"\nFailed to save configuration for '{key}'.")
33
+
34
+ def test_set_config_ok(mocker):
35
+ fake_run = mocker.patch('pygitgo.utils.config.run_command', return_value='ok')
36
+ fake_error = mocker.patch('pygitgo.utils.config.error')
37
+ fake_success = mocker.patch('pygitgo.utils.config.success')
38
+
39
+ key = 'default-key'
40
+ value = 'true'
41
+
42
+ result = set_config(key, value)
43
+ assert result == True
44
+
45
+ fake_error.assert_not_called()
46
+ fake_success.assert_called_with(f"\nConfiguration saved: {key} = '{value}'")
47
+
48
+ def test_config_operation_not_valid_keys(mocker):
49
+ fake_error = mocker.patch('pygitgo.utils.config.error')
50
+ fake_warning = mocker.patch('pygitgo.utils.config.warning')
51
+
52
+
53
+ VALID_KEYS = ["default-branch", "default-message"]
54
+
55
+ key = "not-valid"
56
+ value = "true"
57
+ args = Namespace(key=key, action="set", value=value)
58
+
59
+ assert capture_system_exit_code(lambda: config_operation(args)) is None
60
+
61
+ fake_error.assert_called_with(f"\nInvalid configuration key: '{key}'")
62
+ fake_warning.assert_called_with(f"Valid keys are: {', '.join(VALID_KEYS)}\n")
63
+
64
+ def test_get_config_strip(mocker):
65
+ fake_run = mocker.patch('pygitgo.utils.config.run_command', return_value=" true \n")
66
+ result = get_config("default-key", "false")
67
+ assert result == "true"
68
+
69
+ def test_get_config_error_handling(mocker):
70
+ fake_run = mocker.patch('pygitgo.utils.config.run_command', return_value=subprocess.CalledProcessError(1, 'git'))
71
+ result = get_config("default-key", "fallback")
72
+ assert result == "fallback"
73
+
74
+ def test_config_operation_set_no_value(mocker):
75
+ fake_error = mocker.patch('pygitgo.utils.config.error')
76
+ args = Namespace(key="default-branch", action="set") # value is missing
77
+ config_operation(args)
78
+ fake_error.assert_called_with("\nYou must provide a value to set!\n")
79
+
80
+ def test_config_operation_set_ok(mocker):
81
+ fake_set = mocker.patch('pygitgo.utils.config.set_config')
82
+ args = Namespace(key="default-branch", action="set", value="main")
83
+ config_operation(args)
84
+ fake_set.assert_called_with("default-branch", "main")
85
+
86
+ def test_config_operation_get_ok(mocker):
87
+ mocker.patch('pygitgo.utils.config.get_config', return_value="main")
88
+ fake_info = mocker.patch('pygitgo.utils.config.info')
89
+ args = Namespace(key="default-branch", action="get")
90
+ config_operation(args)
91
+ fake_info.assert_called_with("\ndefault-branch is currently set to: 'main'\n")
92
+
93
+ def test_config_operation_get_none(mocker):
94
+ mocker.patch('pygitgo.utils.config.get_config', return_value=None)
95
+ fake_warning = mocker.patch('pygitgo.utils.config.warning')
96
+ args = Namespace(key="default-branch", action="get")
97
+ config_operation(args)
98
+ fake_warning.assert_called_with("\ndefault-branch is not currently set.\n")
99
+
@@ -7,7 +7,7 @@ from pygitgo.commands.git_operations import (
7
7
  from unittest.mock import call
8
8
  import subprocess
9
9
  import pytest
10
- import os
10
+
11
11
 
12
12
  def test_git_branch_logic(mocker):
13
13
  fake_run = mocker.patch("pygitgo.commands.git_operations.run_command")
@@ -21,6 +21,36 @@ def test_git_branch_logic(mocker):
21
21
  loading_msg="Creating branch 'hello-world'..."
22
22
  )
23
23
 
24
+ def test_git_branch_exists_jump_yes(mocker):
25
+ fake_run = mocker.patch("pygitgo.commands.git_operations.run_command", return_value=subprocess.CalledProcessError(1, 'git'))
26
+ mocker.patch("builtins.input", return_value="y")
27
+ fake_jump = mocker.patch("pygitgo.commands.jump.jump_operation")
28
+ fake_error = mocker.patch("pygitgo.commands.git_operations.error")
29
+
30
+ branch_name = "existing-branch"
31
+ result = git_new_branch(branch_name)
32
+
33
+ assert result == "existing-branch"
34
+ fake_error.assert_called_once_with(f"Failed to create branch '{branch_name}'! It may already exist.")
35
+
36
+ args = fake_jump.call_args[0][0]
37
+ assert args.branch == branch_name
38
+
39
+ def test_git_branch_exists_jump_no(mocker):
40
+ fake_run = mocker.patch("pygitgo.commands.git_operations.run_command", return_value=subprocess.CalledProcessError(1, 'git'))
41
+ mocker.patch("builtins.input", return_value="n")
42
+ fake_jump = mocker.patch("pygitgo.commands.jump.jump_operation")
43
+ fake_error = mocker.patch("pygitgo.commands.git_operations.error")
44
+
45
+ branch_name = "existing-branch"
46
+
47
+ with pytest.raises(SystemExit) as exc_info:
48
+ git_new_branch(branch_name)
49
+
50
+ assert exc_info.value.code == 1
51
+ fake_error.assert_called_once_with(f"Failed to create branch '{branch_name}'! It may already exist.")
52
+ fake_jump.assert_not_called()
53
+
24
54
  def test_git_commit(mocker):
25
55
  fake_run = mocker.patch("pygitgo.commands.git_operations.run_command")\
26
56
 
@@ -1,18 +1,13 @@
1
1
  from pygitgo.commands.jump import undo_jump_operation, jump_operation
2
+ from conftest import capture_system_exit_code
2
3
  from argparse import Namespace
3
4
  import subprocess
4
5
  import pytest
5
6
 
7
+
6
8
  def make_args(branch):
7
- """Helper to create an argparse-like Namespace for jump_operation."""
8
9
  return Namespace(branch=branch)
9
10
 
10
- def check_pytest_system_exit(function):
11
- with pytest.raises(SystemExit) as exc_info:
12
- function()
13
-
14
- return exc_info.value.code
15
-
16
11
  def test_undo_jump_operation_no_stash(mocker):
17
12
  fake_run = mocker.patch('pygitgo.commands.jump.run_command', return_value="")
18
13
 
@@ -47,7 +42,7 @@ def test_jump_operation_same_branch(mocker):
47
42
  )
48
43
  fake_warning = mocker.patch('pygitgo.commands.jump.warning')
49
44
 
50
- assert check_pytest_system_exit(lambda: jump_operation(make_args(main_branch))) == 0
45
+ assert capture_system_exit_code(lambda: jump_operation(make_args(main_branch))) == 0
51
46
 
52
47
  fake_warning.assert_called_with(f"\nYou are already on branch '{main_branch}'.\n")
53
48
 
@@ -60,7 +55,7 @@ def test_jump_operation_not_valid_repo(mocker):
60
55
  return_value=subprocess.CalledProcessError(1, 'git')
61
56
  )
62
57
 
63
- assert check_pytest_system_exit(lambda: jump_operation(make_args('main'))) == 1
58
+ assert capture_system_exit_code(lambda: jump_operation(make_args('main'))) == 1
64
59
 
65
60
  fake_warning.assert_called_with("\nUnable to check for uncommitted changes. Please ensure you're in a valid git repository.")
66
61
 
@@ -77,7 +72,7 @@ def test_jump_operation_has_changes_exit(mocker):
77
72
  side_effect=['some-changes']
78
73
  )
79
74
 
80
- assert check_pytest_system_exit(lambda: jump_operation(make_args('main'))) == 0
75
+ assert capture_system_exit_code(lambda: jump_operation(make_args('main'))) == 0
81
76
 
82
77
  fake_warning.assert_any_call("\nYou cannot switch branches with unsaved changes. Jump canceled.\n")
83
78
  fake_run.assert_any_call(['git', 'status', '--porcelain'], allow_fail=True, loading_msg="Checking for uncommitted changes...")
@@ -94,7 +89,7 @@ def test_jump_operation_save_changes_error(mocker):
94
89
  )
95
90
  )
96
91
 
97
- assert check_pytest_system_exit(lambda: jump_operation(make_args('main'))) == 1
92
+ assert capture_system_exit_code(lambda: jump_operation(make_args('main'))) == 1
98
93
 
99
94
  fake_warning.assert_called_with("\nFailed to save your changes. Please resolve any issues and try again.")
100
95
  fake_run.assert_any_call(['git', 'status', '--porcelain'], allow_fail=True, loading_msg="Checking for uncommitted changes...")
@@ -115,7 +110,7 @@ def test_jump_operation_no_changes(mocker):
115
110
 
116
111
  target_branch = 'feature'
117
112
 
118
- assert check_pytest_system_exit(lambda: jump_operation(make_args(target_branch))) == 0
113
+ assert capture_system_exit_code(lambda: jump_operation(make_args(target_branch))) == 0
119
114
 
120
115
  fake_success.assert_called_with(f"\nSuccess! You are now on '{target_branch}'.\n")
121
116
  fake_run.assert_any_call(['git', 'status', '--porcelain'], allow_fail=True, loading_msg="Checking for uncommitted changes...")
@@ -143,7 +138,7 @@ def test_jump_operation_branch_not_exist_cancel_operation(mocker):
143
138
 
144
139
  target_branch = 'feature'
145
140
 
146
- assert check_pytest_system_exit(lambda: jump_operation(make_args(target_branch))) == 0
141
+ assert capture_system_exit_code(lambda: jump_operation(make_args(target_branch))) == 0
147
142
 
148
143
  fake_info.assert_any_call('\nYour changes have been saved. Jumping to the new branch...')
149
144
  fake_info.assert_any_call("Exiting without jumping...\n")
@@ -175,7 +170,7 @@ def test_jump_operation_branch_not_exist_create_branch(mocker):
175
170
 
176
171
  target_branch = 'feature'
177
172
 
178
- assert check_pytest_system_exit(lambda: jump_operation(make_args(target_branch))) == 0
173
+ assert capture_system_exit_code(lambda: jump_operation(make_args(target_branch))) == 0
179
174
 
180
175
  fake_info.assert_called_with('\nYour changes have been saved. Jumping to the new branch...')
181
176
  fake_success.assert_any_call(f"\nSuccess! You are now on '{target_branch}'.")
@@ -204,7 +199,7 @@ def test_jump_operation_sync_fail_cancel(mocker):
204
199
  )
205
200
  )
206
201
 
207
- assert check_pytest_system_exit(lambda: jump_operation(make_args('feature'))) == 1
202
+ assert capture_system_exit_code(lambda: jump_operation(make_args('feature'))) == 1
208
203
 
209
204
  fake_warning.assert_any_call("\nFailed to pull updates from 'main'. Make sure you have internet or the remote branch exists.")
210
205
 
@@ -225,7 +220,7 @@ def test_jump_operation_sync_fail_stay(mocker):
225
220
  )
226
221
  )
227
222
 
228
- assert check_pytest_system_exit(lambda: jump_operation(make_args('feature'))) == 0
223
+ assert capture_system_exit_code(lambda: jump_operation(make_args('feature'))) == 0
229
224
 
230
225
  fake_success.assert_any_call("\nOkay! You are on the new branch, but without the latest updates from 'main'.")
231
226
 
@@ -247,7 +242,7 @@ def test_jump_operation_merge_conflict_cancel(mocker):
247
242
  )
248
243
  )
249
244
 
250
- assert check_pytest_system_exit(lambda: jump_operation(make_args('feature'))) == 0
245
+ assert capture_system_exit_code(lambda: jump_operation(make_args('feature'))) == 0
251
246
 
252
247
  fake_error.assert_any_call("\nSTOP! There is a 'Merge Conflict'.")
253
248
 
@@ -270,7 +265,7 @@ def test_jump_operation_merge_conflict_stay(mocker):
270
265
  )
271
266
  )
272
267
 
273
- assert check_pytest_system_exit(lambda: jump_operation(make_args('feature'))) == 0
268
+ assert capture_system_exit_code(lambda: jump_operation(make_args('feature'))) == 0
274
269
 
275
270
  fake_success.assert_any_call("\nOkay! You are on the new branch with your code.")
276
271
  fake_warning.assert_any_call("Please open your code editor RIGHT NOW to fix the conflicts!")
@@ -1,5 +1,6 @@
1
- import pytest
2
1
  from pygitgo.main import validate_repo_url
2
+ import pytest
3
+
3
4
 
4
5
  @pytest.mark.parametrize("url", [
5
6
  "https://github.com/Huerte/GitGo.git",
@@ -0,0 +1,55 @@
1
+ from pygitgo.utils.setup import check_git_installed, ensure_first_run_setup
2
+ from conftest import capture_system_exit_code
3
+
4
+
5
+ def test_check_git_installed_no_exist(mocker):
6
+ mocker.patch("shutil.which", return_value=None)
7
+ fake_error = mocker.patch("pygitgo.utils.setup.error")
8
+ fake_info = mocker.patch("pygitgo.utils.setup.info")
9
+
10
+ assert capture_system_exit_code(lambda: check_git_installed()) == 1
11
+
12
+ fake_error.assert_called_with("\nGit is not installed or not found on your PATH!")
13
+ fake_info.assert_any_call("Install Git from: https://git-scm.com/downloads")
14
+ fake_info.assert_any_call("After installing, restart your terminal and try again.\n")
15
+
16
+ def test_check_git_installed_exist(mocker):
17
+ mocker.patch("shutil.which", return_value="ok")
18
+ fake_error = mocker.patch("pygitgo.utils.setup.error")
19
+ fake_info = mocker.patch("pygitgo.utils.setup.info")
20
+
21
+ assert capture_system_exit_code(lambda: check_git_installed()) == None
22
+
23
+ fake_error.assert_not_called()
24
+ fake_info.assert_not_called()
25
+
26
+ def test_ensure_first_run_setup_already_initialized(mocker):
27
+ mocker.patch('pygitgo.utils.setup.check_git_installed', return_value=None)
28
+ fake_get_config = mocker.patch('pygitgo.utils.setup.get_config', return_value="ok")
29
+ fake_github_function = mocker.patch('pygitgo.utils.setup.ensure_github_known_host', return_value=None)
30
+ fake_set_config = mocker.patch('pygitgo.utils.setup.set_config', return_value=True)
31
+ fake_info = mocker.patch("pygitgo.utils.setup.info")
32
+
33
+ ensure_first_run_setup()
34
+
35
+ fake_info.assert_not_called()
36
+ fake_github_function.assert_not_called()
37
+ fake_set_config.assert_not_called()
38
+
39
+ fake_get_config.assert_called_with("initialized", fallback_value="false")
40
+
41
+ def test_ensure_first_run_setup_not_initialized(mocker):
42
+ mocker.patch('pygitgo.utils.setup.check_git_installed', return_value=None)
43
+ fake_get_config = mocker.patch('pygitgo.utils.setup.get_config', return_value="false")
44
+ fake_github_function = mocker.patch('pygitgo.utils.setup.ensure_github_known_host', return_value=None)
45
+ fake_set_config = mocker.patch('pygitgo.utils.setup.set_config', return_value=True)
46
+ fake_info = mocker.patch("pygitgo.utils.setup.info")
47
+
48
+ ensure_first_run_setup()
49
+
50
+ fake_info.assert_called_with("\nInitializing GitGo network settings for the first time... please wait.")
51
+ fake_github_function.assert_called_once()
52
+ fake_set_config.assert_called_with("initialized", "true")
53
+
54
+ fake_get_config.assert_called_with("initialized", fallback_value="false")
55
+
@@ -3,12 +3,11 @@ from pygitgo.commands.state import (
3
3
  all_save_state
4
4
  )
5
5
  from unittest.mock import call
6
- import subprocess
7
6
  import pytest
8
- import os
7
+
9
8
 
10
9
  @pytest.mark.parametrize('state_id',[
11
- '1', '3', '11', '00002', '7.0'
10
+ '1', '3', '11', '00002'
12
11
  ])
13
12
  def test_validate_state_id(state_id, mocker):
14
13
  fake_error = mocker.patch('pygitgo.commands.state.error')
@@ -20,7 +19,7 @@ def test_validate_state_id(state_id, mocker):
20
19
  fake_error.assert_not_called()
21
20
 
22
21
  @pytest.mark.parametrize('state_id',[
23
- '-1', '-3', '-11', '-00002', '-7.0'
22
+ '-1', '-3', '-11', '-00002'
24
23
  ])
25
24
  def test_validate_state_id_negative(state_id, mocker):
26
25
 
@@ -33,7 +32,7 @@ def test_validate_state_id_negative(state_id, mocker):
33
32
  fake_error.assert_called_with("\nState ID cannot be '0' or negative. Please enter a valid state ID.\n")
34
33
 
35
34
  @pytest.mark.parametrize('state_id',[
36
- '4', '10', '15', '0000020', '00007.00000'
35
+ '4', '10', '15', '0000020'
37
36
  ])
38
37
  def test_validate_state_id_out_scope(state_id, mocker):
39
38
 
@@ -156,21 +155,21 @@ def test_load_state_no_args(mocker):
156
155
 
157
156
 
158
157
  def test_save_state_no_args(mocker):
159
- fake_run = mocker.patch("pygitgo.commands.state.run_command")
158
+ fake_run = mocker.patch("pygitgo.commands.state.run_command", return_value="Saved working directory")
160
159
  fake_success = mocker.patch("pygitgo.commands.state.success")
161
160
 
162
161
  save_state()
163
162
 
164
- fake_run.assert_called_once_with(["git", "stash", "push", "-m", "Auto-Save"])
163
+ fake_run.assert_called_once_with(["git", "stash", "push", "-m", "Auto-Save"], allow_fail=True)
165
164
  fake_success.assert_called_once_with("\nState 'Auto-Save' saved successfully.\n")
166
165
 
167
166
  def test_save_state_with_name(mocker):
168
- fake_run = mocker.patch("pygitgo.commands.state.run_command")
167
+ fake_run = mocker.patch("pygitgo.commands.state.run_command", return_value="Saved working directory")
169
168
  fake_success = mocker.patch("pygitgo.commands.state.success")
170
169
 
171
170
  save_state("My-State")
172
171
 
173
- fake_run.assert_called_once_with(["git", "stash", "push", "-m", "My-State"])
172
+ fake_run.assert_called_once_with(["git", "stash", "push", "-m", "My-State"], allow_fail=True)
174
173
  fake_success.assert_called_once_with("\nState 'My-State' saved successfully.\n")
175
174
 
176
175
 
File without changes
File without changes
File without changes
File without changes
@@ -1,5 +1,5 @@
1
- from pygitgo.utils.executor import run_command
2
1
  from pygitgo.utils.colors import info, success, warning, error, BLUE, RESET
2
+ from pygitgo.utils.executor import run_command
3
3
  import subprocess
4
4
 
5
5
 
@@ -1,5 +1,5 @@
1
- from pygitgo.utils.executor import run_command
2
1
  from pygitgo.utils.colors import info, success, warning, error
2
+ from pygitgo.utils.executor import run_command
3
3
  from . import ssh_utils
4
4
  import os
5
5
 
File without changes