@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,127 @@
|
|
|
1
|
+
# Configuration file for recce
|
|
2
|
+
from rich.console import Console
|
|
3
|
+
|
|
4
|
+
from recce import yaml
|
|
5
|
+
from recce.exceptions import RecceConfigException
|
|
6
|
+
from recce.util import SingletonMeta
|
|
7
|
+
|
|
8
|
+
RECCE_CONFIG_FILE = "recce.yml"
|
|
9
|
+
RECCE_PRESET_CHECK_COMMENT = """Preset Checks
|
|
10
|
+
Please see https://docs.datarecce.io/features/preset-checks/
|
|
11
|
+
"""
|
|
12
|
+
RECCE_ERROR_LOG_FILE = "recce_error.log"
|
|
13
|
+
console = Console()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class RecceConfig(metaclass=SingletonMeta):
|
|
17
|
+
def __init__(self, config_file=RECCE_CONFIG_FILE):
|
|
18
|
+
self.config_file = config_file
|
|
19
|
+
self.config = None
|
|
20
|
+
self.load()
|
|
21
|
+
|
|
22
|
+
def load(self):
|
|
23
|
+
try:
|
|
24
|
+
with open(self.config_file, "r", encoding="utf-8") as f:
|
|
25
|
+
config = yaml.safe_load(f)
|
|
26
|
+
self.config = config if config else {}
|
|
27
|
+
self._verify_preset_checks()
|
|
28
|
+
except FileNotFoundError:
|
|
29
|
+
console.print(f"[[orange3]NOTICE[/orange3]] Generate default Recce config file at '{self.config_file}'")
|
|
30
|
+
self.config = self.generate_template()
|
|
31
|
+
self.save()
|
|
32
|
+
|
|
33
|
+
def _verify_preset_checks(self):
|
|
34
|
+
from recce.tasks.core import CheckValidator
|
|
35
|
+
|
|
36
|
+
if not self.config.get("checks"):
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
for check in self.config["checks"]:
|
|
40
|
+
try:
|
|
41
|
+
check_type = check.get("type")
|
|
42
|
+
if check_type is None:
|
|
43
|
+
raise ValueError(f'Check type is required for check "{check}"')
|
|
44
|
+
if check_type == "lineage_diff":
|
|
45
|
+
from recce.tasks.lineage import LineageDiffCheckValidator
|
|
46
|
+
|
|
47
|
+
validator = LineageDiffCheckValidator()
|
|
48
|
+
elif check_type == "schema_diff":
|
|
49
|
+
from recce.tasks.schema import SchemaDiffCheckValidator
|
|
50
|
+
|
|
51
|
+
validator = SchemaDiffCheckValidator()
|
|
52
|
+
elif check_type == "row_count_diff":
|
|
53
|
+
from recce.tasks.rowcount import RowCountDiffCheckValidator
|
|
54
|
+
|
|
55
|
+
validator = RowCountDiffCheckValidator()
|
|
56
|
+
elif check_type == "query":
|
|
57
|
+
from recce.tasks.query import QueryCheckValidator
|
|
58
|
+
|
|
59
|
+
validator = QueryCheckValidator()
|
|
60
|
+
elif check_type == "query_diff":
|
|
61
|
+
from recce.tasks.query import QueryDiffCheckValidator
|
|
62
|
+
|
|
63
|
+
validator = QueryDiffCheckValidator()
|
|
64
|
+
elif check_type == "value_diff" or check_type == "value_diff_detail":
|
|
65
|
+
from recce.tasks.valuediff import ValueDiffCheckValidator
|
|
66
|
+
|
|
67
|
+
validator = ValueDiffCheckValidator()
|
|
68
|
+
elif check_type == "profile_diff":
|
|
69
|
+
from recce.tasks.profile import ProfileCheckValidator
|
|
70
|
+
|
|
71
|
+
validator = ProfileCheckValidator()
|
|
72
|
+
elif check_type == "top_k_diff":
|
|
73
|
+
from recce.tasks.top_k import TopKDiffCheckValidator
|
|
74
|
+
|
|
75
|
+
validator = TopKDiffCheckValidator()
|
|
76
|
+
elif check_type == "histogram_diff":
|
|
77
|
+
from recce.tasks.histogram import HistogramDiffCheckValidator
|
|
78
|
+
|
|
79
|
+
validator = HistogramDiffCheckValidator()
|
|
80
|
+
else:
|
|
81
|
+
validator = CheckValidator()
|
|
82
|
+
validator.validate(check)
|
|
83
|
+
except Exception as e:
|
|
84
|
+
import json
|
|
85
|
+
|
|
86
|
+
raise RecceConfigException(
|
|
87
|
+
f"Load preset checks failed from '{self.config_file}'\n{json.dumps(check, indent=2)}", cause=e
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
def generate_template(self):
|
|
91
|
+
data = yaml.CommentedMap(checks=yaml.CommentedSeq())
|
|
92
|
+
data.yaml_set_comment_before_after_key("checks", before=RECCE_PRESET_CHECK_COMMENT)
|
|
93
|
+
# Define default preset checks
|
|
94
|
+
default_checks = [
|
|
95
|
+
yaml.CommentedMap(
|
|
96
|
+
name="Row count diff",
|
|
97
|
+
description="Check the row count diff for all table models.",
|
|
98
|
+
type="row_count_diff",
|
|
99
|
+
params={"select": "state:modified,config.materialized:table"},
|
|
100
|
+
),
|
|
101
|
+
yaml.CommentedMap(
|
|
102
|
+
name="Schema diff",
|
|
103
|
+
description="Check the schema diff for all nodes.",
|
|
104
|
+
type="schema_diff",
|
|
105
|
+
),
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
for check in default_checks:
|
|
109
|
+
data["checks"].append(check)
|
|
110
|
+
|
|
111
|
+
return data
|
|
112
|
+
|
|
113
|
+
def get(self, key, default=None):
|
|
114
|
+
return self.config.get(key, default)
|
|
115
|
+
|
|
116
|
+
def set(self, key, value):
|
|
117
|
+
self.config[key] = value
|
|
118
|
+
|
|
119
|
+
def save(self):
|
|
120
|
+
with open(RECCE_CONFIG_FILE, "w", encoding="utf-8") as f:
|
|
121
|
+
yaml.dump(self.config, f)
|
|
122
|
+
|
|
123
|
+
def __str__(self):
|
|
124
|
+
return yaml.dump(self.config)
|
|
125
|
+
|
|
126
|
+
def __repr__(self):
|
|
127
|
+
return self.__str__()
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import base64
|
|
2
|
+
import os.path
|
|
3
|
+
import random
|
|
4
|
+
import threading
|
|
5
|
+
from http.server import BaseHTTPRequestHandler, HTTPServer
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
from typing import Tuple
|
|
8
|
+
from urllib.parse import parse_qs, urlparse
|
|
9
|
+
|
|
10
|
+
from cryptography.hazmat.backends import default_backend
|
|
11
|
+
from cryptography.hazmat.primitives import hashes, serialization
|
|
12
|
+
from cryptography.hazmat.primitives.asymmetric import padding, rsa
|
|
13
|
+
from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey, RSAPublicKey
|
|
14
|
+
from rich.console import Console
|
|
15
|
+
|
|
16
|
+
from recce.event import update_recce_api_token
|
|
17
|
+
from recce.exceptions import RecceConfigException
|
|
18
|
+
from recce.util.onboarding_state import update_onboarding_state
|
|
19
|
+
from recce.util.recce_cloud import RECCE_CLOUD_BASE_URL, RecceCloud
|
|
20
|
+
|
|
21
|
+
console = Console()
|
|
22
|
+
|
|
23
|
+
static_folder_path = Path(__file__).parent / "data"
|
|
24
|
+
_server_lock = threading.Lock()
|
|
25
|
+
_connection_url = None
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def decrypt_code(private_key: RSAPrivateKey, code: str) -> str:
|
|
29
|
+
ciphertext = base64.b64decode(code)
|
|
30
|
+
plaintext = private_key.decrypt(
|
|
31
|
+
ciphertext,
|
|
32
|
+
padding.OAEP(
|
|
33
|
+
mgf=padding.MGF1(algorithm=hashes.SHA1()), # Node.js uses SHA1 by default
|
|
34
|
+
algorithm=hashes.SHA1(),
|
|
35
|
+
label=None,
|
|
36
|
+
),
|
|
37
|
+
)
|
|
38
|
+
return plaintext.decode("utf-8")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def handle_callback_request(query_string: str, private_key: RSAPrivateKey):
|
|
42
|
+
query_params = parse_qs(query_string)
|
|
43
|
+
code = query_params.get("code", [None])[0]
|
|
44
|
+
if not code:
|
|
45
|
+
raise RecceConfigException("Missing `code` in query")
|
|
46
|
+
|
|
47
|
+
api_token = decrypt_code(private_key, code)
|
|
48
|
+
if not RecceCloud(api_token).verify_token():
|
|
49
|
+
raise RecceConfigException("Invalid Recce Cloud API token")
|
|
50
|
+
|
|
51
|
+
update_recce_api_token(api_token)
|
|
52
|
+
update_onboarding_state(api_token, False)
|
|
53
|
+
|
|
54
|
+
return api_token # for testability/debugging
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def make_callback_handler(private_key: RSAPrivateKey):
|
|
58
|
+
class OneTimeHTTPRequestHandler(BaseHTTPRequestHandler):
|
|
59
|
+
def do_GET(self):
|
|
60
|
+
try:
|
|
61
|
+
with open(os.path.join(static_folder_path, "auth_callback.html"), "r", encoding="utf-8") as f:
|
|
62
|
+
callback_html_content = f.read()
|
|
63
|
+
|
|
64
|
+
# Parse query parameters
|
|
65
|
+
parsed_url = urlparse(self.path)
|
|
66
|
+
|
|
67
|
+
handle_callback_request(parsed_url.query, private_key)
|
|
68
|
+
|
|
69
|
+
# Construct HTML content
|
|
70
|
+
self.send_response(200)
|
|
71
|
+
self.send_header("Content-Type", "text/html")
|
|
72
|
+
self.send_header("Content-Length", str(len(callback_html_content.encode())))
|
|
73
|
+
self.end_headers()
|
|
74
|
+
self.wfile.write(callback_html_content.encode())
|
|
75
|
+
|
|
76
|
+
except Exception:
|
|
77
|
+
console.print_exception()
|
|
78
|
+
self.send_response(500)
|
|
79
|
+
self.end_headers()
|
|
80
|
+
self.wfile.write(b"<h1>Internal Server Error</h1>")
|
|
81
|
+
finally:
|
|
82
|
+
# Shut down the server after handling the first request
|
|
83
|
+
# Shutdown in a new thread to avoid deadlock
|
|
84
|
+
self.server.server_close()
|
|
85
|
+
threading.Thread(target=self.server.shutdown, daemon=True).start()
|
|
86
|
+
|
|
87
|
+
def log_message(self, format, *args):
|
|
88
|
+
# Suppress default logging
|
|
89
|
+
return
|
|
90
|
+
|
|
91
|
+
return OneTimeHTTPRequestHandler
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def is_callback_server_running():
|
|
95
|
+
return _server_lock.locked()
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def get_connection_url():
|
|
99
|
+
return _connection_url
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def run_one_time_http_server(private_key: RSAPrivateKey, port=8080):
|
|
103
|
+
handler = make_callback_handler(private_key)
|
|
104
|
+
server = HTTPServer(("localhost", port), handler)
|
|
105
|
+
server.serve_forever()
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def prepare_connection_url(public_key: RSAPublicKey):
|
|
109
|
+
public_key_pem_bytes = public_key.public_bytes(
|
|
110
|
+
encoding=serialization.Encoding.PEM,
|
|
111
|
+
format=serialization.PublicFormat.SubjectPublicKeyInfo,
|
|
112
|
+
)
|
|
113
|
+
public_key_pem_str = base64.b64encode(public_key_pem_bytes).decode("utf-8")
|
|
114
|
+
callback_port = random.randint(10000, 15000)
|
|
115
|
+
connect_url = f"{RECCE_CLOUD_BASE_URL}/connect?_key={public_key_pem_str}&_port={callback_port}"
|
|
116
|
+
return connect_url, callback_port
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def generate_key_pair() -> Tuple[RSAPrivateKey, RSAPublicKey]:
|
|
120
|
+
key_size = 2048 # Should be at least 2048
|
|
121
|
+
|
|
122
|
+
private_key = rsa.generate_private_key(
|
|
123
|
+
public_exponent=65537, key_size=key_size, backend=default_backend() # Do not change
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
public_key = private_key.public_key()
|
|
127
|
+
return private_key, public_key
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def connect_to_cloud_background_task(private_key: RSAPrivateKey, callback_port, connection_url):
|
|
131
|
+
if is_callback_server_running():
|
|
132
|
+
return
|
|
133
|
+
|
|
134
|
+
with _server_lock:
|
|
135
|
+
global _connection_url
|
|
136
|
+
_connection_url = connection_url
|
|
137
|
+
run_one_time_http_server(private_key, callback_port)
|
|
138
|
+
_connection_url = None
|
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import json
|
|
3
|
+
import logging
|
|
4
|
+
import os
|
|
5
|
+
from dataclasses import dataclass, field
|
|
6
|
+
from typing import Callable, Dict, List, Optional, Set, Tuple
|
|
7
|
+
|
|
8
|
+
from recce.adapter.base import BaseAdapter
|
|
9
|
+
from recce.models import Check, Run
|
|
10
|
+
from recce.models.types import LineageDiff
|
|
11
|
+
from recce.state import (
|
|
12
|
+
GitRepoInfo,
|
|
13
|
+
PullRequestInfo,
|
|
14
|
+
RecceState,
|
|
15
|
+
RecceStateLoader,
|
|
16
|
+
RecceStateMetadata,
|
|
17
|
+
)
|
|
18
|
+
from recce.util.recce_cloud import set_recce_cloud_onboarding_state
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger("uvicorn")
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class RecceContext:
|
|
25
|
+
review_mode: bool = False
|
|
26
|
+
adapter_type: str = None
|
|
27
|
+
adapter: BaseAdapter = None
|
|
28
|
+
state_loader: RecceStateLoader = None
|
|
29
|
+
runs: List[Run] = field(default_factory=list)
|
|
30
|
+
checks: List[Check] = field(default_factory=list)
|
|
31
|
+
|
|
32
|
+
@classmethod
|
|
33
|
+
def load(cls, **kwargs):
|
|
34
|
+
state_loader: RecceStateLoader = kwargs.get("state_loader")
|
|
35
|
+
is_review_mode = kwargs.get("review", False)
|
|
36
|
+
|
|
37
|
+
context = cls(
|
|
38
|
+
review_mode=is_review_mode,
|
|
39
|
+
state_loader=state_loader,
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
# Initiate the adapter
|
|
43
|
+
if kwargs.get("sqlmesh", False):
|
|
44
|
+
logger.warning("SQLMesh adapter is still in EXPERIMENTAL mode.")
|
|
45
|
+
from recce.adapter.sqlmesh_adapter import SqlmeshAdapter
|
|
46
|
+
|
|
47
|
+
context.adapter_type = "sqlmesh"
|
|
48
|
+
context.adapter = SqlmeshAdapter.load(**kwargs)
|
|
49
|
+
else:
|
|
50
|
+
from recce.adapter.dbt_adapter import DbtAdapter
|
|
51
|
+
|
|
52
|
+
context.adapter_type = "dbt"
|
|
53
|
+
context.adapter = DbtAdapter.load(**kwargs)
|
|
54
|
+
|
|
55
|
+
# Import state
|
|
56
|
+
if state_loader is not None:
|
|
57
|
+
state = state_loader.load()
|
|
58
|
+
if state:
|
|
59
|
+
context.import_state(state)
|
|
60
|
+
|
|
61
|
+
if is_review_mode:
|
|
62
|
+
if not state:
|
|
63
|
+
raise Exception("The state file is required for review mode")
|
|
64
|
+
|
|
65
|
+
return context
|
|
66
|
+
|
|
67
|
+
def get_model(self, model_id: str, base=False):
|
|
68
|
+
return self.adapter.get_model(model_id, base=base)
|
|
69
|
+
|
|
70
|
+
def get_node_name_by_id(self, unique_id: object) -> object:
|
|
71
|
+
return self.adapter.get_node_name_by_id(unique_id)
|
|
72
|
+
|
|
73
|
+
def generate_sql(self, sql_template: str, base: bool = False, context: Dict = {}):
|
|
74
|
+
self.adapter.generate_sql(sql_template, base=base, context=context)
|
|
75
|
+
|
|
76
|
+
def get_lineage(self, base: Optional[bool] = False):
|
|
77
|
+
return self.adapter.get_lineage(base=base)
|
|
78
|
+
|
|
79
|
+
def get_lineage_diff(self) -> LineageDiff:
|
|
80
|
+
return self.adapter.get_lineage_diff()
|
|
81
|
+
|
|
82
|
+
def build_name_to_unique_id_index(self, excluded_types: Set = None) -> Dict[str, str]:
|
|
83
|
+
name_to_unique_id = {}
|
|
84
|
+
curr = self.get_lineage(base=False)
|
|
85
|
+
base = self.get_lineage(base=True)
|
|
86
|
+
|
|
87
|
+
for unique_id, node in curr["nodes"].items():
|
|
88
|
+
if excluded_types and node.get("resource_type") in excluded_types:
|
|
89
|
+
continue
|
|
90
|
+
name_to_unique_id[node["name"]] = unique_id
|
|
91
|
+
for unique_id, node in base["nodes"].items():
|
|
92
|
+
if excluded_types and node.get("resource_type") in excluded_types:
|
|
93
|
+
continue
|
|
94
|
+
name_to_unique_id[node["name"]] = unique_id
|
|
95
|
+
return name_to_unique_id
|
|
96
|
+
|
|
97
|
+
def start_monitor_artifacts(self, callback: Callable = None):
|
|
98
|
+
self.adapter.start_monitor_artifacts(callback=callback)
|
|
99
|
+
|
|
100
|
+
def stop_monitor_artifacts(self):
|
|
101
|
+
self.adapter.stop_monitor_artifacts()
|
|
102
|
+
|
|
103
|
+
def refresh_manifest(self, refresh_file_path: str = None):
|
|
104
|
+
self.adapter.refresh(refresh_file_path)
|
|
105
|
+
|
|
106
|
+
def start_monitor_base_env(self, callback: Callable = None):
|
|
107
|
+
self.adapter.start_monitor_base_env(callback=callback)
|
|
108
|
+
|
|
109
|
+
def stop_monitor_base_env(self):
|
|
110
|
+
self.adapter.stop_monitor_base_env()
|
|
111
|
+
|
|
112
|
+
def export_state(self) -> RecceState:
|
|
113
|
+
"""
|
|
114
|
+
Export the state to a RecceState object.
|
|
115
|
+
"""
|
|
116
|
+
state = RecceState()
|
|
117
|
+
state.metadata = RecceStateMetadata()
|
|
118
|
+
|
|
119
|
+
# runs & checks & artifacts
|
|
120
|
+
state.runs = self.runs
|
|
121
|
+
state.checks = self.checks
|
|
122
|
+
state.artifacts = self.adapter.export_artifacts()
|
|
123
|
+
|
|
124
|
+
# git & pull_request. If in review mode, use the review state
|
|
125
|
+
if self.review_mode:
|
|
126
|
+
state.git = self.state_loader.state.git
|
|
127
|
+
state.pull_request = self.state_loader.state.pull_request
|
|
128
|
+
else:
|
|
129
|
+
git = GitRepoInfo.from_current_repository()
|
|
130
|
+
if git:
|
|
131
|
+
state.git = git
|
|
132
|
+
if self.state_loader.pr_info:
|
|
133
|
+
state.pull_request = self.state_loader.pr_info
|
|
134
|
+
|
|
135
|
+
return state
|
|
136
|
+
|
|
137
|
+
def export_demo_state(self) -> RecceState:
|
|
138
|
+
"""
|
|
139
|
+
Export the demo state to a RecceState object for the demo sites.
|
|
140
|
+
"""
|
|
141
|
+
state = RecceState()
|
|
142
|
+
state.metadata = RecceStateMetadata()
|
|
143
|
+
|
|
144
|
+
# runs & checks
|
|
145
|
+
state.runs = self.runs
|
|
146
|
+
state.checks = self.checks
|
|
147
|
+
state.artifacts = self.adapter.export_artifacts()
|
|
148
|
+
git = GitRepoInfo.from_current_repository()
|
|
149
|
+
if git:
|
|
150
|
+
state.git = git
|
|
151
|
+
pr = PullRequestInfo(url=os.getenv("RECCE_PR_URL"))
|
|
152
|
+
state.pull_request = pr
|
|
153
|
+
|
|
154
|
+
return state
|
|
155
|
+
|
|
156
|
+
def sync_state(self, method: str):
|
|
157
|
+
"""
|
|
158
|
+
Sync the state with the remote.
|
|
159
|
+
|
|
160
|
+
:param method: merge, revert, overwrite
|
|
161
|
+
|
|
162
|
+
"""
|
|
163
|
+
if method == "merge":
|
|
164
|
+
self.state_loader.refresh()
|
|
165
|
+
self.import_state(self.state_loader.state, merge=True)
|
|
166
|
+
state = self.export_state()
|
|
167
|
+
self.state_loader.export(state)
|
|
168
|
+
elif method == "revert":
|
|
169
|
+
self.state_loader.refresh()
|
|
170
|
+
self.import_state(self.state_loader.state, merge=False)
|
|
171
|
+
elif method == "overwrite":
|
|
172
|
+
state = self.export_state()
|
|
173
|
+
self.state_loader.export(state)
|
|
174
|
+
else:
|
|
175
|
+
raise Exception(f"Unsupported method: {method}")
|
|
176
|
+
|
|
177
|
+
def _merge_checks(self, import_checks: list[Check]):
|
|
178
|
+
checks = list(self.checks)
|
|
179
|
+
imports = 0
|
|
180
|
+
|
|
181
|
+
def _calculate_checksum(c: Check):
|
|
182
|
+
payload = json.dumps(
|
|
183
|
+
{
|
|
184
|
+
"type": str(c.type),
|
|
185
|
+
"params": c.params,
|
|
186
|
+
"view_options": c.view_options,
|
|
187
|
+
},
|
|
188
|
+
sort_keys=True,
|
|
189
|
+
)
|
|
190
|
+
return hashlib.sha256(payload.encode()).hexdigest()
|
|
191
|
+
|
|
192
|
+
checksum_map = {_calculate_checksum(c): c for c in self.checks if c.is_preset}
|
|
193
|
+
check_map = {c.check_id: c for c in self.checks}
|
|
194
|
+
|
|
195
|
+
# merge checks
|
|
196
|
+
for imported in import_checks:
|
|
197
|
+
check: Check = None
|
|
198
|
+
if imported.check_id in check_map:
|
|
199
|
+
check = check_map[imported.check_id]
|
|
200
|
+
elif imported.is_preset:
|
|
201
|
+
checksum = _calculate_checksum(imported)
|
|
202
|
+
if checksum in checksum_map:
|
|
203
|
+
check = checksum_map[checksum]
|
|
204
|
+
if check:
|
|
205
|
+
is_merge = check.merge(imported)
|
|
206
|
+
if is_merge:
|
|
207
|
+
imports += 1
|
|
208
|
+
else:
|
|
209
|
+
checks.append(imported)
|
|
210
|
+
imports += 1
|
|
211
|
+
self.checks = checks
|
|
212
|
+
return imports
|
|
213
|
+
|
|
214
|
+
def _merge_runs(self, import_runs: list[Run]):
|
|
215
|
+
runs = list(self.runs)
|
|
216
|
+
run_set = {run.run_id for run in self.runs}
|
|
217
|
+
imports = 0
|
|
218
|
+
|
|
219
|
+
for run in import_runs:
|
|
220
|
+
if run.run_id not in run_set:
|
|
221
|
+
runs.append(run)
|
|
222
|
+
imports += 1
|
|
223
|
+
|
|
224
|
+
runs.sort(key=lambda x: x.run_at)
|
|
225
|
+
self.runs = runs
|
|
226
|
+
return imports
|
|
227
|
+
|
|
228
|
+
def import_state(self, import_state: RecceState, merge: bool = True):
|
|
229
|
+
"""
|
|
230
|
+
Import the state from another RecceState object.
|
|
231
|
+
|
|
232
|
+
:param import_state: the state to import
|
|
233
|
+
:param merge: whether to merge the state or replace the current state
|
|
234
|
+
"""
|
|
235
|
+
import_runs = 0
|
|
236
|
+
import_checks = 0
|
|
237
|
+
if merge:
|
|
238
|
+
import_runs = self._merge_runs(import_state.runs)
|
|
239
|
+
import_checks = self._merge_checks(import_state.checks)
|
|
240
|
+
else:
|
|
241
|
+
self.runs = list(import_state.runs)
|
|
242
|
+
import_runs = len(self.runs)
|
|
243
|
+
self.checks = list(import_state.checks)
|
|
244
|
+
import_checks = len(self.checks)
|
|
245
|
+
|
|
246
|
+
# always merge for artifacts
|
|
247
|
+
if self.adapter:
|
|
248
|
+
self.adapter.import_artifacts(import_state.artifacts)
|
|
249
|
+
|
|
250
|
+
return import_runs, import_checks
|
|
251
|
+
|
|
252
|
+
def import_checks(self, import_state: RecceState, merge: bool = True):
|
|
253
|
+
"""
|
|
254
|
+
Import the checks from another RecceState object.
|
|
255
|
+
|
|
256
|
+
:param import_state: the state to import
|
|
257
|
+
:param merge: whether to merge the state or replace the current state
|
|
258
|
+
"""
|
|
259
|
+
|
|
260
|
+
if merge:
|
|
261
|
+
import_checks = self._merge_checks(import_state.checks)
|
|
262
|
+
else:
|
|
263
|
+
self.checks = list(import_state.checks)
|
|
264
|
+
import_checks = len(self.checks)
|
|
265
|
+
|
|
266
|
+
return import_checks
|
|
267
|
+
|
|
268
|
+
def mark_onboarding_completed(self):
|
|
269
|
+
if self.state_loader.cloud_mode:
|
|
270
|
+
try:
|
|
271
|
+
token = self.state_loader.cloud_options.get("github_token")
|
|
272
|
+
set_recce_cloud_onboarding_state(token, "completed")
|
|
273
|
+
except Exception as e:
|
|
274
|
+
logger.debug(f"Failed to mark onboarding completed in Recce Cloud. Reason: {str(e)}")
|
|
275
|
+
else:
|
|
276
|
+
# Skip the onboarding state for non-cloud mode
|
|
277
|
+
pass
|
|
278
|
+
|
|
279
|
+
@staticmethod
|
|
280
|
+
def verify_required_artifacts(**kwargs) -> Tuple[bool, Optional[str]]:
|
|
281
|
+
if kwargs.get("sqlmesh", False):
|
|
282
|
+
pass
|
|
283
|
+
else:
|
|
284
|
+
from recce.adapter.dbt_adapter import DbtAdapter
|
|
285
|
+
|
|
286
|
+
try:
|
|
287
|
+
DbtAdapter.load(**kwargs)
|
|
288
|
+
except FileNotFoundError as e:
|
|
289
|
+
return False, f"Cannot load the manifest: '{e.filename}'. Type 'recce debug'."
|
|
290
|
+
|
|
291
|
+
return True, None
|
|
292
|
+
|
|
293
|
+
def support_tasks(self):
|
|
294
|
+
return self.adapter.support_tasks()
|
|
295
|
+
|
|
296
|
+
def state_loader_mode(self):
|
|
297
|
+
"""
|
|
298
|
+
The state loader mode is used for telemetry purpose.
|
|
299
|
+
"""
|
|
300
|
+
if os.environ.get("DEMO", False):
|
|
301
|
+
return "demo"
|
|
302
|
+
|
|
303
|
+
if not self.state_loader:
|
|
304
|
+
return "none"
|
|
305
|
+
|
|
306
|
+
if self.state_loader.cloud_mode:
|
|
307
|
+
return "cloud"
|
|
308
|
+
elif self.state_loader.state_file:
|
|
309
|
+
return "file"
|
|
310
|
+
else:
|
|
311
|
+
return "none"
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
recce_context: Optional[RecceContext] = None
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def load_context(**kwargs) -> RecceContext:
|
|
318
|
+
global recce_context
|
|
319
|
+
if recce_context is None:
|
|
320
|
+
recce_context = RecceContext.load(**kwargs)
|
|
321
|
+
return recce_context
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def default_context() -> RecceContext:
|
|
325
|
+
return recce_context
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
def set_default_context(context: RecceContext):
|
|
329
|
+
"""
|
|
330
|
+
Set the default context for the recce. This is for test purpose.
|
|
331
|
+
"""
|
|
332
|
+
|
|
333
|
+
global recce_context
|
|
334
|
+
recce_context = context
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import difflib
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def diff_text(before: str, after: str):
|
|
7
|
+
if before is None and after is None:
|
|
8
|
+
print("not found in both states")
|
|
9
|
+
return
|
|
10
|
+
elif before == after:
|
|
11
|
+
print("no changes")
|
|
12
|
+
return
|
|
13
|
+
|
|
14
|
+
diff_output = difflib.unified_diff(before.splitlines(), after.splitlines(), "base", "current", lineterm="")
|
|
15
|
+
for line in diff_output:
|
|
16
|
+
print(line)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def diff_dataframe(before: pd.DataFrame, after: pd.DataFrame):
|
|
20
|
+
if before is None and after is None:
|
|
21
|
+
print("not found in both states")
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
before_aligned, after_aligned = before.align(after)
|
|
25
|
+
diff = before_aligned.compare(after_aligned, result_names=("base", "current"))
|
|
26
|
+
print(diff.to_string(na_rep="-"))
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
event_api_key: <API_KEY>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
https://64b0b12395a4f8596e081b26ca720719@o1081482.ingest.sentry.io/4506268402515968
|