pygitgo 1.1.1__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 (38) hide show
  1. {pygitgo-1.1.1/src/pygitgo.egg-info → pygitgo-1.2.1}/PKG-INFO +29 -2
  2. {pygitgo-1.1.1 → pygitgo-1.2.1}/README.md +28 -1
  3. {pygitgo-1.1.1 → pygitgo-1.2.1}/pyproject.toml +1 -1
  4. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/auth/ssh_utils.py +5 -1
  5. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/commands/git_operations.py +36 -10
  6. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/commands/jump.py +4 -10
  7. pygitgo-1.2.1/src/pygitgo/commands/state.py +177 -0
  8. pygitgo-1.2.1/src/pygitgo/main.py +297 -0
  9. pygitgo-1.2.1/src/pygitgo/utils/config.py +56 -0
  10. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/utils/executor.py +13 -7
  11. pygitgo-1.2.1/src/pygitgo/utils/setup.py +26 -0
  12. {pygitgo-1.1.1 → pygitgo-1.2.1/src/pygitgo.egg-info}/PKG-INFO +29 -2
  13. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo.egg-info/SOURCES.txt +4 -0
  14. pygitgo-1.2.1/tests/test_config.py +99 -0
  15. {pygitgo-1.1.1 → pygitgo-1.2.1}/tests/test_git_operations.py +33 -1
  16. {pygitgo-1.1.1 → pygitgo-1.2.1}/tests/test_jump.py +15 -23
  17. {pygitgo-1.1.1 → pygitgo-1.2.1}/tests/test_main.py +2 -1
  18. pygitgo-1.2.1/tests/test_setup.py +55 -0
  19. {pygitgo-1.1.1 → pygitgo-1.2.1}/tests/test_state.py +19 -72
  20. pygitgo-1.1.1/src/pygitgo/commands/state.py +0 -224
  21. pygitgo-1.1.1/src/pygitgo/main.py +0 -323
  22. {pygitgo-1.1.1 → pygitgo-1.2.1}/LICENSE +0 -0
  23. {pygitgo-1.1.1 → pygitgo-1.2.1}/setup.cfg +0 -0
  24. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/__init__.py +0 -0
  25. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/auth/__init__.py +0 -0
  26. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/auth/account.py +1 -1
  27. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/auth/manager.py +1 -1
  28. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/commands/__init__.py +0 -0
  29. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/exceptions.py +0 -0
  30. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/utils/__init__.py +0 -0
  31. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/utils/colors.py +0 -0
  32. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo/utils/platform_utils.py +0 -0
  33. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo.egg-info/dependency_links.txt +0 -0
  34. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo.egg-info/entry_points.txt +0 -0
  35. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo.egg-info/requires.txt +0 -0
  36. {pygitgo-1.1.1 → pygitgo-1.2.1}/src/pygitgo.egg-info/top_level.txt +0 -0
  37. {pygitgo-1.1.1 → pygitgo-1.2.1}/tests/test_platform.py +0 -0
  38. {pygitgo-1.1.1 → 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.1.1
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
@@ -78,6 +78,7 @@ GitGo provides a CLI environment designed for faster and simpler Git workflows.
78
78
  - **Simplified Git Operations:** Replaces chained commands with single intuitive commands for linking, pushing, and stashing.
79
79
  - **Smart Branch Hopping:** Safely traverse branches with `jump`. Auto-stashes messy code and prevents merge conflict disasters with a Try-And-Revert safety engine.
80
80
  - **State Management:** A human-readable interface over `git stash`. States are named and listed by index so you never have to remember cryptic stash references.
81
+ - **Custom Defaults:** Save your preferred branch name and commit message locally so you never have to type them again.
81
82
  - **SSH Auto-Setup:** Generates an SSH key, adds it to `ssh-agent`, and opens your GitHub settings automatically.
82
83
  - **HTTPS to SSH Conversion:** Silently converts the remote to SSH before pushing if your SSH is configured.
83
84
  - **Termux Compatibility:** Works natively on Android natively handling common issues like dubious ownership errors.
@@ -153,6 +154,14 @@ gitgo state list
153
154
  gitgo state load 1
154
155
  ```
155
156
 
157
+ ### 6. Custom Defaults
158
+ Save your preferred settings so you don't have to provide them every time.
159
+ ```bash
160
+ gitgo config set default-branch develop
161
+ gitgo config set default-message "WIP: updates"
162
+ gitgo config get default-branch
163
+ ```
164
+
156
165
  ---
157
166
 
158
167
  ## Command Reference
@@ -166,6 +175,9 @@ gitgo push [branch] [message]
166
175
  gitgo push -n [branch] [message] # create new branch first
167
176
  ```
168
177
 
178
+ > [!TIP]
179
+ > Use `gitgo push -h` to see all available flags and examples.
180
+
169
181
  | Flag | Description |
170
182
  |------|-------------|
171
183
  | `-n`, `--new` | Create a new branch before pushing |
@@ -209,10 +221,25 @@ gitgo user login # generate SSH key and configure Git identity
209
221
  gitgo user logout # remove SSH keys and Git identity config
210
222
  ```
211
223
 
224
+ ### `gitgo config`
225
+
226
+ Manage your GitGo defaults.
227
+
228
+ ```bash
229
+ gitgo config set <key> <value>
230
+ gitgo config get <key>
231
+ ```
232
+
233
+ | Key | Description | Default |
234
+ |-----|-------------|---------|
235
+ | `default-branch` | The branch used for push/link | `main` |
236
+ | `default-message` | The commit message used for push | `New Project Update` |
237
+
212
238
  ### Global Flags
213
239
 
214
240
  ```bash
215
- gitgo -h # help
241
+ gitgo help # show complete manual
242
+ gitgo <cmd> -h # show help for a specific command
216
243
  gitgo -v # version
217
244
  gitgo -r # verify GitGo is ready
218
245
  ```
@@ -55,6 +55,7 @@ GitGo provides a CLI environment designed for faster and simpler Git workflows.
55
55
  - **Simplified Git Operations:** Replaces chained commands with single intuitive commands for linking, pushing, and stashing.
56
56
  - **Smart Branch Hopping:** Safely traverse branches with `jump`. Auto-stashes messy code and prevents merge conflict disasters with a Try-And-Revert safety engine.
57
57
  - **State Management:** A human-readable interface over `git stash`. States are named and listed by index so you never have to remember cryptic stash references.
58
+ - **Custom Defaults:** Save your preferred branch name and commit message locally so you never have to type them again.
58
59
  - **SSH Auto-Setup:** Generates an SSH key, adds it to `ssh-agent`, and opens your GitHub settings automatically.
59
60
  - **HTTPS to SSH Conversion:** Silently converts the remote to SSH before pushing if your SSH is configured.
60
61
  - **Termux Compatibility:** Works natively on Android natively handling common issues like dubious ownership errors.
@@ -130,6 +131,14 @@ gitgo state list
130
131
  gitgo state load 1
131
132
  ```
132
133
 
134
+ ### 6. Custom Defaults
135
+ Save your preferred settings so you don't have to provide them every time.
136
+ ```bash
137
+ gitgo config set default-branch develop
138
+ gitgo config set default-message "WIP: updates"
139
+ gitgo config get default-branch
140
+ ```
141
+
133
142
  ---
134
143
 
135
144
  ## Command Reference
@@ -143,6 +152,9 @@ gitgo push [branch] [message]
143
152
  gitgo push -n [branch] [message] # create new branch first
144
153
  ```
145
154
 
155
+ > [!TIP]
156
+ > Use `gitgo push -h` to see all available flags and examples.
157
+
146
158
  | Flag | Description |
147
159
  |------|-------------|
148
160
  | `-n`, `--new` | Create a new branch before pushing |
@@ -186,10 +198,25 @@ gitgo user login # generate SSH key and configure Git identity
186
198
  gitgo user logout # remove SSH keys and Git identity config
187
199
  ```
188
200
 
201
+ ### `gitgo config`
202
+
203
+ Manage your GitGo defaults.
204
+
205
+ ```bash
206
+ gitgo config set <key> <value>
207
+ gitgo config get <key>
208
+ ```
209
+
210
+ | Key | Description | Default |
211
+ |-----|-------------|---------|
212
+ | `default-branch` | The branch used for push/link | `main` |
213
+ | `default-message` | The commit message used for push | `New Project Update` |
214
+
189
215
  ### Global Flags
190
216
 
191
217
  ```bash
192
- gitgo -h # help
218
+ gitgo help # show complete manual
219
+ gitgo <cmd> -h # show help for a specific command
193
220
  gitgo -v # version
194
221
  gitgo -r # verify GitGo is ready
195
222
  ```
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pygitgo"
7
- version = "1.1.1"
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:
@@ -1,12 +1,18 @@
1
1
  from pygitgo.auth.ssh_utils import convert_https_to_ssh, is_ssh_url, check_connection
2
- from pygitgo.utils.executor import run_command
3
2
  from pygitgo.utils.colors import info, success, warning, error
3
+ from pygitgo.utils.executor import run_command
4
+ from pygitgo.utils.config import get_config
5
+ from argparse import Namespace
4
6
  import subprocess
5
7
  import sys
6
8
  import os
7
9
 
8
- DEFAULT_MAIN_BRANCH = "main"
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
10
16
 
11
17
  def get_current_branch():
12
18
  branch = run_command(["git", "branch", "--show-current"]).strip()
@@ -16,18 +22,28 @@ def get_current_branch():
16
22
 
17
23
  def get_main_branch():
18
24
  main_branch = run_command(['git', 'remote', 'show', 'origin'], allow_fail=True)
25
+ default_main_branch = get_config("default-branch", "main")
19
26
  if isinstance(main_branch, subprocess.CalledProcessError):
20
- return DEFAULT_MAIN_BRANCH
27
+ return default_main_branch
21
28
 
22
- return main_branch.split("HEAD branch:")[-1].strip().splitlines()[0].strip() if "HEAD branch:" in main_branch else DEFAULT_MAIN_BRANCH
29
+ return main_branch.split("HEAD branch:")[-1].strip().splitlines()[0].strip() if "HEAD branch:" in main_branch else default_main_branch
23
30
 
24
31
  def is_branch_exist(branch):
25
32
  return bool(run_command(["git", "branch", "-r", "--list", f"*/{branch}"])) or bool(run_command(["git", "branch", "--list", 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
 
@@ -50,10 +66,12 @@ def git_init():
50
66
  warning("Already a git repository! Skipping init...")
51
67
  return True
52
68
 
53
- result = run_command(["git", "init", "-b", DEFAULT_MAIN_BRANCH], allow_fail=True, loading_msg="Initializing git repository...")
69
+ default_main_branch = get_config("default-branch", "main")
70
+
71
+ result = run_command(["git", "init", "-b", default_main_branch], allow_fail=True, loading_msg="Initializing git repository...")
54
72
  if isinstance(result, subprocess.CalledProcessError):
55
73
  run_command(["git", "init"], loading_msg="Initializing git repository...")
56
- run_command(["git", "checkout", "-b", DEFAULT_MAIN_BRANCH], allow_fail=True)
74
+ run_command(["git", "checkout", "-b", default_main_branch], allow_fail=True)
57
75
 
58
76
  success("Git repository initialized.")
59
77
  return True
@@ -134,8 +152,16 @@ def git_push(branch):
134
152
  if ssh_url:
135
153
  run_command(["git", "remote", "set-url", "origin", ssh_url], loading_msg="Converting remote from HTTPS to SSH for secure push...")
136
154
  success(f"Remote updated to: {ssh_url}")
137
-
138
- 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)
139
165
 
140
166
 
141
167
  def handle_rebase():
@@ -1,15 +1,11 @@
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
 
10
- def jump_operations_help():
11
- warning("\nUsage: gitgo jump <branch>\n")
12
- warning("branch: The name of the branch to jump to.\n")
13
9
 
14
10
  def undo_jump_operation(original_branch, stashed_code, created_branch=None):
15
11
  if created_branch:
@@ -25,12 +21,10 @@ def undo_jump_operation(original_branch, stashed_code, created_branch=None):
25
21
  success(f"\nCanceled safely!")
26
22
  success(f"You are back on your original branch '{original_branch}', and your code is totally safe.\n")
27
23
 
28
- def jump_operation(arguments):
29
- if len(arguments) == 0 or arguments[0] in ("-h", "--help", "help"):
30
- jump_operations_help()
31
- sys.exit(0)
24
+ def jump_operation(args):
25
+
32
26
 
33
- target_branch = arguments[0]
27
+ target_branch = args.branch
34
28
 
35
29
  original_branch = get_current_branch().strip()
36
30
 
@@ -0,0 +1,177 @@
1
+ from pygitgo.utils.colors import info, highlight, error, warning, success
2
+ from pygitgo.utils.executor import run_command
3
+ import sys
4
+
5
+
6
+ ALIASES = {
7
+ "-l": "list",
8
+ "-s": "save",
9
+ "-o": "load",
10
+ "-d": "delete"
11
+ }
12
+
13
+ def all_save_state():
14
+ output = run_command([
15
+ "git", "stash", "list",
16
+ "--date=format:%Y-%m-%d %H:%M:%S",
17
+ "--pretty=%gd||%cd||%s"
18
+ ])
19
+
20
+ if not output:
21
+ info("\nNo saved states found.\n")
22
+ sys.exit(0)
23
+
24
+ save_states = []
25
+
26
+ for line in output.splitlines():
27
+ try:
28
+ stash_ref, date, message = line.split("||", 2)
29
+
30
+ index = int(
31
+ stash_ref.replace("stash@{", "").replace("}", "")
32
+ )
33
+
34
+ save_states.append({
35
+ "id": index + 1,
36
+ "ref": stash_ref,
37
+ "date": date,
38
+ "message": message
39
+ })
40
+
41
+ except ValueError:
42
+ warning(f"Skipping malformed line: {line}")
43
+
44
+ return save_states
45
+
46
+
47
+ def display_save_states():
48
+ save_states = all_save_state()
49
+
50
+ print("\nID | Date | Saved State")
51
+ print("-" * 60)
52
+
53
+ for state in save_states:
54
+ highlight(
55
+ f"{state['id']:>2} | {state['date']} | {state['message']}"
56
+ )
57
+
58
+ print("-" * 60 + "\n")
59
+
60
+
61
+ def is_number(value):
62
+ val = str(value).strip()
63
+ if val.startswith('-'):
64
+ return val[1:].isdigit()
65
+ return val.isdigit()
66
+
67
+ def validate_state_id(state_id, save_states):
68
+ if not is_number(state_id):
69
+ error("\nInvalid input. Please enter a valid state ID.\n")
70
+ return False
71
+ elif (int(state_id) - 1) < 0:
72
+ error("\nState ID cannot be '0' or negative. Please enter a valid state ID.\n")
73
+ return False
74
+ elif (int(state_id) - 1) >= len(save_states):
75
+ error("\nState ID out of range. Please enter a valid state ID.\n")
76
+ return False
77
+ return True
78
+
79
+
80
+ def ask_state_id(save_states):
81
+ proceed = False
82
+ state_id = None
83
+
84
+ display_save_states()
85
+ info("\nEnter the ID (or 'q' to cancel): ")
86
+
87
+ while not proceed:
88
+ state_id = input(">> ").strip().lower()
89
+ if state_id == 'q':
90
+ warning("\nLoad operation cancelled by user.\n")
91
+ sys.exit(0)
92
+ proceed = validate_state_id(state_id, save_states)
93
+
94
+ return state_id
95
+
96
+
97
+ def state_list():
98
+ display_save_states()
99
+
100
+
101
+ def load_state(state_id=None):
102
+ save_states = all_save_state()
103
+ proceed = False
104
+
105
+ if state_id:
106
+ if state_id.isdigit():
107
+ proceed = validate_state_id(state_id, save_states)
108
+ if not proceed:
109
+ sys.exit(1)
110
+ else:
111
+ error(f"\nInvalid argument '{state_id}' for load operation. Expected a state ID.\n")
112
+ sys.exit(1)
113
+
114
+ if not proceed:
115
+ state_id = ask_state_id(save_states)
116
+
117
+ run_command(["git", "stash", "apply", str(int(state_id) - 1)])
118
+
119
+ success(f"\nState '{save_states[int(state_id) - 1]['message']}' loaded successfully.\n")
120
+
121
+
122
+ def save_state(state_name=None):
123
+ if not state_name:
124
+ state_name = "Auto-Save"
125
+
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")
133
+
134
+
135
+ def delete_state(identifier=None):
136
+ if not identifier:
137
+ state_id = ask_state_id(all_save_state())
138
+ else:
139
+ if identifier == '-a':
140
+ confirm = input("\nAre you sure you want to delete all saved states? (y/n): ").strip().lower()
141
+ if confirm.lower() == 'y':
142
+ run_command(["git", "stash", "clear"])
143
+ success("\nAll saved states deleted successfully.\n")
144
+ sys.exit(0)
145
+ else:
146
+ warning("\nDelete operation cancelled by user.\n")
147
+ sys.exit(0)
148
+
149
+ elif not identifier.isdigit():
150
+ error("\nInvalid input. Please enter a valid state ID.\n")
151
+ sys.exit(1)
152
+
153
+ state_id = identifier
154
+ if not validate_state_id(state_id, all_save_state()):
155
+ sys.exit(1)
156
+
157
+ run_command(["git", "stash", "drop", str(int(state_id) - 1)])
158
+ success(f"\nState with ID '{state_id}' deleted successfully.\n")
159
+
160
+
161
+
162
+
163
+ def state_operations(args):
164
+ action = ALIASES.get(args.action, args.action)
165
+ identifier = getattr(args, "identifier", None)
166
+
167
+ if action == "list":
168
+ state_list()
169
+ elif action == "save":
170
+ save_state(identifier)
171
+ elif action == "load":
172
+ load_state(identifier)
173
+ elif action == "delete":
174
+ delete_state(identifier)
175
+ else:
176
+ error(f"\nUnknown state operation: {action}\n")
177
+ sys.exit(1)