@datarecce/ui 0.1.30 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.d.mts +1 -1
- package/dist/api.d.ts +1 -1
- package/dist/components.d.mts +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/hooks.d.mts +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/{index-BNUP2V_N.d.ts → index-B9lSPJTi.d.ts} +184 -2
- package/dist/index-B9lSPJTi.d.ts.map +1 -0
- package/dist/{index-DOPZuhD8.d.mts → index-IIXVIoOL.d.mts} +253 -71
- package/dist/index-IIXVIoOL.d.mts.map +1 -0
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -2
- package/dist/index.mjs.map +1 -1
- package/dist/styles.css +4 -0
- package/dist/theme.d.mts +2 -185
- package/dist/theme.d.ts +2 -185
- package/dist/types.d.mts +1 -1
- package/dist/types.d.ts +1 -1
- package/package.json +4 -2
- package/recce-source/.editorconfig +26 -0
- package/recce-source/.flake8 +37 -0
- package/recce-source/.github/ISSUE_TEMPLATE/bug_report.yml +67 -0
- package/recce-source/.github/ISSUE_TEMPLATE/custom.md +10 -0
- package/recce-source/.github/ISSUE_TEMPLATE/feature_request.yml +42 -0
- package/recce-source/.github/PULL_REQUEST_TEMPLATE.md +21 -0
- package/recce-source/.github/copilot-instructions.md +331 -0
- package/recce-source/.github/instructions/backend-instructions.md +541 -0
- package/recce-source/.github/instructions/frontend-instructions.md +317 -0
- package/recce-source/.github/workflows/build-statics.yaml +72 -0
- package/recce-source/.github/workflows/bump.yaml +48 -0
- package/recce-source/.github/workflows/integration-tests-cloud.yaml +92 -0
- package/recce-source/.github/workflows/integration-tests-sqlmesh.yaml +33 -0
- package/recce-source/.github/workflows/integration-tests.yaml +52 -0
- package/recce-source/.github/workflows/nightly.yaml +246 -0
- package/recce-source/.github/workflows/release.yaml +196 -0
- package/recce-source/.github/workflows/tests-js.yaml +58 -0
- package/recce-source/.github/workflows/tests-python.yaml +128 -0
- package/recce-source/.pre-commit-config.yaml +26 -0
- package/recce-source/CLAUDE.md +483 -0
- package/recce-source/CODE_OF_CONDUCT.md +128 -0
- package/recce-source/CONTRIBUTING.md +107 -0
- package/recce-source/LICENSE +201 -0
- package/recce-source/Makefile +126 -0
- package/recce-source/README.md +182 -0
- package/recce-source/RECCE_CLOUD.md +81 -0
- package/recce-source/SECURITY.md +25 -0
- package/recce-source/docs/PACKAGING.md +340 -0
- package/recce-source/docs/README.md +1 -0
- package/recce-source/integration_tests/dbt/dbt_project.yml +26 -0
- package/recce-source/integration_tests/dbt/models/customers.sql +69 -0
- package/recce-source/integration_tests/dbt/models/docs.md +14 -0
- package/recce-source/integration_tests/dbt/models/orders.sql +56 -0
- package/recce-source/integration_tests/dbt/models/schema.yml +82 -0
- package/recce-source/integration_tests/dbt/models/staging/schema.yml +31 -0
- package/recce-source/integration_tests/dbt/models/staging/stg_customers.sql +22 -0
- package/recce-source/integration_tests/dbt/models/staging/stg_orders.sql +23 -0
- package/recce-source/integration_tests/dbt/models/staging/stg_payments.sql +25 -0
- package/recce-source/integration_tests/dbt/packages.yml +7 -0
- package/recce-source/integration_tests/dbt/profiles.yml +8 -0
- package/recce-source/integration_tests/dbt/seeds/raw_customers.csv +101 -0
- package/recce-source/integration_tests/dbt/seeds/raw_orders.csv +100 -0
- package/recce-source/integration_tests/dbt/seeds/raw_payments.csv +114 -0
- package/recce-source/integration_tests/dbt/seeds/raw_statuses.csv +5 -0
- package/recce-source/integration_tests/dbt/smoke_test.sh +72 -0
- package/recce-source/integration_tests/dbt/smoke_test_cloud.sh +71 -0
- package/recce-source/integration_tests/sqlmesh/__init__.py +0 -0
- package/recce-source/integration_tests/sqlmesh/audits/assert_item_price_above_zero.sql +9 -0
- package/recce-source/integration_tests/sqlmesh/audits/items.sql +7 -0
- package/recce-source/integration_tests/sqlmesh/audits/order_items.sql +7 -0
- package/recce-source/integration_tests/sqlmesh/config.py +171 -0
- package/recce-source/integration_tests/sqlmesh/helper.py +20 -0
- package/recce-source/integration_tests/sqlmesh/hooks/__init__.py +0 -0
- package/recce-source/integration_tests/sqlmesh/macros/__init__.py +0 -0
- package/recce-source/integration_tests/sqlmesh/macros/macros.py +8 -0
- package/recce-source/integration_tests/sqlmesh/macros/macros.sql +8 -0
- package/recce-source/integration_tests/sqlmesh/macros/utils.py +11 -0
- package/recce-source/integration_tests/sqlmesh/metrics/metrics.sql +25 -0
- package/recce-source/integration_tests/sqlmesh/models/customer_revenue_by_day.sql +41 -0
- package/recce-source/integration_tests/sqlmesh/models/customer_revenue_lifetime.sql +60 -0
- package/recce-source/integration_tests/sqlmesh/models/customers.sql +32 -0
- package/recce-source/integration_tests/sqlmesh/models/items.py +95 -0
- package/recce-source/integration_tests/sqlmesh/models/marketing.sql +15 -0
- package/recce-source/integration_tests/sqlmesh/models/order_items.py +95 -0
- package/recce-source/integration_tests/sqlmesh/models/orders.py +70 -0
- package/recce-source/integration_tests/sqlmesh/models/raw_marketing.py +62 -0
- package/recce-source/integration_tests/sqlmesh/models/top_waiters.sql +23 -0
- package/recce-source/integration_tests/sqlmesh/models/waiter_as_customer_by_day.sql +29 -0
- package/recce-source/integration_tests/sqlmesh/models/waiter_names.sql +10 -0
- package/recce-source/integration_tests/sqlmesh/models/waiter_revenue_by_day.sql +29 -0
- package/recce-source/integration_tests/sqlmesh/models/waiters.py +62 -0
- package/recce-source/integration_tests/sqlmesh/prep_env.sh +16 -0
- package/recce-source/integration_tests/sqlmesh/schema.yaml +5 -0
- package/recce-source/integration_tests/sqlmesh/seeds/waiter_names.csv +11 -0
- package/recce-source/integration_tests/sqlmesh/test_server.sh +29 -0
- package/recce-source/integration_tests/sqlmesh/tests/test_customer_revenue_by_day.yaml +63 -0
- package/recce-source/integration_tests/sqlmesh/tests/test_order_items.yaml +72 -0
- package/recce-source/js/.editorconfig +27 -0
- package/recce-source/js/.env.development +5 -0
- package/recce-source/js/.husky/pre-commit +29 -0
- package/recce-source/js/.nvmrc +1 -0
- package/recce-source/js/README.md +39 -0
- package/recce-source/js/app/(mainComponents)/DisplayModeToggle.tsx +65 -0
- package/recce-source/js/app/(mainComponents)/NavBar.tsx +228 -0
- package/recce-source/js/app/(mainComponents)/RecceVersionBadge.tsx +107 -0
- package/recce-source/js/app/(mainComponents)/TopBar.tsx +252 -0
- package/recce-source/js/app/@lineage/default.tsx +20 -0
- package/recce-source/js/app/@lineage/page.tsx +14 -0
- package/recce-source/js/app/MainLayout.tsx +170 -0
- package/recce-source/js/app/Providers.tsx +49 -0
- package/recce-source/js/app/checks/page.tsx +296 -0
- package/recce-source/js/app/error.tsx +93 -0
- package/recce-source/js/app/favicon.ico +0 -0
- package/recce-source/js/app/global-error.tsx +115 -0
- package/recce-source/js/app/global.css +82 -0
- package/recce-source/js/app/layout.tsx +48 -0
- package/recce-source/js/app/lineage/page.tsx +15 -0
- package/recce-source/js/app/page.tsx +12 -0
- package/recce-source/js/app/query/page.tsx +8 -0
- package/recce-source/js/biome.json +313 -0
- package/recce-source/js/jest.config.js +34 -0
- package/recce-source/js/jest.globals.d.ts +32 -0
- package/recce-source/js/jest.setup.js +91 -0
- package/recce-source/js/next.config.js +16 -0
- package/recce-source/js/package-lock.json +13843 -0
- package/recce-source/js/package.json +123 -0
- package/recce-source/js/pnpm-lock.yaml +9235 -0
- package/recce-source/js/pnpm-workspace.yaml +6 -0
- package/recce-source/js/postcss.config.js +5 -0
- package/recce-source/js/public/auth_callback.html +68 -0
- package/recce-source/js/public/imgs/feedback/thumbs-down.png +0 -0
- package/recce-source/js/public/imgs/feedback/thumbs-up.png +0 -0
- package/recce-source/js/public/imgs/reload-image.svg +4 -0
- package/recce-source/js/public/logo/recce-logo-white.png +0 -0
- package/recce-source/js/src/components/AuthModal/AuthModal.tsx +202 -0
- package/recce-source/js/src/components/app/AvatarDropdown.tsx +159 -0
- package/recce-source/js/src/components/app/EnvInfo.tsx +357 -0
- package/recce-source/js/src/components/app/Filename.tsx +388 -0
- package/recce-source/js/src/components/app/SetupConnectionPopover.tsx +91 -0
- package/recce-source/js/src/components/app/StateExporter.tsx +57 -0
- package/recce-source/js/src/components/app/StateImporter.tsx +198 -0
- package/recce-source/js/src/components/app/StateSharing.tsx +145 -0
- package/recce-source/js/src/components/app/StateSynchronizer.tsx +205 -0
- package/recce-source/js/src/components/charts/HistogramChart.tsx +291 -0
- package/recce-source/js/src/components/charts/SquareIcon.tsx +51 -0
- package/recce-source/js/src/components/charts/TopKSummaryList.tsx +457 -0
- package/recce-source/js/src/components/charts/chartTheme.ts +74 -0
- package/recce-source/js/src/components/check/CheckBreadcrumb.tsx +97 -0
- package/recce-source/js/src/components/check/CheckDescription.tsx +134 -0
- package/recce-source/js/src/components/check/CheckDetail.tsx +797 -0
- package/recce-source/js/src/components/check/CheckEmptyState.tsx +84 -0
- package/recce-source/js/src/components/check/CheckList.tsx +320 -0
- package/recce-source/js/src/components/check/LineageDiffView.tsx +32 -0
- package/recce-source/js/src/components/check/PresetCheckTemplateView.tsx +48 -0
- package/recce-source/js/src/components/check/SchemaDiffView.tsx +290 -0
- package/recce-source/js/src/components/check/check.ts +25 -0
- package/recce-source/js/src/components/check/timeline/CheckTimeline.tsx +163 -0
- package/recce-source/js/src/components/check/timeline/CommentInput.tsx +84 -0
- package/recce-source/js/src/components/check/timeline/TimelineEvent.tsx +468 -0
- package/recce-source/js/src/components/check/timeline/index.ts +12 -0
- package/recce-source/js/src/components/check/utils.ts +12 -0
- package/recce-source/js/src/components/data-grid/ScreenshotDataGrid.tsx +333 -0
- package/recce-source/js/src/components/data-grid/agGridStyles.css +55 -0
- package/recce-source/js/src/components/data-grid/agGridTheme.ts +43 -0
- package/recce-source/js/src/components/editor/CodeEditor.tsx +107 -0
- package/recce-source/js/src/components/editor/DiffEditor.tsx +162 -0
- package/recce-source/js/src/components/editor/index.ts +12 -0
- package/recce-source/js/src/components/errorboundary/ErrorBoundary.tsx +87 -0
- package/recce-source/js/src/components/histogram/HistogramDiffForm.tsx +147 -0
- package/recce-source/js/src/components/histogram/HistogramDiffResultView.tsx +63 -0
- package/recce-source/js/src/components/icons/index.tsx +142 -0
- package/recce-source/js/src/components/lineage/ActionControl.tsx +63 -0
- package/recce-source/js/src/components/lineage/ActionTag.tsx +141 -0
- package/recce-source/js/src/components/lineage/ChangeStatusLegend.tsx +46 -0
- package/recce-source/js/src/components/lineage/ColumnLevelLineageControl.tsx +327 -0
- package/recce-source/js/src/components/lineage/ColumnLevelLineageLegend.tsx +57 -0
- package/recce-source/js/src/components/lineage/GraphColumnNode.tsx +199 -0
- package/recce-source/js/src/components/lineage/GraphEdge.tsx +59 -0
- package/recce-source/js/src/components/lineage/GraphNode.tsx +555 -0
- package/recce-source/js/src/components/lineage/LineagePage.tsx +10 -0
- package/recce-source/js/src/components/lineage/LineageView.tsx +1384 -0
- package/recce-source/js/src/components/lineage/LineageViewContext.tsx +86 -0
- package/recce-source/js/src/components/lineage/LineageViewContextMenu.tsx +637 -0
- package/recce-source/js/src/components/lineage/LineageViewNotification.tsx +64 -0
- package/recce-source/js/src/components/lineage/LineageViewTopBar.tsx +596 -0
- package/recce-source/js/src/components/lineage/NodeSqlView.tsx +136 -0
- package/recce-source/js/src/components/lineage/NodeTag.tsx +278 -0
- package/recce-source/js/src/components/lineage/NodeView.tsx +642 -0
- package/recce-source/js/src/components/lineage/SandboxView.tsx +436 -0
- package/recce-source/js/src/components/lineage/ServerDisconnectedModalContent.tsx +105 -0
- package/recce-source/js/src/components/lineage/SetupConnectionBanner.tsx +52 -0
- package/recce-source/js/src/components/lineage/SingleEnvironmentQueryView.tsx +152 -0
- package/recce-source/js/src/components/lineage/graph.test.ts +31 -0
- package/recce-source/js/src/components/lineage/graph.ts +58 -0
- package/recce-source/js/src/components/lineage/lineage.test.ts +169 -0
- package/recce-source/js/src/components/lineage/lineage.ts +521 -0
- package/recce-source/js/src/components/lineage/styles.css +42 -0
- package/recce-source/js/src/components/lineage/styles.tsx +165 -0
- package/recce-source/js/src/components/lineage/useMultiNodesAction.ts +352 -0
- package/recce-source/js/src/components/lineage/useValueDiffAlertDialog.tsx +108 -0
- package/recce-source/js/src/components/onboarding-guide/Notification.tsx +62 -0
- package/recce-source/js/src/components/profile/ProfileDiffForm.tsx +134 -0
- package/recce-source/js/src/components/profile/ProfileDiffResultView.tsx +245 -0
- package/recce-source/js/src/components/query/ChangedOnlyCheckbox.tsx +29 -0
- package/recce-source/js/src/components/query/DiffText.tsx +120 -0
- package/recce-source/js/src/components/query/QueryDiffResultView.tsx +470 -0
- package/recce-source/js/src/components/query/QueryForm.tsx +80 -0
- package/recce-source/js/src/components/query/QueryPage.tsx +282 -0
- package/recce-source/js/src/components/query/QueryResultView.tsx +180 -0
- package/recce-source/js/src/components/query/SetupConnectionGuide.tsx +57 -0
- package/recce-source/js/src/components/query/SqlEditor.tsx +245 -0
- package/recce-source/js/src/components/query/ToggleSwitch.tsx +84 -0
- package/recce-source/js/src/components/query/styles.css +21 -0
- package/recce-source/js/src/components/routing/DirectUrlAccess.test.tsx +428 -0
- package/recce-source/js/src/components/routing/LineageStatePreservation.test.tsx +311 -0
- package/recce-source/js/src/components/routing/Navigation.test.tsx +256 -0
- package/recce-source/js/src/components/rowcount/RowCountDiffResultView.tsx +109 -0
- package/recce-source/js/src/components/rowcount/delta.ts +11 -0
- package/recce-source/js/src/components/run/RunList.tsx +303 -0
- package/recce-source/js/src/components/run/RunModal.tsx +191 -0
- package/recce-source/js/src/components/run/RunPage.tsx +26 -0
- package/recce-source/js/src/components/run/RunResultPane.tsx +454 -0
- package/recce-source/js/src/components/run/RunStatusAndDate.tsx +106 -0
- package/recce-source/js/src/components/run/RunToolbar.tsx +70 -0
- package/recce-source/js/src/components/run/RunView.tsx +196 -0
- package/recce-source/js/src/components/run/registry.ts +214 -0
- package/recce-source/js/src/components/run/types.ts +14 -0
- package/recce-source/js/src/components/schema/ColumnNameCell.test.tsx +169 -0
- package/recce-source/js/src/components/schema/ColumnNameCell.tsx +198 -0
- package/recce-source/js/src/components/schema/SchemaView.tsx +337 -0
- package/recce-source/js/src/components/schema/schemaDiff.ts +32 -0
- package/recce-source/js/src/components/schema/style.css +134 -0
- package/recce-source/js/src/components/screenshot/ScreenshotBox.tsx +39 -0
- package/recce-source/js/src/components/shared/HistoryToggle.tsx +35 -0
- package/recce-source/js/src/components/split/Split.tsx +40 -0
- package/recce-source/js/src/components/split/styles.css +24 -0
- package/recce-source/js/src/components/summary/ChangeSummary.tsx +264 -0
- package/recce-source/js/src/components/summary/SchemaSummary.tsx +123 -0
- package/recce-source/js/src/components/summary/SummaryView.tsx +29 -0
- package/recce-source/js/src/components/timeout/IdleTimeoutBadge.tsx +48 -0
- package/recce-source/js/src/components/top-k/TopKDiffForm.tsx +58 -0
- package/recce-source/js/src/components/top-k/TopKDiffResultView.tsx +73 -0
- package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnGroupHeader.tsx +228 -0
- package/recce-source/js/src/components/ui/dataGrid/DataFrameColumnHeader.tsx +113 -0
- package/recce-source/js/src/components/ui/dataGrid/defaultRenderCell.tsx +72 -0
- package/recce-source/js/src/components/ui/dataGrid/index.ts +23 -0
- package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.test.tsx +607 -0
- package/recce-source/js/src/components/ui/dataGrid/inlineRenderCell.tsx +211 -0
- package/recce-source/js/src/components/ui/dataGrid/schemaCells.test.tsx +452 -0
- package/recce-source/js/src/components/ui/dataGrid/schemaCells.tsx +142 -0
- package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.test.tsx +178 -0
- package/recce-source/js/src/components/ui/dataGrid/valueDiffCells.tsx +275 -0
- package/recce-source/js/src/components/ui/markdown/ExternalLinkConfirmDialog.tsx +134 -0
- package/recce-source/js/src/components/ui/markdown/MarkdownContent.tsx +364 -0
- package/recce-source/js/src/components/ui/mui/index.ts +13 -0
- package/recce-source/js/src/components/ui/mui-provider.tsx +67 -0
- package/recce-source/js/src/components/ui/mui-theme.ts +1039 -0
- package/recce-source/js/src/components/ui/mui-utils.ts +113 -0
- package/recce-source/js/src/components/ui/toaster.tsx +288 -0
- package/recce-source/js/src/components/valuediff/ValueDiffDetailResultView.tsx +217 -0
- package/recce-source/js/src/components/valuediff/ValueDiffForm.tsx +246 -0
- package/recce-source/js/src/components/valuediff/ValueDiffResultView.tsx +82 -0
- package/recce-source/js/src/components/valuediff/shared.ts +33 -0
- package/recce-source/js/src/constants/tooltipMessage.ts +3 -0
- package/recce-source/js/src/constants/urls.ts +1 -0
- package/recce-source/js/src/lib/UrlHash.ts +12 -0
- package/recce-source/js/src/lib/api/adhocQuery.ts +70 -0
- package/recce-source/js/src/lib/api/axiosClient.ts +9 -0
- package/recce-source/js/src/lib/api/cacheKeys.ts +13 -0
- package/recce-source/js/src/lib/api/checkEvents.ts +252 -0
- package/recce-source/js/src/lib/api/checks.ts +129 -0
- package/recce-source/js/src/lib/api/cll.ts +53 -0
- package/recce-source/js/src/lib/api/connectToCloud.ts +13 -0
- package/recce-source/js/src/lib/api/flag.ts +37 -0
- package/recce-source/js/src/lib/api/info.ts +198 -0
- package/recce-source/js/src/lib/api/instanceInfo.ts +25 -0
- package/recce-source/js/src/lib/api/keepAlive.ts +108 -0
- package/recce-source/js/src/lib/api/lineagecheck.ts +35 -0
- package/recce-source/js/src/lib/api/localStorageKeys.ts +7 -0
- package/recce-source/js/src/lib/api/models.ts +59 -0
- package/recce-source/js/src/lib/api/profile.ts +65 -0
- package/recce-source/js/src/lib/api/rowcount.ts +19 -0
- package/recce-source/js/src/lib/api/runs.ts +174 -0
- package/recce-source/js/src/lib/api/schemacheck.ts +31 -0
- package/recce-source/js/src/lib/api/select.ts +25 -0
- package/recce-source/js/src/lib/api/sessionStorageKeys.ts +8 -0
- package/recce-source/js/src/lib/api/state.ts +117 -0
- package/recce-source/js/src/lib/api/track.ts +281 -0
- package/recce-source/js/src/lib/api/types.ts +284 -0
- package/recce-source/js/src/lib/api/user.ts +42 -0
- package/recce-source/js/src/lib/api/valuediff.ts +46 -0
- package/recce-source/js/src/lib/api/version.ts +40 -0
- package/recce-source/js/src/lib/const.ts +9 -0
- package/recce-source/js/src/lib/dataGrid/crossFunctionConsistency.test.ts +626 -0
- package/recce-source/js/src/lib/dataGrid/dataGridFactory.test.ts +2140 -0
- package/recce-source/js/src/lib/dataGrid/dataGridFactory.ts +397 -0
- package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.test.ts +132 -0
- package/recce-source/js/src/lib/dataGrid/generators/rowCountUtils.ts +126 -0
- package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.test.ts +1627 -0
- package/recce-source/js/src/lib/dataGrid/generators/toDataDiffGrid.ts +140 -0
- package/recce-source/js/src/lib/dataGrid/generators/toDataGrid.ts +67 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.test.ts +142 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDataGrid.ts +71 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.test.ts +258 -0
- package/recce-source/js/src/lib/dataGrid/generators/toRowCountDiffDataGrid.ts +153 -0
- package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.test.ts +951 -0
- package/recce-source/js/src/lib/dataGrid/generators/toSchemaDataGrid.ts +221 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.test.ts +395 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDataGrid.ts +184 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.test.ts +884 -0
- package/recce-source/js/src/lib/dataGrid/generators/toValueDiffGrid.ts +113 -0
- package/recce-source/js/src/lib/dataGrid/index.ts +51 -0
- package/recce-source/js/src/lib/dataGrid/propertyBased.test.ts +858 -0
- package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.test.ts +482 -0
- package/recce-source/js/src/lib/dataGrid/shared/columnBuilders.ts +345 -0
- package/recce-source/js/src/lib/dataGrid/shared/dataTypeEdgeCases.test.ts +698 -0
- package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.test.tsx +820 -0
- package/recce-source/js/src/lib/dataGrid/shared/diffColumnBuilder.tsx +277 -0
- package/recce-source/js/src/lib/dataGrid/shared/gridUtils.test.ts +785 -0
- package/recce-source/js/src/lib/dataGrid/shared/gridUtils.ts +370 -0
- package/recce-source/js/src/lib/dataGrid/shared/index.ts +81 -0
- package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.test.ts +909 -0
- package/recce-source/js/src/lib/dataGrid/shared/rowBuilders.ts +325 -0
- package/recce-source/js/src/lib/dataGrid/shared/simpleColumnBuilder.tsx +240 -0
- package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.test.tsx +719 -0
- package/recce-source/js/src/lib/dataGrid/shared/toDiffColumn.tsx +231 -0
- package/recce-source/js/src/lib/dataGrid/shared/validation.test.ts +559 -0
- package/recce-source/js/src/lib/dataGrid/shared/validation.ts +367 -0
- package/recce-source/js/src/lib/dataGrid/warehouseNamingConventions.test.ts +1117 -0
- package/recce-source/js/src/lib/formatSelect.ts +50 -0
- package/recce-source/js/src/lib/hooks/ApiConfigContext.tsx +181 -0
- package/recce-source/js/src/lib/hooks/IdleTimeoutContext.tsx +177 -0
- package/recce-source/js/src/lib/hooks/LineageGraphContext.tsx +512 -0
- package/recce-source/js/src/lib/hooks/RecceActionContext.tsx +269 -0
- package/recce-source/js/src/lib/hooks/RecceCheckContext.tsx +33 -0
- package/recce-source/js/src/lib/hooks/RecceContextProvider.tsx +54 -0
- package/recce-source/js/src/lib/hooks/RecceInstanceContext.tsx +129 -0
- package/recce-source/js/src/lib/hooks/RecceQueryContext.tsx +98 -0
- package/recce-source/js/src/lib/hooks/RecceShareStateContext.tsx +59 -0
- package/recce-source/js/src/lib/hooks/ScreenShot.tsx +399 -0
- package/recce-source/js/src/lib/hooks/useAppRouter.test.ts +211 -0
- package/recce-source/js/src/lib/hooks/useAppRouter.ts +200 -0
- package/recce-source/js/src/lib/hooks/useCheckEvents.ts +99 -0
- package/recce-source/js/src/lib/hooks/useCheckToast.tsx +14 -0
- package/recce-source/js/src/lib/hooks/useClipBoardToast.tsx +27 -0
- package/recce-source/js/src/lib/hooks/useCountdownToast.tsx +102 -0
- package/recce-source/js/src/lib/hooks/useFeedbackCollectionToast.tsx +130 -0
- package/recce-source/js/src/lib/hooks/useGuideToast.tsx +45 -0
- package/recce-source/js/src/lib/hooks/useIdleDetection.tsx +185 -0
- package/recce-source/js/src/lib/hooks/useModelColumns.tsx +113 -0
- package/recce-source/js/src/lib/hooks/useRecceInstanceInfo.tsx +13 -0
- package/recce-source/js/src/lib/hooks/useRecceServerFlag.tsx +13 -0
- package/recce-source/js/src/lib/hooks/useRun.tsx +89 -0
- package/recce-source/js/src/lib/hooks/useThemeColors.ts +115 -0
- package/recce-source/js/src/lib/mergeKeys.test.ts +89 -0
- package/recce-source/js/src/lib/mergeKeys.ts +86 -0
- package/recce-source/js/src/lib/result/ResultErrorFallback.tsx +9 -0
- package/recce-source/js/src/lib/utils/formatTime.ts +84 -0
- package/recce-source/js/src/lib/utils/urls.ts +16 -0
- package/recce-source/js/src/utils/DropdownValuesInput.tsx +297 -0
- package/recce-source/js/src/utils/formatters.tsx +237 -0
- package/recce-source/js/src/utils/transforms.ts +81 -0
- package/recce-source/js/tsconfig.json +47 -0
- package/recce-source/macros/README.md +8 -0
- package/recce-source/macros/recce_athena.sql +73 -0
- package/recce-source/pyproject.toml +109 -0
- package/recce-source/recce/VERSION +1 -0
- package/recce-source/recce/__init__.py +84 -0
- package/recce-source/recce/adapter/__init__.py +0 -0
- package/recce-source/recce/adapter/base.py +109 -0
- package/recce-source/recce/adapter/dbt_adapter/__init__.py +1699 -0
- package/recce-source/recce/adapter/dbt_adapter/dbt_version.py +42 -0
- package/recce-source/recce/adapter/sqlmesh_adapter.py +141 -0
- package/recce-source/recce/apis/__init__.py +0 -0
- package/recce-source/recce/apis/check_api.py +203 -0
- package/recce-source/recce/apis/check_events_api.py +353 -0
- package/recce-source/recce/apis/check_func.py +130 -0
- package/recce-source/recce/apis/run_api.py +130 -0
- package/recce-source/recce/apis/run_func.py +258 -0
- package/recce-source/recce/artifact.py +266 -0
- package/recce-source/recce/cli.py +1846 -0
- package/recce-source/recce/config.py +127 -0
- package/recce-source/recce/connect_to_cloud.py +138 -0
- package/recce-source/recce/core.py +334 -0
- package/recce-source/recce/diff.py +26 -0
- package/recce-source/recce/event/CONFIG +1 -0
- package/recce-source/recce/event/SENTRY_DNS +1 -0
- package/recce-source/recce/event/__init__.py +304 -0
- package/recce-source/recce/event/collector.py +184 -0
- package/recce-source/recce/event/track.py +158 -0
- package/recce-source/recce/exceptions.py +21 -0
- package/recce-source/recce/git.py +77 -0
- package/recce-source/recce/github.py +222 -0
- package/recce-source/recce/mcp_server.py +861 -0
- package/recce-source/recce/models/__init__.py +6 -0
- package/recce-source/recce/models/check.py +473 -0
- package/recce-source/recce/models/run.py +46 -0
- package/recce-source/recce/models/types.py +218 -0
- package/recce-source/recce/pull_request.py +124 -0
- package/recce-source/recce/run.py +390 -0
- package/recce-source/recce/server.py +877 -0
- package/recce-source/recce/state/__init__.py +31 -0
- package/recce-source/recce/state/cloud.py +644 -0
- package/recce-source/recce/state/const.py +26 -0
- package/recce-source/recce/state/local.py +56 -0
- package/recce-source/recce/state/state.py +119 -0
- package/recce-source/recce/state/state_loader.py +174 -0
- package/recce-source/recce/summary.py +575 -0
- package/recce-source/recce/tasks/__init__.py +23 -0
- package/recce-source/recce/tasks/core.py +134 -0
- package/recce-source/recce/tasks/dataframe.py +170 -0
- package/recce-source/recce/tasks/histogram.py +433 -0
- package/recce-source/recce/tasks/lineage.py +19 -0
- package/recce-source/recce/tasks/profile.py +298 -0
- package/recce-source/recce/tasks/query.py +450 -0
- package/recce-source/recce/tasks/rowcount.py +277 -0
- package/recce-source/recce/tasks/schema.py +65 -0
- package/recce-source/recce/tasks/top_k.py +172 -0
- package/recce-source/recce/tasks/utils.py +147 -0
- package/recce-source/recce/tasks/valuediff.py +497 -0
- package/recce-source/recce/util/__init__.py +4 -0
- package/recce-source/recce/util/api_token.py +80 -0
- package/recce-source/recce/util/breaking.py +330 -0
- package/recce-source/recce/util/cache.py +25 -0
- package/recce-source/recce/util/cll.py +355 -0
- package/recce-source/recce/util/cloud/__init__.py +15 -0
- package/recce-source/recce/util/cloud/base.py +115 -0
- package/recce-source/recce/util/cloud/check_events.py +190 -0
- package/recce-source/recce/util/cloud/checks.py +242 -0
- package/recce-source/recce/util/io.py +120 -0
- package/recce-source/recce/util/lineage.py +83 -0
- package/recce-source/recce/util/logger.py +25 -0
- package/recce-source/recce/util/onboarding_state.py +45 -0
- package/recce-source/recce/util/perf_tracking.py +85 -0
- package/recce-source/recce/util/pydantic_model.py +22 -0
- package/recce-source/recce/util/recce_cloud.py +454 -0
- package/recce-source/recce/util/singleton.py +18 -0
- package/recce-source/recce/util/startup_perf.py +121 -0
- package/recce-source/recce/yaml/__init__.py +58 -0
- package/recce-source/recce_cloud/README.md +780 -0
- package/recce-source/recce_cloud/VERSION +1 -0
- package/recce-source/recce_cloud/__init__.py +24 -0
- package/recce-source/recce_cloud/api/__init__.py +17 -0
- package/recce-source/recce_cloud/api/base.py +132 -0
- package/recce-source/recce_cloud/api/client.py +186 -0
- package/recce-source/recce_cloud/api/exceptions.py +26 -0
- package/recce-source/recce_cloud/api/factory.py +63 -0
- package/recce-source/recce_cloud/api/github.py +106 -0
- package/recce-source/recce_cloud/api/gitlab.py +111 -0
- package/recce-source/recce_cloud/artifact.py +57 -0
- package/recce-source/recce_cloud/ci_providers/__init__.py +9 -0
- package/recce-source/recce_cloud/ci_providers/base.py +82 -0
- package/recce-source/recce_cloud/ci_providers/detector.py +147 -0
- package/recce-source/recce_cloud/ci_providers/github_actions.py +136 -0
- package/recce-source/recce_cloud/ci_providers/gitlab_ci.py +130 -0
- package/recce-source/recce_cloud/cli.py +434 -0
- package/recce-source/recce_cloud/download.py +230 -0
- package/recce-source/recce_cloud/hatch_build.py +20 -0
- package/recce-source/recce_cloud/pyproject.toml +49 -0
- package/recce-source/recce_cloud/upload.py +214 -0
- package/recce-source/test.py +0 -0
- package/recce-source/tests/__init__.py +0 -0
- package/recce-source/tests/adapter/__init__.py +0 -0
- package/recce-source/tests/adapter/dbt_adapter/__init__.py +0 -0
- package/recce-source/tests/adapter/dbt_adapter/conftest.py +17 -0
- package/recce-source/tests/adapter/dbt_adapter/dbt_test_helper.py +298 -0
- package/recce-source/tests/adapter/dbt_adapter/test_dbt_adapter.py +25 -0
- package/recce-source/tests/adapter/dbt_adapter/test_dbt_cll.py +717 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/dbt_project.yml +4 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/manifest.json +1 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/package-lock.yml +8 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/packages.yml +7 -0
- package/recce-source/tests/adapter/dbt_adapter/test_proj/profiles.yml +6 -0
- package/recce-source/tests/adapter/dbt_adapter/test_selector.py +205 -0
- package/recce-source/tests/apis/__init__.py +0 -0
- package/recce-source/tests/apis/row_count_diff.json +59 -0
- package/recce-source/tests/apis/test_check_events_api.py +615 -0
- package/recce-source/tests/apis/test_run_func.py +433 -0
- package/recce-source/tests/catalog.json +527 -0
- package/recce-source/tests/data/manifest/base/catalog.json +1 -0
- package/recce-source/tests/data/manifest/base/manifest.json +1 -0
- package/recce-source/tests/data/manifest/pr2/catalog.json +1 -0
- package/recce-source/tests/data/manifest/pr2/manifest.json +1 -0
- package/recce-source/tests/manifest.json +10655 -0
- package/recce-source/tests/models/__init__.py +0 -0
- package/recce-source/tests/models/test_check.py +731 -0
- package/recce-source/tests/models/test_run_models.py +295 -0
- package/recce-source/tests/recce_cloud/__init__.py +0 -0
- package/recce-source/tests/recce_cloud/test_ci_providers.py +351 -0
- package/recce-source/tests/recce_cloud/test_cli.py +735 -0
- package/recce-source/tests/recce_cloud/test_client.py +379 -0
- package/recce-source/tests/recce_cloud/test_platform_clients.py +483 -0
- package/recce-source/tests/recce_state.json +1 -0
- package/recce-source/tests/state/test_cloud.py +719 -0
- package/recce-source/tests/state/test_local.py +164 -0
- package/recce-source/tests/state/test_state_loader.py +211 -0
- package/recce-source/tests/tasks/__init__.py +0 -0
- package/recce-source/tests/tasks/conftest.py +4 -0
- package/recce-source/tests/tasks/test_histogram.py +129 -0
- package/recce-source/tests/tasks/test_lineage.py +55 -0
- package/recce-source/tests/tasks/test_preset_checks.py +64 -0
- package/recce-source/tests/tasks/test_profile.py +397 -0
- package/recce-source/tests/tasks/test_query.py +528 -0
- package/recce-source/tests/tasks/test_row_count.py +133 -0
- package/recce-source/tests/tasks/test_schema.py +122 -0
- package/recce-source/tests/tasks/test_top_k.py +77 -0
- package/recce-source/tests/tasks/test_utils.py +439 -0
- package/recce-source/tests/tasks/test_valuediff.py +361 -0
- package/recce-source/tests/test_cli.py +236 -0
- package/recce-source/tests/test_cli_mcp_optional.py +45 -0
- package/recce-source/tests/test_cloud_listing_cli.py +324 -0
- package/recce-source/tests/test_config.py +43 -0
- package/recce-source/tests/test_connect_to_cloud.py +82 -0
- package/recce-source/tests/test_core.py +174 -0
- package/recce-source/tests/test_dbt.py +36 -0
- package/recce-source/tests/test_mcp_server.py +505 -0
- package/recce-source/tests/test_pull_request.py +130 -0
- package/recce-source/tests/test_server.py +202 -0
- package/recce-source/tests/test_server_lifespan.py +138 -0
- package/recce-source/tests/test_summary.py +73 -0
- package/recce-source/tests/util/__init__.py +0 -0
- package/recce-source/tests/util/cloud/__init__.py +0 -0
- package/recce-source/tests/util/cloud/test_check_events.py +255 -0
- package/recce-source/tests/util/cloud/test_checks.py +204 -0
- package/recce-source/tests/util/test_api_token.py +119 -0
- package/recce-source/tests/util/test_breaking.py +1427 -0
- package/recce-source/tests/util/test_cll.py +706 -0
- package/recce-source/tests/util/test_lineage.py +122 -0
- package/recce-source/tests/util/test_onboarding_state.py +84 -0
- package/recce-source/tests/util/test_recce_cloud.py +231 -0
- package/recce-source/tox.ini +40 -0
- package/recce-source/uv.lock +3928 -0
- package/src/api/index.ts +32 -0
- package/src/components/index.ts +154 -0
- package/src/global.d.ts +14 -0
- package/src/hooks/index.ts +56 -0
- package/src/index.ts +17 -0
- package/src/lib/hooks/RouteConfigContext.ts +139 -0
- package/src/lib/hooks/useAppRouter.ts +240 -0
- package/src/mui-augmentation.d.ts +139 -0
- package/src/theme/index.ts +13 -0
- package/src/theme.ts +23 -0
- package/src/types/index.ts +23 -0
- package/dist/index-BNUP2V_N.d.ts.map +0 -1
- package/dist/index-DOPZuhD8.d.mts.map +0 -1
- package/dist/theme.d.mts.map +0 -1
- package/dist/theme.d.ts.map +0 -1
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import logging
|
|
3
|
+
from typing import List, Optional
|
|
4
|
+
|
|
5
|
+
from recce.core import default_context
|
|
6
|
+
from recce.exceptions import RecceException
|
|
7
|
+
from recce.models import Run, RunDAO, RunType
|
|
8
|
+
from recce.models.types import RunStatus
|
|
9
|
+
|
|
10
|
+
running_tasks = {}
|
|
11
|
+
logger = logging.getLogger("uvicorn")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def _get_ref_model(sql_template: str) -> Optional[str]:
|
|
15
|
+
import re
|
|
16
|
+
|
|
17
|
+
pattern = r'\bref\(["\']?(\w+)["\']?\)\s*}}'
|
|
18
|
+
matches = re.findall(pattern, sql_template)
|
|
19
|
+
if len(matches) == 1:
|
|
20
|
+
ref = matches[0]
|
|
21
|
+
return ref
|
|
22
|
+
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def generate_run_name(run):
|
|
27
|
+
# parse utc time with timezone
|
|
28
|
+
|
|
29
|
+
import dateutil
|
|
30
|
+
|
|
31
|
+
run_type = run.type
|
|
32
|
+
params = run.params
|
|
33
|
+
now = dateutil.parser.parse(run.run_at)
|
|
34
|
+
|
|
35
|
+
if run_type == RunType.QUERY:
|
|
36
|
+
ref = _get_ref_model(params.get("sql_template"))
|
|
37
|
+
if ref:
|
|
38
|
+
return f"query of {ref}".capitalize()
|
|
39
|
+
return f"{'query'.capitalize()} - {now}"
|
|
40
|
+
elif run_type == RunType.QUERY_DIFF:
|
|
41
|
+
ref = _get_ref_model(params.get("sql_template"))
|
|
42
|
+
if ref:
|
|
43
|
+
return f"query diff of {ref}".capitalize()
|
|
44
|
+
return f"{'query diff'.capitalize()} - {now}"
|
|
45
|
+
elif run_type == RunType.VALUE_DIFF:
|
|
46
|
+
model = params.get("model")
|
|
47
|
+
return f"value diff of {model}".capitalize()
|
|
48
|
+
elif run_type == RunType.VALUE_DIFF_DETAIL:
|
|
49
|
+
model = params.get("model")
|
|
50
|
+
return f"value diff detail of {model}".capitalize()
|
|
51
|
+
elif run_type == RunType.PROFILE_DIFF:
|
|
52
|
+
model = params.get("model")
|
|
53
|
+
return f"profile diff of {model}".capitalize()
|
|
54
|
+
elif run_type == RunType.ROW_COUNT_DIFF:
|
|
55
|
+
nodes = params.get("node_names")
|
|
56
|
+
if nodes:
|
|
57
|
+
if len(nodes) == 1:
|
|
58
|
+
node = nodes[0]
|
|
59
|
+
return f"row count diff of {node}".capitalize()
|
|
60
|
+
else:
|
|
61
|
+
return f"row count of {len(nodes)} nodes".capitalize()
|
|
62
|
+
else:
|
|
63
|
+
return "row count of multiple nodes".capitalize()
|
|
64
|
+
elif run_type == RunType.TOP_K_DIFF:
|
|
65
|
+
model = params.get("model")
|
|
66
|
+
column = params.get("column_name")
|
|
67
|
+
return f"top-k diff of {model}.{column} ".capitalize()
|
|
68
|
+
elif run_type == RunType.HISTOGRAM_DIFF:
|
|
69
|
+
model = params.get("model")
|
|
70
|
+
column = params.get("column_name")
|
|
71
|
+
return f"histogram diff of {model}.{column} ".capitalize()
|
|
72
|
+
else:
|
|
73
|
+
return f"{'run'.capitalize()} - {now}"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def create_task(run_type: RunType, params: dict):
|
|
77
|
+
context = default_context()
|
|
78
|
+
if context is not None and context.adapter_type == "sqlmesh":
|
|
79
|
+
from recce.adapter.sqlmesh_adapter import (
|
|
80
|
+
sqlmesh_supported_registry as sqlmesh_registry,
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
registry = sqlmesh_registry
|
|
84
|
+
else:
|
|
85
|
+
from recce.adapter.dbt_adapter import dbt_supported_registry as dbt_registry
|
|
86
|
+
|
|
87
|
+
registry = dbt_registry
|
|
88
|
+
|
|
89
|
+
taskClz = registry.get(run_type)
|
|
90
|
+
if not taskClz:
|
|
91
|
+
raise NotImplementedError()
|
|
92
|
+
return taskClz(params)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def submit_run(type, params, check_id=None):
|
|
96
|
+
try:
|
|
97
|
+
run_type = RunType(type)
|
|
98
|
+
except ValueError:
|
|
99
|
+
raise RecceException(f"Run type '{type}' not supported")
|
|
100
|
+
|
|
101
|
+
try:
|
|
102
|
+
task = create_task(run_type, params)
|
|
103
|
+
except NotImplementedError:
|
|
104
|
+
raise RecceException(f"Run type '{type}' not supported")
|
|
105
|
+
|
|
106
|
+
context = default_context()
|
|
107
|
+
if context.review_mode is True:
|
|
108
|
+
from recce.adapter.dbt_adapter import DbtAdapter
|
|
109
|
+
|
|
110
|
+
dbt_adaptor: DbtAdapter = context.adapter
|
|
111
|
+
if dbt_adaptor.adapter is None:
|
|
112
|
+
raise RecceException("Recce Server is not launched under DBT project folder.")
|
|
113
|
+
|
|
114
|
+
run = Run(type=run_type, params=params, check_id=check_id, status=RunStatus.RUNNING)
|
|
115
|
+
run.name = generate_run_name(run)
|
|
116
|
+
RunDAO().create(run)
|
|
117
|
+
|
|
118
|
+
loop = asyncio.get_running_loop()
|
|
119
|
+
running_tasks[run.run_id] = task
|
|
120
|
+
|
|
121
|
+
def progress_listener(message=None, percentage=None):
|
|
122
|
+
run.progress = {"message": message, "percentage": percentage}
|
|
123
|
+
|
|
124
|
+
task.progress_listener = progress_listener
|
|
125
|
+
|
|
126
|
+
async def update_run_result(run, result, error, updated_params=None):
|
|
127
|
+
"""Update run with result, error, and optionally updated params."""
|
|
128
|
+
if run is None:
|
|
129
|
+
return
|
|
130
|
+
if result is not None:
|
|
131
|
+
run.result = result
|
|
132
|
+
run.status = RunStatus.FINISHED
|
|
133
|
+
if updated_params is not None:
|
|
134
|
+
# Merge updated params (preserves any fields not in updated_params)
|
|
135
|
+
run.params.update(updated_params)
|
|
136
|
+
if error is not None:
|
|
137
|
+
failed_reason = str(error) if str(error) != "None" else repr(error)
|
|
138
|
+
run.error = failed_reason
|
|
139
|
+
if run.status != RunStatus.CANCELLED:
|
|
140
|
+
run.status = RunStatus.FAILED
|
|
141
|
+
run.progress = None
|
|
142
|
+
|
|
143
|
+
def fn():
|
|
144
|
+
try:
|
|
145
|
+
result = task.execute()
|
|
146
|
+
|
|
147
|
+
# Extract updated params from task after execution
|
|
148
|
+
updated_params = None
|
|
149
|
+
if hasattr(task, "params") and task.params is not None:
|
|
150
|
+
# Serialization logic:
|
|
151
|
+
# - Most tasks use Pydantic models (v2: model_dump, v1: dict)
|
|
152
|
+
# - Some tasks may use plain dicts
|
|
153
|
+
# - If params is an unexpected type, log a warning for debugging
|
|
154
|
+
# - Handle the case where model_dump() or dict() raises an exception.
|
|
155
|
+
try:
|
|
156
|
+
if hasattr(task.params, "model_dump"):
|
|
157
|
+
updated_params = task.params.model_dump()
|
|
158
|
+
elif hasattr(task.params, "dict"):
|
|
159
|
+
updated_params = task.params.dict()
|
|
160
|
+
elif isinstance(task.params, dict):
|
|
161
|
+
updated_params = task.params
|
|
162
|
+
else:
|
|
163
|
+
logger.warning(
|
|
164
|
+
f"Could not serialize task.params for run_id={run.run_id}: "
|
|
165
|
+
f"unexpected type {type(task.params)} with value {repr(task.params)}"
|
|
166
|
+
)
|
|
167
|
+
except Exception as e:
|
|
168
|
+
logger.warning(f"Failed to serialize task.params: {e}")
|
|
169
|
+
updated_params = None
|
|
170
|
+
|
|
171
|
+
asyncio.run_coroutine_threadsafe(update_run_result(run, result, None, updated_params), loop)
|
|
172
|
+
return result
|
|
173
|
+
except BaseException as e:
|
|
174
|
+
asyncio.run_coroutine_threadsafe(update_run_result(run, None, e, None), loop)
|
|
175
|
+
if isinstance(e, RecceException) and e.is_raise is False:
|
|
176
|
+
return None
|
|
177
|
+
import sentry_sdk
|
|
178
|
+
|
|
179
|
+
sentry_sdk.capture_exception(e)
|
|
180
|
+
failed_reason = str(e) if str(e) != "None" else repr(e)
|
|
181
|
+
failed_reason = failed_reason.replace(". ", ".\n")
|
|
182
|
+
logger.error(f"Failed to execute {run_type} task: {failed_reason}")
|
|
183
|
+
return None
|
|
184
|
+
|
|
185
|
+
future = loop.run_in_executor(None, fn)
|
|
186
|
+
return run, future
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def cancel_run(run_id):
|
|
190
|
+
run = RunDAO().find_run_by_id(run_id)
|
|
191
|
+
if run is None:
|
|
192
|
+
raise RecceException(f"Run ID '{run_id}' not found")
|
|
193
|
+
|
|
194
|
+
task = running_tasks.get(run_id)
|
|
195
|
+
if task is None:
|
|
196
|
+
raise RecceException(f"Run task for Run ID '{run_id}' not found")
|
|
197
|
+
|
|
198
|
+
task.cancel()
|
|
199
|
+
run.status = RunStatus.CANCELLED
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def materialize_run_results(runs: List[Run], nodes: List[str] = None):
|
|
203
|
+
"""
|
|
204
|
+
Materialize the run results for nodes. It walks through all runs and get the last results for primary run types.
|
|
205
|
+
|
|
206
|
+
The result format
|
|
207
|
+
{
|
|
208
|
+
'node_id': {
|
|
209
|
+
'row_count_diff': {
|
|
210
|
+
'run_id': '<run_id>',
|
|
211
|
+
'result': '<result>'
|
|
212
|
+
},
|
|
213
|
+
'value_diff': {
|
|
214
|
+
'run_id': '<run_id>',
|
|
215
|
+
'result': '<result>'
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
}
|
|
219
|
+
"""
|
|
220
|
+
|
|
221
|
+
context = default_context()
|
|
222
|
+
if context:
|
|
223
|
+
mame_to_unique_id = context.build_name_to_unique_id_index(excluded_types={"semantic_model", "metric"})
|
|
224
|
+
else:
|
|
225
|
+
mame_to_unique_id = {}
|
|
226
|
+
|
|
227
|
+
result = {}
|
|
228
|
+
for run in runs:
|
|
229
|
+
if not run.result:
|
|
230
|
+
continue
|
|
231
|
+
|
|
232
|
+
if run.type == RunType.ROW_COUNT_DIFF:
|
|
233
|
+
for model_name, node_run_result in run.result.items():
|
|
234
|
+
key = mame_to_unique_id.get(model_name, model_name)
|
|
235
|
+
|
|
236
|
+
if nodes:
|
|
237
|
+
if key not in nodes:
|
|
238
|
+
continue
|
|
239
|
+
|
|
240
|
+
if model_name not in result:
|
|
241
|
+
node_result = result[key] = {}
|
|
242
|
+
else:
|
|
243
|
+
node_result = result.get(key)
|
|
244
|
+
node_result["row_count_diff"] = {"run_id": run.run_id, "result": node_run_result}
|
|
245
|
+
elif run.type == RunType.ROW_COUNT:
|
|
246
|
+
for model_name, node_run_result in run.result.items():
|
|
247
|
+
key = mame_to_unique_id.get(model_name, model_name)
|
|
248
|
+
|
|
249
|
+
if nodes:
|
|
250
|
+
if key not in nodes:
|
|
251
|
+
continue
|
|
252
|
+
|
|
253
|
+
if model_name not in result:
|
|
254
|
+
node_result = result[key] = {}
|
|
255
|
+
else:
|
|
256
|
+
node_result = result.get(key)
|
|
257
|
+
node_result["row_count"] = {"run_id": run.run_id, "result": node_run_result}
|
|
258
|
+
return result
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import gzip
|
|
2
|
+
import json
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
import tarfile
|
|
6
|
+
import tempfile
|
|
7
|
+
from urllib.parse import urlencode
|
|
8
|
+
|
|
9
|
+
import requests
|
|
10
|
+
from rich.console import Console
|
|
11
|
+
|
|
12
|
+
from recce.git import commit_hash_from_branch, current_branch, hosting_repo
|
|
13
|
+
from recce.state import s3_sse_c_headers
|
|
14
|
+
from recce.util.recce_cloud import PresignedUrlMethod, RecceCloud
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def verify_artifacts_path(target_path: str) -> bool:
|
|
18
|
+
"""
|
|
19
|
+
Verify if the target path is a valid artifacts path.
|
|
20
|
+
|
|
21
|
+
:param target_path: the target path to check
|
|
22
|
+
:return: True if the target path is a valid artifacts path, False otherwise
|
|
23
|
+
"""
|
|
24
|
+
if not target_path:
|
|
25
|
+
return False
|
|
26
|
+
|
|
27
|
+
if not os.path.exists(target_path):
|
|
28
|
+
return False
|
|
29
|
+
|
|
30
|
+
if not os.path.isdir(target_path):
|
|
31
|
+
return False
|
|
32
|
+
|
|
33
|
+
required_artifacts_files = ["manifest.json", "catalog.json"]
|
|
34
|
+
|
|
35
|
+
if all(f in os.listdir(target_path) for f in required_artifacts_files):
|
|
36
|
+
# Check if the required files are present in the target path
|
|
37
|
+
return True
|
|
38
|
+
|
|
39
|
+
return False
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def parse_dbt_version(file_path: str) -> str:
|
|
43
|
+
with open(file_path, "r", encoding="utf-8") as f:
|
|
44
|
+
data = json.load(f)
|
|
45
|
+
|
|
46
|
+
dbt_version = data.get("metadata", {}).get("dbt_version", None)
|
|
47
|
+
return dbt_version
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def archive_artifacts(target_path: str) -> (str, str):
|
|
51
|
+
if verify_artifacts_path(target_path) is False:
|
|
52
|
+
raise Exception(f"Invalid target path: {target_path}")
|
|
53
|
+
|
|
54
|
+
manifest_path = os.path.join(target_path, "manifest.json")
|
|
55
|
+
catalog_path = os.path.join(target_path, "catalog.json")
|
|
56
|
+
|
|
57
|
+
dbt_version = parse_dbt_version(manifest_path)
|
|
58
|
+
if dbt_version is None:
|
|
59
|
+
raise Exception("Failed to parse dbt version from manifest.json")
|
|
60
|
+
|
|
61
|
+
# prepare the temporary artifacts path
|
|
62
|
+
tmp_dir = tempfile.mkdtemp()
|
|
63
|
+
artifacts_tar_path = os.path.join(tmp_dir, "dbt_artifacts.tar")
|
|
64
|
+
artifacts_tar_gz_path = artifacts_tar_path + ".gz"
|
|
65
|
+
|
|
66
|
+
with tarfile.open(artifacts_tar_path, "w") as tar:
|
|
67
|
+
tar.add(manifest_path, arcname="manifest.json")
|
|
68
|
+
tar.add(catalog_path, arcname="catalog.json")
|
|
69
|
+
|
|
70
|
+
# Compress the tar file
|
|
71
|
+
with open(artifacts_tar_path, "rb") as f_in, gzip.open(artifacts_tar_gz_path, "wb") as f_out:
|
|
72
|
+
f_out.writelines(f_in)
|
|
73
|
+
|
|
74
|
+
# Clean up the temporary directory
|
|
75
|
+
try:
|
|
76
|
+
os.remove(artifacts_tar_path)
|
|
77
|
+
except FileNotFoundError:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
return artifacts_tar_gz_path, dbt_version
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def upload_artifacts_to_session(target_path: str, session_id: str, token: str, debug: bool = False):
|
|
84
|
+
"""Upload dbt artifacts to a specific session ID in Recce Cloud."""
|
|
85
|
+
console = Console()
|
|
86
|
+
if verify_artifacts_path(target_path) is False:
|
|
87
|
+
console.print(f"[[red]Error[/red]] Invalid target path: {target_path}")
|
|
88
|
+
console.print("Please provide a valid target path containing manifest.json and catalog.json.")
|
|
89
|
+
return 1
|
|
90
|
+
|
|
91
|
+
manifest_path = os.path.join(target_path, "manifest.json")
|
|
92
|
+
catalog_path = os.path.join(target_path, "catalog.json")
|
|
93
|
+
|
|
94
|
+
# get the adapter type from the manifest file
|
|
95
|
+
with open(manifest_path, "r", encoding="utf-8") as f:
|
|
96
|
+
manifest_data = json.load(f)
|
|
97
|
+
adapter_type = manifest_data.get("metadata", {}).get("adapter_type")
|
|
98
|
+
if adapter_type is None:
|
|
99
|
+
raise Exception("Failed to parse adapter type from manifest.json")
|
|
100
|
+
|
|
101
|
+
recce_cloud = RecceCloud(token)
|
|
102
|
+
|
|
103
|
+
session = recce_cloud.get_session(session_id)
|
|
104
|
+
|
|
105
|
+
org_id = session.get("org_id")
|
|
106
|
+
if org_id is None:
|
|
107
|
+
raise Exception(f"Session ID {session_id} does not belong to any organization.")
|
|
108
|
+
|
|
109
|
+
project_id = session.get("project_id")
|
|
110
|
+
if project_id is None:
|
|
111
|
+
raise Exception(f"Session ID {session_id} does not belong to any project.")
|
|
112
|
+
|
|
113
|
+
# Get the presigned URL for uploading the artifacts using session ID
|
|
114
|
+
console.print(f'Uploading artifacts for session ID "{session_id}"')
|
|
115
|
+
presigned_urls = recce_cloud.get_upload_urls_by_session_id(org_id, project_id, session_id)
|
|
116
|
+
if debug:
|
|
117
|
+
console.rule("Debug information", style="blue")
|
|
118
|
+
console.print(f"Org ID: {org_id}")
|
|
119
|
+
console.print(f"Project ID: {project_id}")
|
|
120
|
+
console.print(f"Session ID: {session_id}")
|
|
121
|
+
console.print(f"Manifest path: {presigned_urls['manifest_url']}")
|
|
122
|
+
console.print(f"Catalog path: {presigned_urls['catalog_url']}")
|
|
123
|
+
console.print(f"Adapter type: {adapter_type}")
|
|
124
|
+
|
|
125
|
+
# Upload the compressed artifacts (no password needed for session uploads)
|
|
126
|
+
console.print(f'Uploading manifest from path "{manifest_path}"')
|
|
127
|
+
response = requests.put(presigned_urls["manifest_url"], data=open(manifest_path, "rb").read())
|
|
128
|
+
if response.status_code != 200 and response.status_code != 204:
|
|
129
|
+
raise Exception(response.text)
|
|
130
|
+
console.print(f'Uploading catalog from path "{catalog_path}"')
|
|
131
|
+
response = requests.put(presigned_urls["catalog_url"], data=open(catalog_path, "rb").read())
|
|
132
|
+
if response.status_code != 200 and response.status_code != 204:
|
|
133
|
+
raise Exception(response.text)
|
|
134
|
+
|
|
135
|
+
# Update the session metadata
|
|
136
|
+
recce_cloud.update_session(org_id, project_id, session_id, adapter_type)
|
|
137
|
+
|
|
138
|
+
return 0
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def upload_dbt_artifacts(target_path: str, branch: str, token: str, password: str, debug: bool = False):
|
|
142
|
+
console = Console()
|
|
143
|
+
if verify_artifacts_path(target_path) is False:
|
|
144
|
+
console.print(f"[[red]Error[/red]] Invalid target path: {target_path}")
|
|
145
|
+
console.print("Please provide a valid target path containing manifest.json and catalog.json.")
|
|
146
|
+
return 1
|
|
147
|
+
|
|
148
|
+
if branch != current_branch():
|
|
149
|
+
console.print(
|
|
150
|
+
f"[[yellow]Warning[/yellow]] You are uploading the dbt artifacts as branch '{branch}'. "
|
|
151
|
+
f"However, the current branch is '{current_branch()}'."
|
|
152
|
+
)
|
|
153
|
+
console.print("Please make sure you are uploading the dbt artifacts to the correct branch.")
|
|
154
|
+
|
|
155
|
+
compress_file_path, dbt_version = archive_artifacts(target_path)
|
|
156
|
+
repo = hosting_repo()
|
|
157
|
+
sha = commit_hash_from_branch(branch)
|
|
158
|
+
metadata = {"commit": sha, "dbt_version": dbt_version}
|
|
159
|
+
|
|
160
|
+
# Get the presigned URL for uploading the artifacts
|
|
161
|
+
presigned_url = RecceCloud(token).get_presigned_url_by_github_repo(
|
|
162
|
+
method=PresignedUrlMethod.UPLOAD,
|
|
163
|
+
repository=repo,
|
|
164
|
+
artifact_name="dbt_artifacts.tar.gz",
|
|
165
|
+
branch=branch,
|
|
166
|
+
metadata=metadata,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
if debug:
|
|
170
|
+
console.rule("Debug information", style="blue")
|
|
171
|
+
console.print(f"Branch: {branch}")
|
|
172
|
+
console.print(f"Commit hash: {sha}")
|
|
173
|
+
console.print(f"GitHub repository: {repo}")
|
|
174
|
+
console.print(f"Artifact path: {compress_file_path}")
|
|
175
|
+
console.print(f"DBT version: {dbt_version}")
|
|
176
|
+
console.print(f"Presigned URL: {presigned_url}")
|
|
177
|
+
console.print(f'Uploading the dbt artifacts from path "{target_path}" to branch "{branch}"')
|
|
178
|
+
|
|
179
|
+
# Upload the compressed artifacts
|
|
180
|
+
|
|
181
|
+
headers = s3_sse_c_headers(password)
|
|
182
|
+
if metadata:
|
|
183
|
+
headers["x-amz-tagging"] = urlencode(metadata)
|
|
184
|
+
response = requests.put(presigned_url, data=open(compress_file_path, "rb").read(), headers=headers)
|
|
185
|
+
if response.status_code != 200:
|
|
186
|
+
raise Exception({response.text})
|
|
187
|
+
|
|
188
|
+
# Clean up the compressed artifacts
|
|
189
|
+
try:
|
|
190
|
+
# Remove the compressed artifacts
|
|
191
|
+
os.remove(compress_file_path)
|
|
192
|
+
# Clean up the temporary directory
|
|
193
|
+
os.rmdir(os.path.dirname(compress_file_path))
|
|
194
|
+
except FileNotFoundError:
|
|
195
|
+
pass
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def download_dbt_artifacts(
|
|
199
|
+
target_path: str, branch: str, token: str, password: str, force: bool = False, debug: bool = False
|
|
200
|
+
):
|
|
201
|
+
console = Console()
|
|
202
|
+
repo = hosting_repo()
|
|
203
|
+
sha = None
|
|
204
|
+
dbt_version = None
|
|
205
|
+
|
|
206
|
+
presigned_url, tags = RecceCloud(token).get_download_presigned_url_by_github_repo_with_tags(
|
|
207
|
+
repository=repo,
|
|
208
|
+
artifact_name="dbt_artifacts.tar.gz",
|
|
209
|
+
branch=branch,
|
|
210
|
+
)
|
|
211
|
+
if tags:
|
|
212
|
+
sha = tags.get("commit")
|
|
213
|
+
dbt_version = tags.get("dbt_version")
|
|
214
|
+
|
|
215
|
+
if debug:
|
|
216
|
+
console.rule("Debug information", style="blue")
|
|
217
|
+
console.print(f"Git Branch: {branch}")
|
|
218
|
+
console.print(f"Git Commit: {sha}")
|
|
219
|
+
console.print(f"GitHub repository: {repo}")
|
|
220
|
+
console.print(f"DBT version: {dbt_version}")
|
|
221
|
+
console.print(f'Downloading from branch: "{branch}" and extracting to "{target_path}"')
|
|
222
|
+
|
|
223
|
+
headers = s3_sse_c_headers(password)
|
|
224
|
+
response = requests.get(presigned_url, headers=headers)
|
|
225
|
+
|
|
226
|
+
if response.status_code != 200:
|
|
227
|
+
raise Exception(response.text)
|
|
228
|
+
|
|
229
|
+
if os.path.exists(target_path):
|
|
230
|
+
if not force:
|
|
231
|
+
raise Exception(
|
|
232
|
+
f"Path {target_path} already exists. Please provide a new path or use '--force' option to overwrite the existing folder."
|
|
233
|
+
)
|
|
234
|
+
console.print(f"[[yellow]Warning[/yellow]] Overwrite existing path: {target_path}")
|
|
235
|
+
shutil.rmtree(target_path)
|
|
236
|
+
os.mkdir(target_path)
|
|
237
|
+
|
|
238
|
+
tar_gz_file = os.path.join(target_path, "dbt_artifacts.tar.gz")
|
|
239
|
+
with open(tar_gz_file, "wb") as f:
|
|
240
|
+
f.write(response.content)
|
|
241
|
+
|
|
242
|
+
with tarfile.open(tar_gz_file, "r") as tar:
|
|
243
|
+
tar.extractall(path=target_path)
|
|
244
|
+
|
|
245
|
+
# Clean up the compressed artifacts
|
|
246
|
+
try:
|
|
247
|
+
# Remove the compressed artifacts
|
|
248
|
+
os.remove(tar_gz_file)
|
|
249
|
+
except FileNotFoundError:
|
|
250
|
+
pass
|
|
251
|
+
return 0
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def delete_dbt_artifacts(branch: str, token: str, debug: bool = False):
|
|
255
|
+
"""Delete dbt artifacts from a specific branch in Recce Cloud."""
|
|
256
|
+
console = Console()
|
|
257
|
+
repo = hosting_repo()
|
|
258
|
+
|
|
259
|
+
if debug:
|
|
260
|
+
console.rule("Debug information", style="blue")
|
|
261
|
+
console.print(f"Git Branch: {branch}")
|
|
262
|
+
console.print(f"GitHub repository: {repo}")
|
|
263
|
+
|
|
264
|
+
console.print(f'Deleting dbt artifacts from branch: "{branch}"')
|
|
265
|
+
|
|
266
|
+
RecceCloud(token).purge_artifacts(repo, branch=branch)
|