openretailscience 0.46.0__tar.gz → 0.48.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- openretailscience-0.48.0/.env_sample +9 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.github/dependabot.yml +15 -0
- openretailscience-0.48.0/.github/workflows/bigquery-integration.yml +48 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.github/workflows/claude-code-review.yml +6 -2
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.github/workflows/claude.yml +5 -4
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.github/workflows/cloudflare-docs-preview.yml +18 -18
- openretailscience-0.48.0/.github/workflows/gh-page.yml +46 -0
- openretailscience-0.48.0/.github/workflows/oracle-integration.yml +46 -0
- openretailscience-0.48.0/.github/workflows/pyspark-integration.yml +36 -0
- openretailscience-0.48.0/.github/workflows/release.yml +206 -0
- openretailscience-0.48.0/.github/workflows/security-audit.yml +86 -0
- openretailscience-0.48.0/.github/workflows/slack-notifications.yml +110 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.github/workflows/snowflake-integration.yml +30 -40
- openretailscience-0.48.0/.github/workflows/sqlserver-integration.yml +64 -0
- openretailscience-0.48.0/.github/workflows/test.yml +104 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.gitignore +5 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.pre-commit-config.yaml +13 -11
- {openretailscience-0.46.0 → openretailscience-0.48.0}/CLAUDE.md +21 -3
- {openretailscience-0.46.0 → openretailscience-0.48.0}/CONTRIBUTING.md +13 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/PKG-INFO +30 -13
- {openretailscience-0.46.0 → openretailscience-0.48.0}/README.md +25 -8
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/analysis_modules.md +3 -3
- openretailscience-0.48.0/docs/api/experimental/clv.md +3 -0
- openretailscience-0.48.0/docs/api/experimental/metrics/distribution.md +5 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/examples/retention.ipynb +9 -11
- openretailscience-0.48.0/docs/experimental/clv.md +167 -0
- {openretailscience-0.46.0/docs → openretailscience-0.48.0/docs/experimental}/metrics.md +6 -2
- openretailscience-0.48.0/docs/gallery/index.md +156 -0
- openretailscience-0.48.0/docs/gallery/plots/customer_decision_hierarchy.ipynb +249 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/waterfall.ipynb +3 -3
- openretailscience-0.48.0/docs/getting_started/agent_skills.md +94 -0
- openretailscience-0.48.0/docs/getting_started/connecting_to_data.md +493 -0
- openretailscience-0.48.0/docs/getting_started/data_structures.md +274 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/getting_started/options_guide.md +5 -3
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/overrides/home.html +1 -1
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/scripts/regenerate_analysis_modules_svgs.py +5 -7
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/stylesheets/extra.css +95 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/mkdocs.yml +16 -4
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/SKILL.md +105 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/references/analysis.md +105 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/references/clv.md +128 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/references/configuration.md +113 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/references/plotting.md +87 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_advanced_customization.py +29 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_area.py +79 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_bar.py +98 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_broken_timeline.py +74 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_clv_stats.py +80 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_cohort.py +50 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_cohort_analysis.py +56 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_composite_rank.py +35 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_connecting_to_data.py +167 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_cross_shop.py +43 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_customer_decision_hierarchy.py +108 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_filter_and_label.py +94 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_filter_by_periods.py +36 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_gain_loss.py +109 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_haversine_distance.py +78 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_heatmap.py +40 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_histogram.py +78 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_hml_segmentation.py +70 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_human_format.py +45 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_index.py +82 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_label_by_condition.py +87 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_line.py +56 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_nlr_segmentation.py +70 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_options.py +106 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_overlapping_periods.py +21 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_period_on_period.py +70 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_price.py +83 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_product_association.py +70 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_purchases_per_customer.py +42 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_revenue_tree.py +82 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_rfm_segmentation.py +89 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_scatter.py +103 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_segment_transaction_stats.py +102 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_set_axis_percent.py +68 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_threshold_segmentation.py +96 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_time.py +90 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_tree_diagram.py +115 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_trend_line.py +25 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_venn.py +69 -0
- openretailscience-0.48.0/openretailscience/.agents/skills/using-openretailscience/scripts/example_waterfall.py +61 -0
- openretailscience-0.48.0/openretailscience/__init__.py +1 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/cohort.py +62 -17
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/composite_rank.py +22 -86
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/cross_shop.py +9 -10
- openretailscience-0.48.0/openretailscience/analysis/customer.py +377 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/customer_decision_hierarchy.py +2 -4
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/gain_loss.py +5 -5
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/product_association.py +9 -13
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/revenue_tree.py +8 -22
- openretailscience-0.48.0/openretailscience/core/__init__.py +1 -0
- openretailscience-0.48.0/openretailscience/core/validation.py +349 -0
- openretailscience-0.48.0/openretailscience/experimental/__init__.py +4 -0
- openretailscience-0.48.0/openretailscience/experimental/clv.py +483 -0
- {openretailscience-0.46.0/openretailscience → openretailscience-0.48.0/openretailscience/experimental}/metrics/distribution/acv.py +9 -13
- {openretailscience-0.46.0/openretailscience → openretailscience-0.48.0/openretailscience/experimental}/metrics/distribution/pct_of_stores.py +14 -15
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/options.py +33 -16
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/bar.py +31 -28
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/broken_timeline.py +19 -43
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/index.py +18 -19
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/line.py +16 -13
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/price.py +4 -1
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/scatter.py +4 -1
- openretailscience-0.48.0/openretailscience/plots/styles/graph_utils.py +481 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/styles/styling_helpers.py +376 -77
- openretailscience-0.48.0/openretailscience/plots/styles/trend.py +506 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/waterfall.py +19 -13
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/segmentation/nlr.py +26 -27
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/segmentation/rfm.py +11 -15
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/segmentation/segstats.py +188 -88
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/segmentation/threshold.py +12 -21
- openretailscience-0.48.0/openretailscience/skills.py +425 -0
- openretailscience-0.48.0/openretailscience/utils/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/options_template.toml +5 -0
- openretailscience-0.48.0/osv-scanner.toml +9 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/pyproject.toml +27 -13
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_cohort.py +109 -15
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_composite_rank.py +22 -23
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_cross_shop.py +2 -2
- openretailscience-0.48.0/tests/analysis/test_customer.py +522 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_customer_decision_hierarchy.py +24 -25
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_gain_loss.py +1 -1
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_revenue_tree.py +14 -12
- openretailscience-0.48.0/tests/core/__init__.py +0 -0
- openretailscience-0.48.0/tests/core/test_validation.py +331 -0
- {openretailscience-0.46.0/tests → openretailscience-0.48.0/tests/experimental}/metrics/distribution/test_acv.py +6 -6
- {openretailscience-0.46.0/tests → openretailscience-0.48.0/tests/experimental}/metrics/distribution/test_pct_of_stores.py +3 -3
- {openretailscience-0.46.0/tests → openretailscience-0.48.0/tests/experimental}/metrics/test_base.py +2 -2
- openretailscience-0.48.0/tests/experimental/test_clv.py +720 -0
- openretailscience-0.48.0/tests/integration/conftest.py +213 -0
- openretailscience-0.48.0/tests/integration/docker/README.md +61 -0
- openretailscience-0.48.0/tests/integration/docker/docker-compose.oracle.yml +24 -0
- openretailscience-0.48.0/tests/integration/docker/docker-compose.sqlserver.yml +23 -0
- openretailscience-0.48.0/tests/integration/test_clv_stats.py +133 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/styles/test_chart_chrome.py +263 -48
- openretailscience-0.48.0/tests/plots/styles/test_graph_utils.py +427 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/styles/test_styling_helper.py +118 -25
- openretailscience-0.48.0/tests/plots/styles/test_trend.py +625 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_bar.py +34 -7
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_broken_timeline.py +33 -22
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_index.py +47 -1
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_line.py +15 -2
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_price.py +15 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_scatter.py +29 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_waterfall.py +36 -1
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/segmentation/test_nlr.py +22 -23
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/segmentation/test_rfm.py +119 -74
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/segmentation/test_segstats.py +374 -439
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/segmentation/test_threshold.py +1 -1
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/test_options.py +34 -13
- openretailscience-0.48.0/tests/test_skills.py +685 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/uv.lock +1777 -1744
- openretailscience-0.46.0/.claude/commands/review-pr-tests.md +0 -607
- openretailscience-0.46.0/.env_sample +0 -9
- openretailscience-0.46.0/.github/workflows/bigquery-integration.yml +0 -67
- openretailscience-0.46.0/.github/workflows/gh-page.yml +0 -45
- openretailscience-0.46.0/.github/workflows/pyspark-integration.yml +0 -63
- openretailscience-0.46.0/.github/workflows/release.yml +0 -220
- openretailscience-0.46.0/.github/workflows/slack-notifications.yml +0 -103
- openretailscience-0.46.0/.github/workflows/test.yml +0 -75
- openretailscience-0.46.0/docs/api/metrics/distribution.md +0 -5
- openretailscience-0.46.0/docs/gallery/index.md +0 -212
- openretailscience-0.46.0/docs/gallery/plots/customer_decision_hierarchy.ipynb +0 -228
- openretailscience-0.46.0/openretailscience/__init__.py +0 -3
- openretailscience-0.46.0/openretailscience/analysis/customer.py +0 -237
- openretailscience-0.46.0/openretailscience/plots/styles/graph_utils.py +0 -923
- openretailscience-0.46.0/openretailscience/plugin.py +0 -238
- openretailscience-0.46.0/openretailscience/utils/validation.py +0 -45
- openretailscience-0.46.0/tests/analysis/test_customer.py +0 -203
- openretailscience-0.46.0/tests/integration/conftest.py +0 -47
- openretailscience-0.46.0/tests/plots/styles/test_graph_utils.py +0 -979
- openretailscience-0.46.0/tests/test_plugin.py +0 -367
- openretailscience-0.46.0/tests/utils/test_validation.py +0 -87
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/.markdownlint.json +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/CNAME +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/CODE_OF_CONDUCT.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/LICENSE +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/data/transactions.parquet +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/cohort.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/composite_rank.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/cross_shop.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/customer.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/customer_decision_hierarchy.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/gain_loss.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/haversine.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/product_association.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/analysis/revenue_tree.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/options.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/area.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/bar.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/broken_timeline.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/cohort.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/heatmap.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/histogram.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/index.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/line.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/period_on_period.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/price.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/scatter.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/styles/graph_utils.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/styles/styling_helpers.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/time.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/venn.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/plots/waterfall.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/segmentation/hml.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/segmentation/nlr.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/segmentation/rfm.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/segmentation/segstats.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/segmentation/threshold.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/utils/date.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/utils/filter_and_label.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/api/utils/label.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/cohort.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/cross_shop.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/customer_decision_hierarchy.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/days_between_purchases.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/gain_loss.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/hml_segmentation.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/purchases_per_customer.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/revenue_tree.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/threshold_segmentation.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/analysis_modules/transaction_churn.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/features/charts.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/features/cross_shop.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/area_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/bar_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/broken_timeline_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/cohort_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/customer_decision_hierarchy_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/heatmap_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/histogram_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/index_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/line_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/period_on_period_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/price_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/revenue_tree_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/scatter_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/time_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/venn_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/gallery/waterfall_thumbnail.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/assets/images/logo.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/examples/cross_shop.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/examples/gain_loss.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/examples/product_association.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/examples/revenue_tree.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/examples/segmentation.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/area.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/bar.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/broken_timeline.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/cohort.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/heatmap.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/histogram.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/index_plot.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/line.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/period_on_period.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/price.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/revenue_tree.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/scatter.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/time.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/gallery/plots/venn.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/getting_started/installation.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/getting_started/styling_guide.ipynb +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/index.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/javascripts/mathjax.js +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/overrides/main.html +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/robots.txt +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/docs/scripts/README.md +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/analysis/haversine.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/assets/fonts/Poppins-Bold.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/assets/fonts/Poppins-LightItalic.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/assets/fonts/Poppins-Medium.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/assets/fonts/Poppins-Regular.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/assets/fonts/Poppins-SemiBold.ttf +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/constants.py +0 -0
- {openretailscience-0.46.0/openretailscience → openretailscience-0.48.0/openretailscience/experimental}/metrics/__init__.py +0 -0
- {openretailscience-0.46.0/openretailscience → openretailscience-0.48.0/openretailscience/experimental}/metrics/base.py +0 -0
- {openretailscience-0.46.0/openretailscience → openretailscience-0.48.0/openretailscience/experimental}/metrics/distribution/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/area.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/cohort.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/heatmap.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/histogram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/period_on_period.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/styles/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/styles/colors.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/styles/font_utils.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/time.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/tree_diagram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/plots/venn.py +0 -0
- /openretailscience-0.46.0/openretailscience/segmentation/__init__.py → /openretailscience-0.48.0/openretailscience/py.typed +0 -0
- {openretailscience-0.46.0/openretailscience/utils → openretailscience-0.48.0/openretailscience/segmentation}/__init__.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/segmentation/hml.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/utils/date.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/utils/filter_and_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/openretailscience/utils/label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/readme_assets/cross_shop_chart.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/readme_assets/days_until_next_purchase.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/readme_assets/gain_loss_chart.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/readme_assets/logo.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/readme_assets/logo.svg +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/readme_assets/new_store_cannibalization.png +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/taplo.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_haversine.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/analysis/test_product_association.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_cohort_analysis.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_composite_rank.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_cross_shop.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_customer_decision_hierarchy.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_date.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_filter_and_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_haversine.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_hml_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_product_association.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_revenue_tree.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_rfm_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_segstats_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/integration/test_threshold_segmentation.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/styles/test_color.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/styles/test_font_utils.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_area.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_cohort.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_heatmap.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_histogram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_period_on_period.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_styling_options_integration.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_time.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_tree_diagram.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/plots/test_venn.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/segmentation/test_hml.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/toml_files/corrupt.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/toml_files/invalid_option.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/toml_files/test_options.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/toml_files/valid.toml +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/utils/test_date.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/utils/test_filter_and_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tests/utils/test_label.py +0 -0
- {openretailscience-0.46.0 → openretailscience-0.48.0}/tox.ini +0 -0
|
@@ -5,6 +5,8 @@ updates:
|
|
|
5
5
|
schedule:
|
|
6
6
|
interval: "weekly"
|
|
7
7
|
open-pull-requests-limit: 5
|
|
8
|
+
cooldown:
|
|
9
|
+
default-days: 7
|
|
8
10
|
commit-message:
|
|
9
11
|
prefix: "chore(deps)"
|
|
10
12
|
prefix-development: "chore(deps-dev)"
|
|
@@ -13,3 +15,16 @@ updates:
|
|
|
13
15
|
dependency-type: "production"
|
|
14
16
|
development-dependencies:
|
|
15
17
|
dependency-type: "development"
|
|
18
|
+
|
|
19
|
+
- package-ecosystem: "github-actions"
|
|
20
|
+
directory: "/"
|
|
21
|
+
schedule:
|
|
22
|
+
interval: "weekly"
|
|
23
|
+
open-pull-requests-limit: 5
|
|
24
|
+
cooldown:
|
|
25
|
+
default-days: 7
|
|
26
|
+
commit-message:
|
|
27
|
+
prefix: "chore(deps)"
|
|
28
|
+
groups:
|
|
29
|
+
actions-minor-patch:
|
|
30
|
+
update-types: ["minor", "patch"]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: BigQuery Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
secrets:
|
|
7
|
+
GCP_SA_KEY:
|
|
8
|
+
required: true
|
|
9
|
+
GCP_PROJECT_ID:
|
|
10
|
+
required: true
|
|
11
|
+
|
|
12
|
+
permissions:
|
|
13
|
+
contents: read
|
|
14
|
+
|
|
15
|
+
jobs:
|
|
16
|
+
integration-tests:
|
|
17
|
+
name: Run BigQuery Integration Tests
|
|
18
|
+
runs-on: ubuntu-latest
|
|
19
|
+
timeout-minutes: 30
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
23
|
+
with:
|
|
24
|
+
persist-credentials: false
|
|
25
|
+
- name: Setup Python
|
|
26
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
27
|
+
with:
|
|
28
|
+
python-version: "3.11"
|
|
29
|
+
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
|
|
35
|
+
- name: Install Dependencies
|
|
36
|
+
run: |
|
|
37
|
+
uv sync --locked
|
|
38
|
+
|
|
39
|
+
- name: Set up GCP Authentication
|
|
40
|
+
uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0
|
|
41
|
+
with:
|
|
42
|
+
credentials_json: ${{ secrets.GCP_SA_KEY }}
|
|
43
|
+
|
|
44
|
+
- name: Run Integration Tests
|
|
45
|
+
env:
|
|
46
|
+
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
|
|
47
|
+
run: |
|
|
48
|
+
uv run pytest tests/integration -k "bigquery" -v
|
{openretailscience-0.46.0 → openretailscience-0.48.0}/.github/workflows/claude-code-review.yml
RENAMED
|
@@ -18,6 +18,9 @@ jobs:
|
|
|
18
18
|
# github.event.pull_request.user.login == 'new-developer' ||
|
|
19
19
|
# github.event.pull_request.author_association == 'FIRST_TIME_CONTRIBUTOR'
|
|
20
20
|
|
|
21
|
+
# Skip automated dependency PRs: Dependabot runs without access to secrets and
|
|
22
|
+
# claude-code-action refuses to run for bot actors, so the job can only ever fail.
|
|
23
|
+
if: github.actor != 'dependabot[bot]'
|
|
21
24
|
runs-on: ubuntu-latest
|
|
22
25
|
permissions:
|
|
23
26
|
contents: read
|
|
@@ -27,13 +30,14 @@ jobs:
|
|
|
27
30
|
|
|
28
31
|
steps:
|
|
29
32
|
- name: Checkout repository
|
|
30
|
-
uses: actions/checkout@
|
|
33
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
31
34
|
with:
|
|
32
35
|
fetch-depth: 1
|
|
36
|
+
persist-credentials: false
|
|
33
37
|
|
|
34
38
|
- name: Run Claude Code Review
|
|
35
39
|
id: claude-review
|
|
36
|
-
uses: anthropics/claude-code-action@v1
|
|
40
|
+
uses: anthropics/claude-code-action@b76a0776ae74036e77cd11018083743453d7ad35 # v1.0.179
|
|
37
41
|
with:
|
|
38
42
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
39
43
|
track_progress: true
|
|
@@ -27,7 +27,7 @@ jobs:
|
|
|
27
27
|
steps:
|
|
28
28
|
- name: Check user permissions
|
|
29
29
|
id: check_permissions
|
|
30
|
-
uses: actions/github-script@
|
|
30
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
31
31
|
with:
|
|
32
32
|
script: |
|
|
33
33
|
let actor;
|
|
@@ -60,7 +60,7 @@ jobs:
|
|
|
60
60
|
|
|
61
61
|
- name: Comment on permission denied
|
|
62
62
|
if: steps.check_permissions.outputs.has_permission == 'false'
|
|
63
|
-
uses: actions/github-script@
|
|
63
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
64
64
|
with:
|
|
65
65
|
script: |
|
|
66
66
|
let issueNumber;
|
|
@@ -85,14 +85,15 @@ jobs:
|
|
|
85
85
|
|
|
86
86
|
- name: Checkout repository
|
|
87
87
|
if: steps.check_permissions.outputs.has_permission == 'true'
|
|
88
|
-
uses: actions/checkout@
|
|
88
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
89
89
|
with:
|
|
90
90
|
fetch-depth: 1
|
|
91
|
+
persist-credentials: false
|
|
91
92
|
|
|
92
93
|
- name: Run Claude Code
|
|
93
94
|
if: steps.check_permissions.outputs.has_permission == 'true'
|
|
94
95
|
id: claude
|
|
95
|
-
uses: anthropics/claude-code-action@v1
|
|
96
|
+
uses: anthropics/claude-code-action@b76a0776ae74036e77cd11018083743453d7ad35 # v1.0.179
|
|
96
97
|
with:
|
|
97
98
|
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
|
98
99
|
|
{openretailscience-0.46.0 → openretailscience-0.48.0}/.github/workflows/cloudflare-docs-preview.yml
RENAMED
|
@@ -22,23 +22,25 @@ jobs:
|
|
|
22
22
|
|
|
23
23
|
steps:
|
|
24
24
|
- name: Checkout repository
|
|
25
|
-
uses: actions/checkout@
|
|
26
|
-
|
|
25
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
27
28
|
- name: Setup Python
|
|
28
|
-
uses: actions/setup-python@
|
|
29
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
29
30
|
with:
|
|
30
31
|
python-version: "3.11"
|
|
31
32
|
|
|
32
|
-
- name: Install uv
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
33
|
+
- name: Install uv
|
|
34
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
35
|
+
with:
|
|
36
|
+
# Disabled: a shared cache feeding the preview deploy is a poisoning vector.
|
|
37
|
+
enable-cache: "false"
|
|
36
38
|
|
|
37
39
|
- name: Install Dependencies
|
|
38
|
-
run: uv sync
|
|
40
|
+
run: uv sync --locked
|
|
39
41
|
|
|
40
42
|
- name: Build docs
|
|
41
|
-
run: uv run mkdocs build
|
|
43
|
+
run: uv run mkdocs build --strict
|
|
42
44
|
|
|
43
45
|
- name: Verify build output
|
|
44
46
|
run: |
|
|
@@ -50,18 +52,16 @@ jobs:
|
|
|
50
52
|
|
|
51
53
|
- name: Publish to Cloudflare Pages
|
|
52
54
|
id: cloudflare-deploy
|
|
53
|
-
uses: cloudflare/
|
|
55
|
+
uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0
|
|
54
56
|
with:
|
|
55
57
|
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
56
58
|
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
|
57
|
-
projectName: openretailscience-docs
|
|
58
|
-
directory: site
|
|
59
59
|
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
|
|
60
|
-
|
|
60
|
+
command: pages deploy site --project-name=openretailscience-docs --branch=${{ github.head_ref || github.ref_name }}
|
|
61
61
|
|
|
62
62
|
- name: Find existing comment
|
|
63
63
|
if: github.event_name == 'pull_request'
|
|
64
|
-
uses: peter-evans/find-comment@
|
|
64
|
+
uses: peter-evans/find-comment@b30e6a3c0ed37e7c023ccd3f1db5c6c0b0c23aad # v4.0.0
|
|
65
65
|
id: find-comment
|
|
66
66
|
with:
|
|
67
67
|
issue-number: ${{ github.event.pull_request.number }}
|
|
@@ -70,7 +70,7 @@ jobs:
|
|
|
70
70
|
|
|
71
71
|
- name: Create or update deployment comment
|
|
72
72
|
if: github.event_name == 'pull_request'
|
|
73
|
-
uses: peter-evans/create-or-update-comment@
|
|
73
|
+
uses: peter-evans/create-or-update-comment@e8674b075228eee787fea43ef493e45ece1004c9 # v5.0.0
|
|
74
74
|
with:
|
|
75
75
|
comment-id: ${{ steps.find-comment.outputs.comment-id }}
|
|
76
76
|
issue-number: ${{ github.event.pull_request.number }}
|
|
@@ -80,15 +80,15 @@ jobs:
|
|
|
80
80
|
|
|
81
81
|
✅ Preview deployed successfully!
|
|
82
82
|
|
|
83
|
-
**Preview URL:** ${{ steps.cloudflare-deploy.outputs.url }}
|
|
84
|
-
**Deployment ID:** ${{ steps.cloudflare-deploy.outputs.id }}
|
|
83
|
+
**Preview URL:** ${{ steps.cloudflare-deploy.outputs.deployment-url }}
|
|
84
|
+
**Deployment ID:** ${{ steps.cloudflare-deploy.outputs.pages-deployment-id }}
|
|
85
85
|
|
|
86
86
|
---
|
|
87
87
|
*This preview will be updated automatically when you push new changes to this PR.*
|
|
88
88
|
|
|
89
89
|
- name: Comment on deployment failure
|
|
90
90
|
if: failure() && github.event_name == 'pull_request'
|
|
91
|
-
uses: actions/github-script@
|
|
91
|
+
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
92
92
|
with:
|
|
93
93
|
script: |
|
|
94
94
|
github.rest.issues.createComment({
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Page Deploy
|
|
2
|
+
on:
|
|
3
|
+
workflow_call:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
contents: read
|
|
8
|
+
pages: write
|
|
9
|
+
id-token: write
|
|
10
|
+
|
|
11
|
+
concurrency:
|
|
12
|
+
group: "pages"
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
jobs:
|
|
15
|
+
docs:
|
|
16
|
+
environment:
|
|
17
|
+
name: github-pages
|
|
18
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
timeout-minutes: 15
|
|
21
|
+
steps:
|
|
22
|
+
- name: Checkout
|
|
23
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
24
|
+
with:
|
|
25
|
+
persist-credentials: false
|
|
26
|
+
- name: Setup Python
|
|
27
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
28
|
+
with:
|
|
29
|
+
python-version: "3.11"
|
|
30
|
+
- name: Install uv
|
|
31
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
32
|
+
with:
|
|
33
|
+
enable-cache: true
|
|
34
|
+
- name: Install Dependencies
|
|
35
|
+
run: uv sync --locked
|
|
36
|
+
- name: Build docs
|
|
37
|
+
run: uv run mkdocs build
|
|
38
|
+
- name: Setup Pages
|
|
39
|
+
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6.0.0
|
|
40
|
+
- name: Upload artifact
|
|
41
|
+
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
|
|
42
|
+
with:
|
|
43
|
+
path: "site/"
|
|
44
|
+
- name: Deploy to GitHub Pages
|
|
45
|
+
id: deployment
|
|
46
|
+
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
name: Oracle Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
integration-tests:
|
|
12
|
+
name: Run Oracle Integration Tests
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 30
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
18
|
+
with:
|
|
19
|
+
persist-credentials: false
|
|
20
|
+
- name: Setup Python
|
|
21
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
27
|
+
with:
|
|
28
|
+
enable-cache: true
|
|
29
|
+
|
|
30
|
+
- name: Install Dependencies
|
|
31
|
+
run: |
|
|
32
|
+
uv sync --locked
|
|
33
|
+
|
|
34
|
+
# Oracle 23ai Free (the supported LTS); the Compose file pins the gvenzl image.
|
|
35
|
+
- name: Start Oracle
|
|
36
|
+
run: |
|
|
37
|
+
docker compose -f tests/integration/docker/docker-compose.oracle.yml up -d --wait --wait-timeout 600
|
|
38
|
+
|
|
39
|
+
- name: Run Integration Tests
|
|
40
|
+
run: |
|
|
41
|
+
uv run pytest tests/integration -k "oracle" -v
|
|
42
|
+
|
|
43
|
+
- name: Stop Oracle
|
|
44
|
+
if: always()
|
|
45
|
+
run: |
|
|
46
|
+
docker compose -f tests/integration/docker/docker-compose.oracle.yml down -v
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
name: PySpark Integration Tests
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
workflow_call:
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
integration-tests:
|
|
12
|
+
name: Run PySpark Integration Tests
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 30
|
|
15
|
+
steps:
|
|
16
|
+
- name: Checkout
|
|
17
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
18
|
+
with:
|
|
19
|
+
persist-credentials: false
|
|
20
|
+
- name: Setup Python
|
|
21
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
22
|
+
with:
|
|
23
|
+
python-version: "3.11"
|
|
24
|
+
|
|
25
|
+
- name: Install uv
|
|
26
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
27
|
+
with:
|
|
28
|
+
enable-cache: true
|
|
29
|
+
|
|
30
|
+
- name: Install Dependencies
|
|
31
|
+
run: |
|
|
32
|
+
uv sync --locked
|
|
33
|
+
|
|
34
|
+
- name: Run Integration Tests
|
|
35
|
+
run: |
|
|
36
|
+
uv run pytest tests/integration -k "pyspark" -v
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
name: PyPi Package Deploy
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
inputs:
|
|
5
|
+
release:
|
|
6
|
+
type: choice
|
|
7
|
+
description: Select Release Type
|
|
8
|
+
default: "minor"
|
|
9
|
+
options:
|
|
10
|
+
- major
|
|
11
|
+
- minor
|
|
12
|
+
- patch
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
concurrency:
|
|
16
|
+
group: "release"
|
|
17
|
+
cancel-in-progress: false
|
|
18
|
+
jobs:
|
|
19
|
+
pre-commit:
|
|
20
|
+
name: Pre-Commit Checks
|
|
21
|
+
runs-on: ubuntu-latest
|
|
22
|
+
timeout-minutes: 10
|
|
23
|
+
steps:
|
|
24
|
+
- name: Checkout
|
|
25
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
26
|
+
with:
|
|
27
|
+
persist-credentials: false
|
|
28
|
+
- name: Setup Python
|
|
29
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
30
|
+
with:
|
|
31
|
+
python-version: "3.11"
|
|
32
|
+
- name: Install uv
|
|
33
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
34
|
+
with:
|
|
35
|
+
enable-cache: true
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: uv sync --locked
|
|
38
|
+
- name: Run Pre-commit
|
|
39
|
+
run: uv run pre-commit run --all-files
|
|
40
|
+
|
|
41
|
+
security-audit:
|
|
42
|
+
name: Dependency Security Audit
|
|
43
|
+
uses: ./.github/workflows/security-audit.yml
|
|
44
|
+
permissions:
|
|
45
|
+
contents: read
|
|
46
|
+
security-events: write
|
|
47
|
+
|
|
48
|
+
bigquery-integration-tests:
|
|
49
|
+
name: BigQuery Integration Tests
|
|
50
|
+
uses: ./.github/workflows/bigquery-integration.yml
|
|
51
|
+
secrets:
|
|
52
|
+
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
|
|
53
|
+
GCP_PROJECT_ID: ${{ secrets.GCP_PROJECT_ID }}
|
|
54
|
+
|
|
55
|
+
pyspark-integration-tests:
|
|
56
|
+
name: PySpark Integration Tests
|
|
57
|
+
uses: ./.github/workflows/pyspark-integration.yml
|
|
58
|
+
|
|
59
|
+
snowflake-integration-tests:
|
|
60
|
+
name: Snowflake Integration Tests
|
|
61
|
+
uses: ./.github/workflows/snowflake-integration.yml
|
|
62
|
+
secrets:
|
|
63
|
+
GCP_SA_KEY: ${{ secrets.GCP_SA_KEY }}
|
|
64
|
+
GCP_INFRA_PROJECT_ID: ${{ secrets.GCP_INFRA_PROJECT_ID }}
|
|
65
|
+
SNOWFLAKE_CI_ACCOUNT: ${{ secrets.SNOWFLAKE_CI_ACCOUNT }}
|
|
66
|
+
SNOWFLAKE_CI_USER: ${{ secrets.SNOWFLAKE_CI_USER }}
|
|
67
|
+
SNOWFLAKE_CI_WAREHOUSE: ${{ secrets.SNOWFLAKE_CI_WAREHOUSE }}
|
|
68
|
+
SNOWFLAKE_CI_DATABASE: ${{ secrets.SNOWFLAKE_CI_DATABASE }}
|
|
69
|
+
SNOWFLAKE_CI_SCHEMA: ${{ secrets.SNOWFLAKE_CI_SCHEMA }}
|
|
70
|
+
|
|
71
|
+
sqlserver-integration-tests:
|
|
72
|
+
name: SQL Server Integration Tests
|
|
73
|
+
uses: ./.github/workflows/sqlserver-integration.yml
|
|
74
|
+
|
|
75
|
+
oracle-integration-tests:
|
|
76
|
+
name: Oracle Integration Tests
|
|
77
|
+
uses: ./.github/workflows/oracle-integration.yml
|
|
78
|
+
|
|
79
|
+
multi-python-tests:
|
|
80
|
+
name: Multi-Python Version Tests
|
|
81
|
+
runs-on: ubuntu-latest
|
|
82
|
+
timeout-minutes: 20
|
|
83
|
+
strategy:
|
|
84
|
+
fail-fast: false
|
|
85
|
+
matrix:
|
|
86
|
+
python-version: ["3.10", "3.11", "3.12", "3.13"]
|
|
87
|
+
steps:
|
|
88
|
+
- name: Checkout code
|
|
89
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
90
|
+
with:
|
|
91
|
+
persist-credentials: false
|
|
92
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
93
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
94
|
+
with:
|
|
95
|
+
python-version: ${{ matrix.python-version }}
|
|
96
|
+
- name: Install uv
|
|
97
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
98
|
+
with:
|
|
99
|
+
enable-cache: true
|
|
100
|
+
- name: Install dependencies
|
|
101
|
+
run: |
|
|
102
|
+
uv sync --locked
|
|
103
|
+
- name: Run tests (excluding integration)
|
|
104
|
+
run: |
|
|
105
|
+
uv run pytest tests/ --ignore=tests/integration --tb=short -v
|
|
106
|
+
|
|
107
|
+
build:
|
|
108
|
+
name: Build
|
|
109
|
+
runs-on: ubuntu-latest
|
|
110
|
+
timeout-minutes: 15
|
|
111
|
+
needs: [security-audit, pre-commit, bigquery-integration-tests, pyspark-integration-tests, snowflake-integration-tests, sqlserver-integration-tests, oracle-integration-tests, multi-python-tests]
|
|
112
|
+
permissions:
|
|
113
|
+
contents: write
|
|
114
|
+
id-token: write
|
|
115
|
+
attestations: write
|
|
116
|
+
env:
|
|
117
|
+
CI_COMMIT_MESSAGE: Continuous Integration Version Bump ${{ inputs.release }}
|
|
118
|
+
steps:
|
|
119
|
+
# zizmor: ignore[artipacked] this job pushes the version-bump commit and
|
|
120
|
+
# tag, so it requires the GITHUB_TOKEN persisted by actions/checkout. Only
|
|
121
|
+
# dist/ is uploaded as an artifact, not .git/, so the token is not exposed.
|
|
122
|
+
- name: Checkout # zizmor: ignore[artipacked]
|
|
123
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
124
|
+
- name: Setup Python
|
|
125
|
+
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
|
126
|
+
with:
|
|
127
|
+
python-version: "3.11"
|
|
128
|
+
- name: Install uv
|
|
129
|
+
uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2
|
|
130
|
+
with:
|
|
131
|
+
enable-cache: true
|
|
132
|
+
- name: Install Dependencies
|
|
133
|
+
run: uv sync --locked --group dev
|
|
134
|
+
- name: Bump Version
|
|
135
|
+
run: |
|
|
136
|
+
uv run python - <<EOF
|
|
137
|
+
from tomlkit import parse, dumps
|
|
138
|
+
from tomlkit.toml_file import TOMLFile
|
|
139
|
+
file = TOMLFile("pyproject.toml")
|
|
140
|
+
doc = file.read()
|
|
141
|
+
version = doc["project"]["version"]
|
|
142
|
+
release = "${{ inputs.release }}"
|
|
143
|
+
major, minor, patch = map(int, version.split('.'))
|
|
144
|
+
if release == "major":
|
|
145
|
+
new_version = f"{major + 1}.0.0"
|
|
146
|
+
elif release == "minor":
|
|
147
|
+
new_version = f"{major}.{minor + 1}.0"
|
|
148
|
+
elif release == "patch":
|
|
149
|
+
new_version = f"{major}.{minor}.{patch + 1}"
|
|
150
|
+
doc["project"]["version"] = new_version
|
|
151
|
+
file.write(doc)
|
|
152
|
+
print(f"New Version: {new_version}")
|
|
153
|
+
EOF
|
|
154
|
+
echo "RELEASE_TAG=$(uv run python -c 'from tomlkit.toml_file import TOMLFile; print(TOMLFile("pyproject.toml").read()["project"]["version"])')" >> $GITHUB_ENV
|
|
155
|
+
- name: Build package
|
|
156
|
+
run: uv build
|
|
157
|
+
- name: Attest build provenance
|
|
158
|
+
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
|
|
159
|
+
with:
|
|
160
|
+
subject-path: "dist/*"
|
|
161
|
+
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
162
|
+
with:
|
|
163
|
+
name: build
|
|
164
|
+
path: dist/
|
|
165
|
+
retention-days: 1
|
|
166
|
+
- name: GIT commit and tag
|
|
167
|
+
run: |
|
|
168
|
+
git config user.name 'github-actions[bot]'
|
|
169
|
+
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
|
170
|
+
git add pyproject.toml
|
|
171
|
+
git commit -m "$CI_COMMIT_MESSAGE"
|
|
172
|
+
git push
|
|
173
|
+
echo "Tagging new version: $RELEASE_TAG"
|
|
174
|
+
git tag -a "$RELEASE_TAG" -m "Auto-generated tag"
|
|
175
|
+
git push origin "$RELEASE_TAG"
|
|
176
|
+
- name: Create release
|
|
177
|
+
env:
|
|
178
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
179
|
+
run: gh release create "$RELEASE_TAG" --generate-notes
|
|
180
|
+
pypi-publish:
|
|
181
|
+
name: Upload release to PyPI
|
|
182
|
+
runs-on: ubuntu-latest
|
|
183
|
+
timeout-minutes: 10
|
|
184
|
+
needs: build
|
|
185
|
+
environment:
|
|
186
|
+
name: production
|
|
187
|
+
url: "https://pypi.org/project/openretailscience"
|
|
188
|
+
permissions:
|
|
189
|
+
id-token: write
|
|
190
|
+
steps:
|
|
191
|
+
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
|
192
|
+
with:
|
|
193
|
+
name: build
|
|
194
|
+
path: dist
|
|
195
|
+
- name: Publish package distributions to PyPI
|
|
196
|
+
uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
|
|
197
|
+
with:
|
|
198
|
+
attestations: true
|
|
199
|
+
deploy-docs:
|
|
200
|
+
name: Deploy Documentation
|
|
201
|
+
needs: pypi-publish
|
|
202
|
+
permissions:
|
|
203
|
+
contents: read
|
|
204
|
+
pages: write
|
|
205
|
+
id-token: write
|
|
206
|
+
uses: ./.github/workflows/gh-page.yml
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
name: Security Audit
|
|
2
|
+
|
|
3
|
+
# Scans the resolved dependency lockfile (uv.lock) for known vulnerabilities
|
|
4
|
+
# using OSV-Scanner. Because it reads uv.lock statically, it audits every pinned
|
|
5
|
+
# version across all supported Python versions (3.10-3.13) and platforms.
|
|
6
|
+
# Results are uploaded to GitHub code scanning (Security tab) as SARIF, so a
|
|
7
|
+
# newly-disclosed CVE in a pinned dependency surfaces as a failing check and a
|
|
8
|
+
# code-scanning alert rather than a passive Dependabot alert.
|
|
9
|
+
#
|
|
10
|
+
# Suppressions (each with a rationale, and an ignoreUntil expiry where a fix may
|
|
11
|
+
# yet appear) live in osv-scanner.toml at the repo root.
|
|
12
|
+
#
|
|
13
|
+
# On pull requests the scan runs only when dependencies or this workflow change,
|
|
14
|
+
# and is advisory (results still post to code scanning); pushes to main (same
|
|
15
|
+
# path filter) refresh the default-branch code-scanning state, and manual
|
|
16
|
+
# dispatches and release calls are hard gates. Detection of newly-disclosed CVEs
|
|
17
|
+
# against already-pinned dependencies (with no repo change) is left to Dependabot
|
|
18
|
+
# alerts and security updates, so no scheduled scan is needed here.
|
|
19
|
+
|
|
20
|
+
on:
|
|
21
|
+
pull_request:
|
|
22
|
+
types: [opened, synchronize]
|
|
23
|
+
paths:
|
|
24
|
+
- "uv.lock"
|
|
25
|
+
- "pyproject.toml"
|
|
26
|
+
- "osv-scanner.toml"
|
|
27
|
+
- ".github/workflows/security-audit.yml"
|
|
28
|
+
push:
|
|
29
|
+
branches: [main]
|
|
30
|
+
paths:
|
|
31
|
+
- "uv.lock"
|
|
32
|
+
- "pyproject.toml"
|
|
33
|
+
- "osv-scanner.toml"
|
|
34
|
+
- ".github/workflows/security-audit.yml"
|
|
35
|
+
workflow_dispatch:
|
|
36
|
+
workflow_call:
|
|
37
|
+
|
|
38
|
+
permissions: {}
|
|
39
|
+
|
|
40
|
+
concurrency:
|
|
41
|
+
group: "security-audit-${{ github.ref }}-${{ github.event_name }}"
|
|
42
|
+
cancel-in-progress: true
|
|
43
|
+
|
|
44
|
+
jobs:
|
|
45
|
+
osv-scan:
|
|
46
|
+
name: OSV-Scanner (uv.lock)
|
|
47
|
+
runs-on: ubuntu-latest
|
|
48
|
+
timeout-minutes: 10
|
|
49
|
+
permissions:
|
|
50
|
+
contents: read
|
|
51
|
+
security-events: write # upload SARIF to code scanning
|
|
52
|
+
steps:
|
|
53
|
+
- name: Checkout
|
|
54
|
+
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
|
55
|
+
with:
|
|
56
|
+
persist-credentials: false
|
|
57
|
+
- name: Run OSV-Scanner
|
|
58
|
+
id: osv
|
|
59
|
+
continue-on-error: true # gate is enforced explicitly below, after SARIF upload
|
|
60
|
+
uses: google/osv-scanner-action/osv-scanner-action@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8
|
|
61
|
+
with:
|
|
62
|
+
scan-args: |-
|
|
63
|
+
--config=osv-scanner.toml
|
|
64
|
+
--format=sarif
|
|
65
|
+
--output=results.sarif
|
|
66
|
+
--lockfile=uv.lock
|
|
67
|
+
- name: Upload results to code scanning
|
|
68
|
+
# Skip cleanly if the scanner errored before writing the SARIF, rather
|
|
69
|
+
# than erroring and being swallowed by continue-on-error.
|
|
70
|
+
if: always() && hashFiles('results.sarif') != ''
|
|
71
|
+
continue-on-error: true # never let SARIF upload (e.g. missing perms) break the gate
|
|
72
|
+
uses: github/codeql-action/upload-sarif@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1
|
|
73
|
+
with:
|
|
74
|
+
sarif_file: results.sarif
|
|
75
|
+
category: osv-scanner
|
|
76
|
+
- name: Enforce gate
|
|
77
|
+
# Pull requests are advisory only (results still post to code scanning);
|
|
78
|
+
# every other trigger is a hard gate. Fail closed: block unless the scan
|
|
79
|
+
# completed successfully, so a failed, errored, or skipped scan never
|
|
80
|
+
# passes the gate. !cancelled() (rather than always()) avoids marking a
|
|
81
|
+
# concurrency-superseded run as failed; a real timeout still blocks
|
|
82
|
+
# downstream via the job's needs dependency.
|
|
83
|
+
if: ${{ !cancelled() && github.event_name != 'pull_request' && steps.osv.outcome != 'success' }}
|
|
84
|
+
run: |
|
|
85
|
+
echo "::error::OSV-Scanner did not complete cleanly (vulnerabilities found or scan failed) — see the SARIF results in the Security tab."
|
|
86
|
+
exit 1
|