skypilot-nightly 1.0.0.dev20250716__py3-none-any.whl → 1.0.0.dev20250717__py3-none-any.whl

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 (51) hide show
  1. sky/__init__.py +4 -2
  2. sky/backends/backend.py +8 -4
  3. sky/backends/cloud_vm_ray_backend.py +50 -1
  4. sky/backends/docker_utils.py +1 -1
  5. sky/backends/local_docker_backend.py +2 -1
  6. sky/catalog/common.py +60 -50
  7. sky/catalog/data_fetchers/fetch_gcp.py +1 -0
  8. sky/catalog/gcp_catalog.py +24 -7
  9. sky/catalog/kubernetes_catalog.py +5 -1
  10. sky/client/cli/command.py +180 -77
  11. sky/client/cli/git.py +549 -0
  12. sky/client/common.py +1 -1
  13. sky/clouds/gcp.py +1 -1
  14. sky/dashboard/out/404.html +1 -1
  15. sky/dashboard/out/_next/static/chunks/4869.bdd42f14b51d1d6f.js +16 -0
  16. sky/dashboard/out/_next/static/chunks/{webpack-3fad5d4a0541a02d.js → webpack-c3b45b7b0eaef66f.js} +1 -1
  17. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  18. sky/dashboard/out/clusters/[cluster].html +1 -1
  19. sky/dashboard/out/clusters.html +1 -1
  20. sky/dashboard/out/config.html +1 -1
  21. sky/dashboard/out/index.html +1 -1
  22. sky/dashboard/out/infra/[context].html +1 -1
  23. sky/dashboard/out/infra.html +1 -1
  24. sky/dashboard/out/jobs/[job].html +1 -1
  25. sky/dashboard/out/jobs.html +1 -1
  26. sky/dashboard/out/users.html +1 -1
  27. sky/dashboard/out/volumes.html +1 -1
  28. sky/dashboard/out/workspace/new.html +1 -1
  29. sky/dashboard/out/workspaces/[name].html +1 -1
  30. sky/dashboard/out/workspaces.html +1 -1
  31. sky/exceptions.py +5 -0
  32. sky/execution.py +1 -1
  33. sky/provision/kubernetes/utils.py +6 -0
  34. sky/server/common.py +4 -3
  35. sky/setup_files/MANIFEST.in +1 -0
  36. sky/setup_files/dependencies.py +2 -0
  37. sky/task.py +12 -2
  38. sky/utils/command_runner.py +144 -35
  39. sky/utils/controller_utils.py +4 -3
  40. sky/utils/git.py +9 -0
  41. sky/utils/git_clone.sh +460 -0
  42. sky/utils/schemas.py +15 -1
  43. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250717.dist-info}/METADATA +3 -1
  44. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250717.dist-info}/RECORD +50 -47
  45. sky/dashboard/out/_next/static/chunks/4869.c139c0124e677fc8.js +0 -16
  46. /sky/dashboard/out/_next/static/{gVXjeFhvtWXyOsx9xYNvM → Et5IQ5Y3WvH608nXClo4z}/_buildManifest.js +0 -0
  47. /sky/dashboard/out/_next/static/{gVXjeFhvtWXyOsx9xYNvM → Et5IQ5Y3WvH608nXClo4z}/_ssgManifest.js +0 -0
  48. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250717.dist-info}/WHEEL +0 -0
  49. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250717.dist-info}/entry_points.txt +0 -0
  50. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250717.dist-info}/licenses/LICENSE +0 -0
  51. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250717.dist-info}/top_level.txt +0 -0
sky/utils/git.py ADDED
@@ -0,0 +1,9 @@
1
+ """Git related constants."""
2
+
3
+ GIT_TOKEN_ENV_VAR = 'GIT_TOKEN'
4
+ GIT_SSH_KEY_PATH_ENV_VAR = 'GIT_SSH_KEY_PATH'
5
+ GIT_SSH_KEY_ENV_VAR = 'GIT_SSH_KEY'
6
+ GIT_URL_ENV_VAR = 'GIT_URL'
7
+ GIT_COMMIT_HASH_ENV_VAR = 'GIT_COMMIT_HASH'
8
+ GIT_BRANCH_ENV_VAR = 'GIT_BRANCH'
9
+ GIT_TAG_ENV_VAR = 'GIT_TAG'
sky/utils/git_clone.sh ADDED
@@ -0,0 +1,460 @@
1
+ #!/bin/bash
2
+
3
+ # Git clone script for SkyPilot remote clusters
4
+ # This script handles Git repository cloning with authentication and different ref types
5
+
6
+ set -e # Exit on any error
7
+
8
+ # Function to log messages
9
+ log() {
10
+ echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >&2
11
+ }
12
+
13
+ # Function to check and install Git if not present
14
+ check_and_install_git() {
15
+ # Check if git is already installed
16
+ if command -v git >/dev/null 2>&1; then
17
+ log "Git is already installed: $(git --version)"
18
+ return 0
19
+ fi
20
+
21
+ log "Git not found, attempting to install..."
22
+
23
+ # Function to try installing with error handling
24
+ install_with_error_handling() {
25
+ local cmd_with_sudo="$1"
26
+ local cmd_without_sudo="$2"
27
+ local pkg_manager="$3"
28
+
29
+ log "Trying to install Git using $pkg_manager..."
30
+
31
+ # First, try with sudo
32
+ log "Attempting with sudo..."
33
+ if eval "$cmd_with_sudo" 2>&1 >/tmp/git_install.log; then
34
+ log "Installation with sudo completed successfully"
35
+ rm -f /tmp/git_install.log
36
+ return 0
37
+ else
38
+ log "Installation with sudo failed, trying without sudo..."
39
+ cat /tmp/git_install.log >&2
40
+ rm -f /tmp/git_install.log
41
+ fi
42
+
43
+ # If sudo failed, try without sudo
44
+ log "Attempting without sudo..."
45
+ if eval "$cmd_without_sudo" 2>&1 >/tmp/git_install.log; then
46
+ log "Installation without sudo completed successfully"
47
+ rm -f /tmp/git_install.log
48
+ return 0
49
+ else
50
+ log "Installation failed. Error output:"
51
+ cat /tmp/git_install.log >&2
52
+
53
+ # Check for common error patterns
54
+ if grep -q -i "permission\|denied\|unauthorized" /tmp/git_install.log; then
55
+ log "ERROR: Installation failed due to permission issues"
56
+ log "Current user: $(whoami), UID: $(id -u)"
57
+ log "Try running this script as root or with appropriate permissions"
58
+ elif grep -q -i "command not found\|not found" /tmp/git_install.log; then
59
+ log "ERROR: Package manager command not found"
60
+ log "Please install Git manually using your system's package manager"
61
+ fi
62
+
63
+ rm -f /tmp/git_install.log
64
+ return 1
65
+ fi
66
+ }
67
+
68
+ # Detect the operating system and package manager
69
+ if [ -f /etc/debian_version ]; then
70
+ # Debian/Ubuntu
71
+ log "Detected Debian/Ubuntu system"
72
+ if command -v apt-get >/dev/null 2>&1; then
73
+ install_with_error_handling "sudo apt-get update -y && sudo apt-get install -y git" "apt-get update -y && apt-get install -y git" "apt-get"
74
+ elif command -v apt >/dev/null 2>&1; then
75
+ install_with_error_handling "sudo apt update -y && sudo apt install -y git" "apt update -y && apt install -y git" "apt"
76
+ else
77
+ log "ERROR: Neither apt-get nor apt found on Debian/Ubuntu system"
78
+ return 1
79
+ fi
80
+ elif [ -f /etc/redhat-release ] || [ -f /etc/centos-release ]; then
81
+ # Red Hat/CentOS/Fedora
82
+ log "Detected Red Hat/CentOS/Fedora system"
83
+ if command -v dnf >/dev/null 2>&1; then
84
+ install_with_error_handling "sudo dnf install -y git" "dnf install -y git" "dnf"
85
+ elif command -v yum >/dev/null 2>&1; then
86
+ install_with_error_handling "sudo yum install -y git" "yum install -y git" "yum"
87
+ else
88
+ log "ERROR: Neither dnf nor yum found on Red Hat/CentOS/Fedora system"
89
+ return 1
90
+ fi
91
+ elif [ -f /etc/arch-release ]; then
92
+ # Arch Linux
93
+ log "Detected Arch Linux system"
94
+ if command -v pacman >/dev/null 2>&1; then
95
+ install_with_error_handling "sudo pacman -S --noconfirm git" "pacman -S --noconfirm git" "pacman"
96
+ else
97
+ log "ERROR: pacman not found on Arch Linux system"
98
+ return 1
99
+ fi
100
+ elif [ -f /etc/alpine-release ]; then
101
+ # Alpine Linux
102
+ log "Detected Alpine Linux system"
103
+ if command -v apk >/dev/null 2>&1; then
104
+ install_with_error_handling "sudo apk add --no-cache git" "apk add --no-cache git" "apk"
105
+ else
106
+ log "ERROR: apk not found on Alpine Linux system"
107
+ return 1
108
+ fi
109
+ elif [ "$(uname)" = "Darwin" ]; then
110
+ # macOS
111
+ log "Detected macOS system"
112
+ if command -v brew >/dev/null 2>&1; then
113
+ install_with_error_handling "brew install git" "brew install git" "Homebrew"
114
+ elif command -v port >/dev/null 2>&1; then
115
+ install_with_error_handling "sudo port install git" "port install git" "MacPorts"
116
+ else
117
+ log "ERROR: Neither Homebrew nor MacPorts found on macOS"
118
+ log "Please install Git manually: https://git-scm.com/download/mac"
119
+ return 1
120
+ fi
121
+ else
122
+ log "ERROR: Unsupported operating system: $(uname -s)"
123
+ log "Please install Git manually: https://git-scm.com/downloads"
124
+ return 1
125
+ fi
126
+
127
+ # Verify installation
128
+ if command -v git >/dev/null 2>&1; then
129
+ log "Git successfully installed: $(git --version)"
130
+ return 0
131
+ else
132
+ log "ERROR: Git installation failed or Git is not in PATH"
133
+ log "Please install Git manually and ensure it's in your PATH"
134
+ return 1
135
+ fi
136
+ }
137
+
138
+ # Function to cleanup temporary files
139
+ cleanup() {
140
+ if [ -n "$SSH_KEY_FILE" ] && [ -f "$SSH_KEY_FILE" ]; then
141
+ log "Cleaning up temporary SSH key file"
142
+ rm -f "$SSH_KEY_FILE"
143
+ fi
144
+ }
145
+
146
+ # Function to normalize Git URL for comparison and extract schema
147
+ # Note: URLs from GitRepo are already standardized as HTTPS or SSH format
148
+ # Returns: "normalized_url schema"
149
+ normalize_git_url() {
150
+ local url="$1"
151
+ local schema=""
152
+
153
+ # Remove trailing .git and /
154
+ url=$(echo "$url" | sed 's|\.git/*$||' | sed 's|/*$||')
155
+
156
+ # Convert standardized formats to host/path for comparison and extract schema
157
+ if [[ "$url" =~ ^ssh://([^@]+@)?([^:/]+)(:([0-9]+))?/(.+)$ ]]; then
158
+ # SSH standard format: ssh://user@host:port/path -> host/path
159
+ local host="${BASH_REMATCH[2]}"
160
+ local path="${BASH_REMATCH[5]}"
161
+ schema="ssh"
162
+ echo "$host/$path $schema"
163
+ elif [[ "$url" =~ ^https?://([^@]*@)?([^:/]+)(:([0-9]+))?/(.+)$ ]]; then
164
+ # HTTPS format: https://token@host:port/path -> host/path
165
+ local host="${BASH_REMATCH[2]}"
166
+ local path="${BASH_REMATCH[5]}"
167
+ schema="https"
168
+ echo "$host/$path $schema"
169
+ else
170
+ # Fallback: return as-is (shouldn't happen with standardized URLs)
171
+ schema="unknown"
172
+ echo "$url $schema"
173
+ fi
174
+ }
175
+
176
+ # Set up cleanup trap
177
+ trap cleanup EXIT
178
+
179
+ # Check if target directory is provided
180
+ if [ -z "$1" ]; then
181
+ log "ERROR: Target directory not provided"
182
+ echo "Usage: $0 <target_directory>"
183
+ exit 1
184
+ fi
185
+
186
+ TARGET_DIR="$1"
187
+ log "Target directory: $TARGET_DIR"
188
+
189
+ # Check if GIT_URL is provided
190
+ if [ -z "$GIT_URL" ]; then
191
+ log "GIT_URL environment variable not set, skipping git clone"
192
+ exit 0
193
+ fi
194
+
195
+ log "Git URL: $GIT_URL"
196
+
197
+ # Check and install Git if not present
198
+ if ! check_and_install_git; then
199
+ log "ERROR: Failed to ensure Git is installed"
200
+ exit 1
201
+ fi
202
+
203
+ # Setup SSH key if provided
204
+ SSH_KEY_FILE=""
205
+ if [ -n "$GIT_SSH_KEY" ]; then
206
+ log "Setting up SSH key authentication"
207
+ SSH_KEY_FILE=$(mktemp)
208
+ echo "$GIT_SSH_KEY" > "$SSH_KEY_FILE"
209
+ chmod 600 "$SSH_KEY_FILE"
210
+
211
+ # Setup Git SSH command
212
+ export GIT_SSH_COMMAND="ssh -i $SSH_KEY_FILE -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null -o IdentitiesOnly=yes"
213
+ log "SSH key written to temporary file: $SSH_KEY_FILE"
214
+ fi
215
+
216
+ # Setup token authentication if provided
217
+ CLONE_URL="$GIT_URL"
218
+ if [ -n "$GIT_TOKEN" ]; then
219
+ log "Setting up token authentication"
220
+ if [[ "$GIT_URL" =~ ^https://(.*)$ ]]; then
221
+ # For container environments, directly embed token in URL for reliability
222
+ # This is simpler and more reliable than credential helper in containers
223
+ CLONE_URL="https://${GIT_TOKEN}@${BASH_REMATCH[1]}"
224
+ log "Token authentication configured via URL embedding"
225
+ else
226
+ log "WARNING: GIT_TOKEN provided but URL is not HTTPS, ignoring token"
227
+ fi
228
+ fi
229
+
230
+ # Determine reference type and clone strategy
231
+ REF_TYPE=""
232
+ REF_VALUE=""
233
+ CLONE_ARGS=""
234
+
235
+ if [ -n "$GIT_BRANCH" ]; then
236
+ REF_TYPE="branch"
237
+ REF_VALUE="$GIT_BRANCH"
238
+ CLONE_ARGS="--depth 1 --branch $GIT_BRANCH"
239
+ log "Using branch: $GIT_BRANCH (shallow clone)"
240
+ elif [ -n "$GIT_TAG" ]; then
241
+ REF_TYPE="tag"
242
+ REF_VALUE="$GIT_TAG"
243
+ CLONE_ARGS="--depth 1 --branch $GIT_TAG"
244
+ log "Using tag: $GIT_TAG (shallow clone)"
245
+ elif [ -n "$GIT_COMMIT_HASH" ]; then
246
+ REF_TYPE="commit"
247
+ REF_VALUE="$GIT_COMMIT_HASH"
248
+ # For commit hash, we need full clone first, then checkout
249
+ CLONE_ARGS=""
250
+ log "Using commit hash: $GIT_COMMIT_HASH (full clone required)"
251
+ else
252
+ # Use git default behavior to clone the default branch
253
+ REF_TYPE="default"
254
+ # Get the remote default branch name before cloning
255
+ log "Determining remote default branch..."
256
+ if REF_VALUE=$(git ls-remote --symref "$CLONE_URL" HEAD 2>/dev/null | grep '^ref:' | sed 's/^ref: refs\/heads\///' | awk '{print $1}' | head -1); then
257
+ if [ -n "$REF_VALUE" ]; then
258
+ CLONE_ARGS="--depth 1 --branch $REF_VALUE"
259
+ log "Remote default branch: $REF_VALUE (shallow clone)"
260
+ else
261
+ REF_VALUE="" # Will be determined after clone
262
+ CLONE_ARGS="--depth 1"
263
+ log "Could not determine remote default branch, using git default behavior"
264
+ fi
265
+ else
266
+ REF_VALUE="" # Will be determined after clone
267
+ CLONE_ARGS="--depth 1"
268
+ log "Could not query remote, using git default behavior"
269
+ fi
270
+ fi
271
+
272
+ # Check if target directory already exists and has git repository
273
+ if [ -d "$TARGET_DIR" ]; then
274
+ if [ -d "$TARGET_DIR/.git" ]; then
275
+ log "Git repository already exists, updating..."
276
+ cd "$TARGET_DIR"
277
+
278
+ # Verify this is the same repository
279
+ CURRENT_REMOTE=$(git remote get-url origin 2>/dev/null || echo "")
280
+ if [ -n "$CURRENT_REMOTE" ]; then
281
+ # Normalize URLs for comparison (handles HTTPS, SSH formats)
282
+ CURRENT_RESULT=$(normalize_git_url "$CURRENT_REMOTE")
283
+ TARGET_RESULT=$(normalize_git_url "$GIT_URL")
284
+
285
+ # Extract normalized URL and schema
286
+ CURRENT_CLEAN=$(echo "$CURRENT_RESULT" | cut -d' ' -f1)
287
+ CURRENT_SCHEMA=$(echo "$CURRENT_RESULT" | cut -d' ' -f2)
288
+ TARGET_CLEAN=$(echo "$TARGET_RESULT" | cut -d' ' -f1)
289
+ TARGET_SCHEMA=$(echo "$TARGET_RESULT" | cut -d' ' -f2)
290
+
291
+ if [ "$CURRENT_CLEAN" != "$TARGET_CLEAN" ]; then
292
+ log "WARNING: Existing repository has different remote URL"
293
+ log "Current: $CURRENT_REMOTE -> $CURRENT_CLEAN ($CURRENT_SCHEMA)"
294
+ log "Target: $GIT_URL -> $TARGET_CLEAN ($TARGET_SCHEMA)"
295
+ log "Please manually remove the directory or use a different target directory."
296
+ exit 1
297
+ elif [ "$CURRENT_SCHEMA" != "$TARGET_SCHEMA" ]; then
298
+ # Same repository but different schema (HTTPS vs SSH)
299
+ log "Repository matches but schema differs"
300
+ log "Current: $CURRENT_REMOTE ($CURRENT_SCHEMA)"
301
+ log "Target: $GIT_URL ($TARGET_SCHEMA)"
302
+ log "Updating remote URL to match authentication method"
303
+ git remote set-url origin "$CLONE_URL"
304
+ log "Remote URL updated successfully"
305
+ NEED_CLONE=false
306
+ else
307
+ log "Repository remote URL matches exactly, fetching updates"
308
+ NEED_CLONE=false
309
+ fi
310
+ else
311
+ log "Cannot determine remote URL, assuming repository needs update"
312
+ NEED_CLONE=false
313
+ fi
314
+ else
315
+ log "Directory exists but is not a git repository"
316
+ cd "$TARGET_DIR"
317
+ NEED_CLONE=true
318
+ fi
319
+ else
320
+ log "Creating target directory: $TARGET_DIR"
321
+ mkdir -p "$TARGET_DIR"
322
+ cd "$TARGET_DIR"
323
+ NEED_CLONE=true
324
+ fi
325
+
326
+ # Clone or update repository
327
+ if [ "$NEED_CLONE" = true ]; then
328
+ log "Cloning repository..."
329
+ if [ "$REF_TYPE" = "commit" ]; then
330
+ # Clone full repository for commit hash
331
+ git clone "$CLONE_URL" .
332
+ log "Successfully cloned repository"
333
+ else
334
+ # Clone with appropriate arguments (branch-specific, tag-specific, or default)
335
+ git clone $CLONE_ARGS "$CLONE_URL" .
336
+ if [ "$REF_TYPE" = "branch" ]; then
337
+ log "Successfully cloned branch: $REF_VALUE"
338
+ elif [ "$REF_TYPE" = "tag" ]; then
339
+ log "Successfully cloned tag: $REF_VALUE"
340
+ else
341
+ # Determine the actual default branch name (if not already known)
342
+ if [ -z "$REF_VALUE" ]; then
343
+ REF_VALUE=$(git branch --show-current)
344
+ fi
345
+ log "Successfully cloned default branch: $REF_VALUE"
346
+ fi
347
+ fi
348
+ else
349
+ # Update existing repository
350
+ log "Fetching updates..."
351
+
352
+ if [ "$REF_TYPE" = "commit" ]; then
353
+ # For commit hash, we need to fetch all refs
354
+ # Check if this is a shallow repository
355
+ if [ -f ".git/shallow" ]; then
356
+ log "Detected shallow repository, converting to full clone for commit access"
357
+ git fetch --unshallow
358
+ else
359
+ git fetch origin
360
+ fi
361
+ elif [ "$REF_TYPE" = "tag" ]; then
362
+ # For specific tag, fetch that tag
363
+ if ! git fetch origin "+refs/tags/$REF_VALUE:refs/tags/$REF_VALUE"; then
364
+ log "ERROR: Failed to fetch tag '$REF_VALUE' from remote"
365
+ log "This could mean:"
366
+ log " 1. Remote tag '$REF_VALUE' does not exist"
367
+ log " 2. Network connectivity issues"
368
+ log " 3. Authentication problems"
369
+ log "Checking available remote tags..."
370
+ git ls-remote --tags origin | sed 's/.*refs\/tags\// - /' || true
371
+ exit 1
372
+ fi
373
+ elif [ "$REF_TYPE" = "default" ]; then
374
+ # For default branch, get current branch and fetch it (if not already known)
375
+ if [ -z "$REF_VALUE" ]; then
376
+ REF_VALUE=$(git branch --show-current)
377
+ fi
378
+ log "Current default branch: $REF_VALUE"
379
+ if ! git fetch origin "+refs/heads/$REF_VALUE:refs/remotes/origin/$REF_VALUE"; then
380
+ log "ERROR: Failed to fetch default branch '$REF_VALUE' from remote"
381
+ log "This could mean the remote branch no longer exists"
382
+ exit 1
383
+ fi
384
+ else
385
+ # For specific branch, fetch that branch and create remote tracking branch
386
+ if ! git fetch origin "+refs/heads/$REF_VALUE:refs/remotes/origin/$REF_VALUE"; then
387
+ log "ERROR: Failed to fetch branch '$REF_VALUE' from remote"
388
+ log "This could mean:"
389
+ log " 1. Remote branch '$REF_VALUE' does not exist"
390
+ log " 2. Network connectivity issues"
391
+ log " 3. Authentication problems"
392
+ log "Checking available remote branches..."
393
+ git ls-remote --heads origin | sed 's/.*refs\/heads\// - /' || true
394
+ exit 1
395
+ fi
396
+ fi
397
+ log "Successfully fetched updates"
398
+ fi
399
+
400
+ # Checkout the desired reference
401
+ if [ "$REF_TYPE" = "commit" ]; then
402
+ # Checkout specific commit
403
+ log "Checking out commit: $REF_VALUE"
404
+ if ! git checkout "$REF_VALUE"; then
405
+ log "ERROR: Failed to checkout commit '$REF_VALUE'"
406
+ log "This could mean:"
407
+ log " 1. The commit hash does not exist in the repository"
408
+ log " 2. The commit hash is incomplete or invalid"
409
+ log " 3. The repository may still be missing some history"
410
+ log "Try providing a longer commit hash or ensure the commit exists"
411
+ exit 1
412
+ fi
413
+ log "Successfully checked out commit: $REF_VALUE"
414
+ elif [ "$REF_TYPE" = "tag" ]; then
415
+ # Checkout specific tag
416
+ log "Checking out tag: $REF_VALUE"
417
+ if ! git checkout "$REF_VALUE"; then
418
+ log "ERROR: Failed to checkout tag '$REF_VALUE'"
419
+ log "This could mean:"
420
+ log " 1. The tag '$REF_VALUE' does not exist in the repository"
421
+ log " 2. The tag name is invalid"
422
+ log " 3. Local repository is in an inconsistent state"
423
+ exit 1
424
+ fi
425
+ log "Successfully checked out tag: $REF_VALUE"
426
+ else
427
+ # Checkout specific branch
428
+ log "Checking out branch: $REF_VALUE"
429
+ if git checkout "$REF_VALUE" 2>/dev/null; then
430
+ log "Switched to existing local branch: $REF_VALUE"
431
+ elif git checkout -b "$REF_VALUE" "origin/$REF_VALUE" 2>/dev/null; then
432
+ log "Created new local branch tracking origin/$REF_VALUE"
433
+ else
434
+ log "ERROR: Failed to checkout branch '$REF_VALUE'"
435
+ log "This could mean:"
436
+ log " 1. Remote branch 'origin/$REF_VALUE' does not exist"
437
+ log " 2. Local repository is in an inconsistent state"
438
+ exit 1
439
+ fi
440
+
441
+ # Ensure we're on the latest commit of the branch
442
+ if [ "$NEED_CLONE" != true ]; then
443
+ git reset --hard "origin/$REF_VALUE"
444
+ fi
445
+ log "Successfully checked out branch: $REF_VALUE"
446
+ fi
447
+
448
+ # Verify final state
449
+ CURRENT_REF=$(git rev-parse HEAD)
450
+ log "Repository is now at commit: $CURRENT_REF"
451
+
452
+ if [ "$REF_TYPE" = "branch" ] || [ "$REF_TYPE" = "default" ]; then
453
+ CURRENT_BRANCH=$(git branch --show-current 2>/dev/null || echo "detached")
454
+ log "Current branch: $CURRENT_BRANCH"
455
+ elif [ "$REF_TYPE" = "tag" ]; then
456
+ CURRENT_TAG=$(git describe --tags --exact-match 2>/dev/null || echo "unknown")
457
+ log "Current tag: $CURRENT_TAG"
458
+ fi
459
+
460
+ log "Git clone/update completed successfully"
sky/utils/schemas.py CHANGED
@@ -791,7 +791,21 @@ def get_task_schema():
791
791
  'type': 'string',
792
792
  },
793
793
  'workdir': {
794
- 'type': 'string',
794
+ 'anyOf': [{
795
+ 'type': 'string',
796
+ }, {
797
+ 'type': 'object',
798
+ 'required': ['url'],
799
+ 'additionalProperties': False,
800
+ 'properties': {
801
+ 'url': {
802
+ 'type': 'string',
803
+ },
804
+ 'ref': {
805
+ 'type': 'string',
806
+ },
807
+ },
808
+ }],
795
809
  },
796
810
  'event_callback': {
797
811
  'type': 'string',
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skypilot-nightly
3
- Version: 1.0.0.dev20250716
3
+ Version: 1.0.0.dev20250717
4
4
  Summary: SkyPilot: Run AI on Any Infra — Unified, Faster, Cheaper.
5
5
  Author: SkyPilot Team
6
6
  License: Apache 2.0
@@ -54,6 +54,8 @@ Requires-Dist: sqlalchemy_adapter
54
54
  Requires-Dist: prometheus_client>=0.8.0
55
55
  Requires-Dist: passlib
56
56
  Requires-Dist: pyjwt
57
+ Requires-Dist: gitpython
58
+ Requires-Dist: types-paramiko
57
59
  Provides-Extra: aws
58
60
  Requires-Dist: awscli>=1.27.10; extra == "aws"
59
61
  Requires-Dist: botocore>=1.29.10; extra == "aws"