mage-ai 0.9.68__py3-none-any.whl → 0.9.70__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.
Potentially problematic release.
This version of mage-ai might be problematic. Click here for more details.
- mage_ai/api/policies/BackfillPolicy.py +1 -0
- mage_ai/api/policies/PipelinePolicy.py +1 -0
- mage_ai/api/policies/WorkspacePolicy.py +1 -0
- mage_ai/api/presenters/BackfillPresenter.py +1 -0
- mage_ai/api/resources/GitBranchResource.py +56 -23
- mage_ai/api/resources/GitCustomBranchResource.py +29 -1
- mage_ai/api/resources/OauthResource.py +1 -1
- mage_ai/api/resources/PipelineResource.py +11 -5
- mage_ai/api/resources/PipelineRunResource.py +41 -4
- mage_ai/api/resources/PipelineScheduleResource.py +4 -0
- mage_ai/api/resources/PullRequestResource.py +6 -4
- mage_ai/api/resources/SeedResource.py +2 -1
- mage_ai/api/resources/SessionResource.py +13 -1
- mage_ai/api/resources/WorkspaceResource.py +5 -4
- mage_ai/authentication/permissions/constants.py +2 -0
- mage_ai/authentication/permissions/seed.py +32 -21
- mage_ai/authentication/providers/active_directory.py +4 -3
- mage_ai/authentication/providers/okta.py +22 -83
- mage_ai/cache/block_action_object/__init__.py +1 -1
- mage_ai/cluster_manager/kubernetes/workload_manager.py +52 -1
- mage_ai/cluster_manager/workspace/base.py +6 -0
- mage_ai/cluster_manager/workspace/kubernetes.py +22 -1
- mage_ai/command_center/applications/utils.py +2 -2
- mage_ai/command_center/presenters/text.py +1 -1
- mage_ai/data_preparation/executors/k8s_block_executor.py +30 -7
- mage_ai/data_preparation/executors/k8s_pipeline_executor.py +30 -7
- mage_ai/data_preparation/executors/streaming_pipeline_executor.py +78 -8
- mage_ai/data_preparation/git/__init__.py +50 -22
- mage_ai/data_preparation/git/api.py +62 -7
- mage_ai/data_preparation/git/utils.py +45 -21
- mage_ai/data_preparation/models/block/__init__.py +31 -8
- mage_ai/data_preparation/models/block/data_integration/mixins.py +16 -5
- mage_ai/data_preparation/models/block/dynamic/child.py +3 -0
- mage_ai/data_preparation/models/block/dynamic/utils.py +9 -4
- mage_ai/data_preparation/models/block/dynamic/variables.py +2 -2
- mage_ai/data_preparation/models/block/extension/utils.py +1 -0
- mage_ai/data_preparation/models/block/global_data_product/__init__.py +25 -2
- mage_ai/data_preparation/models/block/integration/__init__.py +1 -1
- mage_ai/data_preparation/models/block/remote/__init__.py +0 -0
- mage_ai/data_preparation/models/block/remote/models.py +58 -0
- mage_ai/data_preparation/models/block/sql/__init__.py +1 -1
- mage_ai/data_preparation/models/block/utils.py +38 -0
- mage_ai/data_preparation/models/constants.py +2 -0
- mage_ai/data_preparation/models/global_data_product/__init__.py +12 -0
- mage_ai/data_preparation/models/pipeline.py +31 -11
- mage_ai/data_preparation/models/triggers/__init__.py +4 -2
- mage_ai/data_preparation/models/utils.py +6 -0
- mage_ai/data_preparation/models/variable.py +18 -4
- mage_ai/data_preparation/repo_manager.py +3 -2
- mage_ai/data_preparation/shared/utils.py +1 -1
- mage_ai/data_preparation/storage/local_storage.py +12 -6
- mage_ai/data_preparation/templates/data_exporters/mysql.py +2 -2
- mage_ai/data_preparation/templates/data_exporters/oracledb.py +27 -0
- mage_ai/data_preparation/templates/repo/metadata.yaml +1 -0
- mage_ai/io/bigquery.py +131 -58
- mage_ai/io/mysql.py +38 -6
- mage_ai/io/snowflake.py +152 -29
- mage_ai/orchestration/db/migrations/versions/42a14d6143f1_update_token_column_type.py +54 -0
- mage_ai/orchestration/db/models/oauth.py +14 -13
- mage_ai/orchestration/db/models/schedules.py +30 -2
- mage_ai/orchestration/job_manager.py +6 -0
- mage_ai/orchestration/notification/sender.py +37 -15
- mage_ai/orchestration/pipeline_scheduler_original.py +48 -31
- mage_ai/orchestration/queue/celery_queue.py +8 -1
- mage_ai/orchestration/queue/process_queue.py +67 -4
- mage_ai/orchestration/queue/queue.py +8 -0
- mage_ai/orchestration/triggers/api.py +29 -1
- mage_ai/orchestration/triggers/global_data_product.py +9 -4
- mage_ai/orchestration/triggers/utils.py +10 -1
- mage_ai/orchestration/utils/resources.py +3 -0
- mage_ai/server/api/downloads.py +4 -1
- mage_ai/server/api/runs.py +151 -0
- mage_ai/server/constants.py +1 -1
- mage_ai/server/frontend_dist/404.html +6 -6
- mage_ai/server/frontend_dist/_next/static/{i8pymuJDTVHdWjUP1QSh1 → RhDiJSkcjCsh4xxX4BFBk}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/1557-b3502f3f1aa92ac7.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/3548-9d26185b3fb663b1.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/7966-b9b85ba10667e654.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-a66b4c7641ae03eb.js → frontend_dist/_next/static/chunks/pages/pipeline-runs-6d183f91a2ff6668.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7181b086c93784d2.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-cb88fd075a357fcf.js → triggers-4612d15a65c35912.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +1 -0
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js +1 -0
- mage_ai/server/{frontend_dist_base_path_template/_next/static/chunks/pages/triggers-9cba3211434a8966.js → frontend_dist/_next/static/chunks/pages/triggers-a599c6ac89be8c8d.js} +1 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +1 -0
- mage_ai/server/frontend_dist/block-layout.html +2 -2
- mage_ai/server/frontend_dist/compute.html +2 -2
- mage_ai/server/frontend_dist/files.html +2 -2
- mage_ai/server/frontend_dist/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-data-products.html +2 -2
- mage_ai/server/frontend_dist/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/index.html +2 -2
- mage_ai/server/frontend_dist/manage/files.html +2 -2
- mage_ai/server/frontend_dist/manage/settings.html +2 -2
- mage_ai/server/frontend_dist/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist/manage/users.html +2 -2
- mage_ai/server/frontend_dist/manage.html +2 -2
- mage_ai/server/frontend_dist/oauth.html +2 -2
- mage_ai/server/frontend_dist/overview.html +2 -2
- mage_ai/server/frontend_dist/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist/pipelines.html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist/settings.html +2 -2
- mage_ai/server/frontend_dist/sign-in.html +6 -6
- mage_ai/server/frontend_dist/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist/templates.html +2 -2
- mage_ai/server/frontend_dist/terminal.html +2 -2
- mage_ai/server/frontend_dist/test.html +2 -2
- mage_ai/server/frontend_dist/triggers.html +2 -2
- mage_ai/server/frontend_dist/version-control.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/404.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/_next/static/{CKCvjsYCf2imD2X8zAOBf → TdpLLFome13qvM0gXvpHs}/_buildManifest.js +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-b3502f3f1aa92ac7.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-d9200be634dd6766.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-9d26185b3fb663b1.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6d708c6b2153ea08.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-8a23dd8360593e7a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-b9b85ba10667e654.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-8b8e100079ab69e1.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-2a69553d8c6eeb53.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-4e12783b064c1cfe.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-4bfc84ff07d7656f.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/pipeline-runs-a66b4c7641ae03eb.js → frontend_dist_base_path_template/_next/static/chunks/pages/pipeline-runs-6d183f91a2ff6668.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-7181b086c93784d2.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-38e1fbcfbfc1014e.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-b645a6d13ab9fe3a.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-59aca25a5b1d3998.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-eb11c5390c982b49.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/{triggers-cb88fd075a357fcf.js → triggers-4612d15a65c35912.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-3591d035bb3bb2b8.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-32985f3f7c7dd3ab.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-c2e9ef989c8bfa73.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-349af617d05f001b.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-60d01d3887e31136.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/{users-86814e581acaf5db.js → users-a4db8710f703c729.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-09414a8b66fb6f06.js +1 -0
- mage_ai/server/{frontend_dist/_next/static/chunks/pages/triggers-9cba3211434a8966.js → frontend_dist_base_path_template/_next/static/chunks/pages/triggers-a599c6ac89be8c8d.js} +1 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-3433c8b22e8342aa.js +1 -0
- mage_ai/server/frontend_dist_base_path_template/block-layout.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/compute.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-data-products.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/index.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/files.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/[user].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users/new.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/manage.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/oauth.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/overview.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipeline-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/backfills.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/dashboard.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/edit.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/logs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors/block-runtime.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/monitors.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs/[run].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/runs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/syncs.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline]/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines/[pipeline].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/pipelines.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/platform/global-hooks.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/account/profile.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/platform/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/permissions.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/preferences.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/roles.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/sync-data.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings/workspace/users.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/settings.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/sign-in.html +6 -6
- mage_ai/server/frontend_dist_base_path_template/templates/[...slug].html +2 -2
- mage_ai/server/frontend_dist_base_path_template/templates.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/terminal.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/test.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/triggers.html +2 -2
- mage_ai/server/frontend_dist_base_path_template/version-control.html +2 -2
- mage_ai/server/scheduler_manager.py +9 -0
- mage_ai/server/server.py +47 -17
- mage_ai/server/utils/output_display.py +2 -2
- mage_ai/server/websocket_server.py +1 -0
- mage_ai/services/aws/ecs/ecs.py +1 -0
- mage_ai/services/k8s/config.py +4 -4
- mage_ai/services/k8s/utils.py +97 -0
- mage_ai/settings/keys/auth.py +2 -0
- mage_ai/settings/server.py +1 -1
- mage_ai/shared/parsers.py +6 -1
- mage_ai/streaming/sources/influxdb.py +2 -0
- mage_ai/streaming/sources/kafka.py +1 -1
- mage_ai/tests/api/endpoints/mixins.py +10 -9
- mage_ai/tests/api/endpoints/test_seeds.py +24 -0
- mage_ai/tests/api/operations/base/mixins.py +1 -1
- mage_ai/tests/api/operations/test_sessions.py +53 -2
- mage_ai/tests/api/resources/test_pipeline_resource.py +2 -2
- mage_ai/tests/authentication/oauth/test_utils.py +1 -1
- mage_ai/tests/authentication/providers/test_okta.py +43 -0
- mage_ai/tests/data_preparation/models/block/test_global_data_product.py +2 -0
- mage_ai/tests/orchestration/db/models/test_oauth.py +3 -3
- mage_ai/tests/orchestration/queue/test_process_queue.py +1 -0
- mage_ai/tests/orchestration/triggers/test_global_data_product.py +138 -136
- mage_ai/tests/server/test_server.py +27 -4
- mage_ai/tests/services/k8s/test_job_manager.py +9 -6
- mage_ai/version_control/branch/utils.py +2 -1
- mage_ai/version_control/models.py +3 -2
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.70.dist-info}/METADATA +5 -5
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.70.dist-info}/RECORD +272 -264
- mage_ai/server/frontend_dist/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/3548-961ff79ca70038c7.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/_app-08790743315de36a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/index-13760bb72d823b69.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/edit-bd0aff5a5ed8888c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/settings-d1ee961387c58b7f.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/pipelines-ceb06e1616ee9610.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/preferences-8ff16ef9566e911a.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/preferences-d7a8bc51bb7a1082.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/sign-in-f59d34429fe022ee.js +0 -1
- mage_ai/server/frontend_dist/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/1557-01f0843dc6ac4971.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/2717-b5f9575799b594d5.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/3548-961ff79ca70038c7.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/5699-6efc749f2f8ddd20.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7361-18d9d8be96e1ce97.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/7966-f07b2913f7326b50.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/9624-59b2f803f9c88cd6.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/_app-08790743315de36a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/index-13760bb72d823b69.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/manage-852d403c7bda21b3.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills/[...slug]-ff4bd7a8ec3bab40.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/backfills-a8b61d8d239fd16f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/edit-bd0aff5a5ed8888c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/settings-d1ee961387c58b7f.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines/[pipeline]/triggers/[...slug]-f028ef3880ed856c.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/pipelines-ceb06e1616ee9610.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/preferences-8ff16ef9566e911a.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/platform/settings-74d76300942dcee8.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/preferences-d7a8bc51bb7a1082.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/settings/workspace/sync-data-79a4cf66a623e667.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/sign-in-f59d34429fe022ee.js +0 -1
- mage_ai/server/frontend_dist_base_path_template/_next/static/chunks/pages/version-control-5753fac7c1bfdc88.js +0 -1
- /mage_ai/server/frontend_dist/_next/static/{i8pymuJDTVHdWjUP1QSh1 → RhDiJSkcjCsh4xxX4BFBk}/_ssgManifest.js +0 -0
- /mage_ai/server/frontend_dist_base_path_template/_next/static/{CKCvjsYCf2imD2X8zAOBf → TdpLLFome13qvM0gXvpHs}/_ssgManifest.js +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.70.dist-info}/LICENSE +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.70.dist-info}/WHEEL +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.70.dist-info}/entry_points.txt +0 -0
- {mage_ai-0.9.68.dist-info → mage_ai-0.9.70.dist-info}/top_level.txt +0 -0
|
@@ -49,6 +49,7 @@ class BackfillPresenter(BasePresenter):
|
|
|
49
49
|
):
|
|
50
50
|
pipeline_run_dates = preview_run_dates(self.model)
|
|
51
51
|
data['total_run_count'] = len(pipeline_run_dates)
|
|
52
|
+
data['run_status_counts'] = self.model.pipeline_run_status_counts
|
|
52
53
|
if include_preview_runs:
|
|
53
54
|
start_idx = offset
|
|
54
55
|
end_idx = start_idx + limit
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import os
|
|
2
|
-
from typing import Dict, List
|
|
2
|
+
from typing import Dict, List, Tuple
|
|
3
3
|
|
|
4
4
|
from mage_ai.api.errors import ApiError
|
|
5
5
|
from mage_ai.api.resources.GenericResource import GenericResource
|
|
6
6
|
from mage_ai.authentication.oauth.constants import ProviderName
|
|
7
7
|
from mage_ai.data_preparation.git import REMOTE_NAME, Git, api
|
|
8
8
|
from mage_ai.data_preparation.git.clients.base import Client as GitClient
|
|
9
|
-
from mage_ai.data_preparation.git.utils import
|
|
9
|
+
from mage_ai.data_preparation.git.utils import (
|
|
10
|
+
get_oauth_access_token_for_user,
|
|
11
|
+
get_provider_from_remote_url,
|
|
12
|
+
)
|
|
10
13
|
from mage_ai.data_preparation.preferences import get_preferences
|
|
14
|
+
from mage_ai.server.logger import Logger
|
|
11
15
|
from mage_ai.shared.path_fixer import remove_base_repo_path
|
|
12
16
|
from mage_ai.shared.strings import capitalize_remove_underscore_lower
|
|
13
17
|
|
|
18
|
+
logger = Logger().new_server_logger(__name__)
|
|
19
|
+
|
|
14
20
|
|
|
15
21
|
def build_file_object(obj):
|
|
16
22
|
arr = []
|
|
@@ -53,7 +59,7 @@ class GitBranchResource(GenericResource):
|
|
|
53
59
|
if remote_url:
|
|
54
60
|
provider = get_provider_from_remote_url(remote_url)
|
|
55
61
|
|
|
56
|
-
access_token =
|
|
62
|
+
access_token = get_oauth_access_token_for_user(user, provider=provider)
|
|
57
63
|
if access_token:
|
|
58
64
|
branches = GitClient.get_client_for_provider(provider)(
|
|
59
65
|
access_token.token
|
|
@@ -64,7 +70,15 @@ class GitBranchResource(GenericResource):
|
|
|
64
70
|
arr += [dict(name=branch) for branch in git_manager.branches]
|
|
65
71
|
|
|
66
72
|
if include_remote_branches:
|
|
67
|
-
|
|
73
|
+
try:
|
|
74
|
+
git_manager.fetch()
|
|
75
|
+
mage_remote = git_manager.origin
|
|
76
|
+
arr += [
|
|
77
|
+
dict(name=ref.name)
|
|
78
|
+
for ref in mage_remote.refs
|
|
79
|
+
]
|
|
80
|
+
except Exception:
|
|
81
|
+
logger.warning('Failed to fetch remote branches')
|
|
68
82
|
|
|
69
83
|
return self.build_result_set(
|
|
70
84
|
arr,
|
|
@@ -123,32 +137,27 @@ class GitBranchResource(GenericResource):
|
|
|
123
137
|
**kwargs,
|
|
124
138
|
)
|
|
125
139
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
files = payload.get('files', None)
|
|
136
|
-
message = payload.get('message', None)
|
|
137
|
-
|
|
140
|
+
@classmethod
|
|
141
|
+
def get_oauth_config(
|
|
142
|
+
cls,
|
|
143
|
+
remote_url: str = None,
|
|
144
|
+
remote_name: str = None,
|
|
145
|
+
user=None,
|
|
146
|
+
) -> Tuple[str, str, str, Dict]:
|
|
147
|
+
git_manager = cls.get_git_manager(user=user)
|
|
138
148
|
url = None
|
|
139
|
-
remote_url = query.get('remote_url', None)
|
|
140
149
|
if remote_url:
|
|
141
|
-
url = remote_url
|
|
142
|
-
elif
|
|
143
|
-
remote = git_manager.repo.remotes[
|
|
150
|
+
url = remote_url
|
|
151
|
+
elif remote_name:
|
|
152
|
+
remote = git_manager.repo.remotes[remote_name]
|
|
144
153
|
url = list(remote.urls)[0]
|
|
145
154
|
|
|
146
155
|
provider = ProviderName.GITHUB
|
|
147
156
|
if url:
|
|
148
157
|
provider = get_provider_from_remote_url(url)
|
|
149
158
|
|
|
150
|
-
access_token =
|
|
151
|
-
|
|
159
|
+
access_token = get_oauth_access_token_for_user(
|
|
160
|
+
user, provider=provider
|
|
152
161
|
)
|
|
153
162
|
http_access_token = git_manager.get_access_token()
|
|
154
163
|
|
|
@@ -159,7 +168,7 @@ class GitBranchResource(GenericResource):
|
|
|
159
168
|
user_from_api = api.get_user(token, provider=provider)
|
|
160
169
|
# Default to mage user email if no email is returned from API
|
|
161
170
|
email = user_from_api.get(
|
|
162
|
-
'email',
|
|
171
|
+
'email', user.email if user else None
|
|
163
172
|
)
|
|
164
173
|
config_overwrite = dict(
|
|
165
174
|
username=user_from_api.get('username'),
|
|
@@ -168,6 +177,30 @@ class GitBranchResource(GenericResource):
|
|
|
168
177
|
elif http_access_token:
|
|
169
178
|
token = http_access_token
|
|
170
179
|
|
|
180
|
+
return token, provider, url, config_overwrite
|
|
181
|
+
|
|
182
|
+
async def update(self, payload, **kwargs):
|
|
183
|
+
query = kwargs.get('query') or {}
|
|
184
|
+
|
|
185
|
+
git_manager = self.get_git_manager(user=self.current_user)
|
|
186
|
+
action_type = payload.get('action_type')
|
|
187
|
+
action_payload = payload.get('action_payload', dict())
|
|
188
|
+
action_remote = action_payload.get('remote', None)
|
|
189
|
+
action_branch = action_payload.get('branch', None)
|
|
190
|
+
|
|
191
|
+
files = payload.get('files', None)
|
|
192
|
+
message = payload.get('message', None)
|
|
193
|
+
|
|
194
|
+
remote_url = query.get('remote_url', None)
|
|
195
|
+
if remote_url:
|
|
196
|
+
remote_url = remote_url[0]
|
|
197
|
+
|
|
198
|
+
token, provider, url, config_overwrite = self.get_oauth_config(
|
|
199
|
+
remote_url=remote_url,
|
|
200
|
+
remote_name=action_remote,
|
|
201
|
+
user=self.current_user,
|
|
202
|
+
)
|
|
203
|
+
|
|
171
204
|
# Recreate git manager with updated config
|
|
172
205
|
git_manager = self.get_git_manager(
|
|
173
206
|
user=self.current_user, config_overwrite=config_overwrite
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
from typing import Dict, List
|
|
2
2
|
|
|
3
3
|
from mage_ai.api.resources.GitBranchResource import GitBranchResource
|
|
4
|
-
from mage_ai.data_preparation.git import REMOTE_NAME, Git
|
|
4
|
+
from mage_ai.data_preparation.git import REMOTE_NAME, Git, api
|
|
5
5
|
from mage_ai.data_preparation.sync import AuthType
|
|
6
6
|
|
|
7
7
|
|
|
@@ -17,6 +17,34 @@ class GitCustomBranchResource(GitBranchResource):
|
|
|
17
17
|
user=user,
|
|
18
18
|
)
|
|
19
19
|
|
|
20
|
+
@classmethod
|
|
21
|
+
def create(cls, payload, user, **kwargs):
|
|
22
|
+
branch = payload.get('name')
|
|
23
|
+
remote = payload.get('remote')
|
|
24
|
+
|
|
25
|
+
token, _, url, config_overwrite = cls.get_oauth_config(
|
|
26
|
+
remote_name=remote,
|
|
27
|
+
user=user,
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
git_manager = cls.get_git_manager(
|
|
31
|
+
user=user, config_overwrite=config_overwrite
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
if remote:
|
|
35
|
+
api.switch_branch(
|
|
36
|
+
remote,
|
|
37
|
+
url,
|
|
38
|
+
branch,
|
|
39
|
+
token,
|
|
40
|
+
config_overwrite=config_overwrite,
|
|
41
|
+
user=user,
|
|
42
|
+
)
|
|
43
|
+
else:
|
|
44
|
+
git_manager.switch_branch(branch)
|
|
45
|
+
|
|
46
|
+
return cls(dict(name=git_manager.current_branch), user, **kwargs)
|
|
47
|
+
|
|
20
48
|
@classmethod
|
|
21
49
|
async def member(self, pk, user, **kwargs):
|
|
22
50
|
resource = await GitBranchResource.member(pk, user, **kwargs)
|
|
@@ -20,7 +20,7 @@ from mage_ai.authentication.oauth.utils import (
|
|
|
20
20
|
refresh_token_for_client,
|
|
21
21
|
)
|
|
22
22
|
from mage_ai.authentication.providers.constants import NAME_TO_PROVIDER
|
|
23
|
-
from mage_ai.data_preparation.git.
|
|
23
|
+
from mage_ai.data_preparation.git.utils import get_oauth_client_id
|
|
24
24
|
from mage_ai.orchestration.db import safe_db_query
|
|
25
25
|
from mage_ai.orchestration.db.models.oauth import Oauth2AccessToken, Oauth2Application
|
|
26
26
|
|
|
@@ -119,6 +119,12 @@ class PipelineResource(BaseResource):
|
|
|
119
119
|
if include_schedules:
|
|
120
120
|
include_schedules = include_schedules[0]
|
|
121
121
|
|
|
122
|
+
repo_path = query.get('repo_path', [None])
|
|
123
|
+
if repo_path:
|
|
124
|
+
repo_path = repo_path[0]
|
|
125
|
+
if not repo_path:
|
|
126
|
+
repo_path = get_repo_path(root_project=False)
|
|
127
|
+
|
|
122
128
|
search_query = query.get('search', [None])
|
|
123
129
|
if search_query:
|
|
124
130
|
search_query = search_query[0]
|
|
@@ -174,11 +180,11 @@ class PipelineResource(BaseResource):
|
|
|
174
180
|
|
|
175
181
|
if NO_TAGS_QUERY in tags:
|
|
176
182
|
pipeline_uuids_with_tags = set(cache.get_all_pipeline_uuids_with_tags())
|
|
177
|
-
all_pipeline_uuids = set(Pipeline.get_all_pipelines(
|
|
183
|
+
all_pipeline_uuids = set(Pipeline.get_all_pipelines(repo_path))
|
|
178
184
|
pipeline_uuids_without_tags = list(all_pipeline_uuids - pipeline_uuids_with_tags)
|
|
179
185
|
pipeline_uuids = pipeline_uuids + pipeline_uuids_without_tags
|
|
180
186
|
else:
|
|
181
|
-
pipeline_uuids = Pipeline.get_all_pipelines(
|
|
187
|
+
pipeline_uuids = Pipeline.get_all_pipelines(repo_path)
|
|
182
188
|
|
|
183
189
|
if search_query:
|
|
184
190
|
pipeline_uuids = list(filter(
|
|
@@ -206,7 +212,7 @@ class PipelineResource(BaseResource):
|
|
|
206
212
|
|
|
207
213
|
async def get_pipeline(uuid: str) -> Pipeline:
|
|
208
214
|
try:
|
|
209
|
-
return await Pipeline.get_async(uuid)
|
|
215
|
+
return await Pipeline.get_async(uuid, repo_path=repo_path)
|
|
210
216
|
except Exception as err:
|
|
211
217
|
err_message = f'Error loading pipeline {uuid}: {err}.'
|
|
212
218
|
if err.__class__.__name__ == 'OSError' and 'Too many open files' in err.strerror:
|
|
@@ -217,7 +223,7 @@ class PipelineResource(BaseResource):
|
|
|
217
223
|
|
|
218
224
|
def get_pipeline_with_config(uuid, config: Dict) -> Pipeline:
|
|
219
225
|
try:
|
|
220
|
-
return Pipeline(uuid, config=config)
|
|
226
|
+
return Pipeline(uuid, config=config, repo_path=repo_path)
|
|
221
227
|
except Exception as err:
|
|
222
228
|
err_message = f'Error loading pipeline sync {uuid}: {err}.'
|
|
223
229
|
if err.__class__.__name__ == 'OSError' and 'Too many open files' in err.strerror:
|
|
@@ -239,7 +245,7 @@ class PipelineResource(BaseResource):
|
|
|
239
245
|
))
|
|
240
246
|
else:
|
|
241
247
|
for uuid in pipeline_uuids:
|
|
242
|
-
pipeline_dict = cache.get_model(dict(uuid=uuid))
|
|
248
|
+
pipeline_dict = cache.get_model(dict(uuid=uuid, repo_path=repo_path))
|
|
243
249
|
if pipeline_dict and pipeline_dict.get('pipeline'):
|
|
244
250
|
pipeline = get_pipeline_with_config(uuid, pipeline_dict['pipeline'])
|
|
245
251
|
if pipeline:
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from sqlalchemy import and_, desc, func
|
|
1
2
|
from sqlalchemy.orm import selectinload
|
|
2
3
|
|
|
3
4
|
from mage_ai.api.operations.constants import META_KEY_LIMIT, META_KEY_OFFSET
|
|
@@ -5,7 +6,10 @@ from mage_ai.api.resources.DatabaseResource import DatabaseResource
|
|
|
5
6
|
from mage_ai.api.utils import get_query_timestamps
|
|
6
7
|
from mage_ai.cache.tag import TagCache
|
|
7
8
|
from mage_ai.data_preparation.models.block.utils import get_all_descendants
|
|
8
|
-
from mage_ai.data_preparation.models.constants import
|
|
9
|
+
from mage_ai.data_preparation.models.constants import (
|
|
10
|
+
PIPELINE_RUN_STATUS_LAST_RUN_FAILED,
|
|
11
|
+
PipelineType,
|
|
12
|
+
)
|
|
9
13
|
from mage_ai.data_preparation.models.pipeline import Pipeline
|
|
10
14
|
from mage_ai.data_preparation.models.triggers import (
|
|
11
15
|
ScheduleInterval,
|
|
@@ -94,9 +98,38 @@ class PipelineRunResource(DatabaseResource):
|
|
|
94
98
|
|
|
95
99
|
repo_pipeline_schedule_ids = [s.id for s in PipelineSchedule.repo_query]
|
|
96
100
|
|
|
101
|
+
if status == PIPELINE_RUN_STATUS_LAST_RUN_FAILED:
|
|
102
|
+
"""
|
|
103
|
+
The initial query below is used to get the last pipeline run retry
|
|
104
|
+
(or individual pipeline run if there are no retries) for each
|
|
105
|
+
grouping of pipeline runs with the same execution_date,
|
|
106
|
+
pipeline_uuid, and pipeline_schedule_id.
|
|
107
|
+
"""
|
|
108
|
+
latest_pipeline_runs = PipelineRun.select(
|
|
109
|
+
PipelineRun.id,
|
|
110
|
+
func.row_number()
|
|
111
|
+
.over(
|
|
112
|
+
partition_by=(
|
|
113
|
+
PipelineRun.execution_date,
|
|
114
|
+
PipelineRun.pipeline_schedule_id,
|
|
115
|
+
PipelineRun.pipeline_uuid,
|
|
116
|
+
),
|
|
117
|
+
order_by=desc(PipelineRun.id))
|
|
118
|
+
.label('row_number')
|
|
119
|
+
).cte(name='latest_pipeline_runs')
|
|
120
|
+
query = (PipelineRun.select(
|
|
121
|
+
PipelineRun,
|
|
122
|
+
)
|
|
123
|
+
.join(latest_pipeline_runs, and_(
|
|
124
|
+
PipelineRun.id == latest_pipeline_runs.c.id,
|
|
125
|
+
latest_pipeline_runs.c.row_number == 1,
|
|
126
|
+
))
|
|
127
|
+
)
|
|
128
|
+
else:
|
|
129
|
+
query = PipelineRun.query
|
|
130
|
+
|
|
97
131
|
results = (
|
|
98
|
-
|
|
99
|
-
.query
|
|
132
|
+
query
|
|
100
133
|
.filter(PipelineRun.pipeline_schedule_id.in_(repo_pipeline_schedule_ids))
|
|
101
134
|
.options(selectinload(PipelineRun.block_runs))
|
|
102
135
|
.options(selectinload(PipelineRun.pipeline_schedule))
|
|
@@ -120,8 +153,12 @@ class PipelineRunResource(DatabaseResource):
|
|
|
120
153
|
results = results.filter(PipelineRun.pipeline_uuid.in_(pipeline_uuids))
|
|
121
154
|
if pipeline_uuids_with_tags:
|
|
122
155
|
results = results.filter(PipelineRun.pipeline_uuid.in_(pipeline_uuids_with_tags))
|
|
123
|
-
|
|
156
|
+
|
|
157
|
+
if status == PIPELINE_RUN_STATUS_LAST_RUN_FAILED:
|
|
158
|
+
results = results.filter(PipelineRun.status == PipelineRun.PipelineRunStatus.FAILED)
|
|
159
|
+
elif status is not None:
|
|
124
160
|
results = results.filter(PipelineRun.status == status)
|
|
161
|
+
|
|
125
162
|
if statuses:
|
|
126
163
|
results = results.filter(PipelineRun.status.in_(statuses))
|
|
127
164
|
if start_timestamp is not None:
|
|
@@ -403,6 +403,8 @@ class PipelineScheduleResource(DatabaseResource):
|
|
|
403
403
|
if updated_status == ScheduleStatus.ACTIVE and self.model.status == ScheduleStatus.INACTIVE:
|
|
404
404
|
payload['last_enabled_at'] = datetime.now(tz=pytz.UTC)
|
|
405
405
|
|
|
406
|
+
old_name = self.model.name
|
|
407
|
+
|
|
406
408
|
resource = super().update(payload)
|
|
407
409
|
updated_model = resource.model
|
|
408
410
|
|
|
@@ -424,11 +426,13 @@ class PipelineScheduleResource(DatabaseResource):
|
|
|
424
426
|
update_only_if_exists = (
|
|
425
427
|
not pipeline.should_save_trigger_in_code_automatically()
|
|
426
428
|
)
|
|
429
|
+
old_trigger_name = old_name if old_name != updated_model.name else None
|
|
427
430
|
|
|
428
431
|
add_or_update_trigger_for_pipeline_and_persist(
|
|
429
432
|
trigger,
|
|
430
433
|
pipeline.uuid,
|
|
431
434
|
update_only_if_exists=update_only_if_exists,
|
|
435
|
+
old_trigger_name=old_trigger_name,
|
|
432
436
|
)
|
|
433
437
|
|
|
434
438
|
return self
|
|
@@ -3,9 +3,11 @@ from typing import Dict
|
|
|
3
3
|
from mage_ai.api.errors import ApiError
|
|
4
4
|
from mage_ai.api.resources.GenericResource import GenericResource
|
|
5
5
|
from mage_ai.authentication.oauth.constants import ProviderName
|
|
6
|
-
from mage_ai.data_preparation.git import api
|
|
7
6
|
from mage_ai.data_preparation.git.clients.base import Client as GitClient
|
|
8
|
-
from mage_ai.data_preparation.git.utils import
|
|
7
|
+
from mage_ai.data_preparation.git.utils import (
|
|
8
|
+
get_oauth_access_token_for_user,
|
|
9
|
+
get_provider_from_remote_url,
|
|
10
|
+
)
|
|
9
11
|
|
|
10
12
|
|
|
11
13
|
def pull_request_to_dict(pr) -> Dict:
|
|
@@ -40,7 +42,7 @@ class PullRequestResource(GenericResource):
|
|
|
40
42
|
if remote_url:
|
|
41
43
|
provider = get_provider_from_remote_url(remote_url)
|
|
42
44
|
|
|
43
|
-
access_token =
|
|
45
|
+
access_token = get_oauth_access_token_for_user(user, provider=provider)
|
|
44
46
|
|
|
45
47
|
if access_token:
|
|
46
48
|
arr = GitClient.get_client_for_provider(provider)(
|
|
@@ -84,7 +86,7 @@ class PullRequestResource(GenericResource):
|
|
|
84
86
|
remote_url = payload.get('remote_url')
|
|
85
87
|
provider = get_provider_from_remote_url(remote_url)
|
|
86
88
|
|
|
87
|
-
access_token =
|
|
89
|
+
access_token = get_oauth_access_token_for_user(user, provider=provider)
|
|
88
90
|
if not access_token:
|
|
89
91
|
error.update(
|
|
90
92
|
dict(
|
|
@@ -6,6 +6,7 @@ class SeedResource(GenericResource):
|
|
|
6
6
|
@classmethod
|
|
7
7
|
async def create(self, payload, user, **kwargs):
|
|
8
8
|
if payload.get('roles') and payload.get('permissions'):
|
|
9
|
-
|
|
9
|
+
policy_names = payload.get('policy_names')
|
|
10
|
+
await bootstrap_permissions(policy_names=policy_names)
|
|
10
11
|
|
|
11
12
|
return self({}, user, **kwargs)
|
|
@@ -11,9 +11,10 @@ from mage_ai.orchestration.db.models.oauth import Role, User
|
|
|
11
11
|
from mage_ai.settings import (
|
|
12
12
|
AUTHENTICATION_MODE,
|
|
13
13
|
OAUTH_DEFAULT_ACCESS,
|
|
14
|
+
get_bool_value,
|
|
14
15
|
get_settings_value,
|
|
15
16
|
)
|
|
16
|
-
from mage_ai.settings.keys import LDAP_DEFAULT_ACCESS
|
|
17
|
+
from mage_ai.settings.keys import LDAP_DEFAULT_ACCESS, UPDATE_ROLES_ON_LOGIN
|
|
17
18
|
from mage_ai.usage_statistics.logger import UsageStatisticLogger
|
|
18
19
|
|
|
19
20
|
|
|
@@ -29,6 +30,9 @@ class SessionResource(BaseResource):
|
|
|
29
30
|
|
|
30
31
|
oauth_client = kwargs.get('oauth_client')
|
|
31
32
|
|
|
33
|
+
update_roles_on_login = get_bool_value(
|
|
34
|
+
get_settings_value(UPDATE_ROLES_ON_LOGIN, default='False'))
|
|
35
|
+
|
|
32
36
|
# Oauth sign in
|
|
33
37
|
if token and provider:
|
|
34
38
|
roles = []
|
|
@@ -57,6 +61,9 @@ class SessionResource(BaseResource):
|
|
|
57
61
|
email=email,
|
|
58
62
|
roles_new=roles,
|
|
59
63
|
)
|
|
64
|
+
elif update_roles_on_login and roles:
|
|
65
|
+
user.update(roles_new=roles)
|
|
66
|
+
|
|
60
67
|
oauth_token = generate_access_token(user, oauth_client)
|
|
61
68
|
return self(oauth_token, user, **kwargs)
|
|
62
69
|
|
|
@@ -109,6 +116,11 @@ class SessionResource(BaseResource):
|
|
|
109
116
|
roles_new=roles,
|
|
110
117
|
username=email,
|
|
111
118
|
)
|
|
119
|
+
elif update_roles_on_login:
|
|
120
|
+
role_names = conn.get_user_roles(user_attributes)
|
|
121
|
+
if role_names:
|
|
122
|
+
roles = Role.query.filter(Role.name.in_(role_names)).all()
|
|
123
|
+
user.update(roles_new=roles)
|
|
112
124
|
|
|
113
125
|
oauth_token = generate_access_token(user, kwargs['oauth_client'])
|
|
114
126
|
return self(oauth_token, user, **kwargs)
|
|
@@ -123,14 +123,15 @@ class WorkspaceResource(GenericResource):
|
|
|
123
123
|
error = ApiError.RESOURCE_ERROR.copy()
|
|
124
124
|
try:
|
|
125
125
|
action = payload.pop('action')
|
|
126
|
-
args = ignore_keys(payload, ['name', 'cluster_type'])
|
|
127
126
|
if action == 'stop':
|
|
128
|
-
workspace.stop(**
|
|
127
|
+
workspace.stop(**payload)
|
|
129
128
|
elif action == 'resume':
|
|
130
|
-
workspace.resume(**
|
|
129
|
+
workspace.resume(**payload)
|
|
130
|
+
elif action == 'patch':
|
|
131
|
+
workspace.update(payload)
|
|
131
132
|
elif action == 'add_to_ingress':
|
|
132
133
|
if isinstance(workspace, KubernetesWorkspace):
|
|
133
|
-
workspace.add_to_ingress(**
|
|
134
|
+
workspace.add_to_ingress(**payload)
|
|
134
135
|
else:
|
|
135
136
|
raise Exception('This workspace does not support ingress.')
|
|
136
137
|
except Exception as ex:
|
|
@@ -27,6 +27,7 @@ class EntityName(str, Enum):
|
|
|
27
27
|
CustomTemplate = 'CustomTemplate'
|
|
28
28
|
DataProvider = 'DataProvider'
|
|
29
29
|
Database = 'Database'
|
|
30
|
+
Download = 'Download'
|
|
30
31
|
EventMatcher = 'EventMatcher'
|
|
31
32
|
EventRule = 'EventRule'
|
|
32
33
|
ExecutionState = 'ExecutionState'
|
|
@@ -68,6 +69,7 @@ class EntityName(str, Enum):
|
|
|
68
69
|
Scheduler = 'Scheduler'
|
|
69
70
|
SearchResult = 'SearchResult'
|
|
70
71
|
Secret = 'Secret'
|
|
72
|
+
Seed = 'Seed'
|
|
71
73
|
Session = 'Session'
|
|
72
74
|
SparkApplication = 'SparkApplication'
|
|
73
75
|
SparkEnvironment = 'SparkEnvironment'
|
|
@@ -171,13 +171,17 @@ async def action_rules(policy_class):
|
|
|
171
171
|
if scope not in operations_mapping:
|
|
172
172
|
operations_mapping[scope] = {}
|
|
173
173
|
|
|
174
|
-
|
|
175
|
-
|
|
174
|
+
if not isinstance(config2, list):
|
|
175
|
+
config2 = [config2]
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
177
|
+
for c in config2:
|
|
178
|
+
condition = c.get('condition')
|
|
179
|
+
key = await get_key(policy_class, condition)
|
|
180
|
+
|
|
181
|
+
if key not in operations_mapping[scope]:
|
|
182
|
+
operations_mapping[scope][key] = []
|
|
179
183
|
|
|
180
|
-
|
|
184
|
+
operations_mapping[scope][key].append(operation)
|
|
181
185
|
|
|
182
186
|
return operations_mapping
|
|
183
187
|
|
|
@@ -202,34 +206,40 @@ async def attribute_rules(policy_class, rules):
|
|
|
202
206
|
if config2 is None:
|
|
203
207
|
continue
|
|
204
208
|
|
|
205
|
-
|
|
206
|
-
|
|
209
|
+
if not isinstance(config2, list):
|
|
210
|
+
config2 = [config2]
|
|
211
|
+
|
|
212
|
+
for c in config2:
|
|
213
|
+
condition = c.get('condition')
|
|
214
|
+
key = await get_key(policy_class, condition)
|
|
207
215
|
|
|
208
|
-
|
|
209
|
-
|
|
216
|
+
if key not in mapping[scope]:
|
|
217
|
+
mapping[scope][key] = {}
|
|
210
218
|
|
|
211
|
-
|
|
212
|
-
|
|
219
|
+
if operation not in mapping[scope][key]:
|
|
220
|
+
mapping[scope][key][operation] = []
|
|
213
221
|
|
|
214
|
-
|
|
222
|
+
mapping[scope][key][operation].append(attribute)
|
|
215
223
|
|
|
216
224
|
return mapping
|
|
217
225
|
|
|
218
226
|
|
|
219
|
-
async def bootstrap_permissions():
|
|
227
|
+
async def bootstrap_permissions(policy_names: str = None):
|
|
220
228
|
action_rules_mapping = {}
|
|
221
229
|
query_rules_mapping = {}
|
|
222
230
|
read_rules_mapping = {}
|
|
223
231
|
write_rules_mapping = {}
|
|
224
232
|
|
|
225
|
-
policy_names
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
'
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
+
if policy_names is None:
|
|
234
|
+
policy_names = []
|
|
235
|
+
for n in os.listdir(policies.__path__[0]):
|
|
236
|
+
if n.endswith('Policy.py') and n not in [
|
|
237
|
+
'AsyncBasePolicy.py',
|
|
238
|
+
'BasePolicy.py',
|
|
239
|
+
'SeedPolicy.py',
|
|
240
|
+
'UserPolicy.py',
|
|
241
|
+
]:
|
|
242
|
+
policy_names.append(n.replace('Policy.py', ''))
|
|
233
243
|
|
|
234
244
|
for policy_name in policy_names:
|
|
235
245
|
policy_class = getattr(
|
|
@@ -238,6 +248,7 @@ async def bootstrap_permissions():
|
|
|
238
248
|
)
|
|
239
249
|
|
|
240
250
|
model_name = policy_class.model_name()
|
|
251
|
+
print(f'Processing {model_name}...')
|
|
241
252
|
action_rules_mapping[model_name] = await action_rules(policy_class)
|
|
242
253
|
query_rules_mapping[model_name] = await attribute_rules(
|
|
243
254
|
policy_class,
|
|
@@ -34,10 +34,11 @@ class ADProvider(SsoProvider, OauthProvider):
|
|
|
34
34
|
self.client_secret = get_settings_value(ACTIVE_DIRECTORY_CLIENT_SECRET)
|
|
35
35
|
self.__validate()
|
|
36
36
|
|
|
37
|
-
self.roles_mapping =
|
|
38
|
-
|
|
37
|
+
self.roles_mapping = {}
|
|
38
|
+
roles_mapping = get_settings_value(ACTIVE_DIRECTORY_ROLES_MAPPING)
|
|
39
|
+
if roles_mapping:
|
|
39
40
|
try:
|
|
40
|
-
self.roles_mapping = json.loads(
|
|
41
|
+
self.roles_mapping = json.loads(roles_mapping)
|
|
41
42
|
except Exception:
|
|
42
43
|
logger.exception('Failed to parse roles mapping.')
|
|
43
44
|
|