skypilot-nightly 1.0.0.dev20250716__py3-none-any.whl → 1.0.0.dev20250718__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 (65) 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/client/sdk.py +1 -1
  14. sky/clouds/gcp.py +1 -1
  15. sky/dashboard/out/404.html +1 -1
  16. sky/dashboard/out/_next/static/{gVXjeFhvtWXyOsx9xYNvM → FUjweqdImyeYhMYFON-Se}/_buildManifest.js +1 -1
  17. sky/dashboard/out/_next/static/chunks/1043-734e57d2b27dfe5d.js +1 -0
  18. sky/dashboard/out/_next/static/chunks/4869.bdd42f14b51d1d6f.js +16 -0
  19. sky/dashboard/out/_next/static/chunks/8969-8e0b2055bf5dd499.js +1 -0
  20. sky/dashboard/out/_next/static/chunks/{9984.b56614f3c4c5961d.js → 9984.2b5e3fa69171bff9.js} +1 -1
  21. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-fa406155b4223d0d.js +11 -0
  22. sky/dashboard/out/_next/static/chunks/pages/jobs/{[job]-14d404b7dd28502a.js → [job]-c5b357bfd9502fbe.js} +1 -1
  23. sky/dashboard/out/_next/static/chunks/webpack-6b0575ea521af4f3.js +1 -0
  24. sky/dashboard/out/clusters/[cluster]/[job].html +1 -1
  25. sky/dashboard/out/clusters/[cluster].html +1 -1
  26. sky/dashboard/out/clusters.html +1 -1
  27. sky/dashboard/out/config.html +1 -1
  28. sky/dashboard/out/index.html +1 -1
  29. sky/dashboard/out/infra/[context].html +1 -1
  30. sky/dashboard/out/infra.html +1 -1
  31. sky/dashboard/out/jobs/[job].html +1 -1
  32. sky/dashboard/out/jobs.html +1 -1
  33. sky/dashboard/out/users.html +1 -1
  34. sky/dashboard/out/volumes.html +1 -1
  35. sky/dashboard/out/workspace/new.html +1 -1
  36. sky/dashboard/out/workspaces/[name].html +1 -1
  37. sky/dashboard/out/workspaces.html +1 -1
  38. sky/exceptions.py +5 -0
  39. sky/execution.py +1 -1
  40. sky/jobs/client/sdk.py +1 -1
  41. sky/jobs/server/core.py +14 -0
  42. sky/provision/kubernetes/utils.py +6 -0
  43. sky/serve/client/sdk.py +1 -1
  44. sky/server/common.py +8 -3
  45. sky/server/rest.py +71 -26
  46. sky/setup_files/MANIFEST.in +1 -0
  47. sky/setup_files/dependencies.py +2 -0
  48. sky/task.py +12 -2
  49. sky/utils/command_runner.py +144 -35
  50. sky/utils/controller_utils.py +4 -3
  51. sky/utils/git.py +9 -0
  52. sky/utils/git_clone.sh +460 -0
  53. sky/utils/schemas.py +15 -1
  54. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250718.dist-info}/METADATA +3 -1
  55. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250718.dist-info}/RECORD +60 -57
  56. sky/dashboard/out/_next/static/chunks/1043-90a88c46f27b3df5.js +0 -1
  57. sky/dashboard/out/_next/static/chunks/4869.c139c0124e677fc8.js +0 -16
  58. sky/dashboard/out/_next/static/chunks/8969-743abf4bc86baf48.js +0 -1
  59. sky/dashboard/out/_next/static/chunks/pages/clusters/[cluster]/[job]-9096ea50b8e2cf9e.js +0 -6
  60. sky/dashboard/out/_next/static/chunks/webpack-3fad5d4a0541a02d.js +0 -1
  61. /sky/dashboard/out/_next/static/{gVXjeFhvtWXyOsx9xYNvM → FUjweqdImyeYhMYFON-Se}/_ssgManifest.js +0 -0
  62. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250718.dist-info}/WHEEL +0 -0
  63. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250718.dist-info}/entry_points.txt +0 -0
  64. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250718.dist-info}/licenses/LICENSE +0 -0
  65. {skypilot_nightly-1.0.0.dev20250716.dist-info → skypilot_nightly-1.0.0.dev20250718.dist-info}/top_level.txt +0 -0
sky/client/cli/command.py CHANGED
@@ -55,6 +55,7 @@ from sky import skypilot_config
55
55
  from sky.adaptors import common as adaptors_common
56
56
  from sky.client import sdk
57
57
  from sky.client.cli import flags
58
+ from sky.client.cli import git
58
59
  from sky.data import storage_utils
59
60
  from sky.provision.kubernetes import constants as kubernetes_constants
60
61
  from sky.provision.kubernetes import utils as kubernetes_utils
@@ -71,6 +72,7 @@ from sky.utils import common_utils
71
72
  from sky.utils import controller_utils
72
73
  from sky.utils import dag_utils
73
74
  from sky.utils import env_options
75
+ from sky.utils import git as git_utils
74
76
  from sky.utils import infra_utils
75
77
  from sky.utils import log_utils
76
78
  from sky.utils import registry
@@ -467,20 +469,21 @@ def _add_click_options(options: List[click.Option]):
467
469
 
468
470
 
469
471
  def _parse_override_params(
470
- cloud: Optional[str] = None,
471
- region: Optional[str] = None,
472
- zone: Optional[str] = None,
473
- gpus: Optional[str] = None,
474
- cpus: Optional[str] = None,
475
- memory: Optional[str] = None,
476
- instance_type: Optional[str] = None,
477
- use_spot: Optional[bool] = None,
478
- image_id: Optional[str] = None,
479
- disk_size: Optional[int] = None,
480
- disk_tier: Optional[str] = None,
481
- network_tier: Optional[str] = None,
482
- ports: Optional[Tuple[str, ...]] = None,
483
- config_override: Optional[Dict[str, Any]] = None) -> Dict[str, Any]:
472
+ cloud: Optional[str] = None,
473
+ region: Optional[str] = None,
474
+ zone: Optional[str] = None,
475
+ gpus: Optional[str] = None,
476
+ cpus: Optional[str] = None,
477
+ memory: Optional[str] = None,
478
+ instance_type: Optional[str] = None,
479
+ use_spot: Optional[bool] = None,
480
+ image_id: Optional[str] = None,
481
+ disk_size: Optional[int] = None,
482
+ disk_tier: Optional[str] = None,
483
+ network_tier: Optional[str] = None,
484
+ ports: Optional[Tuple[str, ...]] = None,
485
+ config_override: Optional[Dict[str, Any]] = None,
486
+ ) -> Dict[str, Any]:
484
487
  """Parses the override parameters into a dictionary."""
485
488
  override_params: Dict[str, Any] = {}
486
489
  if cloud is not None:
@@ -665,6 +668,8 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
665
668
  # job launch specific
666
669
  job_recovery: Optional[str] = None,
667
670
  config_override: Optional[Dict[str, Any]] = None,
671
+ git_url: Optional[str] = None,
672
+ git_ref: Optional[str] = None,
668
673
  ) -> Union[sky.Task, sky.Dag]:
669
674
  """Creates a task or a dag from an entrypoint with overrides.
670
675
 
@@ -672,6 +677,9 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
672
677
  A dag iff the entrypoint is YAML and contains more than 1 task.
673
678
  Otherwise, a task.
674
679
  """
680
+ if git_url is not None and workdir is not None:
681
+ raise click.UsageError('Cannot specify both --git-url and --workdir')
682
+
675
683
  entrypoint = ' '.join(entrypoint)
676
684
  is_yaml, _ = _check_yaml(entrypoint)
677
685
  entrypoint: Optional[str]
@@ -731,9 +739,10 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
731
739
  task.update_envs(env)
732
740
  task.update_secrets(secret)
733
741
 
734
- # Override.
735
- if workdir is not None:
736
- task.workdir = workdir
742
+ # Update the workdir config from the command line parameters.
743
+ # And update the envs and secrets from the workdir.
744
+ _update_task_workdir(task, workdir, git_url, git_ref)
745
+ _update_task_workdir_and_secrets_from_workdir(task)
737
746
 
738
747
  # job launch specific.
739
748
  if job_recovery is not None:
@@ -748,6 +757,73 @@ def _make_task_or_dag_from_entrypoint_with_overrides(
748
757
  return task
749
758
 
750
759
 
760
+ def _update_task_workdir(task: sky.Task, workdir: Optional[str],
761
+ git_url: Optional[str], git_ref: Optional[str]):
762
+ """Updates the task workdir.
763
+
764
+ Args:
765
+ task: The task to update.
766
+ workdir: The workdir to update.
767
+ git_url: The git url to update.
768
+ git_ref: The git ref to update.
769
+ """
770
+ if task.workdir is None or isinstance(task.workdir, str):
771
+ if workdir is not None:
772
+ task.workdir = workdir
773
+ return
774
+ if git_url is not None:
775
+ task.workdir = {}
776
+ task.workdir['url'] = git_url
777
+ if git_ref is not None:
778
+ task.workdir['ref'] = git_ref
779
+ return
780
+ return
781
+ if git_url is not None:
782
+ task.workdir['url'] = git_url
783
+ if git_ref is not None:
784
+ task.workdir['ref'] = git_ref
785
+ return
786
+
787
+
788
+ def _update_task_workdir_and_secrets_from_workdir(task: sky.Task):
789
+ """Updates the task secrets from the workdir.
790
+
791
+ Args:
792
+ task: The task to update.
793
+ """
794
+ if task.workdir is None:
795
+ return
796
+ if not isinstance(task.workdir, dict):
797
+ return
798
+ url = task.workdir['url']
799
+ ref = task.workdir.get('ref', '')
800
+ token = os.environ.get(git_utils.GIT_TOKEN_ENV_VAR)
801
+ ssh_key_path = os.environ.get(git_utils.GIT_SSH_KEY_PATH_ENV_VAR)
802
+ try:
803
+ git_repo = git.GitRepo(url, ref, token, ssh_key_path)
804
+ clone_info = git_repo.get_repo_clone_info()
805
+ if clone_info is None:
806
+ return
807
+ task.envs[git_utils.GIT_URL_ENV_VAR] = clone_info.url
808
+ if ref:
809
+ ref_type = git_repo.get_ref_type()
810
+ if ref_type == git.GitRefType.COMMIT:
811
+ task.envs[git_utils.GIT_COMMIT_HASH_ENV_VAR] = ref
812
+ elif ref_type == git.GitRefType.BRANCH:
813
+ task.envs[git_utils.GIT_BRANCH_ENV_VAR] = ref
814
+ elif ref_type == git.GitRefType.TAG:
815
+ task.envs[git_utils.GIT_TAG_ENV_VAR] = ref
816
+ if clone_info.token is None and clone_info.ssh_key is None:
817
+ return
818
+ if clone_info.token is not None:
819
+ task.secrets[git_utils.GIT_TOKEN_ENV_VAR] = clone_info.token
820
+ if clone_info.ssh_key is not None:
821
+ task.secrets[git_utils.GIT_SSH_KEY_ENV_VAR] = clone_info.ssh_key
822
+ except exceptions.GitError as e:
823
+ with ux_utils.print_exception_no_traceback():
824
+ raise ValueError(f'{str(e)}') from None
825
+
826
+
751
827
  class _NaturalOrderGroup(click.Group):
752
828
  """Lists commands in the order defined in this script.
753
829
 
@@ -925,42 +1001,49 @@ def _handle_infra_cloud_region_zone_options(infra: Optional[str],
925
1001
  required=False,
926
1002
  help=('[Experimental] If the cluster is already up and available, skip '
927
1003
  'provisioning and setup steps.'))
1004
+ @click.option('--git-url', type=str, help='Git repository URL.')
1005
+ @click.option('--git-ref',
1006
+ type=str,
1007
+ help='Git reference (branch, tag, or commit hash) to use.')
928
1008
  @usage_lib.entrypoint
929
1009
  def launch(
930
- entrypoint: Tuple[str, ...],
931
- cluster: Optional[str],
932
- dryrun: bool,
933
- detach_run: bool,
934
- backend_name: Optional[str],
935
- name: Optional[str],
936
- workdir: Optional[str],
937
- infra: Optional[str],
938
- cloud: Optional[str],
939
- region: Optional[str],
940
- zone: Optional[str],
941
- gpus: Optional[str],
942
- cpus: Optional[str],
943
- memory: Optional[str],
944
- instance_type: Optional[str],
945
- num_nodes: Optional[int],
946
- use_spot: Optional[bool],
947
- image_id: Optional[str],
948
- env_file: Optional[Dict[str, str]],
949
- env: List[Tuple[str, str]],
950
- secret: List[Tuple[str, str]],
951
- disk_size: Optional[int],
952
- disk_tier: Optional[str],
953
- network_tier: Optional[str],
954
- ports: Tuple[str, ...],
955
- idle_minutes_to_autostop: Optional[int],
956
- down: bool, # pylint: disable=redefined-outer-name
957
- retry_until_up: bool,
958
- yes: bool,
959
- no_setup: bool,
960
- clone_disk_from: Optional[str],
961
- fast: bool,
962
- async_call: bool,
963
- config_override: Optional[Dict[str, Any]] = None):
1010
+ entrypoint: Tuple[str, ...],
1011
+ cluster: Optional[str],
1012
+ dryrun: bool,
1013
+ detach_run: bool,
1014
+ backend_name: Optional[str],
1015
+ name: Optional[str],
1016
+ workdir: Optional[str],
1017
+ infra: Optional[str],
1018
+ cloud: Optional[str],
1019
+ region: Optional[str],
1020
+ zone: Optional[str],
1021
+ gpus: Optional[str],
1022
+ cpus: Optional[str],
1023
+ memory: Optional[str],
1024
+ instance_type: Optional[str],
1025
+ num_nodes: Optional[int],
1026
+ use_spot: Optional[bool],
1027
+ image_id: Optional[str],
1028
+ env_file: Optional[Dict[str, str]],
1029
+ env: List[Tuple[str, str]],
1030
+ secret: List[Tuple[str, str]],
1031
+ disk_size: Optional[int],
1032
+ disk_tier: Optional[str],
1033
+ network_tier: Optional[str],
1034
+ ports: Tuple[str, ...],
1035
+ idle_minutes_to_autostop: Optional[int],
1036
+ down: bool, # pylint: disable=redefined-outer-name
1037
+ retry_until_up: bool,
1038
+ yes: bool,
1039
+ no_setup: bool,
1040
+ clone_disk_from: Optional[str],
1041
+ fast: bool,
1042
+ async_call: bool,
1043
+ config_override: Optional[Dict[str, Any]] = None,
1044
+ git_url: Optional[str] = None,
1045
+ git_ref: Optional[str] = None,
1046
+ ):
964
1047
  """Launch a cluster or task.
965
1048
 
966
1049
  If ENTRYPOINT points to a valid YAML file, it is read in as the task
@@ -1008,6 +1091,8 @@ def launch(
1008
1091
  network_tier=network_tier,
1009
1092
  ports=ports,
1010
1093
  config_override=config_override,
1094
+ git_url=git_url,
1095
+ git_ref=git_ref,
1011
1096
  )
1012
1097
  if isinstance(task_or_dag, sky.Dag):
1013
1098
  raise click.UsageError(
@@ -1099,34 +1184,42 @@ def launch(
1099
1184
  'and do not stream execution logs.'))
1100
1185
  @_add_click_options(flags.TASK_OPTIONS_WITH_NAME +
1101
1186
  flags.EXTRA_RESOURCES_OPTIONS + flags.COMMON_OPTIONS)
1187
+ @click.option('--git-url', type=str, help='Git repository URL.')
1188
+ @click.option('--git-ref',
1189
+ type=str,
1190
+ help='Git reference (branch, tag, or commit hash) to use.')
1102
1191
  @usage_lib.entrypoint
1103
1192
  # pylint: disable=redefined-builtin
1104
- def exec(cluster: Optional[str],
1105
- cluster_option: Optional[str],
1106
- entrypoint: Tuple[str, ...],
1107
- detach_run: bool,
1108
- name: Optional[str],
1109
- infra: Optional[str],
1110
- cloud: Optional[str],
1111
- region: Optional[str],
1112
- zone: Optional[str],
1113
- workdir: Optional[str],
1114
- gpus: Optional[str],
1115
- ports: Tuple[str],
1116
- instance_type: Optional[str],
1117
- num_nodes: Optional[int],
1118
- use_spot: Optional[bool],
1119
- image_id: Optional[str],
1120
- env_file: Optional[Dict[str, str]],
1121
- env: List[Tuple[str, str]],
1122
- secret: List[Tuple[str, str]],
1123
- cpus: Optional[str],
1124
- memory: Optional[str],
1125
- disk_size: Optional[int],
1126
- disk_tier: Optional[str],
1127
- network_tier: Optional[str],
1128
- async_call: bool,
1129
- config_override: Optional[Dict[str, Any]] = None):
1193
+ def exec(
1194
+ cluster: Optional[str],
1195
+ cluster_option: Optional[str],
1196
+ entrypoint: Tuple[str, ...],
1197
+ detach_run: bool,
1198
+ name: Optional[str],
1199
+ infra: Optional[str],
1200
+ cloud: Optional[str],
1201
+ region: Optional[str],
1202
+ zone: Optional[str],
1203
+ workdir: Optional[str],
1204
+ gpus: Optional[str],
1205
+ ports: Tuple[str],
1206
+ instance_type: Optional[str],
1207
+ num_nodes: Optional[int],
1208
+ use_spot: Optional[bool],
1209
+ image_id: Optional[str],
1210
+ env_file: Optional[Dict[str, str]],
1211
+ env: List[Tuple[str, str]],
1212
+ secret: List[Tuple[str, str]],
1213
+ cpus: Optional[str],
1214
+ memory: Optional[str],
1215
+ disk_size: Optional[int],
1216
+ disk_tier: Optional[str],
1217
+ network_tier: Optional[str],
1218
+ async_call: bool,
1219
+ config_override: Optional[Dict[str, Any]] = None,
1220
+ git_url: Optional[str] = None,
1221
+ git_ref: Optional[str] = None,
1222
+ ):
1130
1223
  # NOTE(dev): Keep the docstring consistent between the Python API and CLI.
1131
1224
  """Execute a task or command on an existing cluster.
1132
1225
 
@@ -1225,6 +1318,8 @@ def exec(cluster: Optional[str],
1225
1318
  ports=ports,
1226
1319
  field_to_ignore=['cpus', 'memory', 'disk_size', 'disk_tier', 'ports'],
1227
1320
  config_override=config_override,
1321
+ git_url=git_url,
1322
+ git_ref=git_ref,
1228
1323
  )
1229
1324
 
1230
1325
  if isinstance(task_or_dag, sky.Dag):
@@ -4064,6 +4159,10 @@ def jobs():
4064
4159
  is_flag=True,
4065
4160
  help=('If True, as soon as a job is submitted, return from this call '
4066
4161
  'and do not stream execution logs.'))
4162
+ @click.option('--git-url', type=str, help='Git repository URL.')
4163
+ @click.option('--git-ref',
4164
+ type=str,
4165
+ help='Git reference (branch, tag, or commit hash) to use.')
4067
4166
  @flags.yes_option()
4068
4167
  @timeline.event
4069
4168
  @usage_lib.entrypoint
@@ -4095,6 +4194,8 @@ def jobs_launch(
4095
4194
  yes: bool,
4096
4195
  async_call: bool,
4097
4196
  config_override: Optional[Dict[str, Any]] = None,
4197
+ git_url: Optional[str] = None,
4198
+ git_ref: Optional[str] = None,
4098
4199
  ):
4099
4200
  """Launch a managed job from a YAML or a command.
4100
4201
 
@@ -4140,6 +4241,8 @@ def jobs_launch(
4140
4241
  ports=ports,
4141
4242
  job_recovery=job_recovery,
4142
4243
  config_override=config_override,
4244
+ git_url=git_url,
4245
+ git_ref=git_ref,
4143
4246
  )
4144
4247
 
4145
4248
  if not isinstance(task_or_dag, sky.Dag):