gitarsenal-cli 1.1.1 โ 1.1.3
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.
- package/package.json +1 -1
- package/python/README.md +198 -35
- package/python/gitarsenal.py +434 -65
- package/python/gitarsenal_proxy_client.py +375 -0
- package/python/modal_proxy_service.py +317 -0
- package/python/requirements.txt +6 -0
- package/python/test_modalSandboxScript.py +225 -64
@@ -478,36 +478,73 @@ def create_modal_sandbox(gpu_type, repo_url=None, repo_name=None, setup_commands
|
|
478
478
|
|
479
479
|
# Check if Modal is authenticated
|
480
480
|
try:
|
481
|
-
# Try to
|
482
|
-
import
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
481
|
+
# Try to import modal first to check if it's installed
|
482
|
+
import modal
|
483
|
+
|
484
|
+
# Try to access Modal token to check authentication
|
485
|
+
try:
|
486
|
+
# This will raise an exception if not authenticated
|
487
|
+
modal.config.get_current_workspace_name()
|
488
|
+
print("โ
Modal authentication verified")
|
489
|
+
except modal.exception.AuthError:
|
490
|
+
print("\n" + "="*80)
|
491
|
+
print("๐ MODAL AUTHENTICATION REQUIRED")
|
492
|
+
print("="*80)
|
493
|
+
print("GitArsenal requires Modal authentication to create cloud environments.")
|
494
|
+
|
495
|
+
# Try to get token from credentials manager
|
496
|
+
modal_token = None
|
488
497
|
if credentials_manager:
|
489
|
-
|
490
|
-
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
498
|
+
try:
|
499
|
+
modal_token = credentials_manager.get_modal_token()
|
500
|
+
if modal_token:
|
501
|
+
# Set the token in the environment
|
502
|
+
os.environ["MODAL_TOKEN_ID"] = modal_token
|
503
|
+
print("โ
Modal token set from credentials manager")
|
504
|
+
|
505
|
+
# Try to authenticate with the token
|
506
|
+
try:
|
507
|
+
import subprocess
|
508
|
+
token_result = subprocess.run(
|
509
|
+
["modal", "token", "set", modal_token],
|
510
|
+
capture_output=True, text=True
|
511
|
+
)
|
512
|
+
if token_result.returncode == 0:
|
513
|
+
print("โ
Successfully authenticated with Modal")
|
514
|
+
else:
|
515
|
+
print(f"โ ๏ธ Failed to authenticate with Modal: {token_result.stderr}")
|
516
|
+
print("\nPlease authenticate manually:")
|
517
|
+
print("1. Run 'modal token new' to get a new token")
|
518
|
+
print("2. Then restart this command")
|
519
|
+
return None
|
520
|
+
except Exception as e:
|
521
|
+
print(f"โ ๏ธ Error setting Modal token: {e}")
|
504
522
|
return None
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
|
509
|
-
print("
|
523
|
+
except Exception as e:
|
524
|
+
print(f"โ ๏ธ Error getting Modal token: {e}")
|
525
|
+
|
526
|
+
if not modal_token:
|
527
|
+
print("\nTo authenticate with Modal, you need to:")
|
528
|
+
print("1. Create a Modal account at https://modal.com if you don't have one")
|
529
|
+
print("2. Run the following command to get a token:")
|
530
|
+
print(" modal token new")
|
531
|
+
print("3. Then set up your credentials in GitArsenal:")
|
532
|
+
print(" ./gitarsenal.py credentials set modal_token")
|
533
|
+
print("\nAfter completing these steps, try your command again.")
|
534
|
+
print("="*80)
|
510
535
|
return None
|
536
|
+
except ImportError:
|
537
|
+
print("\n" + "="*80)
|
538
|
+
print("โ MODAL PACKAGE NOT INSTALLED")
|
539
|
+
print("="*80)
|
540
|
+
print("GitArsenal requires the Modal package to be installed.")
|
541
|
+
print("\nTo install Modal, run:")
|
542
|
+
print(" pip install modal")
|
543
|
+
print("\nAfter installation, authenticate with Modal:")
|
544
|
+
print("1. Run 'modal token new'")
|
545
|
+
print("2. Then run './gitarsenal.py credentials set modal_token'")
|
546
|
+
print("="*80)
|
547
|
+
return None
|
511
548
|
except Exception as e:
|
512
549
|
print(f"โ ๏ธ Error checking Modal authentication: {e}")
|
513
550
|
print("Continuing anyway, but Modal operations may fail")
|
@@ -2393,53 +2430,177 @@ def fetch_setup_commands_from_api(repo_url):
|
|
2393
2430
|
|
2394
2431
|
# Make the API request
|
2395
2432
|
print(f"๐ Making POST request to: {api_url}")
|
2396
|
-
|
2397
|
-
|
2398
|
-
|
2399
|
-
|
2400
|
-
|
2401
|
-
|
2402
|
-
|
2403
|
-
|
2404
|
-
|
2405
|
-
# Extract setup commands from the response
|
2406
|
-
if "setupInstructions" in data and "commands" in data["setupInstructions"]:
|
2407
|
-
commands = data["setupInstructions"]["commands"]
|
2408
|
-
print(f"โ
Successfully fetched {len(commands)} setup commands from API")
|
2409
|
-
|
2410
|
-
# Print the commands for reference
|
2411
|
-
for i, cmd in enumerate(commands, 1):
|
2412
|
-
print(f" {i}. {cmd}")
|
2433
|
+
try:
|
2434
|
+
response = requests.post(api_url, json=payload, timeout=60)
|
2435
|
+
|
2436
|
+
print(f"๐ฅ API Response status code: {response.status_code}")
|
2437
|
+
|
2438
|
+
if response.status_code == 200:
|
2439
|
+
try:
|
2440
|
+
data = response.json()
|
2441
|
+
print(f"๐ API Response data received")
|
2413
2442
|
|
2414
|
-
|
2415
|
-
|
2416
|
-
|
2417
|
-
|
2418
|
-
|
2419
|
-
|
2420
|
-
|
2421
|
-
|
2422
|
-
|
2423
|
-
|
2424
|
-
|
2425
|
-
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2431
|
-
|
2432
|
-
|
2443
|
+
# Extract setup commands from the response
|
2444
|
+
if "setupInstructions" in data and "commands" in data["setupInstructions"]:
|
2445
|
+
commands = data["setupInstructions"]["commands"]
|
2446
|
+
print(f"โ
Successfully fetched {len(commands)} setup commands from API")
|
2447
|
+
|
2448
|
+
# Print the commands for reference
|
2449
|
+
for i, cmd in enumerate(commands, 1):
|
2450
|
+
print(f" {i}. {cmd}")
|
2451
|
+
|
2452
|
+
return commands
|
2453
|
+
else:
|
2454
|
+
print("โ ๏ธ API response did not contain setupInstructions.commands field")
|
2455
|
+
print("๐ Available fields in response:")
|
2456
|
+
for key in data.keys():
|
2457
|
+
print(f" - {key}")
|
2458
|
+
# Return fallback commands
|
2459
|
+
return generate_fallback_commands(gitingest_data)
|
2460
|
+
except json.JSONDecodeError as e:
|
2461
|
+
print(f"โ Failed to parse API response as JSON: {e}")
|
2462
|
+
print(f"Raw response: {response.text[:500]}...")
|
2463
|
+
# Return fallback commands
|
2464
|
+
return generate_fallback_commands(gitingest_data)
|
2465
|
+
elif response.status_code == 504:
|
2466
|
+
print(f"โ API request timed out (504 Gateway Timeout)")
|
2467
|
+
print("โ ๏ธ The server took too long to respond. Using fallback commands instead.")
|
2468
|
+
# Return fallback commands
|
2469
|
+
return generate_fallback_commands(gitingest_data)
|
2470
|
+
else:
|
2471
|
+
print(f"โ API request failed with status code: {response.status_code}")
|
2472
|
+
print(f"Error response: {response.text[:500]}...")
|
2473
|
+
# Return fallback commands
|
2474
|
+
return generate_fallback_commands(gitingest_data)
|
2475
|
+
except requests.exceptions.Timeout:
|
2476
|
+
print("โ API request timed out after 60 seconds")
|
2477
|
+
print("โ ๏ธ Using fallback commands instead")
|
2478
|
+
# Return fallback commands
|
2479
|
+
return generate_fallback_commands(gitingest_data)
|
2480
|
+
except requests.exceptions.ConnectionError:
|
2481
|
+
print(f"โ Connection error: Could not connect to {api_url}")
|
2482
|
+
print("โ ๏ธ Using fallback commands instead")
|
2483
|
+
# Return fallback commands
|
2484
|
+
return generate_fallback_commands(gitingest_data)
|
2433
2485
|
except Exception as e:
|
2434
2486
|
print(f"โ Error fetching setup commands from API: {e}")
|
2435
2487
|
import traceback
|
2436
2488
|
traceback.print_exc()
|
2437
|
-
|
2489
|
+
# Return fallback commands
|
2490
|
+
return generate_fallback_commands(None)
|
2438
2491
|
finally:
|
2439
2492
|
# Clean up the temporary directory
|
2440
2493
|
print(f"๐งน Cleaning up temporary directory...")
|
2441
2494
|
shutil.rmtree(temp_dir, ignore_errors=True)
|
2442
2495
|
|
2496
|
+
def generate_fallback_commands(gitingest_data):
|
2497
|
+
"""Generate fallback setup commands based on repository analysis"""
|
2498
|
+
print("\n" + "="*80)
|
2499
|
+
print("๐ GENERATING FALLBACK SETUP COMMANDS")
|
2500
|
+
print("="*80)
|
2501
|
+
print("Using basic repository analysis to generate setup commands")
|
2502
|
+
|
2503
|
+
# Default commands that work for most repositories
|
2504
|
+
default_commands = [
|
2505
|
+
"apt-get update -y",
|
2506
|
+
"apt-get install -y git curl wget",
|
2507
|
+
"pip install --upgrade pip setuptools wheel"
|
2508
|
+
]
|
2509
|
+
|
2510
|
+
# If we don't have any analysis data, return default commands
|
2511
|
+
if not gitingest_data:
|
2512
|
+
print("โ ๏ธ No repository analysis data available. Using default commands.")
|
2513
|
+
return default_commands
|
2514
|
+
|
2515
|
+
# Extract language and technologies information
|
2516
|
+
detected_language = gitingest_data.get("system_info", {}).get("detected_language", "Unknown")
|
2517
|
+
detected_technologies = gitingest_data.get("system_info", {}).get("detected_technologies", [])
|
2518
|
+
primary_package_manager = gitingest_data.get("system_info", {}).get("primary_package_manager", "Unknown")
|
2519
|
+
|
2520
|
+
# Add language-specific commands
|
2521
|
+
language_commands = []
|
2522
|
+
|
2523
|
+
print(f"๐ Detected primary language: {detected_language}")
|
2524
|
+
print(f"๐ Detected technologies: {', '.join(detected_technologies) if detected_technologies else 'None'}")
|
2525
|
+
print(f"๐ Detected package manager: {primary_package_manager}")
|
2526
|
+
|
2527
|
+
# Python-specific commands
|
2528
|
+
if detected_language == "Python" or primary_package_manager == "pip":
|
2529
|
+
print("๐ฆ Adding Python-specific setup commands")
|
2530
|
+
|
2531
|
+
# Check for requirements.txt
|
2532
|
+
requirements_check = [
|
2533
|
+
"if [ -f requirements.txt ]; then",
|
2534
|
+
" echo 'Installing from requirements.txt'",
|
2535
|
+
" pip install -r requirements.txt",
|
2536
|
+
"elif [ -f setup.py ]; then",
|
2537
|
+
" echo 'Installing from setup.py'",
|
2538
|
+
" pip install -e .",
|
2539
|
+
"fi"
|
2540
|
+
]
|
2541
|
+
language_commands.extend(requirements_check)
|
2542
|
+
|
2543
|
+
# Add common Python packages
|
2544
|
+
language_commands.append("pip install pytest numpy pandas matplotlib")
|
2545
|
+
|
2546
|
+
# JavaScript/Node.js specific commands
|
2547
|
+
elif detected_language in ["JavaScript", "TypeScript"] or primary_package_manager in ["npm", "yarn", "pnpm"]:
|
2548
|
+
print("๐ฆ Adding JavaScript/Node.js-specific setup commands")
|
2549
|
+
|
2550
|
+
# Install Node.js if not available
|
2551
|
+
language_commands.append("apt-get install -y nodejs npm")
|
2552
|
+
|
2553
|
+
# Check for package.json
|
2554
|
+
package_json_check = [
|
2555
|
+
"if [ -f package.json ]; then",
|
2556
|
+
" echo 'Installing from package.json'",
|
2557
|
+
" npm install",
|
2558
|
+
"fi"
|
2559
|
+
]
|
2560
|
+
language_commands.extend(package_json_check)
|
2561
|
+
|
2562
|
+
# Java specific commands
|
2563
|
+
elif detected_language == "Java" or primary_package_manager in ["maven", "gradle"]:
|
2564
|
+
print("๐ฆ Adding Java-specific setup commands")
|
2565
|
+
|
2566
|
+
language_commands.append("apt-get install -y openjdk-11-jdk maven gradle")
|
2567
|
+
|
2568
|
+
# Check for Maven or Gradle
|
2569
|
+
build_check = [
|
2570
|
+
"if [ -f pom.xml ]; then",
|
2571
|
+
" echo 'Building with Maven'",
|
2572
|
+
" mvn clean install -DskipTests",
|
2573
|
+
"elif [ -f build.gradle ]; then",
|
2574
|
+
" echo 'Building with Gradle'",
|
2575
|
+
" gradle build --no-daemon",
|
2576
|
+
"fi"
|
2577
|
+
]
|
2578
|
+
language_commands.extend(build_check)
|
2579
|
+
|
2580
|
+
# Go specific commands
|
2581
|
+
elif detected_language == "Go" or primary_package_manager == "go":
|
2582
|
+
print("๐ฆ Adding Go-specific setup commands")
|
2583
|
+
|
2584
|
+
language_commands.append("apt-get install -y golang-go")
|
2585
|
+
language_commands.append("go mod tidy")
|
2586
|
+
|
2587
|
+
# Rust specific commands
|
2588
|
+
elif detected_language == "Rust" or primary_package_manager == "cargo":
|
2589
|
+
print("๐ฆ Adding Rust-specific setup commands")
|
2590
|
+
|
2591
|
+
language_commands.append("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y")
|
2592
|
+
language_commands.append("source $HOME/.cargo/env")
|
2593
|
+
language_commands.append("cargo build")
|
2594
|
+
|
2595
|
+
# Combine all commands
|
2596
|
+
all_commands = default_commands + language_commands
|
2597
|
+
|
2598
|
+
print("\n๐ Generated fallback setup commands:")
|
2599
|
+
for i, cmd in enumerate(all_commands, 1):
|
2600
|
+
print(f" {i}. {cmd}")
|
2601
|
+
|
2602
|
+
return all_commands
|
2603
|
+
|
2443
2604
|
def generate_basic_repo_analysis_from_url(repo_url):
|
2444
2605
|
"""Generate basic repository analysis data from a repository URL."""
|
2445
2606
|
import tempfile
|