gitpush-tool 0.2.8__tar.gz → 0.2.9__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitpush-tool
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Supercharged Git push tool with automatic GitHub repo creation and pushing
5
5
  Home-page: https://github.com/inevitablegs/gitpush
6
6
  Author: Ganesh Sonawane
@@ -0,0 +1 @@
1
+ __version__ = "0.2.9"
@@ -2,40 +2,10 @@ import os
2
2
  import argparse
3
3
  import sys
4
4
  import subprocess
5
+ import shutil
5
6
  import platform
6
7
  import urllib.request
7
8
  import tempfile
8
- import shutil
9
-
10
- def check_gh_installed():
11
- """Check if GitHub CLI is installed, attempt installation if not"""
12
- if shutil.which("gh"):
13
- return True
14
-
15
- print("📦 GitHub CLI not found. Attempting installation...")
16
- system = platform.system()
17
-
18
- try:
19
- if system == "Windows":
20
- return install_gh_cli_windows()
21
- elif system == "Darwin":
22
- subprocess.run(["brew", "install", "gh"], check=True)
23
- elif system == "Linux":
24
- subprocess.run(["sudo", "apt", "install", "-y", "gh"], check=True)
25
- else:
26
- print("❌ Unsupported OS.")
27
- return False
28
-
29
- return shutil.which("gh") is not None
30
- except Exception as e:
31
- print(f"❌ Failed to install GitHub CLI: {e}")
32
- return False
33
-
34
- import os
35
- import subprocess
36
- import shutil
37
- import tempfile
38
- import urllib.request
39
9
  import json
40
10
 
41
11
  def install_gh_cli_windows():
@@ -44,7 +14,7 @@ def install_gh_cli_windows():
44
14
  if shutil.which("winget"):
45
15
  try:
46
16
  print("📦 Attempting to install GitHub CLI with winget...")
47
- subprocess.run(["winget", "install", "--id", "GitHub.cli", "--silent"], check=True)
17
+ subprocess.run(["winget", "install", "--id", "GitHub.cli", "--source", "winget", "--silent"], check=True, capture_output=True)
48
18
  print("✅ GitHub CLI installed successfully via winget.")
49
19
  return True
50
20
  except (subprocess.CalledProcessError, FileNotFoundError):
@@ -57,15 +27,10 @@ def install_gh_cli_windows():
57
27
  with urllib.request.urlopen(api_url) as response:
58
28
  data = json.loads(response.read().decode())
59
29
 
60
- # Find the correct MSI asset
61
- msi_url = None
62
- for asset in data.get("assets", []):
63
- if asset.get("name", "").endswith("_windows_amd64.msi"):
64
- msi_url = asset.get("browser_download_url")
65
- break
30
+ msi_url = next((asset["browser_download_url"] for asset in data.get("assets", []) if asset.get("name", "").endswith("_windows_amd64.msi")), None)
66
31
 
67
32
  if not msi_url:
68
- print("❌ Could not find a downloadable MSI file for the latest release.")
33
+ print("❌ Could not find a downloadable MSI file for the latest release.", file=sys.stderr)
69
34
  return False
70
35
 
71
36
  msi_path = os.path.join(tempfile.gettempdir(), "gh_installer.msi")
@@ -74,36 +39,83 @@ def install_gh_cli_windows():
74
39
  urllib.request.urlretrieve(msi_url, msi_path)
75
40
 
76
41
  print("🛠️ Installing GitHub CLI...")
77
- # Use msiexec for silent installation
78
42
  subprocess.run(["msiexec", "/i", msi_path, "/quiet", "/norestart"], check=True)
79
43
 
80
- # Clean up the downloaded file
81
44
  os.remove(msi_path)
82
45
  print("✅ GitHub CLI installed successfully.")
83
46
  return True
84
47
  except Exception as e:
85
- print(f"❌ Direct installation failed: {e}")
48
+ print(f"❌ Direct installation failed: {e}", file=sys.stderr)
49
+ return False
50
+
51
+ def check_gh_installed():
52
+ """Check if GitHub CLI is installed. If not, prompt the user to install it."""
53
+ if shutil.which("gh"):
54
+ return True
55
+
56
+ print("❓ GitHub CLI (gh) is required for the '--new-repo' feature but was not found.", file=sys.stderr)
57
+ try:
58
+ answer = input(" Would you like this tool to attempt an automatic installation? (y/n): ").lower().strip()
59
+ except (EOFError, KeyboardInterrupt):
60
+ print("\nInstallation cancelled.", file=sys.stderr)
61
+ return False
62
+
63
+ if answer != 'y':
64
+ print("➡️ Installation skipped. Please install 'gh' manually from https://cli.github.com/", file=sys.stderr)
65
+ return False
66
+
67
+ print("\n📦 Attempting to install GitHub CLI...")
68
+ system = platform.system()
69
+ installed = False
70
+
71
+ try:
72
+ if system == "Windows":
73
+ installed = install_gh_cli_windows()
74
+ elif system == "Darwin":
75
+ print(" Running: brew install gh")
76
+ subprocess.run(["brew", "install", "gh"], check=True)
77
+ installed = True
78
+ elif system == "Linux":
79
+ print(" Running: sudo apt update && sudo apt install -y gh")
80
+ subprocess.run(["sudo", "apt", "update"], check=True)
81
+ subprocess.run(["sudo", "apt", "install", "-y", "gh"], check=True)
82
+ installed = True
83
+ else:
84
+ print(f"❌ Automatic installation is not supported for your OS ({system}).", file=sys.stderr)
85
+ print(" Please install 'gh' manually from https://cli.github.com/", file=sys.stderr)
86
+ return False
87
+
88
+ except (subprocess.CalledProcessError, FileNotFoundError) as e:
89
+ print(f"❌ Installation failed: {e}", file=sys.stderr)
90
+ print(" Please try installing 'gh' manually from https://cli.github.com/", file=sys.stderr)
86
91
  return False
87
92
 
93
+ if installed:
94
+ print("\n✅ GitHub CLI was installed successfully!", file=sys.stderr)
95
+ print("‼️ IMPORTANT: You must open a NEW terminal for the changes to take effect.", file=sys.stderr)
96
+ print(" Please re-run your command in a new terminal window.", file=sys.stderr)
97
+ sys.exit(0) # Exit gracefully so the user can follow instructions
98
+
99
+ return False
100
+
88
101
  def gh_authenticated():
89
102
  """Check if user is authenticated with GitHub CLI"""
90
103
  try:
91
- result = subprocess.run(["gh", "auth", "status"], capture_output=True, text=True)
92
- return result.returncode == 0
93
- except:
104
+ result = subprocess.run(["gh", "auth", "status"], capture_output=True, text=True, check=True)
105
+ return "Logged in to github.com" in result.stderr
106
+ except (subprocess.CalledProcessError, FileNotFoundError):
94
107
  return False
95
108
 
96
109
  def authenticate_with_gh():
97
110
  """Authenticate user with GitHub CLI"""
98
- print("\n🔑 GitHub authentication required")
99
- print("We'll use the GitHub CLI (gh) for authentication")
100
- print("This will open your browser for secure login")
111
+ print("\n🔑 GitHub authentication required.")
112
+ print("The tool will use the GitHub CLI (gh) to open a browser for secure login.")
101
113
 
102
114
  try:
103
115
  subprocess.run(["gh", "auth", "login", "--web", "-h", "github.com"], check=True)
104
116
  return True
105
117
  except subprocess.CalledProcessError:
106
- print("❌ Authentication failed")
118
+ print("❌ Authentication failed. Please try running 'gh auth login' manually.", file=sys.stderr)
107
119
  return False
108
120
 
109
121
  def initialize_git_repository():
@@ -113,8 +125,8 @@ def initialize_git_repository():
113
125
 
114
126
  print("🛠 Initializing git repository")
115
127
  try:
116
- subprocess.run(["git", "init"], check=True)
117
- subprocess.run(["git", "branch", "-M", "main"], check=True)
128
+ subprocess.run(["git", "init"], check=True, capture_output=True)
129
+ subprocess.run(["git", "branch", "-M", "main"], check=True, capture_output=True)
118
130
 
119
131
  if not os.path.exists(".gitignore"):
120
132
  with open(".gitignore", "w") as f:
@@ -145,7 +157,7 @@ Thumbs.db
145
157
  print("📁 Created .gitignore file")
146
158
  return True
147
159
  except subprocess.CalledProcessError as e:
148
- print(f"❌ Failed to initialize Git repository: {e}")
160
+ print(f"❌ Failed to initialize Git repository: {e.stderr.decode().strip()}", file=sys.stderr)
149
161
  return False
150
162
 
151
163
  def create_initial_commit(commit_message="Initial commit"):
@@ -162,16 +174,23 @@ def create_initial_commit(commit_message="Initial commit"):
162
174
  return True
163
175
  return False
164
176
  except subprocess.CalledProcessError as e:
165
- print(f" Failed to create initial commit: {e}")
177
+ if "nothing to commit" in e.stderr.decode():
178
+ print(f"❌ Failed to create initial commit: No files found to commit.", file=sys.stderr)
179
+ print("➡️ Add some files to your project directory before creating a repository.", file=sys.stderr)
180
+ else:
181
+ print(f"❌ Failed to create initial commit: {e.stderr.decode().strip()}", file=sys.stderr)
166
182
  return False
167
183
 
168
184
  def create_with_gh_cli(repo_name, private=False, description="", commit_message="Initial commit"):
169
185
  """Create and push to new repository using GitHub CLI"""
170
186
  try:
171
- if not os.path.exists(".git") and not initialize_git_repository():
172
- return False
187
+ if not os.path.exists(".git"):
188
+ if not initialize_git_repository():
189
+ return False
173
190
 
174
191
  if not create_initial_commit(commit_message):
192
+ if subprocess.run(["git", "status"], capture_output=True).returncode != 0:
193
+ return False
175
194
  print("ℹ️ Using existing commits")
176
195
 
177
196
  private_flag = "--private" if private else "--public"
@@ -182,21 +201,22 @@ def create_with_gh_cli(repo_name, private=False, description="", commit_message=
182
201
  cmd.extend(["--description", description])
183
202
 
184
203
  print("🚀 Creating repository and pushing code...")
185
- subprocess.run(cmd, check=True)
204
+ process = subprocess.run(cmd, check=True, capture_output=True, text=True)
186
205
 
187
- url_result = subprocess.run(
188
- ["gh", "repo", "view", "--json", "url", "--jq", ".url"],
189
- capture_output=True, text=True, check=True
190
- )
191
- repo_url = url_result.stdout.strip()
206
+ repo_url = process.stderr.strip()
192
207
  print(f"✅ Successfully created repository: {repo_url}")
193
208
  return True
194
209
 
195
210
  except subprocess.CalledProcessError as e:
196
- print(f"❌ Failed to create repository: {e.stderr if e.stderr else 'Unknown error'}")
211
+ error_message = e.stderr.strip()
212
+ if "already exists" in error_message:
213
+ print(f"❌ Failed to create repository: {error_message}", file=sys.stderr)
214
+ print("➡️ Please choose a different repository name.", file=sys.stderr)
215
+ else:
216
+ print(f"❌ Failed to create repository: {error_message}", file=sys.stderr)
197
217
  return False
198
218
  except Exception as e:
199
- print(f"❌ Unexpected error: {str(e)}")
219
+ print(f"❌ An unexpected error occurred: {str(e)}", file=sys.stderr)
200
220
  return False
201
221
 
202
222
  def standard_git_push(commit_message, branch, remote, force=False, tags=False):
@@ -205,14 +225,15 @@ def standard_git_push(commit_message, branch, remote, force=False, tags=False):
205
225
  subprocess.run(["git", "add", "."], check=True)
206
226
 
207
227
  if commit_message:
208
- print(f"📦 Committing: '{commit_message}'")
209
- subprocess.run(["git", "commit", "-m", commit_message], check=True)
228
+ print(f"📦 Committing with message: '{commit_message}'")
229
+ subprocess.run(["git", "commit", "-m", commit_message, "--allow-empty-message"], check=True)
210
230
  else:
211
- print("ℹ️ No commit message provided - skipping commit")
231
+ print("ℹ️ No commit message provided. Pushing only staged changes.")
212
232
 
213
233
  push_cmd = ["git", "push"]
214
234
  if force:
215
235
  push_cmd.append("--force-with-lease")
236
+ print("⚠️ Using safe force push (--force-with-lease).")
216
237
  if tags:
217
238
  push_cmd.append("--tags")
218
239
  if remote and branch:
@@ -220,10 +241,14 @@ def standard_git_push(commit_message, branch, remote, force=False, tags=False):
220
241
 
221
242
  print(f"🚀 Executing: {' '.join(push_cmd)}")
222
243
  subprocess.run(push_cmd, check=True)
223
- print("✅ Successfully pushed changes")
244
+ print("✅ Successfully pushed changes.")
224
245
  return True
225
246
  except subprocess.CalledProcessError as e:
226
- print(f"❌ Push failed: {e}")
247
+ error_output = e.stderr.decode().strip() if e.stderr else str(e)
248
+ if "nothing to commit" in error_output:
249
+ print("ℹ️ No changes to commit. Nothing to do.")
250
+ return True
251
+ print(f"❌ Push failed: {error_output}", file=sys.stderr)
227
252
  return False
228
253
 
229
254
  def run():
@@ -231,37 +256,40 @@ def run():
231
256
  description="🚀 Supercharged Git push tool with GitHub repo creation",
232
257
  formatter_class=argparse.RawDescriptionHelpFormatter,
233
258
  epilog="""Examples:
234
- Standard push: gitpush_tool "Commit message"
235
- Create new repo: gitpush_tool "Initial commit" --new-repo project-name
236
- Private repository: gitpush_tool --new-repo private-project --private
237
- Force push: gitpush_tool "Fix critical bug" --force
259
+ Standard push: gitpush_tool "My new feature"
260
+ Create new repo: gitpush_tool "Initial commit" --new-repo my-awesome-project
261
+ Private repository: gitpush_tool "Initial commit" --new-repo my-secret-project --private
262
+ Force push (safe): gitpush_tool "Rebased feature" --force
263
+ Initialize only: gitpush_tool --init
238
264
  """
239
265
  )
240
- parser.add_argument("commit", nargs="?", help="Commit message")
241
- parser.add_argument("branch", nargs="?", default="main", help="Branch name (default: main)")
242
- parser.add_argument("remote", nargs="?", default="origin", help="Remote name (default: origin)")
243
- parser.add_argument("--force", action="store_true", help="Force push with --force-with-lease")
244
- parser.add_argument("--tags", action="store_true", help="Push tags")
245
- parser.add_argument("--init", action="store_true", help="Initialize git repo")
246
- parser.add_argument("--new-repo", metavar="NAME", help="Create new GitHub repository")
247
- parser.add_argument("--private", action="store_true", help="Make repository private")
248
- parser.add_argument("--description", help="Repository description")
266
+ parser.add_argument("commit", nargs="?", help="Commit message (optional if just pushing staged changes).")
267
+ parser.add_argument("branch", nargs="?", default=None, help="Branch name (defaults to current branch).")
268
+ parser.add_argument("remote", nargs="?", default="origin", help="Remote name (default: origin).")
269
+ parser.add_argument("--force", action="store_true", help="Force push with --force-with-lease.")
270
+ parser.add_argument("--tags", action="store_true", help="Push all tags.")
271
+ parser.add_argument("--init", action="store_true", help="Initialize a new Git repository and exit.")
272
+ parser.add_argument("--new-repo", metavar="REPO_NAME", help="Create a new GitHub repository with the given name.")
273
+ parser.add_argument("--private", action="store_true", help="Make the new repository private.")
274
+ parser.add_argument("--description", help="Description for the new repository.")
249
275
 
250
276
  args = parser.parse_args()
277
+
278
+ target_branch = args.branch
279
+ if not target_branch:
280
+ try:
281
+ branch_result = subprocess.run(["git", "rev-parse", "--abbrev-ref", "HEAD"], capture_output=True, text=True, check=True)
282
+ target_branch = branch_result.stdout.strip()
283
+ except subprocess.CalledProcessError:
284
+ target_branch = "main"
251
285
 
252
286
  if args.new_repo:
253
- print(f"🆕 Creating repository: {args.new_repo}")
254
-
255
287
  if not check_gh_installed():
256
- print("❌ GitHub CLI (gh) is not installed")
257
- print("Please install it first:")
258
- print(" Mac (Homebrew): brew install gh")
259
- print(" Windows (Winget): winget install --id GitHub.cli")
260
- print(" Linux: See https://github.com/cli/cli#installation")
261
288
  sys.exit(1)
262
289
 
263
- if not gh_authenticated() and not authenticate_with_gh():
264
- sys.exit(1)
290
+ if not gh_authenticated():
291
+ if not authenticate_with_gh():
292
+ sys.exit(1)
265
293
 
266
294
  if not create_with_gh_cli(
267
295
  args.new_repo,
@@ -270,13 +298,15 @@ def run():
270
298
  commit_message=args.commit or "Initial commit"
271
299
  ):
272
300
  sys.exit(1)
301
+
273
302
  elif args.init:
274
303
  if initialize_git_repository():
275
- create_initial_commit(args.commit or "Initial commit")
304
+ print("✅ Git repository initialized successfully.")
305
+
276
306
  else:
277
307
  if not standard_git_push(
278
308
  args.commit,
279
- args.branch,
309
+ target_branch,
280
310
  args.remote,
281
311
  args.force,
282
312
  args.tags
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gitpush-tool
3
- Version: 0.2.8
3
+ Version: 0.2.9
4
4
  Summary: Supercharged Git push tool with automatic GitHub repo creation and pushing
5
5
  Home-page: https://github.com/inevitablegs/gitpush
6
6
  Author: Ganesh Sonawane
@@ -6,7 +6,7 @@ long_description = (Path(__file__).parent / "LONG_DESCRIPTION.md").read_text(enc
6
6
 
7
7
  setup(
8
8
  name="gitpush-tool",
9
- version="0.2.8",
9
+ version="0.2.9",
10
10
  packages=find_packages(),
11
11
  install_requires=[],
12
12
  entry_points={
@@ -1 +0,0 @@
1
- __version__ = "0.2.8"
File without changes
File without changes
File without changes
File without changes