gitpush-tool 0.2.7__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.
- {gitpush_tool-0.2.7/gitpush_tool.egg-info → gitpush_tool-0.2.9}/PKG-INFO +1 -1
- gitpush_tool-0.2.9/gitpush_tool/__init__.py +1 -0
- gitpush_tool-0.2.9/gitpush_tool/cli.py +317 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9/gitpush_tool.egg-info}/PKG-INFO +1 -1
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/setup.py +1 -1
- gitpush_tool-0.2.7/gitpush_tool/__init__.py +0 -1
- gitpush_tool-0.2.7/gitpush_tool/cli.py +0 -258
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/LICENSE +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/MANIFEST.in +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/README.md +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/gitpush_tool/__doc__.py +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/gitpush_tool.egg-info/SOURCES.txt +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/gitpush_tool.egg-info/dependency_links.txt +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/gitpush_tool.egg-info/entry_points.txt +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/gitpush_tool.egg-info/top_level.txt +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/pyproject.toml +0 -0
- {gitpush_tool-0.2.7 → gitpush_tool-0.2.9}/setup.cfg +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.9"
|
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import argparse
|
|
3
|
+
import sys
|
|
4
|
+
import subprocess
|
|
5
|
+
import shutil
|
|
6
|
+
import platform
|
|
7
|
+
import urllib.request
|
|
8
|
+
import tempfile
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
def install_gh_cli_windows():
|
|
12
|
+
"""Install GitHub CLI on Windows using winget or direct download"""
|
|
13
|
+
# Try winget first
|
|
14
|
+
if shutil.which("winget"):
|
|
15
|
+
try:
|
|
16
|
+
print("📦 Attempting to install GitHub CLI with winget...")
|
|
17
|
+
subprocess.run(["winget", "install", "--id", "GitHub.cli", "--source", "winget", "--silent"], check=True, capture_output=True)
|
|
18
|
+
print("✅ GitHub CLI installed successfully via winget.")
|
|
19
|
+
return True
|
|
20
|
+
except (subprocess.CalledProcessError, FileNotFoundError):
|
|
21
|
+
print("⚠️ Winget installation failed. Falling back to direct download.")
|
|
22
|
+
|
|
23
|
+
# Fallback to direct download
|
|
24
|
+
try:
|
|
25
|
+
print("⬇️ Finding the latest GitHub CLI release for Windows...")
|
|
26
|
+
api_url = "https://api.github.com/repos/cli/cli/releases/latest"
|
|
27
|
+
with urllib.request.urlopen(api_url) as response:
|
|
28
|
+
data = json.loads(response.read().decode())
|
|
29
|
+
|
|
30
|
+
msi_url = next((asset["browser_download_url"] for asset in data.get("assets", []) if asset.get("name", "").endswith("_windows_amd64.msi")), None)
|
|
31
|
+
|
|
32
|
+
if not msi_url:
|
|
33
|
+
print("❌ Could not find a downloadable MSI file for the latest release.", file=sys.stderr)
|
|
34
|
+
return False
|
|
35
|
+
|
|
36
|
+
msi_path = os.path.join(tempfile.gettempdir(), "gh_installer.msi")
|
|
37
|
+
|
|
38
|
+
print(f"⬇️ Downloading GitHub CLI from: {msi_url}")
|
|
39
|
+
urllib.request.urlretrieve(msi_url, msi_path)
|
|
40
|
+
|
|
41
|
+
print("🛠️ Installing GitHub CLI...")
|
|
42
|
+
subprocess.run(["msiexec", "/i", msi_path, "/quiet", "/norestart"], check=True)
|
|
43
|
+
|
|
44
|
+
os.remove(msi_path)
|
|
45
|
+
print("✅ GitHub CLI installed successfully.")
|
|
46
|
+
return True
|
|
47
|
+
except Exception as 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)
|
|
91
|
+
return False
|
|
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
|
+
|
|
101
|
+
def gh_authenticated():
|
|
102
|
+
"""Check if user is authenticated with GitHub CLI"""
|
|
103
|
+
try:
|
|
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):
|
|
107
|
+
return False
|
|
108
|
+
|
|
109
|
+
def authenticate_with_gh():
|
|
110
|
+
"""Authenticate user with GitHub CLI"""
|
|
111
|
+
print("\n🔑 GitHub authentication required.")
|
|
112
|
+
print("The tool will use the GitHub CLI (gh) to open a browser for secure login.")
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
subprocess.run(["gh", "auth", "login", "--web", "-h", "github.com"], check=True)
|
|
116
|
+
return True
|
|
117
|
+
except subprocess.CalledProcessError:
|
|
118
|
+
print("❌ Authentication failed. Please try running 'gh auth login' manually.", file=sys.stderr)
|
|
119
|
+
return False
|
|
120
|
+
|
|
121
|
+
def initialize_git_repository():
|
|
122
|
+
"""Initialize git repository if not already initialized"""
|
|
123
|
+
if os.path.exists(".git"):
|
|
124
|
+
return False
|
|
125
|
+
|
|
126
|
+
print("🛠 Initializing git repository")
|
|
127
|
+
try:
|
|
128
|
+
subprocess.run(["git", "init"], check=True, capture_output=True)
|
|
129
|
+
subprocess.run(["git", "branch", "-M", "main"], check=True, capture_output=True)
|
|
130
|
+
|
|
131
|
+
if not os.path.exists(".gitignore"):
|
|
132
|
+
with open(".gitignore", "w") as f:
|
|
133
|
+
f.write("""# Python
|
|
134
|
+
__pycache__/
|
|
135
|
+
*.py[cod]
|
|
136
|
+
*.so
|
|
137
|
+
.Python
|
|
138
|
+
env/
|
|
139
|
+
venv/
|
|
140
|
+
.env
|
|
141
|
+
|
|
142
|
+
# IDE
|
|
143
|
+
.vscode/
|
|
144
|
+
.idea/
|
|
145
|
+
*.swp
|
|
146
|
+
*.swo
|
|
147
|
+
|
|
148
|
+
# System
|
|
149
|
+
.DS_Store
|
|
150
|
+
Thumbs.db
|
|
151
|
+
|
|
152
|
+
# Project specific
|
|
153
|
+
*.log
|
|
154
|
+
*.tmp
|
|
155
|
+
*.bak
|
|
156
|
+
""")
|
|
157
|
+
print("📁 Created .gitignore file")
|
|
158
|
+
return True
|
|
159
|
+
except subprocess.CalledProcessError as e:
|
|
160
|
+
print(f"❌ Failed to initialize Git repository: {e.stderr.decode().strip()}", file=sys.stderr)
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
def create_initial_commit(commit_message="Initial commit"):
|
|
164
|
+
"""Create initial commit if no commits exist"""
|
|
165
|
+
try:
|
|
166
|
+
result = subprocess.run(["git", "rev-list", "--count", "HEAD"],
|
|
167
|
+
capture_output=True, text=True)
|
|
168
|
+
commit_count = int(result.stdout.strip()) if result.stdout.strip().isdigit() else 0
|
|
169
|
+
|
|
170
|
+
if commit_count == 0:
|
|
171
|
+
print("📦 Creating initial commit")
|
|
172
|
+
subprocess.run(["git", "add", "."], check=True)
|
|
173
|
+
subprocess.run(["git", "commit", "-m", commit_message], check=True)
|
|
174
|
+
return True
|
|
175
|
+
return False
|
|
176
|
+
except subprocess.CalledProcessError as 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)
|
|
182
|
+
return False
|
|
183
|
+
|
|
184
|
+
def create_with_gh_cli(repo_name, private=False, description="", commit_message="Initial commit"):
|
|
185
|
+
"""Create and push to new repository using GitHub CLI"""
|
|
186
|
+
try:
|
|
187
|
+
if not os.path.exists(".git"):
|
|
188
|
+
if not initialize_git_repository():
|
|
189
|
+
return False
|
|
190
|
+
|
|
191
|
+
if not create_initial_commit(commit_message):
|
|
192
|
+
if subprocess.run(["git", "status"], capture_output=True).returncode != 0:
|
|
193
|
+
return False
|
|
194
|
+
print("ℹ️ Using existing commits")
|
|
195
|
+
|
|
196
|
+
private_flag = "--private" if private else "--public"
|
|
197
|
+
cmd = ["gh", "repo", "create", repo_name, private_flag,
|
|
198
|
+
"--source=.", "--remote=origin", "--push"]
|
|
199
|
+
|
|
200
|
+
if description:
|
|
201
|
+
cmd.extend(["--description", description])
|
|
202
|
+
|
|
203
|
+
print("🚀 Creating repository and pushing code...")
|
|
204
|
+
process = subprocess.run(cmd, check=True, capture_output=True, text=True)
|
|
205
|
+
|
|
206
|
+
repo_url = process.stderr.strip()
|
|
207
|
+
print(f"✅ Successfully created repository: {repo_url}")
|
|
208
|
+
return True
|
|
209
|
+
|
|
210
|
+
except subprocess.CalledProcessError as e:
|
|
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)
|
|
217
|
+
return False
|
|
218
|
+
except Exception as e:
|
|
219
|
+
print(f"❌ An unexpected error occurred: {str(e)}", file=sys.stderr)
|
|
220
|
+
return False
|
|
221
|
+
|
|
222
|
+
def standard_git_push(commit_message, branch, remote, force=False, tags=False):
|
|
223
|
+
"""Handle standard git push operations"""
|
|
224
|
+
try:
|
|
225
|
+
subprocess.run(["git", "add", "."], check=True)
|
|
226
|
+
|
|
227
|
+
if commit_message:
|
|
228
|
+
print(f"📦 Committing with message: '{commit_message}'")
|
|
229
|
+
subprocess.run(["git", "commit", "-m", commit_message, "--allow-empty-message"], check=True)
|
|
230
|
+
else:
|
|
231
|
+
print("ℹ️ No commit message provided. Pushing only staged changes.")
|
|
232
|
+
|
|
233
|
+
push_cmd = ["git", "push"]
|
|
234
|
+
if force:
|
|
235
|
+
push_cmd.append("--force-with-lease")
|
|
236
|
+
print("⚠️ Using safe force push (--force-with-lease).")
|
|
237
|
+
if tags:
|
|
238
|
+
push_cmd.append("--tags")
|
|
239
|
+
if remote and branch:
|
|
240
|
+
push_cmd.extend([remote, branch])
|
|
241
|
+
|
|
242
|
+
print(f"🚀 Executing: {' '.join(push_cmd)}")
|
|
243
|
+
subprocess.run(push_cmd, check=True)
|
|
244
|
+
print("✅ Successfully pushed changes.")
|
|
245
|
+
return True
|
|
246
|
+
except subprocess.CalledProcessError as 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)
|
|
252
|
+
return False
|
|
253
|
+
|
|
254
|
+
def run():
|
|
255
|
+
parser = argparse.ArgumentParser(
|
|
256
|
+
description="🚀 Supercharged Git push tool with GitHub repo creation",
|
|
257
|
+
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
258
|
+
epilog="""Examples:
|
|
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
|
|
264
|
+
"""
|
|
265
|
+
)
|
|
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.")
|
|
275
|
+
|
|
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"
|
|
285
|
+
|
|
286
|
+
if args.new_repo:
|
|
287
|
+
if not check_gh_installed():
|
|
288
|
+
sys.exit(1)
|
|
289
|
+
|
|
290
|
+
if not gh_authenticated():
|
|
291
|
+
if not authenticate_with_gh():
|
|
292
|
+
sys.exit(1)
|
|
293
|
+
|
|
294
|
+
if not create_with_gh_cli(
|
|
295
|
+
args.new_repo,
|
|
296
|
+
private=args.private,
|
|
297
|
+
description=args.description or "",
|
|
298
|
+
commit_message=args.commit or "Initial commit"
|
|
299
|
+
):
|
|
300
|
+
sys.exit(1)
|
|
301
|
+
|
|
302
|
+
elif args.init:
|
|
303
|
+
if initialize_git_repository():
|
|
304
|
+
print("✅ Git repository initialized successfully.")
|
|
305
|
+
|
|
306
|
+
else:
|
|
307
|
+
if not standard_git_push(
|
|
308
|
+
args.commit,
|
|
309
|
+
target_branch,
|
|
310
|
+
args.remote,
|
|
311
|
+
args.force,
|
|
312
|
+
args.tags
|
|
313
|
+
):
|
|
314
|
+
sys.exit(1)
|
|
315
|
+
|
|
316
|
+
if __name__ == "__main__":
|
|
317
|
+
run()
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "0.2.7"
|
|
@@ -1,258 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
import argparse
|
|
3
|
-
import sys
|
|
4
|
-
import subprocess
|
|
5
|
-
import platform
|
|
6
|
-
import urllib.request
|
|
7
|
-
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
|
-
def install_gh_cli_windows():
|
|
35
|
-
"""Install GitHub CLI on Windows using winget or direct download"""
|
|
36
|
-
# Try winget first
|
|
37
|
-
if shutil.which("winget"):
|
|
38
|
-
try:
|
|
39
|
-
subprocess.run(["winget", "install", "--id", "GitHub.cli", "--silent"], check=True)
|
|
40
|
-
return True
|
|
41
|
-
except subprocess.CalledProcessError:
|
|
42
|
-
print("⚠️ winget installation failed.")
|
|
43
|
-
|
|
44
|
-
# Fallback to direct download
|
|
45
|
-
try:
|
|
46
|
-
print("⬇️ Downloading GitHub CLI installer...")
|
|
47
|
-
url = "https://github.com/cli/cli/releases/latest/download/gh_2.46.0_windows_amd64.msi"
|
|
48
|
-
msi_path = os.path.join(tempfile.gettempdir(), "gh_installer.msi")
|
|
49
|
-
urllib.request.urlretrieve(url, msi_path)
|
|
50
|
-
|
|
51
|
-
print("🛠 Installing GitHub CLI...")
|
|
52
|
-
subprocess.run(["msiexec", "/i", msi_path, "/quiet", "/norestart"], check=True)
|
|
53
|
-
os.remove(msi_path) # Clean up
|
|
54
|
-
return True
|
|
55
|
-
except Exception as e:
|
|
56
|
-
print(f"❌ Direct installation failed: {e}")
|
|
57
|
-
return False
|
|
58
|
-
|
|
59
|
-
def gh_authenticated():
|
|
60
|
-
"""Check if user is authenticated with GitHub CLI"""
|
|
61
|
-
try:
|
|
62
|
-
result = subprocess.run(["gh", "auth", "status"], capture_output=True, text=True)
|
|
63
|
-
return result.returncode == 0
|
|
64
|
-
except:
|
|
65
|
-
return False
|
|
66
|
-
|
|
67
|
-
def authenticate_with_gh():
|
|
68
|
-
"""Authenticate user with GitHub CLI"""
|
|
69
|
-
print("\n🔑 GitHub authentication required")
|
|
70
|
-
print("We'll use the GitHub CLI (gh) for authentication")
|
|
71
|
-
print("This will open your browser for secure login")
|
|
72
|
-
|
|
73
|
-
try:
|
|
74
|
-
subprocess.run(["gh", "auth", "login", "--web", "-h", "github.com"], check=True)
|
|
75
|
-
return True
|
|
76
|
-
except subprocess.CalledProcessError:
|
|
77
|
-
print("❌ Authentication failed")
|
|
78
|
-
return False
|
|
79
|
-
|
|
80
|
-
def initialize_git_repository():
|
|
81
|
-
"""Initialize git repository if not already initialized"""
|
|
82
|
-
if os.path.exists(".git"):
|
|
83
|
-
return False
|
|
84
|
-
|
|
85
|
-
print("🛠 Initializing git repository")
|
|
86
|
-
try:
|
|
87
|
-
subprocess.run(["git", "init"], check=True)
|
|
88
|
-
subprocess.run(["git", "branch", "-M", "main"], check=True)
|
|
89
|
-
|
|
90
|
-
if not os.path.exists(".gitignore"):
|
|
91
|
-
with open(".gitignore", "w") as f:
|
|
92
|
-
f.write("""# Python
|
|
93
|
-
__pycache__/
|
|
94
|
-
*.py[cod]
|
|
95
|
-
*.so
|
|
96
|
-
.Python
|
|
97
|
-
env/
|
|
98
|
-
venv/
|
|
99
|
-
.env
|
|
100
|
-
|
|
101
|
-
# IDE
|
|
102
|
-
.vscode/
|
|
103
|
-
.idea/
|
|
104
|
-
*.swp
|
|
105
|
-
*.swo
|
|
106
|
-
|
|
107
|
-
# System
|
|
108
|
-
.DS_Store
|
|
109
|
-
Thumbs.db
|
|
110
|
-
|
|
111
|
-
# Project specific
|
|
112
|
-
*.log
|
|
113
|
-
*.tmp
|
|
114
|
-
*.bak
|
|
115
|
-
""")
|
|
116
|
-
print("📁 Created .gitignore file")
|
|
117
|
-
return True
|
|
118
|
-
except subprocess.CalledProcessError as e:
|
|
119
|
-
print(f"❌ Failed to initialize Git repository: {e}")
|
|
120
|
-
return False
|
|
121
|
-
|
|
122
|
-
def create_initial_commit(commit_message="Initial commit"):
|
|
123
|
-
"""Create initial commit if no commits exist"""
|
|
124
|
-
try:
|
|
125
|
-
result = subprocess.run(["git", "rev-list", "--count", "HEAD"],
|
|
126
|
-
capture_output=True, text=True)
|
|
127
|
-
commit_count = int(result.stdout.strip()) if result.stdout.strip().isdigit() else 0
|
|
128
|
-
|
|
129
|
-
if commit_count == 0:
|
|
130
|
-
print("📦 Creating initial commit")
|
|
131
|
-
subprocess.run(["git", "add", "."], check=True)
|
|
132
|
-
subprocess.run(["git", "commit", "-m", commit_message], check=True)
|
|
133
|
-
return True
|
|
134
|
-
return False
|
|
135
|
-
except subprocess.CalledProcessError as e:
|
|
136
|
-
print(f"❌ Failed to create initial commit: {e}")
|
|
137
|
-
return False
|
|
138
|
-
|
|
139
|
-
def create_with_gh_cli(repo_name, private=False, description="", commit_message="Initial commit"):
|
|
140
|
-
"""Create and push to new repository using GitHub CLI"""
|
|
141
|
-
try:
|
|
142
|
-
if not os.path.exists(".git") and not initialize_git_repository():
|
|
143
|
-
return False
|
|
144
|
-
|
|
145
|
-
if not create_initial_commit(commit_message):
|
|
146
|
-
print("ℹ️ Using existing commits")
|
|
147
|
-
|
|
148
|
-
private_flag = "--private" if private else "--public"
|
|
149
|
-
cmd = ["gh", "repo", "create", repo_name, private_flag,
|
|
150
|
-
"--source=.", "--remote=origin", "--push"]
|
|
151
|
-
|
|
152
|
-
if description:
|
|
153
|
-
cmd.extend(["--description", description])
|
|
154
|
-
|
|
155
|
-
print("🚀 Creating repository and pushing code...")
|
|
156
|
-
subprocess.run(cmd, check=True)
|
|
157
|
-
|
|
158
|
-
url_result = subprocess.run(
|
|
159
|
-
["gh", "repo", "view", "--json", "url", "--jq", ".url"],
|
|
160
|
-
capture_output=True, text=True, check=True
|
|
161
|
-
)
|
|
162
|
-
repo_url = url_result.stdout.strip()
|
|
163
|
-
print(f"✅ Successfully created repository: {repo_url}")
|
|
164
|
-
return True
|
|
165
|
-
|
|
166
|
-
except subprocess.CalledProcessError as e:
|
|
167
|
-
print(f"❌ Failed to create repository: {e.stderr if e.stderr else 'Unknown error'}")
|
|
168
|
-
return False
|
|
169
|
-
except Exception as e:
|
|
170
|
-
print(f"❌ Unexpected error: {str(e)}")
|
|
171
|
-
return False
|
|
172
|
-
|
|
173
|
-
def standard_git_push(commit_message, branch, remote, force=False, tags=False):
|
|
174
|
-
"""Handle standard git push operations"""
|
|
175
|
-
try:
|
|
176
|
-
subprocess.run(["git", "add", "."], check=True)
|
|
177
|
-
|
|
178
|
-
if commit_message:
|
|
179
|
-
print(f"📦 Committing: '{commit_message}'")
|
|
180
|
-
subprocess.run(["git", "commit", "-m", commit_message], check=True)
|
|
181
|
-
else:
|
|
182
|
-
print("ℹ️ No commit message provided - skipping commit")
|
|
183
|
-
|
|
184
|
-
push_cmd = ["git", "push"]
|
|
185
|
-
if force:
|
|
186
|
-
push_cmd.append("--force-with-lease")
|
|
187
|
-
if tags:
|
|
188
|
-
push_cmd.append("--tags")
|
|
189
|
-
if remote and branch:
|
|
190
|
-
push_cmd.extend([remote, branch])
|
|
191
|
-
|
|
192
|
-
print(f"🚀 Executing: {' '.join(push_cmd)}")
|
|
193
|
-
subprocess.run(push_cmd, check=True)
|
|
194
|
-
print("✅ Successfully pushed changes")
|
|
195
|
-
return True
|
|
196
|
-
except subprocess.CalledProcessError as e:
|
|
197
|
-
print(f"❌ Push failed: {e}")
|
|
198
|
-
return False
|
|
199
|
-
|
|
200
|
-
def run():
|
|
201
|
-
parser = argparse.ArgumentParser(
|
|
202
|
-
description="🚀 Supercharged Git push tool with GitHub repo creation",
|
|
203
|
-
formatter_class=argparse.RawDescriptionHelpFormatter,
|
|
204
|
-
epilog="""Examples:
|
|
205
|
-
Standard push: gitpush_tool "Commit message"
|
|
206
|
-
Create new repo: gitpush_tool "Initial commit" --new-repo project-name
|
|
207
|
-
Private repository: gitpush_tool --new-repo private-project --private
|
|
208
|
-
Force push: gitpush_tool "Fix critical bug" --force
|
|
209
|
-
"""
|
|
210
|
-
)
|
|
211
|
-
parser.add_argument("commit", nargs="?", help="Commit message")
|
|
212
|
-
parser.add_argument("branch", nargs="?", default="main", help="Branch name (default: main)")
|
|
213
|
-
parser.add_argument("remote", nargs="?", default="origin", help="Remote name (default: origin)")
|
|
214
|
-
parser.add_argument("--force", action="store_true", help="Force push with --force-with-lease")
|
|
215
|
-
parser.add_argument("--tags", action="store_true", help="Push tags")
|
|
216
|
-
parser.add_argument("--init", action="store_true", help="Initialize git repo")
|
|
217
|
-
parser.add_argument("--new-repo", metavar="NAME", help="Create new GitHub repository")
|
|
218
|
-
parser.add_argument("--private", action="store_true", help="Make repository private")
|
|
219
|
-
parser.add_argument("--description", help="Repository description")
|
|
220
|
-
|
|
221
|
-
args = parser.parse_args()
|
|
222
|
-
|
|
223
|
-
if args.new_repo:
|
|
224
|
-
print(f"🆕 Creating repository: {args.new_repo}")
|
|
225
|
-
|
|
226
|
-
if not check_gh_installed():
|
|
227
|
-
print("❌ GitHub CLI (gh) is not installed")
|
|
228
|
-
print("Please install it first:")
|
|
229
|
-
print(" Mac (Homebrew): brew install gh")
|
|
230
|
-
print(" Windows (Winget): winget install --id GitHub.cli")
|
|
231
|
-
print(" Linux: See https://github.com/cli/cli#installation")
|
|
232
|
-
sys.exit(1)
|
|
233
|
-
|
|
234
|
-
if not gh_authenticated() and not authenticate_with_gh():
|
|
235
|
-
sys.exit(1)
|
|
236
|
-
|
|
237
|
-
if not create_with_gh_cli(
|
|
238
|
-
args.new_repo,
|
|
239
|
-
private=args.private,
|
|
240
|
-
description=args.description or "",
|
|
241
|
-
commit_message=args.commit or "Initial commit"
|
|
242
|
-
):
|
|
243
|
-
sys.exit(1)
|
|
244
|
-
elif args.init:
|
|
245
|
-
if initialize_git_repository():
|
|
246
|
-
create_initial_commit(args.commit or "Initial commit")
|
|
247
|
-
else:
|
|
248
|
-
if not standard_git_push(
|
|
249
|
-
args.commit,
|
|
250
|
-
args.branch,
|
|
251
|
-
args.remote,
|
|
252
|
-
args.force,
|
|
253
|
-
args.tags
|
|
254
|
-
):
|
|
255
|
-
sys.exit(1)
|
|
256
|
-
|
|
257
|
-
if __name__ == "__main__":
|
|
258
|
-
run()
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|