zenml-nightly 0.75.0.dev20250312__py3-none-any.whl → 0.75.0.dev20250313__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 (160) hide show
  1. zenml/VERSION +1 -1
  2. zenml/__init__.py +2 -0
  3. zenml/analytics/context.py +7 -0
  4. zenml/artifacts/utils.py +0 -2
  5. zenml/cli/login.py +6 -0
  6. zenml/cli/model.py +7 -15
  7. zenml/cli/secret.py +47 -44
  8. zenml/cli/service_connectors.py +0 -1
  9. zenml/cli/stack.py +0 -1
  10. zenml/cli/tag.py +3 -5
  11. zenml/cli/utils.py +25 -23
  12. zenml/cli/workspace.py +79 -5
  13. zenml/client.py +615 -348
  14. zenml/config/global_config.py +16 -3
  15. zenml/config/pipeline_configurations.py +3 -2
  16. zenml/config/pipeline_run_configuration.py +2 -1
  17. zenml/config/secret_reference_mixin.py +1 -1
  18. zenml/constants.py +1 -3
  19. zenml/enums.py +0 -7
  20. zenml/event_hub/event_hub.py +3 -1
  21. zenml/exceptions.py +0 -24
  22. zenml/integrations/aws/orchestrators/sagemaker_orchestrator.py +5 -3
  23. zenml/integrations/bitbucket/plugins/event_sources/bitbucket_webhook_event_source.py +1 -4
  24. zenml/integrations/github/plugins/event_sources/github_webhook_event_source.py +1 -4
  25. zenml/integrations/mlflow/steps/mlflow_registry.py +1 -1
  26. zenml/integrations/seldon/model_deployers/seldon_model_deployer.py +1 -1
  27. zenml/integrations/wandb/flavors/wandb_experiment_tracker_flavor.py +3 -3
  28. zenml/model/model.py +8 -8
  29. zenml/models/__init__.py +18 -1
  30. zenml/models/v2/base/base.py +0 -5
  31. zenml/models/v2/base/filter.py +1 -1
  32. zenml/models/v2/base/scoped.py +104 -121
  33. zenml/models/v2/core/api_key.py +1 -1
  34. zenml/models/v2/core/artifact.py +31 -18
  35. zenml/models/v2/core/artifact_version.py +42 -25
  36. zenml/models/v2/core/component.py +22 -33
  37. zenml/models/v2/core/device.py +3 -2
  38. zenml/models/v2/core/event_source.py +2 -2
  39. zenml/models/v2/core/flavor.py +19 -47
  40. zenml/models/v2/core/logs.py +1 -2
  41. zenml/models/v2/core/model.py +7 -4
  42. zenml/models/v2/core/model_version.py +36 -27
  43. zenml/models/v2/core/pipeline.py +1 -1
  44. zenml/models/v2/core/pipeline_run.py +5 -13
  45. zenml/models/v2/core/run_template.py +1 -2
  46. zenml/models/v2/core/schedule.py +0 -9
  47. zenml/models/v2/core/secret.py +93 -127
  48. zenml/models/v2/core/server_settings.py +2 -2
  49. zenml/models/v2/core/service.py +43 -12
  50. zenml/models/v2/core/service_connector.py +14 -16
  51. zenml/models/v2/core/stack.py +24 -26
  52. zenml/models/v2/core/step_run.py +3 -15
  53. zenml/models/v2/core/tag.py +41 -15
  54. zenml/models/v2/core/user.py +19 -2
  55. zenml/models/v2/misc/statistics.py +45 -0
  56. zenml/models/v2/misc/tag.py +27 -0
  57. zenml/orchestrators/cache_utils.py +1 -1
  58. zenml/orchestrators/input_utils.py +1 -0
  59. zenml/orchestrators/step_launcher.py +0 -1
  60. zenml/orchestrators/step_run_utils.py +0 -2
  61. zenml/orchestrators/step_runner.py +10 -1
  62. zenml/pipelines/build_utils.py +0 -2
  63. zenml/pipelines/pipeline_decorator.py +3 -2
  64. zenml/pipelines/pipeline_definition.py +4 -5
  65. zenml/pipelines/run_utils.py +3 -3
  66. zenml/service_connectors/service_connector.py +0 -7
  67. zenml/service_connectors/service_connector_utils.py +0 -1
  68. zenml/stack/authentication_mixin.py +1 -1
  69. zenml/stack/flavor.py +3 -14
  70. zenml/stack/stack_component.py +1 -5
  71. zenml/steps/step_context.py +19 -0
  72. zenml/utils/string_utils.py +1 -1
  73. zenml/utils/tag_utils.py +642 -0
  74. zenml/zen_server/cloud_utils.py +21 -0
  75. zenml/zen_server/exceptions.py +0 -6
  76. zenml/zen_server/rbac/endpoint_utils.py +134 -46
  77. zenml/zen_server/rbac/models.py +65 -3
  78. zenml/zen_server/rbac/rbac_interface.py +9 -0
  79. zenml/zen_server/rbac/rbac_sql_zen_store.py +15 -7
  80. zenml/zen_server/rbac/utils.py +156 -29
  81. zenml/zen_server/rbac/zenml_cloud_rbac.py +43 -11
  82. zenml/zen_server/routers/actions_endpoints.py +3 -5
  83. zenml/zen_server/routers/artifact_endpoint.py +0 -5
  84. zenml/zen_server/routers/artifact_version_endpoints.py +15 -9
  85. zenml/zen_server/routers/auth_endpoints.py +22 -7
  86. zenml/zen_server/routers/code_repositories_endpoints.py +56 -3
  87. zenml/zen_server/routers/devices_endpoints.py +0 -4
  88. zenml/zen_server/routers/event_source_endpoints.py +0 -5
  89. zenml/zen_server/routers/flavors_endpoints.py +0 -5
  90. zenml/zen_server/routers/logs_endpoints.py +0 -1
  91. zenml/zen_server/routers/model_versions_endpoints.py +102 -23
  92. zenml/zen_server/routers/models_endpoints.py +51 -68
  93. zenml/zen_server/routers/pipeline_builds_endpoints.py +58 -4
  94. zenml/zen_server/routers/pipeline_deployments_endpoints.py +58 -4
  95. zenml/zen_server/routers/pipelines_endpoints.py +73 -4
  96. zenml/zen_server/routers/plugin_endpoints.py +0 -1
  97. zenml/zen_server/routers/run_metadata_endpoints.py +99 -0
  98. zenml/zen_server/routers/run_templates_endpoints.py +66 -3
  99. zenml/zen_server/routers/runs_endpoints.py +60 -8
  100. zenml/zen_server/routers/schedule_endpoints.py +69 -6
  101. zenml/zen_server/routers/secrets_endpoints.py +40 -4
  102. zenml/zen_server/routers/server_endpoints.py +53 -1
  103. zenml/zen_server/routers/service_accounts_endpoints.py +14 -15
  104. zenml/zen_server/routers/service_connectors_endpoints.py +96 -14
  105. zenml/zen_server/routers/service_endpoints.py +20 -7
  106. zenml/zen_server/routers/stack_components_endpoints.py +68 -7
  107. zenml/zen_server/routers/stacks_endpoints.py +98 -7
  108. zenml/zen_server/routers/steps_endpoints.py +17 -11
  109. zenml/zen_server/routers/tag_resource_endpoints.py +115 -0
  110. zenml/zen_server/routers/tags_endpoints.py +6 -17
  111. zenml/zen_server/routers/triggers_endpoints.py +5 -8
  112. zenml/zen_server/routers/users_endpoints.py +47 -12
  113. zenml/zen_server/routers/workspaces_endpoints.py +56 -1285
  114. zenml/zen_server/template_execution/utils.py +5 -4
  115. zenml/zen_server/utils.py +21 -0
  116. zenml/zen_server/zen_server_api.py +4 -0
  117. zenml/zen_stores/base_zen_store.py +29 -44
  118. zenml/zen_stores/migrations/versions/1cb6477f72d6_move_artifact_save_type.py +20 -10
  119. zenml/zen_stores/migrations/versions/1f9d1cd00b90_add_unique_name_constraints.py +231 -0
  120. zenml/zen_stores/migrations/versions/288f4fb6e112_make_tags_user_scoped.py +74 -0
  121. zenml/zen_stores/migrations/versions/2e695a26fe7a_add_user_default_workspace.py +45 -0
  122. zenml/zen_stores/migrations/versions/3b1776345020_remove_workspace_from_globals.py +81 -0
  123. zenml/zen_stores/migrations/versions/41b28cae31ce_make_artifacts_workspace_scoped.py +136 -0
  124. zenml/zen_stores/migrations/versions/9e7bf0970266_adding_exclusive_attribute_to_tags.py +47 -0
  125. zenml/zen_stores/migrations/versions/b557b2871693_update_step_run_input_types.py +8 -4
  126. zenml/zen_stores/migrations/versions/cc269488e5a9_separate_run_metadata.py +12 -6
  127. zenml/zen_stores/migrations/versions/f1d723fd723b_add_secret_private_attr.py +61 -0
  128. zenml/zen_stores/migrations/versions/f76a368a25a5_add_stack_description.py +35 -0
  129. zenml/zen_stores/rest_zen_store.py +172 -171
  130. zenml/zen_stores/schemas/action_schemas.py +8 -1
  131. zenml/zen_stores/schemas/api_key_schemas.py +8 -1
  132. zenml/zen_stores/schemas/artifact_schemas.py +28 -1
  133. zenml/zen_stores/schemas/code_repository_schemas.py +8 -1
  134. zenml/zen_stores/schemas/component_schemas.py +9 -14
  135. zenml/zen_stores/schemas/event_source_schemas.py +8 -1
  136. zenml/zen_stores/schemas/flavor_schemas.py +14 -20
  137. zenml/zen_stores/schemas/model_schemas.py +3 -0
  138. zenml/zen_stores/schemas/pipeline_deployment_schemas.py +3 -1
  139. zenml/zen_stores/schemas/pipeline_run_schemas.py +0 -3
  140. zenml/zen_stores/schemas/run_template_schemas.py +8 -4
  141. zenml/zen_stores/schemas/schedule_schema.py +9 -14
  142. zenml/zen_stores/schemas/secret_schemas.py +15 -25
  143. zenml/zen_stores/schemas/service_connector_schemas.py +8 -17
  144. zenml/zen_stores/schemas/service_schemas.py +0 -1
  145. zenml/zen_stores/schemas/stack_schemas.py +12 -15
  146. zenml/zen_stores/schemas/step_run_schemas.py +7 -8
  147. zenml/zen_stores/schemas/tag_schemas.py +30 -2
  148. zenml/zen_stores/schemas/trigger_schemas.py +8 -1
  149. zenml/zen_stores/schemas/user_schemas.py +24 -2
  150. zenml/zen_stores/schemas/utils.py +16 -0
  151. zenml/zen_stores/schemas/workspace_schemas.py +7 -25
  152. zenml/zen_stores/secrets_stores/service_connector_secrets_store.py +0 -3
  153. zenml/zen_stores/sql_zen_store.py +2905 -2280
  154. zenml/zen_stores/template_utils.py +1 -1
  155. zenml/zen_stores/zen_store_interface.py +82 -58
  156. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/METADATA +1 -1
  157. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/RECORD +160 -147
  158. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/LICENSE +0 -0
  159. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/WHEEL +0 -0
  160. {zenml_nightly-0.75.0.dev20250312.dist-info → zenml_nightly-0.75.0.dev20250313.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,81 @@
1
+ """remove workspace from globals [3b1776345020].
2
+
3
+ Revision ID: 3b1776345020
4
+ Revises: 0392807467dc
5
+ Create Date: 2025-02-13 15:57:38.255825
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ from alembic import op
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = "3b1776345020"
14
+ down_revision = "0392807467dc"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ """Upgrade database schema and/or data, creating a new revision.
21
+
22
+ Raises:
23
+ RuntimeError: If more than one workspace exists.
24
+ """
25
+ # If more than one workspace exists, we fail the migration because it
26
+ # would mean merging together resources from different workspaces, which
27
+ # can lead to naming conflicts.
28
+ workspace_count_query = sa.text("SELECT COUNT(*) FROM workspace")
29
+ connection = op.get_bind()
30
+ workspace_count = connection.execute(
31
+ workspace_count_query,
32
+ ).scalar()
33
+ assert isinstance(workspace_count, int)
34
+ if workspace_count > 1:
35
+ raise RuntimeError(
36
+ "Your ZenML installation has more than just the default workspace "
37
+ "configured. This migration removes the workspace scopes of all "
38
+ "stacks, components, flavors, service connectors and secrets, "
39
+ "which may lead to naming conflicts if multiple workspaces are "
40
+ "present. Please delete all but the default workspace before "
41
+ "running this migration."
42
+ )
43
+
44
+ with op.batch_alter_table("flavor", schema=None) as batch_op:
45
+ batch_op.drop_constraint(
46
+ "fk_flavor_workspace_id_workspace", type_="foreignkey"
47
+ )
48
+ batch_op.drop_column("workspace_id")
49
+
50
+ with op.batch_alter_table("secret", schema=None) as batch_op:
51
+ batch_op.drop_constraint(
52
+ "fk_secret_workspace_id_workspace", type_="foreignkey"
53
+ )
54
+ batch_op.drop_column("workspace_id")
55
+
56
+ with op.batch_alter_table("service_connector", schema=None) as batch_op:
57
+ batch_op.drop_constraint(
58
+ "fk_service_connector_workspace_id_workspace", type_="foreignkey"
59
+ )
60
+ batch_op.drop_column("workspace_id")
61
+
62
+ with op.batch_alter_table("stack", schema=None) as batch_op:
63
+ batch_op.drop_constraint(
64
+ "fk_stack_workspace_id_workspace", type_="foreignkey"
65
+ )
66
+ batch_op.drop_column("workspace_id")
67
+
68
+ with op.batch_alter_table("stack_component", schema=None) as batch_op:
69
+ batch_op.drop_constraint(
70
+ "fk_stack_component_workspace_id_workspace", type_="foreignkey"
71
+ )
72
+ batch_op.drop_column("workspace_id")
73
+
74
+
75
+ def downgrade() -> None:
76
+ """Downgrade database schema and/or data back to the previous revision.
77
+
78
+ Raises:
79
+ NotImplementedError: This migration is not reversible.
80
+ """
81
+ raise NotImplementedError("This migration is not reversible.")
@@ -0,0 +1,136 @@
1
+ """make artifacts workspace scoped [41b28cae31ce].
2
+
3
+ Revision ID: 41b28cae31ce
4
+ Revises: 288f4fb6e112
5
+ Create Date: 2025-02-19 23:23:08.133826
6
+
7
+ """
8
+
9
+ import os
10
+
11
+ import sqlalchemy as sa
12
+ import sqlmodel
13
+ from alembic import op
14
+ from sqlalchemy.orm import Session
15
+ from sqlalchemy.sql import column, table
16
+
17
+ from zenml.constants import (
18
+ DEFAULT_WORKSPACE_NAME,
19
+ ENV_ZENML_DEFAULT_WORKSPACE_NAME,
20
+ )
21
+
22
+ # revision identifiers, used by Alembic.
23
+ revision = "41b28cae31ce"
24
+ down_revision = "288f4fb6e112"
25
+ branch_labels = None
26
+ depends_on = None
27
+
28
+
29
+ def upgrade() -> None:
30
+ """Upgrade database schema and/or data, creating a new revision.
31
+
32
+ Raises:
33
+ Exception: If the default workspace is not found.
34
+ """
35
+ # ### commands auto generated by Alembic - please adjust! ###
36
+ with op.batch_alter_table("artifact", schema=None) as batch_op:
37
+ # First add columns as nullable
38
+ batch_op.add_column(
39
+ sa.Column(
40
+ "workspace_id", sqlmodel.sql.sqltypes.GUID(), nullable=True
41
+ )
42
+ )
43
+ batch_op.add_column(
44
+ sa.Column("user_id", sqlmodel.sql.sqltypes.GUID(), nullable=True)
45
+ )
46
+
47
+ # Create a temp table object for the update
48
+ artifact_table = table(
49
+ "artifact",
50
+ column("id", sqlmodel.sql.sqltypes.GUID()),
51
+ column("workspace_id", sqlmodel.sql.sqltypes.GUID()),
52
+ )
53
+
54
+ default_workspace_name = os.getenv(
55
+ ENV_ZENML_DEFAULT_WORKSPACE_NAME, DEFAULT_WORKSPACE_NAME
56
+ )
57
+
58
+ default_workspace_query = sa.text(
59
+ "SELECT id FROM workspace WHERE name = :default_workspace_name LIMIT 1"
60
+ )
61
+ connection = op.get_bind()
62
+ default_workspace_id = connection.execute(
63
+ default_workspace_query,
64
+ {"default_workspace_name": default_workspace_name},
65
+ ).scalar()
66
+
67
+ if default_workspace_id is None:
68
+ raise Exception(
69
+ "Default workspace not found. Cannot proceed with migration."
70
+ )
71
+
72
+ # Update existing records with the default workspace
73
+ op.execute(
74
+ artifact_table.update().values(workspace_id=default_workspace_id)
75
+ )
76
+
77
+ bind = op.get_bind()
78
+ session = Session(bind=bind)
79
+
80
+ # Set the artifact owner to the owner of the latest artifact version.
81
+ # NOTE: we skip this for SQLite because the subquery will fail.
82
+ if bind.dialect.name != "sqlite":
83
+ session.execute(
84
+ sa.text(
85
+ """
86
+ UPDATE artifact a
87
+ SET user_id = (
88
+ SELECT v.user_id
89
+ FROM `artifact_version` v
90
+ WHERE v.artifact_id = a.id
91
+ ORDER BY v.created DESC
92
+ LIMIT 1
93
+ )
94
+ """
95
+ ),
96
+ )
97
+
98
+ # Now make workspace_id non-nullable
99
+ with op.batch_alter_table("artifact", schema=None) as batch_op:
100
+ batch_op.alter_column(
101
+ "workspace_id",
102
+ existing_type=sqlmodel.sql.sqltypes.GUID(),
103
+ nullable=False,
104
+ )
105
+
106
+ # Add foreign key constraints
107
+ batch_op.create_foreign_key(
108
+ "fk_artifact_workspace_id_workspace",
109
+ "workspace",
110
+ ["workspace_id"],
111
+ ["id"],
112
+ ondelete="CASCADE",
113
+ )
114
+ batch_op.create_foreign_key(
115
+ "fk_artifact_user_id_user",
116
+ "user",
117
+ ["user_id"],
118
+ ["id"],
119
+ ondelete="SET NULL",
120
+ )
121
+
122
+
123
+ def downgrade() -> None:
124
+ """Downgrade database schema and/or data back to the previous revision."""
125
+ # ### commands auto generated by Alembic - please adjust! ###
126
+ with op.batch_alter_table("artifact", schema=None) as batch_op:
127
+ batch_op.drop_constraint(
128
+ "fk_artifact_user_id_user", type_="foreignkey"
129
+ )
130
+ batch_op.drop_constraint(
131
+ "fk_artifact_workspace_id_workspace", type_="foreignkey"
132
+ )
133
+ batch_op.drop_column("user_id")
134
+ batch_op.drop_column("workspace_id")
135
+
136
+ # ### end Alembic commands ###
@@ -0,0 +1,47 @@
1
+ """adding exclusive attribute to tags [9e7bf0970266].
2
+
3
+ Revision ID: 9e7bf0970266
4
+ Revises: 2e695a26fe7a
5
+ Create Date: 2025-03-03 15:17:49.341208
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ from alembic import op
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = "9e7bf0970266"
14
+ down_revision = "2e695a26fe7a"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ """Upgrade database schema and/or data, creating a new revision."""
21
+ # Use batch_alter_table for safer schema modifications
22
+ with op.batch_alter_table("tag") as batch_op:
23
+ # First add the column as nullable
24
+ batch_op.add_column(
25
+ sa.Column(
26
+ "exclusive",
27
+ sa.Boolean(),
28
+ nullable=True,
29
+ ),
30
+ )
31
+
32
+ # Update existing rows with default value
33
+ op.execute("UPDATE tag SET exclusive = FALSE WHERE exclusive IS NULL")
34
+
35
+ # Then alter the column to be non-nullable with a default
36
+ with op.batch_alter_table("tag") as batch_op:
37
+ batch_op.alter_column(
38
+ "exclusive",
39
+ existing_type=sa.Boolean(),
40
+ nullable=False,
41
+ server_default=sa.false(),
42
+ )
43
+
44
+
45
+ def downgrade() -> None:
46
+ """Downgrade database schema and/or data back to the previous revision."""
47
+ op.drop_column("tag", "exclusive")
@@ -17,17 +17,21 @@ depends_on = None
17
17
 
18
18
  def upgrade() -> None:
19
19
  """Upgrade database schema and/or data, creating a new revision."""
20
- op.execute("""
20
+ op.execute(
21
+ """
21
22
  UPDATE step_run_input_artifact
22
23
  SET type = 'step_output'
23
24
  WHERE type = 'default'
24
- """)
25
+ """
26
+ )
25
27
 
26
28
 
27
29
  def downgrade() -> None:
28
30
  """Downgrade database schema and/or data back to the previous revision."""
29
- op.execute("""
31
+ op.execute(
32
+ """
30
33
  UPDATE step_run_input_artifact
31
34
  SET type = 'default'
32
35
  WHERE type = 'step_output'
33
- """)
36
+ """
37
+ )
@@ -41,10 +41,12 @@ def upgrade() -> None:
41
41
  connection = op.get_bind()
42
42
 
43
43
  run_metadata_data = connection.execute(
44
- sa.text("""
44
+ sa.text(
45
+ """
45
46
  SELECT id, resource_id, resource_type
46
47
  FROM run_metadata
47
- """)
48
+ """
49
+ )
48
50
  ).fetchall()
49
51
 
50
52
  # Prepare data with new UUIDs for bulk insert
@@ -107,20 +109,24 @@ def downgrade() -> None:
107
109
 
108
110
  # Fetch data from `run_metadata_resource`
109
111
  run_metadata_resource_data = connection.execute(
110
- sa.text("""
112
+ sa.text(
113
+ """
111
114
  SELECT resource_id, resource_type, run_metadata_id
112
115
  FROM run_metadata_resource
113
- """)
116
+ """
117
+ )
114
118
  ).fetchall()
115
119
 
116
120
  # Update `run_metadata` with the data from `run_metadata_resource`
117
121
  for row in run_metadata_resource_data:
118
122
  connection.execute(
119
- sa.text("""
123
+ sa.text(
124
+ """
120
125
  UPDATE run_metadata
121
126
  SET resource_id = :resource_id, resource_type = :resource_type
122
127
  WHERE id = :run_metadata_id
123
- """),
128
+ """
129
+ ),
124
130
  {
125
131
  "resource_id": row.resource_id,
126
132
  "resource_type": row.resource_type,
@@ -0,0 +1,61 @@
1
+ """add secret private attr [f1d723fd723b].
2
+
3
+ Revision ID: f1d723fd723b
4
+ Revises: 41b28cae31ce
5
+ Create Date: 2025-02-21 19:40:14.596681
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ from alembic import op
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = "f1d723fd723b"
14
+ down_revision = "41b28cae31ce"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade() -> None:
20
+ """Upgrade database schema and/or data, creating a new revision."""
21
+ # Step 1: Add private column as nullable
22
+ with op.batch_alter_table("secret", schema=None) as batch_op:
23
+ batch_op.add_column(sa.Column("private", sa.Boolean(), nullable=True))
24
+
25
+ # Step 2: Update existing records based on scope
26
+ connection = op.get_bind()
27
+ connection.execute(
28
+ sa.text("UPDATE secret SET private = TRUE WHERE scope = 'user';")
29
+ )
30
+ connection.execute(
31
+ sa.text("UPDATE secret SET private = FALSE WHERE scope != 'user';")
32
+ )
33
+
34
+ # Step 3: Make private column non-nullable and drop scope
35
+ with op.batch_alter_table("secret", schema=None) as batch_op:
36
+ batch_op.alter_column(
37
+ "private", existing_type=sa.Boolean(), nullable=False
38
+ )
39
+ batch_op.drop_column("scope")
40
+
41
+
42
+ def downgrade() -> None:
43
+ """Downgrade database schema and/or data back to the previous revision."""
44
+ with op.batch_alter_table("secret", schema=None) as batch_op:
45
+ batch_op.add_column(sa.Column("scope", sa.VARCHAR(), nullable=True))
46
+
47
+ # Restore scope values based on private flag
48
+ connection = op.get_bind()
49
+ connection.execute(
50
+ sa.text("UPDATE secret SET scope = 'user' WHERE private = TRUE;")
51
+ )
52
+ connection.execute(
53
+ sa.text("UPDATE secret SET scope = 'workspace' WHERE private = FALSE;")
54
+ )
55
+
56
+ # Make scope non-nullable and drop private
57
+ with op.batch_alter_table("secret", schema=None) as batch_op:
58
+ batch_op.alter_column(
59
+ "scope", existing_type=sa.VARCHAR(), nullable=False
60
+ )
61
+ batch_op.drop_column("private")
@@ -0,0 +1,35 @@
1
+ """add stack description [f76a368a25a5].
2
+
3
+ Revision ID: f76a368a25a5
4
+ Revises: f1d723fd723b
5
+ Create Date: 2025-02-22 19:03:32.568076
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ import sqlmodel
11
+ from alembic import op
12
+
13
+ # revision identifiers, used by Alembic.
14
+ revision = "f76a368a25a5"
15
+ down_revision = "f1d723fd723b"
16
+ branch_labels = None
17
+ depends_on = None
18
+
19
+
20
+ def upgrade() -> None:
21
+ """Upgrade database schema and/or data, creating a new revision."""
22
+ with op.batch_alter_table("stack", schema=None) as batch_op:
23
+ batch_op.add_column(
24
+ sa.Column(
25
+ "description",
26
+ sqlmodel.sql.sqltypes.AutoString(),
27
+ nullable=True,
28
+ )
29
+ )
30
+
31
+
32
+ def downgrade() -> None:
33
+ """Downgrade database schema and/or data back to the previous revision."""
34
+ with op.batch_alter_table("stack", schema=None) as batch_op:
35
+ batch_op.drop_column("description")