├── .dockerignore ├── .editorconfig ├── .flake8 ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── PULL_REQUEST_TITLE_CHECKER.json ├── images │ └── logo.svg ├── scripts │ ├── bump_amplitude_release.sh │ └── deploy_notify.sh └── workflows │ ├── build-statics.yaml │ ├── ci-statics.yaml │ ├── dbt-compatible-tests.yaml │ ├── e2e-windows-tests.yaml │ ├── flake8.yaml │ ├── nightly.yaml │ ├── pr.yaml │ ├── pypi.yaml │ ├── tests.yaml │ └── tox.yaml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── DEVELOP.md ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── connect.py ├── docs ├── assets │ ├── metrics-composition.png │ └── metrics-uniqueness.png ├── commands │ ├── piperider-compare-report.md │ ├── piperider-debug.md │ ├── piperider-generate-report.md │ ├── piperider-init.md │ ├── piperider-run.md │ ├── piperider-version.md │ └── piperider.md ├── config.md ├── dbt-integration.md ├── metrics.md └── project.md ├── e2e-jaffle-shop ├── 0001-apply-tags.patch ├── 0002-Add-average_value_per_order-to-customers.patch ├── gen_seed.py ├── run.bat ├── run.sh └── windows-result-checker.py ├── entrypoint.sh ├── images ├── compare_pipe.gif ├── icons │ ├── empty.md │ ├── icon-bs-check2-gray.png │ ├── icon-bs-check2-gray@2x.png │ ├── icon-bs-check2.png │ ├── icon-bs-check2@2x.png │ ├── icon-bs-shield-check.png │ ├── icon-bs-shield-check@2x.png │ ├── icon-bs-shield-cross-yellow.png │ ├── icon-bs-shield-cross-yellow@2x.png │ ├── icon-bs-shield-cross.png │ ├── icon-bs-shield-cross@2x.png │ ├── icon-bs-shield.png │ ├── icon-bs-shield@2x.png │ ├── icon-diff-delta-explicit.png │ ├── icon-diff-delta-explicit@2x.png │ ├── icon-diff-delta-implicit.png │ ├── icon-diff-delta-implicit@2x.png │ ├── icon-diff-delta-minus.png │ ├── icon-diff-delta-minus@2x.png │ ├── icon-diff-delta-plus.png │ ├── icon-diff-delta-plus@2x.png │ ├── icon-triangle-yellow.png │ ├── icon-triangle-yellow@2x.png │ ├── icon-triangle.png │ ├── icon-triangle@2x.png │ ├── model-icon-ephemeral.png │ ├── model-icon-ephemeral@2x.png │ ├── model-icon-incremental.png │ ├── model-icon-incremental@2x.png │ ├── model-icon-table.png │ ├── model-icon-table@2x.png │ ├── model-icon-view.png │ └── model-icon-view@2x.png ├── init_pipe.gif ├── piperider_comparison_view.png ├── piperider_logo.png ├── piperider_single_run.png ├── report_pipe.gif └── run_pipe.gif ├── piperider_cli ├── SENTRY_DNS ├── VERSION ├── __init__.py ├── __main__.py ├── cli.py ├── cli_utils │ ├── __init__.py │ ├── cloud.py │ ├── compare_with_recipe.py │ └── run_cmd.py ├── cloud │ └── __init__.py ├── cloud_connector.py ├── compare_report.py ├── configuration.py ├── data │ ├── CONFIG │ ├── __init__.py │ ├── piperider-init-template │ │ ├── config.yml │ │ └── gitignore │ └── report │ │ ├── .gitignore │ │ ├── comparison-report │ │ ├── asset-manifest.json │ │ ├── index.html │ │ ├── logo │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── android-icon-144x144.png │ │ │ ├── android-icon-192x192.png │ │ │ ├── android-icon-36x36.png │ │ │ ├── android-icon-48x48.png │ │ │ ├── android-icon-72x72.png │ │ │ ├── android-icon-96x96.png │ │ │ ├── apple-icon-114x114.png │ │ │ ├── apple-icon-120x120.png │ │ │ ├── apple-icon-144x144.png │ │ │ ├── apple-icon-152x152.png │ │ │ ├── apple-icon-180x180.png │ │ │ ├── apple-icon-57x57.png │ │ │ ├── apple-icon-60x60.png │ │ │ ├── apple-icon-72x72.png │ │ │ ├── apple-icon-76x76.png │ │ │ ├── apple-icon-precomposed.png │ │ │ ├── apple-icon.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── browserconfig.xml │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon-96x96.png │ │ │ ├── favicon.ico │ │ │ ├── logo.svg │ │ │ ├── manifest.json │ │ │ ├── ms-icon-144x144.png │ │ │ ├── ms-icon-150x150.png │ │ │ ├── ms-icon-310x310.png │ │ │ ├── ms-icon-70x70.png │ │ │ ├── mstile-144x144.png │ │ │ ├── mstile-150x150.png │ │ │ ├── mstile-310x150.png │ │ │ ├── mstile-310x310.png │ │ │ ├── mstile-70x70.png │ │ │ └── safari-pinned-tab.svg │ │ └── static │ │ │ ├── css │ │ │ ├── 446.5d87f4f7.chunk.css │ │ │ ├── 446.5d87f4f7.chunk.css.map │ │ │ ├── 628.5d87f4f7.chunk.css │ │ │ ├── 628.5d87f4f7.chunk.css.map │ │ │ ├── main.fcbcb80f.css │ │ │ └── main.fcbcb80f.css.map │ │ │ ├── js │ │ │ ├── 381.3aaaca0b.chunk.js │ │ │ ├── 446.47d6a9d4.chunk.js │ │ │ ├── 479.d5e430c3.chunk.js │ │ │ ├── 479.d5e430c3.chunk.js.LICENSE.txt │ │ │ ├── 628.15fb4e78.chunk.js │ │ │ ├── 759.69cdd006.chunk.js │ │ │ ├── main.acf3e24f.js │ │ │ └── main.acf3e24f.js.LICENSE.txt │ │ │ └── media │ │ │ ├── Inter-Black.ab57b908749eb205e3ad.woff │ │ │ ├── Inter-Black.cadfd7434852779eb395.woff2 │ │ │ ├── Inter-BlackItalic.9bb4dd54e5afbea2e0ac.woff2 │ │ │ ├── Inter-BlackItalic.f0098e273d2a3758b89c.woff │ │ │ ├── Inter-Bold.1577ca92013647c816b5.woff │ │ │ ├── Inter-Bold.f57c31edca48068386d7.woff2 │ │ │ ├── Inter-BoldItalic.52e97aac5945285c9933.woff │ │ │ ├── Inter-BoldItalic.5b7f79817b551400186a.woff2 │ │ │ ├── Inter-ExtraBold.0321ea88d696270daf4b.woff │ │ │ ├── Inter-ExtraBold.a611efd96602ca47acd9.woff2 │ │ │ ├── Inter-ExtraBoldItalic.43f46f665391ff324c72.woff2 │ │ │ ├── Inter-ExtraBoldItalic.dc0b36ae1c1bdac232e7.woff │ │ │ ├── Inter-ExtraLight.4e029f034c7e7263df9a.woff │ │ │ ├── Inter-ExtraLight.bafff4ae7f2a3395aa13.woff2 │ │ │ ├── Inter-ExtraLightItalic.124644177779db0a8867.woff2 │ │ │ ├── Inter-ExtraLightItalic.ff3def84a34422de5487.woff │ │ │ ├── Inter-Italic.9736c3faff86c01270b2.woff2 │ │ │ ├── Inter-Italic.ce6bab8bc932d6080ec1.woff │ │ │ ├── Inter-Light.919d6ffdd987dc2e4717.woff │ │ │ ├── Inter-Light.aafd1643606ee83ad4cb.woff2 │ │ │ ├── Inter-LightItalic.7f7cde8e1548e11231fb.woff2 │ │ │ ├── Inter-LightItalic.e66e7a760a286c694d2b.woff │ │ │ ├── Inter-Medium.5a92f7b05463ecd61f45.woff │ │ │ ├── Inter-Medium.a6ca36dde32b3a1d0fd4.woff2 │ │ │ ├── Inter-MediumItalic.dbc1ed152c7b11f501a3.woff2 │ │ │ ├── Inter-MediumItalic.e3618413f59e00041fb3.woff │ │ │ ├── Inter-Regular.222064f2a764069868f4.woff2 │ │ │ ├── Inter-Regular.67a27362108220436ffb.woff │ │ │ ├── Inter-SemiBold.599ce7634f46c5024ad0.woff2 │ │ │ ├── Inter-SemiBold.c2e7341dd6ac6502be69.woff │ │ │ ├── Inter-SemiBoldItalic.09bc481607bd529abda7.woff2 │ │ │ ├── Inter-SemiBoldItalic.43f7c276720845c6bb59.woff │ │ │ ├── Inter-Thin.92cada3d91581eb5112d.woff2 │ │ │ ├── Inter-Thin.df0b1bcf558ccd5b48a2.woff │ │ │ ├── Inter-ThinItalic.78bf87d2ea41ac4365c1.woff │ │ │ ├── Inter-ThinItalic.82dd2dc2fb674d8273e4.woff2 │ │ │ ├── Inter-italic.var.28904cc0eac675e1d19e.woff2 │ │ │ ├── Inter-roman.var.f05060926bf5023f9930.woff2 │ │ │ └── Inter.var.c3f97a25f56b5b416e49.woff2 │ │ └── single-report │ │ ├── asset-manifest.json │ │ ├── index.html │ │ ├── logo │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── android-icon-144x144.png │ │ ├── android-icon-192x192.png │ │ ├── android-icon-36x36.png │ │ ├── android-icon-48x48.png │ │ ├── android-icon-72x72.png │ │ ├── android-icon-96x96.png │ │ ├── apple-icon-114x114.png │ │ ├── apple-icon-120x120.png │ │ ├── apple-icon-144x144.png │ │ ├── apple-icon-152x152.png │ │ ├── apple-icon-180x180.png │ │ ├── apple-icon-57x57.png │ │ ├── apple-icon-60x60.png │ │ ├── apple-icon-72x72.png │ │ ├── apple-icon-76x76.png │ │ ├── apple-icon-precomposed.png │ │ ├── apple-icon.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ ├── logo.svg │ │ ├── manifest.json │ │ ├── ms-icon-144x144.png │ │ ├── ms-icon-150x150.png │ │ ├── ms-icon-310x310.png │ │ ├── ms-icon-70x70.png │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ └── safari-pinned-tab.svg │ │ └── static │ │ ├── css │ │ ├── 446.5d87f4f7.chunk.css │ │ ├── 446.5d87f4f7.chunk.css.map │ │ ├── 628.5d87f4f7.chunk.css │ │ ├── 628.5d87f4f7.chunk.css.map │ │ ├── main.fcbcb80f.css │ │ └── main.fcbcb80f.css.map │ │ ├── js │ │ ├── 381.3aaaca0b.chunk.js │ │ ├── 446.47d6a9d4.chunk.js │ │ ├── 479.d5e430c3.chunk.js │ │ ├── 479.d5e430c3.chunk.js.LICENSE.txt │ │ ├── 628.15fb4e78.chunk.js │ │ ├── 759.69cdd006.chunk.js │ │ ├── main.ca068521.js │ │ └── main.ca068521.js.LICENSE.txt │ │ └── media │ │ ├── Inter-Black.ab57b908749eb205e3ad.woff │ │ ├── Inter-Black.cadfd7434852779eb395.woff2 │ │ ├── Inter-BlackItalic.9bb4dd54e5afbea2e0ac.woff2 │ │ ├── Inter-BlackItalic.f0098e273d2a3758b89c.woff │ │ ├── Inter-Bold.1577ca92013647c816b5.woff │ │ ├── Inter-Bold.f57c31edca48068386d7.woff2 │ │ ├── Inter-BoldItalic.52e97aac5945285c9933.woff │ │ ├── Inter-BoldItalic.5b7f79817b551400186a.woff2 │ │ ├── Inter-ExtraBold.0321ea88d696270daf4b.woff │ │ ├── Inter-ExtraBold.a611efd96602ca47acd9.woff2 │ │ ├── Inter-ExtraBoldItalic.43f46f665391ff324c72.woff2 │ │ ├── Inter-ExtraBoldItalic.dc0b36ae1c1bdac232e7.woff │ │ ├── Inter-ExtraLight.4e029f034c7e7263df9a.woff │ │ ├── Inter-ExtraLight.bafff4ae7f2a3395aa13.woff2 │ │ ├── Inter-ExtraLightItalic.124644177779db0a8867.woff2 │ │ ├── Inter-ExtraLightItalic.ff3def84a34422de5487.woff │ │ ├── Inter-Italic.9736c3faff86c01270b2.woff2 │ │ ├── Inter-Italic.ce6bab8bc932d6080ec1.woff │ │ ├── Inter-Light.919d6ffdd987dc2e4717.woff │ │ ├── Inter-Light.aafd1643606ee83ad4cb.woff2 │ │ ├── Inter-LightItalic.7f7cde8e1548e11231fb.woff2 │ │ ├── Inter-LightItalic.e66e7a760a286c694d2b.woff │ │ ├── Inter-Medium.5a92f7b05463ecd61f45.woff │ │ ├── Inter-Medium.a6ca36dde32b3a1d0fd4.woff2 │ │ ├── Inter-MediumItalic.dbc1ed152c7b11f501a3.woff2 │ │ ├── Inter-MediumItalic.e3618413f59e00041fb3.woff │ │ ├── Inter-Regular.222064f2a764069868f4.woff2 │ │ ├── Inter-Regular.67a27362108220436ffb.woff │ │ ├── Inter-SemiBold.599ce7634f46c5024ad0.woff2 │ │ ├── Inter-SemiBold.c2e7341dd6ac6502be69.woff │ │ ├── Inter-SemiBoldItalic.09bc481607bd529abda7.woff2 │ │ ├── Inter-SemiBoldItalic.43f7c276720845c6bb59.woff │ │ ├── Inter-Thin.92cada3d91581eb5112d.woff2 │ │ ├── Inter-Thin.df0b1bcf558ccd5b48a2.woff │ │ ├── Inter-ThinItalic.78bf87d2ea41ac4365c1.woff │ │ ├── Inter-ThinItalic.82dd2dc2fb674d8273e4.woff2 │ │ ├── Inter-italic.var.28904cc0eac675e1d19e.woff2 │ │ ├── Inter-roman.var.f05060926bf5023f9930.woff2 │ │ └── Inter.var.c3f97a25f56b5b416e49.woff2 ├── datasource │ ├── __init__.py │ ├── athena.py │ ├── bigquery.py │ ├── bigquery_patch.py │ ├── databricks.py │ ├── duckdb.py │ ├── field.py │ ├── postgres.py │ ├── redshift.py │ ├── snowflake.py │ ├── sqlite.py │ ├── survey.py │ └── unsupported.py ├── dbt │ ├── __init__.py │ ├── changeset.py │ ├── list_task.py │ ├── markdown.py │ ├── reverse_manifest.py │ ├── sorting.py │ └── utils.py ├── dbtutil.py ├── docgen │ ├── __init__.py │ └── __main__.py ├── error.py ├── event │ ├── __init__.py │ ├── collector.py │ ├── events.py │ └── track.py ├── exitcode.py ├── feedback.py ├── generate_report.py ├── githubutil.py ├── guide.py ├── hack │ ├── __init__.py │ ├── datasource_inquirer_prompt.py │ └── inquirer.py ├── initializer.py ├── metrics_engine │ ├── __init__.py │ ├── event.py │ └── metrics.py ├── profiler │ ├── __init__.py │ ├── event.py │ ├── profiler.py │ ├── schema.json │ └── version.py ├── recipe_executor.py ├── recipes │ ├── __init__.py │ ├── default_recipe_generator.py │ ├── git_repo_example.yml │ ├── github_action.py │ ├── recipe_schema.json │ └── utils.py ├── runner.py ├── statistics.py ├── utils.py ├── validator.py └── yaml │ └── __init__.py ├── requirements.txt ├── setup.py ├── static_report ├── .editorconfig ├── .env.development ├── .eslintignore ├── .gitignore ├── .npmrc ├── .vscode │ └── settings.json ├── README.md ├── build-env │ ├── .env.comparison │ ├── .env.comparison-asymmetric │ ├── .env.comparison-e2e │ ├── .env.single │ ├── .env.single-e2e │ └── .env.single-edge ├── craco.config.cjs ├── cypress.config.ts ├── cypress │ ├── e2e │ │ ├── comparison-asym-base-target.cy.ts │ │ ├── comparison-report.cy.ts │ │ ├── single-report-abnormal-data.cy.ts │ │ └── single-report.cy.ts │ ├── fixtures │ │ └── example.json │ ├── support │ │ ├── commands.ts │ │ └── e2e.ts │ └── tsconfig.json ├── jest.config.js ├── package.json ├── pnpm-lock.yaml ├── public │ ├── index.html │ └── logo │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── android-icon-144x144.png │ │ ├── android-icon-192x192.png │ │ ├── android-icon-36x36.png │ │ ├── android-icon-48x48.png │ │ ├── android-icon-72x72.png │ │ ├── android-icon-96x96.png │ │ ├── apple-icon-114x114.png │ │ ├── apple-icon-120x120.png │ │ ├── apple-icon-144x144.png │ │ ├── apple-icon-152x152.png │ │ ├── apple-icon-180x180.png │ │ ├── apple-icon-57x57.png │ │ ├── apple-icon-60x60.png │ │ ├── apple-icon-72x72.png │ │ ├── apple-icon-76x76.png │ │ ├── apple-icon-precomposed.png │ │ ├── apple-icon.png │ │ ├── apple-touch-icon.png │ │ ├── browserconfig.xml │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon-96x96.png │ │ ├── favicon.ico │ │ ├── logo.svg │ │ ├── manifest.json │ │ ├── ms-icon-144x144.png │ │ ├── ms-icon-150x150.png │ │ ├── ms-icon-310x310.png │ │ ├── ms-icon-70x70.png │ │ ├── mstile-144x144.png │ │ ├── mstile-150x150.png │ │ ├── mstile-310x150.png │ │ ├── mstile-310x310.png │ │ ├── mstile-70x70.png │ │ └── safari-pinned-tab.svg ├── schema │ ├── dbt-manifest-schema.json │ └── dbt-run-results-schema.json ├── src │ ├── App.tsx │ ├── components │ │ ├── Assertions │ │ │ ├── AssertionCRModal.tsx │ │ │ ├── AssertionPassFailCountLabel.tsx │ │ │ ├── AssertionStatusIcon.tsx │ │ │ └── index.ts │ │ ├── Charts │ │ │ ├── BMBarChart.tsx │ │ │ ├── BMLineChart.tsx │ │ │ ├── BooleanPieChart.tsx │ │ │ ├── ChartContainer.tsx │ │ │ ├── FlatBoxPlotChart.tsx │ │ │ ├── FlatStackedBarChart.tsx │ │ │ ├── HistogramChart.tsx │ │ │ ├── TopKSummaryList.tsx │ │ │ ├── index.ts │ │ │ └── utils.tsx │ │ ├── Columns │ │ │ ├── ColumnMetrics │ │ │ │ ├── GeneralStats.tsx │ │ │ │ ├── MetricsInfo.tsx │ │ │ │ ├── QuantilesMatrix.tsx │ │ │ │ ├── SummaryStats.tsx │ │ │ │ ├── TypedStats.tsx │ │ │ │ └── index.ts │ │ │ ├── constants.ts │ │ │ ├── index.ts │ │ │ └── utils.ts │ │ ├── Common │ │ │ ├── CommonModal.tsx │ │ │ ├── HelpMenu.tsx │ │ │ ├── Loading.tsx │ │ │ ├── Main.tsx │ │ │ ├── MasterDetailContainer.tsx │ │ │ ├── Navbar.tsx │ │ │ ├── NoData.tsx │ │ │ ├── NotFound.tsx │ │ │ ├── SearchTextInput.tsx │ │ │ ├── SkipDataSource.tsx │ │ │ ├── constant.ts │ │ │ └── index.ts │ │ ├── Icons │ │ │ └── index.tsx │ │ ├── LineageGraph │ │ │ ├── CopyGraphUrlButton.tsx │ │ │ ├── GraphEdge.tsx │ │ │ ├── GraphGroup.tsx │ │ │ ├── GraphNode.tsx │ │ │ ├── LineageGraph.tsx │ │ │ ├── TableSummary.tsx │ │ │ ├── style.ts │ │ │ └── util.ts │ │ ├── MasterSideNav │ │ │ ├── ColumnDetailListItem.tsx │ │ │ ├── ColumnListAccordionPanel.tsx │ │ │ ├── ColumnName.tsx │ │ │ ├── MasterSideNav.tsx │ │ │ ├── RoutableAccordionButton.tsx │ │ │ ├── TableItemAccordionButton.tsx │ │ │ └── index.ts │ │ ├── Overview │ │ │ ├── ChangeSummary.tsx │ │ │ ├── LineageDiffPopover.tsx │ │ │ ├── MetricList.tsx │ │ │ ├── ModelList.tsx │ │ │ ├── NodeList.tsx │ │ │ └── Overview.tsx │ │ ├── Reports │ │ │ ├── ReportContextBar.tsx │ │ │ └── index.ts │ │ ├── SideBar │ │ │ ├── SideBar.tsx │ │ │ └── SideBarTree.tsx │ │ ├── Tables │ │ │ ├── TableColumnHeader.tsx │ │ │ ├── TableList │ │ │ │ ├── ColumnBadge.tsx │ │ │ │ ├── ColumnSchemaDeltaSummary.tsx │ │ │ │ ├── ColumnSchemaTypeLabel.tsx │ │ │ │ ├── TableColumnSchemaList.tsx │ │ │ │ ├── TableListAssertions.tsx │ │ │ │ ├── TableListItem.tsx │ │ │ │ ├── TableListItemDecorations.tsx │ │ │ │ ├── TableRowColDeltaSummary.tsx │ │ │ │ └── index.ts │ │ │ ├── TableMetrics │ │ │ │ ├── DupedTableRowStats.tsx │ │ │ │ ├── TableGeneralStats.tsx │ │ │ │ └── index.ts │ │ │ ├── TableOverview.tsx │ │ │ ├── constant.ts │ │ │ ├── index.ts │ │ │ └── utils.ts │ │ ├── Widgets │ │ │ ├── AssertionListWidget.tsx │ │ │ ├── BMWidget.tsx │ │ │ ├── ChangeStatusWidget.tsx │ │ │ ├── ChartTabsWidget.tsx │ │ │ ├── DataCompositionWidget.tsx │ │ │ ├── DataSummaryWidget.tsx │ │ │ ├── DupedTableRowsWidget.tsx │ │ │ ├── QuantilesWidget.tsx │ │ │ ├── StatDiff.tsx │ │ │ └── index.ts │ │ └── index.ts │ ├── hooks │ │ ├── index.ts │ │ ├── useDocumentTitle.ts │ │ ├── useHashLcocation.ts │ │ └── useTrackOnMount.ts │ ├── index.tsx │ ├── lib │ │ └── index.ts │ ├── pages │ │ ├── CRAssertionListPage.tsx │ │ ├── CRBMPage.tsx │ │ ├── CRColumnDetailPage.tsx │ │ ├── CROverviewPage.tsx │ │ ├── CRPage.tsx │ │ ├── CRSemanticModelPage.tsx │ │ ├── CRTableDetailPage.tsx │ │ ├── CRTableListPage.tsx │ │ ├── SRAssertionListPage.tsx │ │ ├── SRBMPage.tsx │ │ ├── SRColumnDetailPage.tsx │ │ ├── SROverviewPage.tsx │ │ ├── SRPage.tsx │ │ ├── SRSemanticModelPage.tsx │ │ ├── SRTableDetailPage.tsx │ │ ├── SRTablesListPage.tsx │ │ └── index.ts │ ├── sdlc │ │ ├── check-report-data.js │ │ ├── clean-window-data.js │ │ ├── core.js │ │ ├── dbt-manifest-schema.ts │ │ ├── dbt-run-results-schema.ts │ │ ├── embed-window-data.js │ │ ├── extract-schema-metadata.js │ │ ├── generate-e2e-data.sh │ │ ├── global.d.ts │ │ ├── index.ts │ │ ├── schema-meta.ts │ │ ├── single-report-schema.ts │ │ └── single-report-schema.z.ts │ ├── types │ │ └── index.ts │ └── utils │ │ ├── __tests__ │ │ ├── graph_test.ts │ │ └── mergeKeys_test.ts │ │ ├── cloud.tsx │ │ ├── dbt.ts │ │ ├── formatters.tsx │ │ ├── graph.ts │ │ ├── index.ts │ │ ├── layout.ts │ │ ├── localStorageKeys.ts │ │ ├── mergeKeys.ts │ │ ├── reportWebVitals.tsx │ │ ├── routes.ts │ │ ├── store.ts │ │ ├── theme.ts │ │ └── trackEvents.ts └── tsconfig.json ├── tests ├── common.py ├── conftest.py ├── datasource │ ├── test_datasource.py │ └── test_duckdb.py ├── mock_dbt_data │ ├── case_base_not_profiled_1.json │ ├── case_base_not_profiled_2.json │ ├── compatible │ │ ├── dbt-duckdb-1.4.2-manifest.json │ │ ├── dbt-duckdb-1.5.1-manifest.json │ │ ├── dbt-duckdb-1.6.0-manifest.json │ │ ├── dbt-duckdb-1.7.0-manifest.json │ │ └── dbt-postgres-1.3.4-manifest.json │ ├── dbt-list-altered-manifest.json │ ├── dbt-list-base-manifest.json │ ├── git-repo-analytics_metrics_1.json │ ├── git-repo-analytics_metrics_2.json │ ├── jaffle_shop_base.json │ ├── jaffle_shop_base_1.3.json │ ├── jaffle_shop_base_1_6.json │ ├── jaffle_shop_base_1_7.json │ ├── jaffle_shop_target.json │ ├── jaffle_shop_target_1.3.json │ ├── jaffle_shop_target_1_6.json │ ├── jaffle_shop_target_1_7.json │ ├── manifest.json │ ├── run-with-run_results.json │ ├── run_results.json │ ├── sc-31587-base.json │ ├── sc-31587-input.json │ ├── sc-31587-metrics-base.json │ ├── sc-31587-metrics-input.json │ ├── sc-31587-with-ref-base.json │ ├── sc-31587-with-ref-input.json │ ├── sc-31711-run-dbt-1.5.4-no-profiled.json │ ├── sc-31723-base.json │ ├── sc-31723-target.json │ ├── sc-31782-base.json │ └── sc-31782-target.json ├── mock_dbt_project │ ├── dbt_project.yml │ ├── profiles.yml │ └── skip_datasource_connection │ │ ├── .piperider │ │ └── config.yml │ │ ├── dbt_project.yml │ │ ├── profiles.yml │ │ └── target │ │ └── manifest.json ├── orders_1k.json ├── profiler │ ├── test_multi_db.py │ └── test_profiler.py ├── test_cli.py ├── test_compare_report.py ├── test_compare_summary_ng.py ├── test_dbt_integeration.py ├── test_dbt_manifest_compatible.py ├── test_dbt_util.py ├── test_github_util.py ├── test_links.py ├── test_recipe.py ├── test_reversed_manifest.py ├── test_runner.py ├── test_track_setup.py └── test_util.py ├── tox-ruamel.ini └── tox-sqlalchemy.ini /.dockerignore: -------------------------------------------------------------------------------- 1 | .* 2 | 3 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | charset = utf-8 12 | 13 | # 4 space indentation 14 | [*.{py,java,r,R}] 15 | indent_style = space 16 | indent_size = 4 17 | 18 | # 2 space indentation 19 | [*.{js,json,y{a,}ml,html,cwl}] 20 | indent_style = space 21 | indent_size = 2 22 | 23 | [*.{md,Rmd,rst}] 24 | trim_trailing_whitespace = false 25 | indent_style = space 26 | indent_size = 2 -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore = W605, F401, E501, E125, E126 3 | max-line-length = 120 4 | exclude = tests, 5 | docs, 6 | .git, 7 | .venv, 8 | venv, 9 | debug, 10 | build, 11 | dist, 12 | images, 13 | static_report, 14 | *.egg-info, 15 | piperider, 16 | piperider_cli/data/piperider-init-template/plugins/customized_assertions.py 17 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Setup environment '...' 16 | 2. Execute command '....' 17 | 3. Execute another command '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. macOS, ubuntu, Windows] 28 | - Python Version [e.g. 3.7.5, 3.9.10] 29 | - Version [e.g. v0.1.3.14] 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | **PR checklist** 4 | 5 | - [ ] Ensure you have added or ran the appropriate tests for your PR. 6 | - [ ] DCO signed 7 | 8 | **What type of PR is this?** 9 | 10 | **What this PR does / why we need it**: 11 | 12 | **Which issue(s) this PR fixes**: 13 | 14 | **Special notes for your reviewer**: 15 | 16 | **Does this PR introduce a user-facing change?**: 17 | 22 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TITLE_CHECKER.json: -------------------------------------------------------------------------------- 1 | { 2 | "LABEL": { 3 | "name": "PR Title Check Failed", 4 | "color": "FC6666" 5 | }, 6 | "CHECKS": { 7 | "prefixes": [ 8 | "Bump ", 9 | "[Feature] ", 10 | "[Bug] ", 11 | "[Release] ", 12 | "[Document] ", 13 | "[Chore] " 14 | ], 15 | "ignoreLabels": [ 16 | "Skip PR Title Check" 17 | ] 18 | }, 19 | "MESSAGES": { 20 | "success": "PR Title Check Passed", 21 | "failure": "PR Title Check Failed", 22 | "notice": "PR title should should start with one of the following prefixes: [Feature], [Bug], [Release], [Document], [Chore]" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /.github/scripts/bump_amplitude_release.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | set -x 3 | API_KEY=${AMPLITUDE_API_KEY:-} 4 | SECRET_KEY=${AMPLITUDE_SECRET_KEY:-} 5 | API_ENDPOINT='https://amplitude.com/api/2/release' 6 | 7 | if [ "$API_KEY" = "" ] || [ "$SECRET_KEY" = "" ]; then 8 | echo "[Skip] No Amplitude API key or secret key provided." 9 | exit 0 10 | fi 11 | 12 | RELEASE_START=$(date -u "+%Y-%m-%d %H:%m:%S") 13 | VERSION=${1:-} 14 | ENVIRONMENT=${2:-production} 15 | 16 | if [[ "$ENVIRONMENT" == "production" ]]; then 17 | TITLE="PipeRider v$VERSION" 18 | else 19 | TITLE="PipeRider $ENVIRONMENT v$VERSION" 20 | fi 21 | 22 | curl -X POST $API_ENDPOINT \ 23 | -H "Content-Type: application/json" \ 24 | -u "$API_KEY:$SECRET_KEY" \ 25 | -d "{ 26 | \"release_start\": \"$RELEASE_START\", 27 | \"title\": \"$TITLE\", 28 | \"version\": \"$VERSION\" 29 | }" 30 | 31 | echo "[Done] Amplitude release created: $TITLE" 32 | -------------------------------------------------------------------------------- /.github/workflows/build-statics.yaml: -------------------------------------------------------------------------------- 1 | 2 | name: Node.js - Build & Auto-Commit to CLI data/report/** 3 | 4 | on: 5 | pull_request: 6 | types: 7 | - closed 8 | # Trigger when PR is closed 9 | paths: 10 | - "static_report/**" 11 | - "piperider_cli/**" 12 | # Trigger when diffs detected in cli and report sources 13 | branches: 14 | - main 15 | # Only PR target is `main` 16 | 17 | jobs: 18 | if_merged_build: 19 | if: github.event.pull_request.merged == true 20 | runs-on: ubuntu-latest 21 | defaults: 22 | run: 23 | working-directory: ./static_report 24 | 25 | steps: 26 | - uses: actions/checkout@v3 27 | 28 | - name: Use Node.js ${{ matrix.node-version }} 29 | uses: actions/setup-node@v3 30 | with: 31 | node-version: 16 32 | 33 | - uses: pnpm/action-setup@v2.2.2 34 | with: 35 | version: 7 36 | 37 | - name: Install dependencies 38 | working-directory: ./static_report 39 | run: pnpm install --frozen-lockfile 40 | 41 | 42 | - name: Build Apps 43 | run: pnpm run build 44 | 45 | - name: Pull Remote Changes (before AC) 46 | run: git pull origin main 47 | 48 | - uses: stefanzweifel/git-auto-commit-action@v4 49 | with: 50 | commit_message: AUTO-COMMIT - build report statics to CLI data/report 51 | branch: ${{ github.base_ref }} 52 | # Auto-commits to target merge branch 53 | -------------------------------------------------------------------------------- /.github/workflows/e2e-windows-tests.yaml: -------------------------------------------------------------------------------- 1 | name: Run dbt tests on win 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | workflow_dispatch: 11 | 12 | jobs: 13 | build: 14 | runs-on: windows-latest 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | version: [ '3.11' ] 19 | dbt: [ ">=1.5,<1.6", ">=1.6,<1.7" ] 20 | 21 | steps: 22 | - uses: actions/checkout@v2 23 | - name: Set up Python 24 | uses: actions/setup-python@v2 25 | with: 26 | python-version: ${{ matrix.version }} 27 | - name: Install dependencies 28 | run: | 29 | python -m pip install --upgrade pip 30 | pip install pytest "dbt-core${{ matrix.dbt }}" "dbt-duckdb${{ matrix.dbt }}" 31 | pip install '.[duckdb]' 32 | 33 | - name: Run jaffle shop 34 | run: | 35 | ./e2e-jaffle-shop/run.bat 36 | python ./e2e-jaffle-shop/windows-result-checker.py 37 | -------------------------------------------------------------------------------- /.github/workflows/flake8.yaml: -------------------------------------------------------------------------------- 1 | name: Lint by Flake8 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | flake8: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - name: Setup Python 10 | uses: actions/setup-python@v1 11 | with: 12 | python-version: 3.9 13 | architecture: x64 14 | 15 | - name: Checkout Code 16 | uses: actions/checkout@master 17 | 18 | - name: Install flake8 19 | run: pip install flake8 20 | 21 | - name: Run flake8 22 | uses: suo/flake8-github-action@releases/v1 23 | with: 24 | checkName: 'flake8' # NOTE: this needs to be the same as the job name 25 | env: 26 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 27 | -------------------------------------------------------------------------------- /.github/workflows/pr.yaml: -------------------------------------------------------------------------------- 1 | name: "PipeRider PR Title Checker" 2 | on: 3 | pull_request_target: 4 | types: 5 | - opened 6 | - edited 7 | - synchronize 8 | - labeled 9 | - unlabeled 10 | 11 | jobs: 12 | pr-title-check: 13 | runs-on: ubuntu-latest 14 | steps: 15 | - uses: thehanimo/pr-title-checker@v1.3.4 16 | with: 17 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | pass_on_octokit_error: false 19 | configuration_path: ".github/PULL_REQUEST_TITLE_CHECKER.json" 20 | -------------------------------------------------------------------------------- /.github/workflows/tests.yaml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Run tests 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Set up Python 21 | uses: actions/setup-python@v2 22 | with: 23 | python-version: 3.11 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 28 | pip install -e '.[duckdb]' 29 | - name: Run tests 30 | run: | 31 | make test 32 | - name: Upload coverage reports to Codecov 33 | uses: codecov/codecov-action@v3 34 | env: 35 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 36 | -------------------------------------------------------------------------------- /.github/workflows/tox.yaml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a variety of Python versions 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions 3 | 4 | name: Run tox tests 5 | 6 | on: 7 | push: 8 | branches: 9 | - main 10 | pull_request: 11 | branches: 12 | - main 13 | 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - uses: actions/checkout@v3 20 | - name: Set up Python 21 | uses: actions/setup-python@v2 22 | with: 23 | python-version: "3.10" 24 | - name: Install dependencies 25 | run: | 26 | python -m pip install --upgrade pip 27 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 28 | pip install -e '.[duckdb]' 29 | pip install tox 30 | - name: Run tox-sqlalchemy 31 | run: tox -c tox-sqlalchemy.ini 32 | - name: Run tox-ruamel 33 | run: tox -c tox-ruamel.ini 34 | - name: Upload coverage reports to Codecov 35 | uses: codecov/codecov-action@v3 36 | env: 37 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 38 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9-slim 2 | ARG PIPERIDER_VERSION 3 | 4 | RUN apt-get update && \ 5 | apt-get install -y --no-install-recommends \ 6 | ca-certificates curl uuid-runtime git \ 7 | && apt-get purge -y --auto-remove \ 8 | && rm -rf /var/lib/apt/lists/* 9 | 10 | # Install yq@4 11 | RUN curl -L https://github.com/mikefarah/yq/releases/latest/download/yq_linux_amd64 -o /bin/yq && chmod +x /bin/yq 12 | 13 | RUN if [ -n "$PIPERIDER_VERSION" ]; then \ 14 | pip install --no-cache-dir piperider==${PIPERIDER_VERSION}; \ 15 | else \ 16 | pip install --no-cache-dir piperider; \ 17 | fi 18 | 19 | WORKDIR /usr/src/github/ 20 | 21 | COPY entrypoint.sh /entrypoint.sh 22 | 23 | ENTRYPOINT ["/entrypoint.sh"] 24 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | DOCKER_BUILD_CMD = docker build 2 | detected_OS := $(shell sh -c 'uname 2>/dev/null || echo Unknown') 3 | ifeq ($(detected_OS),Darwin) # Mac OS X 4 | DOCKER_BUILD_CMD = docker buildx build --platform linux/amd64 5 | endif 6 | 7 | dev-requires: 8 | pip install -e .[dev] 9 | 10 | flake8: 11 | @echo "Check Python coding style by flake8 ..." 12 | @flake8 13 | @echo "Passed" 14 | 15 | test: dev-requires 16 | python3 -m pytest --cov=piperider_cli --cov-report html tests 17 | 18 | pre-release: dev-requires 19 | pip install build 20 | python3 -m build 21 | python3 -m twine upload --repository testpypi dist/* 22 | 23 | release: dev-requires 24 | pip install build 25 | python3 -m build 26 | python3 -m twine upload dist/* 27 | 28 | require-%: 29 | @if [ "${${*}}" = "" ]; then \ 30 | echo "Environment variable $* not set"; \ 31 | exit 1; \ 32 | fi 33 | 34 | bump-version: require-VERSION 35 | @echo "Bumping version to ${VERSION}" 36 | @echo "${VERSION}" > piperider_cli/VERSION 37 | 38 | docker-build: require-VERSION 39 | $(DOCKER_BUILD_CMD) --build-arg PIPERIDER_VERSION=${VERSION} -t piperider:${VERSION} . 40 | 41 | docker-deploy: docker-build 42 | docker tag piperider:${VERSION} piperider/piperider:${VERSION} 43 | docker push piperider/piperider:${VERSION} 44 | 45 | docker-deploy-latest: docker-build 46 | docker tag piperider:${VERSION} piperider/piperider:latest 47 | docker push piperider/piperider:latest 48 | 49 | generate-cli-docs: 50 | @python3 -m piperider_cli.docgen 51 | -------------------------------------------------------------------------------- /connect.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/connect.py -------------------------------------------------------------------------------- /docs/assets/metrics-composition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/docs/assets/metrics-composition.png -------------------------------------------------------------------------------- /docs/assets/metrics-uniqueness.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/docs/assets/metrics-uniqueness.png -------------------------------------------------------------------------------- /docs/commands/piperider-compare-report.md: -------------------------------------------------------------------------------- 1 | 2 | # piperider compare-report 3 | None 4 | ## Usage 5 | ``` 6 | Usage: piperider compare-report [OPTIONS] 7 | ``` 8 | ## Options 9 | * `base`: 10 | * Type: Path 11 | * Default: `none` 12 | * Usage: `--base` 13 | 14 | Path of the base json report file 15 | 16 | 17 | * `input`: 18 | * Type: Path 19 | * Default: `none` 20 | * Usage: `--input` 21 | 22 | Path of the json report file to compare 23 | 24 | 25 | * `debug`: 26 | * Type: BOOL 27 | * Default: `false` 28 | * Usage: `--debug` 29 | 30 | Enable debug mode 31 | 32 | 33 | * `help`: 34 | * Type: BOOL 35 | * Default: `false` 36 | * Usage: `--help` 37 | 38 | Show this message and exit. 39 | 40 | 41 | ## CLI Help 42 | ``` 43 | Usage: piperider compare-report [OPTIONS] 44 | 45 | Options: 46 | --base PATH Path of the base json report file 47 | --input PATH Path of the json report file to compare 48 | --debug Enable debug mode 49 | --help Show this message and exit. 50 | ``` 51 | -------------------------------------------------------------------------------- /docs/commands/piperider-debug.md: -------------------------------------------------------------------------------- 1 | 2 | # piperider debug 3 | None 4 | ## Usage 5 | ``` 6 | Usage: piperider debug [OPTIONS] 7 | ``` 8 | ## Options 9 | * `help`: 10 | * Type: BOOL 11 | * Default: `false` 12 | * Usage: `--help` 13 | 14 | Show this message and exit. 15 | 16 | 17 | ## CLI Help 18 | ``` 19 | Usage: piperider debug [OPTIONS] 20 | 21 | Options: 22 | --help Show this message and exit. 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/commands/piperider-generate-report.md: -------------------------------------------------------------------------------- 1 | 2 | # piperider generate-report 3 | None 4 | ## Usage 5 | ``` 6 | Usage: piperider generate-report [OPTIONS] 7 | ``` 8 | ## Options 9 | * `input`: 10 | * Type: Path 11 | * Default: `none` 12 | * Usage: `--input` 13 | 14 | Path of json report file 15 | 16 | 17 | * `debug`: 18 | * Type: BOOL 19 | * Default: `false` 20 | * Usage: `--debug` 21 | 22 | Enable debug mode 23 | 24 | 25 | * `help`: 26 | * Type: BOOL 27 | * Default: `false` 28 | * Usage: `--help` 29 | 30 | Show this message and exit. 31 | 32 | 33 | ## CLI Help 34 | ``` 35 | Usage: piperider generate-report [OPTIONS] 36 | 37 | Options: 38 | --input PATH Path of json report file 39 | --debug Enable debug mode 40 | --help Show this message and exit. 41 | ``` 42 | -------------------------------------------------------------------------------- /docs/commands/piperider-init.md: -------------------------------------------------------------------------------- 1 | 2 | # piperider init 3 | None 4 | ## Usage 5 | ``` 6 | Usage: piperider init [OPTIONS] 7 | ``` 8 | ## Options 9 | * `no_auto_search`: 10 | * Type: BOOL 11 | * Default: `false` 12 | * Usage: `--no-auto-search` 13 | 14 | Don't search for dbt projects 15 | 16 | 17 | * `dbt_project_dir`: 18 | * Type: Path 19 | * Default: `none` 20 | * Usage: `--dbt-project-dir` 21 | 22 | Directory of dbt project config 23 | 24 | 25 | * `dbt_profiles_dir`: 26 | * Type: Path 27 | * Default: `none` 28 | * Usage: `--dbt-profiles-dir` 29 | 30 | Directory of dbt profiles config 31 | 32 | 33 | * `debug`: 34 | * Type: BOOL 35 | * Default: `false` 36 | * Usage: `--debug` 37 | 38 | Enable debug mode 39 | 40 | 41 | * `help`: 42 | * Type: BOOL 43 | * Default: `false` 44 | * Usage: `--help` 45 | 46 | Show this message and exit. 47 | 48 | 49 | ## CLI Help 50 | ``` 51 | Usage: piperider init [OPTIONS] 52 | 53 | Options: 54 | --no-auto-search Don't search for dbt projects 55 | --dbt-project-dir PATH Directory of dbt project config 56 | --dbt-profiles-dir PATH Directory of dbt profiles config 57 | --debug Enable debug mode 58 | --help Show this message and exit. 59 | ``` 60 | -------------------------------------------------------------------------------- /docs/commands/piperider-run.md: -------------------------------------------------------------------------------- 1 | 2 | # piperider run 3 | None 4 | ## Usage 5 | ``` 6 | Usage: piperider run [OPTIONS] 7 | ``` 8 | ## Options 9 | * `datasource`: 10 | * Type: STRING 11 | * Default: `none` 12 | * Usage: `--datasource` 13 | 14 | 15 | 16 | 17 | * `table`: 18 | * Type: STRING 19 | * Default: `none` 20 | * Usage: `--table` 21 | 22 | 23 | 24 | 25 | * `output`: 26 | * Type: STRING 27 | * Default: `none` 28 | * Usage: `--output` 29 | 30 | 31 | 32 | 33 | * `no_interaction`: 34 | * Type: BOOL 35 | * Default: `false` 36 | * Usage: `--no-interaction` 37 | 38 | Disable interactive question 39 | 40 | 41 | * `generate_report`: 42 | * Type: BOOL 43 | * Default: `false` 44 | * Usage: `--generate-report` 45 | 46 | Generate report directly 47 | 48 | 49 | * `debug`: 50 | * Type: BOOL 51 | * Default: `false` 52 | * Usage: `--debug` 53 | 54 | Enable debug mode 55 | 56 | 57 | * `help`: 58 | * Type: BOOL 59 | * Default: `false` 60 | * Usage: `--help` 61 | 62 | Show this message and exit. 63 | 64 | 65 | ## CLI Help 66 | ``` 67 | Usage: piperider run [OPTIONS] 68 | 69 | Options: 70 | --datasource TEXT 71 | --table TEXT 72 | --output TEXT 73 | --no-interaction Disable interactive question 74 | --generate-report Generate report directly 75 | --debug Enable debug mode 76 | --help Show this message and exit. 77 | ``` 78 | -------------------------------------------------------------------------------- /docs/commands/piperider-version.md: -------------------------------------------------------------------------------- 1 | 2 | # piperider version 3 | None 4 | ## Usage 5 | ``` 6 | Usage: piperider version [OPTIONS] 7 | ``` 8 | ## Options 9 | * `help`: 10 | * Type: BOOL 11 | * Default: `false` 12 | * Usage: `--help` 13 | 14 | Show this message and exit. 15 | 16 | 17 | ## CLI Help 18 | ``` 19 | Usage: piperider version [OPTIONS] 20 | 21 | Options: 22 | --help Show this message and exit. 23 | ``` 24 | -------------------------------------------------------------------------------- /docs/commands/piperider.md: -------------------------------------------------------------------------------- 1 | # piperider 2 | 3 | None 4 | 5 | ## Usage 6 | 7 | ``` 8 | Usage: piperider [OPTIONS] COMMAND [ARGS]... 9 | ``` 10 | 11 | ## Options 12 | 13 | * `help`: 14 | * Type: BOOL 15 | * Default: `false` 16 | * Usage: `--help` 17 | 18 | Show this message and exit. 19 | 20 | ## CLI Help 21 | 22 | ``` 23 | Usage: piperider [OPTIONS] COMMAND [ARGS]... 24 | 25 | Options: 26 | --help Show this message and exit. 27 | 28 | Commands: 29 | compare-report Compare two existing reports 30 | debug Test Configuration 31 | generate-report Show report 32 | init Initialize PipeRider configurations 33 | run Collect data profiles and test results 34 | version Show the version of piperider 35 | ``` 36 | -------------------------------------------------------------------------------- /docs/project.md: -------------------------------------------------------------------------------- 1 | # Product Structure 2 | 3 | A piperider project is initialized by `piperider init`. Then, a folder `.piperider/` is generated. 4 | 5 | The `.piperider/` folder may contains these files 6 | 7 | Name | Description 8 | ------------|--------------- 9 | config.yml | The project config file. Generated by `piperider init`. Contains the data source and dbt integration settings. 10 | credentials.yml | The data source connection parameters and credentials to connect to data sources. This is supposed to not be source controlled. 11 | outputs/ | The piperider run raw result generated by `piperider run` 12 | reports/ | The piperider report generated by `piperider generate-report` 13 | comparisons/ | The piperider report generated by `piperider compare-report` 14 | .gitignore | Generated by `piperider init`. Contains the default ignore file and folder. 15 | 16 | # Git Versioning 17 | 18 | Piperider project is by design to be source-controlled in a git repository. The generated `.piperider/.gitignore` is our recommended way to ignore files/folder in git. The current settings are 19 | 20 | ```text 21 | **.log 22 | __pycache__/ 23 | logs/ 24 | outputs/ 25 | reports/ 26 | comparisons/ 27 | credentials.yml 28 | .unsend_events.json 29 | ``` 30 | 31 | -------------------------------------------------------------------------------- /e2e-jaffle-shop/0001-apply-tags.patch: -------------------------------------------------------------------------------- 1 | From 88439b5e99f95ff00ffb8f3f378f55452199b7c7 Mon Sep 17 00:00:00 2001 2 | From: "Ching Yi, Chan" 3 | Date: Tue, 11 Jul 2023 15:43:54 +0800 4 | Subject: [PATCH] apply tags 5 | 6 | Signed-off-by: Ching Yi, Chan 7 | --- 8 | models/customers.sql | 2 ++ 9 | models/orders.sql | 2 ++ 10 | 2 files changed, 4 insertions(+) 11 | 12 | diff --git a/models/customers.sql b/models/customers.sql 13 | index 016a004..0b3d35d 100644 14 | --- a/models/customers.sql 15 | +++ b/models/customers.sql 16 | @@ -1,3 +1,5 @@ 17 | +{{ config(tags=['piperider']) }} 18 | + 19 | with customers as ( 20 | 21 | select * from {{ ref('stg_customers') }} 22 | diff --git a/models/orders.sql b/models/orders.sql 23 | index cbb2934..5bdfd49 100644 24 | --- a/models/orders.sql 25 | +++ b/models/orders.sql 26 | @@ -1,3 +1,5 @@ 27 | +{{ config(tags=['piperider']) }} 28 | + 29 | {% set payment_methods = ['credit_card', 'coupon', 'bank_transfer', 'gift_card'] %} 30 | 31 | with orders as ( 32 | -- 33 | 2.32.1 (Apple Git-133) 34 | 35 | -------------------------------------------------------------------------------- /e2e-jaffle-shop/0002-Add-average_value_per_order-to-customers.patch: -------------------------------------------------------------------------------- 1 | From 1937da51c2828890f74ed327719a3f3e925b41da Mon Sep 17 00:00:00 2001 2 | From: "Ching Yi, Chan" 3 | Date: Tue, 11 Jul 2023 15:52:04 +0800 4 | Subject: [PATCH] Add average_value_per_order to customers 5 | 6 | Signed-off-by: Ching Yi, Chan 7 | --- 8 | models/customers.sql | 1 + 9 | 1 file changed, 1 insertion(+) 10 | 11 | diff --git a/models/customers.sql b/models/customers.sql 12 | index 0b3d35d..c4b0655 100644 13 | --- a/models/customers.sql 14 | +++ b/models/customers.sql 15 | @@ -55,6 +55,7 @@ final as ( 16 | customers.last_name, 17 | customer_orders.first_order, 18 | customer_orders.most_recent_order, 19 | + customer_payments.total_amount / customer_orders.number_of_orders as average_value_per_order, 20 | customer_orders.number_of_orders, 21 | customer_payments.total_amount as customer_lifetime_value 22 | 23 | -- 24 | 2.32.1 (Apple Git-133) 25 | 26 | -------------------------------------------------------------------------------- /e2e-jaffle-shop/gen_seed.py: -------------------------------------------------------------------------------- 1 | import csv 2 | import os 3 | 4 | 5 | def create_csv_file(file_path, file_size_mb): 6 | row_size = 1024 # 1KB row size 7 | rows_per_mb = int((1024 * 1024) / row_size) 8 | target_rows = rows_per_mb * file_size_mb 9 | 10 | headers = [f'Column{i}' for i in range(1, 65)] # Generate headers from Column1 to Column64 11 | 12 | with open(file_path, 'w', newline='') as csvfile: 13 | writer = csv.writer(csvfile) 14 | writer.writerow(headers) # Write the header row 15 | for _ in range(target_rows): 16 | writer.writerow(['Sample data'] * 64) # Writing a row with sample data for 64 columns 17 | 18 | # Check if the file has reached the target size 19 | while os.path.getsize(file_path) < (file_size_mb * 1024 * 1024): 20 | with open(file_path, 'a', newline='') as csvfile: 21 | writer = csv.writer(csvfile) 22 | writer.writerow(['Sample data'] * 64) # Writing additional rows until the target size is reached 23 | 24 | 25 | # Example usage 26 | file_path = 'seeds/sample.csv' 27 | file_size_mb = 2 28 | create_csv_file(file_path, file_size_mb) 29 | print(f"CSV file '{file_path}' created with a size of {file_size_mb}MB.") 30 | -------------------------------------------------------------------------------- /e2e-jaffle-shop/run.bat: -------------------------------------------------------------------------------- 1 | :: Set Git global configurations 2 | git config --global user.email "dev-ci@infuseai.io" 3 | git config --global user.name "dev-ci" 4 | 5 | :: Move to the e2e directory 6 | pushd "%~dp0" 7 | echo Current Directory: %CD% 8 | 9 | :: Show dbt version 10 | dbt --version 11 | 12 | :: Reference 13 | :: https://docs.piperider.io/get-started/quick-start 14 | 15 | :: Step 1: Clone the repo 16 | git clone https://github.com/dbt-labs/jaffle_shop.git 17 | cd jaffle_shop 18 | 19 | :: Step 2: Create the configuration 20 | echo ^>^> Creating profiles.yml 21 | echo. > profiles.yml 22 | echo jaffle_shop: >> profiles.yml 23 | echo target: dev >> profiles.yml 24 | echo outputs: >> profiles.yml 25 | echo dev: >> profiles.yml 26 | echo type: duckdb >> profiles.yml 27 | echo path: jaffle_shop.duckdb >> profiles.yml 28 | 29 | :: Generate seed files 30 | python ..\gen_seed.py 31 | 32 | :: Step 3: The first dbt build 33 | dbt build 34 | 35 | :: Tag models 36 | git apply ..\0001-apply-tags.patch 37 | git add . 38 | git commit -m "Added PipeRider tags" 39 | 40 | :: Show selected 41 | echo dbt list with selector 42 | dbt list -s tag:piperider 43 | 44 | :: Make a change to the project 45 | git checkout -b feature/add-average-value-per-order 46 | git apply ..\0002-Add-average_value_per_order-to-customers.patch 47 | git commit -sam "Add average_value_per_order to customers" 48 | 49 | :: Compare your branch with main 50 | piperider compare 51 | 52 | :: Restore previous directory 53 | popd 54 | -------------------------------------------------------------------------------- /e2e-jaffle-shop/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | git config --global user.email "dev-ci@infuseai.io" 4 | git config --global user.name "dev-ci" 5 | 6 | # Move to the e2e directory 7 | 8 | SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" 9 | cd "$SCRIPT_DIR" 10 | pwd 11 | 12 | # Show dbt version 13 | dbt --version 14 | 15 | # Reference 16 | # https://docs.piperider.io/get-started/quick-start 17 | # 18 | 19 | # Step 1: clone the repo 20 | git clone https://github.com/dbt-labs/jaffle_shop.git 21 | cd jaffle_shop 22 | 23 | # Step 2: create the configuration 24 | cat >profiles.yml < -------------------------------------------------------------------------------- /piperider_cli/data/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/__init__.py -------------------------------------------------------------------------------- /piperider_cli/data/piperider-init-template/config.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/piperider-init-template/config.yml -------------------------------------------------------------------------------- /piperider_cli/data/piperider-init-template/gitignore: -------------------------------------------------------------------------------- 1 | **.log 2 | __pycache__/ 3 | logs/ 4 | outputs/ 5 | reports/ 6 | comparisons/ 7 | credentials.yml 8 | .unsend_events.json -------------------------------------------------------------------------------- /piperider_cli/data/report/.gitignore: -------------------------------------------------------------------------------- 1 | *.js.map 2 | -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/index.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-chrome-192x192.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-chrome-512x512.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-icon-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-icon-192x192.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-icon-36x36.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-icon-48x48.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-icon-72x72.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/android-icon-96x96.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-114x114.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-120x120.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-152x152.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-180x180.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-57x57.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-60x60.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-72x72.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-76x76.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon-precomposed.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-icon.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/apple-touch-icon.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/favicon-16x16.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/favicon-32x32.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/favicon-96x96.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/favicon.ico -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/ms-icon-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/ms-icon-150x150.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/ms-icon-310x310.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/ms-icon-70x70.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/mstile-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/mstile-150x150.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/mstile-310x150.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/mstile-310x310.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/logo/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/logo/mstile-70x70.png -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/js/479.d5e430c3.chunk.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * react-table 3 | * 4 | * Copyright (c) TanStack 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.md file in the root directory of this source tree. 8 | * 9 | * @license MIT 10 | */ 11 | 12 | /** 13 | * table-core 14 | * 15 | * Copyright (c) TanStack 16 | * 17 | * This source code is licensed under the MIT license found in the 18 | * LICENSE.md file in the root directory of this source tree. 19 | * 20 | * @license MIT 21 | */ 22 | -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Black.ab57b908749eb205e3ad.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Black.ab57b908749eb205e3ad.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Black.cadfd7434852779eb395.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Black.cadfd7434852779eb395.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-BlackItalic.9bb4dd54e5afbea2e0ac.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-BlackItalic.9bb4dd54e5afbea2e0ac.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-BlackItalic.f0098e273d2a3758b89c.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-BlackItalic.f0098e273d2a3758b89c.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Bold.1577ca92013647c816b5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Bold.1577ca92013647c816b5.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Bold.f57c31edca48068386d7.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Bold.f57c31edca48068386d7.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-BoldItalic.52e97aac5945285c9933.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-BoldItalic.52e97aac5945285c9933.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-BoldItalic.5b7f79817b551400186a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-BoldItalic.5b7f79817b551400186a.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBold.0321ea88d696270daf4b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBold.0321ea88d696270daf4b.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBold.a611efd96602ca47acd9.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBold.a611efd96602ca47acd9.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBoldItalic.43f46f665391ff324c72.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBoldItalic.43f46f665391ff324c72.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBoldItalic.dc0b36ae1c1bdac232e7.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraBoldItalic.dc0b36ae1c1bdac232e7.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLight.4e029f034c7e7263df9a.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLight.4e029f034c7e7263df9a.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLight.bafff4ae7f2a3395aa13.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLight.bafff4ae7f2a3395aa13.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLightItalic.124644177779db0a8867.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLightItalic.124644177779db0a8867.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLightItalic.ff3def84a34422de5487.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ExtraLightItalic.ff3def84a34422de5487.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Italic.9736c3faff86c01270b2.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Italic.9736c3faff86c01270b2.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Italic.ce6bab8bc932d6080ec1.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Italic.ce6bab8bc932d6080ec1.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Light.919d6ffdd987dc2e4717.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Light.919d6ffdd987dc2e4717.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Light.aafd1643606ee83ad4cb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Light.aafd1643606ee83ad4cb.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-LightItalic.7f7cde8e1548e11231fb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-LightItalic.7f7cde8e1548e11231fb.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-LightItalic.e66e7a760a286c694d2b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-LightItalic.e66e7a760a286c694d2b.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Medium.5a92f7b05463ecd61f45.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Medium.5a92f7b05463ecd61f45.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Medium.a6ca36dde32b3a1d0fd4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Medium.a6ca36dde32b3a1d0fd4.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-MediumItalic.dbc1ed152c7b11f501a3.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-MediumItalic.dbc1ed152c7b11f501a3.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-MediumItalic.e3618413f59e00041fb3.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-MediumItalic.e3618413f59e00041fb3.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Regular.222064f2a764069868f4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Regular.222064f2a764069868f4.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Regular.67a27362108220436ffb.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Regular.67a27362108220436ffb.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-SemiBold.599ce7634f46c5024ad0.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-SemiBold.599ce7634f46c5024ad0.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-SemiBold.c2e7341dd6ac6502be69.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-SemiBold.c2e7341dd6ac6502be69.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-SemiBoldItalic.09bc481607bd529abda7.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-SemiBoldItalic.09bc481607bd529abda7.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-SemiBoldItalic.43f7c276720845c6bb59.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-SemiBoldItalic.43f7c276720845c6bb59.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Thin.92cada3d91581eb5112d.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Thin.92cada3d91581eb5112d.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-Thin.df0b1bcf558ccd5b48a2.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-Thin.df0b1bcf558ccd5b48a2.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ThinItalic.78bf87d2ea41ac4365c1.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ThinItalic.78bf87d2ea41ac4365c1.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-ThinItalic.82dd2dc2fb674d8273e4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-ThinItalic.82dd2dc2fb674d8273e4.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-italic.var.28904cc0eac675e1d19e.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-italic.var.28904cc0eac675e1d19e.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter-roman.var.f05060926bf5023f9930.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter-roman.var.f05060926bf5023f9930.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/comparison-report/static/media/Inter.var.c3f97a25f56b5b416e49.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/comparison-report/static/media/Inter.var.c3f97a25f56b5b416e49.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/index.html: -------------------------------------------------------------------------------- 1 |
-------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-chrome-192x192.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-chrome-512x512.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-icon-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-icon-192x192.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-icon-36x36.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-icon-48x48.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-icon-72x72.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/android-icon-96x96.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-114x114.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-120x120.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-152x152.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-180x180.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-57x57.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-60x60.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-72x72.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-76x76.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon-precomposed.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-icon.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/apple-touch-icon.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/favicon-16x16.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/favicon-32x32.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/favicon-96x96.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/favicon.ico -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/ms-icon-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/ms-icon-150x150.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/ms-icon-310x310.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/ms-icon-70x70.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/mstile-144x144.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/mstile-150x150.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/mstile-310x150.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/mstile-310x310.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/logo/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/logo/mstile-70x70.png -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/js/479.d5e430c3.chunk.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /** 2 | * react-table 3 | * 4 | * Copyright (c) TanStack 5 | * 6 | * This source code is licensed under the MIT license found in the 7 | * LICENSE.md file in the root directory of this source tree. 8 | * 9 | * @license MIT 10 | */ 11 | 12 | /** 13 | * table-core 14 | * 15 | * Copyright (c) TanStack 16 | * 17 | * This source code is licensed under the MIT license found in the 18 | * LICENSE.md file in the root directory of this source tree. 19 | * 20 | * @license MIT 21 | */ 22 | -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Black.ab57b908749eb205e3ad.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Black.ab57b908749eb205e3ad.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Black.cadfd7434852779eb395.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Black.cadfd7434852779eb395.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-BlackItalic.9bb4dd54e5afbea2e0ac.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-BlackItalic.9bb4dd54e5afbea2e0ac.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-BlackItalic.f0098e273d2a3758b89c.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-BlackItalic.f0098e273d2a3758b89c.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Bold.1577ca92013647c816b5.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Bold.1577ca92013647c816b5.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Bold.f57c31edca48068386d7.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Bold.f57c31edca48068386d7.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-BoldItalic.52e97aac5945285c9933.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-BoldItalic.52e97aac5945285c9933.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-BoldItalic.5b7f79817b551400186a.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-BoldItalic.5b7f79817b551400186a.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraBold.0321ea88d696270daf4b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraBold.0321ea88d696270daf4b.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraBold.a611efd96602ca47acd9.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraBold.a611efd96602ca47acd9.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraBoldItalic.43f46f665391ff324c72.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraBoldItalic.43f46f665391ff324c72.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraBoldItalic.dc0b36ae1c1bdac232e7.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraBoldItalic.dc0b36ae1c1bdac232e7.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraLight.4e029f034c7e7263df9a.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraLight.4e029f034c7e7263df9a.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraLight.bafff4ae7f2a3395aa13.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraLight.bafff4ae7f2a3395aa13.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraLightItalic.124644177779db0a8867.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraLightItalic.124644177779db0a8867.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ExtraLightItalic.ff3def84a34422de5487.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ExtraLightItalic.ff3def84a34422de5487.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Italic.9736c3faff86c01270b2.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Italic.9736c3faff86c01270b2.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Italic.ce6bab8bc932d6080ec1.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Italic.ce6bab8bc932d6080ec1.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Light.919d6ffdd987dc2e4717.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Light.919d6ffdd987dc2e4717.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Light.aafd1643606ee83ad4cb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Light.aafd1643606ee83ad4cb.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-LightItalic.7f7cde8e1548e11231fb.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-LightItalic.7f7cde8e1548e11231fb.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-LightItalic.e66e7a760a286c694d2b.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-LightItalic.e66e7a760a286c694d2b.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Medium.5a92f7b05463ecd61f45.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Medium.5a92f7b05463ecd61f45.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Medium.a6ca36dde32b3a1d0fd4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Medium.a6ca36dde32b3a1d0fd4.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-MediumItalic.dbc1ed152c7b11f501a3.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-MediumItalic.dbc1ed152c7b11f501a3.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-MediumItalic.e3618413f59e00041fb3.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-MediumItalic.e3618413f59e00041fb3.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Regular.222064f2a764069868f4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Regular.222064f2a764069868f4.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Regular.67a27362108220436ffb.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Regular.67a27362108220436ffb.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-SemiBold.599ce7634f46c5024ad0.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-SemiBold.599ce7634f46c5024ad0.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-SemiBold.c2e7341dd6ac6502be69.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-SemiBold.c2e7341dd6ac6502be69.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-SemiBoldItalic.09bc481607bd529abda7.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-SemiBoldItalic.09bc481607bd529abda7.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-SemiBoldItalic.43f7c276720845c6bb59.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-SemiBoldItalic.43f7c276720845c6bb59.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Thin.92cada3d91581eb5112d.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Thin.92cada3d91581eb5112d.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-Thin.df0b1bcf558ccd5b48a2.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-Thin.df0b1bcf558ccd5b48a2.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ThinItalic.78bf87d2ea41ac4365c1.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ThinItalic.78bf87d2ea41ac4365c1.woff -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-ThinItalic.82dd2dc2fb674d8273e4.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-ThinItalic.82dd2dc2fb674d8273e4.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-italic.var.28904cc0eac675e1d19e.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-italic.var.28904cc0eac675e1d19e.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter-roman.var.f05060926bf5023f9930.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter-roman.var.f05060926bf5023f9930.woff2 -------------------------------------------------------------------------------- /piperider_cli/data/report/single-report/static/media/Inter.var.c3f97a25f56b5b416e49.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/data/report/single-report/static/media/Inter.var.c3f97a25f56b5b416e49.woff2 -------------------------------------------------------------------------------- /piperider_cli/datasource/survey.py: -------------------------------------------------------------------------------- 1 | from piperider_cli.error import PipeRiderError 2 | from piperider_cli.feedback import Feedback 3 | from . import DataSource 4 | from .field import ListField, TextField 5 | 6 | 7 | class UserSurveyMockDataSource(DataSource): 8 | def __init__(self, name, **kwargs): 9 | super().__init__(name, 'datasource survey', **kwargs) 10 | self.fields = [ 11 | ] 12 | 13 | # Always return None to prevent it generate the configue files 14 | def ask_credential(self): 15 | super().ask_credential() 16 | return None 17 | 18 | def validate(self): 19 | return False, [] 20 | 21 | def to_database_url(self): 22 | return '' 23 | 24 | def verify_connector(self): 25 | return PipeRiderError('', 26 | hint="Thanks for your feedback. We will improve Piperider in the future.\nPlease execute command 'piperider init' with supported data source.") 27 | 28 | def _get_display_description(self): 29 | return '' 30 | 31 | def get_database(self): 32 | return '' 33 | 34 | def get_schema(self): 35 | return '' 36 | 37 | def send_survey(self): 38 | datasource = self.credential.get('datasource_candidates') 39 | if datasource == 'Other': 40 | datasource = self.credential.get('other') 41 | Feedback.suggest_datasource(datasource) 42 | pass 43 | -------------------------------------------------------------------------------- /piperider_cli/datasource/unsupported.py: -------------------------------------------------------------------------------- 1 | from piperider_cli.datasource import DataSource 2 | from piperider_cli.error import PipeRiderConnectorUnsupportedError 3 | 4 | 5 | class UnsupportedDataSource(DataSource): 6 | def __init__(self, name, **kwargs): 7 | super().__init__(name, 'unsupported', **kwargs) 8 | self.fields = [ 9 | ] 10 | 11 | def validate(self): 12 | return True, [] 13 | 14 | def to_database_url(self): 15 | return '' 16 | 17 | def verify_connector(self): 18 | datasource_type = self.credential.get('type', 'Unknown') 19 | return PipeRiderConnectorUnsupportedError( 20 | f"Piperider doesn't support data source '{self.name}' of type '{datasource_type}'.", 21 | datasource_type) 22 | 23 | def _get_display_description(self): 24 | return '' 25 | 26 | def get_database(self): 27 | return '' 28 | 29 | def get_schema(self): 30 | return '' 31 | 32 | def get_engine_by_database(self): 33 | return None 34 | -------------------------------------------------------------------------------- /piperider_cli/dbt/markdown.py: -------------------------------------------------------------------------------- 1 | from typing import Any, List 2 | 3 | 4 | class MarkdownTable: 5 | 6 | def __init__(self, *, headers: List[str]): 7 | self.headers: List[str] = headers 8 | self.num_of_columns = len(self.headers) 9 | self.rows = [] 10 | 11 | def add_row(self, columns: List): 12 | if len(columns) != self.num_of_columns: 13 | raise ValueError('The number of columns doesn\'t match headers') 14 | 15 | self.rows.append(columns) 16 | 17 | def build(self): 18 | header_lines = "| " + " | ".join(self.headers).strip() 19 | header_ending = "| " + " | ".join(["--" for x in self.headers]).strip() 20 | row_lines = [] 21 | 22 | for r in self.rows: 23 | row = "| " + " | ".join([self.as_str(x) for x in r]).strip() 24 | row_lines.append(row) 25 | 26 | return "\n".join([header_lines, header_ending] + row_lines) 27 | 28 | def as_str(self, entry: Any): 29 | if isinstance(entry, str): 30 | return entry 31 | return str(entry) 32 | -------------------------------------------------------------------------------- /piperider_cli/dbt/reverse_manifest.py: -------------------------------------------------------------------------------- 1 | from typing import Dict 2 | 3 | 4 | def build_columns(column_details: Dict): 5 | result = dict() 6 | for name, v in column_details.items(): 7 | result[name] = dict(name=name, description=v.get('description'), 8 | type='other', schema_type='other') 9 | return result 10 | 11 | 12 | def reverse_to_run(manifest_data: Dict): 13 | from piperider_cli.dbt.list_task import list_resources_data_from_manifest, load_manifest 14 | base_data = dict(id="tmp-run", tables={}, created_at="2023-08-14T03:46:51.629668Z", 15 | datasource=dict(name='empty', type='duckdb')) 16 | dbt = dict(manifest=manifest_data, run_results={}) 17 | base_data['dbt'] = dbt 18 | 19 | tables = dict() 20 | nodes = manifest_data.get('nodes') 21 | 22 | for x in list_resources_data_from_manifest(load_manifest(manifest_data)): 23 | resource_type = x.get('resource_type') 24 | unique_id = x.get('unique_id') 25 | 26 | if unique_id not in nodes: 27 | continue 28 | 29 | if resource_type not in ['model', 'seed', 'source']: 30 | continue 31 | table_name = x.get('name') 32 | column_details: Dict[Dict] = nodes.get(unique_id).get('columns') 33 | tables[table_name] = dict(name=table_name, col_count=len(column_details), columns=build_columns(column_details), 34 | ref_id=unique_id) 35 | 36 | base_data["tables"] = tables 37 | return base_data 38 | -------------------------------------------------------------------------------- /piperider_cli/dbt/sorting.py: -------------------------------------------------------------------------------- 1 | from collections import deque 2 | 3 | 4 | def topological_sort(graph, num_of_vertices): 5 | in_degree = {i: 0 for i in graph} 6 | 7 | for i in graph: 8 | for j in graph[i]: 9 | in_degree[j] += 1 10 | 11 | queue = deque() 12 | for i in graph: 13 | if in_degree[i] == 0: 14 | queue.append(i) 15 | 16 | cnt = 0 17 | top_order = [] 18 | 19 | while queue: 20 | u = queue.popleft() 21 | top_order.append(u) 22 | 23 | for i in graph[u]: 24 | in_degree[i] -= 1 25 | if in_degree[i] == 0: 26 | queue.append(i) 27 | 28 | cnt += 1 29 | 30 | # Check if there was a cycle 31 | if cnt != num_of_vertices: 32 | raise Exception("There exists a cycle in the graph. Topological sorting is not possible.") 33 | else: 34 | return top_order 35 | -------------------------------------------------------------------------------- /piperider_cli/docgen/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/docgen/__init__.py -------------------------------------------------------------------------------- /piperider_cli/event/events.py: -------------------------------------------------------------------------------- 1 | class RunEventPayload: 2 | 3 | def __init__(self): 4 | self.status = False 5 | self.reason = None 6 | self.step = None 7 | self.datasource_type = None 8 | self.skip_datasource = None 9 | self.tables = 0 10 | self.columns = [] 11 | self.rows = [] 12 | self.passed_dbt_testcases = 0 13 | self.failed_dbt_testcases = 0 14 | 15 | def to_dict(self): 16 | return self.__dict__ 17 | 18 | 19 | class CompareEventPayload: 20 | 21 | def __init__(self): 22 | self.status = False 23 | self.reason = None 24 | self.step = None 25 | self.datasource_type = None 26 | self.skip_datasource = None 27 | 28 | def to_dict(self): 29 | return self.__dict__ 30 | -------------------------------------------------------------------------------- /piperider_cli/exitcode.py: -------------------------------------------------------------------------------- 1 | EC_OK = 0 2 | EC_ERR_GENERAL = 1 3 | EC_ERR_TEST_FAILED = 2 4 | EC_WARN_NO_PROFILED_MODULES = 3 5 | -------------------------------------------------------------------------------- /piperider_cli/feedback.py: -------------------------------------------------------------------------------- 1 | import webbrowser 2 | 3 | 4 | def _send_feedback(url): 5 | try: 6 | webbrowser.open(url, new=2) 7 | except webbrowser.Error: 8 | print(f"The feedback form: {url}") 9 | 10 | 11 | class Feedback: 12 | 13 | @staticmethod 14 | def exec(): 15 | url = "https://docs.google.com/forms/d/e/1FAIpQLSe0J8qC78lqMVxSAJFPub6QXx2NcVY8WLvIVEGthOeQcJHxFQ/viewform?usp=pp_url&entry.2024961102=PipeRider+CLI" 16 | _send_feedback(url) 17 | 18 | @staticmethod 19 | def suggest_datasource(data_source_name): 20 | url = "https://docs.google.com/forms/d/e/1FAIpQLSe0J8qC78lqMVxSAJFPub6QXx2NcVY8WLvIVEGthOeQcJHxFQ/viewform?usp=pp_url&entry.2024961102=PipeRider+CLI&entry.326955045=I+suggest+supporting+a+data+source+for+%5Bfill+me%5D" 21 | _send_feedback(url) 22 | pass 23 | -------------------------------------------------------------------------------- /piperider_cli/hack/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/piperider_cli/hack/__init__.py -------------------------------------------------------------------------------- /piperider_cli/hack/datasource_inquirer_prompt.py: -------------------------------------------------------------------------------- 1 | import inquirer.themes as themes 2 | from inquirer.render.console import ConsoleRender 3 | 4 | 5 | def prompt(questions, render=None, answers=None, theme=themes.Default(), raise_keyboard_interrupt=False): 6 | render = render or ConsoleRender(theme=theme) 7 | answers = answers or {} 8 | 9 | try: 10 | for question in questions: 11 | # support the hidden field 12 | # the answer is getting from callback, not by users input directly 13 | if hasattr(question, 'callback') and getattr(question, 'callback') is not None: 14 | answers[question.name] = question.callback(answers) 15 | else: 16 | answers[question.name] = render.render(question, answers) 17 | return answers 18 | except KeyboardInterrupt: 19 | if raise_keyboard_interrupt: 20 | raise 21 | print("") 22 | print("Cancelled by user") 23 | print("") 24 | -------------------------------------------------------------------------------- /piperider_cli/metrics_engine/__init__.py: -------------------------------------------------------------------------------- 1 | from .metrics import MetricEngine, Metric 2 | from .event import MetricEventHandler 3 | -------------------------------------------------------------------------------- /piperider_cli/profiler/__init__.py: -------------------------------------------------------------------------------- 1 | from .profiler import Profiler, ProfileSubject 2 | from .event import ProfilerEventHandler, DefaultProfilerEventHandler 3 | -------------------------------------------------------------------------------- /piperider_cli/profiler/version.py: -------------------------------------------------------------------------------- 1 | import hashlib 2 | import os.path 3 | 4 | 5 | def schema_version(): 6 | import piperider_cli.profiler as p 7 | schema_def = os.path.join(os.path.dirname(p.__file__), 'schema.json') 8 | with open(schema_def) as fh: 9 | m = hashlib.md5() 10 | m.update(fh.read().encode()) 11 | return m.hexdigest() 12 | 13 | 14 | if __name__ == '__main__': 15 | print(schema_version()) 16 | -------------------------------------------------------------------------------- /piperider_cli/recipes/git_repo_example.yml: -------------------------------------------------------------------------------- 1 | # .piperider/compare/default.yml 2 | base: 3 | branch: main 4 | dbt: 5 | commands: 6 | - dbt deps 7 | - dbt run 8 | piperider: 9 | commands: 10 | - piperider run --dbt-state target/ 11 | target: 12 | dbt: 13 | commands: 14 | - dbt deps 15 | - dbt run 16 | piperider: 17 | commands: 18 | - piperider run --dbt-state target/ 19 | -------------------------------------------------------------------------------- /piperider_cli/statistics.py: -------------------------------------------------------------------------------- 1 | from rich.console import Console 2 | 3 | 4 | class Statistics: 5 | _instance = None 6 | statistic = {} 7 | 8 | def __new__(cls, *args, **kwargs): 9 | if cls._instance is None: 10 | cls._instance = super().__new__(cls) 11 | return cls._instance 12 | 13 | def reset(self): 14 | self.statistic = {} 15 | 16 | def add_field(self, field: str, num: int): 17 | if field not in self.statistic: 18 | self.statistic[field] = 0 19 | self.statistic[field] += num 20 | 21 | def add_field_one(self, field: str): 22 | self.add_field(field, 1) 23 | 24 | def display_statistic(self, action, subject): 25 | console = Console() 26 | if self.statistic.get('total', 0) == 0: 27 | console.print(f"No {subject}s to {action}") 28 | return 29 | num_skip = sum(self.statistic.values()) - self.statistic['total'] 30 | if self.statistic['total'] - num_skip == 0: 31 | console.print(f"No {subject}s to {action}") 32 | elif num_skip > 0: 33 | subject = subject + 's' if num_skip > 1 else subject 34 | msg = ", ".join([f"{k}={v}" for k, v in self.statistic.items() if k != 'total' and v != 0]) 35 | console.print( 36 | f"{action} {self.statistic['total'] - num_skip} {subject}, skip {num_skip} {subject} ({msg})\n") 37 | -------------------------------------------------------------------------------- /piperider_cli/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import platform 3 | import subprocess 4 | 5 | 6 | def remove_link(link_path): 7 | try: 8 | if platform.system() == 'Windows': 9 | if os.path.exists(link_path): 10 | subprocess.run(["rmdir", link_path], shell=True, check=True) 11 | else: 12 | if os.path.exists(link_path) or os.path.islink(link_path): 13 | os.unlink(link_path) 14 | except OSError as e: 15 | raise e 16 | 17 | 18 | def create_link(source: str, target: str): 19 | if not os.path.isabs(source): 20 | raise ValueError(f'source must be abspath: {source}') 21 | if not os.path.isabs(target): 22 | raise ValueError(f'target must be abspath: {target}') 23 | 24 | remove_link(target) 25 | 26 | # Check the platform 27 | if platform.system() == "Windows": 28 | # On Windows, try creating a junction 29 | try: 30 | subprocess.run(["mklink", "/J", target, source], shell=True, check=True, 31 | stderr=subprocess.DEVNULL, 32 | stdout=subprocess.DEVNULL) 33 | except subprocess.CalledProcessError as e: 34 | raise e 35 | else: 36 | # On non-Windows platforms, create a symbolic link 37 | os.symlink(source, target) 38 | -------------------------------------------------------------------------------- /piperider_cli/yaml/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Any, Callable 2 | 3 | from ruamel import yaml 4 | from ruamel.yaml import CommentedMap as _cm, CommentedSeq as _cs 5 | 6 | _yaml = yaml.YAML() 7 | 8 | CommentedMap = _cm 9 | CommentedSeq = _cs 10 | YAMLError = yaml.YAMLError 11 | 12 | 13 | def load(stream) -> Any: 14 | return _yaml.load(stream) 15 | 16 | 17 | def allow_duplicate_keys_loader() -> Callable: 18 | yml = yaml.YAML() 19 | yml.allow_duplicate_keys = True 20 | return yml.load 21 | 22 | 23 | def safe_load(stream, version=None) -> Any: 24 | return yaml.safe_load(stream, version) 25 | 26 | 27 | def dump( 28 | data, stream: Any = None, *, transform: Any = None 29 | ) -> Any: 30 | return _yaml.dump(data, stream, transform=transform) 31 | 32 | 33 | def safe_load_yaml(file_path): 34 | try: 35 | with open(file_path, 'r') as f: 36 | payload = safe_load(f) 37 | except yaml.YAMLError as e: 38 | print(e) 39 | return None 40 | except FileNotFoundError: 41 | return None 42 | return payload 43 | 44 | 45 | def round_trip_load_yaml(file_path): 46 | with open(file_path, 'r') as f: 47 | try: 48 | payload = load(f) 49 | except yaml.YAMLError as e: 50 | print(e) 51 | return None 52 | return payload 53 | 54 | 55 | def round_trip_dump( 56 | data: Any, 57 | stream=None): 58 | return yaml.round_trip_dump(data, stream) 59 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # install dependencies from setup.py (editable mode) 2 | -e . 3 | -------------------------------------------------------------------------------- /static_report/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*.{js,json}] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /static_report/.env.development: -------------------------------------------------------------------------------- 1 | # Please manually fill Amplitude API Key 2 | AMPLITUDE_API_KEY= 3 | -------------------------------------------------------------------------------- /static_report/.eslintignore: -------------------------------------------------------------------------------- 1 | src/sdlc/schema-meta.ts 2 | src/sdls/single-report-schema.d.ts 3 | -------------------------------------------------------------------------------- /static_report/.gitignore: -------------------------------------------------------------------------------- 1 | # generated report schemas 2 | *-report-schema.json 3 | node_modules/ 4 | package-lock.json 5 | npm-debug.log* 6 | .pnp.* 7 | .yarn/* 8 | piperider-metadata.json 9 | !lib/ 10 | !pnpm-lock.yaml 11 | run.json 12 | comparison_data.json 13 | -------------------------------------------------------------------------------- /static_report/.npmrc: -------------------------------------------------------------------------------- 1 | auto-install-peers=true 2 | -------------------------------------------------------------------------------- /static_report/.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.codeActionsOnSave": { 3 | "source.fixAll.eslint": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /static_report/build-env/.env.comparison: -------------------------------------------------------------------------------- 1 | PORT=4000 2 | REACT_APP_SINGLE_REPORT=false 3 | BUILD_PATH='./build/comparison-report' 4 | WDS_SOCKET_PORT=0 5 | -------------------------------------------------------------------------------- /static_report/build-env/.env.comparison-asymmetric: -------------------------------------------------------------------------------- 1 | PORT=4001 2 | REACT_APP_SINGLE_REPORT=false 3 | BUILD_PATH='./build/comparison-asymmetric-report' -------------------------------------------------------------------------------- /static_report/build-env/.env.comparison-e2e: -------------------------------------------------------------------------------- 1 | PORT=3001 2 | REACT_APP_SINGLE_REPORT=false 3 | REACT_APP_E2E=true 4 | BUILD_PATH='./build/comparison-report' 5 | -------------------------------------------------------------------------------- /static_report/build-env/.env.single: -------------------------------------------------------------------------------- 1 | PORT=3000 2 | REACT_APP_SINGLE_REPORT=true 3 | BUILD_PATH='./build/single-report' 4 | WDS_SOCKET_PORT=0 5 | -------------------------------------------------------------------------------- /static_report/build-env/.env.single-e2e: -------------------------------------------------------------------------------- 1 | PORT=3000 2 | REACT_APP_SINGLE_REPORT=true 3 | REACT_APP_E2E=true 4 | BUILD_PATH='./build/single-report' 5 | -------------------------------------------------------------------------------- /static_report/build-env/.env.single-edge: -------------------------------------------------------------------------------- 1 | PORT=4000 2 | REACT_APP_SINGLE_REPORT=true 3 | BUILD_PATH='./build/single-edge-report' -------------------------------------------------------------------------------- /static_report/craco.config.cjs: -------------------------------------------------------------------------------- 1 | const CracoEsbuildPlugin = (async () => await import('craco-esbuild'))(); 2 | const event = process.env.npm_lifecycle_event; 3 | 4 | if (event === 'serve:single' || event === 'serve:comparison') { 5 | const { readFileSync, existsSync } = require('fs'); 6 | const { resolve } = require('path'); 7 | const FILENAME_SINGLE = 'run.json'; 8 | const FILENAME_COMPARISON = 'comparison_data.json'; 9 | 10 | const report_type = event.split(':')[1]; 11 | process.env.REACT_APP_SINGLE_REPORT_DATA_JSON = {}; 12 | process.env.REACT_APP_COMPARISON_REPORT_DATA_JSON = {}; 13 | 14 | // Load report data from current directory 15 | if (report_type === 'single') { 16 | const singleReportPath = resolve(FILENAME_SINGLE); 17 | if (existsSync(singleReportPath)) { 18 | process.env.REACT_APP_SINGLE_REPORT_DATA_JSON = JSON.stringify( 19 | JSON.parse(Buffer.from(readFileSync(singleReportPath, 'utf8'))), 20 | ); 21 | } 22 | } else if (report_type === 'comparison') { 23 | const comparisonReportPath = resolve(FILENAME_COMPARISON); 24 | if (existsSync(comparisonReportPath)) { 25 | process.env.REACT_APP_COMPARISON_REPORT_DATA_JSON = JSON.stringify( 26 | JSON.parse(Buffer.from(readFileSync(comparisonReportPath, 'utf8'))), 27 | ); 28 | } 29 | } 30 | } 31 | 32 | module.exports = { 33 | plugins: [{ plugin: CracoEsbuildPlugin }], 34 | }; 35 | -------------------------------------------------------------------------------- /static_report/cypress.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "cypress"; 2 | 3 | export default defineConfig({ 4 | e2e: { 5 | setupNodeEvents(on, config) { 6 | // implement node event listeners here 7 | }, 8 | }, 9 | }); 10 | -------------------------------------------------------------------------------- /static_report/cypress/e2e/comparison-asym-base-target.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Comparison Report (sp500.db -> profiler-e2e.db)', () => { 2 | it('Navigate thru Abnormal Datasets CR Pages ', () => { 3 | cy.visit('http://localhost:4001'); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /static_report/cypress/e2e/comparison-report.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Comparison Report [table-list-page, table-detail-page]', () => { 2 | it('should navigate to the table detail page', () => { 3 | cy.visit('http://localhost:3001'); 4 | }); 5 | it('should navigate to assertions list page', () => { 6 | cy.visit('http://localhost:3001/#/assertions'); 7 | }); 8 | it('should navigate to BM page ', () => { 9 | cy.visit('http://localhost:3001/#/metrics'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /static_report/cypress/e2e/single-report-abnormal-data.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Single Report (profiler-e2e.db)', () => { 2 | it('Navigate thru Abnormal Datasets SR Pages ', () => { 3 | cy.visit('http://localhost:4000'); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /static_report/cypress/e2e/single-report.cy.ts: -------------------------------------------------------------------------------- 1 | describe('Single Report [table-list-page, table-detail-page]', () => { 2 | it('should navigate to the table list page', () => { 3 | cy.visit('http://localhost:3000/'); 4 | }); 5 | it('should navigate to assertions list page', () => { 6 | cy.visit('http://localhost:3000/#/assertions'); 7 | }); 8 | it('should navigate to BM page ', () => { 9 | cy.visit('http://localhost:3000/#/metrics'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /static_report/cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } 6 | -------------------------------------------------------------------------------- /static_report/cypress/support/commands.ts: -------------------------------------------------------------------------------- 1 | /// 2 | // *********************************************** 3 | // This example commands.ts shows you how to 4 | // create various custom commands and overwrite 5 | // existing commands. 6 | // 7 | // For more comprehensive examples of custom 8 | // commands please read more here: 9 | // https://on.cypress.io/custom-commands 10 | // *********************************************** 11 | // 12 | // 13 | // -- This is a parent command -- 14 | // Cypress.Commands.add('login', (email, password) => { ... }) 15 | // 16 | // 17 | // -- This is a child command -- 18 | // Cypress.Commands.add('drag', { prevSubject: 'element'}, (subject, options) => { ... }) 19 | // 20 | // 21 | // -- This is a dual command -- 22 | // Cypress.Commands.add('dismiss', { prevSubject: 'optional'}, (subject, options) => { ... }) 23 | // 24 | // 25 | // -- This will overwrite an existing command -- 26 | // Cypress.Commands.overwrite('visit', (originalFn, url, options) => { ... }) 27 | // 28 | // declare global { 29 | // namespace Cypress { 30 | // interface Chainable { 31 | // login(email: string, password: string): Chainable 32 | // drag(subject: string, options?: Partial): Chainable 33 | // dismiss(subject: string, options?: Partial): Chainable 34 | // visit(originalFn: CommandOriginalFn, url: string, options: Partial): Chainable 35 | // } 36 | // } 37 | // } -------------------------------------------------------------------------------- /static_report/cypress/support/e2e.ts: -------------------------------------------------------------------------------- 1 | // *********************************************************** 2 | // This example support/e2e.ts is processed and 3 | // loaded automatically before your test files. 4 | // 5 | // This is a great place to put global configuration and 6 | // behavior that modifies Cypress. 7 | // 8 | // You can change the location of this file or turn off 9 | // automatically serving support files with the 10 | // 'supportFile' configuration option. 11 | // 12 | // You can read more here: 13 | // https://on.cypress.io/configuration 14 | // *********************************************************** 15 | 16 | // Import commands.js using ES2015 syntax: 17 | import './commands' 18 | 19 | // Alternatively you can use CommonJS syntax: 20 | // require('./commands') -------------------------------------------------------------------------------- /static_report/cypress/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "lib": ["es5", "dom"], 5 | "types": ["cypress", "node"] 6 | }, 7 | "include": ["**/*.ts"] 8 | } 9 | -------------------------------------------------------------------------------- /static_report/jest.config.js: -------------------------------------------------------------------------------- 1 | export default { 2 | coverageDirectory: 'coverage', 3 | preset: 'ts-jest', 4 | testEnvironment: 'node', 5 | testRegex: '(/__tests__/.*|(\\.|/)(test|spec))\\.tsx?$', 6 | }; 7 | -------------------------------------------------------------------------------- /static_report/public/logo/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-chrome-192x192.png -------------------------------------------------------------------------------- /static_report/public/logo/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-chrome-512x512.png -------------------------------------------------------------------------------- /static_report/public/logo/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-icon-144x144.png -------------------------------------------------------------------------------- /static_report/public/logo/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-icon-192x192.png -------------------------------------------------------------------------------- /static_report/public/logo/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-icon-36x36.png -------------------------------------------------------------------------------- /static_report/public/logo/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-icon-48x48.png -------------------------------------------------------------------------------- /static_report/public/logo/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-icon-72x72.png -------------------------------------------------------------------------------- /static_report/public/logo/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/android-icon-96x96.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-114x114.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-120x120.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-144x144.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-152x152.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-180x180.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-57x57.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-60x60.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-72x72.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-76x76.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon-precomposed.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-icon.png -------------------------------------------------------------------------------- /static_report/public/logo/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/apple-touch-icon.png -------------------------------------------------------------------------------- /static_report/public/logo/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | #ffffff -------------------------------------------------------------------------------- /static_report/public/logo/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/favicon-16x16.png -------------------------------------------------------------------------------- /static_report/public/logo/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/favicon-32x32.png -------------------------------------------------------------------------------- /static_report/public/logo/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/favicon-96x96.png -------------------------------------------------------------------------------- /static_report/public/logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/favicon.ico -------------------------------------------------------------------------------- /static_report/public/logo/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "App", 3 | "icons": [ 4 | { 5 | "src": "\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } -------------------------------------------------------------------------------- /static_report/public/logo/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/ms-icon-144x144.png -------------------------------------------------------------------------------- /static_report/public/logo/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/ms-icon-150x150.png -------------------------------------------------------------------------------- /static_report/public/logo/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/ms-icon-310x310.png -------------------------------------------------------------------------------- /static_report/public/logo/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/ms-icon-70x70.png -------------------------------------------------------------------------------- /static_report/public/logo/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/mstile-144x144.png -------------------------------------------------------------------------------- /static_report/public/logo/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/mstile-150x150.png -------------------------------------------------------------------------------- /static_report/public/logo/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/mstile-310x150.png -------------------------------------------------------------------------------- /static_report/public/logo/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/mstile-310x310.png -------------------------------------------------------------------------------- /static_report/public/logo/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/InfuseAI/piperider/523762ca163640bb34b4d4efe66d15880cc8be8c/static_report/public/logo/mstile-70x70.png -------------------------------------------------------------------------------- /static_report/src/components/Assertions/AssertionStatusIcon.tsx: -------------------------------------------------------------------------------- 1 | import { Text } from '@chakra-ui/react'; 2 | import { AssertionTest } from '../../sdlc'; 3 | 4 | export function AssertionStatusIcon({ 5 | status, 6 | }: { 7 | status?: AssertionTest['status']; 8 | }) { 9 | switch (status) { 10 | case 'passed': 11 | return ( 12 | 13 | ✅ 14 | 15 | ); 16 | case 'failed': 17 | return ( 18 | 19 | ❌ 20 | 21 | ); 22 | default: 23 | return ( 24 | 25 | - 26 | 27 | ); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /static_report/src/components/Assertions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AssertionCRModal'; 2 | export * from './AssertionPassFailCountLabel'; 3 | export * from './AssertionStatusIcon'; 4 | -------------------------------------------------------------------------------- /static_report/src/components/Charts/ChartContainer.tsx: -------------------------------------------------------------------------------- 1 | import { Button, Flex, FlexProps, useDisclosure } from '@chakra-ui/react'; 2 | import { ReactNode } from 'react'; 3 | 4 | import { CommonModal } from '../Common/CommonModal'; 5 | 6 | /** 7 | * Container to display one chart. 8 | * Children clickable for showing modal popup zoom of chart 9 | */ 10 | type Props = { 11 | children: ReactNode; 12 | title?: string; 13 | allowModalPopup?: boolean; 14 | height?: number; 15 | }; 16 | export function ChartContainer({ 17 | title, 18 | children, 19 | allowModalPopup, 20 | ...props 21 | }: Props & FlexProps) { 22 | const modal = useDisclosure(); 23 | return ( 24 | <> 25 | allowModalPopup && modal.onOpen()} 29 | {...props} 30 | > 31 | {children} 32 | 33 | {allowModalPopup && ( 34 | 40 | 43 | 44 | } 45 | > 46 | {children} 47 | 48 | )} 49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /static_report/src/components/Charts/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BooleanPieChart'; 2 | export * from './ChartContainer'; 3 | export * from './FlatBoxPlotChart'; 4 | export * from './FlatStackedBarChart'; 5 | export * from './TopKSummaryList'; 6 | export * from './HistogramChart'; 7 | export * from './utils'; 8 | -------------------------------------------------------------------------------- /static_report/src/components/Columns/ColumnMetrics/GeneralStats.tsx: -------------------------------------------------------------------------------- 1 | import { FlexProps } from '@chakra-ui/react'; 2 | import { ColumnSchema } from '../../../sdlc/single-report-schema'; 3 | import { colorMap } from '../../../utils/theme'; 4 | import { MetricNameMetakeyList, transformSRMetricsInfoList } from '../utils'; 5 | import { MetricMetaKeys, MetricsInfo } from './MetricsInfo'; 6 | 7 | interface Props { 8 | columnDatum?: ColumnSchema; 9 | } 10 | /** 11 | * Shows metric stats for Invalids, Missing(nulls) 12 | */ 13 | export function GeneralStats({ columnDatum, ...props }: Props & FlexProps) { 14 | const metakeyEntries: MetricNameMetakeyList = [ 15 | ['invalids', 'Invalid'], 16 | ['nulls', 'Missing'], 17 | ]; 18 | // metric info list defaults to display as percentage 19 | const metricsList = transformSRMetricsInfoList(metakeyEntries, columnDatum); 20 | 21 | return ( 22 | <> 23 | {metricsList.map( 24 | ({ firstSlot, secondSlot, metakey, name, tooltipValues }, index) => ( 25 | 37 | ), 38 | )} 39 | 40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /static_report/src/components/Columns/ColumnMetrics/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GeneralStats'; 2 | export * from './MetricsInfo'; 3 | export * from './QuantilesMatrix'; 4 | export * from './SummaryStats'; 5 | export * from './TypedStats'; 6 | -------------------------------------------------------------------------------- /static_report/src/components/Columns/constants.ts: -------------------------------------------------------------------------------- 1 | export const DISTINCTS = 'DISTINCT'; 2 | export const NULLS = 'MISSING'; 3 | export const NONNULLs = 'NON-NULL'; 4 | export const DUPLICATES = 'DUPLICATE'; 5 | export const NONDUPLICATES = 'NON-DUPLICATE'; 6 | export const NONDUPLICATE_ROWS = 'NON-DUPLICATE ROWS'; 7 | export const VALIDS = 'VALID'; 8 | export const INVALIDS = 'INVALID'; 9 | export const MIN = 'MIN'; 10 | export const MAX = 'MAX'; 11 | export const STDDEV = 'SD'; 12 | export const PLUSMINUS = '±'; 13 | export const AVG = 'AVERAGE'; 14 | export const MODE = 'MOST COMMON'; 15 | export const NONZEROLENGTH = 'NON-ZERO-LENGTH'; 16 | export const ZEROLENGTH = 'ZERO-LENGTH'; 17 | export const TEXTLENGTH = 'Text Length'; 18 | export const TEXTCOUNT = 'Words'; 19 | export const DATE_RANGE = 'Date Range'; 20 | export const VALUE_RANGE = 'Value Range'; 21 | export const CATEGORY_RANGE = 'Category'; 22 | export const POSITIVES = 'POSITIVES'; 23 | export const NEGATIVES = 'NEGATIVES'; 24 | export const ZEROS = 'ZEROS'; 25 | export const TRUES = 'TRUES'; 26 | export const FALSES = 'FALSES'; 27 | export const BOOLEANCOUNT = 'Boolean Value'; 28 | export const TOTAL = 'TOTAL'; 29 | export const NO_VALUE = '-'; 30 | -------------------------------------------------------------------------------- /static_report/src/components/Columns/index.ts: -------------------------------------------------------------------------------- 1 | export * from '../MasterSideNav/index'; 2 | export * from './ColumnMetrics'; 3 | export * from './constants'; 4 | export * from './utils'; 5 | -------------------------------------------------------------------------------- /static_report/src/components/Common/CommonModal.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Modal, 3 | ModalProps, 4 | ModalOverlay, 5 | ModalContent, 6 | ModalHeader, 7 | ModalFooter, 8 | ModalBody, 9 | ModalCloseButton, 10 | UseDisclosureReturn, 11 | } from '@chakra-ui/react'; 12 | import type { ReactNode } from 'react'; 13 | 14 | interface CommonModalProps extends UseDisclosureReturn, ModalProps { 15 | title?: ReactNode | string; 16 | children: ReactNode | string; 17 | footer?: ReactNode; 18 | } 19 | 20 | export function CommonModal({ 21 | title, 22 | children, 23 | footer, 24 | ...modal 25 | }: CommonModalProps) { 26 | return ( 27 | 28 | 29 | 30 | {title && {title}} 31 | 32 | {children} 33 | 34 | {footer && {footer}} 35 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /static_report/src/components/Common/Loading.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Spinner, FlexProps } from '@chakra-ui/react'; 2 | 3 | export function Loading(props: FlexProps) { 4 | return ( 5 | 13 | 14 | 15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /static_report/src/components/Common/MasterDetailContainer.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Flex } from '@chakra-ui/react'; 2 | import { ReactNode } from 'react'; 3 | import { Comparable } from '../../types'; 4 | import { mainContentAreaHeight } from '../../utils'; 5 | import { CloudReportProvider } from '../../utils/cloud'; 6 | import { SideBar } from '../SideBar/SideBar'; 7 | 8 | interface Props extends Comparable { 9 | children: ReactNode; 10 | singleOnly?: boolean; 11 | cloud?: boolean; 12 | sideNavTop?: string; 13 | } 14 | 15 | //NOTE: Only for OSS usage. Reusable for Cloud? 16 | export function MasterDetailContainer({ 17 | children, 18 | sideNavTop = '0px', 19 | cloud, 20 | singleOnly, 21 | }: Props) { 22 | return ( 23 | 24 | 25 | {/* Master Area */} 26 | 37 | 38 | 39 | 40 | 47 | {children} 48 | 49 | 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /static_report/src/components/Common/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Flex, Icon, Image, Link, Text } from '@chakra-ui/react'; 2 | import { FiSquare, FiColumns } from 'react-icons/fi'; 3 | import { NO_VALUE } from '../Columns'; 4 | import { useReportStore } from '../../utils/store'; 5 | import { HelpMenu, FeedbackLinkFromLocalReport } from './HelpMenu'; 6 | 7 | type Props = { 8 | isSingleReport: boolean; 9 | }; 10 | 11 | export function Navbar({ isSingleReport }: Props) { 12 | const { reportDisplayTime } = useReportStore.getState(); 13 | 14 | return ( 15 | 24 | 25 | 26 | PipeRider 27 | 28 | 29 | 30 | 39 | 45 | 46 | {reportDisplayTime || NO_VALUE} 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | ); 55 | } 56 | -------------------------------------------------------------------------------- /static_report/src/components/Common/NoData.tsx: -------------------------------------------------------------------------------- 1 | import { Text, TextProps } from '@chakra-ui/react'; 2 | 3 | interface Props extends TextProps { 4 | text?: string; 5 | } 6 | 7 | const DEFAULT_TEXT = 'No data available'; 8 | 9 | export function NoData({ text = DEFAULT_TEXT, ...props }: Props) { 10 | return ( 11 | 12 | {text} 13 | 14 | ); 15 | } 16 | -------------------------------------------------------------------------------- /static_report/src/components/Common/NotFound.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Heading, Button } from '@chakra-ui/react'; 2 | import { Link } from 'wouter'; 3 | 4 | export function NotFound() { 5 | return ( 6 | 13 | 404, Not Found! 14 | 17 | 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /static_report/src/components/Common/SearchTextInput.tsx: -------------------------------------------------------------------------------- 1 | import { SearchIcon } from '@chakra-ui/icons'; 2 | import { InputGroup, InputLeftElement, Input } from '@chakra-ui/react'; 3 | 4 | interface Props { 5 | onChange: (search: string) => void; 6 | filterString?: string; 7 | placeholder?: string; 8 | } 9 | export function SearchTextInput({ 10 | onChange, 11 | filterString, 12 | placeholder, 13 | }: Props) { 14 | return ( 15 | 16 | } 19 | /> 20 | onChange(target.value)} 27 | /> 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /static_report/src/components/Common/SkipDataSource.tsx: -------------------------------------------------------------------------------- 1 | import { Alert, AlertIcon, AlertDescription } from '@chakra-ui/react'; 2 | 3 | export function SkipDataSource() { 4 | return ( 5 | 6 | 7 | 8 | Schemas and reports generated from manifest files are limited to 9 | information in those manifests. For a more detailed report, follow these{' '} 10 | 16 | instructions 17 | 18 | 19 | 20 | ); 21 | } 22 | -------------------------------------------------------------------------------- /static_report/src/components/Common/constant.ts: -------------------------------------------------------------------------------- 1 | export const NO_DESCRIPTION_MSG = 'No Description Provided'; 2 | -------------------------------------------------------------------------------- /static_report/src/components/Common/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Loading'; 2 | export * from './NoData'; 3 | export * from './SearchTextInput'; 4 | -------------------------------------------------------------------------------- /static_report/src/components/LineageGraph/CopyGraphUrlButton.tsx: -------------------------------------------------------------------------------- 1 | import { Button, useClipboard } from '@chakra-ui/react'; 2 | import { useEffect } from 'react'; 3 | import { useHashParams } from '../../hooks'; 4 | 5 | function getWindow(): Window | undefined { 6 | if (typeof window === 'undefined') { 7 | return undefined; 8 | } 9 | 10 | return window; 11 | } 12 | 13 | function patchUrl(url) { 14 | const urlObj = new URL(url); 15 | const utmParams = [ 16 | 'utm_source', 17 | 'utm_medium', 18 | 'utm_campaign', 19 | 'utm_term', 20 | 'utm_content', 21 | ]; 22 | 23 | for (const param of utmParams) { 24 | urlObj.searchParams.delete(param); 25 | } 26 | 27 | urlObj.searchParams.append('utm_source', 'lineage'); 28 | return urlObj.toString(); 29 | } 30 | 31 | export function CopyGraphUrlButton() { 32 | const _window = getWindow(); 33 | 34 | const { onCopy, setValue, hasCopied } = useClipboard(''); 35 | const hashParams = useHashParams(); 36 | 37 | useEffect(() => { 38 | let url = _window?.location?.href; 39 | if (!url) { 40 | return; 41 | } 42 | url = patchUrl(url); 43 | setValue(url); 44 | }, [_window, hashParams, setValue]); 45 | 46 | return ( 47 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /static_report/src/components/LineageGraph/GraphEdge.tsx: -------------------------------------------------------------------------------- 1 | import { BaseEdge, EdgeProps, getBezierPath } from 'reactflow'; 2 | import { LineageGraphEdge } from '../../utils/dbt'; 3 | import { COLOR_ADDED, COLOR_HIGHLIGHT, COLOR_REMOVED } from './style'; 4 | 5 | interface GraphEdgeProps extends EdgeProps { 6 | data?: LineageGraphEdge; 7 | } 8 | 9 | export default function GraphEdge(props: GraphEdgeProps) { 10 | const { 11 | sourceX, 12 | sourceY, 13 | targetX, 14 | targetY, 15 | sourcePosition, 16 | targetPosition, 17 | style: styleOverride = {}, 18 | markerEnd, 19 | data, 20 | } = props; 21 | 22 | const style = { 23 | ...styleOverride, 24 | }; 25 | 26 | style['storke'] = 'gray'; 27 | if (!data?.singleOnly) { 28 | if (!data?.from.includes('target')) { 29 | style['stroke'] = COLOR_REMOVED; 30 | style['strokeDasharray'] = '5'; 31 | } else if (!data?.from.includes('base')) { 32 | style['stroke'] = COLOR_ADDED; 33 | style['strokeDasharray'] = '5'; 34 | } 35 | } 36 | 37 | if (data?.isHighlighted) { 38 | style['stroke'] = COLOR_HIGHLIGHT; 39 | } 40 | 41 | const [edgePath] = getBezierPath({ 42 | sourceX, 43 | sourceY, 44 | sourcePosition, 45 | targetX, 46 | targetY, 47 | targetPosition, 48 | }); 49 | return ( 50 | <> 51 | 56 | 57 | ); 58 | } 59 | -------------------------------------------------------------------------------- /static_report/src/components/LineageGraph/GraphGroup.tsx: -------------------------------------------------------------------------------- 1 | import { Flex } from '@chakra-ui/react'; 2 | import { NodeProps } from 'reactflow'; 3 | import { COLOR_GROUP } from './style'; 4 | 5 | interface GraphGroupProps extends NodeProps { 6 | data: any; 7 | } 8 | 9 | export function GraphGroup({ data }: GraphGroupProps) { 10 | return ( 11 | <> 12 | 20 | 31 | 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /static_report/src/components/LineageGraph/style.ts: -------------------------------------------------------------------------------- 1 | export const COLOR_ADDED = '#1a7f37'; 2 | export const COLOR_REMOVED = '#cf222e'; 3 | export const COLOR_CHANGED = '#9a6700'; 4 | export const COLOR_NOPROFILED = 'gray'; 5 | export const COLOR_UNCHANGED = 'black'; 6 | export const COLOR_HIGHLIGHT = 'darkorange'; 7 | export const COLOR_GROUP = '#B3B3B340'; 8 | -------------------------------------------------------------------------------- /static_report/src/components/MasterSideNav/ColumnListAccordionPanel.tsx: -------------------------------------------------------------------------------- 1 | import { AccordionPanel, Box } from '@chakra-ui/react'; 2 | import { Comparable } from '../../types'; 3 | import { CompColEntryItem } from '../../utils'; 4 | import { ColumnDetailListItem } from './ColumnDetailListItem'; 5 | 6 | /** 7 | * ColumnItemList: Accordion UI Child Body 8 | */ 9 | interface ColumnListAccordionPanelProps extends Comparable { 10 | tableName: string; 11 | compColList?: CompColEntryItem[]; 12 | indexedTableName: string; 13 | } 14 | export function ColumnListAccordionPanel({ 15 | tableName, 16 | compColList = [], 17 | singleOnly, 18 | }: ColumnListAccordionPanelProps) { 19 | return ( 20 | 21 | 22 | {compColList.map(([colKey, { base, target }]) => { 23 | return ( 24 | 25 | {/* LIST - Columns */} 26 | 33 | 34 | ); 35 | })} 36 | 37 | 38 | ); 39 | } 40 | -------------------------------------------------------------------------------- /static_report/src/components/MasterSideNav/ColumnName.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | ColorProps, 3 | Flex, 4 | FlexProps, 5 | Icon, 6 | Text, 7 | Tooltip, 8 | } from '@chakra-ui/react'; 9 | import { NO_VALUE } from '../Columns'; 10 | 11 | interface Props { 12 | name?: string; 13 | icon: any; 14 | iconColor?: ColorProps['color']; 15 | } 16 | export function ColumnName({ 17 | name, 18 | icon, 19 | iconColor = 'piperider.500', 20 | ...props 21 | }: Props & FlexProps) { 22 | return ( 23 | 24 | 25 | 26 | 27 | {name || NO_VALUE} 28 | 29 | 30 | 31 | ); 32 | } 33 | -------------------------------------------------------------------------------- /static_report/src/components/MasterSideNav/RoutableAccordionButton.tsx: -------------------------------------------------------------------------------- 1 | import { AccordionButton, Text } from '@chakra-ui/react'; 2 | import { useLocation } from 'wouter'; 3 | 4 | /** 5 | * TableItem: Accordion UI parent 6 | */ 7 | interface RoutableAccordionButtonProps { 8 | path: string; 9 | title: string; 10 | } 11 | 12 | export function RoutableAccordionButton({ 13 | path, 14 | title, 15 | }: RoutableAccordionButtonProps) { 16 | const [location, setLocation] = useLocation(); 17 | const isActive = location === path; 18 | 19 | return ( 20 | { 27 | setLocation(path); 28 | }} 29 | > 30 | {title} 31 | 32 | ); 33 | } 34 | -------------------------------------------------------------------------------- /static_report/src/components/MasterSideNav/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ColumnDetailListItem'; 2 | export * from './MasterSideNav'; 3 | export * from './ColumnName'; 4 | -------------------------------------------------------------------------------- /static_report/src/components/Reports/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ReportContextBar'; 2 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableColumnHeader.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Heading, 3 | Flex, 4 | Icon, 5 | Box, 6 | Text, 7 | BoxProps, 8 | ColorProps, 9 | Tooltip, 10 | } from '@chakra-ui/react'; 11 | import { FiGrid, FiInfo } from 'react-icons/fi'; 12 | import { IconType } from 'react-icons/lib'; 13 | import { NO_VALUE } from '../Columns'; 14 | import { NO_DESCRIPTION_MSG } from '../Common/constant'; 15 | interface Props { 16 | title?: string; 17 | subtitle?: string; 18 | infoTip?: string; 19 | iconColor?: ColorProps['color']; 20 | icon?: IconType; 21 | } 22 | export function TableColumnHeader({ 23 | title = NO_VALUE, 24 | subtitle = NO_VALUE, 25 | infoTip = NO_DESCRIPTION_MSG, 26 | iconColor = 'piperider.500', 27 | icon = FiGrid, 28 | ...props 29 | }: Props & BoxProps) { 30 | return ( 31 | 32 | 33 | 34 | {title || NO_VALUE} 35 | 40 | 41 | 42 | 43 | {subtitle} 44 | 45 | ); 46 | } 47 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableList/ColumnBadge.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Text, Icon, ColorProps } from '@chakra-ui/react'; 2 | import { FiGrid } from 'react-icons/fi'; 3 | 4 | interface Props { 5 | name?: string; 6 | icon: any; 7 | iconColor?: ColorProps['color']; 8 | } 9 | export function ColumnBadge({ 10 | name, 11 | icon = FiGrid, 12 | iconColor = 'piperider.500', 13 | }: Props) { 14 | return ( 15 | 22 | 23 | 24 | {name} 25 | 26 | 27 | ); 28 | } 29 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableList/ColumnSchemaDeltaSummary.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, FlexProps, Text } from '@chakra-ui/react'; 2 | interface Props { 3 | added?: number; 4 | deleted?: number; 5 | changed?: number; 6 | } 7 | export function ColumnSchemaDeltaSummary({ 8 | added = 0, 9 | deleted = 0, 10 | changed = 0, 11 | ...props 12 | }: Props & FlexProps) { 13 | return ( 14 | 15 | ( Added: 16 | 17 | {added} 18 | 19 | Deleted: 20 | 21 | {deleted} 22 | 23 | Changed: 24 | 25 | {changed} 26 | 27 | ) 28 | 29 | ); 30 | } 31 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableList/ColumnSchemaTypeLabel.tsx: -------------------------------------------------------------------------------- 1 | import { Badge, Flex, FlexProps, Icon, Text, Tooltip } from '@chakra-ui/react'; 2 | import { FiArrowRight } from 'react-icons/fi'; 3 | import { ColumnSchema, Comparable } from '../../../types'; 4 | import { NO_VALUE } from '../../Columns'; 5 | 6 | interface Props extends Comparable { 7 | baseSchemaType?: ColumnSchema['schema_type']; 8 | targetSchemaType?: ColumnSchema['schema_type']; 9 | isAsymmetricCol?: boolean; 10 | } 11 | export function ColumnSchemaTypeLabel({ 12 | baseSchemaType, 13 | targetSchemaType, 14 | isAsymmetricCol, 15 | singleOnly, 16 | ...props 17 | }: Props & FlexProps) { 18 | const labelContent = ( 19 | 20 | {baseSchemaType || NO_VALUE} 21 | {!singleOnly && ( 22 | <> 23 | 24 | {targetSchemaType || NO_VALUE} 25 | 26 | )} 27 | 28 | ); 29 | return ( 30 | 31 | 36 | {labelContent} 37 | 38 | 39 | ); 40 | } 41 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableList/TableListAssertions.tsx: -------------------------------------------------------------------------------- 1 | import { Icon, Grid } from '@chakra-ui/react'; 2 | import { FiArrowRight } from 'react-icons/fi'; 3 | import { AssertionPassFailCountLabel } from '../../Assertions'; 4 | 5 | interface Props { 6 | baseAssertionTotal?: number | string; 7 | baseAssertionFailed?: number | string; 8 | targetAssertionTotal?: number | string; 9 | targetAssertionFailed?: number | string; 10 | } 11 | 12 | export function TableListAssertionSummary({ 13 | baseAssertionFailed, 14 | baseAssertionTotal, 15 | targetAssertionFailed, 16 | targetAssertionTotal, 17 | }: Props) { 18 | return ( 19 | 25 | 29 | 30 | 31 | 32 | 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableList/TableRowColDeltaSummary.tsx: -------------------------------------------------------------------------------- 1 | import { Flex, Text, Icon } from '@chakra-ui/react'; 2 | import { FiArrowRight } from 'react-icons/fi'; 3 | import { NO_VALUE } from '../../Columns'; 4 | 5 | interface Props { 6 | baseCount?: number; 7 | targetCount?: number; 8 | } 9 | export function TableRowColDeltaSummary({ baseCount, targetCount }: Props) { 10 | if (baseCount === targetCount) { 11 | return ( 12 | 13 | {baseCount ?? NO_VALUE} 14 | 15 | {targetCount ?? NO_VALUE} 16 | 17 | ); 18 | } 19 | 20 | return ( 21 | 22 | {baseCount ?? NO_VALUE} 23 | 24 | 25 | {targetCount ?? NO_VALUE} 26 | 27 | 28 | ); 29 | } 30 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableList/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ColumnBadge'; 2 | export * from '../../MasterSideNav/ColumnName'; 3 | export * from './TableColumnSchemaList'; 4 | export * from './TableListAssertions'; 5 | export * from './TableListItem'; 6 | export * from './TableRowColDeltaSummary'; 7 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableMetrics/DupedTableRowStats.tsx: -------------------------------------------------------------------------------- 1 | import { BoxProps } from '@chakra-ui/react'; 2 | import { SaferTableSchema } from '../../../types'; 3 | import { MetricsInfo } from '../../Columns/ColumnMetrics/MetricsInfo'; 4 | import { TableMetakeyList, transformSRTableMetricsInfoList } from '../utils'; 5 | 6 | interface Props { 7 | tableDatum?: SaferTableSchema; 8 | } 9 | export function DupedTableRowStats({ tableDatum, ...props }: Props & BoxProps) { 10 | const metakeyEntries: TableMetakeyList = [ 11 | [tableDatum?.samples ? 'samples' : 'row_count', 'Total'], 12 | ['duplicate_rows', 'Duplicates'], 13 | ]; 14 | const metricsList = transformSRTableMetricsInfoList( 15 | metakeyEntries, 16 | tableDatum, 17 | ); 18 | 19 | /* Others - (1): % + n (2): % + % */ 20 | return ( 21 | <> 22 | {metricsList.map( 23 | ({ firstSlot, secondSlot, metakey, name, tooltipValues }, index) => ( 24 | 34 | ), 35 | )} 36 | 37 | ); 38 | } 39 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableMetrics/index.ts: -------------------------------------------------------------------------------- 1 | export * from './DupedTableRowStats'; 2 | export * from './TableGeneralStats'; 3 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/TableOverview.tsx: -------------------------------------------------------------------------------- 1 | import { Grid, GridItem, BoxProps } from '@chakra-ui/react'; 2 | 3 | import { SaferTableSchema } from '../../types'; 4 | import { DupedTableRowsWidget } from '../Widgets/DupedTableRowsWidget'; 5 | import { TableGeneralStats } from './TableMetrics/TableGeneralStats'; 6 | 7 | interface Props { 8 | tableDatum?: SaferTableSchema; 9 | } 10 | 11 | export function TableOverview({ tableDatum, ...props }: Props & BoxProps) { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ); 22 | } 23 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/constant.ts: -------------------------------------------------------------------------------- 1 | export const SAMPLE = 'Total Sample Size'; 2 | export const DUPLICATE_ROWS = 'Duplicate Rows'; 3 | export const NO_ASSERTIONS = 'No Assertions'; 4 | -------------------------------------------------------------------------------- /static_report/src/components/Tables/index.ts: -------------------------------------------------------------------------------- 1 | export * from './TableColumnHeader'; 2 | export * from './TableList'; 3 | export * from './TableMetrics'; 4 | export * from './TableOverview'; 5 | export * from './utils'; 6 | -------------------------------------------------------------------------------- /static_report/src/components/Widgets/ChangeStatusWidget.tsx: -------------------------------------------------------------------------------- 1 | import { Text, Flex, Icon, Box } from '@chakra-ui/react'; 2 | import { ChangeStatus } from '../../lib'; 3 | import { getIconForChangeStatus } from '../Icons'; 4 | 5 | type Props = { 6 | added?: number; 7 | removed?: number; 8 | modified?: number; 9 | }; 10 | 11 | function ChangeStatusOne({ 12 | value, 13 | changeStatus, 14 | }: { 15 | value?: number; 16 | changeStatus: ChangeStatus; 17 | }) { 18 | const { icon, color } = getIconForChangeStatus(changeStatus); 19 | 20 | return ( 21 | <> 22 | {value} 23 | 24 | ); 25 | } 26 | 27 | export function ChangeStatusWidget({ added, removed, modified }: Props) { 28 | const items: any[] = []; 29 | let first = true; 30 | 31 | if (added) { 32 | items.push(first ? <>( : ,); 33 | items.push(); 34 | first = false; 35 | } 36 | if (removed) { 37 | items.push(first ? <>( : ,); 38 | items.push(); 39 | first = false; 40 | } 41 | if (modified) { 42 | items.push(first ? <>( : ,); 43 | items.push(); 44 | first = false; 45 | } 46 | if (!first) { 47 | items.push(<>{')'}); 48 | } 49 | 50 | return ( 51 | 52 | 53 | {items} 54 | 55 | 56 | ); 57 | } 58 | -------------------------------------------------------------------------------- /static_report/src/components/Widgets/DataCompositionWidget.tsx: -------------------------------------------------------------------------------- 1 | import { Box, Flex } from '@chakra-ui/react'; 2 | import { ColumnSchema } from '../../sdlc/single-report-schema'; 3 | import { renderChartUnavailableMsg } from '../Charts/utils'; 4 | import { FlatStackedBarChart } from '../Charts/FlatStackedBarChart'; 5 | import { GeneralStats } from '../Columns/ColumnMetrics/GeneralStats'; 6 | import { TypedStats } from '../Columns/ColumnMetrics/TypedStats'; 7 | import { transformCompositionAsFlatStackInput } from '../Columns/utils'; 8 | 9 | interface Props { 10 | hasAnimation?: boolean; 11 | columnDatum?: ColumnSchema; 12 | } 13 | export function DataCompositionWidget({ columnDatum, hasAnimation }: Props) { 14 | const dataCompInput = transformCompositionAsFlatStackInput(columnDatum); 15 | 16 | const animationOptions = hasAnimation ? {} : false; 17 | 18 | return ( 19 | 20 | 21 | {dataCompInput ? ( 22 | 26 | ) : ( 27 | renderChartUnavailableMsg({}) 28 | )} 29 | 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /static_report/src/components/Widgets/DataSummaryWidget.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import { ColumnSchema } from '../../sdlc/single-report-schema'; 3 | import { renderChartUnavailableMsg } from '../Charts/utils'; 4 | import { SummaryStats } from '../Columns/ColumnMetrics/SummaryStats'; 5 | 6 | interface Props { 7 | columnDatum?: ColumnSchema; 8 | } 9 | /** 10 | * A widget that displays a block of metrics related to avg, stddev, etc 11 | * Will render empty-state when columnDatum is falsey 12 | */ 13 | export function DataSummaryWidget({ columnDatum }: Props) { 14 | return ( 15 | 16 | {columnDatum ? ( 17 | 18 | ) : ( 19 | renderChartUnavailableMsg({}) 20 | )} 21 | 22 | ); 23 | } 24 | -------------------------------------------------------------------------------- /static_report/src/components/Widgets/QuantilesWidget.tsx: -------------------------------------------------------------------------------- 1 | import { Box } from '@chakra-ui/react'; 2 | import { ColumnSchema } from '../../sdlc/single-report-schema'; 3 | import { renderChartUnavailableMsg } from '../Charts/utils'; 4 | import { FlatBoxPlotChart } from '../Charts/FlatBoxPlotChart'; 5 | import { QuantilesMatrix } from '../Columns/ColumnMetrics/QuantilesMatrix'; 6 | 7 | interface Props { 8 | columnDatum?: ColumnSchema; 9 | } 10 | export function QuantilesWidget({ columnDatum }: Props) { 11 | const { p50, max, min, p25, p75 } = columnDatum || {}; 12 | return ( 13 | 14 | {columnDatum ? ( 15 | <> 16 | 17 | 26 | 27 | 28 | 29 | ) : ( 30 | renderChartUnavailableMsg({}) 31 | )} 32 | 33 | ); 34 | } 35 | -------------------------------------------------------------------------------- /static_report/src/components/Widgets/index.ts: -------------------------------------------------------------------------------- 1 | export * from './AssertionListWidget'; 2 | export * from './ChartTabsWidget'; 3 | export * from './DataCompositionWidget'; 4 | export * from './DataSummaryWidget'; 5 | export * from './DupedTableRowsWidget'; 6 | export * from './QuantilesWidget'; 7 | -------------------------------------------------------------------------------- /static_report/src/components/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Assertions'; 2 | export * from './Charts'; 3 | export * from './Columns'; 4 | export * from './Common'; 5 | export * from './Reports'; 6 | export * from './Tables'; 7 | export * from './Widgets'; 8 | -------------------------------------------------------------------------------- /static_report/src/hooks/index.ts: -------------------------------------------------------------------------------- 1 | export * from './useTrackOnMount'; 2 | export * from './useDocumentTitle'; 3 | export * from './useHashLcocation'; 4 | -------------------------------------------------------------------------------- /static_report/src/hooks/useDocumentTitle.ts: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react'; 2 | 3 | export function useDocumentTitle(value = null) { 4 | const [title, setTitle] = useState(value); 5 | 6 | useEffect(() => { 7 | document.title = title ? `${title} | PipeRider` : 'PipeRider'; 8 | }, [title]); 9 | 10 | return [title, setTitle]; 11 | } 12 | -------------------------------------------------------------------------------- /static_report/src/hooks/useHashLcocation.ts: -------------------------------------------------------------------------------- 1 | import { useState, useEffect, useCallback } from 'react'; 2 | 3 | function getWindow(): Window | undefined { 4 | if (typeof window === 'undefined') { 5 | return undefined; 6 | } 7 | 8 | return window; 9 | } 10 | 11 | function useHash(defaultValue?: string): [string, (string) => void] { 12 | const _window = getWindow(); 13 | const [hash, setHash] = useState(defaultValue ?? ''); 14 | 15 | useEffect(() => { 16 | if (!_window) { 17 | return; 18 | } 19 | 20 | setHash(_window!.location.hash); 21 | const handler = () => setHash(_window!.location.hash); 22 | _window.addEventListener('hashchange', handler); 23 | 24 | return () => window.removeEventListener('hashchange', handler); 25 | }, [_window]); 26 | 27 | const navigate = useCallback( 28 | (to) => { 29 | _window!.location.hash = to; 30 | }, 31 | [_window], 32 | ); 33 | 34 | return [hash, navigate]; 35 | } 36 | 37 | // This is used by wouter Router 38 | // 39 | export function useHashLocation() { 40 | const [hash, setHash] = useHash('#/ssr'); 41 | 42 | // replace '#/path/to/resource?foo=bar' with '/path/to/resource' 43 | let location = hash.replace(/^#/, '') || '/'; 44 | if (location.includes('?')) { 45 | location = location.split('?')[0]; 46 | } 47 | 48 | return [location, setHash]; 49 | } 50 | 51 | export function useHashParams() { 52 | const [hash] = useHash(); 53 | 54 | if (hash.includes('?')) { 55 | const [, search] = hash.split('?'); 56 | return new URLSearchParams(search); 57 | } else { 58 | return new URLSearchParams(''); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /static_report/src/hooks/useTrackOnMount.ts: -------------------------------------------------------------------------------- 1 | import { useEffect } from 'react'; 2 | 3 | import { TrackEvent, useTrackerStore } from '../utils/trackEvents'; 4 | 5 | export function useTrackOnMount(event: TrackEvent) { 6 | const tracker = useTrackerStore((state) => state.tracker); 7 | useEffect(() => { 8 | if (tracker) { 9 | tracker.track({ ...event }); 10 | } 11 | // eslint-disable-next-line react-hooks/exhaustive-deps 12 | }, []); 13 | } 14 | -------------------------------------------------------------------------------- /static_report/src/index.tsx: -------------------------------------------------------------------------------- 1 | import { ChakraProvider } from '@chakra-ui/react'; 2 | import { StrictMode } from 'react'; 3 | import { createRoot } from 'react-dom/client'; 4 | import App from './App'; 5 | import 'inter-ui/inter-latin.css'; 6 | import theme from './utils/theme'; 7 | import reportWebVitals from './utils/reportWebVitals'; 8 | 9 | const rootElement = document.getElementById('root') as HTMLElement; 10 | const root = createRoot(rootElement); 11 | 12 | root.render( 13 | 14 | 15 | 16 | 17 | , 18 | ); 19 | 20 | // If you want to start measuring performance in your app, pass a function 21 | // to log results (for example: reportWebVitals(console.log)) 22 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 23 | reportWebVitals(); 24 | -------------------------------------------------------------------------------- /static_report/src/lib/index.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Main Entry File for UI Library 3 | */ 4 | export * from '../components'; 5 | export * from '../hooks'; 6 | export * from '../types'; 7 | export * from '../sdlc'; 8 | export * from '../utils'; 9 | -------------------------------------------------------------------------------- /static_report/src/pages/CROverviewPage.tsx: -------------------------------------------------------------------------------- 1 | import { useTrackOnMount } from '../hooks'; 2 | import { EVENTS, CR_TYPE_LABEL } from '../utils/trackEvents'; 3 | import { Overview } from '../components/Overview/Overview'; 4 | import { CRTablesListPage } from './CRTableListPage'; 5 | import { useReportStore } from '../utils/store'; 6 | 7 | export function CROverviewPage() { 8 | useTrackOnMount({ 9 | eventName: EVENTS.PAGE_VIEW, 10 | eventProperties: { 11 | type: CR_TYPE_LABEL, 12 | page: 'overview_page', 13 | }, 14 | }); 15 | 16 | const { isLegacy } = useReportStore.getState(); 17 | 18 | return isLegacy ? : ; 19 | } 20 | -------------------------------------------------------------------------------- /static_report/src/pages/CRSemanticModelPage.tsx: -------------------------------------------------------------------------------- 1 | import { useRoute } from 'wouter'; 2 | import { getIconForResourceType } from '../components/Icons'; 3 | import { 4 | EVENTS, 5 | NoData, 6 | SR_TYPE_LABEL, 7 | TableColumnHeader, 8 | useReportStore, 9 | useTrackOnMount, 10 | } from '../lib'; 11 | import { SEMANTIC_MODEL_DETAILS_ROUTE_PATH } from '../utils/routes'; 12 | 13 | export function CRSemanticModelPage() { 14 | const [match, params] = useRoute(SEMANTIC_MODEL_DETAILS_ROUTE_PATH); 15 | 16 | useTrackOnMount({ 17 | eventName: EVENTS.PAGE_VIEW, 18 | eventProperties: { 19 | type: SR_TYPE_LABEL, 20 | page: 'resource-page', 21 | }, 22 | }); 23 | 24 | if (!match) { 25 | return <>Something wrong.; 26 | } 27 | 28 | const { tableColumnsOnly = [] } = useReportStore.getState(); 29 | const entry = tableColumnsOnly.find(([key]) => key === params?.uniqueId); 30 | if (!entry) { 31 | return ; 32 | } 33 | 34 | const [, { base, target }] = entry; 35 | const fallback = target ?? base; 36 | 37 | const name = fallback?.name; 38 | const description = fallback?.description; 39 | const resourceType = fallback?.resource_type; 40 | const { icon } = getIconForResourceType(resourceType); 41 | 42 | return ( 43 | <> 44 | 50 | 51 | ); 52 | } 53 | -------------------------------------------------------------------------------- /static_report/src/pages/SROverviewPage.tsx: -------------------------------------------------------------------------------- 1 | import { useTrackOnMount } from '../hooks'; 2 | import { EVENTS, SR_TYPE_LABEL } from '../utils/trackEvents'; 3 | import { Overview } from '../components/Overview/Overview'; 4 | import { useReportStore } from '../utils/store'; 5 | import { SRTablesListPage } from './SRTablesListPage'; 6 | 7 | export function SROverviewPage() { 8 | useTrackOnMount({ 9 | eventName: EVENTS.PAGE_VIEW, 10 | eventProperties: { 11 | type: SR_TYPE_LABEL, 12 | page: 'overview_page', 13 | }, 14 | }); 15 | 16 | const { isLegacy } = useReportStore.getState(); 17 | 18 | return isLegacy ? : ; 19 | } 20 | -------------------------------------------------------------------------------- /static_report/src/pages/SRSemanticModelPage.tsx: -------------------------------------------------------------------------------- 1 | import { useRoute } from 'wouter'; 2 | import { getIconForResourceType } from '../components/Icons'; 3 | import { 4 | EVENTS, 5 | NoData, 6 | SR_TYPE_LABEL, 7 | TableColumnHeader, 8 | useReportStore, 9 | useTrackOnMount, 10 | } from '../lib'; 11 | import { SEMANTIC_MODEL_DETAILS_ROUTE_PATH } from '../utils/routes'; 12 | 13 | export function SRSemanticModelPage() { 14 | const [match, params] = useRoute(SEMANTIC_MODEL_DETAILS_ROUTE_PATH); 15 | 16 | useTrackOnMount({ 17 | eventName: EVENTS.PAGE_VIEW, 18 | eventProperties: { 19 | type: SR_TYPE_LABEL, 20 | page: 'resource-page', 21 | }, 22 | }); 23 | 24 | if (!match) { 25 | return <>Something wrong.; 26 | } 27 | 28 | const { tableColumnsOnly = [] } = useReportStore.getState(); 29 | const entry = tableColumnsOnly.find(([key]) => key === params?.uniqueId); 30 | if (!entry) { 31 | return ; 32 | } 33 | 34 | const [, { base: data }] = entry; 35 | 36 | const name = data?.name; 37 | const description = data?.description; 38 | const resourceType = data?.resource_type; 39 | const { icon } = getIconForResourceType(resourceType); 40 | 41 | return ( 42 | <> 43 | 49 | 50 | ); 51 | } 52 | -------------------------------------------------------------------------------- /static_report/src/pages/index.ts: -------------------------------------------------------------------------------- 1 | export * from './SRPage'; 2 | export * from './CRPage'; 3 | -------------------------------------------------------------------------------- /static_report/src/sdlc/check-report-data.js: -------------------------------------------------------------------------------- 1 | import { existsSync, copyFileSync } from 'fs'; 2 | import { 3 | isE2E, 4 | FILENAME_SINGLE, 5 | FILENAME_COMPARISON, 6 | PATH_TO_SINGLE_REPORT_DATA_JSON, 7 | getComparisonDataPath, 8 | } from './core.js'; 9 | 10 | const checkSingleReportData = async () => { 11 | if (existsSync(FILENAME_SINGLE)) { 12 | console.log(`Found ${FILENAME_SINGLE} in current directory`); 13 | return true; 14 | } 15 | 16 | try { 17 | // Copy single report data from .piperider 18 | if (existsSync(PATH_TO_SINGLE_REPORT_DATA_JSON)) { 19 | copyFileSync(PATH_TO_SINGLE_REPORT_DATA_JSON, FILENAME_SINGLE); 20 | return true; 21 | } 22 | } catch (error) {} 23 | 24 | console.error( 25 | `No ${FILENAME_SINGLE} found in current directory or .piperider`, 26 | ); 27 | return false; 28 | }; 29 | 30 | const checkComparisonReportData = async () => { 31 | if (existsSync(FILENAME_COMPARISON)) { 32 | console.log(`Found ${FILENAME_COMPARISON} in current directory`); 33 | return true; 34 | } 35 | 36 | // Copy comparison report data from .piperider 37 | try { 38 | const PATH_TO_COMPARISON_REPORT_DATA_JSON = await getComparisonDataPath( 39 | isE2E, 40 | ); 41 | if (existsSync(PATH_TO_COMPARISON_REPORT_DATA_JSON)) { 42 | copyFileSync(PATH_TO_COMPARISON_REPORT_DATA_JSON, FILENAME_COMPARISON); 43 | return true; 44 | } 45 | } catch (error) {} 46 | 47 | console.error( 48 | `No ${FILENAME_COMPARISON} found in current directory or .piperider`, 49 | ); 50 | return false; 51 | }; 52 | 53 | const checkReportData = async () => { 54 | await checkSingleReportData(); 55 | await checkComparisonReportData(); 56 | }; 57 | 58 | checkReportData(); 59 | -------------------------------------------------------------------------------- /static_report/src/sdlc/clean-window-data.js: -------------------------------------------------------------------------------- 1 | import { generateFile, getEmbeddedIndexHTML, PATH_TO_INDEX } from './core.js'; 2 | 3 | const cleanWindowData = async () => { 4 | const cleanHtml = await getEmbeddedIndexHTML(new Map()); 5 | await generateFile(PATH_TO_INDEX, cleanHtml.toString()); 6 | }; 7 | 8 | cleanWindowData(); 9 | -------------------------------------------------------------------------------- /static_report/src/sdlc/extract-schema-metadata.js: -------------------------------------------------------------------------------- 1 | import { getSchemaDescriptions } from './core.js'; 2 | 3 | const extractSchemaColumnDescriptions = async () => { 4 | getSchemaDescriptions(); 5 | }; 6 | 7 | extractSchemaColumnDescriptions(); 8 | -------------------------------------------------------------------------------- /static_report/src/sdlc/generate-e2e-data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # For generating comparison_data.json from `piperider-getting-started` 3 | # NOTE: This file assumes you are calling from the root of repo 4 | # NOTE: Pass parameters to shell call e.g. $1 5 | if [ $2 = "clean" ]; then 6 | rm -rf piperider-getting-started 7 | fi 8 | 9 | # First 2 run.jsons 10 | if [ $1 = "first" ]; then 11 | echo "initializing...$1" 12 | 13 | git clone https://github.com/InfuseAI/piperider-getting-started.git 14 | cd piperider-getting-started 15 | 16 | # Fetch data sqlite - First run.json #1 17 | curl -o data/sp500.db https://piperider-data.s3.ap-northeast-1.amazonaws.com/getting-started/sp500_20220401.db 18 | 19 | piperider run --debug #first run 20 | 21 | # Fetch data sqlite - Second run.json #2 22 | curl -o data/sp500.db https://piperider-data.s3.ap-northeast-1.amazonaws.com/getting-started/sp500_20220527.db 23 | 24 | piperider run --debug #second run 25 | fi 26 | 27 | # edge-cases (another run.json) 28 | if [ "$1" = "second" ]; then 29 | cd piperider-getting-started 30 | echo "initializing...$1" 31 | # Fetch data sqlite - Third run.json #3 (diff table) 32 | curl -o data/sp500.db https://piperider-data.s3.ap-northeast-1.amazonaws.com/integration-test-sqlite/profiler-e2e.db 33 | 34 | piperider run --debug # third run 35 | fi 36 | 37 | # Gather single run base/target refs for comparison-report 38 | E2E_SR_REPORTS="./.piperider/outputs/*" 39 | ARR_PATHS=() 40 | for FILE_PATH in $E2E_SR_REPORTS; do 41 | ARR_PATHS+=($FILE_PATH) 42 | done 43 | # generate comparison report (base: latest, target: previous ) 44 | piperider compare-reports --base ${ARR_PATHS[0]}/run.json --target ${ARR_PATHS[1]}/run.json --debug 45 | 46 | cd .. 47 | -------------------------------------------------------------------------------- /static_report/src/sdlc/global.d.ts: -------------------------------------------------------------------------------- 1 | import { ComparisonReportSchema } from 'comparison-report-schema.d'; 2 | import { SingleReportSchema } from 'single-report-schema.d'; 3 | 4 | declare global { 5 | interface PipeRiderMetadata { 6 | name: string; 7 | sentry_dns: string; 8 | sentry_env: string; 9 | version: string; 10 | amplitude_api_key: string; 11 | amplitude_user_id: string; 12 | amplitude_project_id: string; 13 | } 14 | interface Window { 15 | PIPERIDER_SINGLE_REPORT_DATA: SingleReportSchema; 16 | PIPERIDER_COMPARISON_REPORT_DATA: ComparisonReportSchema; 17 | PIPERIDER_METADATA: PipeRiderMetadata; 18 | } 19 | namespace NodeJS { 20 | interface ProcessEnv { 21 | REACT_APP_SINGLE_REPORT: string; 22 | } 23 | } 24 | } 25 | export {}; 26 | -------------------------------------------------------------------------------- /static_report/src/sdlc/index.ts: -------------------------------------------------------------------------------- 1 | export * from './schema-meta'; 2 | export * from './single-report-schema.z'; 3 | export * from './single-report-schema'; 4 | -------------------------------------------------------------------------------- /static_report/src/utils/cloud.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext, useContext } from 'react'; 2 | 3 | const CloudReportContext = createContext(false); 4 | 5 | interface Props { 6 | cloud: boolean; 7 | children: React.ReactNode; 8 | } 9 | export const CloudReportProvider = ({ cloud, children }: Props) => { 10 | return ( 11 | 12 | {children} 13 | 14 | ); 15 | }; 16 | 17 | export function useCloudReport() { 18 | return useContext(CloudReportContext); 19 | } 20 | -------------------------------------------------------------------------------- /static_report/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './trackEvents'; 2 | export * from './localStorageKeys'; 3 | export * from './formatters'; 4 | export * from './store'; 5 | export * from './theme'; 6 | export * from './layout'; 7 | -------------------------------------------------------------------------------- /static_report/src/utils/layout.ts: -------------------------------------------------------------------------------- 1 | export const topNavAndFooterHeightOffset = 130; 2 | export const topProjectNavHeightOffset = 130; 3 | export const mainContentAreaHeight = `100%`; 4 | export const mainContentAreaHeightWithProjectNav = `100%`; 5 | export const tableListGridTempCols = '2fr 1fr 1.5fr'; 6 | export const tableListWidth = 1150; 7 | export const tableListMaxWidth = `calc(${tableListWidth}px - 30px)`; 8 | export const assertionListWidth = 1280; 9 | export const borderVal = '1px solid lightgray'; 10 | -------------------------------------------------------------------------------- /static_report/src/utils/localStorageKeys.ts: -------------------------------------------------------------------------------- 1 | export const SR_LIST_VIEW = 'ppr-sr-list-view'; 2 | export const CR_LIST_VIEW = 'ppr-cr-list-view'; 3 | export const MASTER_LIST_DISPLAY_MODE = 'ppr-master-list-display-mode'; 4 | export const MASTER_LIST_SHOW_EXTRA = 'ppr-master-list-show-extra'; 5 | -------------------------------------------------------------------------------- /static_report/src/utils/mergeKeys.ts: -------------------------------------------------------------------------------- 1 | export function mergeKeys(_base: string[], _target: string[]) { 2 | // Merge keys from base, target tables. Unlike default union, it preserves the order for column rename, added, removed. 3 | const base = [..._base]; 4 | const target = [..._target]; 5 | 6 | const results: string[] = []; 7 | while (base.length > 0 && target.length > 0) { 8 | if (results.includes(base[0])) { 9 | base.shift(); 10 | } else if (results.includes(target[0])) { 11 | target.shift(); 12 | } else if (base[0] === target[0]) { 13 | results.push(base[0]); 14 | base.shift(); 15 | target.shift(); 16 | } else if (target.includes(base[0])) { 17 | const idx = target.indexOf(base[0]); 18 | for (let i = 0; i < idx; i++) { 19 | if (!results.includes(target[i])) { 20 | results.push(target[i]); 21 | } 22 | } 23 | results.push(base[0]); 24 | base.shift(); 25 | target.splice(0, idx + 1); 26 | } else { 27 | results.push(base[0]); 28 | base.shift(); 29 | } 30 | } 31 | 32 | base.forEach((key) => { 33 | if (!results.includes(key)) { 34 | results.push(key); 35 | } 36 | }); 37 | 38 | target.forEach((key) => { 39 | if (!results.includes(key)) { 40 | results.push(key); 41 | } 42 | }); 43 | 44 | return results; 45 | } 46 | -------------------------------------------------------------------------------- /static_report/src/utils/reportWebVitals.tsx: -------------------------------------------------------------------------------- 1 | const reportWebVitals = (onPerfEntry = () => {}) => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /static_report/src/utils/trackEvents.ts: -------------------------------------------------------------------------------- 1 | import { track } from '@amplitude/analytics-browser'; 2 | import type { EventOptions } from '@amplitude/analytics-types'; 3 | import create from 'zustand'; 4 | 5 | export const SR_TYPE_LABEL = 'single-report'; 6 | export const CR_TYPE_LABEL = 'comparison-report'; 7 | export const WARNING_TYPE_LABEL = 'mobile-device-warning'; 8 | export const EVENTS = { 9 | PAGE_VIEW: 'Page View', 10 | }; 11 | 12 | export type TrackEvent = { 13 | eventName: string; 14 | eventProperties?: Record; 15 | eventOptions?: EventOptions; 16 | }; 17 | 18 | export interface Tracker { 19 | track: (TrackEvent) => void; 20 | } 21 | 22 | interface TrackerState { 23 | tracker?: Tracker; 24 | setTracker: (tracker: Tracker) => void; 25 | } 26 | 27 | export const useTrackerStore = create((set) => ({ 28 | tracker: undefined, 29 | setTracker: (tracker) => set({ tracker: tracker }), 30 | })); 31 | 32 | export function amplitudeTrack({ 33 | eventName, 34 | eventProperties = {}, 35 | eventOptions = {}, 36 | }: TrackEvent) { 37 | const PROJECT_ID = window.PIPERIDER_METADATA.amplitude_project_id; 38 | const API_KEY = window.PIPERIDER_METADATA.amplitude_api_key; 39 | 40 | if ( 41 | !API_KEY || 42 | process.env.NODE_ENV === 'development' || 43 | process.env.REACT_APP_E2E === 'true' 44 | ) { 45 | return console.warn( 46 | eventName, 47 | { project_id: PROJECT_ID, ...eventProperties }, 48 | eventOptions, 49 | ); 50 | } 51 | 52 | track( 53 | eventName, 54 | { 55 | project_id: PROJECT_ID, 56 | ...eventProperties, 57 | }, 58 | eventOptions, 59 | ); 60 | } 61 | -------------------------------------------------------------------------------- /static_report/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "dom", 5 | "dom.iterable", 6 | "esnext" 7 | ], 8 | "module": "esnext", 9 | "target": "es6", 10 | "allowJs": true, 11 | "allowSyntheticDefaultImports": true, 12 | "declaration": true, 13 | "declarationDir": "types", 14 | "esModuleInterop": true, 15 | "emitDeclarationOnly": true, //Don't generate JS (rollup will do that) only export type declarations 16 | "forceConsistentCasingInFileNames": true, 17 | "isolatedModules": true, 18 | "jsx": "react-jsx", 19 | "moduleResolution": "node", 20 | "noImplicitAny": false, 21 | "noFallthroughCasesInSwitch": true, 22 | "outDir": "dist", 23 | "resolveJsonModule": true, 24 | "skipLibCheck": true, 25 | "sourceMap": true, 26 | "strict": true 27 | }, 28 | "exclude": [ 29 | "node_modules", 30 | "dist", 31 | "build", 32 | "cypress", 33 | "cypress.config.ts" 34 | ] 35 | } -------------------------------------------------------------------------------- /tests/common.py: -------------------------------------------------------------------------------- 1 | from datetime import date, datetime 2 | from sqlalchemy import * 3 | from typing import List 4 | 5 | from sqlalchemy.engine import Engine 6 | 7 | 8 | def create_table(engine: Engine, table_name: str, data: List[tuple], columns=None, metadata=None): 9 | header = data[0] 10 | data = data[1:] 11 | 12 | if not metadata: 13 | metadata = MetaData() 14 | 15 | if not columns: 16 | columns = [] 17 | if len(data) == 0: 18 | raise Exception("columns is not specified and data is empty") 19 | first = data[0] 20 | for i in range(len(header)): 21 | col_name = header[i] 22 | value = first[i] 23 | col = None 24 | if isinstance(value, str): 25 | col = Column(col_name, String) 26 | elif isinstance(value, float): 27 | col = Column(col_name, Float) 28 | elif isinstance(value, int): 29 | col = Column(col_name, Integer) 30 | elif isinstance(value, datetime): 31 | col = Column(col_name, DateTime) 32 | elif isinstance(value, date): 33 | col = Column(col_name, Date) 34 | else: 35 | raise Exception(f"not support type: {type(value)}") 36 | columns.append(col) 37 | table = Table(table_name, metadata, *columns) 38 | table.create(bind=engine) 39 | 40 | with engine.connect() as conn: 41 | for row in data: 42 | row_data = dict(zip(header, row)) 43 | stmt = ( 44 | insert(table). 45 | values(**row_data) 46 | ) 47 | conn.execute(stmt) 48 | 49 | return table 50 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | 4 | import pytest 5 | 6 | 7 | def load_mock_dbt_data(file_name): 8 | file_path = os.path.join(os.path.dirname(__file__), 'mock_dbt_data', file_name) 9 | with open(file_path, 'r') as file: 10 | content = file.read() 11 | return json.loads(content) 12 | 13 | 14 | @pytest.fixture() 15 | def sc_31711_run_data(): 16 | return load_mock_dbt_data('sc-31711-run-dbt-1.5.4-no-profiled.json') 17 | 18 | 19 | @pytest.fixture() 20 | def piperider_schema_validate_func(): 21 | import piperider_cli.profiler as p 22 | from jsonschema import validate 23 | 24 | schema_def = os.path.join(os.path.dirname(p.__file__), 'schema.json') 25 | with open(schema_def) as fh: 26 | schema = json.loads(fh.read()) 27 | 28 | def func(data): 29 | from jsonschema.exceptions import ValidationError 30 | try: 31 | validate(instance=data, schema=schema) 32 | except ValidationError as e: 33 | print(f"error: {e.message}") 34 | print(f"path: {e.json_path}") 35 | assert False 36 | 37 | return func 38 | -------------------------------------------------------------------------------- /tests/datasource/test_datasource.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase, mock 2 | 3 | from piperider_cli.datasource import DataSource, _should_use_fancy_user_input 4 | 5 | 6 | class TestAbstractDataSource(TestCase): 7 | def test_abstract_datasource(self): 8 | with self.assertRaises(TypeError): 9 | DataSource('fake data source', 'fake type') 10 | 11 | 12 | class TestUseFancyUserInput(TestCase): 13 | @mock.patch.dict('os.environ', {'PIPERIDER_FANCY_USER_INPUT': 'FALSE'}, clear=True) 14 | def test_env_set_to_false(self, *args): 15 | self.assertFalse(_should_use_fancy_user_input()) 16 | 17 | @mock.patch('sys.stdin.isatty', return_value=False) 18 | @mock.patch('sys.stdout.isatty', return_value=False) 19 | def test_not_running_by_terminal(self, *args): 20 | self.assertFalse(_should_use_fancy_user_input()) 21 | 22 | @mock.patch('sys.platform', 'darwin') 23 | @mock.patch('sys.stdin.isatty', return_value=True) 24 | @mock.patch('sys.stdout.isatty', return_value=True) 25 | def test_running_on_windows(self, *args): 26 | with mock.patch('sys.platform', 'win32'): 27 | self.assertFalse(_should_use_fancy_user_input()) 28 | 29 | @mock.patch('sys.platform', 'darwin') 30 | @mock.patch('sys.stdin.isatty', return_value=True) 31 | @mock.patch('sys.stdout.isatty', return_value=True) 32 | @mock.patch.dict('os.environ', {}, clear=True) 33 | def test_default_behavior(self, *args): 34 | self.assertTrue(_should_use_fancy_user_input()) 35 | -------------------------------------------------------------------------------- /tests/datasource/test_duckdb.py: -------------------------------------------------------------------------------- 1 | from unittest import TestCase, mock 2 | 3 | from piperider_cli.datasource import DATASOURCE_PROVIDERS 4 | 5 | 6 | class TestDuckDBDataSource(TestCase): 7 | def setUp(self) -> None: 8 | self.datasource_cls = DATASOURCE_PROVIDERS['duckdb'] 9 | self.mock_dbt = { 10 | 'projectDir': '.', 11 | 'tag': 'piperider', 12 | } 13 | self.mock_credentials = { 14 | 'type': 'duckdb', 15 | 'path': '/mock_data/duckdb.db' 16 | } 17 | 18 | def test_duckdb(self): 19 | ds = self.datasource_cls('unittest') 20 | self.assertEqual('unittest', ds.name) 21 | self.assertEqual('duckdb', ds.type_name) 22 | self.assertEqual('config', ds.credential_source) 23 | self.assertTrue(ds.validate()) 24 | 25 | def test_duckdb_validate_method(self): 26 | ds = self.datasource_cls('unittest', dbt=self.mock_dbt, credential=self.mock_credentials) 27 | rc, reason = ds.validate() 28 | self.assertTrue(rc) 29 | 30 | @mock.patch('os.path.exists', return_value=True) 31 | def test_duckdb_to_database_url_method(self, *args): 32 | ds = self.datasource_cls('unittest', dbt=self.mock_dbt, credential=self.mock_credentials) 33 | url = ds.to_database_url(None) 34 | self.assertEqual(url, f'duckdb:///{self.mock_credentials.get("path")}') 35 | -------------------------------------------------------------------------------- /tests/mock_dbt_project/dbt_project.yml: -------------------------------------------------------------------------------- 1 | name: 'jaffle_shop' 2 | 3 | config-version: 2 4 | version: '0.1' 5 | 6 | profile: 'jaffle_shop' 7 | 8 | model-paths: ["models"] 9 | seed-paths: ["seeds"] 10 | test-paths: ["tests"] 11 | analysis-paths: ["analysis"] 12 | macro-paths: ["macros"] 13 | 14 | target-path: "target" 15 | clean-targets: 16 | - "target" 17 | - "dbt_modules" 18 | - "logs" 19 | 20 | require-dbt-version: [">=1.0.0", "<2.0.0"] 21 | 22 | models: 23 | jaffle_shop: 24 | materialized: table 25 | staging: 26 | materialized: view 27 | +tags: piperider 28 | marts: 29 | +tags: piperider 30 | -------------------------------------------------------------------------------- /tests/mock_dbt_project/profiles.yml: -------------------------------------------------------------------------------- 1 | jaffle_shop: 2 | target: dev 3 | outputs: 4 | dev: 5 | type: duckdb 6 | path: jaffle_shop.duckdb 7 | -------------------------------------------------------------------------------- /tests/mock_dbt_project/skip_datasource_connection/.piperider/config.yml: -------------------------------------------------------------------------------- 1 | dataSources: [] 2 | dbt: 3 | projectDir: . 4 | -------------------------------------------------------------------------------- /tests/mock_dbt_project/skip_datasource_connection/dbt_project.yml: -------------------------------------------------------------------------------- 1 | name: 'jaffle_shop' 2 | 3 | config-version: 2 4 | version: '0.1' 5 | 6 | profile: 'jaffle_shop' 7 | 8 | model-paths: ["models"] 9 | seed-paths: ["seeds"] 10 | test-paths: ["tests"] 11 | analysis-paths: ["analysis"] 12 | macro-paths: ["macros"] 13 | 14 | target-path: "target" 15 | clean-targets: 16 | - "target" 17 | - "dbt_modules" 18 | - "logs" 19 | 20 | require-dbt-version: [">=1.0.0", "<2.0.0"] 21 | 22 | models: 23 | jaffle_shop: 24 | materialized: table 25 | staging: 26 | materialized: view 27 | +tags: piperider 28 | marts: 29 | +tags: piperider 30 | -------------------------------------------------------------------------------- /tests/mock_dbt_project/skip_datasource_connection/profiles.yml: -------------------------------------------------------------------------------- 1 | # PipeRider haven't supported hive yet 2 | jaffle_shop: 3 | target: dev 4 | outputs: 5 | dev: 6 | type: hive 7 | host: localhost 8 | port: 10000 9 | -------------------------------------------------------------------------------- /tests/profiler/test_multi_db.py: -------------------------------------------------------------------------------- 1 | from datetime import date, datetime 2 | 3 | from sqlalchemy.engine import Engine 4 | 5 | from piperider_cli.datasource.sqlite import SqliteDataSource 6 | from piperider_cli.profiler import Profiler, ProfileSubject 7 | from sqlalchemy import * 8 | from typing import List 9 | 10 | from tests.common import create_table 11 | 12 | 13 | def almost_equal(x, y, threshold=0.01): 14 | return abs(x - y) < threshold 15 | 16 | 17 | class TestMultiDB: 18 | 19 | def test_basic_profile(self): 20 | data_source = SqliteDataSource("test") 21 | engine1 = data_source.get_engine_by_database("db1") 22 | engine2 = data_source.get_engine_by_database("db2") 23 | data = [ 24 | ("user_id", "user_name", "age"), 25 | (1, "bob", 23), 26 | (2, "alice", 25), 27 | ] 28 | create_table(engine1, "test1", data) 29 | create_table(engine2, "test2", data) 30 | 31 | profiler = Profiler(data_source) 32 | result = profiler.profile([ProfileSubject('test1', database='db1', ref_id='foo.test1'), 33 | ProfileSubject('test2', database='db2', ref_id='foo.test2')]) 34 | assert "test1" in result["tables"] 35 | assert "test2" in result["tables"] 36 | -------------------------------------------------------------------------------- /tests/test_links.py: -------------------------------------------------------------------------------- 1 | import json 2 | import os 3 | import shutil 4 | 5 | from piperider_cli.utils import create_link 6 | 7 | 8 | def test_create_link(): 9 | dirname = os.path.join(os.getcwd(), "__create_link__") 10 | dirname_latest = os.path.join(os.getcwd(), "__create_link__latest") 11 | 12 | def cleanup(): 13 | if os.path.exists(dirname_latest): 14 | os.unlink(dirname_latest) 15 | if os.path.exists(dirname): 16 | shutil.rmtree(dirname, ignore_errors=True) 17 | 18 | cleanup() 19 | 20 | try: 21 | os.makedirs(dirname, exist_ok=True) 22 | create_link(dirname, dirname_latest) 23 | finally: 24 | cleanup() 25 | -------------------------------------------------------------------------------- /tests/test_reversed_manifest.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import Callable, Dict 3 | 4 | import pytest 5 | 6 | from piperider_cli.dbt import dbt_version 7 | from piperider_cli.dbt.reverse_manifest import reverse_to_run 8 | 9 | 10 | @pytest.mark.skipif( 11 | dbt_version < "v1.5", reason="skip manifest test before dbt-core 1.5" 12 | ) 13 | def test_reversed_manifest( 14 | sc_31711_run_data: Dict, piperider_schema_validate_func: Callable[[Dict], None] 15 | ): 16 | run_data: Dict = sc_31711_run_data 17 | manifest_data = run_data.get("dbt", {}).get("manifest") 18 | 19 | fake_run = reverse_to_run(manifest_data) 20 | piperider_schema_validate_func(fake_run) 21 | 22 | assert manifest_data == fake_run.get("dbt", {}).get("manifest") 23 | with open("sample.json", "w") as fh: 24 | fh.write(json.dumps(fake_run)) 25 | 26 | # it is impossible to generate the same tables information without profiling 27 | # assert fake_run.get('tables') == run_data.get('tables') 28 | -------------------------------------------------------------------------------- /tests/test_util.py: -------------------------------------------------------------------------------- 1 | import os 2 | from unittest import TestCase, mock 3 | 4 | from piperider_cli import load_jinja_string_template 5 | 6 | 7 | class TestUtil(TestCase): 8 | 9 | @mock.patch.dict(os.environ, {"dummy_env_text": "test", "dummy_env_number": str(1), "dummy_env_bool": str(True)}) 10 | def test_load_jinja_string_template(self): 11 | val = "{{ env_var('dummy_env_text') | as_text }}" 12 | result = load_jinja_string_template(val).render() 13 | 14 | self.assertEqual("test", result) 15 | 16 | val = "{{ env_var('dummy_env_number') | as_number }}" 17 | result = load_jinja_string_template(val).render() 18 | 19 | self.assertEqual('1', result) 20 | 21 | val = "{{ env_var('dummy_env_bool') | as_bool }}" 22 | result = load_jinja_string_template(val).render() 23 | 24 | self.assertEqual("True", result) 25 | 26 | val = "{{ env_var('dummy_env_none') }}" 27 | result = load_jinja_string_template(val).render() 28 | 29 | self.assertEqual("", result) 30 | 31 | val = "{{ env_var('dummy_env_none') | as_number }}" 32 | result = load_jinja_string_template(val).render() 33 | 34 | self.assertEqual("", result) 35 | 36 | -------------------------------------------------------------------------------- /tox-ruamel.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | env_list = ruamel-{0.17.21,0.17.22} 3 | minversion = 4.7.0 4 | 5 | [testenv] 6 | description = run the tests with pytest 7 | package = wheel 8 | wheel_build_env = .pkg 9 | 10 | 11 | deps = 12 | pytest>=6 13 | dbt-core 14 | dbt-duckdb 15 | ruamel-0.17.21: ruamel.yaml<=0.17.21 16 | ruamel-0.17.22: ruamel.yaml>0.17.21,<0.18 17 | 18 | 19 | commands = 20 | pytest {tty:--color=yes} {posargs} 21 | 22 | setenv = 23 | PYTHONPATH = {toxinidir}/tests/:{env:PYTHONPATH} 24 | 25 | 26 | -------------------------------------------------------------------------------- /tox-sqlalchemy.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | env_list = sqlalchemy-{14,20} 3 | minversion = 4.7.0 4 | 5 | [testenv] 6 | description = run the tests with pytest 7 | package = wheel 8 | wheel_build_env = .pkg 9 | 10 | 11 | deps = 12 | pytest>=6 13 | dbt-core 14 | dbt-duckdb 15 | sqlalchemy-14: sqlalchemy>=1.4,<2.0 16 | sqlalchemy-20: sqlalchemy>=2.0 17 | 18 | 19 | commands = 20 | pytest {tty:--color=yes} {posargs} 21 | 22 | setenv = 23 | PYTHONPATH = {toxinidir}/tests/:{env:PYTHONPATH} 24 | 25 | 26 | --------------------------------------------------------------------------------