commitflow 1.0.2__tar.gz → 1.0.4__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.
- {commitflow-1.0.2 → commitflow-1.0.4}/PKG-INFO +1 -1
- {commitflow-1.0.2 → commitflow-1.0.4}/commitflow.egg-info/PKG-INFO +1 -1
- commitflow-1.0.4/daily_git_assistant/__init__.py +1 -0
- commitflow-1.0.4/daily_git_assistant/repo_scanner.py +385 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/setup.py +16 -1
- commitflow-1.0.2/daily_git_assistant/__init__.py +0 -1
- commitflow-1.0.2/daily_git_assistant/repo_scanner.py +0 -127
- {commitflow-1.0.2 → commitflow-1.0.4}/LICENSE +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/README.md +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/commitflow.egg-info/SOURCES.txt +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/commitflow.egg-info/dependency_links.txt +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/commitflow.egg-info/entry_points.txt +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/commitflow.egg-info/requires.txt +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/commitflow.egg-info/top_level.txt +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/config.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/git_utils.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/logger.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/main.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/modes/__init__.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/modes/auto.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/modes/interactive.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/modes/quick.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/modes/setup.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/scheduler.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/daily_git_assistant/ui.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/setup.cfg +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/tests/test_commit_flow.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/tests/test_config.py +0 -0
- {commitflow-1.0.2 → commitflow-1.0.4}/tests/test_git_utils.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "1.0.4"
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import json
|
|
4
|
+
import threading
|
|
5
|
+
import itertools
|
|
6
|
+
import time
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
9
|
+
|
|
10
|
+
from .git_utils import is_git_repo
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
# --------------------------------------------------
|
|
14
|
+
# Repo index file
|
|
15
|
+
# --------------------------------------------------
|
|
16
|
+
|
|
17
|
+
INDEX_FILE = os.path.join(Path.home(), ".commitflow_repo_index.json")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
# --------------------------------------------------
|
|
21
|
+
# Directories to skip during scanning
|
|
22
|
+
# --------------------------------------------------
|
|
23
|
+
|
|
24
|
+
SKIP_DIRS = {
|
|
25
|
+
# Windows system
|
|
26
|
+
"Windows",
|
|
27
|
+
"Program Files",
|
|
28
|
+
"Program Files (x86)",
|
|
29
|
+
"ProgramData",
|
|
30
|
+
"$Recycle.Bin",
|
|
31
|
+
"System Volume Information",
|
|
32
|
+
"Recovery",
|
|
33
|
+
"PerfLogs",
|
|
34
|
+
|
|
35
|
+
# Windows user cache
|
|
36
|
+
"AppData",
|
|
37
|
+
"Temp",
|
|
38
|
+
|
|
39
|
+
# Development dependencies
|
|
40
|
+
"node_modules",
|
|
41
|
+
"__pycache__",
|
|
42
|
+
".cache",
|
|
43
|
+
".npm",
|
|
44
|
+
".yarn",
|
|
45
|
+
".venv",
|
|
46
|
+
"venv",
|
|
47
|
+
"env",
|
|
48
|
+
".tox",
|
|
49
|
+
"dist",
|
|
50
|
+
"build",
|
|
51
|
+
".mypy_cache",
|
|
52
|
+
".pytest_cache",
|
|
53
|
+
".gradle",
|
|
54
|
+
|
|
55
|
+
# IDE folders
|
|
56
|
+
".idea",
|
|
57
|
+
".vscode",
|
|
58
|
+
|
|
59
|
+
# Linux system
|
|
60
|
+
"proc",
|
|
61
|
+
"sys",
|
|
62
|
+
"dev",
|
|
63
|
+
"run",
|
|
64
|
+
"boot",
|
|
65
|
+
"lib",
|
|
66
|
+
"lib64",
|
|
67
|
+
"snap",
|
|
68
|
+
"var",
|
|
69
|
+
"lost+found",
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
# --------------------------------------------------
|
|
74
|
+
# Known developer directories
|
|
75
|
+
# --------------------------------------------------
|
|
76
|
+
|
|
77
|
+
def get_dev_directories():
|
|
78
|
+
|
|
79
|
+
home = Path.home()
|
|
80
|
+
|
|
81
|
+
candidates = [
|
|
82
|
+
home / "projects",
|
|
83
|
+
home / "Projects",
|
|
84
|
+
home / "dev",
|
|
85
|
+
home / "workspace",
|
|
86
|
+
home / "code",
|
|
87
|
+
home / "src",
|
|
88
|
+
home / "repos",
|
|
89
|
+
home / "Documents",
|
|
90
|
+
home / "Downloads",
|
|
91
|
+
home / "Pictures",
|
|
92
|
+
home / "Videos",
|
|
93
|
+
home / "Music",
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
dev_dirs = []
|
|
97
|
+
|
|
98
|
+
for d in candidates:
|
|
99
|
+
|
|
100
|
+
if d.exists():
|
|
101
|
+
dev_dirs.append(str(d))
|
|
102
|
+
|
|
103
|
+
return dev_dirs
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
# --------------------------------------------------
|
|
107
|
+
# Save repo index
|
|
108
|
+
# --------------------------------------------------
|
|
109
|
+
|
|
110
|
+
def save_repo_index(repos):
|
|
111
|
+
|
|
112
|
+
try:
|
|
113
|
+
with open(INDEX_FILE, "w", encoding="utf-8") as f:
|
|
114
|
+
json.dump(repos, f, indent=2)
|
|
115
|
+
|
|
116
|
+
except Exception:
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
# --------------------------------------------------
|
|
121
|
+
# Load repo index
|
|
122
|
+
# --------------------------------------------------
|
|
123
|
+
|
|
124
|
+
def load_repo_index():
|
|
125
|
+
|
|
126
|
+
if not os.path.exists(INDEX_FILE):
|
|
127
|
+
return []
|
|
128
|
+
|
|
129
|
+
try:
|
|
130
|
+
with open(INDEX_FILE, "r", encoding="utf-8") as f:
|
|
131
|
+
return json.load(f)
|
|
132
|
+
|
|
133
|
+
except Exception:
|
|
134
|
+
return []
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
# --------------------------------------------------
|
|
138
|
+
# Validate stored repo paths
|
|
139
|
+
# --------------------------------------------------
|
|
140
|
+
|
|
141
|
+
def validate_repo_index(repos):
|
|
142
|
+
|
|
143
|
+
valid = []
|
|
144
|
+
|
|
145
|
+
for repo in repos:
|
|
146
|
+
|
|
147
|
+
if os.path.exists(repo) and is_git_repo(repo):
|
|
148
|
+
valid.append(repo)
|
|
149
|
+
|
|
150
|
+
return valid
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
# --------------------------------------------------
|
|
154
|
+
# Detect system roots
|
|
155
|
+
# --------------------------------------------------
|
|
156
|
+
|
|
157
|
+
def get_system_roots():
|
|
158
|
+
|
|
159
|
+
roots = []
|
|
160
|
+
|
|
161
|
+
if os.name == "nt":
|
|
162
|
+
|
|
163
|
+
for letter in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
|
|
164
|
+
|
|
165
|
+
drive = f"{letter}:\\"
|
|
166
|
+
|
|
167
|
+
if os.path.exists(drive):
|
|
168
|
+
roots.append(drive)
|
|
169
|
+
|
|
170
|
+
else:
|
|
171
|
+
roots.append("/")
|
|
172
|
+
|
|
173
|
+
return roots
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
# --------------------------------------------------
|
|
177
|
+
# Spinner progress
|
|
178
|
+
# --------------------------------------------------
|
|
179
|
+
|
|
180
|
+
def spinner_progress(counter, repos_found, stop_event):
|
|
181
|
+
|
|
182
|
+
spinner = itertools.cycle([
|
|
183
|
+
"⠋","⠙","⠹","⠸","⠼","⠴","⠦","⠧","⠇","⠏"
|
|
184
|
+
])
|
|
185
|
+
|
|
186
|
+
while not stop_event.is_set():
|
|
187
|
+
|
|
188
|
+
spin = next(spinner)
|
|
189
|
+
|
|
190
|
+
sys.stdout.write(
|
|
191
|
+
f"\rScanning system {spin} folders: {counter[0]} repos: {repos_found[0]}"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
sys.stdout.flush()
|
|
195
|
+
|
|
196
|
+
time.sleep(0.1)
|
|
197
|
+
|
|
198
|
+
print()
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# --------------------------------------------------
|
|
202
|
+
# Scan a directory with adaptive depth
|
|
203
|
+
# --------------------------------------------------
|
|
204
|
+
|
|
205
|
+
def scan_directory(base_directory, counter, repos_found):
|
|
206
|
+
|
|
207
|
+
repos = []
|
|
208
|
+
|
|
209
|
+
base_depth = base_directory.count(os.sep)
|
|
210
|
+
|
|
211
|
+
for root, dirs, files in os.walk(base_directory):
|
|
212
|
+
|
|
213
|
+
counter[0] += 1
|
|
214
|
+
|
|
215
|
+
# Directory pruning
|
|
216
|
+
dirs[:] = [d for d in dirs if d not in SKIP_DIRS]
|
|
217
|
+
|
|
218
|
+
depth = root.count(os.sep) - base_depth
|
|
219
|
+
|
|
220
|
+
# Adaptive depth
|
|
221
|
+
if base_directory == str(Path.home()):
|
|
222
|
+
max_depth = 5
|
|
223
|
+
else:
|
|
224
|
+
max_depth = 3
|
|
225
|
+
|
|
226
|
+
if depth > max_depth:
|
|
227
|
+
dirs[:] = []
|
|
228
|
+
continue
|
|
229
|
+
|
|
230
|
+
# Early git detection
|
|
231
|
+
if ".git" in dirs:
|
|
232
|
+
|
|
233
|
+
if is_git_repo(root):
|
|
234
|
+
|
|
235
|
+
repos.append(root)
|
|
236
|
+
repos_found[0] += 1
|
|
237
|
+
|
|
238
|
+
dirs.remove(".git")
|
|
239
|
+
|
|
240
|
+
return repos
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
# --------------------------------------------------
|
|
244
|
+
# Scan entire filesystem (parallel)
|
|
245
|
+
# --------------------------------------------------
|
|
246
|
+
|
|
247
|
+
def scan_entire_system():
|
|
248
|
+
|
|
249
|
+
roots = get_system_roots()
|
|
250
|
+
dev_dirs = get_dev_directories()
|
|
251
|
+
|
|
252
|
+
repos = []
|
|
253
|
+
|
|
254
|
+
counter = [0]
|
|
255
|
+
repos_found = [0]
|
|
256
|
+
|
|
257
|
+
stop_event = threading.Event()
|
|
258
|
+
|
|
259
|
+
spinner_thread = threading.Thread(
|
|
260
|
+
target=spinner_progress,
|
|
261
|
+
args=(counter, repos_found, stop_event),
|
|
262
|
+
daemon=True
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
spinner_thread.start()
|
|
266
|
+
|
|
267
|
+
try:
|
|
268
|
+
|
|
269
|
+
# 1️⃣ Scan developer directories first
|
|
270
|
+
for dev_dir in dev_dirs:
|
|
271
|
+
|
|
272
|
+
repos.extend(scan_directory(dev_dir, counter, repos_found))
|
|
273
|
+
|
|
274
|
+
# 2️⃣ Parallel scan system roots
|
|
275
|
+
with ThreadPoolExecutor(max_workers=4) as executor:
|
|
276
|
+
|
|
277
|
+
futures = []
|
|
278
|
+
|
|
279
|
+
for root in roots:
|
|
280
|
+
futures.append(
|
|
281
|
+
executor.submit(scan_directory, root, counter, repos_found)
|
|
282
|
+
)
|
|
283
|
+
|
|
284
|
+
for f in futures:
|
|
285
|
+
repos.extend(f.result())
|
|
286
|
+
|
|
287
|
+
except Exception:
|
|
288
|
+
pass
|
|
289
|
+
|
|
290
|
+
stop_event.set()
|
|
291
|
+
spinner_thread.join()
|
|
292
|
+
|
|
293
|
+
return repos
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
# --------------------------------------------------
|
|
297
|
+
# Display repositories
|
|
298
|
+
# --------------------------------------------------
|
|
299
|
+
|
|
300
|
+
def display_repos(repos):
|
|
301
|
+
|
|
302
|
+
if not repos:
|
|
303
|
+
|
|
304
|
+
print("\nNo Git repositories found.")
|
|
305
|
+
return
|
|
306
|
+
|
|
307
|
+
print("\nDetected Git Repositories:\n")
|
|
308
|
+
|
|
309
|
+
for index, repo in enumerate(repos, start=1):
|
|
310
|
+
|
|
311
|
+
name = os.path.basename(repo)
|
|
312
|
+
|
|
313
|
+
print(f"{index}. {name} ({repo})")
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
# --------------------------------------------------
|
|
317
|
+
# Repo selection
|
|
318
|
+
# --------------------------------------------------
|
|
319
|
+
|
|
320
|
+
def select_repo(repos):
|
|
321
|
+
|
|
322
|
+
if not repos:
|
|
323
|
+
return None
|
|
324
|
+
|
|
325
|
+
display_repos(repos)
|
|
326
|
+
|
|
327
|
+
while True:
|
|
328
|
+
|
|
329
|
+
choice = input("\nSelect repository number (or 'r' to rescan) ➤ ").strip()
|
|
330
|
+
|
|
331
|
+
if choice.lower() == "r":
|
|
332
|
+
return "rescan"
|
|
333
|
+
|
|
334
|
+
try:
|
|
335
|
+
|
|
336
|
+
index = int(choice) - 1
|
|
337
|
+
|
|
338
|
+
if 0 <= index < len(repos):
|
|
339
|
+
return repos[index]
|
|
340
|
+
|
|
341
|
+
else:
|
|
342
|
+
print("Invalid selection.")
|
|
343
|
+
|
|
344
|
+
except ValueError:
|
|
345
|
+
|
|
346
|
+
print("Enter a valid number or 'r'.")
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
# --------------------------------------------------
|
|
350
|
+
# Main repo detection workflow
|
|
351
|
+
# --------------------------------------------------
|
|
352
|
+
|
|
353
|
+
def auto_detect_repo():
|
|
354
|
+
|
|
355
|
+
print("Scanning system for Git repositories...\n")
|
|
356
|
+
|
|
357
|
+
repos = load_repo_index()
|
|
358
|
+
|
|
359
|
+
repos = validate_repo_index(repos)
|
|
360
|
+
|
|
361
|
+
if not repos:
|
|
362
|
+
|
|
363
|
+
repos = scan_entire_system()
|
|
364
|
+
|
|
365
|
+
repos = list(set(repos))
|
|
366
|
+
|
|
367
|
+
save_repo_index(repos)
|
|
368
|
+
|
|
369
|
+
while True:
|
|
370
|
+
|
|
371
|
+
repo = select_repo(repos)
|
|
372
|
+
|
|
373
|
+
if repo == "rescan":
|
|
374
|
+
|
|
375
|
+
print("\nRescanning entire system...\n")
|
|
376
|
+
|
|
377
|
+
repos = scan_entire_system()
|
|
378
|
+
|
|
379
|
+
repos = list(set(repos))
|
|
380
|
+
|
|
381
|
+
save_repo_index(repos)
|
|
382
|
+
|
|
383
|
+
continue
|
|
384
|
+
|
|
385
|
+
return repo
|
|
@@ -18,6 +18,21 @@ else:
|
|
|
18
18
|
long_description = ""
|
|
19
19
|
|
|
20
20
|
|
|
21
|
+
# -----------------------------
|
|
22
|
+
# Read version from package
|
|
23
|
+
# -----------------------------
|
|
24
|
+
|
|
25
|
+
def get_version():
|
|
26
|
+
|
|
27
|
+
version_file = Path("daily_git_assistant/__init__.py").read_text()
|
|
28
|
+
|
|
29
|
+
for line in version_file.splitlines():
|
|
30
|
+
|
|
31
|
+
if line.startswith("__version__"):
|
|
32
|
+
|
|
33
|
+
return line.split("=")[1].strip().strip('"').strip("'")
|
|
34
|
+
|
|
35
|
+
|
|
21
36
|
# -----------------------------
|
|
22
37
|
# Add Scripts folder to PATH
|
|
23
38
|
# -----------------------------
|
|
@@ -62,7 +77,7 @@ setup(
|
|
|
62
77
|
|
|
63
78
|
name="commitflow",
|
|
64
79
|
|
|
65
|
-
version=
|
|
80
|
+
version=get_version(),
|
|
66
81
|
|
|
67
82
|
description="CLI tool for maintaining consistent Git commits automatically",
|
|
68
83
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "1.0.0"
|
|
@@ -1,127 +0,0 @@
|
|
|
1
|
-
import os
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from .git_utils import is_git_repo
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
def scan_for_git_repos(base_directory=None, max_depth=3):
|
|
7
|
-
"""
|
|
8
|
-
Scan a directory recursively to find Git repositories.
|
|
9
|
-
"""
|
|
10
|
-
|
|
11
|
-
repos = []
|
|
12
|
-
|
|
13
|
-
if base_directory is None:
|
|
14
|
-
base_directory = Path.home()
|
|
15
|
-
|
|
16
|
-
base_directory = os.path.expanduser(base_directory)
|
|
17
|
-
|
|
18
|
-
for root, dirs, files in os.walk(base_directory):
|
|
19
|
-
|
|
20
|
-
# limit search depth
|
|
21
|
-
depth = root[len(base_directory):].count(os.sep)
|
|
22
|
-
if depth > max_depth:
|
|
23
|
-
dirs[:] = []
|
|
24
|
-
continue
|
|
25
|
-
|
|
26
|
-
if ".git" in dirs:
|
|
27
|
-
|
|
28
|
-
if is_git_repo(root):
|
|
29
|
-
repos.append(root)
|
|
30
|
-
|
|
31
|
-
dirs.remove(".git")
|
|
32
|
-
|
|
33
|
-
return repos
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def scan_common_dev_directories():
|
|
37
|
-
"""
|
|
38
|
-
Scan common development directories automatically.
|
|
39
|
-
"""
|
|
40
|
-
|
|
41
|
-
common_dirs = [
|
|
42
|
-
os.path.join(Path.home(), "projects"),
|
|
43
|
-
os.path.join(Path.home(), "Projects"),
|
|
44
|
-
os.path.join(Path.home(), "Documents"),
|
|
45
|
-
os.path.join(Path.home(), "workspace"),
|
|
46
|
-
os.path.join(Path.home(), "dev"),
|
|
47
|
-
]
|
|
48
|
-
|
|
49
|
-
repos = []
|
|
50
|
-
|
|
51
|
-
for directory in common_dirs:
|
|
52
|
-
|
|
53
|
-
if os.path.exists(directory):
|
|
54
|
-
|
|
55
|
-
repos.extend(scan_for_git_repos(directory))
|
|
56
|
-
|
|
57
|
-
# remove duplicates
|
|
58
|
-
repos = list(set(repos))
|
|
59
|
-
|
|
60
|
-
return repos
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
def display_repos(repos):
|
|
64
|
-
"""
|
|
65
|
-
Display detected repositories.
|
|
66
|
-
"""
|
|
67
|
-
|
|
68
|
-
if not repos:
|
|
69
|
-
|
|
70
|
-
print("No Git repositories found.")
|
|
71
|
-
return
|
|
72
|
-
|
|
73
|
-
print("\nDetected Git Repositories:\n")
|
|
74
|
-
|
|
75
|
-
for index, repo in enumerate(repos, start=1):
|
|
76
|
-
|
|
77
|
-
name = os.path.basename(repo)
|
|
78
|
-
|
|
79
|
-
print(f"{index}. {name} ({repo})")
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
def select_repo(repos):
|
|
83
|
-
"""
|
|
84
|
-
Allow user to choose repository interactively.
|
|
85
|
-
"""
|
|
86
|
-
|
|
87
|
-
if not repos:
|
|
88
|
-
return None
|
|
89
|
-
|
|
90
|
-
display_repos(repos)
|
|
91
|
-
|
|
92
|
-
while True:
|
|
93
|
-
|
|
94
|
-
try:
|
|
95
|
-
|
|
96
|
-
choice = input("\nSelect repository number ➤ ").strip()
|
|
97
|
-
|
|
98
|
-
index = int(choice) - 1
|
|
99
|
-
|
|
100
|
-
if 0 <= index < len(repos):
|
|
101
|
-
|
|
102
|
-
return repos[index]
|
|
103
|
-
|
|
104
|
-
else:
|
|
105
|
-
print("Invalid selection. Try again.")
|
|
106
|
-
|
|
107
|
-
except ValueError:
|
|
108
|
-
|
|
109
|
-
print("Enter a valid number.")
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
def auto_detect_repo():
|
|
113
|
-
"""
|
|
114
|
-
Auto detect repositories and allow selection.
|
|
115
|
-
"""
|
|
116
|
-
|
|
117
|
-
print("Scanning for Git repositories...")
|
|
118
|
-
|
|
119
|
-
repos = scan_common_dev_directories()
|
|
120
|
-
|
|
121
|
-
if not repos:
|
|
122
|
-
|
|
123
|
-
print("No repositories detected.")
|
|
124
|
-
|
|
125
|
-
return None
|
|
126
|
-
|
|
127
|
-
return select_repo(repos)
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|