Compare commits

...

692 Commits

Author SHA1 Message Date
Jakub Chodorowicz
42e3a98805 add split openapi to the repo 2026-03-06 16:02:32 +01:00
Jakub Chodorowicz
245825e10e fix paths in openapi scripts 2026-03-02 10:21:11 +01:00
Jakub Chodorowicz
b0b2b597ab cleanup openapi scripts 2026-03-02 10:12:50 +01:00
Jakub Chodorowicz
3eaf107895 split openapi into separate components, paths 2026-03-02 10:07:50 +01:00
Romeo Van Snick
d54e6b64e2 Convert parameters to typescript (#70137)
* Convert parameters to TypeScript

* Fix types

* Fix types in normalizeValue

* Fix types in dashboard tests

* Fix more types

* Fix test

* Remove duplicate check

* Naming
2026-03-02 17:07:10 +11:00
metabase-bot[bot]
763d5e1777 [chore] Update E2E test timings with recent data (#70236)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-03-02 12:16:14 +13:00
Fraser
b746306e12 Convert VisualizationError utils to TypeScript (#69062)
* Convert VisualizationError utils to TypeScript

Closes DEV-1407

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-02 11:53:39 +13:00
Fraser
f0c90980ff Convert DefaultParametersSection to TypeScript (#69075)
* Convert DefaultParametersSection to TypeScript

Closes DEV-1420

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-03-02 11:53:21 +13:00
Egor Grushin
e53f226b40 GDGT-1852 fix ui issues in Data Summary tab in Transform Inspector (#70150)
* GDGT-1852 fix ui issues
2026-03-01 22:48:32 +00:00
Romeo Van Snick
40cbf2ffb5 Avoid updating url when navigating to query builder (#68982)
* Use Question.serializeCardForUrl for consistency

* Convert metabase/lib/card to typescript

* Remove broken createCard helper

* Fix types

* Remove unused parameter

* Remove entityId from cards

* Remove createCard tests

* Avoid renaming Card to CardObject for no reason

* Also allow serializing UnsavedCard

* Make options optional

* Simplify serializeCardForUrl

* Make serializeCardForUrl implementation match the Question.serializeCardForUrl implementation

* Use serializeCardForUrl from metabase/lib/card

* Use serializeCardForUrl from metabase/lib/card

* Use stable stringify for url hashes

* Remove unnecessary _serializeForUrl helper

* Correctly ignore possibly infinite type instantiations

* Fix unit tests

* Allow passing parameterValues

* Fix comparison

* Coerce values to undefined

* Update unit tests

* Remove duplicate key

* Make cards optional
2026-03-02 08:38:55 +11:00
Braden Shepherdson
55a0afbd2a [MBQL lib] Stop using ID-based refs for fields from joined cards (#70116)
Fixes QUE2-383.

Uses `:lib/card-id` in metadata to check if a column came from a card at any point.
If so, it should use a name-based `:field` ref rather than an ID-based one.
This makes the refs to joined columns consistent with those to main source columns,
based on whether the source is a table or card.
2026-02-28 20:10:19 +00:00
Robert Kosara
f759d9f473 Docs: Tenant attributes and collections improvements (#70179)
* Tenant attributes and collections improvements

First round of edits to add the ability to create tenant attributes using SSO.

* Revise tenant-specific access for non-admin internal users

* Edits based on Alberto's comments

* Move tenant claims info to claims section, link to it from attributes

* Apply suggestion from @alexyarosh

Co-authored-by: Alex Yarosh <alexandra@metabase.com>

* Moved tenant attribute logic and simplified sentence

* Fix a sentence, improve code example, and clean up permissions bullet points

---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-02-27 13:46:20 -08:00
Uladzimir Havenchyk
39951a570a chore: make entity copy modal generic (#70018)
* chore: convert dashcard related redux components to typescript

* fixup

* address review

* another review iteration

* chore: make entity copy modal generic

* chore: convert dashcard related redux components to typescript

* fixup

* address review

* another review iteration

* add a missing import

* type cleanup

* address review
2026-02-28 00:07:56 +03:00
Alex Yarosh
6b369ef818 docs: writeable connection (#70210)
* writeable connection

* Optimized 1 images, saved 89.0 KB (46.9% smaller)

* routing notes

* typos

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-02-27 14:33:37 -05:00
Nemanja Glumac
f3c352d920 Increase viewport to reduce "extract column" flakes (#70206) 2026-02-27 20:06:00 +01:00
Anderson
9c0576cc5c Add snowplow event for opening Data Studio (#69880)
* Add snowplow event for when opening Data Studio

* Update triggered_from
2026-02-27 18:21:02 +00:00
Nemanja Glumac
fc00027fca Migrate away from deprecated Cypress.env() API (#70189)
As of Cypress 15.10.0, `Cypress.env()` is deprecated. This commit migrates
all usages to the new recommended APIs:

- Non-sensitive config values → `Cypress.expose()` (synchronous)
- Sensitive token values → `cy.env()` (asynchronous)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-27 19:03:29 +01:00
Ngoc Khuat
3be69174e6 Improve logging around notifications (#70099) 2026-02-27 16:55:43 +00:00
Nicola Mometto
11a73d8621 Add position field to dashboard parameters for stable serialization (#70107)
* revert sorting by id on parameters serialization, parameters ordering is significant and must be preserved

* revert, we're storing position

* feat: add :position to parameters, backfill

* feat: backfill position on imported parameters

* chore: tests

* FE: update position

* chore: gitignore python-sources.lock

* chore: ensure we get position

* restrict to dashboard params

* tests

* simpler approach: just sort by position on serialization export/import
2026-02-27 16:06:32 +00:00
Dan Stone
d1e7b483dd Prefer SQL DML for insert-from-source! to fix bigquery metadata consistency (#69753)
The legacy .insertAll API (and newer Storage API) do not work well with
tables that are created/dropped frequently. This is because their
metadata caches can take a long time to up date.

Python transforms use the drop-recreate fallback strategy for bigquery
so we observe this inconsistency for every run after the first, even
with absurd multi minute timeouts.

The SQL API does not have a problem, so we'll use that. We expect a
performance regression but its better to work slowly than not work at
all.

Other changes:

- Removed now redundant bigquery retry loop

- Dropped dictionary support, we cannot support it easily and it cannot be
considered higher prio than bigquery working at all.

- Added correct parameter typing for JSON.

- Fixed ordering issues in tests (assumed row order when it is
non-deterministic)
2026-02-27 15:47:58 +00:00
Ngoc Khuat
aa66ab25d6 Simplify notification result data flow (#70115) 2026-02-27 21:58:54 +07:00
Edward Paget
8207fc3181 feat: error code on streaming response throw/fail (#62351)
* fix: real error codes in streaming responses

* fixup! try faking old errors deeper in the stack

* fixup! wrap fetch endpoint in embedding too

* fixup! treat string only errors differently

* fixup! handle errors in a couple other places

* fixup! hard to figure out what kind of error it is

* fixup! typecasts

* fixup! test arity

* fixup! remove blanket 403 page from dataset

* fixup! simplify backend 403 responses

* fixup! a couple missed tests

* fixup! add mockresponse for mockclient

* fixup! other failing tests

* fixup! last failing test

* fixup! add another OSS check

* fixup! one more oss test

* fixup! update status codes on some more tests

* fixup! use committed function
2026-02-27 09:42:20 -05:00
Nicolò Pretto
b429839f0a remove sdk import error on core app e2e tests (#70188)
try to untangle imports
2026-02-27 14:41:19 +01:00
Jakub Chodorowicz
451f080ede add new variants to action icon and use it in Inspector Header cell (#70180)
* add new variants to action icon and use it in Inspector Header cell

* add is-active state
2026-02-27 12:10:07 +01:00
Dan Stone
4f00289729 Fix bigquery routing test (#70154)
- Was using wrong project / creds
- Using two different sha names only worked when shas were not used as
qualifiers in the query (they are for bigquery)

Added the ability to override the hash-key used for tx/hash-dataset to
support forcing a hash collision (as is required by routing).
2026-02-27 10:58:14 +00:00
Maksym Yakubych
369d410d4d fix: new SQL questions automatically open DataReference sidebar (#70120) 2026-02-26 21:09:43 +00:00
Nicola Mometto
b8c13482df fix: replace usage of source-table-id with primary-source-table-id (#70162) 2026-02-26 14:24:20 -05:00
Sloan Sparger
126eb6b1b1 [Metabot] Prevent OSS SQL gen UI from showing in cloud migrated instances (#69649)
prevent oss sql gen ui from showing for customsers with had set it up locally and migrated to cloud
2026-02-26 12:54:41 -06:00
Noah Moss
4ab19dce4d Ring middleware for public sharing endpoints (#70153)
* Ring middleware for public sharing endpoints

* Refactor test

* move +public-sharing-enabled to address module lint

* Fix documents test
2026-02-26 12:59:54 -05:00
Braden Shepherdson
39b4a21830 [MBQL lib] Refactor a common pattern into new lib functions (#68474)
Many uses of `lib.util/source-card-id` and `source-table-id` were
followed by calling `lib.metadata/card` or `lib.metadata/table`
respectively.

This PR adds two new functions `lib.metadata.calculation/primary-source-card`
and `primary-source-table` which look up the card/table directly.

It also adds `lib.metadata.calculation/primary-source` for the handful
of places where whichever of `primary-source-card` or `primary-source-table`
returns non-nil gets used, such as in some drill-thrus.
2026-02-26 17:32:57 +00:00
Eric Normand
3ba0f90cf0 Automate mutation testing end-to-end with run! orchestrator (#70126)
- Adds a fully automated `run!` entry point to `dev.mutation-testing` that orchestrates the entire mutation testing workflow: generate report → create Linear project → group functions → write tests via `claude -p` → verify → retry →
  commit → create draft PRs
  - Replaces the previous manual, step-by-step SKILL.md instructions (which required the operator to execute each step) with Clojure functions that handle the full pipeline automatically
  - Key new functions: `parse-namespace`, `group-functions`, `build-test-prompt`, `invoke-claude!`, `verify-and-retry!`, `process-group!`, `print-summary!`

  ## Motivation

  The mutation testing workflow previously required ~20 manual steps per namespace, with the Claude operator interpreting skill instructions and running each step. This was slow, error-prone, and required constant supervision. Now you just
  call `(mut-test/run! 'metabase.lib.order-by)` and walk away.

  ## How it works

  1. **`parse-namespace`** — derives source/test paths, short names, auto-detects `.cljc` vs `.clj`
  2. **`group-functions`** — clusters private functions with their public entry points based on test overlap, skips fully-covered functions
  3. **`build-test-prompt`** — assembles a prompt with function source, existing tests, and surviving mutations
  4. **`invoke-claude!`** — shells out to `claude -p` with scoped tool access (`Edit`, `Read`, `Bash(clj-nrepl-eval*)`)
  5. **`verify-and-retry!`** — checks which mutations were killed, retries up to 2x with targeted prompts for survivors
  6. **`process-group!`** — full per-group pipeline: branch → invoke Claude → verify → commit & push → Linear issue → draft PR
  7. **`run!`** — ties it all together, catches errors per group so one failure doesn't stop the batch
2026-02-26 09:51:59 -07:00
Nemanja Glumac
6e799b2ef6 Bump Cypress retries to two (#70157) 2026-02-26 17:42:51 +01:00
Dan Stone
dcd2d7394d Fix snowflake integer type (#70031)
BigInteger is observed
2026-02-26 16:04:33 +00:00
Aleksandr Lesnenko
3c693179e4 fix content translations break visualization settings (#70054)
* fix content translation produces unstable translated keys in viz settings
2026-02-26 10:54:11 -05:00
Braden Shepherdson
b01732fd69 [perf] Tools to repro query + metadata locally, given instance API access (#67952)
Given browser or API access to a Metabase instance, the tools in this PR
can recursively fetch cards and all the metadata (tables, fields, etc.)
required to run them through QP preprocessing and compilation.

Of course this cannot actually _execute_ the compiled form, since you
don't have access to the user's DWH, but it enables debugging of
hard-to-reproduce user bug reports in your local REPL.

This works by making API calls like `/api/card` and
`/api/card/query_metadata` until a complete picture of the metadata is
acquired. This is poured into a `MetadataProvider`, which is all the QP
needs to analyze and compile the query.
2026-02-26 15:49:56 +00:00
Nicola Mometto
a75ee49fd1 restrict a transform inspector test to sql (#70152)
fix: restrict to sql drivers
2026-02-26 15:23:21 +00:00
Eric Normand
dbfe313b4a Filter transforms based on permissions GHY-3152 (#70125)
Filter transforms based on permissions

We were leaking transforms in the :bad_transforms key
2026-02-26 14:55:12 +00:00
github-automation-metabase
088bd180d5 Auto-update documentation for master (#70133)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-26 09:46:51 -05:00
metabase-bot[bot]
0226eaa5d2 [chore] Update E2E test timings with recent data (#69996)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-26 15:04:49 +01:00
Nicola Mometto
3d68aa1ac4 feat: restrict join-analysis to only table-level join analysis (#70105) 2026-02-26 13:08:34 +00:00
Nemanja Glumac
c18c08b02c Pin patched libraries to their patched version (#70143) 2026-02-26 13:02:41 +01:00
Katya Voropaieva
851bedf5bb Update v59 sample Examples visualizations and dashboard. (#70075)
Adds Box Plot viz and a Scalar viz with conditional colors to the Example dashboard.
The resources/sample-content.edn was regenerated from the live instance content.
2026-02-26 10:45:57 +01:00
Uladzimir Havenchyk
9981cd5323 chore: convert dashboard reducer to typescript and rtk (#69842)
* chore: convert dashboard reducer to typescript

* convert to rtk

* use immer when possible

* fixup

* Apply suggestion from @kamilmielnik

I checked it locally and it is indeed unnecessary guard

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>

---------

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
2026-02-26 11:47:52 +03:00
Uladzimir Havenchyk
264604b61e chore: convert dashcard mapping files to ts (#69836) 2026-02-26 10:30:10 +03:00
Sébastien
a5a0773eaf Migrate ChartTypeDropdown to use Mantine ComboBox (#69734)
* Migrate ChartTypeDropdown to use Mantine ComboBox

* test fixes

* .

* .

* .

* .

* screenshot
2026-02-26 10:56:02 +07:00
Romeo Van Snick
c463756c60 Remove deprecated unit test helpers (#69275)
* Replace createQueryWithClauses with createTestQuery

# Conflicts:
#	frontend/src/metabase-lib/test-helpers.ts
#	frontend/src/metabase/querying/filters/hooks/use-date-filter/use-date-filter.unit.spec.ts

* Remove unnused helpers

# Conflicts:
#	frontend/src/metabase-lib/test-helpers.ts

* WIP

* Export createMetadataProvider

* Use Lib.createTestHelper

* Remove createQuery helper usage

* Remove createQuery helper

* Remove unneeded getJoinQueryHelpers

* Fix test

* Remove DEFAULT_QUERY

* Move or remove unneeded test helpers

* Fix lint

* Allow auto binning in test spec

* Fix test

* Allow disamiguating column name by index

* Fix tests

* Fix imports
2026-02-26 13:09:27 +11:00
Romeo Van Snick
0f7e8983ca Metakey helper (#68987)
* Use H.metaKey where applicable

* Add helper for meta key options

* Fix import

* Update more instances

* Fix test
2026-02-26 00:51:03 +00:00
Sloan Sparger
3401c9e902 Fix e2e dashboard-questions.cy.spec.js scrollTo flakes (#70114)
* invert assertions about scrollTo hash param and instead assert on visibility

* update e2e/test/scenarios/question/saved.cy.spec.js

* try to improve flakiness

* trying something dumb
2026-02-25 16:22:00 -06:00
Eric Normand
0aeda87a3d [Mutation Testing] Kill mutations in metabase.lib.field/fingerprint-based-default-unit (#69319)
Part of the mutation testing project for metabase.lib.field.

Closes QUE2-338

Functions
Stats
Surviving mutations before: 16
Tests added: 1
Mutations killed by this PR: 16
Mutations remaining: 0
Mutations killed
Replace fingerprint with nil
Replace :type with :type__
Replace :type/DateTime with :DateTime__
Replace let with comment
Replace earliest with nil
Replace latest with nil
Replace when-not with when
Replace days with nil
Replace > with >=
Replace > with nil
Replace days with nil
Replace 1 with 0
Replace :minute with :minute__
Replace 31 with 0
Replace 365 with 0
Replace :week with :week__
Mutations not killed (with rationale)
Replace :day with :day__ — available-temporal-buckets-for-type has its own internal default of :day for datetime types, so the :day return value from fingerprint-based-default-unit is redundant with the fallback
2026-02-25 22:07:25 +00:00
metamben
b1ece80c0d Support DB-local settings in the JVM and JS metadata-providers (#70117)
Closes QUE2-292
2026-02-25 21:52:17 +00:00
metamben
486a6fc826 Add test to prove that #35842 has been fixed (#70080)
Closes #35842
2026-02-25 21:25:19 +00:00
Eric Normand
29f75c1251 test: mutation tests for column-metadata-effective-type and nest-display-name (#69328)
* [Mutation Testing] Add tests for metabase.lib.field/fieldable-columns

* test: add mutation tests for column-metadata-effective-type and nest-display-name

Adds tests that exercise:
- type-of fallback to :base-type when :effective-type is absent
- type-of preference for :effective-type over :base-type
- temporal extraction returning :type/Integer
- temporal truncation preserving effective type
- nested field with nil parent display-name graceful fallback

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 21:03:39 +00:00
metamben
66dc6b6cdc Add test to prove that #57978 has been fixed (#70076)
Closes #57978
2026-02-25 23:37:16 +03:00
metamben
7433f38a22 Make visible-columns for cards respect field visibility (#70040)
Closes QUE2-5
2026-02-25 23:36:59 +03:00
Cam Saul
71606de98c Test to prove #28060 is fixed 🔧 (#69865)
* Test to prove #28060 is fixed 🔧

* Update src/metabase/driver/mysql.clj

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>

* Update src/metabase/driver/mysql.clj

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>

* Fix syntax error from PR feedback suggestion

* Test fix 🔧

* Fix 🔧

---------

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2026-02-25 17:25:35 +00:00
Braden Shepherdson
d2e8fcac5b [MBQL lib] Export some healthy API functions; drop some API nses (#69666)
Fixes QUE2-350.

There are two changes here:
- Exporting some legit public functions from `lib.core`
- "Befriending" the `enterprise/sandbox` and `lib-be` modules, which are
  deeply coupled to lib and MBQL in any case.

That allows us to remove several exported namespaces:
- `lib.binning`
- `lib.convert`
- `lib.field`
- `lib.metadata.cached-provider`
- `lib.metadata.column`
- `lib.metadata.invocation-tracker`
- `lib.metadata.result-metadata`
- `lib.normalize`
- `lib.query`
- `lib.temporal-bucket`
- `lib.walk`

The functions newly exported from `lib.core` are:

- `lib.field/infer-has-field-values`, called from some BE API handlers
  and AppDB readers, producing a "cooked" value the FE wants rather than
  exposing details of how `:model/FieldValues` is stored. Single-use,
  but a legitimate export.
- `lib.field/json-field?`, checks if the passed in field is a JSON field,
  that's a valid export used in a few places.
- `lib.query/native?`, checks if the first stage of this query is native,
  that's another legit export used in a few places.

`lib.normalize/normalize` and `lib.query/query` were already exported, I
updated some usages of those functions to `lib/foo` instead.
2026-02-25 10:37:07 -05:00
github-automation-metabase
e4d1706837 Auto-update documentation for master (#70096)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-25 10:14:22 -05:00
Uladzimir Havenchyk
cc1361936a convert dashboard redux related files to typescript (#69797)
* chore: convert dashcard related redux components to typescript

* fixup

* address review

* another review iteration

* add a missing import

* cleanup
2026-02-25 17:40:38 +03:00
Nemanja Glumac
69c0a2ca90 Upgrade Cypress to v15.10.0 (#69839) 2026-02-25 15:14:45 +01:00
Ngoc Khuat
3d3bbe22db Move pulse preview endpoints to dev-only (#70068) 2026-02-25 11:15:00 +00:00
Romeo Van Snick
ba0ddc9a32 Only switch to full-width native preview at small breakpoint (#70048)
* Only switch to full-width native preview at small breakpoint

* Add e2e test for metabase#67767
2026-02-25 20:22:46 +11:00
Fraser
da223ea0a1 Updated Chromium to v144 in Cypress (#69721)
* Bump chrome to v144
2026-02-25 21:07:41 +13:00
Noah Moss
f53c8d1513 Always run Metabot-triggered refingerprinting in admin context to match sync behavior (#70087)
* always run fingerprinting in admin perms context

* address comment
2026-02-24 17:47:22 -05:00
Fraser
51d7669d7d Convert admin/permissions/utils/urls to TypeScript (#69432)
* Convert `admin/permissions/utils/urls` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1510

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* improve type guard

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Uladzimir Havenchyk <uladzimir@metabase.com>
2026-02-25 10:18:09 +13:00
Anton Kostenko
eb20991259 Fix PR envs cleaning (#70024)
* Fix PR envs cleaning

* Add manual dispatch for pr env destroy
2026-02-24 15:16:50 -05:00
Nicolò Pretto
ec4874cfe5 re-generate lock file to remove stale deps (#70062)
* re-generate lock file to remove stale deps

* add sample apps to the deps for the package
2026-02-24 19:02:35 +01:00
Ngoc Khuat
8f442ca39b Add diagnostic logging for duplicate alert investigation (#70020) 2026-02-24 17:20:02 +00:00
Nicola Mometto
8c6e4aa60b Ensure we can resolve map lookups (#70060)
* feat: explicit handlebars context

* chore: unit tests
2026-02-24 13:53:19 +00:00
Nemanja Glumac
3d3d49dfca Automate Crowdin context harvester and trigger pre-translation (#70035) 2026-02-24 11:11:15 +01:00
Nicolò Pretto
bba60088cb emb-1300: use plugin for handleLink in eajs and fix double sdk plugin init (#69961)
* emb-1300: use plugin for handleLink in eajs and fix double sdk plugin init

* typo and fix unit test

* restore old comment
2026-02-24 09:25:38 +01:00
metamben
981113ef47 Use lib namespace on properties instead of real namespace names (#69808)
* Use lib namespace on properties instead of real namespace names

Closes QUE2-279
2026-02-23 22:53:37 +00:00
Braden Shepherdson
9c8e505c9f [QP] Move logging-only work inside the log/* call (#68362)
Move some logging-only computations into the `(log/* ...)` call so it won't be executed
unless the log level is sufficiently verbose for the log to actually be output.
2026-02-23 16:19:03 -05:00
Noah Moss
f4bbf2984f Add some better defaults & limits to agent API (#70033) 2026-02-23 15:35:18 -05:00
metamben
273f1677a1 Add tests for calculated display_name and fix nested name handling (#69982)
Closes QUE2-288
2026-02-23 23:23:58 +03:00
metamben
12e6b46118 Support all kinds of identity types on sqlserver (#69871)
Closes QUE2-251
2026-02-23 23:23:17 +03:00
Fraser
f27597b904 Convert AddEditSidebar to TypeScript (#69421)
* Convert AddEditSidebar to TypeScript (DEV-1499)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-24 08:45:56 +13:00
bryan
b2889824b3 Fix flaky count-of-grouping-test for Redshift by using UTC timezone (#67196)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-23 19:18:07 +00:00
Jeff Bruemmer
28cfae2e67 docs - table variables and snippets (#69983)
table variables and snippets
2026-02-23 11:34:02 -05:00
github-automation-metabase
60707e20ec Auto-update documentation for master (#70009)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-23 11:21:09 -05:00
bryan
a4e418f280 Fix OpenAPI 3.1.0 validation errors and add CI workflow (#69948) 2026-02-23 09:13:33 -07:00
Stas Gavrylov
c20bf2a943 GDGT-1755: Migrate common components to TypeScript (partial) (#69354)
* GDGT-1755: Migrate Text to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate Label to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate Subhead to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate IconWrapper to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate LabelIcon to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate use-scroll-on-mount to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Missed TS fixes

* GDGT-1755: Migrate QueryButton to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Migrate IconBorder to TS

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Remove Text.tsx wrapper, import from metabase/ui directly

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* GDGT-1755: Adjust line height in places using new Text component

* GDGT-1755: Fix styling inconsistencies

* Update frontend Claude guidelines for typecheck/linting to use bun

* GDGT-1755: Address PR comments

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 18:13:01 +02:00
Alexander Polyankin
c66d31fec1 Drop table created in a e2e test (#70023)
* drop table created in a e2e test

* fix
2026-02-23 10:43:37 -05:00
Egor Grushin
93cb3bc327 lock a card display type for the VisualizationCard (#70016)
lock a card display type for the VisualizationCard in the transform inspector
2026-02-23 14:55:23 +00:00
Timothy S. Dean
52325a7503 Write Connections for Actions, Model Persistence, Uploads (#69878) 2026-02-23 09:15:35 -05:00
Fraser
dadf042982 Convert ExpandableString to TypeScript (#69084)
Closes DEV-1429

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-23 15:49:29 +02:00
Dan Stone
18e1fb02aa Revert turning on snowflake/bq tests for transform (#70017)
Revert "Re-enable Python transform tests for BigQuery and Snowflake (#67685)"

This reverts commit b6c1a51630.
2026-02-23 12:41:22 +00:00
Egor Grushin
5dd8b26770 getting rid of annoying warnings (#69975) 2026-02-23 12:17:08 +00:00
Dan Stone
b6c1a51630 Re-enable Python transform tests for BigQuery and Snowflake (#67685)
These tests were temporarily disabled on 2025-09-26 due to flakes.
Re-enabling them now to restore full test coverage.

Lets monitor and see what happens
2026-02-23 10:38:56 +00:00
Nicola Mometto
09ee4178ca Transforms inspector (#68675)
* wip: transform inspector BE

* WIP: inspect tables

* wip

* format join info as code

* wip: join info

* style

* add join stats type and display match rate

* chore: row

* chore: remove limit

* wip

* handle differerent cases for match rate and row count

* add joins table display and icons

* fix copy

* fix missing join table names

* cleanup

* cleanup

* extend match

* fix missing source table type

* add join tooltip

* chore: with join info

* wip

* wip

* add field statistics dummy component

* small ui adjustments

* small ui adjustments

* add filled rows

* order input columns like joins

* update visualization card styling

* wip: update join calc to be iterative

* add target and source stats

* add target and source stats, a filter by output fields and a tab for unmapped fields

* add target and source stats, a filter by output fields and a tab for unmapped fields

* chore: sort by order

* fix: inverse map

* add cross product warning

* add null join warning

* small QoL UI improvements

* wip: render output_row_count

* wip: native joins

* fix a bug with conditional rendering

* wip: try to pull out useful fields

* WIP: claude'd UI selection of visited_fields

* use default automatic display selection logic

* add transform mock page with mock summary section

* add mock api console log

* fix fetch wrong query metadata

* add mock lenses

* add mock lenses api

* REVERTME: ignore for deploy

* feat: schemas

* require

* feat: degeneracy check

* WIP cljc api

* wip context

* wip lenses

* update comments

* chore: visited-fields

* wip

* wip: base

* wip: triggered lens

* wip: lib

* distinguish drill lenses

* fix: return visited-fields

* wip: v2 api

* WIP: vibe'd FE

* tabs/remove mock

* account for params

* params

* ui improvements

* fix

* show fingerprinting

* fingerprint layout

* use BE fallback

* handle more complex joins

* fallback to interesting fields

* fix trigger via cljc

* remove debug

* different text

* compute-card-results in cljs

* condition trigger in cljc

* semi working

* fix card_id correlation

* remove dead code

* rename BE to just inspector

* switch to new

* ensure transform is deleted

* chore: cleanup schema

* bring back the field fingerprint info

* move cljs out of lib

* fix: schema

* minor cleanup

* appease kondo

* kondo

* remove dead code

* feat: centralize native analysis in query_analisis

* chore: remove #p

* clean up

* Gdgt 1663 move fingerprints out of the lens to data inspect (#68996)

* [transforms inspector] depend on trunk macaw (#69022)

depend on trunk macaw

* fix lint and type issues (#69017)

* remove unused lib function

* fix infinite rendering loop

* fix type lib.interestingFields

* fix

* fix: ui bug

* chore: disable visited fields for now

* chore: better unmatched-rows

* chore: exclude not nulls

* minor tweaks

* minor tweaks

* rename

* chore: tighter contract

* minor optimisation

* Gdgt 1669 make cards clickable (#69116)

* Add card link

* link to hash of question

* add clickable title

* remove tooltip

* Use MBQL info to match columns whe npossible (#69120)

use mbql info for column matching

* Gdgt 1675 disable unmatched rows view details button in inspector (#69152)

* remove row index column

* adapt viz UI, hide row index column

* Unmatched rows lens: return cards for both LHS or RHS null scenarios (#69123)

* feat: handle both cases of no join match

* feat: simple degeneracy

* export function

* remove dead fields

* only propose drill lenses that are applicable (#69169)

* Transforms inspector consistent casing for FE (#69174)

* chore: consistency

* chore: some docstrings updats

* feat: snake_case for the FE

* feat: pass visitedFields to interestingFields, remove ad-hoc logic in FE (#69175)

feat: pass visitedFields to interestingFields, remove ad-hoc logic in the FE

* feat: namespace card-ids with params (#69180)

* add estimated lens complexity (hardcoded for now)  (#69181)

* add estimated lens complexity (hardcoded for now)

* refactor: use with-metadata

* add metadata to triggers, not just cards (#69182)

* appease kondo

* chore: don't depend on git sha macaw

* reinstate metabase-enterprise.transforms.core from merge conflict

* Gdgt 1722 new UI for data summary new (#69220)

* Transforms inspector BE tests  (#69225)

* feat: inspector tests

* fix: impls

* fix: nil safe

* feat: integration tests

* make it work for both FE and BE

* fix card-results for non oute rjoin

* e2e test

* fixes

* fix: quoting

* fix for mysql/bigquery/redshift

* gdgt-1721 rework lenses navigation (#69205)

* Transforms inspector module (#69278)

* split transforms inspector into its own module, introduce transforms-rest

* handle kondo modules warnings

* fix: shadow_cljs

* kondo: fixes

* Transforms inspector be review (#69339)

* chore: align

* remove useless comments

* feat: add schema to context

* feat: simplify column-matching

* fix: visited-fields

* fix test

* remove unused

* tighter schema

* extrac-sources test

* fix: missing metadata-provider

* Gdgt 1744 combine separate averages columns into one for data summary (#69355)

* gdgt-1723 New UI for Joins Analysis (#69325)

* Gdgt 1725 allow running transform from empty screen (#69394)

* chore: move crud functions on transforms, avoid -rest modules dependencies

* fix tests

* appease kondo

* fix modules

* fix: small UI bug

* Transforms orphaned columns (#69497)

* add orphaned columns to unmatched-rows analysis

* chore: update tests

* Transforms inspector analytics (#69484)

* feat: flow discover/lens through transform events

* track transform_id in query execution

* feat: add transform-inspector ids/params to query info

* feat: add inspector specific /query endpoint

* feat: hook FE to new api

* feat: add lens_id/params to view

* feat: add them to ua

* fix: pass params too

* fix: use text.type

* fix test

* chore: remove unused requires

* chore: events

* fix FE part

---------

Co-authored-by: Egor Grushin <egor@metabase.com>

* fix: use lib functions instead of manual mbql construction (#69519)

* fix: use lib functions instead of manual mbql construction

* chore: refactor utils

* cleanup

* more manipulation with lib

* bugfix

* strip fields/filters early

* do it in util function

* fix: bad merge resolution

* kondo

* another bad merge resolution

* chore: indent

* Gdgt 1754 handle slow loading lens indicator (#69334)

* lens loading indicator

# Conflicts:
#	frontend/src/metabase/transforms/pages/TransformInspectPage/TransformInspectPage.tsx
#	frontend/src/metabase/transforms/pages/TransformInspectPage/components/LensContent/LensContent.tsx

* add onCardLoaded handler to context

* Gdgt 1724 new UI column (#69282)

* Gdgt 1783 fix wrong args passed to lens query (#69546)

* fix wrong args being passed to lens queries

* improve naming of query parameters

* remove whitespaces from merge resolution

* add transforms api test

* feat: i18n the inspector strings (#69565)

* fix dark mode color issues (#69570)

fix bg fixed to white

* Gdgt 1737 use card metadata instead of parsing card ids (#69583)

* use card metadata instead of parsing ids

* improve way of getting the table name from cards

* use macaw still, TODO

* port some query-analysis to sql-tools (#69732)

* chore: port some query-analysis to sql-tools

* remove sql-tools from transforms

* chore: vendor macaw functions, appease kondo

* refactor

* chore: refactor

* side agnostic

* revert manual delete, closes https://linear.app/metabase/issue/GDGT-1730/pre-merge-blocker-revert-t2delete-on-transform-once-uxw-3021-is-fixed

* fix: always sync audit db on change

* dead code

* fix: use honeysql instead of building sql manually (#69774)

* GDGT-1791 Maximum depth error in console (#69754)

GDGT-1791 fix and refactor useCardLoadingTracker

* Gdgt 1651 add frontend e2e tests for transform inspector UI (#69677)

* GDGT-1823 make guarantee that LensContent is always stores one lens data (#69800)

* fix: 404 on lens not found (#69838)

* fix: 404 on lens not found

* chore: don't pmap

* fix: remove nil values from statistics

* fix

* Transforms inspector self review be (#69843)

* style

* chore: reuse resolve-join-sides

* add from-table-id for mbql queries too

* split context in mbql/native, don't union

* whitespace

* fix: preprocess native queries

* fix: update tests

* fix

* revert unrelated commit that made in the branch erroneously

* Gdgt 1812 better handle missing sources in lens inspector (#69848)

* Gdgt 1817 add snowplow product events fe (#69801)

* Add analytics events

# Conflicts:
#	frontend/src/metabase/transforms/analytics.ts

* add analytics tests

* simplify and improve lens loaded tracking event

* Move the idempotence check to useLensLoadedTracking

* GDGT-1831 replace unstyled button with a box to get rid of button in button error

* chore: transform lens_params

* GDGT-1786: Parametric lens navigation improvement (#69821)

* GDGT-1757: Refactor Column Comparison utils grouping and scoring logic (#69853)

* Improve types with entity ids (#69891)

* add concrete type declarations and usage for InspectorLensId, InspectorCardId, InspectorSectionId

* add better type to lens params

* cleanup of utils

* improve type for displaySettings

* use entity aliases in more places

* use existing type aliases for source and target

* add comment about InspectorTriggerCondition type

* unify prefix for inspector types

* remove spurious catch

* deduplicate types between metabase-api and lib

* Remove unused query

* fix provided tags for transform inspector

* add alerts and drill buttons test for default lens sections (#69899)

* restrict join analysis to single condition joins

* fix: bad merge reoslution

* fix types in lens test

* use isa function to detect type

* use concrete table id type alias

* use Urls.openInNewTab util

* remove empty mocks file

* use concrete table id type

* move lib for transform inspector to src/transforms/lib

* remove superflous log in e2e tests

* add proper SchemaName type

* remove superflous export

* revert move of isFetchBaseQueryError

* remove obsolete test

* use correct SchemaName type alias

* use correct VisualizationDisplay type

* remove leftover unused type

* remove superflous export

* Use CardId type alias

* discern lens also by based on params when tracking loading

* GDGT-1839 addressing the PR comments

* GDGT-1839 addressing the PR comments

* GDGT-1839 addressing the PR comments

* GDGT-1839 move getLensKey and LensHandle from api/tags directory

---------

Co-authored-by: Egor Grushin <egor@metabase.com>
Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
Co-authored-by: Jakub Chodorowicz <jakub@chodorowicz.com>
2026-02-23 10:16:35 +00:00
Ngoc Khuat
a68b644ec8 Add prominent CTA button per failed transform in failure email (#69458) 2026-02-23 14:51:28 +07:00
Fraser
ca002fd953 Convert app-embed and app-public to TypeScript (#69438)
* Convert `app-embed` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1516

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-23 09:49:58 +13:00
Anderson
ba5de0f2fa Show Python upsell on self hosted (#69759)
* Show Python upsell on self hosted

* Add e2e tests

* Fix unit test

* Simplify TransformsUpsellPage a bit more, fix tests

* Simplify logic

* Fix e2e and unit test

* Update self-hosted python upsell as per new design / Code clean up

* Fix unit test and also add a new one for useTransformsBilling

* Remove e2e tests to be moved to a new PR

* Fix cta link and bullet points icon alignment
2026-02-20 22:42:10 +00:00
Nathan Voxland
b4f717609e Add support for OpenID Connect (#69538) 2026-02-20 16:18:58 -06:00
Oleksandr Yakushev
3f898be45a [match] Implement replace-lite and use it instead of replace (#69270) 2026-02-20 23:39:57 +02:00
Edward Paget
071fc345b4 fix: better check for dirty collection state (#69974)
Our frontend code that prevents sending unchanged collections missed
tenant collections being added to the payload. This fixes both the
frontend to make sure we don't send when there are no changed
collections and it updates the backend actually check if collections are
being changed rather than just checking if the collections map exists.
2026-02-20 13:13:27 -06:00
Timofey Kachalov
08c4a89f91 fix(EmbedJS): Downloads fail on guest embedded questions (#69972) 2026-02-20 23:04:33 +04:00
Edward Paget
7d2d6571cb fix: transforms collections set setting on import (#69852)
* fix: transforms collections set setting on import

Also turns off the transforms sync setting if there are not transform
related models in the import

* fix: transform/snippet settings on collection sync

Updates our check for 'did transforms or snippets change on remote' to
examine collections in the respective namespaces so an import with only
transform collections (or snippet collection) creates the correct
settings on the importing instance.

* fixup! better handling for custom vs builtin tags

* fixup! better conflict checking of namespaced cols

* fixup! explicit connectionb for token cache

* fixup! PR feedback
2026-02-20 10:54:57 -06:00
Ryan Laurie
f6f2a31b6a Enable automated patch releases (#69971)
enable automated patch releases
2026-02-20 16:26:26 +00:00
github-automation-metabase
1342901722 Auto-update documentation for master (#69953)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-20 09:53:52 -05:00
Timofey Kachalov
a554da88bd Change the way of building the base_ref embedjs bundle (#69910) 2026-02-20 15:55:19 +04:00
Mahatthana (Kelvin) Nomsawadi
7fa10713ea Support passing dataPicker to SDK components to force staged data picker (#69631)
* Adding dataPicker to embedding-data-picker redux store

* Refactor: move `dataPicker` redux

Move from interactive embedding store to embedding data picker store

* Add `dataPicker` type for the SDK

* Fix storybook id value

* Accept `dataPicker` in modular embedding SDK

* Make the doc more suitable for markdown table in the docs site

* Add test for InteractiveQuestion

* Fix drillThroughQuestionProps type

* Add tests for drillThroughQuestionProps.dataPicker

* Fix SDK components can't specify different `entityTypes` or `dataPicker`

* Fix doc error

* Fix comment grammar

* Fix wrong file name

* Clarify redux slice usage with a comment

* Make context more specific to avoid misuse

* Add `question` back to SDK's `entityTypes` on the API doc
2026-02-20 11:27:46 +00:00
Nemanja Glumac
43e3fa694d Revert "Run container as non-root, simplify H2 handling in entrypoint (#64977)" (#69958)
This reverts commit 54bd11c5b9.
2026-02-20 10:42:48 +00:00
lbrdnk
370a4dff14 Enable check_snippet endpoint (#69892)
* Enable the check_snippet endpoint

* Param

* Test

* Test
2026-02-20 10:04:58 +01:00
Uladzimir Havenchyk
dc319ca76a feat(dashboard): move subscriptions to action menu (#64950)
* feat(dashboard): move subscriptions to action menu

* fix unit tests

* fix e2e tests

* fix console warning about uncontrolled component

* fix more tests

* fix remaining test

* bring test back
2026-02-20 08:39:55 +00:00
Romeo Van Snick
b08d62e316 Transforms with params UI (#69728)
* Validate transform queries can be preprocessed

* remove prn

* update backend error messages

* Add support for custom toggleTemplateTagEditor

* Allow passing setTemplateTagConfig to TagEditorParam

* Add support for storing parameter values when question changes

* Add template-tags tab

* Add template tag sidebar

* Allow saving optional template tags or tags with a default value

* Show error message on save

* Add new spec for transform template tags

* Avoid sharing state when navigating

* Add combination test for template tag types in transforms

* Add definitionTab helper

* Add test for multiple template tags

* Fix error message

* Fix tooltips in test

* Remove tooltip check in tests

* Use getErrorMessage to get error message in toast

* Only return message if it is not empty

* Wrap error message in form

* Use H.createTestNativeQuery helper

* Move variableTemplateTags and isVariableTemplateTag to Lib

* Use more conventional key to reset uistate

* update backend error messages again

* Revert "Wrap error message in form"

This is now handled in the api

This reverts commit 9efecaf261.

* Fix test

---------

Co-authored-by: William Zimrin <william@metabase.com>
2026-02-20 13:15:02 +11:00
Alexander Polyankin
ba302fc0ef Diagnostics cleanup pulled from the metrics branch (#69926) 2026-02-20 01:15:01 +00:00
Anderson
716a26ef75 Remove Exit sidebar menu item now that app switcher exists (#69886) 2026-02-19 23:53:20 +00:00
dpsutton
f1de74d0d2 [master] security fixes (#69924)
* security fixes

* Use actions dataset

Symptom:
We started having tests failing

like:

```
expected: {:has_more_values false,
           :values [["African"] ["American"] ["Artisan"]]}
  actual: {:has_more_values false, :values (("American") ("Artisan") ("Asian"))}
    diff: - {:values [["African"] ["American"] ["Artisan"]]}
          + {:values [["American"] ["Artisan"] ["Asian"]]}
```

and

```
expected: {:has_more_values true,
           :values [["African"] ["American"] ["Artisan"] ["Asian"] ["BBQ"]]}
  actual: {:has_more_values true,
           :values (("American")
                    ("Artisan")
                    ("Asian")
                    ("BBQ")
                    ("European Shop"))}
    diff: - {:values [["African"] ["American"] ["Artisan"] ["Asian"] ["BBQ"]]}
          + {:values [["American"]
                      ["Artisan"]
                      ["Asian"]
                      ["BBQ"]
                      ["European Shop"]]}
```

Identify:
```
modified   src/metabase/actions/execution.clj
@@ -35,6 +35,10 @@
                                                               [:model_id      ::lib.schema.id/card]
                                                               [:dataset_query ::lib.schema/native-only-query]]
    request-parameters]
+  (let [db-name (-> ((requiring-resolve 'metabase.test/db)) :name)]
+    (when-not (.startsWith db-name "actions-test-data")
+      (println clojure.test/*testing-vars*)
+      #_(clojure.repl/pst (Exception. "how here?") 500)))
   (log/tracef "Executing action\n\n%s" (u/pprint-to-str action))
   (try
     (let [parameters (for [parameter (:parameters action)]
@@ -61,6 +65,10 @@
 (defn- execute-custom-action! [action request-parameters]
   (let [{action-type :type} action]
     (actions/check-actions-enabled! action)
+    (let [db-name (-> ((requiring-resolve 'metabase.test/db)) :name)]
+      (when-not (.startsWith db-name "actions-test-data")
+        (println clojure.test/*testing-vars*)
+        #_(clojure.repl/pst (Exception. "how here?") 500)))
     (let [model (t2/select-one :model/Card :id (:model_id action))]
       (when (and (= action-type :query) (not= (:database_id model) (:database_id action)))
         ;; the above check checks the db of the model. We check the db of the query action here
@@ -165,8 +173,14 @@
   (let [k (keyword (:kind action-instance))]
     (legacy->current k k)))

+(require 'clojure.repl)
+
 (defn- execute-implicit-action!
   [action request-parameters]
+  (let [db-name (-> ((requiring-resolve 'metabase.test/db)) :name)]
+    (when-not (.startsWith db-name "actions-test-data")
+      (println clojure.test/*testing-vars*)
+      #_(clojure.repl/pst (Exception. "how here?") 500)))
   (let [model-id        (:model_id action)
         implicit-action (parse-implicit-action action)
         {:keys [query row-parameters]} (build-implicit-query action implicit-action request-parameters)
```

I modified the action execution to print out test vars that weren't
using the correct dataset. A few need cross datasets to ensure can't run
on different dbs, and a few don't matter because they assert that
permissions fail or data is missing. But this
execute-action-permission-test didn't, and it's last branch asserts
"Admin can still execute actions" and that seems to have been the cause
of our troubles
2026-02-19 15:16:26 -08:00
Rodrigo López Dato
54bd11c5b9 Run container as non-root, simplify H2 handling in entrypoint (#64977)
* Run container as non-root, simplify H2 setup

* Permissions

* add to bin/Dockerfile

* Update Dockerfile

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>

* Update bin/docker/Dockerfile

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>

* bad bot :(

* docs

* bring back JAVA_TIMEZONE

* don't hardcode default h2 directory in command

* fix link

* update openapi

---------

Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>
2026-02-19 19:25:16 -03:00
Nemanja Glumac
2e3efef978 Use core.setFailed instead of throw for missing artifacts (#69897)
When an artifact doesn't exist (expected for new commits), the
fetch-artifact action was using throw new Error() which causes
GitHub Actions to report "Unhandled error" - confusing and noisy.

Using core.setFailed() cleanly marks the step as failed without
the scary error message.

Fixes: DEV-1581

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-19 23:15:33 +01:00
Rodrigo López Dato
9d9433b5b0 docs: Fix step numbering + add details on how to confirm if using H2 (#69581)
* Fix step numbering + add details on how to confirm if using H2

* fix anchor links
2026-02-19 18:19:46 -03:00
Rodrigo López Dato
f56c4e39cb Mention that the appdb schema must always be public (#69905) 2026-02-19 18:19:16 -03:00
bryan
f3fa8226cf Add debug echo to driver-decisions CI step (#69881)
Prints the mage command and args before execution so we can quickly
see what labels/flags were passed when debugging CI driver issues.

Closes: DEV-1577
2026-02-19 21:10:20 +00:00
Rodrigo López Dato
4376ecc379 Update model index limit in docs (#69933) 2026-02-19 18:08:16 -03:00
Braden Shepherdson
2c04482d27 [MBQL lib] Move leaky column logic from models.interface into lib (#69665)
Fixes QUE2-353.

`mi/normalize-result-metadata-column` called some internals to modernize
a possibly-lib, possibly-legacy column from `:result_metadata` on a
card. Pull that logic into Lib as a new exported function.
2026-02-19 20:52:27 +00:00
bryan
be492dc637 Remove unused HTTP action code paths (#69764)
* Remove dead code for actions

* Disable HTTP action type at API level

* clarify thrown exceptions

* Remove HTTP action tests

HTTP actions are now blocked at the API level; these tests cover
functionality that's no longer accessible.

* Remove remaining HTTP action references from api_test

The previous commit missed several HTTP action usages:
- all-actions-default helper function
- list-actions-test action-1 binding
- action-parameters-test (now uses query action)
2026-02-19 20:07:24 +00:00
Anderson
b2fb97a98a Replace 'Set up git sync' with 'Set up remote sync' on Data Studio sidebar (#69883) 2026-02-19 19:11:52 +00:00
William
347f3f11b4 Transforms with parameters (#69592)
We want to support transforms with template tags, as long as those tags aren't required or have default values. However, if we do that, the backend should actually verify that we do in fact have values for all relevant template tags. This pr adds basic validation logic to transform creation and update routes -- essentially, we just run qp.preprocess/preprocess and see if we get an error.
2026-02-19 12:03:00 -06:00
Edward Paget
d59d58e61a Fix narrow symbol downloads with tests (#69811)
* Fix downloading currency values in narrowSymbol format (#69779)

* Add tests for narrowSymbol currency style in downloads

---------

Co-authored-by: Will Bryant <will.bryant@gmail.com>
2026-02-19 11:39:11 -06:00
Timofey Kachalov
c8d8369fec feat(embed-js): Add docs hint for additional wizard properties (#69906) 2026-02-19 21:14:10 +04:00
Sébastien
ecaff38ac0 improved doc generation for EAJS (#69890) 2026-02-19 17:30:20 +01:00
Nemanja Glumac
951f74665d Do not cache UV (#69902) 2026-02-19 17:18:14 +01:00
Dan Stone
acf4530cc6 Move transform metering back into EE module (#69840)
* Move transform metering back into EE module

The defenterprise shadowing was not working as the metering function was
moved

* Add test of EE stats
2026-02-19 16:05:06 +00:00
Rodrigo López Dato
8eccd8a0f9 Capitalize Jar -> JAR (#69900) 2026-02-19 11:26:31 -03:00
Nemanja Glumac
83fdafad01 Introduce Copilot code review instructions (#69846) 2026-02-19 11:14:54 +01:00
github-automation-metabase
71cfad67bb Auto-update documentation for master (#69888)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-18 20:43:17 -05:00
Fraser
103e9056e1 Convert QueryButton to TypeScript (#69419)
* Convert QueryButton to TypeScript (DEV-1497)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Tighten types
2026-02-19 14:15:56 +13:00
Cam Saul
984cf44eca More robust visualization settings normalization (#69860)
* More robust visualization settings normalization

* Remove stray `println`
2026-02-18 16:20:00 -08:00
Jeff Bruemmer
d2f7234d7f docs - sql table variable (#69817) 2026-02-18 17:07:30 -05:00
Timothy S. Dean
4ab6f9df02 Transforms DB Connection (#68883)
Problem: When a database is configured for both SQL access and Transforms, any feature with SQL access (like raw SQL questions) inherits the elevated permissions (CREATE, DROP, INSERT, etc.) that Transforms need.

Solution: Admins can _optionally_ configure write credentials alongside existing read credentials. One logical database, two connection types. Specific code paths opt in to using write credentials; by default everything uses a read-only connection.

How: This PR adds a new `write_data_details` column on `Database`. If `write_data_details` isn't configured, everything will still use `details` as before. When it is configured, it acts as a set of overrides on top of `details`, but only in code paths that require write permissions. There should be no behavioral change for existing deployments.
2026-02-18 13:57:16 -07:00
Edward Paget
4c0c9aa08f fix: log parameter not nil value (#68200) 2026-02-18 14:29:50 -06:00
Rodrigo López Dato
32a00c99e5 Explain how DB routing and query caching work together (#69855)
* Explain how DB routing and query caching work together

* Update docs/configuring-metabase/caching.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-18 19:38:19 +00:00
github-automation-metabase
559c2f27de Auto-update documentation for master (#69833)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-18 11:44:49 -05:00
Nemanja Glumac
fd775c440d Split long running e2e specs into smaller chunks (#69844) 2026-02-18 17:18:36 +01:00
Nemanja Glumac
4a79872533 Clean up more unneeded dependency "resolutions" (#69837) 2026-02-18 17:14:53 +01:00
Timofey Kachalov
127132f8a6 Measure Embedding SDK Hosted Bundle bundle size (#69743) 2026-02-18 19:57:09 +04:00
Nathan Voxland
140d1adcb7 Remote-Sync: Support other git providers (#69675) 2026-02-18 09:37:25 -06:00
lbrdnk
639c8debc9 Enable native entity validation (#69784)
* Enable native entity validation

* Adjust tests

* Adjust test

* Adjuts tests

* Enable check_card and check_transform for native entities

* Adjust test to check child staleness

* Adjust test

* Adjust e2e test
2026-02-18 14:23:18 +01:00
Oleksandr Yakushev
795fa21b9d Add &parents to match-lite and rewrite remaining match/match-one usages (#69259) 2026-02-18 15:04:04 +02:00
lbrdnk
2f043ea9d2 Sqlglot review follow-up (#69788)
* Review remarks (incl. .sqlglot-version removal)

* Use uv.lock

* Restore batch-lookup-table-ids

* Adjust test

* Apply suggestions from code review

Co-authored-by: bryan <bryan.maass@gmail.com>

* Add sqlglot version parsing test

---------

Co-authored-by: bryan <bryan.maass@gmail.com>
2026-02-18 13:23:29 +01:00
Dan Stone
0e113a5c68 Accept string target :type in transform test helper (#69804)
It makes sense to use strings in http tests because that is what the
http-client will accept as json.

If a string target :type is supplied, we convert it to a keyword to
ensure we can dispatch to the intended method.
2026-02-18 11:06:04 +00:00
Uladzimir Havenchyk
e3ec99133a chore: convert IconBorder component to typescript (#69735)
* chore: convert IconBorder component to typescript

* pass rest parameters

* inline component

* fixup
2026-02-18 06:19:21 +00:00
Fraser
cd8c4b1e98 Convert lib/syncing to TypeScript (#69428)
* Convert `lib/syncing` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1507
2026-02-18 16:16:10 +13:00
Romeo Van Snick
ead4e7d4d9 Fix unreferenced dependency flakes (#69535)
* Scroll item into view

* Fix sidebar test

* Wait for page to be visible
2026-02-18 14:15:52 +11:00
Fraser
f3fe43bb86 Convert LoginHistory to TypeScript (#69412)
Convert LoginHistory to TypeScript (DEV-1491)

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 14:36:39 +13:00
Fraser
e385103a21 Convert LimitPopover to TypeScript (#69076)
* Convert LimitPopover to TypeScript

Closes DEV-1421

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-18 14:10:11 +13:00
Nathan Voxland
13681a004a Improve event creation remote-sync (#69768) 2026-02-17 18:05:08 -06:00
Fraser
a8715223ae Convert embedding/saved-entity-picker/utils to TypeScript (#69442)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1520

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:29:25 +13:00
Fraser
3cbf8919a7 Convert lib/string to TypeScript (#69424)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1505

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-18 11:29:11 +13:00
Oleksandr Yakushev
d4702e10e0 Merge remaining match -> match-many rewrites (#69686)
* [match] Implement match-many as a replacement for match

* [match] Add proper docs to match-lite and match-many
2026-02-17 23:56:04 +02:00
Braden Shepherdson
c8cd828410 [MBQL lib] Don't export a dynamic var; add with-card-clean-hook macro (#69662)
Fixes QUE2-354.

`lib/with-card-clean-hook` can be used to bind a callback function to
any material changes made by the `lib.convert/clean` process, which
generally indicates errors.
2026-02-17 21:36:48 +00:00
Edward Paget
aa5c870dc4 fix: cancelling remote sync tasks dismisses modal (#67613)
* fix: cancelling remote sync tasks dismisses modal

Previously we didn't close this modal until the task reached a
'cancelled' state which could take several seconds.

* fixup! PR feedback
2026-02-17 15:08:18 -06:00
Kevin Kelleher
f4aa0cc722 Visualizer trend lines and bug fixes: colors, settings, legends, axes (#69296) 2026-02-17 15:54:47 -05:00
metamben
764befaffb Document :metabase.lib.field/simple-display-name (#69590)
* Document :metabase.lib.field/simple-display-name

Closes QUE2-286

* Fix merge
2026-02-17 23:08:32 +03:00
metamben
dbced47022 Name the default join strategy (#69748)
Closes QUE2-285

The original idea was making the :strategy key required and leaving the setting of the value to the normalization, but
I decided not to go down that road. Here's why: there are multiple places on the path of constructing a join where we
can specify the join strategy but don't have to. These steps are not going through normalization and introducing
normalization would be inefficient and feel strange. Also, it would need to be done at several points, so it doesn't
seem a gain in the end. Because of this, all this PR does is naming the default strategy, so that changing it should
be possible at a single point. (Doing this would be a bad idea, so this PR is meant to be a documentation
improvement.)
2026-02-17 23:08:21 +03:00
Edward Paget
224d17965d fix: allow uploads when schema is unrestricted (#69657)
* fix: allow uploads when schema is unrestricted

* fixup! add upload enabled flag

* Update impl.clj

* fixup! where upload flag is set
2026-02-17 13:26:36 -06:00
Abed Habli
0b644a038f Docs v59: Nav UI update -- Grid icon and Admin rename (#69803)
* Update gear icon

* Update docs/data-modeling/json-unfolding.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-modeling/json-unfolding.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/sdk/quickstart-with-sample-app.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/sdk/quickstart.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/full-app-embedding-quick-start-guide.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/full-app-embedding-quick-start-guide.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/user-provisioning.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/permissions/application.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/permissions/data.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/util/resources/introduction.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/usage-and-performance-tools/audit.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Apply suggestion from @jeff-bruemmer

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/public-links.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/embedding/public-links.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/api-keys.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/api-keys.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/people-and-groups/api-keys.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Remove few "ons"

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-17 20:16:14 +01:00
github-automation-metabase
65c102daf2 Auto-update documentation for master (#69781)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-17 11:14:20 -05:00
Nathan Voxland
5da65b6c52 Un-publishing remote-sync'ed library tables should remove them from the git repo (#69757) 2026-02-17 09:57:31 -06:00
Jeff Bruemmer
5f66a26a53 docs - one-shot sql gen (#69766) 2026-02-17 15:36:16 +00:00
Jakub Chodorowicz
75db6b5973 split large data model shared spec cypress file (#69744)
* split large data model shared spec cypress file

* split 2nd group further, rename files
2026-02-17 16:31:27 +01:00
Uladzimir Havenchyk
085fc52dca chore: cleanup relationships which we never show (#69786) 2026-02-17 17:24:11 +03:00
Uladzimir Havenchyk
b404c13d0c chore: convert dashboard actions to typescript (#69737)
* chore: convert dashboard actions to typescript

* cleanup

* fix unit test

* address review

* fix typecheck
2026-02-17 17:14:08 +03:00
Uladzimir Havenchyk
727664ccc6 chore: cleanup moment leftovers (#69733) 2026-02-17 16:29:31 +03:00
Jeff Bruemmer
97fa5da0c0 docs - embedding native question (#69762)
native question
2026-02-17 08:28:01 -05:00
Kamil Mielnik
a1b8cbca83 GDGT-1781 Fix flaky "should check out transform into a new workspace from the transform page" e2e test (#69619) 2026-02-17 13:26:48 +00:00
Gabriel Moreno
e0d953e257 Implement improved illustration for in-app Library upsell (#69760)
feat: add new library upsell illustrations
2026-02-17 09:14:08 -04:00
Nemanja Glumac
f405f3d36a Remove set-value and unset-value from "resolutions" (#69787) 2026-02-17 13:10:40 +00:00
Fraser
554bb10750 Convert Heading to TypeScript (#69064)
* Convert Heading to TypeScript

Closes DEV-1409

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* Delete heading and replace with title

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-18 00:20:06 +13:00
Kamil Mielnik
c51eeace1d Visualization Typescript Conversions - lib/dom.js (#69630) 2026-02-17 17:30:01 +07:00
Mahatthana (Kelvin) Nomsawadi
da01813210 Fix flaky view-and-curate-content.cy.spec.ts (#69749)
Fix flaky test
2026-02-17 10:03:49 +00:00
Fraser
2a12752ec7 Convert lib/security to TypeScript (#69422)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1504

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 22:45:14 +13:00
lbrdnk
7da41b4874 Add uv to build docs and dev-install (#69727)
* Add uv to build docs and dev-install

* Update docs/developers-guide/build.md

Co-authored-by: bryan <bryan.maass@gmail.com>

* Add also python to mise.toml

---------

Co-authored-by: bryan <bryan.maass@gmail.com>
2026-02-17 09:19:35 +01:00
Kamil Mielnik
7cab7b1458 GDGT-1740 Datamodel Typescript Conversions (#69343) 2026-02-17 15:12:39 +07:00
Fraser
801720f077 Convert lib/schema_metadata to TypeScript (#69425)
* Convert `lib/schema_metadata` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1506

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 14:03:57 +13:00
Cam Saul
bd1e91191c Map Snowflake big integers to :type/BigInteger (#67609)
* Map Snowflake big integers to :type/BigInteger (fix #63600)

* Test fixes 🔧

* Test fixes 🔧

* Test fix 🔧

* More test fixes 🔧

* Another round of test fixes 🔧

* (Hopefully) final test fix 🔧

* Code cleanup

* Revert changes that broke Clickhouse test

* Test fix 🔧
2026-02-16 17:03:13 -08:00
Fraser
d4cb2fb735 Convert Alert to TypeScript (DEV-1493) (#69415)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 13:47:08 +13:00
Rodrigo López Dato
5259af771e Fix navigate_to not doing anything in full-app embedding (#69761) 2026-02-16 23:47:11 +00:00
Romeo Van Snick
f3f72f8cb3 Fix missing availableHeight on model native editor (#69723)
* Fix missing availableHeight on model native editor

* Add repro for metabase#69722
2026-02-17 10:42:47 +11:00
Fraser
a46e4da604 Convert PermissionsTabs to TypeScript (#69080)
* Convert PermissionsTabs to TypeScript

Closes DEV-1425

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-17 12:21:15 +13:00
Fraser
4568848fb0 Convert common/hooks/use-scroll-on-mount to TypeScript (#69440)
* Convert `common/hooks/use-scroll-on-mount` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1518

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 12:20:51 +13:00
Fraser
a6bf8e9326 Convert lib/encoding to TypeScript (#69413)
* Convert `lib/encoding` to TypeScript

Part of the Accelerate TypeScript Migration project.

Closes DEV-1490

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-17 12:19:35 +13:00
Kevin Kelleher
32b8ab866d Default viz behavior fixes (#69664) 2026-02-16 17:39:16 -05:00
Egor Grushin
bbf5aebd5a Gdgt 1774 incremental update field not displaying in transforms (#69740)
* GDGT-1774 fetch metadata to enable field picking in incremental transform settings

* GDGT-1774 add e2e reproduction
2026-02-16 22:01:44 +00:00
Ryan Laurie
55d4145794 Update workflow triggers (#69758)
update workflow triggers
2026-02-16 19:47:56 +00:00
Anderson
98f4633388 Add tracking events for when Dependency Graph is opened for an entity (#69604)
* Add events for transform run tags and dependency diagnostics row selection

* Fix e2e test

* Adjust event as per review / Fix e2e tests

* Add tracking events for when Dependency Graph is opened for an entity

* Add remaining e2e tests

* Update simple_event/jsonschema/1-0-0
2026-02-16 18:59:36 +00:00
Dan Stone
d987764034 Fix bigquery/snowflake transforms tests (#69566)
* Add python transforms .yml for manually verifying flakes

* Fix bigquery/snowflake failing tests

* Fix bigquery name quoting

* Use explicit schema in table gens

* Schema fixes for bigquery
2026-02-16 18:34:24 +00:00
Maksym Yakubych
7bf8c80d42 fix: double new lines are not pasted correctly into metabot prompt input (#69493) 2026-02-16 09:42:37 -06:00
Maksym Yakubych
a971f7972b feat: add @ mention to metabot placeholders (#69374) 2026-02-16 09:41:32 -06:00
Nicola Mometto
cfcba5160e remove task logs from usage analytics (#69739) 2026-02-16 14:30:56 +00:00
metamben
04e14dcee2 Remove :metabase.lib.field/original-temporal-unit and document friends (#69627)
* Remove :metabase.lib.field/original-temporal-unit and document friends

Closes QUE2-287

* Remove unused alias
2026-02-16 16:34:00 +03:00
Jeff Bruemmer
832a04aa91 docs - box plot (#69689)
* box plot docs

* Optimized 3 images, saved 221.8 KB (44.8% smaller)

* Apply suggestion from @jeff-bruemmer

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-02-16 13:24:40 +00:00
Abed Habli
c5591f5ece Docs: Add screenshots to Data Studio docs (#69634)
* Add screenshots to Data Studio docs

* Optimized 8 images, saved 757.5 KB (38.2% smaller)

* Update docs/data-studio/data-structure.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Delete docs/data-studio/images/sync-settings.png

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-16 12:07:28 +00:00
metabase-bot[bot]
bf1610f1cd [chore] Update E2E test timings with recent data (#69685)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-16 10:05:05 +00:00
Romeo Van Snick
e1813fedb5 Fix more measure unit tests (#69596)
* Rewrite test to use Lib.createTestQuery

* Force OpaqueDatasetQuery to be used

* Break cyclic imports
2026-02-16 19:51:39 +11:00
Kamil Mielnik
3339413f6e GDGT-1775 Convert Gauge Viz to Functional Component + Typescript (#69468) 2026-02-16 15:19:36 +07:00
Kamil Mielnik
2958401e6e GDGT-1772 Convert Progress Visualization to Typescript + Functional Component (#69449)
* Refactor Progress viz to TypeScript and a function component

* Always run the effect
2026-02-16 15:19:01 +07:00
Nemanja Glumac
63bae84a2d Restore 60 minute timeout for BigQuery and Snowflake (#69687) 2026-02-15 14:39:14 +01:00
Ryan Laurie
ea30b8973d Fix Circular Dependency in useGetPlan (#69672)
fix circular dependency
2026-02-14 19:53:23 +00:00
Oleksandr Yakushev
7beb2e3eb1 [match] Implement match-many as a replacement for match (#68659)
[match-lite] Add support for &match anaphor and better nil handling
2026-02-14 16:24:48 +02:00
Nemanja Glumac
1f5eef83b0 Reduce the CI test timeout to 40 minutes (#69625) 2026-02-14 05:37:44 -07:00
Anderson
8a39fdc126 Add tracking events for transform run tags update and dependency diagnostics row selection (#69531)
* Add events for transform run tags and dependency diagnostics row selection

* Fix e2e test

* Adjust event as per review / Fix e2e tests
2026-02-13 20:38:45 -03:00
Denis Berezin
c2aaa12429 Python library upsell (#69600)
* Temp

* Separate EE and OSS transforms upsell logic

* Remove upsell
2026-02-13 19:52:57 -03:00
Anderson
d38d54ec94 Prevent editing snippets from question editor when remote sync is read-only (#69147)
* Prevent snippets to be edited from question editor when remote sync is read-only

* Fix test
2026-02-13 19:28:27 -03:00
Aleksandr Lesnenko
e525135245 rework chart selection ui (#69289) 2026-02-13 17:27:45 -05:00
Kevin Kelleher
d6da6f1198 Fixes for email clients in dark mode (#69023) 2026-02-13 17:08:15 -05:00
Braden Shepherdson
4d9dc19271 [deps] Ignore "soft" refs (in :fields clauses) in deps analysis (#69198)
Fixes QUE-3044.

The QP will ignore refs in `:fields` clauses which cannot be resolved, since they're output only and not critical to the meaning of the query. This change makes the deps analysis treat these "soft" refs the same way - they are not considered to break the queries.

I added some commented tests that are now captured as part of QUE-3081 rather than part of this PR.
2026-02-13 21:23:18 +00:00
Anderson
93e5f86792 Fix docs link on incremental transforms section (#69648) 2026-02-13 21:19:48 +00:00
Denis Berezin
b57eb0d2c7 Dashboard category filter not correctly populated when using multiple datasources in one graph (#69318)
* Add repro e2e test

* Dashboard filter values when connected to card with multiple datasets

* Fix kondo
2026-02-13 23:51:23 +03:00
Ryan Laurie
c55a5d23a1 Dont show hosting upsell to pro self hosted users (#69522)
dont show hosting upsell to pro self hosted users
2026-02-13 13:19:15 -07:00
Braden Shepherdson
ce9a7027cf [MBQL lib] "Befriend" legacy-mbql module, drop some exported namespaces (#69578)
Fixes QUE2-349.

This removes several namespaces from the export list for `lib` which were only used by `legacy-mbql`.

- `metabase.lib.filter.desugar.jvm`
- `metabase.lib.hierarchy`
- `metabase.lib.schema.binning`
- `metabase.lib.schema.constraints`
- `metabase.lib.schema.middleware-options`
- `metabase.lib.schema.settings`
- `metabase.lib.schema.window`
2026-02-13 20:01:20 +00:00
Nemanja Glumac
ff9690156a Remove forced jsdom resolution (#69575) 2026-02-13 20:18:46 +01:00
github-automation-metabase
34fc6597f3 Auto-update documentation for master (#69606)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-13 14:17:42 -05:00
Jeff Bruemmer
6cc10beb56 docs - agent API (#69647) 2026-02-13 18:59:39 +00:00
Dan Stone
fe3b6f83d7 Ensure race free waiting for overlapping transforms (#69287)
* Ensure race free waiting for overlapping transforms

Previously transforms could contend for the is_active slot.
A common outcome (observed with two overlapping schedules) was that one transform would crash (due to the duplicate key violation).

This commit ensures a collision will fallback to waiting to try again rather than crashing (and alerting the user).
2026-02-13 17:35:22 +00:00
Nathan Voxland
45a8927bb8 Revert "Do a rollback before discard all (#69026)" (#69633)
This reverts commit 42d0d35dbd.
2026-02-13 11:01:38 -06:00
Sébastien
60b86d85a5 Fixes isSticky class not being properly applied to dashboard parameters (#69623) 2026-02-13 17:57:16 +01:00
Nemanja Glumac
9c8bf32532 Remove Claude review workflows (#69632)
[ci skip]
2026-02-13 17:56:03 +01:00
Nathan Voxland
fe325b3de7 Improve remote sync errors with missing objects (#69591) 2026-02-13 10:22:09 -06:00
bryan
07fbc6997e Use sqlglot for SQL parsing via GraalVM Polyglot (#68911)
Introduces a unified `sql-tools` API for SQL parsing with swappable backends:
- Macaw (Java, existing) — moved from `metabase.driver.sql`, behavior preserved
- SQLGlot (Python, new) — broader dialect support via GraalVM Polyglot

Architecture: callers go through `sql-tools` which dispatches to either backend
via the `MB_SQL_TOOLS_PARSER_BACKEND` setting (default: sqlglot). The old
Macaw calls (parsed-query -> ast -> field-references) are replaced
with a `sql-tools` API (e.g. `sql-tools/referenced-fields`,
`sql-tools/validate-query`).

SQLGlot runs Python inside GraalVM Polyglot contexts managed by a reusable pool
to amortize initialization cost. The Python source and SQLGlot library are
bundled into the uberjar via a dedicated build step.
2026-02-13 15:57:17 +01:00
Jeff Bruemmer
28585e4119 docs - remove auth (#69594)
remove auth
2026-02-13 15:37:07 +01:00
John Swanson
b6b77a19e7 record group membership removals in activity log (#69316)
* record group membership removals in activity log

Previously the `PUT /api/membership/:group-id/clear` and
`DELETE /api/membership/:id` endpoints did not emit group membership
deletion events.

In the long run it would be better if `t2` were the interface for
PermissionsGroupMembership, so users didn't need to call these "blessed"
functions. But for now, let's go along with the existing pattern here,
have some blessed functions for doing things, and throw exceptions if
someone does a direct `t2/delete!` on a `:model/PermissionsGroupMembership`.

* use macro for more obvious workaround
2026-02-13 05:10:11 -08:00
Timofey Kachalov
890771e40e Prepare Shoppy Sample App GH job to run synthetic monitoring tests (#69492) 2026-02-13 16:59:32 +04:00
Kamil Mielnik
3c724995fb GDGT-1760 Remove Code & BoldCode components (#69348) 2026-02-13 12:29:57 +00:00
Kamil Mielnik
3bd26a0179 GDGT-1761 Remove Grid component (#69351) 2026-02-13 18:42:14 +07:00
Nemanja Glumac
55959131e9 Remove unused Tusk GitHub workflow (#69612) 2026-02-13 11:46:16 +01:00
Nemanja Glumac
9845f0e964 Fix ci-test-config driver quarantine name translation (#69615)
The ci-test-config.json uses driver directory names (e.g., "bigquery-cloud-sdk")
but the mage code uses internal driver keywords (e.g., :bigquery). This mismatch
meant quarantined drivers like bigquery were not being recognized.

Now uses the existing driver-directory->drivers mapping to translate config names
to internal keywords, with fallback to direct keyword conversion for names that
match (like "databricks").

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-13 11:28:19 +01:00
Mahatthana (Kelvin) Nomsawadi
7efad1c105 Correct the modular embedding preview usage count (#69473)
* Correct the modular embedding preview count as :internal

* Add tests

* Fix the modular embedding preview count while not breaking alerts emails

* Fix E2E tests

* Fix wrong e2e syntax
2026-02-13 09:39:32 +00:00
Romeo Van Snick
82d5e7b7ed Native query test helper (#69402)
* Add schema for test-native-query-spec

* Implement test-native-query helper

* Add js wrapper for test-native-query

* Add ts wrapper for test-native-query

* Make common parts optional

* Fix types

* Fix temporal-unit test spec

* Handle snippet tags

* Fix temporal-unit tags

* Fix card tag spec

* Simplify schema

* Add unit tests for createNativeQuery

* Add tests for test-native-query

* Add missing options

* Fix types

* Actually resolve field ref

* Code style

* Add native-query api endpoint

* Add h.createTestNativeQuery helper

* Add test for required, widget-type and default options

* Move parsing into test-spec module as it is part of the implementation

* Add example e2e test use of H.createTestNativeQuery

* Use coercer instead of decoder to validate spec too

* Fix lint

* Move adjust to update-vals

Co-authored-by: Braden Shepherdson <braden@metabase.com>

* Match threading style

* Add test for optional template tagsfg

---------

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2026-02-13 02:53:16 +00:00
Fraser
b69c4d4e26 Convert PermissionsEditorBreadcrumbs to TypeScript (#69052)
* Convert PermissionsEditorBreadcrumbs to TypeScript

Resolves DEV-1397

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 22:21:41 -03:00
Fraser
92157c0c06 Convert PermissionsSelectOption to TypeScript (#69054)
* Convert PermissionsSelectOption to TypeScript

Closes DEV-1399

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 22:20:33 -03:00
Anderson
3e5a4dc818 When instance is not on trial, still allow them to start Transforms trial if available (#69499)
* show both transforms tiers even when on trial

* Show upgrade modal in place when clicking Upgrade to Pro

* Improve comments

* Show upsell transforms trial variant when available for instance not on trial

* Fix ts

* Say 'Start trial' when trial is available
2026-02-12 22:18:13 -03:00
metamben
72699a1927 Remove :lib/model-display-name (#69579)
Closes QUE2-296
2026-02-13 02:50:46 +03:00
Romeo Van Snick
9f22d94341 Move test helper parser to lib (#69405)
* Use correct type for order-bys

* Move parser for test-query-spec into implementation

* Be more strict in test

* Convert another e2e test to prove the parsing works

* Make args optional in test-query-spec

* Use threading instead of partial

Co-authored-by: Braden Shepherdson <braden@metabase.com>

---------

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2026-02-12 23:18:40 +00:00
Nick Fitzpatrick
b7b9d20ad7 Move app switcher into Dependency Graph (#69128)
* move app switcher into Dependency Graph

* adjusting unit test

* remove z-index nonsense

* moving the app switcher up to DependencyGraphPage, small change to SelectItem
2026-02-12 17:53:55 -04:00
Noah Moss
aa4389bd60 Correct function for fetching field values in Metabot tools (#69589)
* switch function for metabot fetching field values

* refactor tests

* fix lint

* fix tests - keep existing behavior of auto-creating field values if needed
2026-02-12 16:50:14 -05:00
Noah Moss
e70631b3ab Move agent api reference out of docs/ (#69567)
move agent api reference
2026-02-12 16:36:32 -05:00
Anderson
52c4ff856d Fix 'Upgrade to Pro' button to open upgrade modal / Show two transforms tier options when on trial (#69387)
* show both transforms tiers even when on trial

* Show upgrade modal in place when clicking Upgrade to Pro

* Improve comments
2026-02-12 16:56:53 -03:00
Nathan Voxland
7bf638e16e Audit DB should exclude databasechangeloglock (#69487)
auditdb should exclude databasechangeloglock as well
2026-02-12 13:23:37 -06:00
metamben
c950231ec9 Document source-field-join-alias and resolve TODOs (#69503)
Fixes QUE2-297
2026-02-12 22:05:42 +03:00
metamben
3c774eccc8 Add missing multimethods for datetime-subtract (#69324)
Closes QUE2-336
2026-02-12 22:05:27 +03:00
Maksym Yakubych
81d20a97b9 fix: mention popup doesn't close when clicking esc (#69485) 2026-02-12 11:46:13 -06:00
Cam Saul
7c05a09619 Ban legacy keys in column metadata (#69504)
* [Lib] remove deprecated/confusing `:source-alias` key from col metadata

* Metadata schema cleanup

* Test fixes 🔧

* New test fix 🔧

* Ban legacy keys in column metadata

* Fix most tests

* More test fixes 🔧

* Kondo

* Test fix 🔧
2026-02-12 09:26:21 -08:00
Sébastien
0a05ffd76a Implement auto-generated props tables for modular embedding (#69407)
* Add TypeDoc-friendly interfaces for EAJS web component documentation

* Add TypeDoc config for EAJS web component docs generation

* Generate EAJS web component props tables via TypeDoc

* Replace manual parameter lists with auto-generated props tables

* Fixed file references in components.md and enforced types in embed.ts

* .

* .

* .

* added detail on a prop and uncommited *.md files

* added info about attributes needing to be stringified

* .
2026-02-12 16:53:03 +01:00
github-automation-metabase
e1346eb492 Update translations 2026-02-10 (#69372)
* Update translation sources 2026-02-10

* Update translations

* update localization e2e test

* Wochentag

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2026-02-12 14:45:50 +00:00
Nemanja Glumac
1f03ce8fca Update Jest snapshot headers for Jest v30 compatibility (#69564)
Jest v30 validates that snapshot files have the current documentation URL.
Updated the header from the old shortened URL to the new official URL.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 14:43:09 +00:00
Nick Fitzpatrick
bb9c1a1171 add 59 to version-helpers.ts (#69500) 2026-02-12 09:24:06 -04:00
Kamil Mielnik
2291e7f38b GDGT-1776 Query Builder transform fails at join stage (#69552)
* Fix virtualized list items rendering

* Add a repro for GDGT-1776

* Fix GDGT-1776

* Remove isHidden prop from MiniPickerItem and instead just do not render items that should be hidden

* Clean up

* Fix var access
2026-02-12 20:14:54 +07:00
Mahatthana (Kelvin) Nomsawadi
d0d678d9d8 Add "New embed" to command palette in OSS (#69447)
* Improve type ergonomics

* Add tests

* Fix proper discrinimated unions

* Add new keywords to match modern terms

* Fix types

* Sort basic actions in command palette

* Fix tests
2026-02-12 13:10:15 +00:00
Nicola Mometto
09ff1de363 Remove LIMIT in query builder transforms (#69347)
* feat(python-transforms): massage query

* feat(transforms-util): disable-max-results

* feat(QP): respect disable-max-results

* feat(transforms/ui): set disable-max-results

* add tests

* export function in lib

* use disableMaxResults

* more tests

* add e2e test

* 0 max rows is no limit

* fix test

* comment

* address review comments

* Remove trailing newline
2026-02-12 12:42:09 +00:00
Nemanja Glumac
adb448828b Upgrade Jest to v30 (#69490) 2026-02-12 12:19:28 +01:00
Nemanja Glumac
a9c4781d78 Include the relevant step outcome in Trunk inputs (#68947) 2026-02-12 12:04:28 +01:00
Nemanja Glumac
2391e04ea3 Fix the release-log workflow (#69547)
Use prepare-release-scripts action in release-log workflow

Simplify the workflow by using the shared action instead of
manually setting up bun and building release scripts.

This works because the workflow always checks out master,
so the action from master (which uses bun) is always used.

Fixes: DEV-1544

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 11:40:32 +01:00
Ngoc Khuat
636dc63968 Require explicit user approval for agent data access (#69280) 2026-02-12 10:15:56 +00:00
Nemanja Glumac
867aa1ae83 Conditionally resolve the package manager in pre-release (#69545) 2026-02-12 10:01:31 +01:00
lbrdnk
985082f059 Make ci-report work without GNU timeout (#69453)
* Make ci-report work without GNU timeout

* Destroy process on timeout

* Cherry-pick b9ff360230

---------

Co-authored-by: Bryan Maass <bryan.maass@gmail.com>
2026-02-12 09:22:31 +01:00
Sébastien
6b5577a351 Fix flaky embedding sdk backward compatibility test (#69540)
* fixed e2e test

* .
2026-02-12 07:26:24 +00:00
Romeo Van Snick
8d285e7bee Fix broken measure unit tests (#69515)
* Allow passing measures to entities schema

* Fix measures test

* Use toJsQuery
2026-02-12 13:57:47 +11:00
Fraser
fe11f27110 Convert JobInfoApp to TypeScript (#69073)
* Convert JobInfoApp to TypeScript

Closes DEV-1418

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 15:25:11 +13:00
Fraser
3bceaecf2b Convert PasswordReveal to TypeScript (#69061)
* Convert PasswordReveal to TypeScript

Closes DEV-1406

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 15:24:45 +13:00
Fraser
85b82b52f6 Convert CopyWidget to TypeScript (#69056)
* Convert CopyWidget to TypeScript

Closes DEV-1401

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 15:23:32 +13:00
Fraser
8e03727b66 Convert dashboard/actions/revisions to TypeScript (#69437)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1515

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 15:23:04 +13:00
Fraser
b5e052b0c9 Convert JobTriggersModal to TypeScript (#69072)
* Convert JobTriggersModal to TypeScript

Closes DEV-1417

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 17:40:52 -07:00
Fraser
bdb2ce7dae Convert UsefulQuestions to TypeScript (#69069)
* Convert UsefulQuestions to TypeScript

Closes DEV-1414
2026-02-11 17:39:55 -07:00
William
17a3afa85e Add table template tags (#68922)
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-02-11 23:28:16 +00:00
Fraser
50801fc441 Pin bun version in workflows (#69514) 2026-02-12 12:04:10 +13:00
Denis Berezin
31516230f5 Update Upsell to match design (#69488)
* Update Upsell to match design

* Remove loader for trial message
2026-02-12 02:03:02 +03:00
Fraser
a678c2ff8e Convert caching/utils to TypeScript (#69444)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1522

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 11:31:19 +13:00
Fraser
c4090623a9 Convert moderation/selectors to TypeScript (#69445)
Part of the Accelerate TypeScript Migration project.

Closes DEV-1523

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-12 11:26:31 +13:00
Cam Saul
570952497a [Lib] remove deprecated/confusing :source-alias key from col metadata (#69314)
* [Lib] remove deprecated/confusing `:source-alias` key from col metadata

* Metadata schema cleanup

* Test fixes 🔧

* New test fix 🔧
2026-02-11 13:56:41 -08:00
da
ef622a4832 Add entity id and entity type to the dependency calculation error (#69001)
* Initial commit

* Fix tests

* Fix events test
2026-02-11 18:53:49 -03:00
Fraser
43daa3b222 Convert AccountLayout to TypeScript (#69067)
* Convert AccountLayout to TypeScript

Closes DEV-1412

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-12 10:48:03 +13:00
Aleksandr Lesnenko
f0582cb46a Add boxplot visualization (#68104)
* add boxplot visualization type

* Add boxplot viz type visual tests (#68327)

boxplot visual tests
2026-02-11 16:39:14 -05:00
Nemanja Glumac
360ae8c713 fix: Snyk workflow using wrong working directory for release/yarn.lock (#69510)
The previous fix ran `cd release && bun install --yarn` which changed the
working directory for subsequent commands. The sed command then tried to
access `release/yarn.lock` from within the `release/` directory, resulting
in "sed: can't read release/yarn.lock: No such file or directory".

Split into separate steps with explicit working-directory for clarity.
The sed commands now continue on error to let Snyk report parsing issues
directly rather than failing on the workaround.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 22:27:33 +01:00
John Swanson
34837bc9bb Implement DB-level caching of premium features (#69241)
Premium feature token checks are cached per-instance in memory with a 12h TTL. During rolling deploys after a plan upgrade, different instances can disagree about which features are available:

   1. Request hits instance A (old cache) → reports old features
   2. Request hits instance B (freshly started, no cache) → reports new features
   3. Frontend says "upgrade successful!"
   4. Request hits instance A again → old features are back

This flapping means the frontend can't reliably detect when an upgrade has landed.

## Solution

### DB-hash-aware cross-instance cache

Replace the per-instance in-memory TTL cache with a two-layer caching scheme coordinated through the DB:

 - A **local in-memory cache** holds the full token status (features, validity, etc.)
 - A **DB table** (`premium_features_token_cache`) stores only a SHA-256 hash of the token status, keyed by a hash of the token itself. The DB never stores actual features — just enough to coordinate freshness across instances.

When a token check comes in:
- If the local cache matches the DB hash and is < 12h old: serve it immediately
- If it matches the DB hash and is < 36h old: serve the stale data and refresh asynchronously in the background
- If the DB hash doesn't match (another instance refreshed), or the cache is > 36h old, or this is a cold start: synchronous MetaStore fetch

This ensures all instances converge quickly after a plan change while keeping MetaStore traffic low. Cold-starting instances always hit the MetaStore — there's no way to bootstrap features from the DB alone, since it only stores hashes.

### Checker stack (inner to outer)

1. **`store-and-airgap-token-checker`** — hits MetaStore or validates airgap token
2. **`circuit-breaker-token-checker`** — circuit breaking + timeout
3. **`db-hash-aware-token-checker`** — the core caching layer (described above)
4. **`local-cached-token-checker`** — 5s TTL memoization to avoid hitting the DB on every request
5. **`error-catching-token-checker`** — wraps exceptions into `{:valid false}` responses

The 5s local cache means we hit the DB at most once every 5s, even during the grace period.

### Force-refresh endpoint

`POST /api/premium-features/token/refresh` clears all caches and synchronously re-checks against the MetaStore. The frontend uses this when polling for new features after a purchase (`useTokenRefreshUntil` in `UpgradeModalLoading`, `MetabotSettingUpModal`, `TransformsSettingUpModal`). A cookie-based mechanism propagates the invalidation to other instances so they clear their local caches on the next request.
2026-02-11 13:11:52 -08:00
Nemanja Glumac
dccfcc9db1 fix: Snyk scan failing after bun migration (#69498)
Root Cause:
Bun's `bun install --yarn` command has a bug where it normalizes version
ranges inconsistently in the generated yarn.lock:

- Alias entries normalize ranges: "safer-buffer@>= 2.1.2 < 3"
  (converts "< 3.0.0" to "< 3")
- Dependency specs keep original: safer-buffer ">= 2.1.2 < 3.0.0"
  (preserves the ".0.0")

Snyk performs exact string matching when resolving dependencies to their
lock file entries. When it sees `safer-buffer@>= 2.1.2 < 3.0.0` as a
dependency, it looks for that exact string in the alias list, but only
finds `safer-buffer@>= 2.1.2 < 3`, causing the error:

  "Dependency safer-buffer@>= 2.1.2 < 3.0.0 was not found in yarn.lock"

Solution:
Add a post-processing sed command that normalizes version ranges in the
dependency specifications to match the aliases. This transforms:
- "< 3.0.0" → "< 3"
- "< 3.0" → "< 3"

This ensures Snyk can match dependencies to their resolutions.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 17:53:34 -03:00
Edward Paget
6d1b58aaa2 feat: add a stable sort for card parameters serdes (#69478)
Sorts parameters by their uuid to ensure that we maintain an order for
parameters across exports no matter the order they are serialized to the
database in.
2026-02-11 14:39:12 -06:00
John Swanson
4dcab243b9 Don't attempt to add revisions for viewing docs (#69305)
Luckily a bug saved us from *actually* creating revisions here (the
`before-update` hook doesn't get an actual instance in this case). But
... we shouldn't be attempting it.
2026-02-11 11:45:45 -08:00
Nick Fitzpatrick
4501e69eb0 add build cljs to pre-release steps (#69495)
add buuild cljs to pre-release steps
2026-02-11 14:53:41 -04:00
Nemanja Glumac
b9363e3f75 Set up bun authenticated (#69491)
This prevents API rate limits.
2026-02-11 19:29:36 +01:00
Nemanja Glumac
1ad08d2ac9 Add automatic build tools installation to dev-install (#69451)
Offer to install essential build tools during setup, which are required
for compiling native extensions in development dependencies.

macOS:
- Detects Xcode Command Line Tools via xcode-select -p
- Triggers native installer dialog and polls for completion
- 10-minute timeout with manual installation fallback

Linux (multi-distro support):
- Debian/Ubuntu/Mint/Pop: build-essential
- Fedora/RHEL/CentOS/Rocky/Alma: Development Tools group
- Arch/Manjaro/EndeavourOS: base-devel
- openSUSE/SLES: devel_basis pattern
- Unknown distros: manual installation guidance

The check runs as part of step 1 (prerequisites) and is idempotent -
existing installations are detected and skipped with a success message.

* Add progress indicator during Xcode CLT installation wait

Show dots every 10 seconds while polling for installation completion,
so users know the script is still running during the wait.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 18:32:26 +01:00
Maksym Yakubych
1be2cb8497 fix: error message for unauthenticated requests is generic (#69352) 2026-02-11 16:54:01 +00:00
Nicolò Pretto
b9e6c5bc06 feat(sdk): add isHostAppInDevMode (#69450)
* feat(sdk): add isHostAppInDevMode

* i forgot package.json
2026-02-11 16:55:35 +01:00
Fraser
b806fb5b31 Convert AdminAwareEmptyState to TypeScript (#69055)
* Convert AdminAwareEmptyState to TypeScript

Closes DEV-1400

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 17:53:13 +02:00
Nemanja Glumac
f94f6a847a Remove @peculiar/webcrypto polyfill from ClojureScript tests (#69475)
This completes the removal of `@peculiar/webcrypto` from the codebase,
following the Jest setup cleanup in #69466.

Changes:
- Update `polyfills.cljc` to use Node's native `crypto.webcrypto`
- Remove `@peculiar/webcrypto` from package.json

The previous comment about needing Node v23+ was outdated:
- `crypto.webcrypto` available since Node 15
- `globalThis.crypto` available since Node 19
- Node 22 (current LTS) fully supports it

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 15:44:03 +00:00
Nick Fitzpatrick
f37171d483 Add loading state to pull changes (#69380)
adding unit test
2026-02-11 11:26:32 -04:00
Maksym Yakubych
77cb535614 fix: drag handler selecting text in query editor (#68970) 2026-02-11 11:12:19 -04:00
Nemanja Glumac
3532b35b00 Remove @peculiar/webcrypto polyfill from the Jest setup (#69466)
* Use native NodeJS cryppolyfill in fe unit tests

* Force jose library to use Node.js runtime in Jest tests

The jose library's browser runtime expects CryptoKey to be globally
available, which jsdom doesn't provide. This caused tests using JWT
signing (via jose) to fail with "CryptoKey is not defined" after
switching from @peculiar/webcrypto to Node's native webcrypto.

By mapping jose to its Node.js runtime via moduleNameMapper, we avoid
the CryptoKey dependency since the Node runtime uses require('crypto')
directly.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 15:48:45 +01:00
Maksym Yakubych
d77ae0cedb feat: tooltips for metabot message action buttons (#69369) 2026-02-11 14:43:10 +00:00
metamben
8239cbfa00 Prevent expression editor from forcing literal types (#67647)
* Prevent expression editor from forcing literal types

Closes #63910
2026-02-11 14:37:45 +00:00
Nemanja Glumac
dd2b2929a1 Update FE Claude.md scripts instructions (#69463) 2026-02-11 15:25:05 +01:00
Riley Thompson
9cd60a5d77 Set bigquery transport options with read timeout (#69306)
* set read timeout

* add tests
2026-02-11 08:53:21 -05:00
Nemanja Glumac
d0cef57a4f Remove superfluous jest-localstorage-mock (#69455) 2026-02-11 14:34:35 +01:00
Nemanja Glumac
f2bb215346 Fix determine-driver-skips failing on a release branch (#69448) 2026-02-11 09:26:48 -04:00
Maksym Yakubych
7a1aec685f fix: line height of placeholder text in metabot side panel should be 20px (#69377) 2026-02-11 10:05:12 -03:00
Kamil Mielnik
5474fca0c0 GDGT-1531 - Opening a transform should open tab immediately (#69224) 2026-02-11 18:11:11 +07:00
Nemanja Glumac
ab7baf7ca7 Upgrade webpack (#69341) 2026-02-11 10:12:59 +01:00
Mahatthana (Kelvin) Nomsawadi
d7607ccf8a support targetCollection in CreateDashboardModal (#69359)
* Remove old and unused props

* Support `targetCollection` in the CreateDashboardModal

* Add tests

* Handle special collection name e.g. `root`, `personal`

* Address review

* Update test names
2026-02-11 09:00:41 +00:00
Sébastien
d6082bba08 Fixes show detail button showing in embeds (#69338)
fixes show detail button showing in embeds
2026-02-11 06:33:32 +01:00
Anderson
1d0eaf9ca8 Show confirmation popup when overwriting data during remote sync setup (#68525)
* Report conflicts on transforms/snippets/lib

[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)

Co-authored-by: edpaget<ed@metabase.com>

* fixup! store conflicts in remote-sync-task table

* fixup! make conflict checking spec driven

* Restore initial implementation (implement conflict modal when pulling for the first time)

* Fix modal not opening when in data studio

* Don't set version in task when it fails with conflict / Adjust conflict options / Start e2e tests

* Add e2e tests

* Add some unit tests

* Fix remote sync settings update when creating new branch

* Isolate git config for initial import conflict test cases

* Report conflicts on transforms/snippets/lib

[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)

Co-authored-by: edpaget<ed@metabase.com>

* fixup! store conflicts in remote-sync-task table

* fixup! make conflict checking spec driven

* fixup! tests failures

* fixup! lints

* fixup! exclude tags from conflict

* Fix unintended changes from merge in RemoteSyncSettingsForm.tsx

* Address PR comments

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
2026-02-11 03:37:38 +00:00
Anderson
70878781e4 Allow adding segments and measures to hidden tables (#69373) 2026-02-11 00:37:11 -03:00
github-automation-metabase
d4229d9cd8 Auto-update documentation for master (#69396)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-10 19:21:57 -08:00
John Swanson
00c573febe Report conflicts on transforms/snippets/lib (#68506)
* Report conflicts on transforms/snippets/lib

[UXW-2743: Warn before remote sync overwrites local library/transforms](https://linear.app/metabase/issue/UXW-2743/warn-before-remote-sync-overwrites-local-librarytransforms)

Co-authored-by: edpaget<ed@metabase.com>

* fixup! store conflicts in remote-sync-task table

* fixup! make conflict checking spec driven

* fixup! tests failures

* fixup! lints

* fixup! exclude tags from conflict

* fixup! don't delete builtins

* fixup! ignore built-in tags

* fixup! preserve built-in python library

* fixup! kondo

* fixup! correct condition

* fixup! module sort

* fixup! build where clause for post-import removal

* fixup! ws

* fixup! pythonlibrary in serialization tests

---------

Co-authored-by: Edward Paget <ed.paget@gmail.com>
2026-02-10 23:35:21 -03:00
Anderson
6602db9fd2 Implement Archived Snippets page (#68823)
* Implement archived snippets page / Adjust archive/unarchive actions for snippets and folders

* Add more coverage

* Fix ts

* Fix ts / Fix e2e test

* Fix eslint/prettier

* Fix e2e test

* Remove empty file
2026-02-10 22:33:40 +00:00
John Swanson
78d36e43e4 Do not allow publishing tables without query perms (#69171)
* Do not allow publishing tables without query perms

Publishing a table changes query permissions. So you shouldn't be able
to publish a table that you don't have query permissions on, and then be
able to query it.

* fns for `can-publish?`, `can-publish-all-table?`

* switch to `library` ff
2026-02-10 14:28:38 -08:00
John Swanson
88a769d9a8 Unify table visibility with can-query semantics (#69199)
* Unify table visibility with can-query semantics

Table visibility checks had drifted across different APIs.

- `(can-query? table)` checked whether you had view access
and create-queries access OR the table was published. This is incorrect:
the table is queryable if you have view access AND either the table is
published OR you have create-queries.

- the collections API included tables that were not queryable.

- the search API allowed you to view tables if a) you had data
permissions on the table, AND b) the table was unpublished or published
in a collection you had access to. This is incorrect, since publishing a
table shouldn't hide a previously visible table from search results.
Search should return tables for which you have view-data permissions
PLUS the table is either published or you have create-queries
permissions.

Fundamentally this change:

- correctly defines what `(can-query? table)` means, and
- uses that new definition of `can-query` to determine table visibility
  across the collection, search, and table APIs.

Note that I did not change some existing usages of
`(mi/visible-filter-clause :model/Table ...)`, which will continue to
exclude tables for which the user does not have explicit data
permissions set (but could otherwise query due to being published). That
should be a simple followup PR.

- align SQL table visibility with mi/can-query? semantics for search paths

- add enterprise `published-table-visible-clause` and wire optional

- `published-via-collection` support into `(mi/visible-filter-clause :model/Table ...)`

- update search table fallback permission check to use canonical `mi/can-query?`

- fix collection table children filtering to include `published-via-collection` queryability

- make `(mi/can-query? :model/Table)` return explicit booleans

- add/adjust EE tests for:
  - published-table SQL clause behavior
  - collection items visibility under view/query perms
  - search visibility when user lacks query perms
  - search visibility for unpublished tables when user has data perms
  - stabilize appdb negation test by avoiding brittle exact count for "customer" in shared index data

* don't use `published-tables` directly

and fix kondo config

* correct feature for library

* kondo

* ensure we bind `*current-user-id*` in search

fallbacks rely on functions that use dynamic vars to check permissions.

Search is designed to use only the search context (with its
`current-user-id` and `current-user-perms`) and binds those dynamic vars
accordingly.

Previously we just needed to bind `current-user-permissions-set` but now
we should also bind `current-user-id` as well.

* fix tests

* correct feature for library
2026-02-10 14:28:21 -08:00
Fraser
4789ed4666 Convert LogoIcon to TypeScript (#69060)
* Convert LogoIcon to TypeScript

Closes DEV-1405

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-11 09:42:54 +13:00
kevinkelleher12
135d176247 Update table email styles to match frontend (#69176) 2026-02-10 15:20:48 -05:00
Nathan Voxland
43b3ecf3e2 Minor code cleanup (#69236)
Code cleanup
2026-02-10 13:37:28 -06:00
Cam Saul
843350757c Disallow using -rest modules in non-rest modules (#69045)
* Disallow using `-rest` modules in non-rest modules

* Add Kondo linter

* Kondo lint fixes 🔧

* Test fix 🔧
2026-02-10 10:35:33 -08:00
Riley Thompson
0464d028b3 Interrupt threads stuck after query cancellation (#69254)
* interruot stuck threads

* small changes
2026-02-10 13:26:31 -05:00
Jeff Bruemmer
9c9c18d653 docs - fix typo in transforms-enabled setting description (#69353)
Fix typo in transforms-enabled setting description
2026-02-10 18:14:16 +00:00
Maksym Yakubych
38bf8580ea fix: grid Map Pins Offset in PDF Export (#68751) 2026-02-10 12:48:25 -05:00
Nick Fitzpatrick
ce11a50d64 update edit table metadata button link to stay in data studio (#69187) 2026-02-10 13:43:31 -04:00
Chris Truter
b1212ac263 Support transform upserts in Workspace (#69283) 2026-02-10 17:22:37 +00:00
dpsutton
d77f52936e test files trigger module change, workspaces trigger drivers (#69358)
two changes:
- chris changed a file in a workspaces test file and no backend tests
ran at all:

```
=== Module Analysis ===
Changed modules: #{}
Driver module affected: false
Important file changed: false
Drivers with file changes: #{}

=== Driver Decisions ===
h2                        RUN  - H2/Postgres always run
athena                    SKIP - no relevant changes for cloud driver
bigquery                  SKIP - no relevant changes for cloud driver
clickhouse                SKIP - driver module not affected
databricks                SKIP - no relevant changes for cloud driver
druid                     SKIP - driver module not affected
druid-jdbc                SKIP - driver module not affected
mongo                     SKIP - driver module not affected
mongo-ssl                 SKIP - driver module not affected
mongo-sharded-cluster     SKIP - driver module not affected
mysql-mariadb             SKIP - driver module not affected
oracle                    SKIP - driver module not affected
postgres                  RUN  - H2/Postgres always run
presto-jdbc               SKIP - driver module not affected
redshift                  SKIP - no relevant changes for cloud driver
snowflake                 SKIP - no relevant changes for cloud driver
sparksql                  SKIP - driver module not affected
sqlite                    SKIP - driver module not affected
sqlserver                 SKIP - driver module not affected
vertica                   SKIP - driver module not affected
```

So we want the workspace module to be marked dirty by this change. It's
currently filtered out by `remove-non-driver-test-namespaces`.

But a follow-on: workspaces run against different dbs and we therefore
want to ensure this not only triggers driver tests, but also cloud db
tests. So a few tests change to ensure this happens, consequent of
adding `enterprise/workspaces` to `modules-triggering-cloud-drivers`.
2026-02-10 11:04:25 -06:00
Edward Paget
f0abb34fe4 fix: better display for transforms sync changes (#68919)
Better display for transform sync changes where we treat toggling the
`remote-sync-transforms` as though we are toggling the
`is_remote_synced` setting on Root transforms collection. This then
creates a 'collection' typed remote sync object entry for the Root
collection and uses that to drive dirty state display (or non-display)
on the frontend.

This object also drives how items are deleted from the sync so when this
'collection' is in a deleted state it removes all transforms related
content from the sync but preserves it locally.
2026-02-10 17:04:13 +00:00
dpsutton
a2a08af4b1 ease how we generate nano-ids (#69317)
* ease how we generate nano-ids

Fixes https://github.com/metabase/metabase/issues/68130

nano-ids are not needed to be secure, they just need to be
distinct. They hide no secrets but assign identity.

In https://github.com/metabase/metabase/pull/66413 we replaced our usage
of https://github.com/zelark/nano-id with encore. These are almost the
same except that encore uses `secure?` to be true by default. In
practice this is:

```clojure
(if secure?
  (com.taoensso.encore.Ids/genNanoId (.get com.taoensso.encore.Ids/SRNG_STRONG) len)
  (com.taoensso.encore.Ids/genNanoId                                            len))
```

And that `com.taoensso.encore.Ids/SRNG_STRONG` is

```java
public static final ThreadLocal<SecureRandom> SRNG        = ThreadLocal.withInitial(SecureRandom::new);
public static final ThreadLocal<SecureRandom> SRNG_STRONG = ThreadLocal.withInitial(() -> {
        try { return SecureRandom.getInstanceStrong(); }
        catch (java.security.NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to initialize strong SecureRandom", e);
        }});
```

the implmentation in the old library was

```clojure
(defonce *secure-random (delay (SecureRandom.)))
```

So passing `false` for the encore version of the nanoid restores the
previous behavior.

CALLOUT:
One thing to call out is that this did slightly change how we generate
nano-ids based on a seed. We used this behavior to backfill
nano-ids. That let us try to ensure that the same thing in multiple
systems would have the same nano-id, thus identifying them across
systems.

We are now generating different nanoids for the same inputs.

```clojure
❯ java -cp $JARS/1.45.4.jar clojure.main
Clojure 1.11.1
user=> (doto 'metabase.util require in-ns)
metabase.util
metabase.util=> (generate-nano-id "cafebabe")
"VlXdQMzunVywNw_SArkKX"
metabase.util=>
```
This is a consistent nanoid all the way up to 57:
```clojure
❯ java -cp $JARS/1.57.10.jar clojure.main
Clojure 1.12.2
user=> (doto 'metabase.util require in-ns)
metabase.util
metabase.util=> (generate-nano-id "cafebabe")
"VlXdQMzunVywNw_SArkKX"
metabase.util=>
```

And now is different in 58:

```clojure
❯ java -cp $JARS/1.58.3.jar clojure.main
Clojure 1.12.3
user=> (doto 'metabase.util require in-ns)
metabase.util
metabase.util=> (generate-nano-id "cafebabe")
"xNzFsobWPxaYpY0ucTMmz"
```

This is not a problem because we backfilled these nanoids in ~41 or so
and no longer allow anyone to save a model without one. But is worth a
callout that 58 changed this.

* fix drivers team attribution (#69323)

causes module config tests to fail
2026-02-10 11:03:33 -06:00
Jeff Bruemmer
33a572f9a6 docs - handleLink in mod embeds (#69255) 2026-02-10 12:01:55 -05:00
Nathan Voxland
89bb889883 Added MB_MONITOR_PERFORMANCE option (#69298) 2026-02-10 10:59:03 -06:00
Jeff Bruemmer
8e33138caf docs - embedded alerts (#69201)
* embedded alerts

* Apply suggestion from @jeff-bruemmer
2026-02-10 11:58:07 -05:00
Fraser
355a5fc29c Use bun package manager (#68170)
* Use bun in package.json

* Update workflows

* Update more workflows

* Kick ci

* Fix yaml

* Fix type errors

* Compat with snyk

* Fix jest resolutions

* Add another esm package

* Fix aliases and next js missing deps

* Update next js embed tests

* Try fix embed test config

* Fix

* Fix requires in e2e support

* Use bun not yarn in embed bin

* Revert config changes

* Use bun in more scripts and use prepare-release action

* Replace more yarn usages

* Remove overrides from bunfig move to package json

* Revert e2e support changes

* Add back comment

* [ci skip] comment typo

* Update bun lock

* Update to reference bun

* Update to reference bun

* Update license disclaimer

* Tidy tests

* Update to use bun in workflows

* Change aliases

* Update codemirrort selector

* Tidy license generation

* Remove .only

* Fix yarn references

* Checkout .github for release scripts

* Update lockfile

* Re-add package

* update release bunlock

* fix checkout check

---------

Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-02-10 16:27:57 +00:00
github-automation-metabase
50241cb516 Auto-update documentation for master (#69326)
* Update generated docs (master)

* Apply suggestion from @jeff-bruemmer

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-10 16:01:40 +00:00
Braden Shepherdson
3fcac725b2 [QP] Properly escape SQL LIKE metachars for :contains and friends (#67665)
Fixes #67075.

`:starts-with`, `:contains` and `:ends-with`, which use SQL `LIKE`
clauses on SQL databases, were previously using the literal string from
the user directly, without escaping the `LIKE` metacharacters `%`, `_`
and backslash.

This change adds a new `sql.qp` multimethod to the driver API, with a
basic implementation that uses backslashes and works for Postgres,
MySQL/Maria and H2. SQL Server supports escaping via regex-style `[%]`
character classes.

Oracle and SQLite need an explicitly set `LIKE '...' ESCAPE '\'` clause.
I'm leaving that for a future PR since it requires refactoring how the
`LIKE` clauses are constructed more deeply.

Updates the driver changelog, though fortunately the default case should
work for most drivers. Not to be backported, because of the driver API
change.
2026-02-10 15:26:27 +00:00
Nemanja Glumac
e2e2c70165 Fix containerize-uberjar workflow failing on pull requests (#69346)
The workflow was using `github.sha` (the merge commit SHA) when fetching
artifacts, but the uberjar workflow uploads artifacts using the PR head
commit SHA (`github.event.pull_request.head.sha`). This mismatch caused
the containerize workflow to fail with "artifact not found" errors.

Added `github.event.pull_request.head.sha` to the fallback chain in three
places: the artifact fetch commit, the GIT_COMMIT_SHA build arg, and the
Trivy scanner checkout ref.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 16:08:06 +01:00
Timofey Kachalov
df0622c46a Move some logic from translateColumnDisplayName to CLJ lib side (#69005) 2026-02-10 18:45:50 +04:00
Nemanja Glumac
05ab4e7919 Resolve CVE-2026-25639 (#69340)
Even though this vulnerability does not affect our production code,
it was easy to resolve `axios` to the patched version.
2026-02-10 07:15:43 -07:00
Nicolò Pretto
b8ad77a580 fix Back button on eajs browser component (#69273)
* wip

* Revert "wip"

This reverts commit a4dbdef16c.

* cleanup

* fix bug when clicking on breadcrumbs

* clean up old type

* Update frontend/src/embedding-sdk-bundle/components/private/SdkInternalNavigation/SdkInternalNavigationProvider.tsx

Co-authored-by: Phoomparin Mano <poom@metabase.com>

* jsdoc for virtual

---------

Co-authored-by: Phoomparin Mano <poom@metabase.com>
2026-02-10 13:14:09 +00:00
Nicolò Pretto
22c7912005 export InteractiveQuestion.NavigationBackButton and deprecate the old one (#69292)
* export `InteractiveQuestion.NavigationBackButton` and deprecate
`InteractiveQuestion.BackButton`

* jsdoc

* more jsdoc

* add test
2026-02-10 12:32:18 +01:00
Chris Truter
6c73d0a9d4 Return WS api key when it's created (#69333) 2026-02-10 12:48:58 +02:00
Sébastien
084e3ea6df fix(SDK): fixed bugged scrolling in embedded metabot (second version) (#69265)
* fixed bugged scrolling in embedded metabot

* focus

* .

* e2e test
2026-02-10 11:43:36 +01:00
Chris Truter
2957fc98c6 Allow workspace user to archive its own workspace (#69288) 2026-02-10 10:38:58 +00:00
Chris Truter
3286107b15 Ad hoc query API for workspaces (#69274) 2026-02-10 12:33:56 +02:00
Chris Truter
fb97c31b6b Run-stale-ancestors option for workspace transform execution (#69281) 2026-02-10 09:46:13 +00:00
Stas Gavrylov
9529117f1e GDGT-1668: Migrate notifications to TypeScript (#69104)
* Update Claude instructions

* Some DashboardSubscription type usage refactoring

* Migrate SendTestPulse to TS. Introduce DashboardSubscriptionData. Related refactoring

* Migrate ArchivePulseModal to TS

* Migrate UnsubscribePulseModal to TS

* Migrate ArchiveModal and test

* Migrate to TS: UnsubscribeModal. Related refactoring

* Migrate to TS: Notifications actions and routes

* Migrate to TS: ModalRoute refinement

* Fix eslint

* Adjust types of ModalRoutecomponents

* Fixes following bot code review

* Some more type refinement

* Address PR comments

* More fixes/refactoring

* Update route files. Convert to components

* Rename ArchiveNotificationModal to avoid confusion with collections. Fix export

* Fix more exports. Remove type casting. Add Response type guard

* Refactor routes back to getter functions

* Add early return for modals rendering. Add isObject in type-guard

* Refine Response type-guard
2026-02-10 10:41:53 +02:00
Nemanja Glumac
cb119f840b Add auto-detection of changed Loki stories for stress testing (#68951)
* Add auto-detection of changed Loki stories for stress testing

Enable the Loki stress test workflow to automatically trigger on PRs
that modify .stories.tsx files and detect which stories to test based
on git diff. Manual workflow_dispatch still works with optional filter
override.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 09:02:48 +01:00
dpsutton
551108d317 fix drivers team attribution (#69323)
causes module config tests to fail
2026-02-09 21:23:37 -06:00
Fraser
9c5b714279 Convert LegendActions to TypeScript (#69065)
Closes DEV-1410

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-10 15:05:46 +13:00
Maksym Yakubych
19d9dcb047 feat: allow empty min and max for scalar conditional colors (#69177) 2026-02-09 20:34:18 -05:00
Fraser
13a641e649 Convert ViewSidebar to TypeScript (#69070)
* Convert ViewSidebar to TypeScript

Closes DEV-1415

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 20:20:39 -05:00
Fraser
c5fe906f7b Convert ViewLeftSidebarContainer to TypeScript (#69068)
Closes DEV-1413

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 20:20:12 -05:00
Riley Thompson
045a331f78 Update querying team and remove drivers (#69307)
update querying team, remove drivers
2026-02-09 23:01:01 +00:00
Nick Fitzpatrick
5602bcee19 updating upsell CTA links (#69308) 2026-02-09 18:43:26 -04:00
Nick Fitzpatrick
30b32c0c7f Uxw 2973 admin toggle for transforms global (#69240)
* enable page

* update permission functions, add transformsEnabled check

* hook up button

* temp

* add unit tests for transform layout page

* adjusting unit tests for permissions graph

* adjust e2e tests

* temp

* updating checks in e2e tests

* adding missing route mocks to unit test

* now the test should work

* do not export transforms-enabled

* adjust transforms e2e test

* update selectors to be a bit more clear

* additional tests
2026-02-09 18:42:52 -04:00
Nick Fitzpatrick
976f73531b update AllChangesView unit tests (#69313)
* update AllChangesView unit tests

* removing unneeded test
2026-02-09 17:52:42 -04:00
Jeff Bruemmer
98d8aef4f0 docs - embed translations (#69196) 2026-02-09 21:50:32 +00:00
Nathan Voxland
f3e1558740 Don't use the deprecated enable-query-caching value (#69256)
Don't use the deprecated enable-query-caching value which may have been stored as "false" in the database.
2026-02-09 14:21:23 -06:00
Edward Paget
aa7f30169f feat: snippets under 'library' in changes view (#68910)
Display dirty snippets and snippets collections as children of the
library collection in the list of dirty changes for push.
2026-02-09 12:48:52 -06:00
Nathan Voxland
c5c1d2424d Allow data-analysts to call GET /api/user (#69033) 2026-02-09 11:52:41 -06:00
Fraser
744ba25909 Convert Grid to TypeScript (#69058)
* Convert Grid to TypeScript

Closes DEV-1403

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:19:44 -07:00
kevinkelleher12
4c6d90cf00 Fix infinite hang caused by selecting drop down in conditional formatting settings (#69141) 2026-02-09 12:07:15 -05:00
Anderson
b6427ea107 Address issues found by Claude review on "Data Studio Upsells" #68886 (#69258)
Address issues found by Claude review
2026-02-09 13:53:12 -03:00
Fraser
530ca1eab1 Convert Warnings to TypeScript (#69066)
Closes DEV-1411

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 16:45:04 +01:00
Timofey Kachalov
c82d33f4b3 Revert temporary FE-side filters content-translation logic (#69276) 2026-02-09 15:42:39 +04:00
Fraser
265438590b Convert DisclosureTriangle to TypeScript (#69057)
Closes DEV-1402

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 20:51:43 +13:00
metabase-bot[bot]
29790430fe [chore] Update E2E test timings with recent data (#69269)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-09 11:50:52 +13:00
Fraser
30a8a97d84 Convert PermissionsEditorEmptyState to TypeScript (#69053)
Closes DEV-1398

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:12:17 +13:00
Fraser
c7c20bfb12 Convert GlobalFingerprint to TypeScript (#69078)
* Convert GlobalFingerprint to TypeScript

Closes DEV-1423

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:12:01 +13:00
Fraser
04c6381858 Convert LoadingAndGenericErrorWrapper to TypeScript (#69063)
Closes DEV-1408

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:11:45 +13:00
Fraser
2af98ce335 Convert TableSidebar to TypeScript (#69088)
* Convert TableSidebar to TypeScript

Closes DEV-1433

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:11:14 +13:00
Fraser
6c3a3b99ca Convert BaseSidebar to TypeScript (#69089)
* Convert BaseSidebar to TypeScript

Closes DEV-1434

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:09:53 +13:00
Fraser
71e21281bb Convert SegmentFieldSidebar to TypeScript (#69090)
* Convert SegmentFieldSidebar to TypeScript

Closes DEV-1435

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-09 10:09:25 +13:00
Gabriel Moreno
5458b8ae50 Data Studio Upsells (#68886)
* feat: add new gem & pattern backgrounds for upsell page

* feat: use new upsell designs

* feat: bring app switcher & enhance designs

* feat: create `DottedBackground` component

* refactor: purchase page

* fix: pyton transforms upsell condition

* fix: remove unnecessary relative selector

* fix: cta hover states

* fix: border causing layout shift

* fix: draggable decoration lines

* feat: implemnet new designs for remote sync

* refactor: remove DottedBackground from `metabase/ui`

* feat: implement initial in-place trial-up

* feat: use right add-on names for python transforms

* feat: transforms purchase page

* feat: add correct transforms add-ons on api

* reafactor: reorganize upsells code

* feat: python transforms upsell modal

* refactor: reorganize transforms upsell page

* fix: use right add-on

* Move renderTierSelection and renderTierSelection to dedicated components

* remove commented code

* refactor: organize structure properly

* Add some unit tests for transforms upsell

* Add more unit tests

* Clean up

* Fix translatable cost description string / Improve scrolling UX

* Fix copy to make it clear we are charging additional costs

* Fix ts

* Fix tests part 1

* Simplify upsell cost description text

* Fix 1 e2e test

* a few more tested fixed

---------

Co-authored-by: Anderson <anderson@metabase.com>
2026-02-06 20:12:10 -03:00
Riley Thompson
4586ae1efc Allow syncing timestamp_ntz columns in databricks (#67140)
dont exclude timestamp_ntz
2026-02-06 21:48:30 +00:00
Nick Fitzpatrick
7200371783 Scalar viz ensure field to select has a section (#69179) 2026-02-06 17:22:01 -04:00
kevinkelleher12
8e68044b26 Fix "View as table" in visualizer (#69204) 2026-02-06 15:48:24 -05:00
Alexander Polyankin
868b69bc46 Create MBQL queries with the lib in unit and E2E tests (#68719) 2026-02-06 15:47:27 -05:00
Maksym Yakubych
88df5f5a0e fix: prompt suggestions should left-align with the input box (#69227) 2026-02-06 20:42:10 +00:00
Timofey Kachalov
95875a4166 feat(sdk,embed-js): Cover displayed column names with content-translations in additional places (#69192) 2026-02-07 00:42:03 +04:00
Maksym Yakubych
903307c93a fix: the timing of the shimmer loading indicator effect should be 2x as fast (#69239) 2026-02-06 14:41:46 -06:00
Maksym Yakubych
9155352685 chore: move undrfined from ux-west to metabot team in team.json (#69243) 2026-02-06 14:41:18 -06:00
Maksym Yakubych
4a35e01689 fix: dark Theme Hides values in Gauge Chart (#69237) 2026-02-06 14:38:10 -06:00
Maksym Yakubych
378a6384d7 fix: dashboard card becomes uneditable after reordering funnel steps (#69242) 2026-02-06 14:36:22 -06:00
Sébastien
495f4fd395 Guest embedding should use the primary database for queries (#68952)
* Guest Embedding should use the primary database for queries

* make sure user is set to nil for guest embeds

* test

* test

* .

* .

* fixed existing clj test

* fixed existing clj test

* lint

* address comments on unit tests

* using with-database-routing-off

* kondo

* whitespace

* modules order

* addressed comments on tests
2026-02-06 20:27:48 +01:00
Jeff Bruemmer
23831c6fbe docs - note on turning off downloads (#69231) 2026-02-06 18:33:08 +00:00
Nicolò Pretto
4181179942 [feature branch] support internal click behavior with enableInternalNavigation prop in SDK and EAJS (#69117)
* SDK internal navigation: main implementation with context (#68900)

* squashed everything

* Trigger CI

* test ci

* fix accidentally enabling navigation by default

* fix tests

* clean up

* clean up and revert

* fix eslint rule after v9 migration

* idon'trememberanymore

* fix stale closure

* fix button position and more cleanup

* rename to virtual

* fix virtual

* more renaming

* more tests

* more fixes

* more fixes

* more reverts and cleaning up

* remove unused type

* internal navigation: change back button cover on hover (#69122)

* add support for ct to sdk back button (#69219)

add support for tc in back button

* support enable-entity-navigation in EAJS (#69185)

* tests, fixes

* do a real test for guest on a dashboard

* add     "enableEntityNavigation" to types for browser

* Update frontend/src/embedding-sdk-bundle/components/private/SdkInternalNavigation/SdkInternalNavigationProvider.tsx

Co-authored-by: Sébastien <sebastien@metabase.com>

---------

Co-authored-by: Sébastien <sebastien@metabase.com>

* export back button, test that it shows up with title=false, align button (#69222)

* export back button and test it, also test that it shows up with
title={false}

* EMB-1275 map question props to question

* EMB-1278 add last remaining test

* EMB-1299: align back button with save button when drilling

* revert back button changes to keep backward compatibilty

* removed test

---------

Co-authored-by: Sébastien <sebastien@metabase.com>
2026-02-06 17:43:41 +00:00
Nathan Voxland
5fffeb5c62 Allow source-readable to be null in response schema (#69232) 2026-02-06 11:14:09 -06:00
Nicolò Pretto
6a400ce43a feat(modular): support handleLink function (#68418)
* feat(eajs): support handleLink function

* fix unit tests

* rename, remove timeout which caused bugs if host app used alert() or other blocking things

* nest in pluginsConfig as is in the sdk

* put token feature guard

* Revert " put token feature guard"

This reverts commit 4f368ab41e.

* remove isWithinIframe
2026-02-06 17:06:53 +00:00
github-automation-metabase
c0ac8fdce6 Auto-update documentation for master (#69206)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-06 12:04:07 -05:00
Maksym Yakubych
da0f559b55 fix: logo in email is not centered (#68806) 2026-02-06 10:46:44 -06:00
Mahatthana (Kelvin) Nomsawadi
d3f97ef81c Fix broken Metabase icon in SDK banner when using EE with license (#69215)
* Make eslint rule easier to read

* Prevent future misuse of the Metabase logo in the SDK

* Fix wrong Metabase icon on the SDK when using EE build with whitelabel feature

* fix eslint error message
2026-02-06 15:59:01 +00:00
Alex Yarosh
5367b57309 docs: number chart revision and colors (#69207)
* number chart revision and colors

* Optimized 4 images, saved 166.4 KB (48.9% smaller)

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-06 08:59:40 -05:00
John Swanson
2b027c0ed1 JWTs can set tenant attributes (#68562)
* JWTs can set tenant attributes

* use the merge method directly

---------

Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>
2026-02-06 13:08:00 +00:00
Kamil Mielnik
8ba4132e42 GDGT-1620 Flaky workspaces test (#69103) 2026-02-06 18:32:55 +07:00
John Swanson
25cd50c5c4 Allow internal users to have perms on tenant colls (#68181)
* Allow internal users to have perms on tenant colls

Notably, this required allowing internal users to list tenants. I think
this is acceptable?

* CR response

* more cr response
2026-02-06 04:17:39 +00:00
github-automation-metabase
c0085e42d5 Auto-update documentation for master (#69148)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-05 18:24:39 -05:00
Alex Yarosh
24649ede3e docs: data studion perms (#69203)
* access

* sneak in some other edits

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2026-02-05 22:31:41 +00:00
dpsutton
a3e48f0867 trigger cloud driver tests on certain modules (#69200)
* trigger cloud driver tests on certain modules

Motivating example:
https://github.com/metabase/metabase/pull/68256/changes added some
schemas to transform apis. Transforms run when drivers run. But it
didn't trigger cloud dbs. And of course, there was an issue with
redshift transform tests.

https://github.com/metabase/metabase/actions/runs/21718378450/job/62645866080
is the determine driver skips link:

```
=== Module Analysis ===
Changed modules: #{models transforms}
Driver module affected: true
Important file changed: false
Drivers with file changes: #{}

=== Driver Decisions ===
h2                        RUN  - H2/Postgres always run
athena                    SKIP - no relevant changes for cloud driver
bigquery                  SKIP - no relevant changes for cloud driver
clickhouse                RUN  - driver module affected by shared code changes
databricks                SKIP - no relevant changes for cloud driver
druid                     RUN  - driver module affected by shared code changes
druid-jdbc                RUN  - driver module affected by shared code changes
mongo                     RUN  - driver module affected by shared code changes
mongo-ssl                 RUN  - driver module affected by shared code changes
mongo-sharded-cluster     RUN  - driver module affected by shared code changes
mysql-mariadb             RUN  - driver module affected by shared code changes
oracle                    RUN  - driver module affected by shared code changes
postgres                  RUN  - H2/Postgres always run
presto-jdbc               RUN  - driver module affected by shared code changes
redshift                  SKIP - no relevant changes for cloud driver
snowflake                 SKIP - no relevant changes for cloud driver
sparksql                  RUN  - driver module affected by shared code changes
sqlite                    RUN  - driver module affected by shared code changes
sqlserver                 RUN  - driver module affected by shared code changes
vertica                   RUN  - driver module affected by shared code changes
```

Important part is `Changed modules: #{models transforms}` and `redshift
SKIP - no relevant changes for cloud driver`. This intends to change that.

* update comment
2026-02-05 16:08:43 -06:00
Robert Kosara
0ae4c70ba8 Data Studio docs (#66299)
* First check-in of the initial skeleton

* Minor edits

* Docs: dependency graph (#66562)

* first draft of dependency graph

* few edits

* typo

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-graph.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* few edits

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* docs - data studio library (#68602)

* library skeleton

* link

* collection perms

* plans blockquote

* table notes

* updates

* remove data editing

* edits

* Apply suggestion from @jeff-bruemmer

* overview

* intro

* transforms links

* links

* docs: transforms updates (#69037)

* intermediate draft

* more transforms

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* edits

* more links

* more links

* more links

* bot comments

* more bot comments, please just give me all at once

* bot needs to shut up

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* docs: Add Dependency diagnostics page (#68928)

* adding dep diagnostics

* Update docs/data-studio/dependency-diagnostics.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-diagnostics.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Update docs/data-studio/dependency-diagnostics.md

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* some edits

* more edits

* typo

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* docs: data structure (#69184)

* draft

* data structure

* description

* it's measures not metrics

* measures not segments

* Apply suggestion from @jeff-bruemmer

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* Apply suggestions from code review

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

* review

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>

---------

Co-authored-by: Abed Habli <154609371+abdhabli@users.noreply.github.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Co-authored-by: Jeff Bruemmer <jeffbruemmer@gmail.com>
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-02-05 15:24:29 -05:00
William
bf3a0df461 Fix nested if statements (#69144)
If you have an expression with an if statement inside an if statement, the outer if would get desugared to a case
statement, but the inner if would be left untouched.  This makes desugaring also desugar the inner if.
2026-02-05 20:06:31 +00:00
Braden Shepherdson
a609c0466b [deps] Split "supported" entities into analyzable and dependable (#69188)
Fixes QUE-3070.

This splits the vague, dual-purpose `supported-entities` into two:
- those entities which can be depended on, whose dependents get marked
  stale when they're updated (eg. a table during sync)
- those entities which we can analyze, and should check for staleness

I added `:table` to the old `supported-entities` since they're a valid
*upstream* dependency that might needs its downstream dependents to be
marked as stale, and it failed the schema.

The trouble is that we don't run analysis on tables, but the same set of
"supported" types was used to check for what entities need reanalysis.

That led to a chain like this:
- Something changed, and the entity-check job is scheduled immediately.
- It runs, and checks each `supported-entities` for any entity with
  a missing, `stale` or outdated analysis finding.
- That list now includes tables, and since tables are not analyzed none
  of them have entries - so there's apparently lots of work to do!
- On trying to analyze tables, it fails because they're not supported,
  and it silently does nothing.
- But the batch draining logic still thinks the whole batch was used, so
  it reschedules.
- No real progress is getting made, since the tables cannot really be
  analyzed, therefore they never get marked as done.
- Infinite loop spinning forever!
2026-02-05 14:47:33 -05:00
Nathan Voxland
eeea8c5f3f Add metabase_table.transform_id column (#69125)
* Create a metabase_table.transform_id column instead of dynamically populating it from the dependencies

* Fixing tests

* Include transform in table dependencies

* Moved test after merge

* Moved test after merge

* transforms are now oss

* Fixed failing tests

* Review fixes
2026-02-05 11:24:49 -08:00
Anderson
59c9a579f2 Replace 'data-studio' token feature with 'library' (#69040)
* Replace 'data-studio' token feature with 'library' / data_analyst behind advanced permissions (clean git history)

* Fix clj test

* Fix a couple be tests

* Fix e2e test
2026-02-05 16:19:29 -03:00
Nathan Voxland
eb3d3d806b Added schema to transform API responses (#68256) 2026-02-05 13:07:34 -06:00
Nathan Voxland
42d0d35dbd Do a rollback before discard all (#69026)
Do a rollback before discard all, since discard all can't be ran in a transaction.
2026-02-05 13:07:20 -06:00
Nathan Voxland
5d40e0ab95 Correctly select jobs to run based on tags (#69137) 2026-02-05 13:06:59 -06:00
John Swanson
9e980b9315 bugfix for dependency diagnostics error (#68968)
We were calling `perms/visible-database-filter-select` incorrectly. It
takes a minimum permission.
2026-02-05 10:27:19 -08:00
Maksym Yakubych
4b805ef246 feat: add duplicate option in 3 dot menu in a document (#68075) 2026-02-05 15:10:48 -03:00
Noah Moss
0234ce1061 Hide transforms from metabot if source is not readable (#69041)
* Hide transforms from metabot if source is not readable

* test simplification

* fix test nesting

* dedupe transform-ids earlier

* Fix module interface

* Fix rebase - transforms were moved to OSS
2026-02-05 10:59:23 -05:00
Ryan Laurie
bfc4963109 Automate js/ts stats update (#69167)
* automate typescript stats update

* job id

* fix var name

* cleanup

* remove test code
2026-02-05 08:27:30 -07:00
Nick Fitzpatrick
f7336c2068 update copy (#69130)
* update copy

* update e2e tests
2026-02-05 11:15:37 -04:00
dpsutton
04ac52e1d6 make sure database is initialized (#69173)
seeing error in CI:

```
ERROR in metabase.upload.db-test/current-database-test (DbException.java:502)
Uncaught exception, not in assertion.

             clojure.lang.ExceptionInfo: Table "METABASE_DATABASE" not found (this database is empty); SQL statement:
                                         SELECT * FROM "METABASE_DATABASE" WHERE "UPLOADS_ENABLED" = TRUE [42104-214]
```

https://github.com/metabase/metabase/actions/runs/21711162702/job/62620032674

we just need to ensure that the db is initialized first
2026-02-05 09:05:26 -06:00
Roman Abdulmanov
5d745ce4c8 Report tenants usage info to HM (#69009)
report tenants usage info to HM
2026-02-05 14:28:37 +00:00
Nemanja Glumac
c5960b7d9d Add Rosetta 2 detection and installation to dev-install (#69115)
On Apple Silicon Macs, some webpack dependencies (webpack-notifier)
require Rosetta 2 to run x86_64 binaries. Without it, the webpack dev
server fails with "Error: spawn Unknown system error -86".

This adds a check during prerequisites that detects if Rosetta is
missing and offers to install it via softwareupdate --install-rosetta.

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 14:22:08 +01:00
da
478b097458 Upgrade jspdf (#69113) 2026-02-05 13:37:24 +01:00
Dan Stone
14d95aaf44 Allow medallion values on read (#69158)
Our migrations can race with writers, this leads to situations
where we might still see values for e.g. an enum according to some prior
schema.

We saw on stats a sync occurred concurrently with the migrations and caused a record with medallion data_layer values to appear _after_ the migration.

Should follow up with a longer term fix without leaving such cruft in the code.
2026-02-05 12:17:41 +00:00
Nemanja Glumac
0d24b395e8 Fix broken containerize workflow (#69156) 2026-02-05 11:23:45 +00:00
Kamil Mielnik
8c0645cc97 GDGT-1585 Update incremental transform warning copy for complex queries (#69109)
Update copy in QueryComplexityWarning
2026-02-05 17:54:39 +07:00
Nemanja Glumac
ee20f35b7f Programmatically list source directories for cloverage (#68955) 2026-02-05 11:18:16 +01:00
Nicolò Pretto
5b8748fda3 feat(modular): support relative paths for jwtProviderUri (#69119)
feat(modular): support relative paths for jwtPRoviderUri
2026-02-05 10:28:12 +01:00
Nemanja Glumac
8143e32165 Unify the JAR artifact naming strategy (#69114) 2026-02-05 10:03:40 +01:00
Fraser
ad9d9d886b Convert List to TypeScript (#69059)
Closes DEV-1404

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 21:24:17 +13:00
Mahatthana (Kelvin) Nomsawadi
2028e4af8c Remove links from all alerts/subscriptions related emails in modular embeddings (#69014)
* Remove link from broken dashboard notification

* Remove links from alerts setup email

* Add tests

* Remove links from unsubscribe email

* Remove links from card change or archived emails

* add tests for card change email notifications

* add tests to the broken dashboard email

* Format

* Remove unused comments

* Improve test util names

* Format again

* Fix name
2026-02-05 05:11:20 +00:00
Fraser
d0f660ba08 Convert Remapped to TypeScript (#69083) 2026-02-05 03:03:30 +00:00
Fraser
7d269ec8cd Convert ReferenceHeader to TypeScript (#69085)
Closes DEV-1430

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:57:42 +13:00
Fraser
d3c44902a1 Convert QuestionSummarizeWidget to TypeScript (#69071)
Closes DEV-1416

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:55:55 +13:00
Fraser
2963e8e325 Convert DatabaseSidebar to TypeScript (#69086)
* Convert DatabaseSidebar to TypeScript

Closes DEV-1431

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:55:36 +13:00
Fraser
2785b1391c Convert SegmentSidebar to TypeScript (#69091)
* Convert SegmentSidebar to TypeScript

Closes DEV-1436

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:41:53 +13:00
Fraser
4e87135f5f Convert ChartSettingColorsPicker to TypeScript (#69094)
Closes DEV-1439

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:41:04 +13:00
Fraser
e27825b087 Convert AccountApp to TypeScript (#69077)
Closes DEV-1422

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:39:08 +13:00
Fraser
4336e7bc1c Convert FieldSidebar to TypeScript (#69087)
* Convert FieldSidebar to TypeScript

Closes DEV-1432

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:38:51 +13:00
Fraser
5ce4289d08 Convert SidebarLayout to TypeScript (#69074)
Closes DEV-1419

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-05 15:36:34 +13:00
Denis Berezin
9585b7a065 Move Data Studio common stuff to OSS (#68571)
* Fixing tests

* Fixing tests

* Fixing tests

* Fixing tests

* Fixing tests

* Fixing tests

* Fixing test

* Added source_readable to transform APIs

* Fixing tests

* Starts implementing read-only state for job detail page

* Stubs out potential solution for preventing non-admins from putting jobs into a state where they can no longer edit them

* Troubleshooting failing test

* Shows permissions error on transform page when user doesn't have source-read permissions. Disables run button when user lacks write access.

* Troubleshooting failing test

* Makes TagSection readOnly on job page if user lacks write access on any transforms that'd be run by the job

* Removes unnecessarily duplicated code from ScheduleSection

* Troubleshooting failing test

* Troubleshooting failing test

* Troubleshooting failing test

* Troubleshooting failing test

* Cleanup

* Fix unit tests

* Updates e2e test (group-15)

* Updates e2e tests (transforms-permissions.cy.spec.ts)

* Fixed transform-job permission check

* Only require transform write access for tag selector on job page

* Tweak tag tooltip text

* Prevents deleting/editing tag when it runs a job the user doesn't have transform write access on

* Adds a couple more transforms-permissions e2e tests

* Build transform permission off table can-query

* Added :can_run to transform-tag API

* Updates FE to use can_run on TransformTag

* Code cleanup

* Updates transforms list to disable transform rows the user doesn't have read access for

* Code cleanup

* Fixing test failures

* Fixing test failures

* Fixing test failures

* Fixing test failures

* Merged from master

* Test troubleshooting

* Resolved conflicts

* fixup: Reimplements row disabling in TransformListPage

* fixup: Adds readOnly prop to new IncrementalTransformSettingsWrapper component

* fixup: Reimplements readOnly state for PythonTransformEditor

* Adds read-only state for transform owner section

* Updates recently-moved canAccessDataStudio with canAccessTransforms check

* Updates permission-management unit tests

* Adds tooltip to transform column in permissions table

* Hides tooltip in Transforms column in permissions table if selected group is admin or analysts

* Fix unit test

* Updates some e2e tests that deal with non-admins using transforms to make sure they belong to the analyst group

* Adjusting backend permissions for new logic: all analysists can see transforms they have db access to, transform-permission is for writes

* Code improvements

* Code improvements

* Fixed test

* Fixing tests

* Troubleshooting tests

* Troubleshooting tests

* Fixing tests

* Update e2e tests

* Brought back can_access_transforms

* Fixing tests

* Better python permission checking

* Start, WIP

* Moved Library back to EE

# Conflicts:
#	enterprise/frontend/src/metabase-enterprise/data-studio/library/LibrarySectionLayout/PublishTableModal.tsx
#	frontend/src/metabase/data-studio/data-model/components/TableSection/TableAttributesEditBulk.tsx

* Continue moving Library back to EE

* Hotfix

* Fixing permissions

* Fixing permissions

* Fixing tests

* Fixing tests

* move out transforms api

* Fixing tests

* move transforms to oss

* actually it is true

* cleanup

* Fixing tests

* Fix post-merge ts error

* Close library functionality in OSS, fix some units

* Move oss table api endpoints for data structure, fix more unit tests

* Move oss table api endpoints for data structure, fix more unit tests

* Updates transforms list page so "New" is hidden and "Python library" is disabled if user has no transform permission for any database

* Fix typecheck issues

* Move non-python transform APIs to OSS

* Fix kondo

* Fix EE BE

* Code review fixes

* Code review fixes

* Merge remote-tracking branch 'origin/master' into transforms-permissions

# Conflicts:
#	.clj-kondo/config/modules/config.edn
#	enterprise/backend/test/metabase_enterprise/remote_sync/transforms_test.clj
#	enterprise/frontend/src/metabase-enterprise/transforms/pages/TransformListPage/TransformListPage.tsx

* Code review fixes

* Fixed merge conflict

* Fixed merge conflict

* Fix lint and TS error from merge

* Fix merge issues

* Fix be issues

* Fix some unit tests

* Fix be tests issues

* Fix be tests issues

* Code review fixes

* Allow people with transform permission to see syncable schemas on a db

* code cleanup

* Fix be tests issues

* Fixing permissions

* Fix be tests issues

* Fix prettier

* wip: oss transforms

* fix module order

* fix tests for OSS transforms

* cleanup

* cleanup

* Fix some unit tests

* Fix library for OSS

* fix some more tests

* cljfmt

* add missing placeholder file

* fix more tests

* more tests

* more tests

* deftest-oss into `metabase.test`

* Fix some unit tests

* Fix some unit tests

* Fix transforms upsell for oss

* fix search filter

* fix transforms tables

* fix cycles

* feat: transform setting into collection list (#68758)

* feat: transform setting into collection list

Move the setting for syncing transforms into the list of collections
available to remote sync, so conceptually the transforms root collection
looks like a standard syncable collection.

* Clean up FE a little bit

* undo unneeded changes

---------

Co-authored-by: Anderson <anderson@metabase.com>

* Remove Security and Appearance from embedding settings related links on OSS (#68151)

* feat: enable transform setting on first import (#68807)

* feat: enable transform setting on first import

When a we import a remote that has transforms set the
`remote-sync-transforms` setting to true.

Update the remote sync object table clean up to be driven by the spec
configuration.

Add tests showing that transforms are consistently synced and erased
according to the following rules:

1. if the instance has `remote-sync-transforms` off and local transforms
and the remote does not have transforms content they are preserved after
an import
2. if the instance has `remote-sync-transforms` off and local transforms
and the remote has transforms content, the local transforms are
completely replaced by the remote.
3. if the instance has `remote-sync-transforms` on and the remote has
transforms content any local transforms are completely replaced by the
remote.
4. if the instance has `remote-sync-transforms` on has local transforms,
but the remote has no transforms, the local transforms are removed on import.

* fixup! relocate settings update

* fixup! don't let python libraries clash on import

* fixup! transactions for mysql

* fix: y axis not shown even if it would fit (#68861)

* Deps breaking broken (#68866)

* Add rename /broken to /breaking and add new /broken

---------

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>

* Analysts can do crud on segments and measures (#68501)

* Data Analyst CRUD on measures/segments

Data analysts with unrestricted view-data permissions on a table can now
create, update, and delete segments and measures for that table
(previously superuser-only).

`can-read?` was already granted by the `manage-table-metadata` permission.

Add permission tests for `can-write?` and `can-create?` methods.

* Remove `brand-light` and `brand-lighter` (#68290)

* brand key adjustments

* loki tests

* handle the forgotten brand-dark

* Update Loki Snapshots

* removing brand-hover from dynamic-css-vars

* Adjustments to calendar picker colors

* small adjustments on the permissions pages

* sdk: remove background-hover tests from sdk as dynamic css derives are replaced with color-mix

* stupid spelling

* building shared resources

* Adjusting unit test, loki images

* rebasing adjustments

* Update Loki Snapshots

* small color fixes while I wait for loki

* re-adding highlighted class

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>

* Fix empty Python Library not showing placeholder/comment (#68826)

* CI: query-processor module should trigger driver tests (#68877)

* Delete fuzzing workflow (#68880)

* fix(sdk): fix failing tests for white-labeled colors (#68790)

* Dependency diagnostics sidebar updates (#68825)

* Use getter function to move element (#68714)

* Fix cloud implicit join tests (#68762)

A previous pr broke some tests on master, and this fixes them.

* feat(sdk, embed-js): Add an alerts support to modular embeddings (#68777)

* Add an alerts button on the SDK (#67796)

* Prepare to add alerts to SDK

* Remove unrelated prop from storybook

* Add basic alerts button

* Only show alerts button with the proper flag

* Prevent download button from being shown without proper flag

* use CSS to hide things instead of JS

* Properly position all question buttons

* Use JS to hide empty divs as pure CSS is impossible

* Render alert modal ✌️

* Fix type

* Add todo

* Structure the components better

* Control alert modal state

* Add interactive question storybook

* Make interactive and static question button styles consistent

* Add alerts modal to interactive question

* Make alert button works with custom layouts

* Fix tests

* Fix unit tests

* Fix import order issue

* Remove outdated comment

* Add the same condition to display alert button from the core app

* Polish

* Modify question storybooks to show a question instead of a model

* Hide empty elements more reliably

* Add more conditions to display alert button

* Remove unused `classNames` prop

* Use the same style as the interactive question one

* Remove outdated diff

* Fix alerts button not working in custom layouts

* Remove another unused code

* Add a basic test

* Add unit tests

* fix visibility logic

* Fix E2E tests

* Make assertion on static question tests better

* Improve assertions

* Add interactive question unit tests

* Add e2e test for static question

* Add interactive question e2e tests

* Fix subcomponent

* clarify comment

* Hide other channels than email on the alert modal (#68184)

* Hide channel options on alerts modal

* Add unit tests

* Make the test name clearer

* Fix can't view created notifications the first time (#68197)

* Fix can't view created notifications

* Add tests

* Remove unnecessary return type

* Add a safety guard

* Hide Alert (and download) button on edit mode (#68189)

Hide some buttons on edit mode as it makes no sense there

* Alerts polishing (#68477)

* Misc. improvements

* Make it typesafe

* Add alerts to modular embedding (#68286)

* Add the option in modular embedding wizard

* Support `withAlerts` in modular embedding

* Close the modal after hiding the alert button

* Add E2E tests

* Fix type

* Fix `withAlerts` not working on modular embedding with `drills: false`

* It's 2026!

* 1 plugin to rule 'em all!

* Fix E2E after merging master

* Fix test name

* Add alerts analytics (#68531)

* Add alert setup analytics

* Track withAlerts on modular embedding

* Update snowplow schema

* Fix E2E tests

* Fix schema version

* Remove links from alerts test email (#68547)

* Remove links from alerts template

* Remove links from alert email computed part

* Add tests

* Make embedding util easier to use

* Make alerts and subscriptions payload lighter

* Remove unexpected pprint

* Remove links from alert email via tasks (#68610)

* Save notification card's disable_links when creating

* Add tests

* make bin/mage run-tests able to run a single test (#67450)

* Add content translations for aggregations (#68733)

* fix: typecheck

* oops, add missing file

* fix upload impl tests

* Move upsells to ee for transforms

* fix search tests

* fix mage tests

* fix audit perms

* fix `user->tenant-collection-and-descendant-ids`

* reorganize transform permissions

* fix cyclic dep

* add forgotten test file

* fix modules tests / kondo

* another module config fix

* Fix python transforms upsell in oss, fix unit tests

* fix more tests

* one more test

* one more

* Fix e2e tests

* one more

* and a few more

* oops, syntax error

* fix more tests

* kondoooooo

* dumb test: try increasing latch timeout

* hopefully actually fix h2 oss test

* Fix flaky e2e tests

* Fix lint

* Trigger rebuild

* Fix CI

* Fix CI

* Fix failing e2e test

* fix check for is-data-analyst

* Gate transforms based on `:hosting` flag

* move noop events

* Remove unnecessary `check-permissions-for-model`

* use transform feature gating in `can-read?`

* cr resp: moving tests around

* add `enabled-source-types-for-user` and use it

* remove last `deftest-oss` usage

also clean up kondo config:

- no longer define custom expansions for old macros that no longer exist
- remove `deftest-oss`

* change owner to UX west

* use `is-data-analyst?` and `check-data-analyst`

... in a few more places, instead of manual `(or api/*is-superuser?* api/*is-data-analyst?*)`

* Fixes for BE after merge

* Integrate Workspaces code

* Fixes for BE

* Fixes for BE

* Fixes

* remove unnecessary `when-ee-evailable`

also that typo is driving me up the wall and I'm going to need to fix
it :grimace:

* transforms doesn't use config

* missing import

* fix tests

* kondoooo

* last be test failure?

* fix feature gating for workspaces transforms API

why do we have a separate workspaces transforms API

* kondo

* two more tests

* tests

* couple more tests

* almost... there

* fix a flaky transform run test

this was failing locally because I already had enough transform runs to
fill up the page. simple helper to clean up the transform runs that
exist before running the test, then restore them.

* fix data-model.shared.cy.spec.ts

---------

Co-authored-by: Nathan Voxland <nathan@metabase.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
Co-authored-by: Aleksandr Lesnenko <alxnddr@gmail.com>
Co-authored-by: John Swanson <john.swanson@metabase.com>
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Anderson <anderson@metabase.com>
Co-authored-by: kevinkelleher12 <kevin.kelleher@metabase.com>
Co-authored-by: Maksym Yakubych <undrfined@gmail.com>
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
Co-authored-by: bryan <bryan.maass@gmail.com>
Co-authored-by: Fraser <fraser@metabase.com>
Co-authored-by: Phoomparin Mano <poom@metabase.com>
Co-authored-by: Romeo Van Snick <romeo@romeovansnick.be>
Co-authored-by: William <william@metabase.com>
Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
Co-authored-by: Oleksandr Solovyov <alexander@solovyov.net>
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2026-02-05 02:30:18 +00:00
Fraser
b3f643fad6 Convert CollectionName to TypeScript (#69082) 2026-02-05 15:27:04 +13:00
Maksym Yakubych
2d3ed1861c fix: mini picker loader style (#69027) 2026-02-04 15:17:10 -08:00
John Swanson
beb2b5b751 Change permission required to view segment (#67855)
I think this permission makes more sense and is probably what we
intended. Note that users without `manage-table-metadata` but with table
permission can already read this information from the
`/api/query_metadata` endpoint.
2026-02-04 22:26:25 +00:00
dpsutton
b5ef6e1d0c module test runner (#69124)
* module test runner

support for `:module` and `:modules` syntax for our test runner

When using multiple with `:modules` need to put them in a vector, and
for shell reasons need to quote it. So there's a convenience method
where you just pass an individual:

```shell
clj -X:dev:ee:ee-dev:test :modules '[tiles enterprise/agent-api]'
clj -X:dev:ee:ee-dev:test :module enterprise/agent-api
```

REPL
===

```clojure
test-runner=> (metabase.test-runner/find-and-run-tests-repl
                {:modules '[tiles enterprise/agent-api]})
Running tests with options {:mode :repl, :namespace-pattern #"^(?:(?:metabase.*)|(?:hooks\..*))", :exclude-directories [".clj-kondo/src" "classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000, :only ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")}
Running tests in ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")
Looking for test namespaces in directory test/metabase/tiles
Looking for test namespaces in directory enterprise/backend/test/metabase_enterprise/agent_api
Finding tests took 159.0 ms.
Running 32 tests
Running before-run hooks...

LONG TEST in metabase-enterprise.agent-api.api-test/get-metric-details-test
Test took 3.447 seconds seconds to run
Ran 32 tests in 6.506 seconds
129 assertions, 0 failures, 0 errors.
{:test 32, :pass 129, :fail 0, :error 0, :type :summary, :duration 6505.825875, :single-threaded 20, :parallel 12}
Ran 12 tests in parallel, 20 single-threaded.
Finding and running tests took 6.7 s.
All tests passed.
Running after-run hooks...
Running QP tests against these drivers: #{:h2}
{:test 32,
 :pass 129,
 :fail 0,
 :error 0,
 :type :summary,
 :duration 6505.825875,
 :single-threaded 20,
 :parallel 12}
```

CLI
===

multiple:
```shell
❯ clj -X:dev:ee:ee-dev:test :modules '[tiles enterprise/agent-api]'
Warning: environ value /Users/dan/.sdkman/candidates/java/current for key :java-home has been overwritten with /Users/dan/.sdkman/candidates/java/21.0.2-tem
Reflection warning, clojurewerkz/quartzite/triggers.clj:85:6 - call to method forJob on org.quartz.TriggerBuilder can't be resolved (argument types: unknown).
Reflection warning, clojurewerkz/quartzite/scheduler.clj:254:3 - call to method checkExists on org.quartz.Scheduler can't be resolved (argument types: unknown).
Reflection warning, macaw/walk.clj:47:5 - call to method walk on com.metabase.macaw.AstWalker can't be resolved (argument types: unknown).
Running tests with options {:mode :cli/local, :namespace-pattern #"^(?:(?:metabase.*)|(?:hooks\..*))", :exclude-directories [".clj-kondo/src" "classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000, :exclude-tags [:metabot-v3/e2e], :only ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")}
Running tests in ("test/metabase/tiles" "enterprise/backend/test/metabase_enterprise/agent_api")
Looking for test namespaces in directory test/metabase/tiles
Looking for test namespaces in directory enterprise/backend/test/metabase_enterprise/agent_api
Finding tests took 11.8 s.
Running 32 tests
Running before-run hooks...

 0/32     0% [                                                  ]  ETA: --:--Placeholder until other changesets
LONG TEST in metabase-enterprise.agent-api.api-test/get-metric-details-test
Test took 10.536 seconds seconds to run

32/32   100% [==================================================]  ETA: 00:00

Ran 32 tests in 18.556 seconds
129 assertions, 0 failures, 0 errors.
{:test 32, :pass 129, :fail 0, :error 0, :type :summary, :duration 18555.859333, :single-threaded 20, :parallel 12}
Ran 12 tests in parallel, 20 single-threaded.
Finding and running tests took 30.4 s.
All tests passed.
Running after-run hooks...
Running QP tests against these drivers: #{:h2}
```

individual:

```
❯ clj -X:dev:ee:ee-dev:test :module enterprise/agent-api
Warning: environ value /Users/dan/.sdkman/candidates/java/current for key :java-home has been overwritten with /Users/dan/.sdkman/candidates/java/21.0.2-tem
Reflection warning, clojurewerkz/quartzite/triggers.clj:85:6 - call to method forJob on org.quartz.TriggerBuilder can't be resolved (argument types: unknown).
Reflection warning, clojurewerkz/quartzite/scheduler.clj:254:3 - call to method checkExists on org.quartz.Scheduler can't be resolved (argument types: unknown).
Reflection warning, macaw/walk.clj:47:5 - call to method walk on com.metabase.macaw.AstWalker can't be resolved (argument types: unknown).
Running tests with options {:mode :cli/local, :namespace-pattern #"^(?:(?:metabase.*)|(?:hooks\..*))", :exclude-directories [".clj-kondo/src" "classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000, :exclude-tags [:metabot-v3/e2e], :module enterprise/agent-api, :only ("enterprise/backend/test/metabase_enterprise/agent_api")}
Running tests in ("enterprise/backend/test/metabase_enterprise/agent_api")
Looking for test namespaces in directory enterprise/backend/test/metabase_enterprise/agent_api
Finding tests took 12.6 s.
Running 19 tests
Running before-run hooks...

 0/19     0% [                                                  ]  ETA: --:--Placeholder until other changesets
LONG TEST in metabase-enterprise.agent-api.api-test/get-metric-details-test
Test took 11.252 seconds seconds to run

19/19   100% [==================================================]  ETA: 00:00

Ran 19 tests in 19.122 seconds
105 assertions, 0 failures, 0 errors.
{:test 19, :pass 105, :fail 0, :error 0, :type :summary, :duration 19122.404791, :single-threaded 19}
Ran 0 tests in parallel, 19 single-threaded.
Finding and running tests took 31.8 s.
All tests passed.
Running after-run hooks...
Running QP tests against these drivers: #{:h2}
```

* very opinionated
2026-02-04 15:40:51 -06:00
Phoomparin Mano
de1fb87ba1 Add onboarding stepper component for embedding data permissions onboarding (#68801)
* add onboarding accordion

* add storybook for onboarding accordion

* fix the hover color of accordion

* chore: remove unused scrollListItemIntoView

* cleanup accordion

* add onboarding stepper instead

* retain checked icon in selected steps

* remove active step

* add unit tests for accordion

* rename step label to step number

* remove stepper root

* remove explicit ref

* refactor: simplify styles

* simplify storybook

* auto advance stepper

* support locked steps

* auto-infer step number

* remove forwardRef

* do not provide defaults for completed and locked steps

* add horizontal padding to match 64px in design

* style fixes to match design

* address reviews on scroll refs

* fix inconsistent scroll state
2026-02-04 21:18:27 +00:00
Phoomparin Mano
72c578bfdc Remove old llms.txt superseded by Jekyll plugin on docs site (#69132)
remove llms.txt and llms-embedding-full.txt superseded by Jekyll build plugin
2026-02-05 04:57:01 +08:00
Edward Paget
13389939e4 fix: dependency check for snippet eligibility (#69024)
* fix: dependency check for snippet eligibility

* fixup! rename eligibility function
2026-02-04 20:53:19 +00:00
appleby
8824365c61 Remove metabase.llm.costs (#69043)
Rather than providing a best-effort estimate that is likely to get stale, just report 0.0 for the estimated cost.

https://github.com/metabase/metabase/pull/68929#discussion_r2761321583
2026-02-04 11:25:05 -08:00
da
52c03c5b8a Fix formatting and spacing in quartz.properties. Add check in intervals to clusters (#68983)
Fix formatting and spacing in quartz.properties

Adding a new line for Quartz to check in on clusters
2026-02-04 15:54:52 -03:00
Alexander Polyankin
e10dfc7cfc Extract UI components for QB filter widgets (#69051) 2026-02-04 18:41:19 +00:00
github-automation-metabase
8d5a4f6804 Auto-update documentation for master (#69048)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-04 13:21:20 -05:00
Jakub Chodorowicz
ce6d00430d Gdgt 1298 act on e2e code duplication of admin metadata and data (#68600) 2026-02-04 18:35:20 +01:00
Eric Normand
7017eb7941 [Mutation Testing] Kill mutations in metabase.lib.page/page (#69019)
* [Mutation Testing] Add tests for metabase.lib.page/page
2026-02-04 11:03:14 -06:00
Eric Normand
57f23cf311 [Mutation Testing] Kill mutations in metabase.lib.segment/check-segment-overwrite (#68981)
* [Mutation Testing] Add tests for metabase.lib.segment/check-segment-overwrite
2026-02-04 11:02:46 -06:00
Timofey Kachalov
9bacef5fc1 feat(sdk, embed-js): Add joined tables/temporal/bins content translations for aggregations and breakouts and question title (#68954) 2026-02-04 19:09:25 +04:00
Nick Fitzpatrick
5bd8b24794 Only show an app switcher in the dependency page, not the tabs (#68966)
* Only show an app switcher in the dependency page, not the tabs

* fix unit test
2026-02-04 10:54:57 -04:00
Braden Shepherdson
fb225582a8 [Athena] Correctly recognize :base_type when db type is uppercase (#68369)
Athena's JDBC driver returns type names with the same capitalization as
the user types into the admin interface, but the
`sql-jdbc.sync/database-type->base-type` implementation for Athena only
recognized lower-case names (which are the defaults, I gather).

I think most databases don't have this problem, since they ignore the
case you typed in e.g. `CREATE TABLE` statements and have the JDBC
driver always return the canonical spelling of the type names.
2026-02-04 14:39:14 +00:00
Nick Fitzpatrick
c34013f4ff updating color for .SecondaryCTALink (#68001)
* updating color for .SecondaryCTALink

* light and dark upsell themes

* faster storybook build maybe?

* fix types, undo storybook changes

* Update Loki Snapshots

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
2026-02-04 10:32:49 -04:00
Braden Shepherdson
cb62b19dd6 [deps] When Table Metadata is edited, re-analyze all dependents (#68683)
Fixes QUE-3000.

When either the table metadata or field metadata is edited, this runs
the analysis. Since only some metadata changes can impact the analysis,
this is over-sensitive and runs sometimes when it doesn't need to.
2026-02-04 09:21:20 -05:00
Kamil Mielnik
d08614d4d2 GDGT-1658 Unskip custom columns repro (#69097) 2026-02-04 20:38:06 +07:00
Sébastien
5558eeabed feat(sdk, embedjs): support saving and editing questions created with metabot (#68950)
* support saving and editing questiosn created with metabot in SDK/EAJS

* EAJS

* added schema types

* e2e test

* addressed PR comments
2026-02-04 14:36:16 +01:00
github-automation-metabase
f5942dae77 [chore] Update llms.txt for master (#69102)
Update llms.txt and llms-full.txt (master)

Regenerated llms.txt to include all markdown files from the docs/ directory.
Also generated llms-full.txt files for the embedding section.

🤖 Generated automatically by llms-txt-generate workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-02-04 10:53:59 +00:00
Fraser
c8d1566e3c Convert routes-embed to TypeScript (#69092)
Closes DEV-1437

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 22:17:53 +13:00
Fraser
ad356ffe36 Convert routes-public to TypeScript (#69093)
Closes DEV-1438

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 22:17:32 +13:00
Fraser
823559542c Remove unused eslintrc files (#69098) 2026-02-04 22:14:02 +13:00
Jakub Chodorowicz
f7801bbc47 feat: change data layer medallion inspired values to hidden, internal and published (#66330)
Change medallion values to hidden/internal/published. Hidden inherits visbility_type = hidden behaviour, internal/final are label only for now.

---------

Co-authored-by: Dan Stone <wotbrew@gmail.com>
2026-02-04 09:13:31 +00:00
Sloan Sparger
9eebf22cbc [Typescript] Convert files that need no changes (#68321) 2026-02-04 21:55:43 +13:00
Nemanja Glumac
cf48b132de Fix jest-haste-map duplicate manual mock warning (#68993)
Jest's haste map uses filenames (without extensions) as identifiers for
manual mocks. Both ExplicitSize and NativeQueryEditor had `__mocks__/index.ts`
barrel files, causing a collision on the name "index".

Fix by removing the barrel files and using explicit require() calls in
register-visualizations.js to point directly to the uniquely-named mock
files (ExplicitSize.tsx and NativeQueryEditor.jsx).

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-04 14:58:33 +07:00
Nemanja Glumac
12f5000d9f Fix broken Link mock (#68995)
The fix was changing the mock from returning a function directly (which
would be a default export) to returning an object with a Link property
(named export), matching how the actual module exports the component.
2026-02-04 14:47:39 +07:00
Alexander Polyankin
db53feb9ab Hydrate root collection in transform runs (#69047) 2026-02-03 23:38:23 -05:00
dpsutton
604a1d4301 log attribution (#68906)
* log attribution

```
2026-01-30 16:00:53,351 INFO audit-app.audit :: Copying complete. {mb-team=UX West}
2026-01-30 16:00:53,451 INFO notification.seed :: Seeding default notifications {mb-team=Gadget}
2026-01-30 16:00:53,647 INFO notification.seed :: Seeded notifications: {:skip 6} {mb-team=Gadget}
2026-01-30 16:00:53,658 INFO startup.core :: Running setup logic SearchIndexInit ☑️ {mb-team=DevEx}
2026-01-30 16:00:53,658 INFO startup.core :: Running setup logic analytics-dev-mode-setup ☑️ {mb-team=DevEx}
2026-01-30 16:00:53,668 INFO jdbcjobstore.JobStoreTX :: ClusterManager: detected 1 failed or restarted instances.
2026-01-30 16:00:53,668 INFO jdbcjobstore.JobStoreTX :: ClusterManager: Scanning for instance "mbp-m1.lan1769787254192"'s failed in-progress jobs.
2026-01-30 16:00:53,671 INFO search.core :: Initializing search indexes {mb-team=UX West}
2026-01-30 16:00:53,671 INFO core.QuartzScheduler :: Scheduler MetabaseScheduler_$_mbp-m1.lan1769788852529 started.
2026-01-30 16:00:53,671 INFO task.impl :: Task scheduler started {mb-team=UX West}
2026-01-30 16:00:53,678 INFO util.queue :: Starting listener field-value-invalidate with 1 threads 🎧 {mb-team=DevEx}
2026-01-30 16:00:53,688 INFO util.queue :: Starting listener search-index-update with 1 threads 🎧 {mb-team=DevEx}
2026-01-30 16:00:53,688 INFO core.core :: Metabase Initialization COMPLETE {mb-team=UX West}
2026-01-30 16:00:53,697 INFO core.core :: Metabase Initialization COMPLETE in 3.2 s (JVM uptime: 53.0 s) {mb-team=UX West}
2026-01-30 16:00:53,735 INFO search.core :: Found existing search index, and using it. {mb-team=UX West}
```

* include env variable

```shell
MB_LOG_TEAM_ATTRIBUTION=true clj -J-Xmx6g ...
...
2026-02-02 14:51:26,653 INFO core.core :: Setting up prometheus metrics {mb-team=UX West}
2026-02-02 14:51:26,655 INFO analytics.prometheus :: Starting prometheus metrics collector {mb-team=UX West}
2026-02-02 14:51:26,695 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191 {mb-team=UX West}
...
```

* copy module config file over for log attribution

* comment indentation

* restore module config location

* proper "from jar" detection

* correct logic for which env has a file and which a resource

* missed one

* ns cleanup

* trigger CI

* don't check config each time, only once
2026-02-03 17:25:51 -06:00
dpsutton
339136f500 fix kerberos tests (#69028)
* fix kerberos tests

in CI we're running:

```
[2/3] RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig

...

3.579 Hit:1 http://deb.debian.org/debian trixie InRelease
(#6 3.579 Hit:2 http://deb.debian.org/debian trixie-updates InRelease
(#6 3.588 Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
(#6 3.651 Hit:4 https://deb.nodesource.com/node_22.x nodistro InRelease
(#6 3.661 Reading package lists...
(#6 4.185 Reading package lists...
(#6 4.691 Building dependency tree...
(#6 4.834 Reading state information...
Dockerfile:5

--------------------

   4 |

   5 | >>> RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash ) \

   6 | >>>   && export DEBIAN_FRONTEND=noninteractive \

   7 | >>>   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig

   8 |

--------------------

failed to solve: process "/bin/sh -c ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig" did not complete successfully: exit code: 100

(#6 4.850 E: Unable to locate package yarn
(#6 ERROR: process "/bin/sh -c ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig" did not complete successfully: exit code: 100
------
 > [2/3] RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash )   && export DEBIAN_FRONTEND=noninteractive   && apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig:
3.517 2026-02-03 18:01:51 - To install N|solid Runtime, run: apt install nsolid -y
3.517
3.579 Hit:1 http://deb.debian.org/debian trixie InRelease
3.579 Hit:2 http://deb.debian.org/debian trixie-updates InRelease
3.588 Hit:3 http://deb.debian.org/debian-security trixie-security InRelease
3.651 Hit:4 https://deb.nodesource.com/node_22.x nodistro InRelease

4.850 E: Unable to locate package yarn

```

and it seems like debian doesn't host yarn (anymore?) which is
understandable. So we just do:

```
&& npm install --global yarn
```

And we should be good.

LLM diagnosed this. The setup here is a bit strange to me but it cats
it's resulting dockerfile:

```yaml
      - name: Print compose config
        run: cat mba-compose.yml
```

which was helpful. That dockerfile references:

```yaml
  metabase:
    build:
      context: /home/runner/work/metabase/metabase/.devcontainer/
      dockerfile: Dockerfile
```

And it's that devcontainer we are fixing here

* trigger kerberos tests

it needs files to be changed:

```yaml
  run-presto-kerberos-test:
    needs: files-changed
    if: needs.files-changed.outputs.backend_presto_kerberos == 'true'
```

which is configured in `.github/file-paths.yaml`

```yaml
backend_presto_kerberos:
  - "**/presto_jdbc/**"
  - "**/presto_jdbc.clj"
  - ".github/workflows/presto-kerberos-integration-test.yml"
```

so i add a `^:synchronized` teset to a file that should trigger this
files changed check and we get CI

* fix how we detect presto changes

usually hyphens are underscores, so it was looking for
`"**/presto_jdbc/**"` but the driver module is not a classpath root and
it uses a hyphen. Also it excluded the test file. so just manually add
that in, although it would be hit by the hyphen rule that i added

* correct typo in test filename

* touch test file
2026-02-03 17:10:28 -06:00
appleby
222b6b1bd0 OSS sqlgen snowplow test cleanups (#68929)
* Update oss sqlgen snowplow tests to use snowplow-test/with-fake-snowplow-collector

To follow existing snowplow test patterns from other modules.

* Move chat-completion-returns-usage-test next to other chat-completion tests

* Rename estimate-sanity-test to estimate-simplified-models-test

And use "raw" model names by default

* Update model-pricing with all models returned by list-models

Also add a comment with code for updating the model-pricing table.

* Ensure estimated_costs_usd is both number? and pos?

to ensure you still get a readable diff when the predicate fails rather than a hard to debug stacktrace.

* Use mt/with-random-premium-token! to get valid test token
2026-02-03 15:06:59 -08:00
Jeff Bruemmer
52579e4906 docs - revise Enterprise edition installation recommendations (#69029) 2026-02-03 16:33:33 -05:00
Nathan Voxland
6e4d96a68f Search Indexing: Cache card schema upgrades (#68912) 2026-02-03 15:09:37 -06:00
Cam Saul
d39acdcb96 Add custom Kondo linter to enforce idiomatic var names for def and friends (#68969)
Kondo linter for def using correct casing
2026-02-03 20:50:33 +00:00
Filipe Silva
5166c30ea5 Trial ups (#68478)
* feat: send current user email on cloud reqs

* feat: upgrade modal

* refactor: simplify upsell banner integration & tests

* test: metabase-enterprise.cloud-proxy.api-test

* fix: error stats for upgrade modal

* etc: whitespace

* fix: upgrade modal should only show up for upgrade url

* feat: refresh page after upsell flow for module reload

* refactor: use global modals instead of localized jsx

* refactor: remove unnecessary mock data and convert to localized strings

* test: add hm.client interceptor tests

* constants to types

---------

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-02-03 12:17:30 -08:00
Nick Fitzpatrick
1858472ebe don't render data studio button for non admins or analysts (#68920) 2026-02-03 14:48:37 -04:00
github-actions[bot]
4120da5c4e Fix: Bookmark list is not updated when you archive a collection containing a bookmarked item (#67148)
* Fix: Bookmark list is not updated when you archive a collection containing a bookmarked item

Fixes #44499

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>

* remove unneeded e2e test

---------

Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2026-02-03 18:42:31 +00:00
Brad Anderson
091f66fc32 Fix #66446 - Disambiguate errors when moving content to remote synced collections (#68874) 2026-02-03 12:47:33 -05:00
Vamsi Peri
dbe8b1f36d Workspaces for editing Transforms (#66015)
Co-authored-by: Chris Truter <chris@metabase.com>
Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
Co-authored-by: Uladzimir Havenchyk <uladzimir@metabase.com>
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
Co-authored-by: Stas Gavrylov <stasgavrylov@gmail.com>
Co-authored-by: Oleksandr Solovyov <alexander@solovyov.net>
2026-02-03 17:45:55 +00:00
Dan Stone
21c5c9c424 Add :transform-rolling stats to allow for up-to-date metering (#68999) 2026-02-03 17:16:16 +00:00
Noah Moss
3192d01612 Misc agent API improvements + llms-agent-api.txt (#68914)
* Misc agent API improvements + llms-agent-api.txt

* add llms-agent-api.txt

* Add more specific query execution response schema, fix some tests, and update llms.txt again

* Simplify count aggregation schema

* address comments, some other tweaks

* rename & move agent API llms.txt

* bump ci

* bump ci

* small change: ensure we record query execution properly with :agent context

* fix test
2026-02-03 12:16:00 -05:00
Maksym Yakubych
c3715127e2 fix: stacked bar chart crashes when card has multiple same-type aggregations (#68903) 2026-02-03 17:10:16 +00:00
Eric Normand
c32e0af3ee Bigquery and snowflake failing test QUE-3013 (#68916)
BigQuery can't do case statements with different types in each branch. Other dbs can. This fixes a test that ran a case statement with different types to skip BigQuery, but it adds a new assertion to check correct behavior without it.

This also corrects a fault in the SnowFlake driver that incorrectly assumed that convertTimezone() returned a timestamp_ntz but it returns a timestamp_tz. This wraps it in a cast back to timestamp_ntz.
2026-02-03 16:37:10 +00:00
Timothy S. Dean
59fd52ac43 Add dataset option to disable fk validation on batch insert (#68646)
Gives datasets a new option to specify that when being created fk validation should be disabled on insert
2026-02-03 09:36:50 -07:00
Mahatthana (Kelvin) Nomsawadi
2e9aa4019c Add support for auto refresh prop in modular embeddings (#68896)
* Add `autoRefreshInterval` to the SDK (#68729)

* Fix new callback don't get registered with our own `useInterval`

* wip

* Handle negative number

* Add autoRefreshInterval to StaticDashboard storybook

* Add autoRefreshInvertal to EditableDashboard storybook

* Add tests

* Make test order more sensible

* Add more test coverage

* Update types

* Update test format for consistency

* Make the condition clearer

* Fix wrong user-facing comment

* Fix wrong test name

* use the same jest fake timer configuration for all tests

* Address review

* Add support for `auto-refresh-interval` in modular embedding (#68830)

* Support `auto-refresh-interval` in modular embedding

* Make the test names more sensible

* Add tests

* Add an auto-refresh indicator (#68847)

* Add a dummy refresh indicator

* Add the actual icon

* Pass tests

* Add tests

* Fix another test
2026-02-03 16:30:35 +00:00
Stas Gavrylov
8db69364e8 Chore: Migrate pulse code to TS (#68908)
* Migrate DashboardSubscriptionsSidebar to TS. Related refactoring.

* Migrate redux pulse to TS

* Some more pulse-related migrations to TS

* Remove usage of Pulse and PulseParameter types. Replace with DashboardSubscription

* Fix prettier

* Remove type-casting

* GDGT-1649: Cleanup

* GDGT-1649: Fix TS error

* GDGT-1649: Fix unit tests

* GDGT-1649: Fix PR comments

* GDGT-1649: Fix PR comments

* GDGT-1649: Refactor setStates to remove side-effects
2026-02-03 18:01:12 +02:00
Eric Normand
62402df8b6 Create mutation testing skill (#68978)
A Claude skill with accompanying code for automating the mutation testing of a namespace.
2026-02-03 09:00:40 -07:00
Nathan Voxland
3ef22bbaec Better error handling in queue listeners (#68924)
Better error catching in queue listeners, with auto-restart
2026-02-03 09:34:39 -06:00
Nathan Voxland
00479dbf33 Fix reindex connection management (#68973)
Move reindex connection management to use a connection only around the writes, not try to use a connection across all writes, which may commit and therefore close server-side cursors still being used to read the next batch.
2026-02-03 09:27:09 -06:00
Maksym Yakubych
bbddb39150 fix: cannot save dashboard when dashboard was reverted to one with deleted filter (#68871) 2026-02-03 14:38:42 +00:00
Maksym Yakubych
49fbb0d24e fix: gauge chart breaks when sent via email/slack (#68730) 2026-02-03 14:33:53 +00:00
Jeff Bruemmer
3c5fbff8a8 docs - remote sync edits (#68923) 2026-02-03 14:29:16 +00:00
github-automation-metabase
9ce2f7da36 Auto-update documentation for master (#68984)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-03 09:25:45 -05:00
kevinkelleher12
f4e81f2c62 Allow non-admins to see timezone on Runs page tooltip (#68974) 2026-02-03 13:10:15 +00:00
kevinkelleher12
ac2083205b Fix empty tooltips (#68925) 2026-02-03 07:04:49 -05:00
Stas Gavrylov
f23b210cf1 E2E: Fix frontend port check. Adjust setting visibility (#68964) 2026-02-03 13:20:51 +02:00
Nemanja Glumac
a2f819bd08 Fix broken eslint tests (#68994) 2026-02-03 12:10:48 +01:00
Fraser
d818c6dd46 Remove dead code from admin settings redux (#68976) 2026-02-03 22:53:54 +13:00
Romeo Van Snick
e909583de0 Fix flake in native test (#68972)
* Add metaKey to test helpers

* Fix flake by using realPress helper
2026-02-03 18:24:13 +11:00
Nick Fitzpatrick
7abfb8753f Updating text color for filter counter chip (#68958)
updating text color
2026-02-02 16:51:41 -04:00
metamben
47304d3144 Add table-publish and table-unpublish events to the Activity log (#68899)
Add table-publish and table-unpublish events to the Activity Log

Closes QUE-2881

Register table-publish and table-unpublish as audit log events.
2026-02-02 13:14:55 -07:00
Eric Normand
5caa28c48a Add tests for lib.card/merge-model-metadata (#68869)
* Add tests for lib.card/merge-model-metadata

No mutants survived!

* kick ci
2026-02-02 19:22:56 +00:00
Eric Normand
636c376712 Test card->underlying-query (#68875)
Kills 100% of mutants
2026-02-02 18:30:51 +00:00
Eric Normand
d51ce7c743 Test model-preserved-keys (#68876)
100% mutants killed
2026-02-02 18:02:53 +00:00
Eric Normand
40c0273582 Add test for lib.card/fallback-display-name (#68865) 2026-02-02 17:16:14 +00:00
Eric Normand
b5c0fdd4e3 Fully test source-model-card (#68872)
* Add tests for source-model-card

source-model-card is only called from one function, card-returned-columns.
So we have to test source-model-card (which is private) through card-returned-columns.

This kills all mutants but 3, which have to do with the self-reference check in source-model-card. Is it really
necessary? It is an impossible branch to reach.
2026-02-02 10:56:16 -06:00
Eric Normand
1296b4671b Test lib.card/saved-question-metadata (#68868)
* Test lib.card/saved-question-metadata

* kick ci
2026-02-02 10:52:42 -06:00
Alexander Polyankin
b9ba7de970 Convert Transform Runs page to TreeTable and add a sidebar (#68892) 2026-02-02 16:26:54 +00:00
Ryan Laurie
0fa535476d Add Growth Engineering to Teams (#68959)
add growth engineering to teams
2026-02-02 07:59:57 -07:00
github-automation-metabase
b0d28fcfa4 Auto-update documentation for master (#68941)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-02-02 09:10:33 -05:00
Nemanja Glumac
6b1ceaf93b Update the latest docker tag when the latest major version matches (#68946) 2026-02-02 14:51:46 +01:00
Ngoc Khuat
db7f048d82 Snowflake: fix flaky test (#68844) 2026-02-02 12:12:04 +00:00
Fraser
4842e16f7c Upgrade to eslint v9 (#68772) 2026-02-02 22:39:13 +13:00
Nemanja Glumac
cd1be87231 Upgrade Chrome setup action to version 2 (#68915) 2026-02-02 21:21:45 +13:00
Fraser
89a8970e4a Fix no unused expression violations (#68939) 2026-02-02 13:21:07 +13:00
Fraser
2e7aafe3a0 Fix rules of hooks violations (#68940) 2026-02-02 13:20:42 +13:00
metabase-bot[bot]
39310d4798 [chore] Update E2E test timings with recent data (#68936) 2026-02-02 09:10:32 +13:00
Ryan Laurie
23be6baa0e Entity Picker v26 (#66978)
* new pickers

implement all pickers

remove test code

remove dead code

type fixes

reorganize

type fixes

data picker plus plus

more fixes

type fixes

fix column test ids

type and testfixes

some e2e test updates and kick off ci again

improved default states

more e2e test updates

test updates

better loading state

lint fixes

better root namespace handling

fix more root collection nonsense

improve backparsing logic

fix closing multiple modals on esc or enter

more e2e test updates

e2e test updates 4

fix (some) backparsing and add tests

fix spacing

e2e test updates 5

more backparse fixes

weird snippet deal

more tenant shenanigans

sweet sweet unit tests

add back NewDashboardDialog

more e2e tests and start NewDashboardDialog unit test

lint fixes

fix infinite render loop 😅

various fixes

bug fixes

search improvements

better cache hitting

dialog unit tests

test fixes

mucho test fixes

* fix conflict resolution errors

* test and type fixes

* bug and test fixes

* New folder button for snippets and transforms, e2e tests

* fix some dashboard cases

* test fixes

* entity picker e2e tests

* much fixo

* more e2e fixes

* fix some flakes

* prettier

* fixes

* more e2e test updates

* fix sdk component tests

* some stabilization

* fix dashboard saving bug

* prettier

* address review comments

* test fixes

* fix sandbox tests

* obey the linter

* cant pass null namespace

* oh types

* timeline

* fix default expanded 😫

---------

Co-authored-by: Kevin Kelleher <kevin.kelleher@metabase.com>
2026-01-31 02:57:52 +00:00
Nemanja Glumac
7ed4b012e5 Document rootless docker limitations (#68913) 2026-01-30 23:47:33 +01:00
Tyler Plude
e38d87f616 Metabot OSS Single Shot Text-2-Sql (#67883)
* Experiment with communicating with LLMs in Clojure

* Libor comments

* switch to new openai /v1/responses api, check for structured output support

* support for claude to show how different adapters are

* linter fixes

* update llm config edn

* init chat completion endpoint and env vars

* basic sqlgen BE endpoint

* BE test script

* basic table schema context extraction

* temp hack EE inline entrypoint to use OSS sql gen

* BE OSS async & streaming support

* BE OSS async & streaming support

* structured json response

* dialect instructions and sys prompt mustache

* hacky disable file logging via env var

* improved dialect mapping

* improved table metadata

* fix merge conflict

* abstract out sql generation to a seperate hook

* move MetabotPromptInput and MetabotInlineSQLPrompt components into OSS land

* always register metabot context rather than doing it conditionally in enterprise

* move OSS implementation into a seperate file

* oss implementation first pass

* add setting to know if the feature is enabled or not, optionally show ui based on if it is enabled, consolidate state into a single hook call to fix OSS issues, gets everything working

* clean up

* add test coverage

* revert metabot context changes, they did not end up being needed

* restrict @mentions to tables in OSS and models, tables, questions in EE

* send current sql value and no longer send buffer id

* add anthropic provider

* dumb module resolution workaround to get unit tests working correctly

* if there is only one search model provided preselect it

* tweak sys prompt; add table descriptions

* improved table & field metadata

* tweak model env var

* add openai settings

* fix CSP tiptap nonce console error

* fix oss not having access to default import of use-metabot-sql-suggestion hook in prod builds

* add backend support for source_sql

* OSS SQL Generation v1.6 (#68584)

* update layout

* impl table input bar

* persist state on open / close of inline sql prompt input

* ui improvements, referenced_entities now in req/res body

* support referenced_entities param in /generate-sql; add extract-tables endpoint

* use search, fix some ux/ui issue with dropdown

* fix sizing issue

* simplify generate-sql response format; properly union the referenced entities

* return table model spec in response

* updated backend tests

* improve table selection logic using new endpoint changes w/ richer data

* rate limiting; throttling; http timeouts; max resp tokens

---------

Co-authored-by: Sloan Sparger <sloansparger@gmail.com>

* small spacing / sizing corrections

* fix ee extracting tables when it should not, add test cases

* handle disabeld state and enter press better

* cleanup

* fix modules

* add init; fix kondo

* test fix

* fix modules

* Add snowplow events to oss sqlgen endpoints (#68822)

* Copy token_usage snowplow schema from ai-service

* Add :snowplow/token_usage to metabase.analytics.snowplow/schema->version

* Add basic anthropic cost estimation based on static tables

* Return :usage and :duration-ms from llm.anthropic/chat-completion

* Add snowplow token_usage tracking to oss /generate-sql endpoint

* Add snowplow token_usage tracking to oss /generate-sql-streaming endpoint

* Add snowplow simple_event tracking for sqlgen success and failure events

* Consolidate snowplow tracking tests

* Appease whitespace linter

* Don't use non-api analytics.setting namespace

* Ensure duration_ms is an integer in snowplow events

* Add note about oss instances to hashed_metabase_license_token schema description

Co-authored-by: Thomas Schmidt <thomas@metabase.com>

* Fix snowplow lint by adding old versions of token_usage schemas

The snowplow linter was complaining that these older schemas were missing. These versions had been deleted from the
ai-service repo, so weren't copied over. Restore them from the last version in ai-service prior to being deleted.

---------

Co-authored-by: Thomas Schmidt <thomas@metabase.com>

* Add README reminder to token_usage snowplow schema

See also https://github.com/metabase/ai-service/pull/605

* cleanup streaming

* rm stream test

* pr feedback & test fixes

* test fix

* [Metabot] OSS SQL generation admin UI changes (#68824)

* wip

* load models async, move model input to a select, show error if deprecated model

* move to password input for api key

* handle case where env vars have been set via env vars and can not be changed

* clean up oss view

* remove token checks for deciding to upsell metabot

* be tests for new models endpoint

* fix bug

* fix broken api tests

* ui feedback, token validation, style fixes

* unit tests

* fix cypress

* fix e2e test tag

* type fixes

* condo / eastwood fixes

* fix unit tests

* fix e2e test

* fix stale css var reference

* pr feedback

* fix var

* fix n+1 query; improve metadata fetching

* driver multimethod for dialect instruction resource; review PR cleanups & fixes

* pr feedback

* fix added in driver multimethod

* whitespace lint

* address my own comments

---------

Co-authored-by: Oleksandr Solovyov <o@solovyov.net>
Co-authored-by: Sloan Sparger <sloansparger@gmail.com>
Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
Co-authored-by: Thomas Schmidt <thomas@metabase.com>
Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
Co-authored-by: Noah Moss <noahbmoss@gmail.com>
2026-01-30 14:40:48 -08:00
Rodrigo López Dato
f6e9a91db7 Show Cloud region IDs next to names (#68918) 2026-01-30 18:49:02 -03:00
Uladzimir Havenchyk
423aafea99 replace moment with dayjs in cljs (#66914)
* replace moment with dayjs in cljs

* Fix CLJS compilation with DayJS port of metabase.util.time

* fix some tests

* fix time parsing in drill chart

* formatting

* make a better fix

* kondo

* fix sdk test

* indent

* drop moment from locales

* reorder imports

* ran bin/mage cljfmt-all to indent

* Add an ignore for 1 unsorted namespace

- cljfmt makes the namespaces unordered -> kondo complains

* typo

* attampt to move logic to clojurescript

* one more thing to remove business logic from metabase-lib

* address cljs review

---------

Co-authored-by: Braden Shepherdson <braden@metabase.com>
Co-authored-by: Bryan Maass <bryan.maass@gmail.com>
2026-01-30 23:38:35 +03:00
Riley Thompson
78ae095422 Athena and Databricks adjustments for data upload (#68821)
* fix upload

* use shared impl
2026-01-30 20:18:11 +00:00
bryan
297d612165 Simplify CI workflow trigger conditions (#68917)
Reverts 730265b198
2026-01-30 21:01:50 +01:00
Edward Paget
8ae78915ed feat: add library/transforms toggles to modal (#68852)
* feat: add library/transforms toggles to modal

In the 'Set up git sync' modal in data studio this adds pre-selected
toggles to sync the library and transforms. This also creates the
library if you select it to sync, but it has not yet been created.

* fixup! push the library/transforms behavior into CollectionList

* fixup! better types to reduce casting

* fixup! missing mock setup

* Update enterprise/frontend/src/metabase-enterprise/remote_sync/components/RemoteSyncAdminSettings/RemoteSyncSettingsForm.tsx

Co-authored-by: Anderson <ands.alves.nunes@gmail.com>

* fixup! separate library sync component

* fixup! prettier

---------

Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
2026-01-30 19:31:09 +00:00
Nick Fitzpatrick
02b0bbaf76 updating frontend dev guid colors section (#68904) 2026-01-30 15:26:31 -04:00
Alexander Polyankin
2062c3fb13 Fix colors and strings in the deps sidebar (#68901)
Fix colors and ttag
2026-01-30 19:15:18 +00:00
Eric Normand
37c991c292 Mutation testing basics (#68857)
Initial commit of mutation testing library.
2026-01-30 10:52:47 -06:00
Riley Thompson
3142c39435 Run transforms with a temp table + rename to avoid blocking queries (#68756)
* add fix and test

* dont drop bigquery tables and add test

* use atomic renames when possible

* use helper functions

* use existing wait-for-table

* use shared temp-table-name

* small change

* remove bigquery hack, make more similar to python impl

* address comments

* use random suffix and table name for temp tables

* use table hash

* update temp-table-name

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* mocked test to verify strategy selection

* fix test

* test description

* remove test

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 11:39:26 -05:00
Edward Paget
898b7b4c38 feat: apply remote sync settings to snippets (#68902)
Adds new spec-driven methods to detect writability of remote-sync
controlled methods. These use the existing sync-eligibility settings so
in the future we can straightforwardly apply these settings to
remote-sync controlled models (TODO: follow up to build them for the
other models).

Adds batched-versions of these checks to avoid n+1 queries when loading
can_write for models.

Adds tests of remote-sync checks for snippets.
2026-01-30 10:33:47 -06:00
Maksym Yakubych
c5ff6bbbbd fix: documents charts rendering when resizing is sluggish (#68204) 2026-01-30 15:31:04 +00:00
Noah Moss
50dac4248d Split out more granular error codes for metabot tools (#68627)
* Split out more granular 400 vs 404 error codes for metabot tools

* a couple new tests

* fix test

* fix tests, cleanup

* discrete error handling in resolve-datasource

* refactor

* undo some refactor to fix tests
2026-01-30 10:04:53 -05:00
Timofey Kachalov
df8fd2aa98 Add content translations for aggregations (#68733) 2026-01-30 17:58:24 +04:00
Oleksandr Solovyov
e597be0c10 make bin/mage run-tests able to run a single test (#67450) 2026-01-30 12:35:11 +00:00
Mahatthana (Kelvin) Nomsawadi
64fb9ea259 feat(sdk, embed-js): Add an alerts support to modular embeddings (#68777)
* Add an alerts button on the SDK (#67796)

* Prepare to add alerts to SDK

* Remove unrelated prop from storybook

* Add basic alerts button

* Only show alerts button with the proper flag

* Prevent download button from being shown without proper flag

* use CSS to hide things instead of JS

* Properly position all question buttons

* Use JS to hide empty divs as pure CSS is impossible

* Render alert modal ✌️

* Fix type

* Add todo

* Structure the components better

* Control alert modal state

* Add interactive question storybook

* Make interactive and static question button styles consistent

* Add alerts modal to interactive question

* Make alert button works with custom layouts

* Fix tests

* Fix unit tests

* Fix import order issue

* Remove outdated comment

* Add the same condition to display alert button from the core app

* Polish

* Modify question storybooks to show a question instead of a model

* Hide empty elements more reliably

* Add more conditions to display alert button

* Remove unused `classNames` prop

* Use the same style as the interactive question one

* Remove outdated diff

* Fix alerts button not working in custom layouts

* Remove another unused code

* Add a basic test

* Add unit tests

* fix visibility logic

* Fix E2E tests

* Make assertion on static question tests better

* Improve assertions

* Add interactive question unit tests

* Add e2e test for static question

* Add interactive question e2e tests

* Fix subcomponent

* clarify comment

* Hide other channels than email on the alert modal (#68184)

* Hide channel options on alerts modal

* Add unit tests

* Make the test name clearer

* Fix can't view created notifications the first time (#68197)

* Fix can't view created notifications

* Add tests

* Remove unnecessary return type

* Add a safety guard

* Hide Alert (and download) button on edit mode (#68189)

Hide some buttons on edit mode as it makes no sense there

* Alerts polishing (#68477)

* Misc. improvements

* Make it typesafe

* Add alerts to modular embedding (#68286)

* Add the option in modular embedding wizard

* Support `withAlerts` in modular embedding

* Close the modal after hiding the alert button

* Add E2E tests

* Fix type

* Fix `withAlerts` not working on modular embedding with `drills: false`

* It's 2026!

* 1 plugin to rule 'em all!

* Fix E2E after merging master

* Fix test name

* Add alerts analytics (#68531)

* Add alert setup analytics

* Track withAlerts on modular embedding

* Update snowplow schema

* Fix E2E tests

* Fix schema version

* Remove links from alerts test email (#68547)

* Remove links from alerts template

* Remove links from alert email computed part

* Add tests

* Make embedding util easier to use

* Make alerts and subscriptions payload lighter

* Remove unexpected pprint

* Remove links from alert email via tasks (#68610)

* Save notification card's disable_links when creating

* Add tests
2026-01-30 11:32:31 +00:00
William
52f689cb36 Fix cloud implicit join tests (#68762)
A previous pr broke some tests on master, and this fixes them.
2026-01-30 10:19:47 +00:00
Romeo Van Snick
c51ca23c95 Use getter function to move element (#68714) 2026-01-30 15:10:26 +11:00
Alexander Polyankin
0bacd6c5ca Dependency diagnostics sidebar updates (#68825) 2026-01-30 03:52:21 +00:00
Phoomparin Mano
f46fdd8d27 fix(sdk): fix failing tests for white-labeled colors (#68790) 2026-01-30 09:55:49 +07:00
Fraser
27fd3aac36 Delete fuzzing workflow (#68880) 2026-01-30 15:13:58 +13:00
bryan
92a60c8529 CI: query-processor module should trigger driver tests (#68877) 2026-01-30 01:14:36 +00:00
Anderson
ee030befe2 Fix empty Python Library not showing placeholder/comment (#68826) 2026-01-29 22:11:38 -03:00
Nick Fitzpatrick
5f956d51bd Remove brand-light and brand-lighter (#68290)
* brand key adjustments

* loki tests

* handle the forgotten brand-dark

* Update Loki Snapshots

* removing brand-hover from dynamic-css-vars

* Adjustments to calendar picker colors

* small adjustments on the permissions pages

* sdk: remove background-hover tests from sdk as dynamic css derives are replaced with color-mix

* stupid spelling

* building shared resources

* Adjusting unit test, loki images

* rebasing adjustments

* Update Loki Snapshots

* small color fixes while I wait for loki

* re-adding highlighted class

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>
Co-authored-by: Phoomparin Mano <phoomparin@gmail.com>
2026-01-29 20:06:28 -04:00
John Swanson
590c8945fc Analysts can do crud on segments and measures (#68501)
* Data Analyst CRUD on measures/segments

Data analysts with unrestricted view-data permissions on a table can now
create, update, and delete segments and measures for that table
(previously superuser-only).

`can-read?` was already granted by the `manage-table-metadata` permission.

Add permission tests for `can-write?` and `can-create?` methods.
2026-01-29 23:53:21 +00:00
metamben
c056b03d89 Deps breaking broken (#68866)
* Add rename /broken to /breaking and add new /broken

---------

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-01-30 02:47:55 +03:00
Maksym Yakubych
b4cf7383a4 fix: y axis not shown even if it would fit (#68861) 2026-01-29 15:09:10 -08:00
Edward Paget
9c003314be feat: enable transform setting on first import (#68807)
* feat: enable transform setting on first import

When a we import a remote that has transforms set the
`remote-sync-transforms` setting to true.

Update the remote sync object table clean up to be driven by the spec
configuration.

Add tests showing that transforms are consistently synced and erased
according to the following rules:

1. if the instance has `remote-sync-transforms` off and local transforms
and the remote does not have transforms content they are preserved after
an import
2. if the instance has `remote-sync-transforms` off and local transforms
and the remote has transforms content, the local transforms are
completely replaced by the remote.
3. if the instance has `remote-sync-transforms` on and the remote has
transforms content any local transforms are completely replaced by the
remote.
4. if the instance has `remote-sync-transforms` on has local transforms,
but the remote has no transforms, the local transforms are removed on import.

* fixup! relocate settings update

* fixup! don't let python libraries clash on import

* fixup! transactions for mysql
2026-01-29 22:16:41 +00:00
kevinkelleher12
06a24797b4 Remove Security and Appearance from embedding settings related links on OSS (#68151) 2026-01-29 20:53:58 +00:00
Edward Paget
ad8af02598 feat: transform setting into collection list (#68758)
* feat: transform setting into collection list

Move the setting for syncing transforms into the list of collections
available to remote sync, so conceptually the transforms root collection
looks like a standard syncable collection.

* Clean up FE a little bit

* undo unneeded changes

---------

Co-authored-by: Anderson <anderson@metabase.com>
2026-01-29 14:47:55 -06:00
Riley Thompson
798fc4aff6 Custom test on connection checkout for clickhouse (#68808)
* work around clickhouse bug

* driver change log

* use c3p0 test

* Add todo comment

* kondo

* more kondo
2026-01-29 20:32:51 +00:00
Nick Fitzpatrick
eb0a8d4900 Uxw 2736 improve transitions between main app data studio and admin (#68508)
* temp

* hook up mode switcher in other apps

* Ci issues

* adding get help, fixing e2e tests, other adjustments

* most unit tests

* rename to profile link?

* adjusting unit tests with routing

* partial feedback

* rename profile link

* base current app off routes array

* adjustments

* add non-admin user state, fix unit tests

* PR feedback

* fixing test

* fixing e2e

* only 1 app switcher in admin navbar

* e2e adjustments
2026-01-29 16:08:26 -04:00
Nathan Voxland
d1e940e66b Don't cascade delete transform runs on transform delete (#68642) 2026-01-29 13:16:28 -06:00
Jeff Bruemmer
781282dd40 docs - embedding edits (#68567)
* embedding edits

* edits

* Apply suggestion from @jeff-bruemmer

* edits

* Apply suggestion from @jeff-bruemmer

* update

* sso

* edits
2026-01-29 18:55:43 +00:00
bryan
730265b198 fix: re-run CI when break-quarantine-* or ci:all-cloud-drivers labels are changed (#68037) 2026-01-29 18:29:15 +00:00
Brad Anderson
0897ae0847 Fix Dependency Graph icon (#68855) 2026-01-29 12:57:07 -05:00
Timofey Kachalov
7b921d8f43 Deprecate isEEBuild helper (#68848)
Co-authored-by: Nicolò Pretto <info@npretto.com>
2026-01-29 21:34:11 +04:00
Stas Gavrylov
e22e0e5fb1 GDGT-1581: Add Python preview disclaimer (#68789)
* GDGT-1581: Update layout for Python preview message

* GDGT-1581: Add e2e test

* GDGT-1581: Rename 'Results' tab to 'Results preview'

* GDGT-1581: Adjust footer layout

* GDGT-1581: Add dismiss button to allow closing the footer

* GDGT-1581: Replace CSS with inline props

* GDGT-1581: Fix e2e test
2026-01-29 18:46:36 +02:00
Brad Anderson
c9bcbbfd73 UXW-2862 Fix test flake (#68784) 2026-01-29 11:41:36 -05:00
Brad Anderson
172e56f4b7 Fix data studio guard (#68781) 2026-01-29 11:16:02 -05:00
Eric Normand
1e3406219c Improved message for job failure due to routing (#68804) 2026-01-29 09:27:22 -06:00
Eric Normand
ad8376f6cc Don't double-convert expressions with convertTimezone() (#68740)
In the case statement, the default case did not TIMEZONE() to alter the timezone. The cases with TIMEZONE() returned a timestamp. The default case without TIMEZONE() returned timestamptz. Postgres reconciled the different types by converting all of them to timestamptz. So the timestamp was altered (by TIMEZONE()), but a new UTC timestamp was added (by the cast).

When the post-processor formats the rows, it checks that the metadata for the column has :converted_timezone. If it has that, it is formatted in the converted timezone, and since it's UTC, it will convert it again, a second time, which is incorrect.

The fix here is to check if the returned column is a timestamptz and strip it before formatting. We assume the database has already done the conversion. This avoids the second conversion.
2026-01-29 09:04:30 -06:00
John Swanson
bf81141508 allow getting transforms in root collection (#68731)
allow getting transforms in root collection
2026-01-29 15:00:57 +00:00
Noah Moss
05c2aff020 Split agent api out as a separate friend module to metabot-v3 (#68814)
* Split agent api out as a separate module

* remove old files

* cleanup

* fix module config
2026-01-29 09:57:08 -05:00
Aleksandr Lesnenko
bd3f1d4632 Transforms permissions (#66296)
Co-authored-by: Nathan Voxland <nathan@metabase.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
2026-01-29 09:29:01 -05:00
Sébastien
9743b3cbee Added link to doc for full app embedding (#68773)
* added link to doc for full app embedding

* Apply suggestions from code review

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>

---------

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2026-01-29 15:01:05 +01:00
github-automation-metabase
50c809f3fa Auto-update documentation for master (#68820)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-29 08:27:11 -05:00
Timofey Kachalov
0559e0beee Hide Guest embedding status bar when guest embedding is disabled (#68836) 2026-01-29 16:06:34 +04:00
Dan Stone
cf347ce318 Throw db-routing error on anonymous transform call (#68788)
Fixes GDGT-1588
2026-01-29 11:29:25 +00:00
Stas Gavrylov
eea96b2477 GDGT-1356: Alert Notification Cron Syntax is misleading (#68834)
* GDGT-1356: Adjust day of week parsing in cron string

* GDGT-1356: Add unit test
2026-01-29 13:14:35 +02:00
da
390bcd144e Change log level from info to debug for ignored params on qp (#68748)
reducing a bit more the verbosity of our logs, this time on cards with old metadata
2026-01-29 05:47:36 -03:00
Jakub Chodorowicz
383f6ba968 gdgt-1377 deselect and hide from bulk view tables not matching selection (#68469) 2026-01-29 09:26:54 +01:00
Aleksandr Lesnenko
450f5cc9ba data studio upsell (#68527)
* data studio upsell

* refactor: fix route guards

* fix: lint comments

* fix: data studio layout tests

* fix: remove local stub for api

* fix: moar lint errors

* fix: comments

---------

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2026-01-28 19:57:24 -04:00
metamben
353260e583 Keep field-values for detail-only fields (#67540)
* Keep field-values for detail-only fields

Closes #10851

* Make sure old-preview-display is set

* Fix test
2026-01-29 02:49:33 +03:00
Maksym Yakubych
b300a6118f fix: search in mini data picker only shows loading on the first load (#68365) 2026-01-28 17:53:29 -05:00
Maz Ameli
86410d0667 Boat instead of bird (#67612)
* boat instead of bird

* update tests
2026-01-28 22:41:26 +00:00
Nemanja Glumac
5d84cc6c3f Add a note about the Metabase config (#68803) 2026-01-28 22:51:19 +01:00
Edward Paget
ef4136d69e fix: clean up style issues in new remote-sync code (#68753)
* fix: clean up style issues in new remote-sync code

Fixes a grab bag of small style/docstring issues I found after the
parent PRs were merged.

* fixup! lint

* fixup! keep the newsnippetpage as always dirty
2026-01-28 15:42:02 -06:00
John Swanson
16e013a90d flake: fix temporal pollution (#68745)
flake: frozen clock
2026-01-28 21:31:04 +00:00
bryan
595e171f34 ci: add H2 OSS driver tests to catch OSS-only failures (#68649) 2026-01-28 21:25:05 +00:00
John Swanson
f01589a9d6 Fix migration for data studio (#68585)
* Fix migration for data studio

We usually auto-populate some other fields in permissions based on the value of object - perm_value, perm_type, and collection_id.

This obviously doesn't happen in a migration! So set them manually here.

* just roll forward
2026-01-28 13:15:30 -08:00
John Swanson
bf6c8b3459 Fix throw-if-last-admin! (#68198)
[UXW-341: Reactive old admin account is not possible](https://linear.app/metabase/issue/UXW-341/reactive-old-admin-account-is-not-possible)

Co-authored-by: Ed Paget <edpaget@users.noreply.github.com>
2026-01-28 13:14:31 -08:00
metamben
65189a0b69 Push the analysis of the dependents to the job (#68749)
* Push the analysis of the dependents to the job

Fixes QUE-3001

The analysis findings of dependents are marked as stale (if they exists) and the analysis job picks them up with
higher priority. Also, the job is triggered right after the analysis of the dependency and doesn't stop until all
stale findings are refreshed.

* Fix boolean type in migration

* Set *warn-on-reflection* to true

* Stick to SQL change

* Fix tests

* Remove race condition

* Process review feedback

* fixes

* fix tests

---------

Co-authored-by: Alexander Polyankin <alexander.polyankin@metabase.com>
2026-01-28 20:52:58 +00:00
John Swanson
d950e70482 No special Synced Collection on remote sync setup (#68499)
* No special Synced Collection on remote sync setup

[UXW-2684: Remove creation of special "Synced Collection" that gets created when Remote Sync is setup](https://linear.app/metabase/issue/UXW-2684/remove-creation-of-special-synced-collection-that-gets-created-when)

Co-authored-by: edpaget<ed@metabase.com>

* fix e2e tests
2026-01-28 12:40:50 -08:00
John Swanson
54e150e856 flake: wait for card query after revert (#68796)
The revert operation triggers a chain: revert API -> reload card page.

Test was only waiting for the revert API, then sometimes it would manage
to click the History tab *before* the page reload. Then the page reloads
and we're not on the History tab anymore.

Waiting for the card query request to finish means that we've reloaded
the page and ready to roll.
2026-01-28 11:54:05 -08:00
Riley Thompson
5959ca6c82 ClickHouse to always support schemas (#68517)
* set schemas to true and add migration

* just enable schemas

* remove migration

* add test

* fix schema test
2026-01-28 14:03:56 -05:00
Noah Moss
6b330140ff Semantic layer agent API endpoints (#68260)
* New endpoint implementations

* add new schemas for new endpoints

* new field values endpoints

* simple search endpoint + bastic test

* WIP - query construction endpoint

* Query construction tests, convert :output errors to real 404

* Basic query execution endpoint that just wraps qp/process-query

* Add query response schema

* Add descriptions to malli specs

* Add more tests, simplify some schemas

* Misc fixes, malli description improvements, try to fix decoding/encoding stuff but will need to revisit

* fix whitespace

* Greatly simplify schema sharing w/existing tool endpoints

* cleanup ns

* Fix some tests

* Fix up metric field values test

* add agent-client test helper, and new agent-api-user-binding-test

* simplify base64 query encoding

* small cleanups

* Address feedback

* add comment

* bump ci

* bump ci

* fix modules

* switch to agent-api feature flag
2026-01-28 14:00:28 -05:00
Nathan Voxland
24b7d886aa Paginate caching dashboard (#68242) 2026-01-28 12:52:39 -06:00
kevinkelleher12
b27e93965d Make sunburst charts reflect colors set in the appearance tab (#68641) 2026-01-28 14:12:28 -04:00
Cam Saul
f563a91095 Add additional tables to Lib test metadata (#68754)
* Add additional tables to Lib test metadata

* Cljfmt

* Test fixes 🔧

* Tell generators how to generate booleans
2026-01-28 09:02:39 -08:00
Alexander Polyankin
b0cfcca1e5 Dependency diagnostics UI polish (#68761) 2026-01-28 16:52:26 +00:00
Maksym Yakubych
0421a12c9c fix: documents ignore base path when linking to dashboards (#68633) 2026-01-28 16:31:27 +00:00
Noah Moss
cb42387606 Ensure we catch semantic search errors with failover and prometheus metrics (#68639)
* Ensure we catch semantic search errors before RRF + add a new prometheus metric

* Revert "Ensure we catch semantic search errors before RRF + add a new prometheus metric"

This reverts commit d972fdf6df.

* Move fallback logic to semantic-search.core to not be metabot-specific, add test
2026-01-28 10:23:42 -05:00
Nick Fitzpatrick
731f564a04 Uxw 2696 handle charts where manual y axis hides all data (#68156)
* off grid detection

* woof

* fixing bad counts

* adjusting no data points check

* expose initalUiState in visualizer

* cleaning up dashcard functions

* adjust broken behavior for existing tests

* e2e tests

* PR feedback

* remove buttons to open settings and auto adjust. Adding tests for pinned cards and documents

* removing unneeded code, pr feedback, and adding loki screenshots

* fix silly thing
2026-01-28 15:13:59 +00:00
Timofey Kachalov
d41abaea80 Fix flaky content-translations.cy.spec.ts e2e (#68776) 2026-01-28 16:52:12 +04:00
Sébastien
13af38d9ca Fixed date range parameter widget can overflow in embed flows (#68724)
* fixed date param ovrflowing in embed

* added loki test
2026-01-28 11:59:31 +01:00
Romeo Van Snick
7d107764fe Fix flake in transform repro (#68759)
* Fix flake

* fix typo
2026-01-28 21:34:05 +11:00
Anderson
b871ae4909 Make segments read-only for published tables also on admin (#68651)
* Make segments read-only for published tables also on admin

* improve test coverage

* group tests
2026-01-28 03:25:53 +00:00
github-automation-metabase
114541e4fc Auto-update documentation for master (#68763)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-27 21:35:42 -05:00
bryan
0982712225 Enable fake-sync for Snowflake driver tests (#68322) 2026-01-27 15:47:40 -07:00
Edward Paget
965ce2a47b feat: add remote-sync support for PythonLibrary (#68515)
Add support for syncing PythonLibrary entities (Python transform libraries)
with a Git repository when remote-sync-transforms setting is enabled.

Implements serdes serialization for pythonlibraries using `path` as the
entity id.

Adds FE changes to refresh on dirty state and show changes in the AllChangesView
2026-01-27 16:09:31 -06:00
Noah Moss
7316888913 Semantic layer agent API groundwork + auth (#68163)
* Add support for versioned endpoints to deftool

* Create new API namespace + add custom jwt middleware

* add kondo module dependency

* revert the deftool stuff which isn't needed now

* fix lint issues

* fix jwt case insensitivity issue; more structured errors for auth issues

* small jwt cleanups

* Add support for session token exchange

* cleanup, lint, tests

* more test cases, cleanup

* bump ci

* Restructure session logic to use normal middleware, add test for session expiration

* fix up module config

* share more code with jwt sso module + remove some now-redundent tests

* try to fix tests by using existing SSO JWT test setup

* fix whitespace

* fix up module config
2026-01-27 16:49:55 -05:00
John Swanson
fe290f97e7 Fix collisions in test log file uploads (#68739)
1. if the `log-artifact-suffix` is empty, just do
`test-logs-{github-job}`.

2. include a `log-artifact-suffix` argument for the driver tests

This way we don't get 409 conflict errors when uploading logs on test
failures for driver tests.
2026-01-27 12:22:57 -08:00
Gabriel Moreno
794819ead2 Data Studio Owners, Alignment & Dependency diagnostics icon (#68707)
* refactor: remove avatars and "no owner" fallback from transforms list

* refactor: right-align rows column on data structure

* fix: search_check icon fill color
2026-01-27 16:20:55 -04:00
Riley Thompson
2ef8d50387 Fix redshift sync failing with duplicate key error (#68097)
* select distinct

* filter out duplicates

* skip duplicate cols entirely

* clean up test

* address comments
2026-01-27 19:34:40 +00:00
William
73766cf355 implicit joins get implicit fields added (#68394)
Say you are doing an implicit join from orders to products in order to summarize by products.category. Previously, with implicit joins, we join with the actual products table instead of a select blah from products wrapper, and so the various fields returned by the join were returned under their original name. However, the code would abbreviate excessively long column names from the joined table and break the query.

That difference was due to add-implicit-fields running before add-implicit-joins. Explicit joins got implicit fields added, while implicit joins didn't get those fields. This pr runs add-implicit-fields a second time after add-implicit-joins, which makes implicit and explicit joins compile to the same (correct) sql.
2026-01-27 13:01:52 -06:00
John Swanson
38f42a9386 Don't automatically pull when in read-write mode (#68500)
Don't automatically pull when in read-write mode

Co-authored-by: edpaget<ed@metabase.com>
2026-01-27 10:43:18 -08:00
Oleksandr Yakushev
0ec522227b [match-lite] Make match-lite recursive by default (#68658)
Make match-lite recursive by default
2026-01-27 20:27:01 +02:00
John Swanson
cb42b96ca8 flake: empty schemas in target schemas (#68742)
The test was missing an explicit database selection step which sometimes
resulted in the Save button being disabled.

Also removed the unnecessary sync_schema call — the syncable_schemas
endpoint queries Postgres directly via the driver, so no metadata
sync is needed.
2026-01-27 09:58:51 -08:00
Oleksandr Yakushev
52f48e2400 Refactor match-lite and introduce :or clause (#67345)
* Refactor match-lite

* Add support for :or syntax
2026-01-27 19:23:18 +02:00
John Swanson
36a5234efc Do not delete built-in transform tags on sync (#68727)
* Do not delete built-in transform tags on sync

I found that some tests were failing intermittently - sometimes
TransformTags were present, and sometimes they were missing. I tracked
it down to this test, which enables and then disables remote syncing
transforms.

The issue is that if we sync transforms (... and transform tags), then
unsync them, then we delete everything that was synced - including the
built-in tags.

We should exclude these from deletion.

* Fix serialization API tests
2026-01-27 08:29:58 -08:00
dpsutton
065c23b648 prometheus metrics for jvm startup (#68728)
logs:
```
2026-01-27 15:02:23,442 INFO util.queue :: Starting listener field-value-invalidate with 1 threads 🎧
2026-01-27 15:02:23,448 INFO util.queue :: Starting listener search-index-update with 1 threads 🎧
2026-01-27 15:02:23,448 INFO core.core :: Metabase Initialization COMPLETE
2026-01-27 15:02:23,453 INFO core.core :: Metabase Initialization COMPLETE in 4.8 s (JVM uptime: 57.8 s)
```

metrics:

```
❯ http get :9191/metrics | grep startup
metabase_startup_jvm_to_complete_millis 57764.0
metabase_startup_init_duration_millis 4816.0
```

Note that there two different notions of startup time: from jvm
instantiation, and from before init! was called. This maintains the two
separately so we can diagnose if class load time gets longer
independently of amount of work we do during startup itself
2026-01-27 10:03:20 -06:00
Edward Paget
b8ed3bd4d0 feat: support remote sync for NativeQuerySnippets (#68497)
* feat: support remote sync for NativeQuerySnippets

When the Library collection is remote-synced, all NativeQuerySnippets
and their collections (snippets namespace) are automatically tracked
for remote sync. No separate setting is needed - syncing is tied
directly to the Library collection's is_remote_synced status.

Update the FE to use the declarative approach to refresh dirty state
when snippets are modified and update the library dirty state indicator
to turn on when any snippet or snippet collection is modified.

* fix: deletion of snippets/transforms collections

Fixes a bug where collections in the special namespaces were not cleaned
up after changing branches.

* fixup! don't double create entries

* fixup! transaction scope for test on mysql
2026-01-27 08:38:10 -06:00
Rodrigo López Dato
5486894ab8 Allow [::1] and 127.0.0.1 origins by default for cross-origin requests + support IPv6 origins (#68697)
Allow [::1] origin by default for cross-origin requests
2026-01-27 10:46:56 -03:00
Sébastien
8bafab3e0f Skipping first sso request if possible in EAJS/Modular Embedding (#68679)
skipping first sso request if possible in eajs
2026-01-27 14:04:41 +01:00
Romeo Van Snick
0b8c5cd5a3 Show empty schemas in transform target and table metadata (#68592)
* Show empty schemas when picking a transform target

* Use listSyncableDatabaseSchemas endpoint in data structure

* Handle empty schemas

* Add repro for metabase#68378

* Move transforms tests to new folder

* Split off transforms reproductions into separate specs
2026-01-27 08:15:42 +00:00
github-automation-metabase
9c95c11b7b Update translations 2026-01-27 (#68720)
* Update translation sources 2026-01-27

* Update translations

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-27 06:21:24 +00:00
github-automation-metabase
3a8eae8a39 Auto-update documentation for master (#68713)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-26 23:38:22 -05:00
Ngoc Khuat
b98eb79b38 Flip mariadb during table editing support check (#68171) 2026-01-27 03:27:25 +00:00
Fraser
7d6d5b35a3 Use named exports in common components code (#67779) 2026-01-27 13:34:04 +13:00
Fraser
bc82a001ee Use named exports in visualizations folder (#67058) 2026-01-27 13:26:47 +13:00
kevinkelleher12
0b7737980d Reduce bundle size by removing import of enormous character sizes constant (#68700) 2026-01-26 14:50:03 -07:00
Nathan Voxland
f0a7607b2b Only validate map URLs that changed (#68030) 2026-01-26 14:18:59 -06:00
Nathan Voxland
09d1a5d630 Don't duplicate uploads in admin page (#68077) 2026-01-26 13:53:29 -06:00
dpsutton
c3898889fd try to prevent deadlocks in impersonation tests (#68690) 2026-01-26 13:39:25 -06:00
Edward Paget
233dbfecdc feat: toggle transform dirty status on setting change (#68684) 2026-01-26 12:47:26 -06:00
dpsutton
503108d247 Better logging around token checks (#68625)
* Better logging around token checks

We used to just log we were checking but not give error responses. So it
would look like a ton of token checks for no real reason.

Now includes error responses if any, and also include logs when engaging
the token check circuit breaker, and when it is "half open", when it
lets one real token check happen every 30 seconds to see if the service
is back.

```
2026-01-23 12:26:47,175 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:26:47,186 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:26:49,190 INFO premium-features.token-check :: Error checking token: Connect timed out †
2026-01-23 12:26:49,194 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:26:49,201 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:26:51,205 INFO premium-features.token-check :: Engaging circuit breaker in token check ††
2026-01-23 12:26:51,206 INFO premium-features.token-check :: Error checking token: Connect timed out
2026-01-23 12:27:44,548 INFO premium-features.token-check :: In token check circuit breaker but attempting check
2026-01-23 12:27:44,551 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:27:44,565 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:27:46,574 INFO premium-features.token-check :: Engaging circuit breaker in token check
2026-01-23 12:27:46,575 INFO premium-features.token-check :: Error checking token: Connect timed out

...
2026-01-23 12:32:50,432 INFO premium-features.token-check :: In token check circuit breaker but attempting check †††
2026-01-23 12:32:50,433 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2026-01-23 12:32:50,444 INFO premium-features.token-check :: Reporting Metabase stats: {:embedding-dashboard-count 0, :enabled-embedding-sdk false, :internal-users 1, :embedding-question-count 0, :query_executions_static_embed 0, :query_executions_public_link 0, :domains 1, :metabot-usage-date 2026-01-22, :enabled-embedding-static false, :enabled-embedding-simple false, :metabot-queries 0, :external-users 0, :metabot-tokens 0, :query_executions_simple_embed 0, :enabled-embedding-interactive false, :query_executions_internal 0, :metabot-users 0, :query_executions_sdk_embed 0, :query_executions_interactive_embed 0, :users 1}
2026-01-23 12:32:52,450 INFO premium-features.token-check :: Engaging circuit breaker in token check
2026-01-23 12:32:52,450 INFO premium-features.token-check :: Error checking token: Connect timed out
```

The highlights are now we include:
- † `Error checkign token: Connect timed out` the error response when
appropriate
- †† `Engaging circuit breaker in token check` when we engage the
circuit breaker to no longer do real token checks
- ††† `In token check circuit breaker but attempting check` indicating
we are doing a real one from the circuit breaker to determine if the
service is restored

* Whew. Lots of stuff

add a namespace to the circuit breaker keyword:
`:token-check/circuit-breaker`. Change the keyword holding
`:token-check/app-db-not-ready` to cause. I had used reason but nothing
checked that.

this is because want to log when a token check fails, but not when it is
- failure due to circuit breaker
- failure due to appdb not ready yet.

token checks can happen anywhere and with an enormous frequency. they
fail before the appdb is setup (we can't check settigns yet) and of
course they fail during the circuit breaker opening. that's the point of
the circuit breaker. So we don't have to log these.

We _do_ want to log other failures.

We also want to do some prometheus metrics. Here's a journey:
You previously couldn't import the prometheus analytics namespace
because analytics.settings required appearance.settings. It does so
because a docstring in analytics settings used to include Metabase in
the string. I removed that so now it says "in order to help us
improve". And then things would be smooth sailing.

Except we had an issue.

```
026-01-23 20:50:03,514 INFO analytics.prometheus :: Starting prometheus metrics collector
2026-01-23 20:50:03,539 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
thread229238 we made the system!
thread229238 and now we are done with the lock!
2026-01-23 20:50:03,607 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,611 ERROR premium-features.token-check :: Error validating token: Failed to initialize Prometheus on port 9,191
2026-01-23 20:50:03,611 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,612 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,614 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,616 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,617 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,618 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,619 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,619 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
2026-01-23 20:50:03,653 INFO core.core :: Setting up prometheus metrics
```

We have locking around the system but it is starting tons of times! Lots
of debugging, swearing that this can't happen. but then i finally threw
in my favorite trick: `(clojure.repl/pst (Exception. "how did we get
here"))`. And it turns out we are doing this:

1. token check fails, so we call `prometheus/inc!`
2. inc is helpful, sees system isn't yet setup, and sets it up for us
3. Setup metric system
4. setup metrics in system
5. we hit the following code which gets initial values for labels

```clojure
(defn- initial-labelled-metric-values []
  (for [metric (keys (methods known-labels))
        labels (known-labels metric)]
    {:metric metric
     :labels labels
     :value  (initial-value metric labels)}))
```
6. We hit the following search code about which search we have

```clojure
(defmethod analytics/initial-value :metabase-search/engine-active
  [_ {:keys [engine]}]
  (if (search.engine/supported-engine? (keyword "search.engine" engine))
  1 0))
```

7. This takes us to semantic search:

```clojure
(defmethod search.engine/supported-engine? :search.engine/semantic [_]
  (try
    (supported?)
    (catch Exception e
      (log/warn e "Semantic search engine not supported")
      false)))
```

8. `supported?` here checks to see if you support a particular search
impelementation, which of course depends on _YOUR FEATURES_.
9. Checking features fails, so we should increment our prometheus
counter
10. the system is not yet initialized yet. Let's initialize it. (this is
also step 2)

So I have added a simple `inc-if-initialized!` function. It's not
important if the system is down. It's ok if these events are lost. The
system will be initialized in core anyways.

```
❯ http get :9191/metrics | grep metabase_token
 HELP metabase_token_check_attempt_total Total number of token checks. Includes a status label.
 TYPE metabase_token_check_attempt_total counter
metabase_token_check_attempt_total{status="failure",} 8.0
```

logs:

```
2026-01-23 22:58:26,668 INFO premium-features.token-check :: Checking with the MetaStore to see whether token '82bf...c3fe' is valid...
2026-01-23 22:58:28,706 INFO premium-features.token-check :: Error checking token: Connect timed out
2026-01-23 22:58:28,750 INFO core.core :: Setting up prometheus metrics
2026-01-23 22:58:28,751 INFO analytics.prometheus :: Starting prometheus metrics collector
2026-01-23 22:58:28,789 INFO premium-features.token-check :: Checking with the MetaStore to see whether token '82bf...c3fe' is valid...
2026-01-23 22:58:30,793 INFO premium-features.token-check :: Error checking token: Connect timed out
2026-01-23 22:58:30,798 INFO analytics.prometheus :: Starting prometheus metrics web-server on port 9191
...

2026-01-23 22:58:53,441 INFO premium-features.token-check :: Checking with the MetaStore to see whether token '82bf...c3fe' is valid... {mb-quartz-job-type=SyncAndAnalyzeDatabase}
...
2026-01-23 22:58:55,445 INFO premium-features.token-check :: Engaging circuit breaker in token check {mb-quartz-job-type=SyncAndAnalyzeDatabase}
2026-01-23 22:58:55,445 INFO premium-features.token-check :: Error checking token: Connect timed out {mb-quartz-job-type=SyncAndAnalyzeDatabase}
```

```
Exception how here??
	metabase.analytics.prometheus/setup! (prometheus.clj:584)
	metabase.analytics.prometheus/setup! (prometheus.clj:576)
	metabase.analytics.prometheus/inc! (prometheus.clj:668)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.analytics.prometheus/inc! (prometheus.clj:665)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.premium-features.token-check/error-catching-token-checker/reify--98262 (token_check.clj:431)
	metabase.premium-features.token-check/check-token (token_check.clj:488)
	metabase.premium-features.token-check/check-token (token_check.clj:484)
	metabase.premium-features.token-check/check-token (token_check.clj:486)
	metabase.premium-features.token-check/check-token (token_check.clj:484)
	metabase.premium-features.token-check/eval98325/*token-features*98348--98349 (token_check.clj:534)
	metabase.premium-features.token-check/eval98325/fn--98353 (token_check.clj:529)
	metabase.premium-features.token-check/has-feature? (token_check.clj:575)
	metabase.premium-features.token-check/has-feature? (token_check.clj:569)
	clojure.lang.Var.invoke (Var.java:386)
	metabase.premium-features.defenterprise/check-feature (defenterprise.clj:41)
	metabase.premium-features.defenterprise/check-feature (defenterprise.clj:35)
	metabase.premium-features.defenterprise/dynamic-ee-oss-fn/fn--71956 (defenterprise.clj:53)
	metabase.search.semantic.core/eval180600/fn--180601 (core.clj:58)
	clojure.lang.MultiFn.invoke (MultiFn.java:229)
	metabase.search.core/eval139302/fn--139304 (core.clj:77)
	clojure.lang.MultiFn.invoke (MultiFn.java:234)
	metabase.analytics.prometheus/initial-labelled-metric-values/iter--97802--97808/fn--97809/iter--97804--97810/fn--97811 (prometheus.clj:521)
	clojure.lang.LazySeq.force (LazySeq.java:50)
	clojure.lang.LazySeq.realize (LazySeq.java:89)
	clojure.lang.LazySeq.seq (LazySeq.java:106)
	clojure.lang.RT.seq (RT.java:555)
	clojure.core/seq--5488 (core.clj:139)
	clojure.core/concat/fn--5579 (core.clj:727)
	clojure.lang.LazySeq.force (LazySeq.java:50)
	clojure.lang.LazySeq.realize (LazySeq.java:89)
	clojure.lang.LazySeq.seq (LazySeq.java:106)
	clojure.lang.Cons.next (Cons.java:41)
	clojure.lang.RT.next (RT.java:733)
	clojure.core/next--5472 (core.clj:64)
	clojure.core/next--5472 (core.clj:64)
	metabase.analytics.prometheus/setup-metrics! (prometheus.clj:546)
	metabase.analytics.prometheus/setup-metrics! (prometheus.clj:533)
	metabase.analytics.prometheus/make-prometheus-system (prometheus.clj:60)
	metabase.analytics.prometheus/make-prometheus-system (prometheus.clj:55)
	metabase.analytics.prometheus/setup!/fn--97866 (prometheus.clj:591)
	metabase.analytics.prometheus/setup! (prometheus.clj:590)
	metabase.analytics.prometheus/setup! (prometheus.clj:576)
	metabase.analytics.prometheus/inc! (prometheus.clj:668)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.analytics.prometheus/inc! (prometheus.clj:665)
	metabase.analytics.prometheus/inc! (prometheus.clj:658)
	metabase.premium-features.token-check/error-catching-token-checker/reify--98262 (token_check.clj:431)
	metabase.premium-features.token-check/check-token (token_check.clj:488)
```

* module config fixup
2026-01-26 12:26:48 -06:00
bryan
a45d9203f1 Fix flaky GeoJS-dependent tests by mocking external service (#68623) 2026-01-26 10:34:20 -07:00
William
163180e8d9 Delete from cache in batches of 1000 (#68622)
There's apparently an instance on cloud that is trying to remove 70k queries from the cache at once, and postgres
doesn't allow 70k params to a query.  Batching the deletes in groups of 1000 should fix that.
2026-01-26 11:31:02 -06:00
Timofey Kachalov
b81aa809ad feat(sdk,embed-js): Add content translations for Collection/MetabaseBrowser components (#68608) 2026-01-26 21:07:55 +04:00
Jakub Chodorowicz
78efb4247b Gdgt 1557 migrate eslint from deprecated rulesdir to custom plugin (#68570) 2026-01-26 17:27:36 +01:00
Copilot
e51a02cd56 Refactor .styled files to CSS modules with CSS variables (#66851)
* Refactor batch 1: Convert simple styled files to CSS modules (10 files)

Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>

* Refactor batch 2: Convert more simple styled files to CSS modules (8 files)

Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>

* Refactor batch 3: Convert files with color() functions to CSS modules (5 files)

Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>

* misc fixed

* lint fix

* Revert breakpoint changes

* prettier

* color fixes

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: iethree <30528226+iethree@users.noreply.github.com>
Co-authored-by: Ryan Laurie <iethree@gmail.com>
2026-01-26 08:14:38 -07:00
John Swanson
f8d4a239b3 populate here and below for transforms (#68614)
[UXW-2828: collection/:id/items API does not return transforms](https://linear.app/metabase/issue/UXW-2828/collectioniditems-api-does-not-return-transforms)
2026-01-26 05:30:47 -08:00
Sébastien
ae05f0bab7 Fixed missing bg color for dashboards (#68673)
fixed missing bg color for dashboards
2026-01-26 13:20:41 +01:00
Fraser
e2132ed193 use named exports in admin folder (#67771) 2026-01-26 23:12:47 +13:00
Fraser
50e9d524d6 Use named exports in query_builder code (#67780) 2026-01-26 23:12:34 +13:00
Fraser
fbd16c232b Use Metabase Bot GitHub App to create PR (#68664) 2026-01-26 23:12:17 +13:00
Romeo Van Snick
123f2dafd2 MBQL lib helpers for e2e tests (#68278)
* Rename file containing jsx to .jsx

* Add e2e helpers to build metadata provider

* Split up metadata helpers

* WIP

* Add more direct createTestQuestion helper

* Replace test

* Build cljs for tests

* Export type

* Only require entities in the state for getMetadata

* Just pass state to getMetadata

* Move EntitiesSchema to metabase/schema

* Wrap mbql e2e helpers in promise

* Split off getMetadataWithoutSettings

* Use getMetadataWithoutSettings to get metadata from state

* Build entities state manually

* Simplify wrapper

* Fix metadataProvider

* Add createTestJsQuery wrapper for cypress

* Use plain promises and fetch

* Allow passing GetMetadataOpts to createTest(Native)JsQuery directly

* Improve createTestQuestion types

* Make use of createTestJsQuery in test

* Reduce nest in createTestQuestion

* Use simplified createTestQuestion

* Split up mbql helpers

* Fix card metadata call

* Use correct card endpoint

* Pass missing options

* Convert another more complex test to createTestQuestion

* Fix types

* Use static ids for defaults to avoid import loop

* Fetch more tables by default

* Build cljs in embedding tests

* Build cljs in component tests

* Prepare backend env

* Add plugin so we can avoid building CLJS everywher

* Avoid building cljs where not needed

* Fix types

* Rename query helpers

* Split up helpers

* Compile cljs in stress tests
2026-01-26 19:54:16 +11:00
metabase-bot[bot]
16504fd3c8 [chore] Update E2E test timings with recent data (#68665)
Update E2E test timings with averaged data

Collected timing data from 7 days of test runs.
All specs with timing data were included (simple averages).

🤖 Generated automatically by update-e2e-timings workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-26 21:50:07 +13:00
Romeo Van Snick
997b8d898e Respect abbreviate date style and be defensive around missing settings (#68661)
* Respect date_abbreviate when formatting date

* Respect abbreviate setting in month format too

* Add unit tests for abbreviated formats

* Add unit test for empty formatting settings

* Add repro for metabase#68574

* Add formatting settings unit tests
2026-01-26 15:50:42 +11:00
Alexander Polyankin
ceb518ab4b Dependency diagnostics - update the url, reset page on filter change, fix visibility checks (#68650) 2026-01-25 21:53:08 -05:00
Fraser
0ed6c4deed Link Claude Bugfix PR to Linear issue (#67710) 2026-01-26 10:44:24 +13:00
Sloan Sparger
6c09fca355 Fix NativeQueryEditor's action buttons (#68638)
fix position of buttons for native query editor
2026-01-24 20:34:41 +00:00
Aleksandr Lesnenko
049526c61c Cleanup (#68648)
cleanup
2026-01-24 09:40:18 -06:00
William
a799178420 Python transforms have dependencies (#68572)
The existing transform dependencies code only worked with query-based transforms (mbql or native).  This extends that
code to work with python transforms as well.
2026-01-24 02:34:24 -06:00
Maksym Yakubych
f7b82d5c54 fix: word wrap overflows row when reordering in dashboard table card (#68566) 2026-01-24 00:37:00 -03:00
Anderson
a51d1179d3 Disallow editing transforms when remote sync is read-only (#68380)
* Read-only: Adjust transform header menu options / Remove edit definition button / Run tab updates

* Make Settings tab read-only

* fix remote sync setup in e2e test

* Do not allow creating a new transform

* Make Python library not editable

* Hide edit definition in mbql transform view page

* Fix e2e

* Group e2e tests to improve performance
2026-01-24 01:52:27 +00:00
metamben
cbed2e45a8 Follow up on QUE-2999: move filtering to the database (#68635) 2026-01-23 23:45:05 +00:00
Timothy S. Dean
418d7a0317 Tweak data loading behavior for a test after MySQL 9.6.0 release (#68634)
Closes DEV-1289

### Description

Within the last day or two, `metabase.query-processor-test.remapping-test/self-referencing-test` began failing on MySQL Latest. I hypothesize this has to do with the [latest release](https://dev.mysql.com/doc/relnotes/mysql/9.6/en/news-9-6-0.html) fixing an unknown bug around batch inserts in InnoDB and the deprecation of a recusive [sic] fk-related flag.

The error is thrown not in the test conditions, but in the test setup -- MySQL apparently now checks foreign key constraints row-per-row even on a batch insert.

This adds a flag that the test can set which changes the test data-loading behavior to disable the FK check before insertion and re-enable it after.
2026-01-23 15:56:20 -07:00
Gabriel Moreno
3bce633480 Library empty state: display content in the page body (#68628)
* feat: create library empty state

* refactor: use new designs

* refactor: fix library creation

* fix: paper shadow

* fix: e2e
2026-01-23 18:49:35 -04:00
Gabriel Moreno
48327532c5 More Data Studio UX improvements & QoL fixes (#68546)
* fix(UXW-2752): remove unwanted padding on data structure fields tab group

* fix(UXW-2707): remove double border on job transforms section

* feat(UXW-2718): add horizontal layout for schedule controls

* feat(UXW-2709): fix spacing in the segments empty state

* fix(UXW-2780): long text overflow in user input

* fix(UXW-2710): set proper placeholder text on empty python library first load

* feat(UXW-2767): rename 'New collection' to 'Transform folder'

* refactor: blow grid & use `Ellipsified` instead
2026-01-23 18:03:17 -04:00
Anderson
26f71cfeb5 Fix SQL editor scrolling on Transform pages (#68107)
* Fix SQL editor scrolling on Transform pages

* Fix e2e test for question editor

* Fix python transform scrolling

* Fix lint

* Fix view-only transform content height
2026-01-23 18:42:24 -03:00
Braden Shepherdson
3d4e44b776 [deps] After a sync, re-analyze all dependents of updated tables (#68621)
Closes QUE-2984.

Adds an event handler for when a DWH sync is completed, which checks all its tables and fields for
their latest update times, and re-analyzes all cards which depend on tables updated since the last analysis.
2026-01-23 21:01:41 +00:00
Brad Anderson
86f3e524ba Fix UXW-2759 - Snippet edits in data studio are not saved (#68565) 2026-01-23 15:29:42 -05:00
Nathan Voxland
056d61238e If a dashboard is back to just one tab, auto-assign all cards to that tab (#68201) 2026-01-23 14:22:12 -06:00
Maksym Yakubych
926610da14 fix: custom Logo isn't loaded properly on User Invite Email (#68476) 2026-01-23 11:44:43 -08:00
Alexander Polyankin
75251f933a Fix text wrapping in dependencies (#68615) 2026-01-23 19:28:48 +00:00
Nemanja Glumac
d959d54aec Remove cache cleanup CI action (#68521) 2026-01-23 20:25:23 +01:00
Edward Paget
0933b7378f feat: support remote-syncing measures (#68392)
* feat: support remote-syncing measures

Add remote-sync support for measures, following the same pattern as segments:

- Add :model/Measure spec to remote-sync-specs with hybrid identity,
  parent-table eligibility, and event tracking
- Update measure permissions to check remote-sync/table-editable? for
  can-write? and can-create? (replacing superuser-only derive)
- Add batched hydration for :can_write on measures
- Add measures to serdes/descendants for Table so they export with parent
- Add tests for measure import/export tracking in impl_test.clj

On the Frontend creates a new data-driven approach to setting up the
middleware listener for changes that cause us to refresh dirty-state.

* fixup! typecheck
2026-01-23 13:17:01 -06:00
Edward Paget
e3b200b319 fix: flakey ec keypair test (#68591)
* fix: flakey ec keypair test

* fixup! do crypto in a delay
2026-01-23 13:15:00 -06:00
Edward Paget
fb9c0e4499 fix: derive events remote-sync needs in oss code (#68590) 2026-01-23 13:14:51 -06:00
Nemanja Glumac
40522b6cba Remove unused lodash types (#68593) 2026-01-23 19:26:18 +01:00
metamben
b6edd15de2 Stop reporting errors on archived or inaccessible entities (#68613)
Closes QUE-2999
2026-01-23 12:52:32 -05:00
lbrdnk
16042f45c7 Use macaw options, add parsed-query wrapped (#68466)
* Hoist macaw impl from query analyzer

* Use macaw-opts in bigquery module

* Use macaw-options in sqlserver

* Use macaw-options in sql driver

* Remove require

* Comment

* Test

* Update test

* Update macaw version

* Best effort support for bigquery

* Make test driver specific

* Remove final-not-reserved

* Not allowed on clickhouse only

* Clickhouse exception test

* best effort opts on api

* Remove final-non-reserved

* Remove requires

* driver.u/parsed-query

* Use parsed-query

* parsed-query

* ch test

* throw

* Lint against incorrect Macaw usage (#68568)

* Remove now unused function

* Shutdown loud exceptions for now

* Shutdown ch test

* Update test

---------

Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
2026-01-23 18:37:06 +01:00
Riley Thompson
b28ab0ec1d Revert ClickHouse from 0.9.5 to 0.8.4 (#68502)
* revert to 0.8.4

* disable test
2026-01-23 17:18:22 +00:00
github-actions[bot]
add8906504 Fix: Keyboard navigation annoyance in command palette (#67317)
Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
2026-01-23 11:33:33 -05:00
dpsutton
3345365546 handle empty error message (#68581)
Fixes https://github.com/metabase/metabase/issues/68578

This issue is not about the stack overflow per-se but blowing up on a
string includes:

```javascript
{
  "app": "metabase",
  "time": "2026-01-22T12:08:53.660601485Z",
  "stream": "stderr",
  "app_version": "v1.57.10-X01",
  "message": "Exception in thread \"Thread-41\" java.lang.NullPointerException: Cannot invoke \"Object.toString()\" because \"s\" is null
at clojure.string$includes_QMARK_.invokeStatic(string.clj:377)
at clojure.string$includes_QMARK_.invoke(string.clj:373)
at metabase.app_db.cluster_lock$retryable_QMARK_.invokeStatic(cluster_lock.clj:27)
at metabase.app_db.cluster_lock$retryable_QMARK_.invoke(cluster_lock.clj:19)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invokeStatic(cluster_lock.clj:87)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invoke(cluster_lock.clj:65)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invokeStatic(cluster_lock.clj:79)
at metabase.app_db.cluster_lock$do_with_cluster_lock.invoke(cluster_lock.clj:65)
at metabase.search.task.search_index$init_BANG_.invokeStatic(search_index.clj:36)
at metabase.search.task.search_index$init_BANG_.invoke(search_index.clj:32)
at clojure.lang.AFn.run(AFn.java:22)
at java.base/java.lang.Thread.run(Unknown Source)",
  "namespace": "hosting-eb9b3875e12d465a",
  "container": "metabase",
  "cluster": "metabase-1",
  "_p": "F"
}
```

The error message itself comes from a stackoverflow which perhaps does
not have a message? Either way, it's possible for this to be missing so
be a bit defensive
2026-01-23 10:04:56 -06:00
Sébastien
862dc50c64 Fix ChartTypeDropdown overflowing (#68455)
* Forcing overflow policy on ChartTypeDropdown

* tpyo

* refactoring to enable testing this with loki

* fixed story

* loki

* screenshot

* removed useless unit test
2026-01-23 16:08:37 +01:00
Nicola Mometto
0941091421 ensure common.py library is always available (#68603)
* fix: ensure common python library is always defined

* chore: e2e test

* fix: empty rollback

* fix: empty source

* fix: text
2026-01-23 15:01:18 +00:00
Alexander Polyankin
0bd69823a4 Show view_count for models and metrics in dependencies (#68588) 2026-01-23 17:42:57 +03:00
Alexander Polyankin
6a01533ca7 Use MBQL lib for matching field refs in ValueSourceModal in parameters (#68431) 2026-01-23 17:42:06 +03:00
Nemanja Glumac
7d18a1b5a6 Unset the premium token for E2E tests (#68533) 2026-01-23 13:54:21 +01:00
github-automation-metabase
0bf7e41984 Auto-update documentation for master (#68589)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-23 07:47:03 -05:00
Sébastien
95a25e4a3e fix proper bg color for embedded dashboards with custom theme (#68539) 2026-01-23 13:00:22 +01:00
Dan Stone
a2c4eef9de Revert the revert of column validation for incremental transforms (#68460)
Filter extract-columns endpoint to only return numeric and temporal columns
The extract-columns-from-query function is used to populate the incremental
filter dropdown for native SQL transforms. Previously it returned all columns
without filtering on type, leading to undefined behaviour when unsupported
column types were selected.

This change filters the results to only include columns with types supported
for incremental checkpointing:
- Temporal types (timestamp, timestamp with timezone)
- Numeric types (integer, float, decimal)

Text, boolean, and other unsupported types are now filtered out, matching
the behaviour of MBQL and Python transforms which already filter columns
client-side.

Updated documentation to clarify this endpoint is specifically for incremental
transform checkpoint column selection.

Also validates that transform POST/PUT conform to this rule and you are unable to update the transform to have
a filter column of an unsupported type.

Reverts the revert of https://github.com/metabase/metabase/pull/67686
2026-01-23 11:24:09 +00:00
Chris Truter
2f81937643 Fix data format for TODOs in style guides (#68598) 2026-01-23 13:13:30 +02:00
Sloan Sparger
48bf58b162 Cleanup from #68433 (#68481)
fix ai feedback that came after PR close :'/
2026-01-23 02:33:48 +00:00
Egor Grushin
761a7cf01e GDGT 1533 improve discoverability of python library in transforms UI (#68523) 2026-01-23 00:55:37 +00:00
Timothy S. Dean
8a76f71003 Remove find-column-for-name (#68382)
Remove find-column-for-name
2026-01-22 16:06:41 -07:00
Maksym Yakubych
fd90d13ae3 fix: custom brand color not consistently applied on Enterprise UI elements (#68484) 2026-01-22 22:56:00 +00:00
Maz Ameli
a62aab3f1b Rename Data Studio Library +New menu action labels (#68162)
* Rename Data Studio Library +New menu action labels

Update the menu item labels in the Data Studio Library's +New button:
- "Publish a table" → "Published table"
- "New snippet" → "Snippet"
- "New snippet folder" → "Snippet folder"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* prettier

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 22:39:54 +00:00
metamben
bafd49ee17 Add options to the /graph/dependents endpoint (#68573) 2026-01-22 21:58:19 +00:00
Edward Paget
1f0b461d6f feat: support remote sync transforms in FE (#68306)
* feat: support remote sync transforms in FE

1. Updates the DataStudioLayout to show transform dirty state

   We get the orange dot next to Transforms if transforms or transform
   collections are dirty.

2. Update the all changes view to include transforms

   Also includes their collection heirarchy if the transforms sync
   setting is enabled

3. Add the transforms sync setting

   To both the remote sync admin page and the Set up git sync modal in
   the data studio

* fixup! refresh transforms after sync

* fixup! data studio test feedback

* fixup! refactor failing test to troubleshoot debugging
2026-01-22 14:33:00 -06:00
metamben
1712274b85 Normalize transforms metadata (#68490) 2026-01-22 23:22:39 +03:00
Timofey Kachalov
ea203102e6 Don't show CORS settings in OSS/Starter editions (#68564) 2026-01-23 00:14:05 +04:00
Edward Paget
3c72591b17 feat: add Slack Connect SSO provider (#67955)
* feat: add Slack Connect SSO provider

Add enterprise Slack Connect SSO integration using the OIDC infrastructure:

- Slack Connect provider: OAuth2/OIDC flow for Slack workspace authentication
- Settings: configuration options for Slack client ID, secret, and auth modes
- User provisioning: automatic user creation from Slack identity
- API endpoints: SSO initiation and callback handling
- Analytics: usage tracking for Slack Connect feature

Slack Connect allows users to authenticate via their Slack workspace,
with support for both SSO-only and link-account authentication modes.

* fix: session reset after auth

* fixup! avoid email clash

* fixup! wrong value in sso settings

* fixup! cleanup tests

* fixup! fix test

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-01-22 10:57:12 -08:00
github-automation-metabase
9a19a5e4f0 [chore] Update llms.txt for master (#68561)
Update llms.txt and llms-full.txt (master)

Regenerated llms.txt to include all markdown files from the docs/ directory.
Also generated llms-full.txt files for the embedding section.

🤖 Generated automatically by llms-txt-generate workflow

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-22 18:20:04 +00:00
Sloan Sparger
f387d4aca4 [Metabot] Add close button back to data studio sidebar (#68487)
allow metabot to be closed in data studio
2026-01-22 11:33:21 -06:00
github-automation-metabase
1bb6f6a74a Update translations 2026-01-22 (#68557)
* Update translation sources 2026-01-22

* Update translations

---------

Co-authored-by: github-actions <github-actions@github.com>
2026-01-22 17:19:01 +00:00
Nicolò Pretto
2ad4292465 fix(embed-homepage): rename static embed to guest embed (#68338) 2026-01-22 16:37:02 +00:00
github-automation-metabase
37c3758748 Auto-update documentation for master (#68524)
Update generated docs (master)

Co-authored-by: github-actions <github-actions@github.com>
2026-01-22 09:26:48 -05:00
Jeff Bruemmer
ae9cad5c58 docs - note on ee vs oss path (#68210) 2026-01-22 09:09:05 -05:00
John Swanson
bd14e14974 Reenable deactivated tenants when autoprovisioning (#67947)
Previously even when autoprovisioning was on, you could not log into a
deactivated tenant (either as a new user or an existing user with that
tenant).

This changes the behavior to be more consistent. Just as a deactivated
user can log in when provisioning is on (and their user gets
reactivated), a deactivated tenant's users can still log in, but doing
so reactivates the tenant.
2026-01-22 05:10:23 -08:00
Jakub Chodorowicz
85319217cd Gdgt 1273 add snowplow events to bulk metadata features (#68409)
* add data studio library filtering events

* add bulk properties and unpublish event

* add bulk sync events

* add search event

* add assertions on events in e2e tests

* add search debounce

* remove unncessery comment

* update event names

* track filter searches with data_studio_table_picker_search_performed

* refactor tracking function

* guard and log event only for ConcreteTableId

* log search when started fetching

* fix events not fired

* fix event not fired on first search
2026-01-22 12:30:26 +01:00
Nicola Mometto
240acb4782 add started-at filter to task runs page (#68279)
* WIP: add started-at filter

* fix: kondo

* fix tests

* GDGT-1520 add a started at filter

* GDGT-1520 add a comment

* GDGT-1520 fix typing issues

* GDGT-1520 addressing PR comments

* GDGT-1520 addressing PR comments

* GDGT-1520 fix a tests after changing a text

---------

Co-authored-by: Egor Grushin <egor@metabase.com>
2026-01-22 09:49:15 +00:00
Jakub Chodorowicz
e6bc40c223 add analytics skill (#68419) 2026-01-22 09:36:42 +01:00
bryan
76fcb4d573 Fix transforms module to trigger driver tests + promote pg (#68432) 2026-01-21 16:30:15 -07:00
Arkadi Yaroslavtsev
a92317dd27 Add Anchor Links to Documents (#67940)
* Add AnchorLinkButton component for document anchor links

- Add AnchorLinkButton component that copies URL to clipboard on click
- Shows 'Copied!' tooltip feedback using Mantine useClipboard hook
- Follows same pattern as CommentsButton for consistent styling
- Add unit tests for the component

* Add AnchorLinkMenu component for left-side anchor link hover

- Add AnchorLinkMenu floating menu for document blocks
- Uses createPortal for positioning (same pattern as CommentsMenu)
- Positioned on left side of blocks using floating-ui
- Shows/hides based on hover state via show prop
- Add unit tests for the component

* Add AnchorLinkMenu to document node views

- Add documentWithAnchor URL helper to generate shareable anchor URLs
- Update Heading, Paragraph, and Blockquote node views to render AnchorLinkMenu
- AnchorLinkMenu appears on the left side on hover
- CommentsMenu on the right side remains unchanged
- Each node view now uses two useFloating instances for positioning

* Add scroll-to-anchor for document URLs with hash

- Add E2E tests for anchor links functionality
- Implement scroll-to-anchor when navigating to document with #blockId hash
- Tests cover: hover shows anchor icon, copy to clipboard, scroll to block
- Regression test ensures CommentsMenu still works on right side

* Fix scroll-to-anchor dependency arrays for navigation edge cases

- Add documentId to scroll effect dependencies to re-run when navigating
  between documents with the same anchor hash
- Add location.hash to reset effect dependencies to properly reset flag
  when navigating via back button or changing anchors

* Fix accidental logo replacement and E2E blockquote test

- Restore original Metabase logo SVG (was replaced with red star debug graphic)
- Fix E2E test: use find('blockquote') instead of findByRole('blockquote')
  since native blockquote elements have no implicit ARIA role

* Fix scroll-to-anchor reliability and empty line behavior

- Implement retry mechanism for scroll-to-anchor to ensure target element exists
- Add highlight animation when scrolling to anchor
- Hide anchor link and comment menus on empty lines (Heading, Paragraph, Blockquote)

* Fix selector mismatch for scroll-to-anchor

- Add data-node-id attribute to NodeViewWrappers in Heading, Paragraph, and Blockquote
  extensions so they can be queried by DocumentPage
- Update DocumentPage to query using [data-node-id] selector instead of internal _id attribute
- Remove unused ID_ATTRIBUTE_NAME import in DocumentPage

* Fix highlight animation color variable

- Replace non-existent --mb-color-brand-alpha-25 with --mb-color-brand-light
- Ensure highlight animation is visible when scrolling to anchor

* added anchor links to lists and code blocks. some bugs fixes.

* make sure scroll-to-anchor observer is correctly initialized

- Refactor scroll-to-anchor logic to ensure smoother navigation
- Optimize highlight animation visibility during scrolling
- Adjust anchor link behavior on empty lines for better user experience

* small fixes

* clean up

* fixes and cleanup

* e2e test fixes

* fixed e2e test

* Leave anchor links only for header blocks

* Fix alignment

* Review fixes

* Fix unit tests

---------

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2026-01-22 02:03:04 +03:00
bryan
087a317f70 Fix ci-report output formatting issues (#68505) 2026-01-21 15:50:57 -07:00
Denis Berezin
c63fd746d8 Uxw 2633 copy cells from table (#68429)
* UXW-2633 fix sorted table values copy-paste

* Add e2e test
2026-01-22 01:24:12 +03:00
dpsutton
f29a446aab fix materialized views test (#68509)
https://github.com/metabase/metabase/pull/68190 did:

> Treats a 0 value of n_live_tup as NULL, due to confusion reported when
> auto analyze thresholds have not been met on a table.

I think what's happening is this is trying to suss out "i don't know"
and not give misleading information. When there are no stats pg would
report there are 0 rows rather than saying i don't know. So we toss away
these unreliable 0 count estimations.

This test flakes 7% of the time. Our hypothesis is that stats are empty
7% of the time so this row count estimation now gets removed.

By default the schema is `:estimated_row_count (mt/malli=? [:maybe
:int])` which was being clobbered with
`{:estimated_row_count (mt/malli=? int?)}` So the fix is to just not
clobber
2026-01-21 16:07:45 -06:00
Edward Paget
d26bf4e454 feat: support transforms in remote sync (#68255)
* feat: support transforms in remote sync

1. Serialize Transforms as Collection Items

   Transforms were previously serialized as a top-level item, but this
   moves them to be serialized as a child of the collection they are
   member of. This also fixes an error in their serdes/dependencies
   implementation where it did not include the parent collection leading
   to deserialization issues.

2. Enforce Remote-Sync write rules

   Adds implementations of the model interface permissions methods for
   transforms that enforce the can-write? = false and can-create? =
   false rules when remote-sync is in read-only mode.

3. Add a setting to control whether transforms are synced

   Transforms are globally synced not synced via collections, so this
   adds a new boolean setting that controls whether they are synced on
   instances in read-write mode. Like all other content transforms are
   always synced from the remote source if the instance is in read-only
   mode.

4. Add a new spec-based configuration system for models

   Models we want to make remote-syncable have a complicated, but still
   data-driven system to allow you to specify their remote-sync behavior
   and have that automatically setup in a single place the
   `metabase-enterprise.remote-sync.spec` namespace.

* fixup! test with wrong folder

* fixup! not handling archived transform collections

* fixup! clean up aliases
2026-01-21 15:29:27 -06:00
Denis Berezin
7aa18ae448 Fix flaky test that uses readonly db that lacks permissions (#68417) 2026-01-22 00:15:27 +03:00
Timothy S. Dean
97da3d7c7b Migration follow-up fix to #68100 (#68498)
Move a migration from the v59 file to the v56 file, as we intend to backport it that far.
2026-01-21 14:15:12 -07:00
Aleksandr Lesnenko
10e8a68cf5 Data Analysts user group (#67770)
* basic analyst role

* analyst role

* Backend for data analyst role

* Fixup frontend to work with Backend

The dedicated analyst endpoints have been removed:
- `GET /api/user/analysts` -> Use `GET /api/user?is_data_analyst=true`
- `POST /api/user/analysts/:id` -> Use `PUT /api/user/:id` with `{ is_data_analyst: true }`
- `DELETE /api/user/analysts/:id` -> Use `PUT /api/user/:id` with `{ is_data_analyst: false }`

These hooks no longer exist:
- useListAnalystsQuery
- useAddAnalystMutation
- useRemoveAnalystMutation

New Patterns:

Listing analysts:
```
// Before
const { data } = useListAnalystsQuery();

// After
const { data } = useListUsersQuery({ is_data_analyst: true });
```

Adding an analyst:
```
// Before
await addAnalyst(userId).unwrap();

// After
await updateUser({ id: userId, is_data_analyst: true }).unwrap();
```

Removing an analyst:
```
// Before
await removeAnalyst(userId).unwrap();

// After
await updateUser({ id: userId, is_data_analyst: false }).unwrap();
```

Type Changes:

The field is_analyst has been renamed to is_data_analyst everywhere:

- User.is_data_analyst (was is_analyst)
- UpdateUserRequest.is_data_analyst (was is_analyst)
- ListUsersRequest.is_data_analyst (new field for filtering)

* kondo

* circular dep

* fix backend not compiling

* use the actual role

* analyst management, glossary access for admins

* various data studio access

* access to library

* drop custom analyst seats management ui

* automatic perms group

* fix tests

* specs

* permissions

* fix lints, add migration rollbacks

* data analysts can ALWAYS view table metadata

implemented for:

- search
- `table/can-read?`

* Also remove `can_access_data_model`

* Revert "Also remove `can_access_data_model`"

This reverts commit 03af432ccb.

* fix more tests

* more tests

* snapshots

* remove redundant checks

* everyone can see

* hide data analyst group for OSS

* Make data analysts a normal group on OSS

* Automatically provide data analysts with perms

Data analysts automatically get manage-table-metadata permissions on
every table/database.

* only disable setting some perms for data analysts

* kondo

* oops, one more kondo

* test fixes

* specs, fixes

* more specs, fixes

* cleanup

* more test fixes

* fix module config

* ci

* doh, fix test

* more test whack-a-mole

* move data analyst group to the top of perms views

* review

* ci

* Turn DA into a regular group when feature missing

instead of just on OSS.

The goal is:
- OSS: a previously existing Data Analysts group is a regular group with
configurable permissions. The real Data Analysts group is invisible and
has no members.
- EE without the token: same as above
- EE with the token: the real Data Analysts group is visible.

* oops, remove unnecessary require

* another one

* fix membership API

* fix a couple more tests

* macro gets a !

* fix `fetch-groups-test`

* ci

* ci

* ci

* ci

* fix collection perm in migration

---------

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-01-21 12:43:35 -08:00
Dan Meyer
209a34b102 ci: Enable fail-fast for BigQuery and Snowflake driver tests (#68199)
Add :fail-fast? true to BigQuery and Snowflake test-args, matching the
existing Redshift configuration. This stops test execution on first
failure, saving CI time and resources.
2026-01-21 20:27:03 +00:00
William
a6df84c136 Bump toucan2 version to fix dashboards sometimes failing to load (#68494)
If the first table mentioned by a dashboard has no fields (presumably because the table and its field are all
inactive), /api/dashboard/<id>/query_metadata would fail due to a toucan2 bug.  This bumps toucan2 to fix the bug and
adds a test to verify that this case now works.
2026-01-21 20:18:30 +00:00
Riley Thompson
adb9a5cbf4 Bump dependency analysis version (#68488)
bump dependency analysis version
2026-01-21 19:08:45 +00:00
7252 changed files with 632298 additions and 428633 deletions

View File

@@ -0,0 +1 @@
Run mutation testing for $ARGUMENTS

View File

@@ -29,7 +29,7 @@ This guide covers Clojure and ClojureScript coding conventions for Metabase. See
**Comments:**
- `TODO` format: `;; TODO (Name M/D/YY) -- description`
- `TODO` format: `;; TODO (Name YYYY-MM-DD) -- description`
## Code Organization

View File

@@ -1,21 +1,21 @@
## Linting and Formatting
- **Lint:** `yarn lint-eslint-pure`
- **Lint:** `bun run lint-eslint-pure`
- Run ESLint on the codebase
- **Format:** `yarn prettier`
- **Format:** `bun run prettier`
- Format code using Prettier
- **Type Check:** `yarn type-check-pure`
- **Type Check:** `bun run type-check-pure`
- Run TypeScript type checking
## Testing
### JavaScript/TypeScript Tests
- **Test a specific file:** `yarn test-unit-keep-cljs path/to/file.unit.spec.js`
- **Test by pattern:** `yarn test-unit-keep-cljs -t "pattern"`
- **Test a specific file:** `bun run test-unit-keep-cljs path/to/file.unit.spec.js`
- **Test by pattern:** `bun run test-unit-keep-cljs -t "pattern"`
- Runs tests matching the given pattern
### ClojureScript Tests
- **Test ClojureScript:** `yarn test-cljs`
- **Test ClojureScript:** `bun run test-cljs`
- Run ClojureScript tests

View File

@@ -0,0 +1,504 @@
---
name: analytics-events
description: Add product analytics events to track user interactions in the Metabase frontend
allowed-tools: Read, Write, Edit, Grep, Glob
---
# Frontend Analytics Events Skill
This skill helps you add product analytics (Snowplow) events to track user interactions in the Metabase frontend codebase.
## Quick Reference
Analytics events in Metabase use Snowplow with typed event schemas. All events must be defined in TypeScript types before use.
**Key Files:**
- `frontend/src/metabase-types/analytics/event.ts` - Event type definitions
- `frontend/src/metabase-types/analytics/schema.ts` - Schema registry
- `frontend/src/metabase/lib/analytics.ts` - Core tracking functions
- Feature-specific `analytics.ts` files - Tracking function wrappers
## Quick Checklist
When adding a new analytics event:
- [ ] Define event type in `frontend/src/metabase-types/analytics/event.ts`
- [ ] Add event to appropriate union type (e.g., `DataStudioEvent`, `SimpleEvent`)
- [ ] Create tracking function in feature's `analytics.ts` file
- [ ] Import and call tracking function at the interaction point
- [ ] Use `trackSimpleEvent()` for basic events (most common)
## Event Schema Types
### 1. Simple Events (Most Common)
Use `SimpleEventSchema` for straightforward tracking. It supports these standard fields:
```typescript
type SimpleEventSchema = {
event: string; // Required: Event name (snake_case)
target_id?: number | null; // Optional: ID of affected entity
triggered_from?: string | null; // Optional: UI location/context
duration_ms?: number | null; // Optional: Duration in milliseconds
result?: string | null; // Optional: Outcome (e.g., "success", "failure")
event_detail?: string | null; // Optional: Additional detail/variant
};
```
**When to use:** 90% of events fit this schema. Use for clicks, opens, closes, creates, deletes, etc.
### 2. Custom Schemas (legacy, no events are being added)
Consider adding new event schema only in very special cases.
**Examples:** `DashboardEventSchema`, `CleanupEventSchema`, `QuestionEventSchema`
## Step-by-Step: Adding a Simple Event
### Example: Track when a user applies filters in a table picker
#### Step 1: Define Event Types
Add event type definitions to `frontend/src/metabase-types/analytics/event.ts`:
```typescript
export type DataStudioTablePickerFiltersAppliedEvent = ValidateEvent<{
event: "data_studio_table_picker_filters_applied";
}>;
export type DataStudioTablePickerFiltersClearedEvent = ValidateEvent<{
event: "data_studio_table_picker_filters_cleared";
}>;
```
#### Step 2: Add to Union Type
Find or create the appropriate union type and add your events:
```typescript
export type DataStudioEvent =
| DataStudioLibraryCreatedEvent
| DataStudioTablePublishedEvent
| DataStudioGlossaryCreatedEvent
| DataStudioGlossaryEditedEvent
| DataStudioGlossaryDeletedEvent
| DataStudioTablePickerFiltersAppliedEvent // <- Add here
| DataStudioTablePickerFiltersClearedEvent; // <- Add here
```
#### Step 3: Create Tracking Functions
In your feature's `analytics.ts` file (e.g., `enterprise/frontend/src/metabase-enterprise/data-studio/analytics.ts`):
```typescript
import { trackSimpleEvent } from "metabase/lib/analytics";
export const trackDataStudioTablePickerFiltersApplied = () => {
trackSimpleEvent({
event: "data_studio_table_picker_filters_applied",
});
};
export const trackDataStudioTablePickerFiltersCleared = () => {
trackSimpleEvent({
event: "data_studio_table_picker_filters_cleared",
});
};
```
#### Step 4: Use in Components
Import and call the tracking function at the interaction point:
```typescript
import {
trackDataStudioTablePickerFiltersApplied,
trackDataStudioTablePickerFiltersCleared,
} from "metabase-enterprise/data-studio/analytics";
function FilterPopover({ filters, onSubmit }) {
const handleReset = () => {
trackDataStudioTablePickerFiltersCleared(); // <- Track here
onSubmit(emptyFilters);
};
return (
<form
onSubmit={(event) => {
event.preventDefault();
trackDataStudioTablePickerFiltersApplied(); // <- Track here
onSubmit(form);
}}
>
{/* form content */}
</form>
);
}
```
## Using SimpleEventSchema Fields
### Example: Event with target_id
```typescript
// Type definition
export type DataStudioLibraryCreatedEvent = ValidateEvent<{
event: "data_studio_library_created";
target_id: number | null;
}>;
// Tracking function
export const trackDataStudioLibraryCreated = (id: CollectionId) => {
trackSimpleEvent({
event: "data_studio_library_created",
target_id: Number(id),
});
};
// Usage
trackDataStudioLibraryCreated(newLibrary.id);
```
### Example: Event with triggered_from
```typescript
// Type definition
export type NewButtonClickedEvent = ValidateEvent<{
event: "new_button_clicked";
triggered_from: "app-bar" | "empty-collection";
}>;
// Tracking function
export const trackNewButtonClicked = (location: "app-bar" | "empty-collection") => {
trackSimpleEvent({
event: "new_button_clicked",
triggered_from: location,
});
};
// Usage
<Button onClick={() => {
trackNewButtonClicked("app-bar");
handleCreate();
}}>
New
</Button>
```
### Example: Event with event_detail
```typescript
// Type definition
export type MetadataEditEvent = ValidateEvent<{
event: "metadata_edited";
event_detail: "type_casting" | "semantic_type_change" | "visibility_change";
triggered_from: "admin" | "data_studio";
}>;
// Tracking function
export const trackMetadataChange = (
detail: "type_casting" | "semantic_type_change" | "visibility_change",
location: "admin" | "data_studio"
) => {
trackSimpleEvent({
event: "metadata_edited",
event_detail: detail,
triggered_from: location,
});
};
// Usage
trackMetadataChange("semantic_type_change", "data_studio");
```
### Example: Event with result and duration
```typescript
// Type definition
export type MoveToTrashEvent = ValidateEvent<{
event: "moved-to-trash";
target_id: number | null;
triggered_from: "collection" | "detail_page" | "cleanup_modal";
duration_ms: number | null;
result: "success" | "failure";
event_detail: "question" | "model" | "metric" | "dashboard";
}>;
// Tracking function
export const trackMoveToTrash = (params: {
targetId: number | null;
triggeredFrom: "collection" | "detail_page" | "cleanup_modal";
durationMs: number | null;
result: "success" | "failure";
itemType: "question" | "model" | "metric" | "dashboard";
}) => {
trackSimpleEvent({
event: "moved-to-trash",
target_id: params.targetId,
triggered_from: params.triggeredFrom,
duration_ms: params.durationMs,
result: params.result,
event_detail: params.itemType,
});
};
// Usage with timing
const startTime = Date.now();
try {
await moveToTrash(item);
trackMoveToTrash({
targetId: item.id,
triggeredFrom: "collection",
durationMs: Date.now() - startTime,
result: "success",
itemType: "question",
});
} catch (error) {
trackMoveToTrash({
targetId: item.id,
triggeredFrom: "collection",
durationMs: Date.now() - startTime,
result: "failure",
itemType: "question",
});
}
```
## Naming Conventions
### Event Names (snake_case)
```typescript
// Good
"data_studio_library_created"
"table_picker_filters_applied"
"metabot_chat_opened"
// Bad
"DataStudioLibraryCreated" // Wrong case
"tablePickerFiltersApplied" // Wrong case
"filters-applied" // Use underscore, not hyphen
```
### Event Type Names (PascalCase with "Event" suffix)
```typescript
// Good
DataStudioLibraryCreatedEvent
TablePickerFiltersAppliedEvent
MetabotChatOpenedEvent
// Bad
dataStudioLibraryCreated // Wrong case
DataStudioLibraryCreated // Missing "Event" suffix
```
### Tracking Function Names (camelCase with "track" prefix)
```typescript
// Good
trackDataStudioLibraryCreated
trackTablePickerFiltersApplied
trackMetabotChatOpened
// Bad
DataStudioLibraryCreated // Missing "track" prefix
track_library_created // Wrong case
logLibraryCreated // Use "track" prefix
```
## Common Patterns
### Pattern 1: Feature-Specific Union Types
Group related events together:
```typescript
export type DataStudioEvent =
| DataStudioLibraryCreatedEvent
| DataStudioTablePublishedEvent
| DataStudioGlossaryCreatedEvent;
export type MetabotEvent =
| MetabotChatOpenedEvent
| MetabotRequestSentEvent
| MetabotFixQueryClickedEvent;
// Then add to SimpleEvent union
export type SimpleEvent =
| /* other events */
| DataStudioEvent
| MetabotEvent
| /* more events */;
```
### Pattern 2: Conditional Tracking
Track different events based on user action:
```typescript
const handleSave = async () => {
if (isNewItem) {
await createItem(data);
trackItemCreated(newItem.id);
} else {
await updateItem(id, data);
trackItemUpdated(id);
}
};
```
## Common Pitfalls
### Don't: Add custom fields to SimpleEvent
```typescript
// WRONG - SimpleEvent doesn't support custom fields
export const trackFiltersApplied = (filters: FilterState) => {
trackSimpleEvent({
event: "filters_applied",
data_layer: filters.dataLayer, // ❌ Not in SimpleEventSchema
data_source: filters.dataSource, // ❌ Not in SimpleEventSchema
with_owner: filters.hasOwner, // ❌ Not in SimpleEventSchema
});
};
// RIGHT - Use only standard SimpleEventSchema fields
export const trackFiltersApplied = () => {
trackSimpleEvent({
event: "filters_applied",
});
};
// Or use event_detail for a single variant
export const trackFilterApplied = (filterType: string) => {
trackSimpleEvent({
event: "filter_applied",
event_detail: filterType, // ✓ "data_layer", "data_source", etc.
});
};
```
### Don't: Forget to add event to union type
```typescript
// Define the event
export type NewFeatureClickedEvent = ValidateEvent<{
event: "new_feature_clicked";
}>;
// ❌ WRONG - Forgot to add to SimpleEvent union
// Event won't be recognized by TypeScript
// ✓ RIGHT - Add to appropriate union
export type SimpleEvent =
| /* other events */
| NewFeatureClickedEvent;
```
### Don't: Mix up event name formats
```typescript
// WRONG
event: "dataStudioLibraryCreated" // camelCase
event: "data-studio-library-created" // kebab-case
event: "Data_Studio_Library_Created" // Mixed case
// RIGHT
event: "data_studio_library_created" // snake_case
```
### Don't: Track PII or sensitive data
```typescript
// WRONG - Don't track user emails, names, or sensitive data
trackSimpleEvent({
event: "user_logged_in",
event_detail: user.email, // ❌ PII
});
// RIGHT - Track non-sensitive identifiers only
trackSimpleEvent({
event: "user_logged_in",
target_id: user.id, // ✓ Just the ID
});
```
### Don't: Forget to track both success and failure
```typescript
// WRONG - Only tracking success
try {
await saveData();
trackDataSaved();
} catch (error) {
// ❌ No tracking for failure case
}
// RIGHT - Track both outcomes
try {
await saveData();
trackDataSaved({ result: "success" });
} catch (error) {
trackDataSaved({ result: "failure" });
}
```
## Testing Analytics Events
While developing, you can verify events are firing:
1. **Check browser console** - When `SNOWPLOW_ENABLED=true` in dev, events are logged
2. **Use shouldLogAnalytics** - Set in `metabase/env` to see all analytics in console
3. **Check Snowplow debugger** - Browser extension for Snowplow events
Example console output:
```
[SNOWPLOW EVENT | event sent:true], data_studio_table_picker_filters_applied
```
## File Organization
### Where to put tracking functions:
```
Feature-specific analytics functions:
frontend/src/metabase/{feature}/analytics.ts
enterprise/frontend/src/metabase-enterprise/{feature}/analytics.ts
Event type definitions (all in one place):
frontend/src/metabase-types/analytics/event.ts
Core tracking utilities:
frontend/src/metabase/lib/analytics.ts
```
## Real-World Examples
See these files for reference:
- **Simple events**: `enterprise/frontend/src/metabase-enterprise/data-studio/analytics.ts`
- **Events with variants**: `frontend/src/metabase/dashboard/analytics.ts`
- **Complex events**: `frontend/src/metabase/query_builder/analytics.js`
- **Event type examples**: `frontend/src/metabase-types/analytics/event.ts`
## Workflow Summary
1. **Identify the user interaction** to track
2. **Decide on event name** (snake_case, descriptive)
3. **Define event type** in `event.ts` using `ValidateEvent`
4. **Add to union type** (create feature union if needed)
5. **Create tracking function** in feature's `analytics.ts`
6. **Import and call** at the interaction point
7. **Test** that events fire correctly
## Tips
- **Be specific** - `filters_applied` is better than `action_performed`
- **Use past tense** - `library_created` not `create_library`
- **Group related events** - Create feature-specific event union types
- **Track meaningful actions** - Not every click needs tracking
- **Consider the data** - What would you want to analyze later?
- **Stay consistent** - Follow existing naming patterns in the codebase
- **Document context** - Use `triggered_from` to track where the action happened

View File

@@ -54,7 +54,7 @@ Use this to scan through changes efficiently:
- [ ] Public vars in `src` or `enterprise/backend/src` have useful docstrings
- [ ] Docstrings use Markdown conventions
- [ ] References use `[[other-var]]` not backticks
- [ ] `TODO` comments include author and date: `;; TODO (Name 1/1/25) -- description`
- [ ] `TODO` comments include author and date: `;; TODO (Name 2025-01-01) -- description`
### Code Organization
@@ -118,7 +118,7 @@ Quick scan for common issues:
| `update-db`, `save-model` | Missing `!` for side effects: `update-db!`, `save-model!` |
| `snake_case_var` | Should use kebab-case |
| Public var without docstring | Add docstring explaining purpose |
| `;; TODO fix this` | Missing author/date: `;; TODO (Name 1/1/25) -- description` |
| `;; TODO fix this` | Missing author/date: `;; TODO (Name 2025-01-01) -- description` |
| `(defn foo ...)` in namespace used elsewhere | Should be `(defn ^:private foo ...)` |
| Function > 20 lines | Consider breaking up into smaller functions |
| `/api/dashboards/:id` | Use singular: `/api/dashboard/:id` |

View File

@@ -40,7 +40,7 @@ allowed-tools: Read, Write, Grep, Bash, Glob
**Format:**
- Run prettier on the file after making edits: `yarn prettier --write <file-path>`
- Run prettier on the file after making edits: `bun run prettier --write <file-path>`
- This ensures consistent formatting across all documentation
### Common patterns

View File

@@ -0,0 +1,114 @@
---
name: mutation-testing
description: Run mutation testing on a Clojure namespace, generate tests to kill surviving mutations, and open draft PRs with Linear issue tracking.
---
# Mutation Testing Skill
This skill runs mutation testing end-to-end: generates a coverage report, groups functions, shells out to `claude -p` to write tests, verifies mutations are killed, and creates draft PRs with Linear issues.
## Prerequisites
- A running nREPL connected to the Metabase dev environment
- `LINEAR_API_KEY` environment variable set with a valid Linear personal API key
- `gh` CLI authenticated with GitHub
- `claude` CLI available on PATH
## Reference Files
- `dev/src/dev/coverage.clj` — mutation testing engine (generates reports, runs mutations)
- `dev/src/dev/mutation_testing.clj` — orchestration, Linear API, PR helpers
## Invocation
The argument is a Clojure namespace, optionally followed by a base branch:
```
/mutation-testing metabase.lib.order-by
/mutation-testing metabase.lib.order-by --base-branch release-x.52.x
/mutation-testing metabase.lib.order-by --project-id abc-123
/mutation-testing metabase.lib.order-by --base-branch release-x.52.x --project-id abc-123
```
- `--base-branch`: defaults to the value in config (set via `set-config!`), or `"master"` if not configured.
- `--project-id`: if provided, issues are added to this existing Linear project instead of creating a new one.
## Steps
### 1. Parse arguments
Parse `$ARGUMENTS` to extract:
- **namespace** (required) — the first positional argument
- **`--base-branch`** (optional) — if present, the next argument is the base branch name
- **`--project-id`** (optional) — if present, the next argument is an existing Linear project ID
### 2. Load and configure
```clojure
(require '[dev.mutation-testing :as mut-test] :reload)
(require '[dev.coverage :as cov] :reload)
```
If this is the first invocation (or the REPL was restarted), set up the Linear team:
```clojure
(mut-test/list-teams!)
(mut-test/set-config! {:team-id "<id>"})
```
### 3. Run
```clojure
(mut-test/run! '<target-ns>)
;; Or with options:
(mut-test/run! '<target-ns> {:base-branch "release-x.52.x"})
(mut-test/run! '<target-ns> {:project-id "abc-123"})
(mut-test/run! '<target-ns> {:base-branch "release-x.52.x" :project-id "abc-123"})
```
Pass the opts map with `:base-branch` and/or `:project-id` if those flags were provided in the arguments.
This will:
1. Generate a baseline mutation testing report
2. Create a Linear project for the namespace
3. Group functions by coverage relationships
4. For each group: create branch → invoke Claude to write tests → verify → retry if needed → commit & push → create Linear issue → create draft PR
5. Print a summary with PR links
### 4. Handle failures
If a group fails mid-processing, `run!` catches the error and continues to the next group. To retry a single group manually:
```clojure
;; Get the parsed namespace info
(def parsed (mut-test/parse-namespace '<target-ns>))
;; Run coverage to get the data
(def coverage-results (cov/test-namespace (:target-ns parsed) [(:test-ns parsed)]))
;; Group and find the one you want
(def groups (mut-test/group-functions coverage-results))
;; Process just that group
(mut-test/process-group! parsed (nth groups <index>))
```
### 5. Verify the prompt (dry run)
To inspect what Claude will see without invoking it:
```clojure
(def parsed (mut-test/parse-namespace '<target-ns>))
(def coverage-results (cov/test-namespace (:target-ns parsed) [(:test-ns parsed)]))
(def groups (mut-test/group-functions coverage-results))
(println (mut-test/build-test-prompt
(merge (select-keys parsed [:target-ns :test-ns :source-path :test-path])
(select-keys (first groups) [:fn-names :mutations]))))
```
## Configuration
- **Team ID**: Set once per REPL session via `(mut-test/list-teams!)` and `(mut-test/set-config! {:team-id "..."})`
- **Project ID**: Set automatically when `run!` calls `create-project-for-namespace!`
- **Base Branch**: Defaults to `"master"`. Override via `(mut-test/set-config! {:base-branch "release-x.52.x"})` or pass `{:base-branch "..."}` as the second arg to `run!`
- **Project ID**: If set (via `set-config!` or `run!` opts), `run!` reuses the existing Linear project instead of creating a new one

View File

@@ -12,8 +12,9 @@ allowed-tools: Read, Grep, Bash, Glob
Review pull requests with a focus on:
- Readability and maintainability
- Appropriate test coverage
- Compliance with project coding standards and conventions
- Code quality and best practices
- Clear and correct JSDoc comments
- Type safety and proper TypeScript usage
- React best practices (when applicable)
- React best practices (when applicable)

View File

@@ -1,7 +1,7 @@
;; -*- comment-column: 100; -*-
{:config-paths ["macros" "src" "config"]
:linters
{ ;;
{;;
;; enabled optional linters (these are disabled by default)
;;
@@ -50,13 +50,15 @@
;; disabled linters
;;
:redundant-ignore {:level :off} ; lots of false positives, see https://github.com/clj-kondo/clj-kondo/issues/2414
:redundant-ignore {:level :off} ; lots of false positives, see https://github.com/clj-kondo/clj-kondo/issues/2414
:unexpected-recur {:level :off} ; TODO (cam): I think we just need to tell it how to handle MBQL match and we can enable this?
;;
;; globally-enabled custom linters
;;
:metabase/check-defmulti-arglists {:level :warning}
:metabase/check-def-check-not-uppercase-name {:level :warning}
:metabase/check-def-no-underscores {:level :warning}
:metabase/check-me-humanize {:level :warning}
:metabase/defsetting-must-specify-export {:level :warning}
:metabase/defsetting-namespace {:level :warning}
@@ -65,8 +67,8 @@
:metabase/missing-test-expr-requires-in-cljs {:level :warning}
:metabase/modules {:level :warning} ; more config in `.clj-kondo/config/modules/config.edn`
:metabase/namespace-name {:level :warning}
:metabase/no-jsqlparser-imports {:level :warning}
:metabase/require-shape-checker {:level :warning}
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning} ; more config in `.clj-kondo/config/test-helpers/config.edn`
:metabase/tests-must-live-in-known-modules {:level :warning}
:metabase/validate-defendpoint-route-uses-kebab-case {:level :warning}
:metabase/validate-defendpoint-query-params-use-kebab-case {:level :warning}
@@ -178,6 +180,11 @@
metabase.notification.models/create-notification!
metabase.pulse.send/send-pulse!
metabase-enterprise.transforms-python.python-runner-test/execute!
;; Workspace isolation functions are safe in parallel tests because they operate on
;; isolated, test-specific workspaces and databases that don't affect other tests
metabase-enterprise.workspaces.isolation/destroy-workspace-isolation!
metabase-enterprise.workspaces.isolation/ensure-database-isolation!
metabase-enterprise.workspaces.test-util/create-ready-ws!
;; Safe in tests, where we typically use a private, temporary index per thread.
metabase.search.core/reindex!
metabase.util/run-count!
@@ -191,7 +198,7 @@
:metabase/disallow-hardcoded-driver-names-in-tests
;; don't include `:h2` since that will probably lead to a mountain of tests where we are specifically testing
;; middleware or compilation behavior with just H2 since it's the default.
{:drivers #{ ;; core drivers
{:drivers #{;; core drivers
#_:h2
:postgres
:mysql
@@ -219,7 +226,10 @@
;; misc config for built-in linters
;;
:invalid-arity {:skip-args [metabase.lib.util.match/match]} ; TODO (cam): can we fix these?
:invalid-arity {:skip-args [metabase.lib.util.match/match
metabase.lib.util.match/match-lite
metabase.lib.util.match/match-many
metabase.lib.util.match/replace-lite]} ; TODO (cam): can we fix these?
:refer-all {:level :warning, :exclude [clojure.test]}
:unused-referred-var {:exclude {compojure.core [GET DELETE POST PUT]}}
@@ -238,13 +248,17 @@
(metabase.lib.util.match/match)
(metabase.lib.util.match/match-one)
(metabase.lib.util.match/match-lite)
(metabase.lib.util.match/match-lite-recursive)
(metabase.lib.util.match/match-many)
(metabase.lib.util.match/replace)
(metabase.lib.util.match/replace-in)
(metabase.lib.util.match/replace-lite)
(metabase.driver-api.core/match)
(metabase.driver-api.core/match-one)
(metabase.driver-api.core/match-lite)
(metabase.driver-api.core/match-many)
(metabase.driver-api.core/replace)
(metabase.driver-api.core/replace-in)
(metabase.driver-api.core/replace-lite)
(metabase.query-processor.middleware.cache-backend.interface/with-cached-results)
(metabase.util.regex/rx [opt])
(metabase.util/prog1 [<>])
@@ -296,10 +310,14 @@
metabase.lib.convert/->legacy-MBQL {:message "Conversion to legacy MBQL is discouraged, please use Lib to manipulate MBQL queries"}
metabase.lib.core/->legacy-MBQL {:message "Conversion to legacy MBQL is discouraged, please use Lib to manipulate MBQL queries"}
metabase.lib.equality/find-column-indexes-for-refs {:message "Use lib.equality/closest-matches-in-metadata or lib.equality/find-closest-matches-for-refs instead of lib.equality/find-column-indexes-for-refs"}
metabase.lib.util.match/match {:message "Use lib.util.match/match-many instead of lib.util.match/match."}
metabase.lib.util.match/match-one {:message "Use lib.util.match/match-lite instead of lib.util.match/match-one."}
metabase.lib.util.match/replace {:message "Use lib.util.match/replace-lite instead of lib.util.match/replace."}
metabase-enterprise.transforms.interface/execute! {:message "Use metabase-enterprise.transforms.execute/execute! instead of metabase-enterprise.transforms.interface/execute!"}
next.jdbc/active-tx? {:message "Use metabase.app-db.core/in-transaction? to see if we are in a transaction"}
toucan2.core/debug {:message "Don't commit code using t2/debug"}
toucan2.tools.debug/debug {:message "Don't commit code using t2/debug"}}
toucan2.tools.debug/debug {:message "Don't commit code using t2/debug"}
}
:discouraged-namespace
{camel-snake-kebab.core {:message "CSK is not Turkish-safe, use the versions in metabase.util instead."}
@@ -418,11 +436,10 @@
metabase-enterprise.content-translation.routes-test/with-new-secret-key! clojure.core/fn
metabase-enterprise.serialization.test-util/with-dbs clojure.core/fn
metabase-enterprise.serialization.test-util/with-random-dump-dir clojure.core/let
metabase-enterprise.transforms.api-test/with-transform-tags clojure.core/let
metabase-enterprise.transforms.api-test/with-worker-runs clojure.core/let
metabase-enterprise.transforms.test-util/with-transform-cleanup! clojure.core/let
metabase-enterprise.transforms.execute/with-transform-lifecycle clojure.core/let
metabase-enterprise.workspaces.test-util/with-resources! clojure.core/let
metabase-enterprise.workspaces.test-util/with-workspaces! clojure.core/let
metabase.actions.test-util/with-actions clojure.core/let
metabase.transforms.test-util/with-transform-cleanup! clojure.core/let
metabase.api.common/let-404 clojure.core/let
metabase.app-db.custom-migrations.util/with-temp-scheduler! clojure.core/fn
metabase.app-db.custom-migrations/define-migration clj-kondo.lint-as/def-catch-all
@@ -510,7 +527,16 @@
{cljs.test/deftest hooks.clojure.test/deftest
cljs.test/is hooks.clojure.test/is
cljs.test/use-fixtures hooks.clojure.test/use-fixtures
clojure.core/def hooks.clojure.core.def/lint-def
clojure.core/definterface hooks.clojure.core.def/lint-def
clojure.core/defmacro hooks.clojure.core.defmacro/lint-defmacro
clojure.core/defmulti hooks.clojure.core.defmulti/lint-defmulti
clojure.core/defn hooks.clojure.core.defn/lint-defn
clojure.core/defn- hooks.clojure.core.defn/lint-defn
clojure.core/defonce hooks.clojure.core.def/lint-def
clojure.core/defprotocol hooks.clojure.core.def/lint-def
clojure.core/defrecord hooks.clojure.core.def/lint-def
clojure.core/deftype hooks.clojure.core.def/lint-def
clojure.core/ns hooks.clojure.core.ns/lint-ns
clojure.core/require hooks.clojure.core.require/lint-require
clojure.core/requiring-resolve hooks.clojure.core.require/lint-requiring-resolve
@@ -522,8 +548,10 @@
metabase-enterprise.advanced-permissions.models.permissions.application-permissions-test/with-new-group-and-current-graph hooks.common/with-two-top-level-bindings
metabase-enterprise.audit-app.pages-test/with-temp-objects hooks.common/with-one-binding
metabase-enterprise.cache.config-test/with-temp-persist-models hooks.common/with-seven-bindings
metabase-enterprise.dependencies.api-test/with-dependents-test! hooks.common/with-two-bindings
metabase-enterprise.metabot-v3.tools.dependencies-test/with-dependent-transforms! hooks.common/with-two-bindings
metabase-enterprise.semantic-search.db.connection/with-migrate-tx hooks.common/let-one-with-optional-value
metabase-enterprise.serialization.api-test/with-serialization-test-data! hooks.common/with-three-bindings
metabase-enterprise.serialization.test-util/with-temp-dpc hooks.toucan2.tools.with-temp/with-temp
metabase-enterprise.transforms-python.drivers-test/with-test-table hooks.common/with-two-bindings
metabase.api.common.internal-test/with-jetty-server hooks.common/with-one-binding
@@ -758,22 +786,17 @@
:config-in-ns
{test-namespaces
{:linters
{:inline-def {:level :off}
:missing-docstring {:level :off}
:private-call {:level :off}
:metabase/defsetting-must-specify-export {:level :off}
:metabase/defsetting-namespace {:level :off}
{:inline-def {:level :off}
:missing-docstring {:level :off}
:private-call {:level :off}
:metabase/defsetting-must-specify-export {:level :off}
:metabase/defsetting-namespace {:level :off}
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning} ; more config in `.clj-kondo/config/test-helpers/config.edn
:discouraged-var
{metabase.driver/database-supports? {:level :off}
metabase.lib.convert/->legacy-MBQL {:level :off}
metabase.lib.core/->legacy-MBQL {:level :off}}}
:hooks
{:analyze-call
{clojure.core/defmacro hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation
clojure.core/defn hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation
clojure.core/defn- hooks.clojure.core.defn/non-thread-safe-form-should-end-with-exclamation}}}
metabase.lib.core/->legacy-MBQL {:level :off}}}}
source-namespaces
{:linters

View File

@@ -276,6 +276,7 @@
events
models
premium-features
request
settings
util}}
@@ -383,7 +384,6 @@
:uses #{api
app-db
collections
config
eid-translation
events
lib-be
@@ -395,6 +395,7 @@
request
revisions
settings
transforms
upload
util}}
@@ -409,7 +410,6 @@
models
request
users
users-rest
util}}
;; technically this 'uses' `enterprise/core` and `test` since it tries to load them to see if they exists so we know
@@ -501,6 +501,18 @@
util
xrays}}
data-studio
{:team "Gadget"
:api #{metabase.data-studio.api}
:uses #{api
database-routing
driver
events
request
sync
util
warehouse-schema}}
database-routing
{:team "UX West"
:api #{metabase.database-routing.core}
@@ -530,11 +542,13 @@
view-log}}
driver
{:team "Drivers"
{:team "Querying"
:api #{metabase.driver
metabase.driver.common
metabase.driver.common.parameters
metabase.driver.common.parameters.parse
metabase.driver.connection
metabase.driver.connection.workspaces
metabase.driver.ddl.interface
metabase.driver.h2
metabase.driver.impl
@@ -543,15 +557,22 @@
metabase.driver.postgres
metabase.driver.settings
metabase.driver.sql
metabase.driver.sql-jdbc
metabase.driver.sql-jdbc.connection
metabase.driver.sql-jdbc.execute
metabase.driver.sql-jdbc.execute.diagnostic
metabase.driver.sql-jdbc.sync
;; TODO (lbrdnk 2025/12/17): We should revisit addition of the following line. I've added it to make
;; tests pass as we are using it directly with ee/workspaces module. I believe later, when workspaces
;; are in better state quality wise, it should become part of the driver api and that should be used
;; instead of calling directly into the normalize module.
metabase.driver.sql.normalize
metabase.driver.sql.query-processor
metabase.driver.sql.util
metabase.driver.sync
metabase.driver.util}
:uses #{app-db
:uses #{analytics
app-db
appearance
auth-provider
classloader
@@ -564,13 +585,14 @@
premium-features
query-processor
settings
sql-tools
system
util
warehouse-schema
warehouses}}
driver-api
{:team "Drivers"
{:team "Querying"
:api #{metabase.driver-api.core}
:uses #{actions
api
@@ -624,6 +646,7 @@
:api #{metabase.embedding-rest.api}
:uses #{api
dashboards
database-routing
eid-translation
embedding
events
@@ -713,32 +736,18 @@
lib
{:team "Querying"
:api #{metabase.lib.binning
metabase.lib.convert ; Only so [[metabase.queries.models.card]] can set dynamic vars.
metabase.lib.core
:api #{metabase.lib.core
metabase.lib.equality
metabase.lib.field
metabase.lib.filter.desugar.jvm ; only so [[metabase.legacy-mbql.jvm-util]] can use defined regexes
metabase.lib.hierarchy
metabase.lib.init
metabase.lib.metadata
metabase.lib.metadata.cached-provider
metabase.lib.metadata.column
metabase.lib.metadata.invocation-tracker
metabase.lib.metadata.protocols
metabase.lib.metadata.result-metadata
metabase.lib.normalize
metabase.lib.options
metabase.lib.query
metabase.lib.schema
metabase.lib.schema.actions
metabase.lib.schema.aggregation
metabase.lib.schema.binning
metabase.lib.schema.common
metabase.lib.schema.constraints
metabase.lib.schema.expression
metabase.lib.schema.expression.temporal
metabase.lib.schema.expression.window
metabase.lib.schema.id
metabase.lib.schema.info
metabase.lib.schema.join
@@ -747,25 +756,26 @@
metabase.lib.schema.measure
metabase.lib.schema.metadata
metabase.lib.schema.metadata.fingerprint
metabase.lib.schema.middleware-options
metabase.lib.schema.parameter
metabase.lib.schema.ref
metabase.lib.schema.settings
metabase.lib.schema.template-tag
metabase.lib.schema.temporal-bucketing
metabase.lib.schema.test-spec
metabase.lib.schema.util
metabase.lib.schema.validate
metabase.lib.temporal-bucket
metabase.lib.types.isa
metabase.lib.util
metabase.lib.util.match
metabase.lib.walk}
metabase.lib.util.match}
:uses #{config
graph
legacy-mbql
types
util}
:friends #{query-processor}}
:friends #{legacy-mbql ;; Reuses internal schemas and a few helper functions. Deeply coupled to MBQL.
lib-be ;; BE-specific extension of lib; tight coupling is acceptable.
query-processor ;; Necessarily manipulates MBQL; better to pull most logic into a new module.
enterprise/sandbox ;; Really part of the QP, though its lives in the enterprise/ tree.
}}
lib-be
{:team "Querying"
@@ -776,6 +786,24 @@
settings
util}}
llm
{:team "Metabot"
:api #{metabase.llm.api
metabase.llm.init}
:uses #{analytics
api
driver
lib
lib-be
models
premium-features
request
settings
sql-tools
sync
util
warehouse-schema}}
logger
{:team "DevEx"
:api #{metabase.logger.api
@@ -809,6 +837,7 @@
lib-be
models
permissions
remote-sync
search
util}}
@@ -846,10 +875,19 @@
:uses #{api
app-db
classloader
collections
events
legacy-mbql
lib
lib-be
permissions
query-processor
remote-sync
search
settings
util}}
transforms
util}
:friends #{transforms}}
native-query-snippets
{:team "Querying"
@@ -862,6 +900,7 @@
models
permissions
premium-features
remote-sync
util}}
notification
@@ -879,6 +918,7 @@
config
dashboards
driver
embedding
events
models
parameters
@@ -903,6 +943,7 @@
metabase.parameters.custom-values
metabase.parameters.dashboard
metabase.parameters.field
metabase.parameters.field-values
metabase.parameters.init
metabase.parameters.params
metabase.parameters.schema
@@ -969,13 +1010,15 @@
:api #{metabase.premium-features.api
metabase.premium-features.core
metabase.premium-features.init}
:uses #{api
:uses #{analytics
api
app-db
classloader
config
events
internal-stats
settings
startup
task
util}}
@@ -1131,8 +1174,10 @@
metabase.query-processor.init
metabase.query-processor.interface
metabase.query-processor.metadata
metabase.query-processor.middleware.add-remaps
metabase.query-processor.middleware.annotate
metabase.query-processor.middleware.cache-backend.db
metabase.query-processor.middleware.catch-exceptions
metabase.query-processor.middleware.constraints
metabase.query-processor.middleware.limit
metabase.query-processor.middleware.permissions
@@ -1200,7 +1245,8 @@
:api #{metabase.request.core
metabase.request.init
metabase.request.schema}
:uses #{api
:uses #{analytics
api
config
embedding
permissions ; FIXME
@@ -1264,11 +1310,11 @@
settings
startup
task
util
warehouses}}
transforms
util}}
secrets
{:team "Drivers"
{:team "Querying"
:api #{metabase.secrets.core}
:uses #{api driver models premium-features util}}
@@ -1377,6 +1423,23 @@
system
util}}
sql-parsing
{:team "DevEx"
:api #{metabase.sql-parsing.core}
:uses #{analytics
util}}
sql-tools
{:team "DevEx"
:api #{metabase.sql-tools.core
metabase.sql-tools.init}
:uses #{analytics
driver
lib
settings
sql-parsing
util}}
sso
{:team "UX West"
:api #{metabase.sso.api
@@ -1456,6 +1519,7 @@
models
permissions
premium-features
query-processor
request
task
util}}
@@ -1475,6 +1539,8 @@
api
app-db
config
lib
lib-be
premium-features
search
util}}
@@ -1499,11 +1565,69 @@
:uses #{analytics
api
collections
config
events
models
util}}
transforms
{:team "Querying"
:api #{metabase.transforms.core
metabase.transforms.feature-gating
metabase.transforms.init
metabase.transforms.interface
metabase.transforms.schema
metabase.transforms.util}
:uses #{analytics
api
channel
database-routing
driver
events
lib
lib-be
models
premium-features
queries
query-processor
revisions
settings
sync
task
task-history
util}
:friends #{models
enterprise/transforms-python
enterprise/workspaces}}
transforms-inspector
{:team "Gadget"
:api #{metabase.transforms-inspector.core
metabase.transforms-inspector.schema}
:uses #{driver
lib
lib-be
query-processor
sql-tools
transforms
util}}
transforms-rest
{:team "Gadget"
:api #{metabase.transforms-rest.api.transform
metabase.transforms-rest.api.transform-job
metabase.transforms-rest.api.transform-tag}
:uses #{api
driver
events
models
query-processor
request
server
sql-tools
transforms
transforms-inspector
util}}
types
{:team "Querying"
:api #{metabase.types.core
@@ -1514,6 +1638,7 @@
{:team "Querying"
:api #{metabase.upload.api
metabase.upload.core
metabase.upload.db
metabase.upload.init}
:uses #{analytics
api
@@ -1541,41 +1666,42 @@
users
{:team "UX West"
:api #{metabase.users.init
:api #{metabase.users.core
metabase.users.init
metabase.users.models.user
metabase.users.models.user-parameter-value
metabase.users.schema
metabase.users.settings}
:uses #{api
batch-processing
channel
config
events
models
permissions
premium-features
settings
setup
system
tenants
util}}
users-rest
{:team "UX West"
:api #{metabase.users-rest.api}
:uses #{analytics
api
appearance
auth-identity
collections
batch-processing
channel
config
events
models
notification
permissions
premium-features
request
settings
setup
system
tenants
util
enterprise/advanced-permissions}}
users-rest
{:team "UX West"
:api #{metabase.users-rest.api}
:uses #{api
appearance
auth-identity
collections
config
events
models
permissions
premium-features
request
sso
tenants
users
@@ -1629,7 +1755,6 @@
api
app-db
audit-app
config
driver
lib
lib-be
@@ -1649,7 +1774,6 @@
:uses #{analytics
api
app-db
config
database-routing
driver
events
@@ -1777,6 +1901,7 @@
metabase-enterprise.advanced-permissions.common
metabase-enterprise.advanced-permissions.models.permissions.group-manager}
:uses #{api
audit-app
lib
permissions
premium-features
@@ -1787,6 +1912,17 @@
warehouses
enterprise/impersonation}}
enterprise/agent-api
{:team "Metabot"
:api #{metabase-enterprise.agent-api.api}
:uses #{api
auth-identity
query-processor
request
server
util
enterprise/metabot-v3}}
enterprise/ai-entity-analysis
{:team "Metabot"
:api #{metabase-enterprise.ai-entity-analysis.api}
@@ -1856,7 +1992,7 @@
setup
startup
sync
users-rest
users
util
enterprise/serialization}}
@@ -1898,6 +2034,14 @@
util
enterprise/harbormaster}}
enterprise/cloud-proxy
{:team "Cloud"
:api #{metabase-enterprise.cloud-proxy.api}
:uses #{api
premium-features
util
enterprise/harbormaster}}
enterprise/content-translation
{:team "UX West"
:api #{metabase-enterprise.content-translation.routes}
@@ -1927,20 +2071,15 @@
:uses #{premium-features}}
enterprise/data-studio
{:team "Gadget"
{:team "UX West"
:api #{metabase-enterprise.data-studio.api}
:uses #{api
collections
database-routing
driver
events
models
permissions
premium-features
request
sync
util
warehouse-schema}}
util}}
enterprise/database-replication
{:team "Cloud"
@@ -1968,7 +2107,7 @@
settings
util
warehouse-schema
warehouses-rest}}
warehouses}}
enterprise/dependencies
{:team "Querying"
@@ -1996,8 +2135,8 @@
revisions
settings
task
util
enterprise/transforms}}
transforms
util}}
enterprise/email
{:team "UX West"
@@ -2039,7 +2178,7 @@
util}}
enterprise/impersonation
{:team "Drivers"
{:team "Querying"
:api #{metabase-enterprise.impersonation.api}
:uses #{api
audit-app
@@ -2079,44 +2218,46 @@
util}}
enterprise/metabot-v3
{:team "Metabot"
:api #{metabase-enterprise.metabot-v3.api
metabase-enterprise.metabot-v3.client
metabase-enterprise.metabot-v3.core
metabase-enterprise.metabot-v3.init
metabase-enterprise.metabot-v3.tools.api}
:uses #{activity-feed
api
app-db
audit-app
collections
config
documents
driver
legacy-mbql
lib
lib-be
models
native-query-snippets
permissions
premium-features
pulse
query-processor
request
search
server
settings
store-api
sync
system
task
users-rest
util
warehouse-schema
warehouses-rest
enterprise/dependencies
enterprise/transforms
enterprise/transforms-python}}
{:team "Metabot"
:api #{metabase-enterprise.metabot-v3.api
metabase-enterprise.metabot-v3.client
metabase-enterprise.metabot-v3.core
metabase-enterprise.metabot-v3.init
metabase-enterprise.metabot-v3.tools.api}
:friends #{enterprise/agent-api}
:uses #{activity-feed
api
app-db
audit-app
collections
config
documents
driver
legacy-mbql
lib
lib-be
models
native-query-snippets
parameters
permissions
premium-features
pulse
query-processor
request
search
server
settings
sql-tools
store-api
sync
system
task
transforms
users
util
warehouses
enterprise/dependencies
enterprise/transforms-python}}
enterprise/permission-debug
{:team "UX West"
@@ -2150,7 +2291,8 @@
task
task-history
util
enterprise/serialization}}
enterprise/serialization
enterprise/transforms-python}}
enterprise/sandbox
{:team "UX West"
@@ -2247,6 +2389,7 @@
native-query-snippets
permissions
premium-features
remote-sync
util}}
enterprise/sso
@@ -2274,7 +2417,6 @@
:uses #{analytics
api
collections
collections-rest
embedding
premium-features
queries
@@ -2312,50 +2454,29 @@
enterprise/transforms
{:team "Querying"
:api #{metabase-enterprise.transforms.api
metabase-enterprise.transforms.core
metabase-enterprise.transforms.init
metabase-enterprise.transforms.instrumentation
metabase-enterprise.transforms.interface
metabase-enterprise.transforms.schema
metabase-enterprise.transforms.util}
:uses #{analytics
api
app-db
channel
collections
driver
events
lib
lib-be
models
premium-features
queries
query-processor
request
revisions
search
settings
sync
task
task-history
util}}
:api #{}
:uses #{premium-features}}
enterprise/transforms-python
{:team "Querying"
:api #{metabase-enterprise.transforms-python.api
metabase-enterprise.transforms-python.init}
metabase-enterprise.transforms-python.core
metabase-enterprise.transforms-python.init
metabase-enterprise.transforms-python.python-runner}
:uses #{analytics
api
app-db
config
driver
events
lib
lib-be
models
permissions
query-processor
settings
util
enterprise/transforms}}
transforms
util}}
enterprise/upload-management
{:team "UX West"
@@ -2364,7 +2485,32 @@
models
premium-features
upload
util}}}
util}}
enterprise/workspaces
{:team "Metabot"
:api #{metabase-enterprise.workspaces.api
metabase-enterprise.workspaces.init}
:uses #{api
api-keys
app-db
config
database-routing
driver
events
lib
lib-be
models
queries
;; NOTE: we will remove this once we get "pure transforms" module.
query-processor
request
settings
sql-tools
system
transforms
util
enterprise/transforms-python}}}
;; namespaces matching these patterns (with `re-find`) are excluded from the module linter. Since regex literals
;; aren't allowed in EDN just used the `(str <regex>)` version i.e. two slashes instead of one.

View File

@@ -3,7 +3,7 @@
;; TODO -- seems silly to maintain different blacklists and whitelists here than we use for the deftest `^:parallel`
;; checker...
{:explicitly-safe
#{ ;; these toucan methods might actually set global values if it's used outside of a transaction,
#{;; these toucan methods might actually set global values if it's used outside of a transaction,
;; but since mt/with-temp runs in a transaction, so we'll ignore them in this case.
toucan2.core/delete!
toucan2.core/update!

View File

@@ -0,0 +1,38 @@
(ns hooks.clojure.core
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]))
(defn- all-uppercase? [symb]
(let [s (str symb)]
(= s #_{:clj-kondo/ignore [:discouraged-var]} (str/upper-case s))))
(defn- has-underscores? [symb]
(str/includes? (str symb) "_"))
(defn- check-symbol-is-kebab-case [symbol-node]
(let [symb (hooks/sexpr symbol-node)]
(when (or (all-uppercase? symb)
(has-underscores? symb))
(hooks/reg-finding! (assoc (meta symbol-node)
:message "Use kebab-case for function and variable names; don't use special notation for constants."
:type :metabase/check-def-kebab-case)))))
(defn lint-def* [{:keys [node]}]
(let [[_def & args] (:children node)
name-symbol (some (fn [arg]
(when (and (hooks/token-node? arg)
(symbol? (hooks/sexpr arg)))
arg))
args)]
(check-symbol-is-kebab-case name-symbol)))
(defn lint-def [x]
(lint-def* x)
x)
(comment
(defn x []
(let [node (-> "(def ^:private TYPE->MODEL {\"document\" :model/Document})"
hooks/parse-string)]
(lint-def {:node node}))))

View File

@@ -0,0 +1,52 @@
(ns hooks.clojure.core.def
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]))
(defn- uppercase-name?
"Whether the symbol is clearly an uppercase name like `TYPE-CONSTANTS` or `SOME_CONSTANT` or `TYPE->MODEL`."
[s]
(and (re-find #"[A-Z0-9]+(?:[-_]>?[A-Z0-9]+)+" s)
;; ignore stuff like `->SCREAMING_SNAKE_CASE`... this is ok
(not (str/includes? s "SCREAMING_SNAKE_CASE"))))
(defn- has-underscores? [s]
(and (str/includes? s "_")
;; ignore stuff like `->snake_case` and `->SCREAMING_SNAKE_CASE`
(not (str/includes? s "snake_case"))
(not (str/includes? s "SCREAMING_SNAKE_CASE"))))
(defn- check-symbol-is-kebab-case [symbol-node]
(let [symb (hooks/sexpr symbol-node)
s (str symb)]
(cond
(uppercase-name? s)
(hooks/reg-finding!
(assoc (meta symbol-node)
:message "Use lower-case names for functions and variables; don't use special notation for constants. [:metabase/check-def-check-not-all-uppercase]"
:type :metabase/check-def-check-not-uppercase-name))
(has-underscores? s)
(hooks/reg-finding!
(assoc (meta symbol-node)
:message "Use kebab-case names for functions and variables. [:metabase/check-def-no-underscores]"
:type :metabase/check-def-no-underscores)))))
(defn lint-def* [{:keys [node]}]
(let [[_def & args] (:children node)
name-symbol (some (fn [arg]
(when (and (hooks/token-node? arg)
(symbol? (hooks/sexpr arg)))
arg))
args)]
(check-symbol-is-kebab-case name-symbol)))
(defn lint-def [x]
(lint-def* x)
x)
(comment
(defn x []
(let [node (-> "(def ^:private TYPE->MODEL {\"document\" :model/Document})"
hooks/parse-string)]
(lint-def {:node node}))))

View File

@@ -0,0 +1,7 @@
(ns hooks.clojure.core.defmacro
(:require
[hooks.clojure.core.def]))
(defn lint-defmacro [x]
(hooks.clojure.core.def/lint-def* x)
x)

View File

@@ -2,6 +2,7 @@
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]
[hooks.clojure.core.def]
[hooks.common]))
(defn- check-arglists [report-node arglists]
@@ -49,4 +50,5 @@
(defn lint-defmulti [x]
(defmulti-check-for-arglists-metadata (:node x))
(hooks.clojure.core.def/lint-def* x)
x)

View File

@@ -2,6 +2,7 @@
(:require
[clj-kondo.hooks-api :as hooks]
[clojure.string :as str]
[hooks.clojure.core.def]
[hooks.common]))
(defn- end-with-exclamation?
@@ -50,6 +51,11 @@
(non-thread-safe-form-should-end-with-exclamation* node config))
{:node node})
(defn lint-defn [x]
(non-thread-safe-form-should-end-with-exclamation x)
(hooks.clojure.core.def/lint-def* x)
x)
(comment
(require '[clj-kondo.core :as clj-kondo])
(def form (str '(defmacro a

View File

@@ -99,12 +99,48 @@
:message "Metabase namespaces should have the form metabase[-enterprise].<module>.* [:metabase/namespace-name]"
:type :metabase/namespace-name)))))))
(defn- ns-form-node->import-node [ns-form-node]
(some (fn [node]
(when (and (hooks/list-node? node)
(let [first-child (first (:children node))]
(and (hooks/keyword-node? first-child)
(= (hooks/sexpr first-child) :import))))
node))
(:children ns-form-node)))
(defn- jsqlparser-import?
"Check if a symbol or string represents a jsqlparser import."
[s]
(str/starts-with? (str s) "net.sf.jsqlparser"))
(defn- lint-jsqlparser-imports [ns-form-node]
(when-let [import-node (ns-form-node->import-node ns-form-node)]
(doseq [node (rest (:children import-node))
:when (not (contains? (hooks.common/ignored-linters node) :metabase/no-jsqlparser-imports))]
(cond
;; Handle (net.sf.jsqlparser.foo Bar Baz) form
(hooks/list-node? node)
(let [package-node (first (:children node))
package-name (when package-node (str (hooks/sexpr package-node)))]
(when (jsqlparser-import? package-name)
(hooks/reg-finding! (assoc (meta node)
:message "Don't import net.sf.jsqlparser classes directly. This code should be agnostic to the parsing library. [:metabase/no-jsqlparser-imports]"
:type :metabase/no-jsqlparser-imports))))
;; Handle net.sf.jsqlparser.foo.Bar form (single class import)
(hooks/token-node? node)
(when (jsqlparser-import? (hooks/sexpr node))
(hooks/reg-finding! (assoc (meta node)
:message "Don't import net.sf.jsqlparser classes directly. This code should be agnostic to the parsing library. [:metabase/no-jsqlparser-imports]"
:type :metabase/no-jsqlparser-imports)))))))
(defn lint-ns [x]
(doto (:node x)
lint-require-shapes
lint-requires-on-new-lines
(lint-modules (modules/config x))
lint-namespace-name)
lint-namespace-name
lint-jsqlparser-imports)
x)
(comment

View File

@@ -75,6 +75,15 @@
(contains? module-api-namespaces ns-symb)
(contains? module-friends current-module))))
(defn- rest-module? [module]
(str/ends-with? module "-rest"))
(defn- routes-module? [module]
(str/ends-with? module "-routes"))
(defn- core-module? [module]
(str/ends-with? module "core"))
(defn usage-error
"Find usage errors when a `required-namespace` is required in the `current-module`. Returns a string describing the
error type if there is one, otherwise `nil` if there are no errors."
@@ -93,4 +102,15 @@
(format "Namespace %s is not an allowed external API namespace for the %s module. [:metabase/modules %s :api]"
required-namespace
required-module
required-module)))))
required-module)
;; (for now) rest modules are allowed to use one another; `routes` is ok because it collects routes together
;; and `core` is ok because [[metabase.core.init]] might need to init some of the `-routes` modules'
;; namespaces
(and (not ((some-fn rest-module? routes-module? core-module?) current-module))
(rest-module? required-module))
(format "Do not use -rest modules (%s) in non-rest modules (%s) -- move things from %s to %s if needed"
required-module
current-module
required-module
(symbol (str/replace required-module #"-rest$" "")))))))

View File

@@ -90,6 +90,7 @@
metabase-enterprise.test/with-gtaps! [[:inner 0]]
metabase-enterprise.test/with-gtaps-for-user! [[:inner 0]]
metabase-enterprise.test/with-user-attributes [[:block 2]]
metabase-enterprise.workspaces.models.workspace-log/track! [[:block 2]]
metabase.actions.actions-test/with-actions-test-data-and-actions-permissively-enabled [[:block 0]]
metabase.actions.test-util/with-actions [[:block 1]]
metabase.actions.test-util/with-actions-disabled [[:block 0]]
@@ -119,7 +120,10 @@
metabase.dashboards.models.dashboard-test/with-dash-in-collection [[:inner 0]]
metabase.driver-api.core/match [[:inner 0]]
metabase.driver-api.core/match-one [[:inner 0]]
metabase.driver-api.core/match-lite [[:inner 0]]
metabase.driver-api.core/match-many [[:inner 0]]
metabase.driver-api.core/replace [[:inner 0]]
metabase.driver-api.core/replace-lite [[:inner 0]]
metabase.driver-api.core/replace-in [[:inner 0]]
metabase.driver.bigquery-cloud-sdk.query-processor/with-temporal-type [[:default]]
metabase.driver.druid.client/DELETE [[:default]]
@@ -133,6 +137,7 @@
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info [[:block 1]]
metabase.driver.sql.query-processor/apply-top-level-clause [[:default]]
metabase.driver/with-driver [[:block 1]]
metabase.driver/with-swapped-connection-details [[:block 2]]
metabase.embedding-rest.api.embed-test/do-response-formats [[:block 1]]
metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
metabase.embedding-rest.api.embed-test/with-embedding-enabled-and-temp-card-referencing [[:block 3]]
@@ -154,8 +159,9 @@
metabase.lib.util.match/match [[:inner 0]]
metabase.lib.util.match/match-one [[:inner 0]]
metabase.lib.util.match/match-lite [[:inner 0]]
metabase.lib.util.match/match-lite-recursive [[:inner 0]]
metabase.lib.util.match/match-many [[:inner 0]]
metabase.lib.util.match/replace [[:inner 0]]
metabase.lib.util.match/replace-lite [[:inner 0]]
metabase.lib.util.match/replace-in [[:inner 0]]
metabase.models.interface/define-batched-hydration-method [[:inner 0]]
metabase.models.interface/define-simple-hydration-method [[:inner 0]]

View File

@@ -1,10 +1,11 @@
FROM mcr.microsoft.com/vscode/devcontainers/java:21
# Set up nodesource, install node, yarn, fontconfig for static viz, rlwrap for dev ergonomics
# Set up nodesource, install node, bun, fontconfig for static viz, rlwrap for dev ergonomics
RUN ( curl -fsSL https://deb.nodesource.com/setup_22.x | bash ) \
&& export DEBIAN_FRONTEND=noninteractive \
&& apt-get update && apt-get -y install --no-install-recommends nodejs yarn rlwrap fontconfig
&& apt-get update && apt-get -y install --no-install-recommends nodejs rlwrap fontconfig \
&& npm install -g bun
# install Clojure
RUN curl https://download.clojure.org/install/linux-install-1.12.0.1488.sh | bash

View File

@@ -61,6 +61,7 @@
(eval . (put-clojure-indent 'u/prog1 1))
(eval . (put-clojure-indent 'u/select-keys-when '(:form)))
(eval . (put-clojure-indent 'with-meta '(:form)))
(eval . (put-clojure-indent 'ws.log/track! 2))
;; these ones have to be done with `define-clojure-indent' for now because of upstream bug
;; https://github.com/clojure-emacs/clojure-mode/issues/600 once that's resolved we should use `put-clojure-indent'
;; instead. Please don't add new entries unless they don't work with `put-clojure-indent'

View File

@@ -100,7 +100,7 @@ METASTORE_DEV_SERVER_URL="https://token-check.staging.metabase.com"
#
# The whole environment is already orchestrated via deps.edn using :e2e alias.
# Treat it as a source of truth for JVM flags and ENVs whether you decide to run
# backend on your own, or using `yarn test-cypress` (local test runner).
# backend on your own, or using `bun run test-cypress` (local test runner).
#
# You don't _have to_ export any of these vars (except for the tokens below).
# Things will still work.
@@ -118,6 +118,9 @@ MB_EDITION="ee"
# MB_JETTY_HOST="localhost"
# MB_JETTY_PORT=4000
# Frontend dev server port (for hot reload). Must match the port used by `yarn build-hot`.
# MB_FRONTEND_DEV_PORT=8080
# 3.2 E2E Local Runner Setup
# ------------------------------------------------------------------------------

View File

@@ -1,6 +0,0 @@
frontend/src/cljs
frontend/src/cljs_release
e2e/support/cypress_sample_database.js
e2e/support/cypress_sample_instance_data.js
frontend/src/metabase-types/openapi/types.gen.ts
e2e/embedding-sdk-host-apps

View File

@@ -1,356 +0,0 @@
/* eslint-disable import/no-commonjs */
/* eslint-disable no-undef */
const path = require("path");
// `postcss-modules` lints css modules class names, but it currently crashes
// eslint on vscode. If you use webstorm or want to run the lint for the cli, you
// can use this flag to enable it. This is set to true in CI
const shouldLintCssModules =
process.env.LINT_CSS_MODULES === "true" || process.env.CI;
const plugins = ["react", "no-only-tests", "ttag", "i18next"];
if (shouldLintCssModules) {
plugins.push("postcss-modules");
}
module.exports = {
ignorePatterns: ["!.storybook"],
rules: {
strict: [2, "never"],
"no-undef": 2,
"no-var": 1,
"no-unused-vars": [
"error",
{
vars: "all",
args: "none",
varsIgnorePattern: "^_.+$",
ignoreRestSiblings: true,
},
],
"no-empty": [1, { allowEmptyCatch: true }],
// Note: adding this rule to a eslint config file in a subfolder will remove
// *not* carry over the restricted imports from parent folders, you will
// need to copy them over
"no-restricted-imports": [
"error",
{
paths: [
{
name: "moment",
message: "Moment is deprecated, please use dayjs",
},
{
name: "moment-timezone",
message: "Moment is deprecated, please use dayjs",
},
],
},
],
curly: [1, "all"],
eqeqeq: [1, "smart"],
"import/no-duplicates": ["warn", { considerQueryString: true }],
"import/no-default-export": 2,
"import/no-named-as-default": 0,
"import/no-commonjs": 1,
"import/order": [
"error",
{
"newlines-between": "always",
alphabetize: {
order: "asc",
orderImportKind: "asc",
caseInsensitive: false,
},
groups: [
"builtin",
"external",
"internal",
"parent",
"sibling",
"index",
],
warnOnUnassignedImports: false,
},
],
"sort-imports": [
"error",
{
// allows this rule to work with import/order
ignoreDeclarationSort: true,
},
],
"no-console": [2, { allow: ["warn", "error", "errorBuffer"] }],
"react/no-is-mounted": 2,
"react/prefer-es6-class": 2,
"react/display-name": 1,
"react/prop-types": 2,
"react/no-did-mount-set-state": 0,
"react/no-did-update-set-state": 0,
"react/no-find-dom-node": 0,
"react/no-children-prop": 2,
"react/no-string-refs": 2,
"react/no-unescaped-entities": 2,
"react/jsx-no-target-blank": 2,
"react/jsx-key": 2,
"react/forbid-component-props": [2, { forbid: ["sx"] }],
"react-hooks/exhaustive-deps": ["warn"],
"prefer-const": [1, { destructuring: "all" }],
"no-restricted-globals": ["error", "close"],
"no-useless-escape": 0,
"no-only-tests/no-only-tests": [
"error",
{
block: [
"describe",
"it",
"context",
"test",
"tape",
"fixture",
"serial",
"Feature",
"Scenario",
"Given",
"And",
"When",
"Then",
],
},
],
complexity: ["error", { max: 55 }],
...(shouldLintCssModules
? {
"postcss-modules/no-undef-class": "error",
}
: {}),
},
globals: {
before: true,
cy: true,
Cypress: true,
},
env: {
browser: true,
es2020: true,
commonjs: true,
jest: true,
"jest/globals": true,
},
parser: "babel-eslint",
plugins,
extends: [
"eslint:recommended",
"plugin:react/recommended",
"plugin:react/jsx-runtime",
"plugin:react-hooks/recommended",
"plugin:import/errors",
"plugin:import/warnings",
"plugin:import/typescript",
"plugin:depend/recommended",
"plugin:storybook/recommended",
"plugin:i18next/recommended",
],
settings: {
"import/internal-regex": "^metabase/|^metabase-lib/",
"import/resolver": {
webpack: {
config: path.resolve(__dirname, "./rspack.main.config.js"),
typescript: true,
},
},
"import/ignore": ["\\.css$"],
react: {
version: "detect",
},
"postcss-modules": {
baseDir: "./frontend/src",
},
},
parserOptions: {
ecmaFeatures: {
legacyDecorators: true,
},
},
overrides: [
{
files: ["*.js", "*.jsx", "*.ts", "*.tsx"],
rules: {
"jtag-missing-key": "error",
"no-unconditional-metabase-links-render": "error",
"no-color-literals": "error",
"no-literal-metabase-strings": "error",
"no-oss-reinitialize-import": "error",
"depend/ban-dependencies": [
"error",
{
allowed: [
"underscore",
"moment",
"lodash.orderby",
"lodash.debounce",
],
},
],
},
},
{
files: [
"*.unit.spec.*",
"frontend/src/metabase/admin/**/*",
"frontend/src/metabase/setup/**/*",
"enterprise/frontend/src/metabase-enterprise/whitelabel/**/*",
"enterprise/frontend/src/metabase-enterprise/embedding/**/*",
"frontend/lint/**/*",
"*.stories.*",
"**/.storybook/*",
"stories-data.*",
"e2e/**/*",
"**/tests/*",
"release/**/*",
"rspack.config.js",
"rspack.main.config.js",
"rspack.embedding-sdk-package.config.js",
"rspack.embedding-sdk-bundle.config.js",
],
rules: {
"no-color-literals": "off",
"no-unconditional-metabase-links-render": "off",
"no-literal-metabase-strings": "off",
},
},
{
files: [
"*.unit.spec.*",
"frontend/lint/**/*",
"*.stories.*",
"stories-data.*",
"e2e/**/*",
"**/tests/*",
"release/**/*",
"rspack.main.config.js",
],
rules: {
"i18next/no-literal-string": "off",
},
},
{
extends: ["plugin:@typescript-eslint/recommended"],
files: ["*.ts", "*.tsx"],
parser: "@typescript-eslint/parser",
plugins: ["@typescript-eslint"],
rules: {
"prefer-rest-params": "off",
"react/prop-types": "off", // TypeScript handles prop validation
"@typescript-eslint/explicit-module-boundary-types": "off",
"@typescript-eslint/no-inferrable-types": "off",
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-this-alias": "off",
"@typescript-eslint/consistent-type-imports": [
"error",
{
fixStyle: "inline-type-imports",
},
],
"@typescript-eslint/no-import-type-side-effects": "error",
"@typescript-eslint/no-unused-vars": [
"error",
{
argsIgnorePattern: "^_.+$",
varsIgnorePattern: "^_.+$",
ignoreRestSiblings: true,
destructuredArrayIgnorePattern: "^_.+$",
},
],
// This was introduced in 6.0.0
"@typescript-eslint/no-unsafe-declaration-merging": "off",
},
},
{
extends: [
"plugin:jest/recommended",
"plugin:jest-dom/recommended",
"plugin:testing-library/react",
"plugin:jest-formatting/recommended",
],
plugins: ["jest", "jest-dom", "testing-library", "jest-formatting"],
files: [
"*.unit.spec.ts",
"*.unit.spec.tsx",
"*.unit.spec.js",
"*.unit.spec.jsx",
],
rules: {
"jest/valid-title": ["error", { ignoreTypeOfDescribeName: true }],
"jest/expect-expect": [
"error",
{
assertFunctionNames: ["expect*", "assert*"],
additionalTestBlockFunctions: [],
},
],
},
},
{
// Enable jest formatting for cypress tests too, the plugin logic just works
extends: ["plugin:jest-formatting/recommended"],
files: ["*.cy.spec.ts", "*.cy.spec.js"],
},
{
files: ["frontend/src/**/*"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "Literal[value=/mb-base-color-/]",
message:
"You may not use base colors in the application, use semantic colors instead. (see colors.module.css)",
},
],
},
},
{
files: ["frontend/src/metabase/**/*"],
rules: {
"no-restricted-syntax": [
"error",
{
selector: "Literal[value=/mb-base-color-/]",
message:
"You may not use base colors in the application, use semantic colors instead. (see colors.module.css)",
},
],
},
},
{
files: ["frontend/src/metabase/query_builder/**/*"],
rules: {
"import/no-cycle": "error",
},
},
{
files: ["docs/**/snippets/**/*.{ts,tsx,js,jsx}"],
rules: {
"@typescript-eslint/no-unused-vars": "off",
"@typescript-eslint/no-var-requires": "off",
"import/no-commonjs": "off",
"import/no-default-export": "off",
"import/order": "off",
"import/no-unresolved": "off",
"no-color-literals": "off",
},
},
{
files: ["frontend/build/**/*.js"],
rules: {
"import/no-commonjs": "off",
},
},
{
files: ["**/*.stories.tsx", "**/preview.tsx"],
rules: {
"import/no-default-export": "off",
},
},
],
};

View File

@@ -1,7 +1,5 @@
# execute this in your shell to enable custom merge driver:
# echo '\n[include]\npath=../.gitconfig' >> .git/config
#
# TODO (Bryan 12/12/25) -- reenable this when we can completely verify correctness
# [merge "yaml-migrations"]
# name = YAML migration changeset-aware merge
# driver = mage -merge-yaml-migrations %O %A %B %L %P
[merge "yaml-migrations"]
name = YAML migration changeset-aware merge
driver = bin/mage -merge-yaml-migrations %O %A %B %L %P

View File

@@ -5,7 +5,7 @@ PENDING CI / PENDING REVIEW / READY _(choose one and update accordingly)_
- Reproduces #XXXXX
### How to test this manually?
- `yarn test-cypress`
- `bun run test-cypress`
- `relative/path/to/the/file`
> _(For still unfixed bug)_
- Replace `it.skip()` with `it.only()` to run the test in isolation

View File

@@ -2,9 +2,16 @@ name: Fetch artifact
description: Fetches a specific artifact and downloads it to the current directory
inputs:
name:
description: The name of the artifact to fetch
commit:
description: Commit SHA for the artifact
required: true
edition:
description: Metabase edition (ee or oss)
required: true
release:
description: Whether this is a release artifact (uses metabase-release- prefix)
required: false
default: "false"
output-name:
description: Optional custom name for the output jar file (defaults to metabase.jar)
required: false
@@ -25,15 +32,21 @@ runs:
script: | # js
const fs = require('fs');
const isRelease = "${{ inputs.release }}" === "true";
const prefix = isRelease ? "metabase-release" : "metabase";
const artifactName = `${prefix}-${{ inputs.edition }}-${{ inputs.commit }}-uberjar`;
console.log(`Looking for artifact: ${artifactName}`);
const artifacts = await github.rest.actions.listArtifactsForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
name: "${{ inputs.name }}",
name: artifactName,
per_page: 1,
});
if (!artifacts.data?.artifacts?.[0]?.id) {
throw new Error(`No artifacts found for ${{ inputs.name }}`);
core.setFailed(`No artifacts found for ${artifactName}`);
return;
}
const artifact_id = artifacts.data.artifacts[0].id;

View File

@@ -1,14 +1,13 @@
name: Prepare back-end environment
description: |
Prepare the backend. Installs jdk, Clojure, and fetches the cache for m2.
The CI config fetches `ci-test-config.json` from master and lets us ignore tests at the var level if they are flaking.
inputs:
java-version:
required: true
default: '21'
default: "21"
clojure-version:
required: true
default: '1.12.0.1488'
default: "1.12.0.1488"
runs:
using: "composite"
@@ -17,7 +16,7 @@ runs:
uses: actions/setup-java@v4
with:
java-version: ${{ inputs.java-version }}
distribution: 'temurin'
distribution: "temurin"
- name: Install Clojure CLI
shell: bash
continue-on-error: true
@@ -29,6 +28,13 @@ runs:
uses: ./.github/actions/get-cache-keys
id: get-cache-keys
- name: Install uv (for Python package installation)
uses: astral-sh/setup-uv@v7
with:
enable-cache: false
version: "0.10.2" # keep in sync with mise.toml
github-token: ${{ github.token }}
- name: Restore M2 cache
uses: actions/cache/restore@v4
with:

View File

@@ -3,7 +3,7 @@ description: Cypress preparation steps
inputs:
working-directory:
description: "Optional working directory for yarn commands"
description: "Optional working directory for bun commands"
required: false
default: "."
@@ -15,11 +15,10 @@ outputs:
runs:
using: "composite"
steps:
- name: Install Chrome v111
uses: browser-actions/setup-chrome@v1
- name: Install Chrome v144
uses: browser-actions/setup-chrome@v2
with:
# https://chromium.cypress.io/linux/stable/111.0.5563.146
chrome-version: 1097615
chrome-version: 144
id: setup-chrome
- name: Get cache keys
@@ -34,9 +33,9 @@ runs:
- name: Ensure that Cypress executable is ready
run: |
yarn cypress install
yarn cypress cache path
yarn cypress cache list
yarn cypress verify
bun run cypress install
bun run cypress cache path
bun run cypress cache list
bun run cypress verify
shell: bash
working-directory: ${{ inputs.working-directory }}

View File

@@ -17,6 +17,12 @@ runs:
node-version: ${{ inputs.node-version }} # this overrides, if present
node-version-file: ".nvmrc"
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ github.token }}
- name: Get cache keys
uses: ./.github/actions/get-cache-keys
id: get-cache-keys
@@ -29,12 +35,12 @@ runs:
~/.gitlibs
key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
- name: Get yarn cache directory
id: yarn-cache-dir
- name: Get bun cache directory
id: bun-cache
run: |
YARN_CACHE_DIR=$(yarn cache dir)
echo "Yarn cache directory: $YARN_CACHE_DIR"
echo "dir=$YARN_CACHE_DIR" >> $GITHUB_OUTPUT
BUN_CACHE_DIR=$(bun pm cache)
echo "Bun cache directory: $BUN_CACHE_DIR"
echo "dir=$BUN_CACHE_DIR" >> $GITHUB_OUTPUT
shell: bash
- name: Restore node_modules cache
@@ -42,7 +48,7 @@ runs:
id: node-modules-cache
with:
path: |
${{ steps.yarn-cache-dir.outputs.dir }}
${{ steps.bun-cache.outputs.dir }}
node_modules
key: ${{ steps.get-cache-keys.outputs.node-cache-key }}
@@ -50,9 +56,9 @@ runs:
# If a job wants to patch packages, it does so explicitly in the CI. This setting is opt-out.
# For example, we never want to cache node_modules with patches already applied so cache-generator.yml skips that step.
- name: Clean install
run: yarn install --frozen-lockfile --prefer-offline
run: bun install --frozen-lockfile
shell: bash
- name: Patch frontend dependencies
if: inputs.apply-patches == 'true'
run: yarn patch-package
run: bun run patch-package
shell: bash

View File

@@ -0,0 +1,14 @@
name: Prepare Release Scripts
description: Set up bun and build release scripts
runs:
using: composite
steps:
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ github.token }}
- name: Build release scripts
shell: bash
run: cd ${{ github.workspace }}/release && bun install --frozen-lockfile && bun run build

View File

@@ -0,0 +1,132 @@
name: Prepare Shoppy E2E environment
description: Shared setup steps for Shoppy E2E tests (regular and synthetic)
inputs:
commit:
description: "Commit SHA for artifact retrieval"
required: true
sample-app-branch-name:
description: "Branch name for the sample app"
required: true
sample-app-environment:
description: "Environment (production/development)"
required: true
staging-mb-all-features-token:
description: "Staging MB all features token"
required: true
shoppy-iam-role:
description: "Shoppy IAM role for AWS credentials"
required: true
shoppy-metabase-app-db-s3-bucket:
description: "S3 bucket for Shoppy app DB dump"
required: true
shoppy-metabase-app-db-s3-key:
description: "S3 key for Shoppy app DB dump"
required: true
shoppy-metabase-app-db-user:
description: "Shoppy Metabase app DB user"
required: true
shoppy-metabase-app-db-database:
description: "Shoppy Metabase app DB database"
required: true
metastore-dev-server-url:
description: "Metastore dev server URL"
required: true
shoppy-datadog-application-id:
description: "Shoppy Datadog application ID"
required: true
shoppy-datadog-client-token:
description: "Shoppy Datadog client token"
required: true
outputs:
chrome-path:
description: "Path to Chrome executable"
value: ${{ steps.cypress-prep.outputs.chrome-path }}
sample_app_branch_exists:
description: "Whether the sample app branch exists"
value: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists }}
runs:
using: "composite"
steps:
- uses: ./.github/actions/maximize-disk-space
# We have to use the latest version that does not have this issue https://github.com/docker/compose/pull/12752
- name: Set up Docker Compose
uses: docker/setup-compose-action@v1
with:
version: latest
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
commit: ${{ inputs.commit }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"
- name: Retrieve Embedding SDK dist artifact
uses: actions/download-artifact@v4
with:
name: embedding-sdk-${{ inputs.commit }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Check if sample app branch exists
id: check-sample-app-branch
shell: bash
env:
SAMPLE_APP_BRANCH_NAME: ${{ inputs.sample-app-branch-name }}
run: |
REPO_URL="https://github.com/metabase/shoppy.git"
echo "Checking if branch '${SAMPLE_APP_BRANCH_NAME}' exists in ${REPO_URL}..."
if git ls-remote --exit-code --heads "$REPO_URL" "${SAMPLE_APP_BRANCH_NAME}"; then
echo "sample_app_branch_exists=true" >> $GITHUB_OUTPUT
else
echo "sample_app_branch_exists=false" >> $GITHUB_OUTPUT
fi
- name: Configure AWS credentials
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ inputs.shoppy-iam-role }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
aws-region: us-east-1
- name: Download Shoppy's App DB PostgreSQL dump from S3
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
shell: bash
run: |
aws s3 cp s3://${{ inputs.shoppy-metabase-app-db-s3-bucket }}/${{ inputs.shoppy-metabase-app-db-s3-key }} ./e2e/tmp/db_dumps/shoppy_metabase_app_db_dump.sql
- name: Prepare and launch Shoppy containers
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
shell: bash
env:
SAMPLE_APP_BRANCH_NAME: ${{ inputs.sample-app-branch-name }}
SAMPLE_APP_ENVIRONMENT: ${{ inputs.sample-app-environment }}
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ inputs.staging-mb-all-features-token }}
METASTORE_DEV_SERVER_URL: ${{ inputs.metastore-dev-server-url }}
METABASE_APP_DB_USER: ${{ inputs.shoppy-metabase-app-db-user }}
METABASE_APP_DB: ${{ inputs.shoppy-metabase-app-db-database }}
SHOPPY_DATADOG_APPLICATION_ID: ${{ inputs.shoppy-datadog-application-id }}
SHOPPY_DATADOG_CLIENT_TOKEN: ${{ inputs.shoppy-datadog-client-token }}
SHOPPY_DATADOG_SITE: "us5.datadoghq.com"
SHOPPY_DATADOG_ENV: "staging"
run: npx tsx ./e2e/runner/embedding-sdk/sample-apps/start-ci.ts shoppy-e2e
- name: Prune build cache
shell: bash
run: docker builder prune -af
- name: Log free disk space
shell: bash
run: df -h /

View File

@@ -2,9 +2,10 @@ name: Prepare Uberjar Artifact
description: Prepare and upload Metabase JAR as a GitHub artifact.
inputs:
name:
required: true
description: Artifact name
edition:
required: false
default: "ee"
description: Metabase edition (ee or oss)
runs:
using: "composite"
@@ -18,7 +19,7 @@ runs:
- name: Upload JARs as artifact
uses: actions/upload-artifact@v4
with:
name: ${{ inputs.name }}
name: metabase-${{ inputs.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
path: |
./target/uberjar/metabase.jar
./COMMIT-ID

View File

@@ -0,0 +1,77 @@
name: Embedding SDK Bundle Size Check
description: |
Downloads the current branch's uberjar and builds the base ref's
embedding-sdk.js from source, compares their sizes,
and sets output if the size change exceeds the threshold.
inputs:
edition:
description: 'Metabase edition (ee or oss)'
required: true
base-ref-commit:
description: 'Commit SHA of the base ref (e.g. merge base).'
required: true
threshold-percent:
description: 'Percent threshold for bundle size change'
required: true
outputs:
status:
description: "Bundle size status: increased, decreased, or stable"
value: ${{ steps.compare.outputs.status }}
size_change_percent:
description: "size change percent (positive = increase, negative = decrease)"
value: ${{ steps.compare.outputs.size_change_percent }}
runs:
using: "composite"
steps:
- name: Prepare backend
uses: ./.github/actions/prepare-backend
- name: Prepare frontend
uses: ./.github/actions/prepare-frontend
- name: Download current uberjar
uses: actions/download-artifact@v4
with:
name: metabase-${{ inputs.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
path: temp/current-uberjar
- name: Extract embedding-sdk.js from current uberjar
shell: bash
run: unzip -j temp/current-uberjar/target/uberjar/metabase.jar frontend_client/app/embedding-sdk.js -d temp/current-bundle
- name: Checkout base ref
uses: actions/checkout@v4
with:
ref: ${{ inputs.base-ref-commit }}
path: temp/base-ref-src
- name: Build base-ref embedding-sdk.js
shell: bash
run: |
cd temp/base-ref-src
bun install
MB_EDITION=${{ inputs.edition }} bun run build-release
- name: Compare sizes and set output
id: compare
shell: bash
run: |
current_size=$(wc -c < temp/current-bundle/embedding-sdk.js) || { echo "::error::Failed to read current bundle"; exit 1; }
base_ref_size=$(wc -c < temp/base-ref-src/resources/frontend_client/app/embedding-sdk.js) || { echo "::error::Failed to read base-ref bundle"; exit 1; }
[ "$current_size" -gt 0 ] && [ "$base_ref_size" -gt 0 ] || { echo "::error::Bundle file is empty"; exit 1; }
diff=$((current_size - base_ref_size))
percent=$(( diff * 100 / base_ref_size ))
echo "Current size: $current_size bytes"
echo "Base ref size: $base_ref_size bytes"
echo "Difference: $diff bytes ($percent%)"
threshold="${{ inputs.threshold-percent }}"
if [ "$percent" -gt "$threshold" ]; then
status="increased"
elif [ "$percent" -lt "$(( -threshold ))" ]; then
status="decreased"
else
status="stable"
fi
echo "status=$status" >> $GITHUB_OUTPUT
echo "size_change_percent=$percent" >> $GITHUB_OUTPUT

View File

@@ -12,6 +12,15 @@ inputs:
logs-artifact-suffix:
required: false
description: Suffix to append to the test logs artifact name to avoid conflicts in matrix jobs
edition:
required: false
default: 'ee'
description: Edition to test (oss or ee)
outputs:
test-outcome:
description: "The outcome of the test run (success, failure, cancelled, skipped)"
value: ${{ steps.run-test.outcome }}
runs:
using: "composite"
@@ -23,12 +32,12 @@ runs:
uses: ./.github/actions/prepare-frontend
- name: Build static viz frontend
if: ${{ inputs.build-static-viz == 'true' }}
run: yarn build-static-viz
run: bun run build-static-viz
shell: bash
env:
MB_EDITION: ee
- name: Test database driver
run: clojure -X:dev:ci:ee:ee-dev:drivers:drivers-dev:test ${{ inputs.test-args }}
run: clojure -X:dev:ci:${{ inputs.edition }}:${{ inputs.edition }}-dev:drivers:drivers-dev:test ${{ inputs.test-args }}
shell: bash
id: run-test
# Trunk Quarantine controls the final state of the run in the CI!
@@ -52,7 +61,7 @@ runs:
if: always() && steps.run-test.outcome != 'success'
uses: actions/upload-artifact@v4
with:
name: ${{ format('test-logs-{0}{1}', github.job, (inputs.logs-artifact-suffix == '' || inputs.logs-artifact-suffix == null) && '' || format('-{0}', inputs.logs-artifact-suffix)) }}
name: ${{ format('test-logs-{0}{1}', github.job, inputs.logs-artifact-suffix && format('-{0}', inputs.logs-artifact-suffix) || '') }}
path: logs/test-log.json
retention-days: 1
# Failing to upload the artifact should never affect the outcome of the whole test run.

View File

@@ -21,6 +21,8 @@ inputs:
variant:
required: false
default: ""
previous-step-outcome:
required: true
runs:
using: "composite"
@@ -57,3 +59,4 @@ runs:
dry-run: ${{ github.event_name == 'pull_request' && github.event.pull_request.draft == true }} # quarantine, but do not upload results
token: ${{ inputs.trunk-api-token }}
use-cache: true
previous-step-outcome: ${{ inputs.previous-step-outcome }}

View File

@@ -1,52 +1,55 @@
# Metabase Developer Assistant Instructions
## Frontend Development
For detailed coding standards and conventions, see `CLAUDE.md` and the skills in `.claude/skills/`.
### Repository Structure
## Code Review Standards
```
frontend/src/
├── metabase/ # Main application components and pages
├── metabase-lib/ # Query building and data modeling utilities
├── metabase-types/ # TypeScript type definitions
└── metabase/ui/ # Design system components
Review focus areas: Security → Performance → Testing → Documentation (in priority order)
e2e/ # Cypress end-to-end tests
frontend/test/ # Jest unit tests
```
When reviewing code, use these emoji prefixes to categorize feedback:
- 🔒 Security concerns
- ⚡ Performance opportunities
- 🧹 Cleanup needs
- 📚 Documentation gaps
- 🚨 Blocking issues
- 💭 Clarification questions
### Technology Stack
### Security Critical Issues
- **Framework**: React 18 with TypeScript
- **State**: Redux Toolkit
- **Styling**: CSS Modules (preferred) > Emotion styled-components
- **UI**: `metabase/ui` components built with Mantine v8
- **Build**: Rspack (primary), Webpack (legacy)
- **Testing**: Jest + React Testing Library, Cypress
- Check for hardcoded secrets, API keys, or credentials
- Look for SQL injection and XSS vulnerabilities
- Verify proper input validation and sanitization
- Review authentication and authorization logic
- Ensure enterprise features use the plugin system (no enterprise code in OSS)
### Coding Standards
### Performance Red Flags
#### Component Preferences
- Identify N+1 database query problems
- Spot inefficient loops and algorithmic issues
- Check for memory leaks and resource cleanup
- Review caching opportunities for expensive operations
- Prefer `metabase/ui`components over `metabase/common/components`
- Use `.tsx` for components, `.ts` for utilities
### Code Quality Essentials
#### Styling
- Functions should be focused and appropriately sized
- Use clear, descriptive naming conventions
- Ensure proper error handling throughout
- Remove dead code and unused imports
ALWAYS prefer Mantine style props,then CSS modules. DO NOT suggest styled components, they are deprecated.
### Review Style
#### TypeScript Migration
- Only flag actual issues worth mentioning
- Do not post "looks good" comments or congratulate following conventions
- Be specific and actionable in feedback
- Explain the "why" behind recommendations
- Ask clarifying questions when code intent is unclear
When heavily editing `.js`/`.jsx` files, create a separate PR to convert to TypeScript first, then implement changes.
### Review Format
#### Enterprise Features
- Condense feedback into as few comments as possible
- Prefer a single summary comment over dozens of inline comments
- Only use inline comments for critical issues that require immediate attention
- For non-critical issues, link to the specific line from the summary instead
- Delete all stale comments and summaries on each new push or CI run
Enterprise functionality MUST use the plugin system. It is very important to not expose enterprise code in the OSS version.
#### Testing Requirements
All PRs should include tests. Prefer Unit tests over E2E tests.
#### Localization
All user-facing strings MUST be localized using the ttag library. Localized strings should be complete phrases, do not concatenate a few separately localized strings. You should add context to strings where the meaning of the string might not be obvious in isolation: e.g. "Home" might have different words in some languages depending on whether you're talking about a dwelling or the landing page for a website.
Language-specific rules are in `.github/instructions/*.instructions.md`.

View File

@@ -26,7 +26,7 @@ frontend_ci: &frontend_ci
- ".github/workflows/frontend.yml"
frontend_configs: &frontend_configs
- "yarn.lock"
- "bun.lock"
- "**/tsconfig*.json"
- "package.json"
- "babel.config.json"
@@ -85,7 +85,9 @@ backend_ci: &backend_ci
backend_presto_kerberos:
- "**/presto_jdbc/**"
- "**/presto-jdbc/**" # the driver module has a hyphen. underscores are classpaths
- "**/presto_jdbc.clj"
- "**/presto_jdbc_test.clj"
- ".github/workflows/presto-kerberos-integration-test.yml"
backend_sources: &backend_sources
@@ -197,3 +199,15 @@ cljs:
- *shared_specs
- ".github/workflows/cljs.yml"
- "shadow-cljs.edn"
openapi:
- ".github/workflows/openapi.yml"
- "src/metabase/api/**"
- "src/metabase/api_routes/**"
- "src/metabase/*_rest/api.clj"
- "src/metabase/*/api.clj"
- "src/metabase/*/api/*.clj"
- "enterprise/backend/src/metabase_enterprise/**/api.clj"
- "enterprise/backend/src/metabase_enterprise/**/api/*.clj"
- "resources/openapi/**"
- "package.json"

View File

@@ -0,0 +1,9 @@
---
applyTo: "**/*.{clj,cljs,cljc}"
---
# Clojure/ClojureScript Code Review
When reviewing Clojure or ClojureScript code, apply the guidelines in these files:
- `.claude/skills/_shared/clojure-style-guide.md`
- `.claude/skills/clojure-review/SKILL.md`

View File

@@ -0,0 +1,9 @@
---
applyTo: "docs/**/*.md"
---
# Documentation Review
When reviewing documentation, apply the guidelines in these files:
- `.claude/skills/_shared/metabase-style-guide.md`
- `.claude/skills/docs-review/SKILL.md`

View File

@@ -0,0 +1,11 @@
---
applyTo: "**/*.{ts,tsx,js,jsx}"
---
# TypeScript/JavaScript Code Review
When reviewing TypeScript or JavaScript code, apply the guidelines in these files:
- `.claude/skills/typescript-review/SKILL.md`
- `docs/developers-guide/frontend.md`
- `frontend/CLAUDE.md`

41
.github/scripts/csv-to-mb.js vendored Normal file
View File

@@ -0,0 +1,41 @@
/**
* jsonData must be in the format:
* [
* { column1: value1, column2: value2, ... },
* { column1: value3, column2: value4, ... },
* ...
* ]
*/
function jsonToCsvFormData(jsonData) {
const formData = new FormData();
const csvHeader = Object.keys(jsonData[0]).join(',') + '\n';
const csvContent = jsonData.map(row =>
Object.values(row).map(value => `"${String(value).replace(/"/g, '""')}"`).join(',')
).join('\n');
const blob = new Blob([csvHeader + csvContent], { type: 'text/csv' });
formData.append('file', blob, 'data.csv');
return formData;
}
function uploadCsvToMb({ baseUrl, tableId, jsonData, mode = 'append' }) {
const formData = jsonToCsvFormData(jsonData);
const operation = mode === 'replace' ? 'replace-csv' : 'append-csv';
return fetch(`${baseUrl}/api/table/${tableId}/${operation}`, {
method: 'POST',
headers: {
"x-api-key": process.env.API_KEY
},
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error(`Upload failed`);
}
return { success: true };
});
}
module.exports = { uploadCsvToMb };

40
.github/scripts/find-linear-issue.js vendored Normal file
View File

@@ -0,0 +1,40 @@
async function findLinearIssue({ githubIssueUrl, linearApiKey }) {
const response = await fetch("https://api.linear.app/graphql", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: linearApiKey,
},
body: JSON.stringify({
query: `
query {
attachmentsForURL(url: "${githubIssueUrl}") {
nodes {
issue { identifier }
}
}
}
`,
}),
});
const data = await response.json();
if (!response.ok) {
return { success: false, message: `Linear API error: ${response.status}` };
}
if (!data.data?.attachmentsForURL?.nodes?.length) {
return {
success: false,
message: `No Linear issue linked to ${githubIssueUrl}`,
};
}
return {
success: true,
issue: data.data.attachmentsForURL.nodes[0].issue.identifier,
};
}
module.exports = { findLinearIssue };

View File

@@ -1,317 +0,0 @@
const fs = require("fs");
const path = require("path");
const REPO = "metabase/metabase";
const OUTPUT_FILE = "llms.txt";
// Sections to generate llms-<name>-full.txt for.
// Each section can define a preamble (introductory content before the main docs).
const LLMS_FULL_TO_GENERATE = [
{
section: "embedding",
getPreamble: (branch) =>
aboveVersion(branch, 57) ? getModularEmbeddingGotchaNotes() : "",
},
];
/**
* List directory recursively to get markdown files
*
* @param {string} docsPath - full path to docs directory
* @returns {Array} list of markdown file objects with fullPath and relativePath
*/
function getMarkdownFilesList(docsPath) {
if (!fs.existsSync(docsPath)) {
console.error(`Error: Docs directory '${docsPath}' does not exist`);
process.exit(1);
}
const entries = fs.readdirSync(docsPath, {
recursive: true,
withFileTypes: true,
});
return entries
.filter((entry) => {
return (
entry.isFile() &&
// Only markdown files
entry.name.endsWith(".md") &&
// Ignore README.md
entry.name !== "README.md" &&
// Ignore node_modules and hidden directories
!entry.parentPath
.split(path.sep)
.some((dir) => dir === "node_modules" || dir.startsWith("."))
);
})
.map((entry) => {
const fullPath = path
.join(entry.parentPath, entry.name)
.replace(/\\/g, "/");
const relativePath = path
.relative(docsPath, fullPath)
.replace(/\\/g, "/");
return { fullPath, relativePath };
});
}
/**
* Generate llms.txt file with links to all markdown files in docs/
*
* @param {string} branch - branch name (e.g. 'master' or 'release-x.58.x')
* @param {Array} files - list of all markdown file objects
* @param {Array<Object>} sectionsConfig - list of section config objects to generate complete references for
*/
function generateLlmsTxt(branch, files, sectionsConfig) {
const baseUrl = `https://raw.githubusercontent.com/${REPO}/refs/heads/${branch}`;
const filesToExtract = files
// Files in embedding/sdk/api/snippets does not exist in the repo.
.filter(
(file) => !file.relativePath.startsWith("embedding/sdk/api/snippets"),
);
const entries = filesToExtract.map((file) => {
const content = fs.readFileSync(file.fullPath, "utf8");
const title = extractTitle(content, file.relativePath);
const url = `${baseUrl}/docs/${file.relativePath}`;
return { title, url, path: file.relativePath };
});
// Generate table of contents entries
const tableOfContents = entries.map(
(entry) => `- [${entry.title}](${entry.url})`,
);
// Generate complete references entries
const completeReferences = sectionsConfig
.filter((config) =>
files.some((file) => file.relativePath.startsWith(`${config.section}/`)),
)
.map((config) => {
const capitalized =
config.section.charAt(0).toUpperCase() + config.section.slice(1);
return `- [${capitalized} - Complete Reference](${baseUrl}/llms-${config.section}-full.txt)`;
});
// Generate llms.txt content using template literal
const content = `# Metabase Documentation
Metabase - The simplest, fastest way to get business intelligence and analytics to everyone in your company.
## Table of Contents
${tableOfContents.join("\n")}
## Complete References
These files are very large and are around 90,000 tokens. Do not use by default unless the context window is huge or RAG is supported in your editor.
${completeReferences.join("\n")}
`;
fs.writeFileSync(OUTPUT_FILE, content, "utf8");
console.log(
`✅ Generated ${OUTPUT_FILE} with ${entries.length} markdown files`,
);
console.log(` Branch: ${branch}`);
console.log(` Base URL: ${baseUrl}`);
}
/**
* Generate llms-full.txt files for specified sections
*
* @param {string} branch - branch name (e.g., 'master', 'release-x.58.x')
* @param {Array} files - list of all markdown file objects
* @param {Array<Object>} sectionsConfig - list of section config objects to generate full files for
*/
function generateLlmsFullFiles(branch, files, sectionsConfig) {
const baseUrl = `https://raw.githubusercontent.com/${REPO}/refs/heads/${branch}`;
sectionsConfig.forEach((config) => {
generateLlmsFullTxt(branch, config, files, baseUrl);
});
}
/**
* LLMs are likely to pay attention to the very first lines.
*
* We add the most important context for LLMs to avoid
* confusion and pitfalls like out-of-date APIs in trained data.
*
* @returns {string} Markdown formatted gotcha notes
*/
function getModularEmbeddingGotchaNotes() {
return `> **Important Version Notes**
>
> Watch out for these deprecated props and gotchas for Metabase 57 onwards, for modular embedding:
>
> 1. \`config\` prop on MetabaseProvider no longer exist - it is replaced by \`authConfig\`.
> 2. \`authProviderUri\` field no longer exist.
> 3. \`jwtProviderUri\` optional field only exists in v58+. This is used to make JWT auth faster by skipping the \`GET /auth/sso\` discovery request. Not needed for initial implementation.
> 4. \`fetchRequestToken\` is not needed by default. This is only used to customize how the SDK fetches the request token.
> 5. Numeric IDs must be integers not strings, e.g. \`dashboardId={1}\`. When the ID is retrieved from the URL and it is numeric, convert it to an integer via \`parseInt\` before passing it to the SDK. IDs can also be strings for entity ids, so you should not parse all IDs as numbers if entity ids are also to be expected.
`;
}
/**
* Generate llms-full.txt file for a specific section
* @param {string} branch - The branch name
* @param {Object} config - Section config object with section name and optional getPreamble function
* @param {Array} files - Array of all markdown file objects
* @param {string} baseUrl - Base URL for raw GitHub links
*/
function generateLlmsFullTxt(branch, config, files, baseUrl) {
const { section, getPreamble } = config;
// Filter docs for this section
const sectionFiles = files.filter((file) =>
file.relativePath.startsWith(`${section}/`),
);
if (sectionFiles.length === 0) {
console.log(` Skipping llms-full.txt for ${section} (no files found)`);
return;
}
// Build content
const sectionCapitalized = section.charAt(0).toUpperCase() + section.slice(1);
const header = `# Metabase ${sectionCapitalized} - Complete Reference for AI agents
> Table of contents: ${baseUrl}/${OUTPUT_FILE}
`;
// Add preamble if provided (e.g., version-specific notes, warnings)
const preamble = getPreamble ? getPreamble(branch) : "";
// Concatenate all documents
const docs = sectionFiles
.map((file) => readAndCleanMarkdown(file.fullPath))
.join("\n");
// Write llms-full.txt file at repo root
const content = header + preamble + "\n" + docs;
const llmsFullPath = `llms-${section}-full.txt`;
fs.writeFileSync(llmsFullPath, content, "utf8");
console.log(
`✅ Generated ${llmsFullPath} with ${sectionFiles.length} documents`,
);
}
/**
* Extract title from markdown file frontmatter or filename.
*
* We try to extract the title in this order: 1) YAML frontmatter
* 2) first H1 heading, and 3) the Markdown file name.
*
* Example Markdown and frontmatter format:
* ```markdown
* ---
* title: "Getting Started"
* description: "A guide"
* ---
* # Getting Started
* ```
*
* @param {string} content - file content
* @param {string} filePath - relative file path
* @returns {string} title of content
*/
function extractTitle(content, filePath) {
// Try to extract title from YAML frontmatter
// First, match against the YAML frontmatter delimiter `---`
const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---\s*\n/);
if (frontmatterMatch) {
// Then, match against the title property
// Example: `title: "My Page"`
const frontmatter = frontmatterMatch[1];
const titleMatch = frontmatter.match(/^title:\s*(.+)$/m);
// Remove quotes if present
if (titleMatch) {
return titleMatch[1].trim().replace(/^["']|["']$/g, "");
}
}
// Try to extract title from first H1 heading
// Example: `# My Page`
const h1Match = content.match(/^#\s+(.+)$/m);
if (h1Match) {
return h1Match[1].trim();
}
// Fallback to filename, e.g. `my-page.md`
const filename = path.basename(filePath, ".md");
// Convert kebab-case or snake_case to Title Case
// `my-page.md` would become "My Page"
return filename
.split(/[-_]/)
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
.join(" ");
}
/**
* Read and clean markdown file content
*
* @param {string} filePath - full path to the markdown file
* @returns {string} cleaned markdown content with separator
*/
function readAndCleanMarkdown(filePath) {
let content = fs.readFileSync(filePath, "utf8");
// Strip YAML frontmatter
content = content.replace(/^---\s*\n[\s\S]*?\n---\s*\n/, "");
// Strip Jekyll/Liquid template syntax
content = content.replace(/\{%.*?%\}/g, "");
content = content.replace(/\{\{.*?\}\}/g, "");
return `${content.trim()}\n\n---\n`;
}
/**
* Check if branch version is above target version
* @param {string} branch - Branch name (e.g., 'master', 'release-x.58.x')
* @param {number} targetVersion - Target version number
* @returns {boolean}
*/
function aboveVersion(branch, targetVersion) {
if (branch === "master") {
return true;
}
// Parse version from release branch like "release-x.58.x" -> 58
const match = branch.match(/release-x\.(\d+)\.x/);
if (!match) {
return false;
}
const version = parseInt(match[1], 10);
return version >= targetVersion;
}
// Main execution
if (require.main === module) {
const args = process.argv.slice(2);
const docsPath = args[0] || "docs";
const branch = args[1] || "master";
const resolvedDocsPath = path.resolve(docsPath);
const markdownFiles = getMarkdownFilesList(resolvedDocsPath);
// Sort all files upfront for consistent ordering across all generated files
markdownFiles.sort((a, b) => a.relativePath.localeCompare(b.relativePath));
generateLlmsTxt(branch, markdownFiles, LLMS_FULL_TO_GENERATE);
generateLlmsFullFiles(branch, markdownFiles, LLMS_FULL_TO_GENERATE);
}

28
.github/team.json vendored
View File

@@ -10,14 +10,7 @@
"metamben",
"wzimrin",
"ericnormand",
"galdre"
]
},
{
"name": "Drivers",
"label": ".Team/Drivers",
"members": [
"snoe",
"galdre",
"rileythomp"
]
},
@@ -62,7 +55,8 @@
"tsplude",
"lbrdnk",
"piranha",
"crisptrutski"
"crisptrutski",
"undrfined"
]
},
{
@@ -86,16 +80,12 @@
"eliotmetabase",
"npfitz",
"johnswanson",
"iethree",
"nvoxland",
"edpaget",
"deniskaber",
"alxnddr",
"bpander",
"andsalves",
"gantoreno",
"kevinkelleher12",
"undrfined"
"kevinkelleher12"
]
},
{
@@ -112,6 +102,16 @@
"uladzimirdev",
"egorgrushin"
]
},
{
"name": "Growth Eng",
"label": ".Team/GrowthEng",
"members": [
"iethree",
"bpander",
"gantoreno",
"losrebellos"
]
}
]
}

View File

@@ -15,7 +15,7 @@ jobs:
be-tests-mariadb:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -105,6 +105,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -123,11 +124,12 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-mysql:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -227,6 +229,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -245,11 +248,12 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-postgres:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -336,6 +340,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }} (${{ matrix.job.name }})
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -354,6 +359,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
app-db-tests-result:
needs:

View File

@@ -1,12 +1,33 @@
name: Backend-Cloverage
# Module lists are generated dynamically by listing source directories.
# The setup-oss and setup-ee jobs list folders in src/metabase/ and
# enterprise/backend/src/metabase_enterprise/ respectively, convert
# underscores to dashes (for Clojure namespace convention), and output
# as JSON arrays for the matrix jobs to consume.
#
# jq flags: -R (raw string input), -s (slurp all lines into one string),
# -c (compact single-line output for GitHub Actions).
on:
workflow_dispatch:
schedule:
- cron: '0 10 * * 1-5' # every weekday at 5am US eastern time
jobs:
setup-oss:
runs-on: ubuntu-22.04
outputs:
modules: ${{ steps.get-modules.outputs.modules }}
steps:
- uses: actions/checkout@v4
- id: get-modules
run: |
modules=$(ls -1d src/metabase/*/ | xargs -n1 basename | tr '_' '-' | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "modules=$modules" >> $GITHUB_OUTPUT
be-linter-cloverage:
needs: setup-oss
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ubuntu-22.04
@@ -14,96 +35,7 @@ jobs:
strategy:
fail-fast: false
matrix:
modules:
- actions
- activity-feed
- analytics
- analyze
- api
- api-keys
- api-routes
- app-db
- appearance
- audit-app
- auth-provider
- batch-processing
- bookmarks
- bug-reporting
- cache
- channel
- classloader
- cloud-migration
- cmd
- collections
- config
- connection-pool
- content-translation
- content-verification
- core
- dashboards
- database-routing
- driver
- driver-api
- eid-translation
- embedding
- events
- formatter
- geojson
- glossary
- graph
- indexed-entities
- internal-stats
- legacy-mbql
- lib
- lib-be
- logger
- login-history
- model-persistence
- models
- native-query-snippets
- notification
- parameters
- permissions
- pivot
- plugins
- premium-features
- product-feedback
- public-sharing
- pulse
- queries
- query-permissions
- query-processor
- remote-sync
- request
- revisions
- sample-data
- search
- secrets
- segments
- server
- session
- settings
- setup
- sso
- startup
- store-api
- sync
- system
- task
- task-history
- testing-api
- tiles
- timeline
- types
- upload
- user-key-value
- users
- util
- version
- view-log
- warehouse-schema
- warehouses
- xrays
modules: ${{ fromJson(needs.setup-oss.outputs.modules) }}
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
@@ -112,7 +44,7 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Build static viz frontend
run: yarn build-static-viz
run: bun run build-static-viz
env:
MB_EDITION: ee
- name: Collect the test coverage
@@ -130,7 +62,19 @@ jobs:
files: ./target/coverage/codecov.json
flags: back-end
setup-ee:
runs-on: ubuntu-22.04
outputs:
modules: ${{ steps.get-modules.outputs.modules }}
steps:
- uses: actions/checkout@v4
- id: get-modules
run: |
modules=$(ls -1d enterprise/backend/src/metabase_enterprise/*/ | xargs -n1 basename | tr '_' '-' | jq -R -s -c 'split("\n") | map(select(length > 0))')
echo "modules=$modules" >> $GITHUB_OUTPUT
be-linter-cloverage-enterprise:
needs: setup-ee
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ubuntu-22.04
@@ -138,53 +82,7 @@ jobs:
strategy:
fail-fast: false
matrix:
modules:
- action-v2
- advanced-config
- advanced-permissions
- ai-entity-analysis
- ai-sql-fixer
- ai-sql-generation
- analytics
- api
- audit-app
- auth-provider
- billing
- bookmarks
- cache
- cloud-add-ons
- comments
- content-translation
- content-verification
- core
- dashboard-subscription-filters
- database-replication
- database-routing
- dependencies
- documents
- email
- embedding-hub
- gsheets
- harbormaster
- impersonation
- internal-stats
- llm
- metabot-v3
- permission-debug
- premium-features
- public-sharing
- remote-sync
- sandbox
- scim
- search
- semantic-search
- serialization
- snippet-collections
- sso
- stale
- transforms
- transforms-python
- upload-management
modules: ${{ fromJson(needs.setup-ee.outputs.modules) }}
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
@@ -193,7 +91,7 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Build static viz frontend
run: yarn build-static-viz
run: bun run build-static-viz
env:
MB_EDITION: ee
- name: Collect the test coverage

View File

@@ -39,7 +39,7 @@ jobs:
be-tests:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -104,7 +104,7 @@ jobs:
with:
java-version: "${{ matrix.java-version }}"
- name: Build static-viz frontend
run: yarn build-static-viz
run: bun run build-static-viz
env:
MB_EDITION: ${{ matrix.job.edition }}
@@ -130,6 +130,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-java-tests.outcome }}
- name: Publish Test Report (JUnit)
uses: dorny/test-reporter@v1

View File

@@ -19,9 +19,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Send build start message
uses: actions/github-script@v7
env:
@@ -79,9 +81,11 @@ jobs:
exit 1
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Version
uses: actions/github-script@v7
id: canonical_version
@@ -121,9 +125,11 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0 # IMPORTANT! to get all the branches
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Branch
uses: actions/github-script@v7
id: release_branch
@@ -135,12 +141,13 @@ jobs:
const releaseBranch = getReleaseBranch(version);
return releaseBranch;
- name: Ensure that the specified commit exists in the ${{ steps.release_branch.outputs.result }} release branch
run: |
run: | # bash
RELEASE_BRANCH=${{ steps.release_branch.outputs.result }}
git checkout $RELEASE_BRANCH
git branch --contains ${{ inputs.commit }} | grep -q $RELEASE_BRANCH \
&& echo "Commit found in correct release branch" \
|| (echo "Commit not found in correct release branch" && exit 1)
git checkout -
get-build-requirements:
runs-on: ubuntu-22.04
@@ -152,9 +159,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get build dependencies
uses: actions/github-script@v7
id: dependencies

View File

@@ -82,7 +82,7 @@ jobs:
# Frontend preparation and caches
# `prepare-frontend` action (1) prepares Node.js and (2) fetches the node_modules cache if it exists.
# It then (3) runs `yarn install --frozen-lockfile --prefer-offline` which ensures the local cache is fully populated.
# It then (3) runs `bun install --frozen-lockfile` which ensures the local cache is fully populated.
# IMPORTANT: Caching node_modules after patches are already applied will break any PR that attempts to either:
# - upgrade a patched library
# - change a patch
@@ -92,31 +92,31 @@ jobs:
with:
apply-patches: "false"
- name: Get yarn cache directory
id: yarn-cache-dir
- name: Get bun cache directory
id: bun-cache
run: |
YARN_CACHE_DIR=$(yarn cache dir)
echo "Yarn cache directory: $YARN_CACHE_DIR"
echo "dir=$YARN_CACHE_DIR" >> $GITHUB_OUTPUT
BUN_CACHE_DIR=$(bun pm cache)
echo "Bun cache directory: $BUN_CACHE_DIR"
echo "dir=$BUN_CACHE_DIR" >> $GITHUB_OUTPUT
- name: Ensure that Cypress executable is ready
run: |
yarn cypress install
yarn cypress cache path
yarn cypress cache list
yarn cypress verify
bun run cypress install
bun run cypress cache path
bun run cypress cache list
bun run cypress verify
shell: bash
# Run Prettier to populate its cache (stored in node_modules/.cache/prettier)
# so it gets saved as part of the node_modules cache below
- name: Run Prettier to populate cache
run: yarn lint-prettier-pure
run: bun run lint-prettier-pure
- name: Update node_modules cache
uses: ./.github/actions/update-cache
with:
path: |
${{ steps.yarn-cache-dir.outputs.dir }}
${{ steps.bun-cache.outputs.dir }}
node_modules
key: ${{ env.NODE_CACHE_KEY }}
@@ -128,10 +128,10 @@ jobs:
# ESLint cache (requires both backend and frontend)
- name: Compile CLJS
run: yarn build-pure:cljs
run: bun run build-pure:cljs
- name: Run ESLint to populate cache
run: yarn lint-eslint-pure
run: bun run lint-eslint-pure
- name: Update eslint cache
uses: ./.github/actions/update-cache

View File

@@ -26,11 +26,13 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
sparse-checkout: |
release
.github
fetch-depth: ${{ env.isNewReleaseBranch == 'false' && 3 || 0 }} # we need the full history to get all the commit messages
ref: master # we want the logic from master, even though we're triggering on a release branch
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- uses: actions/github-script@v7
if: ${{ env.isNewReleaseBranch == 'false' }}
name: Set milestone for single commit

View File

@@ -41,7 +41,7 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Compile CLJS
run: NODE_ENV=development yarn build-pure:cljs
run: NODE_ENV=development bun run build-pure:cljs
- name: Publish to Chromatic
uses: chromaui/action@v10.2.0
env:

View File

@@ -70,6 +70,31 @@ jobs:
core.setFailed(error.message);
}
- name: Find linked Linear issue
id: find_linear
continue-on-error: true
uses: actions/github-script@v7
env:
LINEAR_API_KEY: ${{ secrets.LINEAR_API_KEY }}
ISSUE_NUMBER: ${{ steps.get_issue.outputs.issue_number }}
with:
script: |
const { findLinearIssue } = require('${{ github.workspace }}/.github/scripts/find-linear-issue.js');
const githubIssueUrl = `https://github.com/${context.repo.owner}/${context.repo.repo}/issues/${process.env.ISSUE_NUMBER}`;
const result = await findLinearIssue({
githubIssueUrl,
linearApiKey: process.env.LINEAR_API_KEY
});
if (result.success) {
console.log(`Found Linear issue: ${result.issue}`);
core.setOutput('linear_issue', result.issue);
} else {
console.log(`Could not find Linear issue: ${result.message}`);
}
- name: Set up git configuration
run: |
git config --global user.name "Claude Code[bot]"
@@ -205,6 +230,12 @@ jobs:
mkdir -p .claude-scratchpad
echo "Scratchpad directory created for Claude's temporary verification files"
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Generate GitHub App Token for Claude
uses: actions/create-github-app-token@v1
id: claude-app-token
@@ -219,7 +250,7 @@ jobs:
github_token: ${{ steps.claude-app-token.outputs.token }}
prompt: ${{ env.BUG_FIX_PROMPT }}
claude_args: |
--allowedTools "Bash(yarn test-unit*),Bash(yarn lint-eslint-pure),Bash(./bin/mage*),Bash(clojure*),Bash(find*),Bash(ls*),Bash(grep*),Write,Read,Glob,Grep,Edit,MultiEdit"
--allowedTools "Bash(bun run test-unit*),Bash(bun run lint-eslint-pure),Bash(./bin/mage*),Bash(clojure*),Bash(find*),Bash(ls*),Bash(grep*),Write,Read,Glob,Grep,Edit,MultiEdit"
--disallowedTools "Bash(git commit*),Bash(git push*),Bash(gh*)"
- name: Clean up scratchpad directory
@@ -259,6 +290,7 @@ jobs:
core.setOutput('reviewers', issueCreator);
- name: Create Pull Request
id: create_pr
if: steps.check_changes.outputs.has_changes == 'true'
uses: peter-evans/create-pull-request@v6
with:
@@ -279,6 +311,8 @@ jobs:
body: |
This PR automatically fixes the bug reported in #${{ env.ISSUE_NUMBER }}.
${{ steps.find_linear.outputs.linear_issue && format('Closes {0}', steps.find_linear.outputs.linear_issue) || '' }}
## Bug Report
**Original Issue:** #${{ env.ISSUE_NUMBER }}
**Reporter:** @${{ env.ISSUE_AUTHOR }}
@@ -299,7 +333,6 @@ jobs:
- If issues are found, either fix them or close this PR
---
Closes #${{ env.ISSUE_NUMBER }}
🤖 Generated with [Claude Code](https://claude.ai/code)
@@ -309,6 +342,7 @@ jobs:
automated-fix
ci skip
reviewers: ${{ steps.prepare_reviewers.outputs.reviewers }}
assignees: ${{ github.actor }}
- name: Log existing branch update
if: steps.check_changes.outputs.has_changes == 'true' && env.BRANCH_EXISTS == 'true'

View File

@@ -1,98 +0,0 @@
name: "Claude Code Review"
on:
pull_request:
types:
- closed
- synchronize
- labeled
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-claude-code-review
cancel-in-progress: true
jobs:
review:
if: |
(
github.event.action == 'closed' &&
github.event.pull_request.merged == true
) ||
contains(github.event.pull_request.labels.*.name, 'Claude Code Review')
runs-on: ubuntu-latest
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
# Make sure the value of GITHUB_TOKEN will not be persisted in repo's config
persist-credentials: false
# Apparently comments on specific lines and top-level comments about the PR as a whole are TWO TOTALLY DIFFERENT
# TYPES OF THINGS. So we have to fetch and delete separately.
- name: Delete old Claude PR review comments
env:
GH_TOKEN: ${{ github.token }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number }}
shell: bash
run: |
# Get old comment IDs from the bot
old_line_comment_ids=$(gh api "/repos/$REPO/pulls/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
echo "Deleting line comments: $old_line_comment_ids"
# Delete each comment
for id in $old_line_comment_ids; do
gh api -X DELETE "/repos/$REPO/pulls/comments/$id"
echo "Deleted line comment $id"
done
# Get old top-level comment IDs (technically "issue" comments on the PR?)
old_top_level_comment_ids=$(gh api "/repos/$REPO/issues/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
echo "Deleting top-level comments: $old_top_level_comment_ids"
# Delete each comment
for id in $old_top_level_comment_ids; do
gh api -X DELETE "/repos/$REPO/issues/comments/$id"
echo "Deleted top-level comment $id"
done
- name: Generate GitHub App Token for Claude
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
permission-contents: read # Required for reading repository files and PR diffs
permission-pull-requests: write # Required for creating inline comments and PR comments
- name: Fetch Community Clojure Style Guide
run: >-
curl https://raw.githubusercontent.com/bbatsov/clojure-style-guide/refs/heads/master/README.adoc -o CLOJURE_STYLE_GUIDE.adoc
- uses: anthropics/claude-code-action@v1
timeout-minutes: 10
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number }}
Review this pull request for compliance with project coding standards and conventions.
**Use the appropriate review skill based on the file types changed:**
- Use clojure-review for Clojure/ClojureScript files
- Use typescript-review for TypeScript/JavaScript files
- Follow the review guidelines and checklists in each skill
DO NOT post any comments confirming that something is correct - only post comments for style violations or concerns.
Note: The PR branch is already checked out in the current working directory.
Use `gh pr comment` for top-level feedback.
Use `mcp__github_inline_comment__create_inline_comment` to highlight specific code issues.
Only post GitHub comments - don't submit review text as messages.
claude_args: |
--allowedTools "mcp__github_inline_comment__create_inline_comment,Bash(gh pr comment:*),Bash(gh pr diff:*),Bash(gh pr view:*),ReadFile(CLOJURE_STYLE_GUIDE.adoc)"

View File

@@ -1,103 +0,0 @@
name: "Claude Docs Review"
on:
pull_request:
types:
- opened
- synchronize
- reopened
paths:
- 'docs/**/*.md'
- 'docs/**/*.mdx'
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to review'
required: true
type: number
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}-claude-docs-review
cancel-in-progress: true
jobs:
review:
runs-on: ubuntu-latest
if: github.event.pull_request.draft == false
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 1
# Make sure the value of GITHUB_TOKEN will not be persisted in repo's config
persist-credentials: false
- name: Generate GitHub App Token for Claude
uses: actions/create-github-app-token@v1
id: claude-app-token
with:
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
permission-contents: read # Required for reading repository files and PR diffs
permission-pull-requests: write # Required for creating inline comments and PR comments
- name: Delete old Claude docs review comments
env:
GH_TOKEN: ${{ steps.claude-app-token.outputs.token }}
REPO: ${{ github.repository }}
PR_NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
shell: bash
run: |
# Delete pending reviews first (these can be deleted entirely)
pending_review_ids=$(gh api "/repos/$REPO/pulls/$PR_NUMBER/reviews" --jq '.[] | select(.user.login=="metabase-bot[bot]" and .state=="PENDING") | .id')
if [ -n "$pending_review_ids" ]; then
echo "Deleting pending reviews: $pending_review_ids"
for id in $pending_review_ids; do
gh api -X DELETE "/repos/$REPO/pulls/$PR_NUMBER/reviews/$id"
echo "Deleted pending review $id"
done
fi
# Delete individual inline comments from submitted reviews (can't delete the review itself)
old_line_comment_ids=$(gh api "/repos/$REPO/pulls/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
if [ -n "$old_line_comment_ids" ]; then
echo "Deleting line comments: $old_line_comment_ids"
for id in $old_line_comment_ids; do
gh api -X DELETE "/repos/$REPO/pulls/comments/$id"
echo "Deleted line comment $id"
done
fi
# Delete top-level review comments
old_top_level_comment_ids=$(gh api "/repos/$REPO/issues/$PR_NUMBER/comments" --jq '.[] | select(.user.login=="metabase-bot[bot]") | .id')
if [ -n "$old_top_level_comment_ids" ]; then
echo "Deleting top-level comments: $old_top_level_comment_ids"
for id in $old_top_level_comment_ids; do
gh api -X DELETE "/repos/$REPO/issues/comments/$id"
echo "Deleted top-level comment $id"
done
fi
- uses: anthropics/claude-code-action@v1
timeout-minutes: 10
with:
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
github_token: ${{ steps.claude-app-token.outputs.token }}
show_full_output: true
prompt: |
REPO: ${{ github.repository }}
PR NUMBER: ${{ github.event.pull_request.number || github.event.inputs.pr_number }}
Review the documentation changes in this pull request.
Use the docs-review skill to review all changed documentation files for compliance with the Metabase writing style guide.
IMPORTANT: Only review markdown files (.md and .mdx). Skip any .txt files or other non-markdown files.
DO NOT post any comments confirming that something is correct - only post comments for style violations or concerns.
claude_args: |
--allowedTools "Skill,mcp__github__get_pull_request,mcp__github__get_pull_request_files,mcp__github__create_pending_pull_request_review,mcp__github__get_pull_request_diff,mcp__github__add_comment_to_pending_review,mcp__github__add_pull_request_review_comment_to_pending_review,mcp__github__delete_pending_pull_request_review,mcp__github__submit_pending_pull_request_review"

View File

@@ -1,33 +0,0 @@
name: Cleanup caches by a branch
on:
pull_request:
types:
- closed
jobs:
cleanup:
runs-on: ubuntu-22.04
steps:
- name: Check out code
uses: actions/checkout@v4
- name: Cleanup
run: |
gh extension install actions/gh-actions-cache
REPO=${{ github.repository }}
BRANCH="refs/pull/${{ github.event.pull_request.number }}/merge"
echo "Fetching list of cache key"
cacheKeysForPR=$(gh actions-cache list -R $REPO -B $BRANCH | cut -f 1 )
## Setting this to not fail the workflow while deleting cache keys.
set +e
echo "Deleting caches..."
for cacheKey in $cacheKeysForPR
do
gh actions-cache delete $cacheKey -R $REPO -B $BRANCH --confirm
done
echo "Done"
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -39,4 +39,4 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Run Cljs tests
run: yarn run test-cljs
run: bun run test-cljs

View File

@@ -4,8 +4,10 @@ run-name: Containerize ${{ inputs.tag }} Uberjar
on:
workflow_call:
inputs:
artifact-name:
edition:
description: Metabase edition (ee or oss)
type: string
required: true
repo:
description: owner and repo like "metabase/metabase"
type: string
@@ -15,14 +17,18 @@ on:
type: string
release:
type: string
default: 'true'
default: 'false'
build-args:
type: string
workflow_dispatch:
inputs:
artifact-name:
description: usually something like "metabase-release-{{ edition }}-{{ hash }}-uberjar"
type: string
edition:
description: Metabase edition (ee or oss)
type: choice
options:
- ee
- oss
required: true
repo:
description: docker owner and repo like "metabase/metabase"
type: string
@@ -32,6 +38,13 @@ on:
commit:
description: the full commit hash
type: string
release:
description: Whether this is a release artifact (uses metabase-release- prefix)
type: choice
options:
- "false"
- "true"
default: "false"
jobs:
containerize:
@@ -45,12 +58,14 @@ jobs:
fetch-depth: 0
# we want the dockerfile from the commit we're building
- run: git checkout ${{ inputs.commit }} -- bin/docker
- name: Retrieve test build uberjar artifact
- name: Retrieve uberjar artifact
uses: ./.github/actions/fetch-artifact
with:
name: ${{ inputs.artifact-name }}
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
commit: ${{ inputs.commit }}
edition: ${{ inputs.edition }}
release: ${{ inputs.release }}
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get platforms
id: platforms
uses: actions/github-script@v7

View File

@@ -55,13 +55,13 @@ jobs:
uses: ./.github/workflows/containerize-jar.yml
secrets: inherit
with:
artifact-name: metabase-${{ matrix.edition }}-${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.inputs.commit || github.sha }}
edition: ${{ matrix.edition }}
commit: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
repo: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).repo }}
tag: ${{ fromJson(needs.get-container-info.outputs[matrix.edition]).tag }}
release: "false"
build-args: |
GIT_COMMIT_SHA=${{ github.event.inputs.commit || github.sha }}
GIT_COMMIT_SHA=${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
run-trivy:
needs: [get-container-info, containerize]
@@ -74,7 +74,7 @@ jobs:
- name: Check out the code
uses: actions/checkout@v4
with:
ref: ${{ github.event.inputs.commit || github.sha }}
ref: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
- name: Run Trivy vulnerability scanner
uses: aquasecurity/trivy-action@0.29.0
env:

View File

@@ -17,7 +17,7 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Run frontend unit tests
run: |
yarn run test-unit \
bun run test-unit \
--silent \
--coverage \
--testTimeout=60000

View File

@@ -72,11 +72,14 @@ jobs:
# All decision logic is in mage - it analyzes module dependencies,
# branch context, labels, and file changes to decide what runs.
MAGE_ARGS=(
--git-ref="${{ github.event.pull_request.base.ref || 'master' }}"
--git-ref="${{ github.event.pull_request.base.ref || github.ref_name }}"
--is-master-or-release="${{ github.ref_name == 'master' || startsWith(github.ref_name, 'release-') }}"
--pr-labels="${{ join(github.event.pull_request.labels.*.name, ',') }}"
--skip="${{ inputs.skip }}"
)
echo "Running:"
echo "./bin/mage -driver-decisions ${MAGE_ARGS[@]}"
echo ""
# First call: show human-readable output for debugging
./bin/mage -driver-decisions "${MAGE_ARGS[@]}"
# Second call: output only key=value lines for GITHUB_OUTPUT
@@ -87,7 +90,7 @@ jobs:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.athena-should-run == 'true' || needs.determine-driver-skips.outputs.athena-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: athena
@@ -132,6 +135,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-bigquery-cloud-sdk-ee:
needs: determine-driver-skips
@@ -146,6 +150,7 @@ jobs:
test-args: >-
:only-tags [:mb/driver-tests]
:exclude-tags [:mb/transforms-python-test]
:fail-fast? true
# DS 2025-09-26 temporarily disabled while we diagnose flakes
# - name: Transforms Python Tests
# test-args: >-
@@ -197,6 +202,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: ${{ always() && matrix.job.needs-python-runner == true }}
uses: ./.github/actions/cleanup-python-runner
@@ -208,7 +214,7 @@ jobs:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.clickhouse-should-run == 'true' || needs.determine-driver-skips.outputs.clickhouse-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -279,6 +285,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: ${{ always() && matrix.job.needs-python-runner == true }}
uses: ./.github/actions/cleanup-python-runner
@@ -290,7 +297,7 @@ jobs:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.druid-should-run == 'true' || needs.determine-driver-skips.outputs.druid-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: druid
@@ -333,12 +340,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-druid-jdbc-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.druid-jdbc-should-run == 'true' || needs.determine-driver-skips.outputs.druid-jdbc-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: druid-jdbc
@@ -381,12 +389,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-databricks-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.databricks-should-run == 'true' || needs.determine-driver-skips.outputs.databricks-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: databricks
@@ -429,12 +438,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-databricks-multi-catalog-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.databricks-should-run == 'true' || needs.determine-driver-skips.outputs.databricks-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: databricks
@@ -478,12 +488,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-h2:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.h2-should-run == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
name: H2
@@ -508,12 +519,45 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-h2-oss:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.h2-should-run == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 40
env:
CI: 'true'
name: H2 (OSS)
steps:
- uses: actions/checkout@v4
- name: Test H2 driver (OSS)
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-h2-oss'
edition: 'oss'
test-args: >-
:only-tags [:mb/driver-tests]
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-mysql-mariadb:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mysql-mariadb-should-run == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -638,6 +682,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
@@ -649,7 +694,7 @@ jobs:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mongo-should-run == 'true' || needs.determine-driver-skips.outputs.mongo-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -718,6 +763,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: ${{ always() && matrix.job.needs-python-runner == true }}
uses: ./.github/actions/cleanup-python-runner
@@ -729,7 +775,7 @@ jobs:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mongo-ssl-should-run == 'true' || needs.determine-driver-skips.outputs.mongo-ssl-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -800,12 +846,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-mongo-sharded-cluster-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.mongo-sharded-cluster-should-run == 'true' || needs.determine-driver-skips.outputs.mongo-sharded-cluster-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: mongo
@@ -845,12 +892,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-oracle:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.oracle-should-run == 'true' || needs.determine-driver-skips.outputs.oracle-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -930,12 +978,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-postgres:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.postgres-should-run == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -1019,6 +1068,7 @@ jobs:
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-${{ matrix.version.junit-name }}'
logs-artifact-suffix: ${{ matrix.version.name }}-${{ matrix.job.name }}
test-args: >-
${{ matrix.job.test-args }}
:exclude-tags '[ ${{ matrix.job.exclude-tag }} ${{ env.__ADDITIONAL_EXCLUDED_TAG__ }}]'
@@ -1033,6 +1083,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
@@ -1044,7 +1095,7 @@ jobs:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.presto-jdbc-should-run == 'true' || needs.determine-driver-skips.outputs.presto-jdbc-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: presto-jdbc
@@ -1120,12 +1171,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-redshift-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.redshift-should-run == 'true' || needs.determine-driver-skips.outputs.redshift-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -1204,6 +1256,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: ${{ always() && matrix.job.needs-python-runner == true }}
uses: ./.github/actions/cleanup-python-runner
@@ -1224,6 +1277,7 @@ jobs:
test-args: >-
:only-tags [:mb/driver-tests]
:exclude-tags [:mb/transforms-python-test]
:fail-fast? true
# DS 2025-09-26 temporarily disabled while we diagnose flakes
# - name: Transforms Python Tests
@@ -1285,6 +1339,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: ${{ always() && matrix.job.needs-python-runner == true }}
uses: ./.github/actions/cleanup-python-runner
@@ -1296,7 +1351,7 @@ jobs:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.sparksql-should-run == 'true' || needs.determine-driver-skips.outputs.sparksql-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: sparksql
@@ -1337,12 +1392,13 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-sqlite-ee:
needs: determine-driver-skips
if: ${{ needs.determine-driver-skips.outputs.sqlite-should-run == 'true' || needs.determine-driver-skips.outputs.sqlite-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: sqlite
@@ -1378,6 +1434,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
be-tests-sqlserver:
needs: determine-driver-skips
@@ -1454,6 +1511,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
- name: Cleanup python-runner
if: ${{ always() && matrix.job.needs-python-runner == true }}
uses: ./.github/actions/cleanup-python-runner
@@ -1466,7 +1524,7 @@ jobs:
# needs: determine-driver-skips
# if: ${{ !inputs.skip && !(needs.determine-driver-skips.outputs.skip == 'true') }}
# runs-on: ubuntu-latest
# timeout-minutes: 60
# timeout-minutes: 40
# env:
# CI: 'true'
# DRIVERS: starburst
@@ -1534,7 +1592,7 @@ jobs:
needs: [determine-driver-skips, login-to-ecr]
if: ${{ needs.determine-driver-skips.outputs.vertica-should-run == 'true' || needs.determine-driver-skips.outputs.vertica-quarantine-conflict == 'true' }}
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
DRIVERS: vertica
@@ -1580,6 +1638,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
drivers-tests-result:
needs:

View File

@@ -115,11 +115,15 @@ jobs:
- name: Build Embedding SDK package
if: ${{ needs.determine-test-type.outputs.type == 'component' }}
run: yarn build-embedding-sdk-package
run: bun run build-embedding-sdk-package
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Compile CLJS
run: bun run build-pure:cljs
- name: Run Metabase
run: node e2e/runner/run_cypress_ci.js start

View File

@@ -41,12 +41,13 @@ env:
jobs:
e2e-tests:
runs-on: ${{ inputs.runner }}
timeout-minutes: 45
timeout-minutes: 40
name: e2e-tests-${{ inputs.name }}-${{ inputs.edition }}
env:
MB_EDITION: ${{ inputs.edition }}
# Any env starting with `CYPRESS_` will be available to all Cypress tests via `Cypress.env()`
# Example: you can get `CYPRESS_FOO` with `Cypress.env("FOO")`
# Sensitive env vars (tokens, secrets) starting with `CYPRESS_` are accessed via async `cy.env()`
# Example: `cy.env(["FOO"]).then(({ FOO }) => ...)`
# For non-sensitive config, use `Cypress.expose()` in cypress config instead (synchronous)
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
CYPRESS_MB_STARTER_CLOUD_TOKEN: ${{ secrets.STAGING_MB_STARTER_CLOUD_TOKEN }}
CYPRESS_MB_PRO_CLOUD_TOKEN: ${{ secrets.STAGING_MB_PRO_CLOUD_TOKEN }}
@@ -79,7 +80,8 @@ jobs:
- name: Retrieve uberjar artifact for ${{ inputs.edition }}
uses: ./.github/actions/fetch-artifact
with:
name: metabase-${{ inputs.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.pull_request.head.sha || github.sha }}
edition: ${{ inputs.edition }}
extract-path: "target/uberjar"
output-name: "metabase.jar"
@@ -104,6 +106,9 @@ jobs:
if: github.run_attempt != '1'
run: echo "specs=$(cat failed-specs)" >> $GITHUB_ENV
- name: Compile CLJS
run: bun run build-pure:cljs
- name: Run Metabase
run: node e2e/runner/run_cypress_ci.js start
@@ -167,6 +172,7 @@ jobs:
# Related to Trunk uploader
variant: e2e-tests
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ inputs.specs && steps.tagged-e2e.outcome || steps.split-e2e.outcome }}
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4

View File

@@ -19,8 +19,9 @@ jobs:
react-version: [18, 19]
fail-fast: false
env:
# Any env starting with `CYPRESS_` will be available to all Cypress tests via `Cypress.env()`
# Example: you can get `CYPRESS_FOO` with `Cypress.env("FOO")`
# Sensitive env vars (tokens, secrets) starting with `CYPRESS_` are accessed via async `cy.env()`
# Example: `cy.env(["FOO"]).then(({ FOO }) => ...)`
# For non-sensitive config, use `Cypress.expose()` in cypress config instead (synchronous)
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
CYPRESS_MB_STARTER_CLOUD_TOKEN: ${{ secrets.STAGING_MB_STARTER_CLOUD_TOKEN }}
CYPRESS_MB_PRO_CLOUD_TOKEN: ${{ secrets.STAGING_MB_PRO_CLOUD_TOKEN }}
@@ -45,7 +46,8 @@ jobs:
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.pull_request.head.sha || github.sha }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"
@@ -80,6 +82,7 @@ jobs:
run: ./bin/embedding-sdk/change-react-version.bash ${{ matrix.react-version }}
- name: Run component tests for Embedding SDK
id: run-tests
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js component
@@ -95,6 +98,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-tests.outcome }}
- name: "SDK component tests > Upload Cypress Artifacts upon failure"
uses: actions/upload-artifact@v4
@@ -152,8 +156,9 @@ jobs:
env:
MB_RUN_MODE: "e2e"
METASTORE_DEV_SERVER_URL: ${{ secrets.METASTORE_DEV_SERVER_URL }}
# Any env starting with `CYPRESS_` will be available to all Cypress tests via `Cypress.env()`
# Example: you can get `CYPRESS_FOO` with `Cypress.env("FOO")`
# Sensitive env vars (tokens, secrets) starting with `CYPRESS_` are accessed via async `cy.env()`
# Example: `cy.env(["FOO"]).then(({ FOO }) => ...)`
# For non-sensitive config, use `Cypress.expose()` in cypress config instead (synchronous)
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
CYPRESS_MB_STARTER_CLOUD_TOKEN: ${{ secrets.STAGING_MB_STARTER_CLOUD_TOKEN }}
CYPRESS_MB_PRO_CLOUD_TOKEN: ${{ secrets.STAGING_MB_PRO_CLOUD_TOKEN }}
@@ -194,7 +199,8 @@ jobs:
id: download-uberjar
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ steps.get-commit-sha.outputs.sha }}-uberjar
commit: ${{ steps.get-commit-sha.outputs.sha }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"
continue-on-error: true # do not break the whole job if this step doesn't succeed
@@ -228,6 +234,7 @@ jobs:
--spec "e2e/snapshot-creators/default.cy.snap.js"
- name: Run component tests for Embedding SDK
id: run-tests
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: |
@@ -245,6 +252,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-tests.outcome }}
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4

View File

@@ -9,7 +9,6 @@ env:
TZ: US/Pacific # to make Node match the instance tz
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HASH: ${{ github.event.pull_request.head.sha || github.sha }}-${{ github.run_attempt }}
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
MB_EDITION: ee
jobs:
get-sample-apps-data:
@@ -21,12 +20,7 @@ jobs:
TEST_SUITES: |
[
"metabase-nodejs-react-sdk-embedding-sample-e2e",
"metabase-nextjs-sdk-embedding-sample-e2e",
"shoppy-e2e"
]
TEST_SUITES_TO_RUN_IN_MASTER_ONLY: |
[
"shoppy-e2e"
"metabase-nextjs-sdk-embedding-sample-e2e"
]
SAMPLE_APP_MAIN_BRANCH_NAME: "main"
SAMPLE_APP_STABLE_RELEASE_BRANCH_NAME_SUFFIX: "stable"
@@ -36,8 +30,8 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Build sample app compatibility data
uses: actions/github-script@v7
@@ -50,7 +44,6 @@ jobs:
} = require('${{ github.workspace }}/release/dist/index.cjs');
const testSuites = JSON.parse(process.env.TEST_SUITES);
const testSuitesToRunInMasterOnly = JSON.parse(process.env.TEST_SUITES_TO_RUN_IN_MASTER_ONLY);
const ref = '${{ github.base_ref || github.ref }}';
const branchName = ref.replace(/^refs\/heads\//, '');
@@ -74,19 +67,16 @@ jobs:
const sampleAppBranchName = `${currentBranchVersion}-${{ env.SAMPLE_APP_STABLE_RELEASE_BRANCH_NAME_SUFFIX }}`
const shouldRunTestsForVersion = (currentReleaseVersion - currentBranchVersion) <= (supportedReleasesCount - 1);
const releaseBranchTestSuites = testSuites.filter(testSuite => !testSuitesToRunInMasterOnly.includes(testSuite));
return {
branch_name: sampleAppBranchName,
matrix: shouldRunTestsForVersion
? releaseBranchTestSuites
: []
matrix: shouldRunTestsForVersion ? testSuites : [],
};
}
return {
branch_name: '',
matrix: []
matrix: [],
};
# In order to check compatibility between Sample Apps and Embedding SDK, the job for each sample app:
@@ -137,7 +127,8 @@ jobs:
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.pull_request.head.sha || github.sha }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"
@@ -167,28 +158,8 @@ jobs:
echo "sample_app_branch_exists=false" >> $GITHUB_OUTPUT
fi
- name: Configure AWS credentials
if: ${{ matrix.test_suite == 'shoppy-e2e' }}
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.SHOPPY_IAM_ROLE }}
role-session-name: GitHub_to_AWS_via_FederatedOIDC
aws-region: us-east-1
- name: Download Shoppy's App DB PostgreSQL dump from S3
if: ${{ matrix.test_suite == 'shoppy-e2e' }}
run: |
aws s3 cp s3://${{ secrets.SHOPPY_METABASE_APP_DB_S3_BUCKET }}/${{ secrets.SHOPPY_METABASE_APP_DB_S3_KEY }} ./e2e/tmp/db_dumps/shoppy_metabase_app_db_dump.sql
- name: Prepare and launch Sample Apps for shoppy-e2e test suite
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' && matrix.test_suite == 'shoppy-e2e' }}
env:
METABASE_APP_DB_USER: ${{ secrets.SHOPPY_METABASE_APP_DB_USER }}
METABASE_APP_DB: ${{ secrets.SHOPPY_METABASE_APP_DB_DATABASE }}
run: npx tsx ./e2e/runner/embedding-sdk/sample-apps/start-ci.ts shoppy-e2e
- name: Prepare and launch Sample Apps for other test suites
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' && matrix.test_suite != 'shoppy-e2e' }}
- name: Prepare and launch Sample Apps
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
run: npx tsx ./e2e/runner/embedding-sdk/sample-apps/start-ci.ts ${{ matrix.test_suite }}
- name: Prune build cache
@@ -209,7 +180,7 @@ jobs:
uses: actions/upload-artifact@v4
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' && steps.run-e2e-tests.outcome != 'success' }}
with:
name: cypress-recording-sample-app-${{ matrix.test_suite }}-latest
name: cypress-recording-sample-app-${{ matrix.test_suite }}-${{ matrix.environment }}-latest
path: |
./e2e/tmp/${{ steps.get-sample-app-name.outputs.sample_app_name }}/cypress
if-no-files-found: ignore
@@ -219,6 +190,149 @@ jobs:
run: |
exit 1
# Shoppy e2e tests run separately using the shared composite action for setup.
e2e-shoppy-tests:
needs: [get-sample-apps-data]
strategy:
matrix:
environment: ["production", "development"]
if: |
!cancelled() && needs.get-sample-apps-data.result == 'success' &&
(github.ref == 'refs/heads/master' || github.base_ref == 'master')
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-sample-app-shoppy-e2e-tests-${{ matrix.environment }}-bundle
env:
MB_EDITION: ee
MB_RUN_MODE: e2e
METASTORE_DEV_SERVER_URL: ${{ secrets.METASTORE_DEV_SERVER_URL }}
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
SAMPLE_APP_BRANCH_NAME: ${{ needs.get-sample-apps-data.outputs.branch_name }}
SAMPLE_APP_ENVIRONMENT: ${{ matrix.environment }}
permissions:
id-token: write
steps:
- uses: actions/checkout@v4
- name: Prepare Shoppy E2E environment
uses: ./.github/actions/prepare-shoppy-e2e
id: shoppy-prep
with:
commit: ${{ github.event.pull_request.head.sha || github.sha }}
sample-app-branch-name: ${{ needs.get-sample-apps-data.outputs.branch_name }}
sample-app-environment: ${{ matrix.environment }}
staging-mb-all-features-token: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
shoppy-iam-role: ${{ secrets.SHOPPY_IAM_ROLE }}
shoppy-metabase-app-db-s3-bucket: ${{ secrets.SHOPPY_METABASE_APP_DB_S3_BUCKET }}
shoppy-metabase-app-db-s3-key: ${{ secrets.SHOPPY_METABASE_APP_DB_S3_KEY }}
shoppy-metabase-app-db-user: ${{ secrets.SHOPPY_METABASE_APP_DB_USER }}
shoppy-metabase-app-db-database: ${{ secrets.SHOPPY_METABASE_APP_DB_DATABASE }}
metastore-dev-server-url: ${{ secrets.METASTORE_DEV_SERVER_URL }}
shoppy-datadog-application-id: ${{ secrets.SHOPPY_METABASE_APP_DATADOG_APPLICATION_ID }}
shoppy-datadog-client-token: ${{ secrets.SHOPPY_METABASE_APP_DATADOG_CLIENT_TOKEN }}
- name: Run e2e tests for Shoppy
id: run-e2e-tests
if: ${{ steps.shoppy-prep.outputs.sample_app_branch_exists == 'true' }}
continue-on-error: true
env:
CYPRESS_BROWSER: ${{ steps.shoppy-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js shoppy-e2e
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: ${{ steps.shoppy-prep.outputs.sample_app_branch_exists == 'true' && steps.run-e2e-tests.outcome != 'success' }}
with:
name: cypress-recording-sample-app-shoppy-e2e-${{ matrix.environment }}-latest
path: |
./e2e/tmp/shoppy/cypress
if-no-files-found: ignore
- name: Fail job if tests failed
if: ${{ steps.shoppy-prep.outputs.sample_app_branch_exists == 'true' && steps.run-e2e-tests.outcome != 'success' }}
run: |
exit 1
# Synthetic monitoring tests run only on master merges, in parallel with the regular e2e tests.
# They use the shoppy production environment and include performance measurement tests.
e2e-shoppy-synthetic-tests:
needs: [get-sample-apps-data]
if: |
!cancelled() && needs.get-sample-apps-data.result == 'success' &&
github.event_name == 'push' &&
github.ref == 'refs/heads/master'
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-shoppy-synthetic-monitoring-tests
env:
MB_EDITION: ee
MB_RUN_MODE: e2e
METASTORE_DEV_SERVER_URL: ${{ secrets.METASTORE_DEV_SERVER_URL }}
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
SAMPLE_APP_BRANCH_NAME: ${{ needs.get-sample-apps-data.outputs.branch_name }}
SAMPLE_APP_ENVIRONMENT: production
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v4
- name: Prepare Shoppy E2E environment
uses: ./.github/actions/prepare-shoppy-e2e
id: shoppy-prep
with:
commit: ${{ github.event.pull_request.head.sha || github.sha }}
sample-app-branch-name: ${{ needs.get-sample-apps-data.outputs.branch_name }}
sample-app-environment: production
staging-mb-all-features-token: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
shoppy-iam-role: ${{ secrets.SHOPPY_IAM_ROLE }}
shoppy-metabase-app-db-s3-bucket: ${{ secrets.SHOPPY_METABASE_APP_DB_S3_BUCKET }}
shoppy-metabase-app-db-s3-key: ${{ secrets.SHOPPY_METABASE_APP_DB_S3_KEY }}
shoppy-metabase-app-db-user: ${{ secrets.SHOPPY_METABASE_APP_DB_USER }}
shoppy-metabase-app-db-database: ${{ secrets.SHOPPY_METABASE_APP_DB_DATABASE }}
metastore-dev-server-url: ${{ secrets.METASTORE_DEV_SERVER_URL }}
shoppy-datadog-application-id: ${{ secrets.SHOPPY_METABASE_APP_DATADOG_APPLICATION_ID }}
shoppy-datadog-client-token: ${{ secrets.SHOPPY_METABASE_APP_DATADOG_CLIENT_TOKEN }}
- name: Get merged PR number
if: ${{ steps.shoppy-prep.outputs.sample_app_branch_exists == 'true' }}
id: get-merged-pr-number
run: |
PR=$(gh api repos/${{ github.repository }}/commits/${{ github.sha }}/pulls --jq '.[0].number' 2>/dev/null || echo "")
if [ -z "$PR" ] || [ "$PR" = "null" ]; then
echo "number=" >> "$GITHUB_OUTPUT"
else
echo "number=$PR" >> "$GITHUB_OUTPUT"
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Run synthetic monitoring tests
id: run-e2e-tests
if: ${{ steps.shoppy-prep.outputs.sample_app_branch_exists == 'true' }}
continue-on-error: true
env:
CYPRESS_BROWSER: ${{ steps.shoppy-prep.outputs.chrome-path }}
PR_NUMBER: ${{ steps.get-merged-pr-number.outputs.number }}
INCLUDE_SYNTHETIC_MONITORING_TESTS: "true"
run: node e2e/runner/run_cypress_ci.js shoppy-e2e
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: ${{ steps.shoppy-prep.outputs.sample_app_branch_exists == 'true' && steps.run-e2e-tests.outcome != 'success' }}
with:
name: cypress-recording-shoppy-synthetic-tests-latest
path: |
./e2e/tmp/shoppy/cypress
if-no-files-found: ignore
- name: Fail job if tests failed
if: ${{ steps.shoppy-prep.outputs.sample_app_branch_exists == 'true' && steps.run-e2e-tests.outcome != 'success' }}
run: |
exit 1
# The job checks integration of the Embedding SDK with consumer's apps that use different frameworks/bundlers,
# or when we want to test some tricky integration cases like conflicting types.
# The job
@@ -252,7 +366,8 @@ jobs:
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.pull_request.head.sha || github.sha }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"

View File

@@ -23,7 +23,7 @@ jobs:
# Remove the matchers to not report false positives on every PR
# unrelated to embedding (EMB-765)
echo "::remove-matcher owner=tsc::"
yarn build-embedding-sdk-package
bun run build-embedding-sdk-package
- name: Prepare Embedding SDK artifact
uses: actions/upload-artifact@v4
with:

View File

@@ -23,6 +23,10 @@ on:
description: "Whether to run host and sample apps compatibility tests."
required: true
type: boolean
bundle-size-check:
description: "Whether to run bundle size check."
required: true
type: boolean
skip:
description: Whether to skip running tests due to one of the artifacts failing to build.
required: true
@@ -47,7 +51,7 @@ jobs:
name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Run frontend embedding SDK snippets type check
run: yarn run embedding-sdk:cli-snippets:type-check
run: bun run embedding-sdk:cli-snippets:type-check
embedding-sdk-docs-snippets-type-check:
if: inputs.docs-snippets-type-check && !inputs.skip
@@ -63,7 +67,7 @@ jobs:
name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Run frontend embedding SDK snippets type check
run: yarn run embedding-sdk:docs-snippets:type-check
run: bun run embedding-sdk:docs-snippets:type-check
embedding-sdk-api-documentation-generation-validation:
if: inputs.documentation-validation && !inputs.skip
@@ -86,7 +90,7 @@ jobs:
shell: bash
run: |
set -o pipefail
yarn embedding-sdk:docs:generate:pure --emit none 2>&1 \
bun run embedding-sdk:docs:generate:pure --emit none 2>&1 \
| tee /dev/stdout \
| tee >( tail -n 10 \
| sed '1s/^/output<<EOF\n/' \
@@ -98,14 +102,14 @@ jobs:
with:
remove-previous-comment: true
add-new-comment: ${{ steps.docs-generation.outcome == 'failure' && contains(steps.docs-generation.outputs.output, 'not included in the documentation') }}
message: "📝 Some exported types from `@metabase/embedding-sdk-react` reference other types that are not exported, i.e. internal types.<br><br>The internal type reference breaks API documentation generation for the SDK and also may unexpectedly increase the output size of the type declaration file.<br><br>Please check the CI logs to find the name of such type.<br><br>- If a type should be publicly available in the SDK, add a description to it or a TypeDoc annotation and export it from SDK.<br>- If a type is internal and should _not_ be publicly exposed, refactor types to prevent referencing other types that are not exported from SDK.<br><br>You can run `yarn embedding-sdk:docs:generate` locally to verify that the issue has been resolved."
message: "📝 Some exported types from `@metabase/embedding-sdk-react` reference other types that are not exported, i.e. internal types.<br><br>The internal type reference breaks API documentation generation for the SDK and also may unexpectedly increase the output size of the type declaration file.<br><br>Please check the CI logs to find the name of such type.<br><br>- If a type should be publicly available in the SDK, add a description to it or a TypeDoc annotation and export it from SDK.<br>- If a type is internal and should _not_ be publicly exposed, refactor types to prevent referencing other types that are not exported from SDK.<br><br>You can run `bun run embedding-sdk:docs:generate` locally to verify that the issue has been resolved."
include-log: true
- name: Comment on PR if 'Failed to resolve link' error happens
uses: ./.github/actions/notify-pull-request
with:
remove-previous-comment: true
add-new-comment: ${{ steps.docs-generation.outcome == 'failure' && contains(steps.docs-generation.outputs.output, 'Failed to resolve link') }}
message: "📝 A typedoc `{@link <TYPE_NAME>}` annotation is found that can't be resolved.<br><br>Most likely it happens when the referenced type is not exported. Please check the CI logs to find the name of such type.<br><br>- If a referenced in `{@link}` type should be publicly available in the SDK, add a description to it or a TypeDoc annotation and export it from SDK.<br>- If a type is internal and should _not_ be publicly exposed, change types to prevent unexported type reference in `{@link}` annotation.<br><br>You can run `yarn embedding-sdk:docs:generate` locally to verify that the issue has been resolved."
message: "📝 A typedoc `{@link <TYPE_NAME>}` annotation is found that can't be resolved.<br><br>Most likely it happens when the referenced type is not exported. Please check the CI logs to find the name of such type.<br><br>- If a referenced in `{@link}` type should be publicly available in the SDK, add a description to it or a TypeDoc annotation and export it from SDK.<br>- If a type is internal and should _not_ be publicly exposed, change types to prevent unexported type reference in `{@link}` annotation.<br><br>You can run `bun run embedding-sdk:docs:generate` locally to verify that the issue has been resolved."
include-log: true
- name: Fail Job
if: ${{ steps.docs-generation.outcome == 'failure' }}
@@ -124,8 +128,52 @@ jobs:
uses: ./.github/workflows/embedding-sdk-host-sample-apps-tests.yml
secrets: inherit
embedding-sdk-bundle-size-check:
if: inputs.bundle-size-check
continue-on-error: true
runs-on: ubuntu-22.04
timeout-minutes: 20
env:
BUNDLE_SIZE_THRESHOLD_PERCENT: 2
steps:
- uses: actions/checkout@v4
- uses: ./.github/actions/sdk-bundle-size-check
id: compare
with:
edition: ee
base-ref-commit: ${{ github.event.pull_request.base.sha }}
threshold-percent: ${{ env.BUNDLE_SIZE_THRESHOLD_PERCENT }}
- name: Comment on PR if bundle size has increased
uses: ./.github/actions/notify-pull-request
if: success() && steps.compare.outputs.status == 'increased'
with:
remove-previous-comment: true
add-new-comment: true
message: "⚠️ Embedding SDK bundle size increased by ${{ steps.compare.outputs.size_change_percent }}% compared to the ${{ github.base_ref }} branch (threshold: ${{ env.BUNDLE_SIZE_THRESHOLD_PERCENT }}%). Please contact Embedding team."
include-log: false
- name: Send notification to Slack via Zapier
if: success() && steps.compare.outputs.status == 'increased'
shell: bash
run: |
curl -s -X POST "${{ secrets.EMBEDDING_ZAPIER_WEBHOOK_URL }}" \
-d '⚠️ Embedding SDK bundle size increased by ${{ steps.compare.outputs.size_change_percent }}% (threshold: ${{ env.BUNDLE_SIZE_THRESHOLD_PERCENT }}%)
PR #${{ github.event.pull_request.number }} ${{ github.event.pull_request.title }} (${{ github.event.pull_request.html_url }})'
- name: Comment on PR if bundle size has decreased
uses: ./.github/actions/notify-pull-request
if: success() && steps.compare.outputs.status == 'decreased'
with:
remove-previous-comment: true
add-new-comment: true
message: "🎉 Embedding SDK bundle size decreased by ${{ steps.compare.outputs.size_change_percent }}% compared to the ${{ github.base_ref }} branch. Nice work!"
include-log: false
embedding-sdk-tests-result:
needs:
- embedding-sdk-bundle-size-check
- embedding-sdk-cli-snippets-type-check
- embedding-sdk-docs-snippets-type-check
- embedding-sdk-api-documentation-generation-validation

View File

@@ -44,12 +44,12 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Build cljs
run: yarn build:cljs
run: bun run build:cljs
- name: Stress-test ${{ github.event.inputs.spec }} ${{ github.event.inputs.burn_in }} times
run: |
for i in {1..${{ github.event.inputs.burn_in }}}; do
yarn jest --runInBand --ci --silent --no-cache \
--testPathPattern '${{ github.event.inputs.spec }}' \
bun run jest --runInBand --ci --silent --no-cache \
--testPathPatterns '${{ github.event.inputs.spec }}' \
--testNamePattern '${{ github.event.inputs.grep }}'
if [[ "$?" != 0 ]]; then
echo "Failed after $i attempts" && break;

View File

@@ -46,15 +46,15 @@ jobs:
key: ${{ steps.get-cache-keys.outputs.eslint-cache-key }}
- name: Compile CLJS
run: yarn build-pure:cljs
run: bun run build-pure:cljs
- name: Find CSS variables that are used but never defined
run: yarn find-never-defined-css-variables
run: bun run find-never-defined-css-variables
- name: Run Prettier formatting linter
run: yarn run lint-prettier-pure
run: bun run lint-prettier-pure
- name: Run ESLint linter
run: yarn run lint-eslint-pure
run: bun run lint-eslint-pure
- name: Run CSS linter
run: yarn run lint-css
run: bun run lint-css
fe-type-check:
if: ${{ !inputs.skip }}
@@ -66,9 +66,9 @@ jobs:
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- run: yarn build-pure:cljs
- run: bun run build-pure:cljs
name: Compile CLJS
- run: yarn type-check-pure
- run: bun run type-check-pure
name: Check types
fe-tests-unit:
@@ -90,7 +90,8 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Run frontend unit tests
run: yarn run test-unit --silent --shard=${{ matrix.shard }}/${{ env.SHARDS }}
id: fe-tests
run: bun run test-unit --silent --shard=${{ matrix.shard }}/${{ env.SHARDS }}
# Trunk Quarantine controls the final state of the run in the CI!
# Even if this step fails we let it pass, and then `trunk-io/analytics-uploader` determines
# whether to fail or to pass the whole job, based on the quarantine list.
@@ -106,6 +107,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.fe-tests.outcome }}
fe-tests-timezones:
if: ${{ !inputs.skip }}
@@ -118,7 +120,7 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Run frontend timezones tests
run: yarn run test-timezones
run: bun run test-timezones
fe-tests-result:
needs:

View File

@@ -1,56 +0,0 @@
name: Fuzzing
on:
workflow_dispatch:
push:
branches:
- "master"
- "release-**"
paths:
- "frontend/src/metabase/querying/expressions/**"
pull_request:
paths:
- "frontend/src/metabase/querying/expressions/**"
jobs:
fe-fuzz-lexifier:
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- run: yarn test-unit frontend/src/metabase/querying/expressions/pratt/fuzz.lexifier.unit.spec.ts
env:
MB_FUZZ: 1
name: Run fuzz testing on the lexifier
fe-fuzz-compiler:
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- run: yarn test-unit frontend/src/metabase/querying/expressions/fuzz.compiler.unit.spec.ts
env:
MB_FUZZ: 1
name: Run fuzz testing on the custom expression compiler
fe-fuzz-string-quoting:
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- run: yarn test-unit frontend/src/metabase/querying/expressions/fuzz.string.unit.spec.ts
env:
MB_FUZZ: 1
name: Run fuzz testing on the custom expression string quoter

51
.github/workflows/js-stats-update.yml vendored Normal file
View File

@@ -0,0 +1,51 @@
name: JS Stats Update
on:
workflow_dispatch:
schedule:
- cron: 40 1 * * 4 # every Thursday at 1:40
jobs:
js-stats:
runs-on: ubuntu-latest
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
- name: get JS file count
id: get-js-file-count
run: |
oss=$(find ./frontend/src/metabase -type f -name "*.js" -o -name "*.jsx" | wc -l)
ee=$(find ./enterprise/frontend/src/metabase-enterprise -type f -name "*.js" -o -name "*.jsx" | wc -l)
echo $(($oss+$ee)) javascript files
echo "JS_FILES=$(($oss+$ee))" >> $GITHUB_OUTPUT
- name: Upload count to Stats
uses: actions/github-script@v7
env:
JS_FILES: ${{ steps.get-js-file-count.outputs.JS_FILES }}
API_KEY: ${{ secrets.STATS_API_KEY }}
with:
script: | # js
const { uploadCsvToMb } = require('${{ github.workspace }}/.github/scripts/csv-to-mb.js');
console.log("JS_FILES", Number(process.env.JS_FILES));
const data = [
{
'Date': new Date().toISOString().slice(0, 10), // YYYY-MM-DD
'Js files': Number(process.env.JS_FILES),
}
];
uploadCsvToMb({
baseUrl: 'https://stats.metabase.com',
tableId: 73270,
jsonData: data,
mode: 'append',
}).then(() => {
console.log('Data uploaded successfully');
}).catch((error) => {
console.error('Error uploading data:', error);
process.exit(1);
});

View File

@@ -1,198 +0,0 @@
name: Generate llms.txt file
on:
workflow_call:
inputs:
version:
description: 'Metabase version (e.g. v0.57.0)'
type: string
required: true
branch:
description: 'Target branch (e.g. release-x.57.x)'
type: string
required: true
workflow_dispatch:
inputs:
version:
description: 'Metabase version (e.g. v0.57.0)'
type: string
required: true
branch:
description: 'Target branch (e.g. release-x.57.x)'
type: string
required: true
permissions:
contents: write
pull-requests: write
jobs:
check-version:
name: Check if minor or major release
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
should_generate: ${{ steps.check.outputs.should_generate }}
target_branch: ${{ steps.check.outputs.target_branch }}
version: ${{ steps.check.outputs.version }}
steps:
- name: Check version
id: check
run: |
VERSION="${{ inputs.version }}"
BRANCH="${{ inputs.branch }}"
# Extract version number (e.g., v0.57.0 -> 0.57.0)
VERSION_NUM="${VERSION#v}"
# Count dots to determine version type
# Metabase format: v0.MAJOR.MINOR (3 segments) or v0.MAJOR.MINOR.PATCH (4 segments)
DOT_COUNT=$(echo "$VERSION_NUM" | tr -cd '.' | wc -c | tr -d ' ')
# Only proceed if this is a minor or major release (3 segments)
# Examples of minor/major releases: v0.57.8, v0.59.0
# Skip for patch releases (4 segments): v0.57.8.1
# Note: This is a safety check even though the workflow should only be called
# for minor/major releases, just in case the workflow is dispatched manually.
if [ "$DOT_COUNT" -eq 3 ]; then
echo "⏭️ This is a patch release ($VERSION). Skipping llms.txt generation."
echo "should_generate=false" >> $GITHUB_OUTPUT
else
echo "✅ This is a minor or major release ($VERSION). Proceeding with llms.txt generation for branch: $BRANCH"
echo "should_generate=true" >> $GITHUB_OUTPUT
fi
echo "target_branch=$BRANCH" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
generate-llms-txt:
name: Generate llms.txt
needs: check-version
if: needs.check-version.outputs.should_generate == 'true'
runs-on: ubuntu-22.04
timeout-minutes: 15
steps:
- name: Get the generate-llms-txt.js node script via sparse checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
ref: ${{ github.ref }}
sparse-checkout: |
.github/scripts
path: workflow-scripts
- name: Checkout target branch for docs
uses: actions/checkout@v4
with:
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
ref: ${{ needs.check-version.outputs.target_branch }}
path: metabase
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
- name: Generate llms.txt
id: generate
run: |
node workflow-scripts/.github/scripts/generate-llms-txt.js metabase/docs ${{ needs.check-version.outputs.target_branch }}
- name: Sanity check generated files
run: |
if [ ! -f "llms.txt" ]; then
echo "❌ Error: llms.txt was not generated"
exit 1
fi
if [ ! -f "llms-embedding-full.txt" ]; then
echo "❌ Error: llms-embedding-full.txt was not generated"
exit 1
fi
# Check that llms.txt contains URLs with the expected GitHub raw URL prefix
URL_COUNT=$(grep -o "https://raw.githubusercontent.com/metabase/metabase/refs/heads/${{ needs.check-version.outputs.target_branch }}/docs" llms.txt | wc -l)
if [ "$URL_COUNT" -lt 10 ]; then
echo "❌ Error: llms.txt appears to be malformed. Found only $URL_COUNT URLs (expected at least 10)"
exit 1
fi
echo "✅ Both llms.txt and llms-embedding-full.txt were generated successfully"
echo "✅ llms.txt contains $URL_COUNT documentation URLs"
- name: Set up git configuration
working-directory: metabase
run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
BRANCH_NAME="llms-txt/auto-update-${{ needs.check-version.outputs.target_branch }}-$(date +%Y%m%d-%H%M%S)"
echo "BRANCH_NAME=$BRANCH_NAME" >> $GITHUB_ENV
echo "Branch name will be: $BRANCH_NAME"
- name: Copy generated files to metabase repo
run: |
cp llms.txt metabase/
cp llms-embedding-full.txt metabase/
- name: Create Pull Request
id: create_pr
uses: peter-evans/create-pull-request@v6
with:
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
path: metabase
branch: ${{ env.BRANCH_NAME }}
base: ${{ needs.check-version.outputs.target_branch }}
commit-message: |
Update llms.txt and llms-full.txt (${{ needs.check-version.outputs.target_branch }})
Regenerated llms.txt to include all markdown files from the docs/ directory.
Also generated llms-full.txt files for the embedding section.
🤖 Generated automatically by llms-txt-generate workflow
Co-Authored-By: GitHub Actions <actions@github.com>
committer: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
author: "github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
title: "[chore] Update llms.txt for ${{ needs.check-version.outputs.target_branch }}"
body: |
## Summary
This PR contains automatically generated updates to `llms.txt` and `llms-embedding-full.txt` files, triggered by a minor or major release.
## Changes
- The `llms.txt` file has been regenerated to include all markdown files from the `docs/` directory.
- The `llms-embedding-full.txt` file has been generated for the embedding section (concatenated documentation for RAG).
## Generation
These files were generated using:
- Script: `.github/scripts/generate-llms-txt.js`
- Branch: `${{ needs.check-version.outputs.target_branch }}`
- Base URL: `https://raw.githubusercontent.com/metabase/metabase/refs/heads/${{ needs.check-version.outputs.target_branch }}`
Please review the changes and merge if they look correct.
🤖 Generated automatically by the `llms-txt-generate` workflow.
Co-Authored-By: GitHub Actions <actions@github.com>
labels: |
Type:Documentation
no-backport
add-paths: |
llms.txt
llms-embedding-full.txt
- name: Auto approve PR
if: steps.create_pr.outputs.pull-request-number != ''
working-directory: metabase
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr review "${{ steps.create_pr.outputs.pull-request-number }}" --approve --body "Auto-approved by llms-txt-generate workflow"
- name: Auto merge PR
if: steps.create_pr.outputs.pull-request-number != ''
working-directory: metabase
env:
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
run: |
gh pr merge "${{ steps.create_pr.outputs.pull-request-number }}" --auto --squash

View File

@@ -1,10 +1,15 @@
name: Loki Visual Stress Test Flake Fix
on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- 'frontend/**/*.stories.tsx'
- 'enterprise/frontend/**/*.stories.tsx'
workflow_dispatch:
inputs:
stories_filter:
description: "Regex pattern to filter stories (e.g. 'DataGrid' or 'static-viz|viz')"
story_files:
description: "Comma-separated story file paths relative to repo root"
type: string
required: true
burn_in:
@@ -14,22 +19,96 @@ on:
default: "50"
jobs:
detect-changed-stories:
name: Detect changed stories
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
story_files: ${{ steps.detect.outputs.story_files }}
should_run: ${{ steps.detect.outputs.should_run }}
steps:
- name: Detect changed story files
id: detect
env:
GH_TOKEN: ${{ github.token }}
run: |
validate_paths() {
local files="$1"
for file in $(echo "$files" | tr ',' '\n'); do
file=$(echo "$file" | xargs) # trim whitespace
if [[ -z "$file" ]]; then
continue
fi
if [[ ! "$file" =~ ^(frontend/|enterprise/frontend/).+\.stories\. ]]; then
echo "::error::Invalid story path: $file"
echo "Paths must start with 'frontend/' or 'enterprise/frontend/' and contain '.stories.'"
return 1
fi
done
return 0
}
if [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then
FILES=$(echo "${{ inputs.story_files }}" | tr ',' '\n' | xargs -n1 | paste -sd',')
if ! validate_paths "$FILES"; then
exit 1
fi
echo "story_files=$FILES" >> $GITHUB_OUTPUT
echo "should_run=true" >> $GITHUB_OUTPUT
exit 0
fi
FILES=$( \
gh pr view ${{ github.event.pull_request.number }} --repo ${{ github.repository }} --json files --jq '.files[].path' \
| grep '\.stories\.tsx$' \
| xargs -n1 \
| sort -u \
| paste -sd',' \
)
if [[ -z "$FILES" ]]; then
echo "No changed story files found"
echo "should_run=false" >> $GITHUB_OUTPUT
exit 0
fi
if ! validate_paths "$FILES"; then
exit 1
fi
echo "Changed story files: $FILES"
echo "story_files=$FILES" >> $GITHUB_OUTPUT
echo "should_run=true" >> $GITHUB_OUTPUT
workflow-summary:
name: Stress test inputs
name: Summary
needs: detect-changed-stories
if: needs.detect-changed-stories.outputs.should_run == 'true'
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- name: Generate workflow summary
run: |
echo '**Inputs:**' >> $GITHUB_STEP_SUMMARY
echo '## Loki Stress Test' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo '- `branch`: ${{ github.ref_name }}' >> $GITHUB_STEP_SUMMARY
echo '- `stories_filter`: ${{ inputs.stories_filter }}' >> $GITHUB_STEP_SUMMARY
echo '- `burn_in`: ${{ inputs.burn_in }}' >> $GITHUB_STEP_SUMMARY
echo '**Branch:** `${{ github.head_ref || github.ref_name }}`' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
echo 'triggered by: @${{ github.event.sender.login }}' >> $GITHUB_STEP_SUMMARY
echo '**Story files:**' >> $GITHUB_STEP_SUMMARY
echo '${{ needs.detect-changed-stories.outputs.story_files }}' | tr ',' '\n' | while read -r file; do
echo "- \`$file\`" >> $GITHUB_STEP_SUMMARY
done
echo '' >> $GITHUB_STEP_SUMMARY
echo '**Burn-in:** ${{ inputs.burn_in || 50 }} runs' >> $GITHUB_STEP_SUMMARY
echo '' >> $GITHUB_STEP_SUMMARY
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo 'Triggered by PR #${{ github.event.pull_request.number }} from @${{ github.event.pull_request.user.login }}' >> $GITHUB_STEP_SUMMARY
else
echo 'Triggered manually by @${{ github.actor }}' >> $GITHUB_STEP_SUMMARY
fi
stress-test-loki:
needs: detect-changed-stories
if: needs.detect-changed-stories.outputs.should_run == 'true'
runs-on: ubuntu-latest
timeout-minutes: 60
name: Stress test Loki visual tests
@@ -56,17 +135,20 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Compile CLJS
run: NODE_ENV=development yarn build-pure:cljs
run: NODE_ENV=development bun run build-pure:cljs
- name: Build Storybook (once)
run: yarn build-storybook
- name: Build Storybook
run: bun run build-storybook
env:
STORYBOOK_STORIES_FILTER: ${{ needs.detect-changed-stories.outputs.story_files }}
- name: Stress-test Loki "${{ inputs.stories_filter }}" ${{ inputs.burn_in }} times
- name: Stress-test Loki
run: |
BURN_IN=${{ inputs.burn_in }}
STORIES_FILTER='${{ inputs.stories_filter }}'
BURN_IN=${{ inputs.burn_in || '50' }}
STORY_FILES='${{ needs.detect-changed-stories.outputs.story_files }}'
echo "Running Loki visual tests $BURN_IN times for stories matching: $STORIES_FILTER"
echo "Story files: $STORY_FILES"
echo "Running Loki $BURN_IN times"
echo ""
FAILED=0
@@ -75,10 +157,9 @@ jobs:
echo "Run $i of $BURN_IN"
echo "=========================================="
if yarn test-visual:loki \
if bun run test-visual:loki \
--reactUri file:./storybook-static \
--verboseRenderer \
--storiesFilter "$STORIES_FILTER"; then
--verboseRenderer; then
echo "✅ Run $i passed"
else
echo "❌ Run $i FAILED"
@@ -101,10 +182,9 @@ jobs:
- name: Generate Visual Report on Failure
if: failure()
run: yarn test-visual:loki-report
run: bun run test-visual:loki-report
- name: Upload Artifact
id: artifact-upload-step
if: failure()
uses: actions/upload-artifact@v4
with:

View File

@@ -22,10 +22,10 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Compile CLJS
run: yarn build-pure:cljs
run: bun run build-pure:cljs
- name: Update Loki Snapshots
run: yarn test-visual:loki:ci || yarn test-visual:loki-approve-diff && yarn test-visual:loki-prune
run: bun run test-visual:loki:ci || bun run test-visual:loki-approve-diff && bun run test-visual:loki-prune
- name: Check for changes
id: check-changes

View File

@@ -49,14 +49,14 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Compile CLJS
run: NODE_ENV=development yarn build-pure:cljs
run: NODE_ENV=development bun run build-pure:cljs
- name: Run Loki Visual Tests
run: yarn test-visual:loki:ci
run: bun run test-visual:loki:ci
- name: Generate Visual Report on Failure
if: failure()
run: yarn test-visual:loki-report
run: bun run test-visual:loki-report
- name: Upload Artifact
id: artifact-upload-step

View File

@@ -30,9 +30,9 @@ jobs:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
CI: "true"
DRIVERS: postgres
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
@@ -53,10 +53,11 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Postgres App DB
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: true
junit-name: 'minimal-be-tests-postgres-ee'
junit-name: "minimal-be-tests-postgres-ee"
test-args: >-
:only '["test" "enterprise/backend/test"]'
:exclude-tags '[:mb/driver-tests :mb/transforms-python-test]'
@@ -73,15 +74,16 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
# Postgres driver tests
postgres-driver-test:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
runs-on: ubuntu-latest
timeout-minutes: 60
timeout-minutes: 40
env:
CI: 'true'
CI: "true"
DRIVERS: postgres
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
@@ -102,9 +104,10 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Postgres Driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'minimal-be-tests-postgres-driver-ee'
junit-name: "minimal-be-tests-postgres-driver-ee"
test-args: >-
:only-tags [:mb/driver-tests]
:exclude-tags [:mb/transforms-python-test]
@@ -119,6 +122,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
# Frontend unit tests
frontend-unit-tests:
@@ -137,7 +141,8 @@ jobs:
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Run frontend unit tests
run: yarn run test-unit --silent
id: run-tests
run: bun run test-unit --silent
continue-on-error: true
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
@@ -150,6 +155,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.run-tests.outcome }}
# Summary job
minimal-tests-result:

46
.github/workflows/openapi.yml vendored Normal file
View File

@@ -0,0 +1,46 @@
name: Validate OpenAPI
on:
push:
branches:
- "master"
- "release-**"
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
jobs:
files-changed:
name: Check which files changed
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
openapi: ${{ steps.changes.outputs.openapi }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
filters: .github/file-paths.yaml
validate-openapi:
needs: files-changed
if: needs.files-changed.outputs.openapi == 'true'
runs-on: ubuntu-22.04
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Generate OpenAPI spec
run: bun run openapi:generate
- name: Validate OpenAPI spec
run: bun run openapi:lint
- name: Split OpenAPI spec
run: bun run openapi:split

View File

@@ -29,7 +29,8 @@ jobs:
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.pull_request.head.sha || github.sha }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"
- name: Move uberjar to bin/docker

View File

@@ -5,8 +5,8 @@ on:
types: [ closed, unlabeled ]
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: false
jobs:
pr-env:

View File

@@ -0,0 +1,29 @@
name: PR Env Destroy (Manual)
on:
workflow_dispatch:
inputs:
pr_number:
description: 'PR number to destroy environment for'
required: true
type: string
self_hosting:
description: 'Self-hosting stack'
type: boolean
default: false
jobs:
approve:
runs-on: ubuntu-latest
environment: pr-env-admin
steps:
- name: Approved
run: echo "Destroying PR environment for PR #${{ inputs.pr_number }}"
destroy:
needs: approve
uses: ./.github/workflows/pr-env-destroy.yml
secrets: inherit
with:
self_hosting: ${{ inputs.self_hosting }}
pr_number: ${{ inputs.pr_number }}

View File

@@ -9,6 +9,13 @@ on:
required: false
type: boolean
default: false
pr_number:
description: 'PR number (required for manual dispatch)'
required: false
type: string
env:
PR_NUMBER: ${{ inputs.pr_number || github.event.number }}
jobs:
destroy_pr:
@@ -62,8 +69,8 @@ jobs:
- name: Destroy PR Review ENV
if: ${{ !inputs.self_hosting }}
run: |
kubectl delete metabase -n hosting-pr${{ github.event.number }} hosting-pr${{ github.event.number }}
kubectl delete ns hosting-pr${{ github.event.number }}
kubectl delete metabase -n hosting-pr${{ env.PR_NUMBER }} hosting-pr${{ env.PR_NUMBER }}
kubectl delete ns hosting-pr${{ env.PR_NUMBER }}
- name: Setup Helm
if: ${{ inputs.self_hosting }}
uses: azure/setup-helm@v4
@@ -72,8 +79,8 @@ jobs:
- name: Destroy PR Review ENV (self-hosting)
if: ${{ inputs.self_hosting }}
run: |
helm uninstall hosting-pr${{ github.event.number }} --namespace hosting-pr${{ github.event.number }} || true
kubectl delete ns hosting-pr${{ github.event.number }} || true
helm uninstall hosting-pr${{ env.PR_NUMBER }} --namespace hosting-pr${{ env.PR_NUMBER }} || true
kubectl delete ns hosting-pr${{ env.PR_NUMBER }} || true
- name: Setup psql client
run: |
sudo apt-get update
@@ -85,4 +92,4 @@ jobs:
-h ${{ secrets.PR_ENV_DB_HOST }} \
-U ${{ secrets.PR_ENV_DB_USER }} \
-d ${{ secrets.PR_ENV_DB_NAME }} \
-c "DROP DATABASE IF EXISTS hosting_pr${{ github.event.number }};"
-c "DROP DATABASE IF EXISTS hosting_pr${{ env.PR_NUMBER }};"

View File

@@ -40,7 +40,8 @@ jobs:
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.pull_request.head.sha || github.sha }}
edition: ee
extract-path: "target/uberjar"
output-name: "metabase.jar"
- name: Move uberjar to bin/docker

View File

@@ -30,12 +30,15 @@ jobs:
outputs:
run_mode: ${{ fromJson(steps.config.outputs.result).runMode }}
dev_server: ${{ fromJson(steps.config.outputs.result).metastoreDevServer }}
package_manager: ${{ fromJson(steps.config.outputs.result).packageManager }}
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
# note: this block can be removed after we stop needing to be able to test versions before v55
- name: Get test mode config
id: config
@@ -48,13 +51,17 @@ jobs:
// with v55 and later we use enterprise tokens that mirror actual Metabase plans
const MULTIPLE_TEST_TOKEN_THRESHOLD = 55;
// Versions before v59 used yarn, v59 and later use bun
const BUN_PACKAGE_MANAGER_THRESHOLD = 59;
const version = '${{ inputs.version }}';
const majorVersion = Number(getMajorVersion(version));
const oldTestToken = majorVersion < MULTIPLE_TEST_TOKEN_THRESHOLD;
return ({
runMode: oldTestToken ? 'prod' : 'e2e',
metastoreDevServer: oldTestToken ? '' : '${{ vars.METASTORE_DEV_SERVER_URL }}'
metastoreDevServer: oldTestToken ? '' : '${{ vars.METASTORE_DEV_SERVER_URL }}',
packageManager: majorVersion < BUN_PACKAGE_MANAGER_THRESHOLD ? 'yarn' : 'bun',
});
release-artifact:
@@ -71,10 +78,12 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: .github
- name: Retrieve test build uberjar artifact for ${{ matrix.edition }}
- name: Retrieve release uberjar artifact for ${{ matrix.edition }}
uses: ./.github/actions/fetch-artifact
with:
name: metabase-release-${{ matrix.edition }}-${{ inputs.commit }}-uberjar
commit: ${{ inputs.commit }}
edition: ${{ matrix.edition }}
release: "true"
- name: Extract version number from version.properties
id: version-properties
@@ -168,6 +177,8 @@ jobs:
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Compile CLJS
run: ${{ needs.test-mode-config.outputs.package_manager }} run build-pure:cljs
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
@@ -228,32 +239,42 @@ jobs:
uses: ./.github/workflows/containerize-jar.yml
secrets: inherit
with:
artifact-name: metabase-release-oss-${{ inputs.commit }}-uberjar
edition: oss
commit: ${{ inputs.commit }}
repo: ${{ vars.DOCKERHUB_OWNER }}/${{ vars.DOCKERHUB_STAGING_REPO }}
tag: ${{ needs.release-artifact.outputs.oss_version }}-${{ inputs.commit }}
release: "true"
containerize-ee:
needs: release-artifact
uses: ./.github/workflows/containerize-jar.yml
secrets: inherit
with:
artifact-name: metabase-release-ee-${{ inputs.commit }}-uberjar
edition: ee
commit: ${{ inputs.commit }}
repo: ${{ vars.DOCKERHUB_OWNER }}/${{ vars.DOCKERHUB_STAGING_REPO }}
tag: ${{ needs.release-artifact.outputs.ee_version }}-${{ inputs.commit }}
release: "true"
tests-complete-message:
if: always()
runs-on: ubuntu-22.04
needs: [run-sanity-check, check-uberjar-health, containerize-ee, containerize-oss]
needs:
[
run-sanity-check,
check-uberjar-health,
containerize-ee,
containerize-oss,
]
timeout-minutes: 5
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Send tests complete message
uses: actions/github-script@v7
env:

View File

@@ -44,10 +44,12 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
sparse-checkout: |
release
.github
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Cache build scripts
uses: actions/upload-artifact@v4
@@ -178,8 +180,8 @@ jobs:
with:
ref: ${{ inputs.branch }}
- name: Prepare build scripts
run: yarn --cwd release --frozen-lockfile && yarn --cwd release build
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get current SDK version
id: current-sdk-version
@@ -256,7 +258,7 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Run unit tests
run: yarn embedding-sdk:test-unit
run: bun run embedding-sdk:test-unit
build-sdk:
needs: [test, determine-sdk-version]
@@ -282,10 +284,10 @@ jobs:
./bin/embedding-sdk/release_utils.bash update_package_json_template ${{ needs.determine-sdk-version.outputs.sdk_version }}
- name: Build SDK package
run: yarn run build-embedding-sdk-package
run: bun run build-embedding-sdk-package
- name: Generate SDK package.json in the build directory
run: yarn run embedding-sdk:generate-package
run: bun run embedding-sdk:generate-package
- name: Upload built SDK package as artifact
uses: actions/upload-artifact@v4

View File

@@ -38,10 +38,10 @@ jobs:
with:
ref: master # this only works on master
fetch-depth: 0 # we want all branches and tags
- name: Install Dependencies
run: yarn --cwd release --frozen-lockfile && npm i -g tsx
- name: Build release scripts
run: yarn --cwd release build
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Install tsx
run: npm i -g tsx
- name: Get version number
uses: actions/github-script@v7
with:

View File

@@ -21,8 +21,13 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare build scripts
run: yarn --cwd release --frozen-lockfile && yarn --cwd release build
run: bun install --cwd release --frozen-lockfile && bun run --cwd release build
- uses: actions/github-script@v7
env:
GITHUB_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}

View File

@@ -23,9 +23,11 @@ jobs:
exit 1
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Version
uses: actions/github-script@v7
env:

View File

@@ -26,8 +26,13 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
- name: Prepare build scripts
run: yarn --cwd release --frozen-lockfile && yarn --cwd release build
run: bun install --cwd release --frozen-lockfile && bun run --cwd release build
- name: Trigger auto-patch
uses: actions/github-script@v7
with:

View File

@@ -14,9 +14,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn --frozen-lockfile && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Check release status and post to Slack
uses: actions/github-script@v7
env:
@@ -47,9 +49,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn --frozen-lockfile && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Check backport status and post to Slack
uses: actions/github-script@v7
env:

View File

@@ -79,9 +79,11 @@ jobs:
exit 1
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Version
uses: actions/github-script@v7
id: canonical_version
@@ -304,9 +306,11 @@ jobs:
aws-region: ${{ vars.AWS_REGION }}
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Generate new version info
uses: actions/github-script@v7
id: new_version_info

View File

@@ -36,10 +36,15 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: "release"
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
- name: prepare dependencies in release directory
run: yarn --cwd release --frozen-lockfile
run: bun install --cwd release --frozen-lockfile
- name: Run frontend type-check
run: yarn --cwd release type-check
run: bun run --cwd release type-check
release-tests-unit:
needs: files-changed
@@ -50,10 +55,15 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: "release"
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
- name: prepare dependencies in release directory
run: yarn --cwd release --frozen-lockfile
run: bun install --cwd release --frozen-lockfile
- name: Run release unit tests
run: yarn --cwd release test:unit
run: bun run --cwd release test:unit
release-test-build:
needs: files-changed
@@ -64,9 +74,14 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: "release"
- name: Install bun
uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
- name: prepare dependencies in release directory
run: yarn --cwd release --frozen-lockfile
run: bun install --cwd release --frozen-lockfile
- name: Build release bundle
run: yarn --cwd release build
run: bun run --cwd release build
- name: Smoke test release bundle
run: node release/dist/index.cjs

View File

@@ -63,9 +63,11 @@ jobs:
exit 1
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Version
uses: actions/github-script@v7
id: canonical_version
@@ -108,9 +110,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Send publish start message
uses: actions/github-script@v7
env:
@@ -140,10 +144,12 @@ jobs:
- uses: actions/checkout@v4
with:
sparse-checkout: .github
- name: Retrieve test build uberjar artifact for ${{ matrix.edition }}
- name: Retrieve release uberjar artifact for ${{ matrix.edition }}
uses: ./.github/actions/fetch-artifact
with:
name: metabase-release-${{ matrix.edition }}-${{ inputs.commit }}-uberjar
commit: ${{ inputs.commit }}
edition: ${{ matrix.edition }}
release: "true"
- name: Check JAR version properties
run: |
# ensure actual jar checksum matches checksum file
@@ -187,9 +193,11 @@ jobs:
aws-region: ${{ vars.AWS_REGION }}
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: prepare release scripts
run: cd release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- uses: actions/download-artifact@v4
name: Retrieve uberjar artifact
with:
@@ -259,20 +267,22 @@ jobs:
uses: ./.github/workflows/containerize-jar.yml
secrets: inherit
with:
artifact-name: metabase-release-oss-${{ inputs.commit }}-uberjar
edition: oss
commit: ${{ inputs.commit }}
repo: ${{ vars.DOCKERHUB_OWNER }}/${{ vars.DOCKERHUB_REPO }}
tag: ${{ needs.check-version.outputs.oss }}
release: "true"
containerize-ee:
needs: check-version
uses: ./.github/workflows/containerize-jar.yml
secrets: inherit
with:
artifact-name: metabase-release-ee-${{ inputs.commit }}-uberjar
edition: ee
commit: ${{ inputs.commit }}
repo: ${{ vars.DOCKERHUB_OWNER }}/${{ vars.DOCKERHUB_REPO }}-enterprise
tag: ${{ needs.check-version.outputs.ee }}
release: "true"
push-tags:
permissions: write-all
@@ -282,9 +292,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: prepare release scripts
run: cd release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Tag Release
uses: actions/github-script@v7
with:
@@ -314,9 +326,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: prepare release scripts
run: cd release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get extra tags
id: taglist
uses: actions/github-script@v7
@@ -326,10 +340,11 @@ jobs:
const { getExtraTagsForVersion } = require('${{ github.workspace }}/release/dist/index.cjs');
const version = '${{ inputs.version }}';
const latestMajorVersion = '${{ vars.LATEST_MAJOR_VERSION }}';
const extra_tags = getExtraTagsForVersion({ version });
const extra_tags = getExtraTagsForVersion({ version, latestMajorVersion });
console.log({ extra_tags });
console.log({ extra_tags, latestMajorVersion });
core.setOutput('extra_tags', JSON.stringify(extra_tags));
add-extra-tags:
@@ -347,9 +362,11 @@ jobs:
with:
version: ${{ inputs.version }}
tag_name: ${{ matrix.tag }}
tag_ee: ${{ contains(matrix.tag, 'v1') }}
tag_oss: ${{ contains(matrix.tag, 'v0') }}
dot-x-tag: true
# For version tags (v0.x, v1.x), apply to matching edition only
# For non-version tags like "latest", apply to both editions
tag_ee: ${{ contains(matrix.tag, 'v1') || !startsWith(matrix.tag, 'v') }}
tag_oss: ${{ contains(matrix.tag, 'v0') || !startsWith(matrix.tag, 'v') }}
dot-x-tag: ${{ startsWith(matrix.tag, 'v') }}
trigger-cloud-issues:
if: ${{ !inputs.auto }}
@@ -359,9 +376,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Find milestone
id: find-milestone
uses: actions/github-script@v7
@@ -424,19 +443,6 @@ jobs:
}
});
# updates the llms.txt asynchronously.
# release does not need to wait for this PR to be merged,
# because the llms.txt is in the main git repo.
trigger-update-llms-txt:
# do not trigger llms.txt update on automatic patch releases
if: ${{ !inputs.auto }}
needs: add-extra-tags
uses: ./.github/workflows/llms-txt-generate.yml
secrets: inherit
with:
version: ${{ inputs.version }}
branch: ${{ github.ref_name }}
draft-release-notes:
if: ${{ !inputs.auto }}
needs: add-extra-tags
@@ -450,9 +456,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: prepare release scripts
run: cd release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Publish draft release notes to github
uses: actions/github-script@v7
with:
@@ -529,9 +537,11 @@ jobs:
aws-region: ${{ vars.AWS_REGION }}
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Publish version info
uses: actions/github-script@v7
id: new_version_info
@@ -586,9 +596,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Send publish complete message
uses: actions/github-script@v7
env:
@@ -617,9 +629,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Update milestones
uses: actions/github-script@v7
with:

View File

@@ -103,7 +103,8 @@ jobs:
(needs.files-changed.outputs.embedding_sdk_components == 'true' ||
needs.files-changed.outputs.frontend_sources == 'true' ||
needs.files-changed.outputs.embedding_documentation == 'true' ||
needs.files-changed.outputs.embedding_sdk_ci == 'true')
needs.files-changed.outputs.embedding_sdk_ci == 'true' ||
needs.files-changed.outputs.embedding_sdk_host_sample_apps == 'true')
uses: ./.github/workflows/embedding-sdk-package-build.yml
secrets: inherit
@@ -113,6 +114,7 @@ jobs:
uses: ./.github/workflows/embedding-sdk.yml
secrets: inherit
with:
bundle-size-check: ${{ github.event_name == 'pull_request' && needs.uberjar.result == 'success' && needs.files-changed.outputs.frontend_sources == 'true' }}
cli-snippets-type-check: ${{ needs.files-changed.outputs.frontend_sources == 'true' }}
docs-snippets-type-check: ${{ needs.files-changed.outputs.embedding_documentation == 'true' }}
documentation-validation: ${{ needs.files-changed.outputs.frontend_sources == 'true' }}

View File

@@ -15,7 +15,7 @@ jobs:
semantic-search-tests-h2:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -46,6 +46,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -64,11 +65,12 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
semantic-search-tests-mariadb:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -118,6 +120,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -136,11 +139,12 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
semantic-search-tests-mysql:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -190,6 +194,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -208,11 +213,12 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
semantic-search-tests-postgres:
if: ${{ !inputs.skip }}
runs-on: ubuntu-22.04
timeout-minutes: 60
timeout-minutes: 40
strategy:
fail-fast: false
matrix:
@@ -263,6 +269,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
build-static-viz: ${{ matrix.job.build-static-viz }}
@@ -281,6 +288,7 @@ jobs:
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
previous-step-outcome: ${{ steps.test-driver.outputs.test-outcome }}
semantic-search-tests-result:
needs:

View File

@@ -41,16 +41,36 @@ jobs:
strategy:
matrix:
project:
- name: Main Frontend (yarn)
- name: Main Frontend (bun w/ yarn.lock)
file: yarn.lock
package-manager: yarn
category: main-frontend-yarn
category: main-frontend-bun
- name: Release Helper
file: release/yarn.lock
package-manager: yarn
category: release-helper
steps:
- uses: actions/checkout@v4
- uses: oven-sh/setup-bun@v2
with:
bun-version: "1.3.7"
token: ${{ secrets.GITHUB_TOKEN }}
# Snyk doesn't support bun.lock yet, so we generate yarn.lock and scan that.
# Bun has a bug where it normalizes "< 3.0.0" to "< 3" in alias entries
# but not in dependency specs, causing Snyk to fail matching dependencies.
# The sed commands fix this inconsistency. They continue on error to let
# Snyk report parsing issues directly rather than failing on the workaround.
- name: Generate yarn.lock
if: matrix.project.file == 'yarn.lock'
run: |
bun install --yarn
sed -i -E 's/< ([0-9]+)\.0\.0"/< \1"/g; s/< ([0-9]+)\.0"/< \1"/g' yarn.lock || true
- name: Generate release/yarn.lock
if: matrix.project.file == 'release/yarn.lock'
run: |
bun install --yarn
sed -i -E 's/< ([0-9]+)\.0\.0"/< \1"/g; s/< ([0-9]+)\.0"/< \1"/g' yarn.lock || true
working-directory: release
- uses: snyk/actions/setup@0.4.0
- name: Run snyk test
env:

View File

@@ -23,9 +23,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Send build start message
uses: actions/github-script@v7
env:
@@ -62,9 +64,11 @@ jobs:
exit 1
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Version
uses: actions/github-script@v7
id: canonical_version
@@ -104,9 +108,11 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0 # IMPORTANT! to get all the branches
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get Release Branch
uses: actions/github-script@v7
id: release_branch
@@ -124,6 +130,7 @@ jobs:
git branch --contains ${{ inputs.commit }} | grep -q $RELEASE_BRANCH \
&& echo "Commit found in correct release branch" \
|| (echo "Commit not found in correct release branch" && exit 1)
git checkout -
tag-uberjar-for-release:
needs: [check-version, check-commit]
@@ -156,7 +163,8 @@ jobs:
- name: Retrieve test build uberjar artifact for ${{ matrix.edition }}
uses: ./.github/actions/fetch-artifact
with:
name: metabase-${{ matrix.edition }}-${{ inputs.commit }}-uberjar
commit: ${{ inputs.commit }}
edition: ${{ matrix.edition }}
- name: Update version.properties in jar
run: | # sh

View File

@@ -0,0 +1,495 @@
name: Transforms Python Stress Test
on:
workflow_dispatch:
inputs:
ref:
description: 'Branch name or commit SHA to checkout'
type: string
required: false
default: ''
driver:
description: 'Which driver(s) to test'
required: true
default: 'all'
type: choice
options:
- all
- bigquery
- clickhouse
- mongo
- mysql
- postgres
- redshift
- snowflake
- sqlserver
jobs:
be-tests-bigquery-transforms:
# inputs.driver is empty on push triggers, so treat '' as 'all'
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'bigquery' }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
CI: 'true'
DRIVERS: bigquery-cloud-sdk
MB_BIGQUERY_TEST_PROJECT_ID: ${{ secrets.BIGQUERY_TEST_PROJECT_ID }}
MB_BIGQUERY_TEST_CLIENT_ID: ${{ secrets.MB_BIGQUERY_TEST_CLIENT_ID }}
MB_BIGQUERY_TEST_CLIENT_SECRET: ${{ secrets.MB_BIGQUERY_TEST_CLIENT_SECRET }}
MB_BIGQUERY_TEST_ACCESS_TOKEN: ${{ secrets.MB_BIGQUERY_TEST_ACCESS_TOKEN }}
MB_BIGQUERY_TEST_REFRESH_TOKEN: ${{ secrets.MB_BIGQUERY_TEST_REFRESH_TOKEN }}
MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON: ${{ secrets.MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON }}
MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON_ROUTING: ${{ secrets.MB_BIGQUERY_CLOUD_SDK_TEST_SERVICE_ACCOUNT_JSON_ROUTING }}
name: BigQuery Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test BigQuery transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-bigquery-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: BigQuery Transforms
be-tests-clickhouse-transforms:
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'clickhouse' }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
CI: 'true'
DRIVERS: clickhouse
MB_CLICKHOUSE_TEST_HOST: localhost
MB_CLICKHOUSE_TEST_PORT: 8123
MB_CLICKHOUSE_TEST_OLD_PORT: 8124
MB_CLICKHOUSE_TEST_NGINX_PORT: 8127
name: ClickHouse Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Add ClickHouse TLS instance to /etc/hosts
run: |
sudo echo "127.0.0.1 server.clickhouseconnect.test" | sudo tee -a /etc/hosts
- name: Start ClickHouse in Docker
uses: hoverkraft-tech/compose-action@v2.0.0
with:
compose-file: "modules/drivers/clickhouse/docker-compose.yml"
down-flags: "--volumes"
services: |
clickhouse
clickhouse_tls
clickhouse_older_version
clickhouse_cluster_node1
clickhouse_cluster_node2
nginx
- name: Test ClickHouse transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-clickhouse-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: ClickHouse Transforms
be-tests-mongo-transforms:
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'mongo' }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
CI: 'true'
DRIVERS: mongo
MB_MONGO_TEST_USER: metabase
MB_MONGO_TEST_PASSWORD: metasample123
services:
mongodb:
image: mongo:latest
ports:
- "27017:27017"
env:
MONGO_INITDB_ROOT_USERNAME: metabase
MONGO_INITDB_ROOT_PASSWORD: metasample123
name: MongoDB Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test MongoDB transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-mongo-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: MongoDB Transforms
be-tests-mysql-transforms:
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'mysql' }}
runs-on: ubuntu-latest
timeout-minutes: 60
services:
mysql:
image: mysql:latest
ports:
- "3306:3306"
env:
MYSQL_ALLOW_EMPTY_PASSWORD: true
MYSQL_DATABASE: circle_test
env:
CI: 'true'
DRIVERS: mysql
MB_DB_TYPE: mysql
MB_DB_HOST: localhost
MB_DB_PORT: 3306
MB_DB_DBNAME: circle_test
MB_DB_USER: root
MB_MYSQL_TEST_USER: root
name: MySQL Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test MySQL transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-mysql-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: MySQL Transforms
be-tests-postgres-transforms:
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'postgres' }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
CI: 'true'
DRIVERS: postgres
MB_DB_TYPE: postgres
MB_DB_PORT: 5432
MB_DB_HOST: localhost
MB_DB_DBNAME: mb_test
MB_DB_USER: mb_test
MB_POSTGRESQL_TEST_USER: mb_test
services:
postgres:
image: postgres:latest
ports:
- "5432:5432"
env:
POSTGRES_USER: mb_test
POSTGRES_DB: mb_test
POSTGRES_HOST_AUTH_METHOD: trust
name: Postgres Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test Postgres transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-postgres-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: Postgres Transforms
be-tests-redshift-transforms:
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'redshift' }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
CI: 'true'
DRIVERS: redshift
MB_REDSHIFT_TEST_USER: metabase_ci
MB_REDSHIFT_TEST_DB: testdb
MB_REDSHIFT_TEST_DB_ROUTING: dev
MB_REDSHIFT_TEST_HOST: ${{ secrets.MB_REDSHIFT_TEST_HOST }}
MB_REDSHIFT_TEST_PASSWORD: ${{ secrets.MB_REDSHIFT_TEST_PASSWORD }}
name: Redshift Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test Redshift transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-redshift-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: Redshift Transforms
be-tests-snowflake-transforms:
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'snowflake' }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
CI: 'true'
DRIVERS: snowflake
MB_SNOWFLAKE_TEST_USER: METABASE CI
MB_SNOWFLAKE_TEST_ACCOUNT: ${{ secrets.MB_SNOWFLAKE_TEST_ACCOUNT }}
MB_SNOWFLAKE_TEST_PASSWORD: ${{ secrets.MB_SNOWFLAKE_TEST_PASSWORD }}
MB_SNOWFLAKE_TEST_PRIVATE_KEY: ${{ secrets.MB_SNOWFLAKE_TEST_PRIVATE_KEY }}
MB_SNOWFLAKE_TEST_WAREHOUSE: ${{ secrets.MB_SNOWFLAKE_TEST_WAREHOUSE }}
MB_SNOWFLAKE_TEST_PK_USER: METABASE PK
MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY }}
MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY_2: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PRIVATE_KEY_2 }}
MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY }}
MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY_2: ${{ secrets.MB_SNOWFLAKE_TEST_PK_PUBLIC_KEY_2 }}
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_DEFAULT_USER: RSA_ROLE_TEST_DEFAULT_USER
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_CUSTOM_USER: RSA_ROLE_TEST_CUSTOM_USER
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_ROLE: RSA_ROLE_TEST_ROLE
MB_SNOWFLAKE_TEST_RSA_ROLE_TEST_DB: RSA_ROLE_TEST_DB
name: Snowflake Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test Snowflake transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-snowflake-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: Snowflake Transforms
be-tests-sqlserver-transforms:
if: ${{ inputs.driver == 'all' || inputs.driver == '' || inputs.driver == 'sqlserver' }}
runs-on: ubuntu-latest
timeout-minutes: 60
env:
CI: 'true'
DRIVERS: sqlserver
MB_SQLSERVER_TEST_HOST: localhost
MB_SQLSERVER_TEST_PASSWORD: 'P@ssw0rd'
MB_SQLSERVER_TEST_USER: SA
services:
sqlserver:
image: mcr.microsoft.com/mssql/server:2022-latest
ports:
- "1433:1433"
env:
ACCEPT_EULA: Y
SA_PASSWORD: 'P@ssw0rd'
MSSQL_MEMORY_LIMIT_MB: 1024
name: SQL Server Transforms
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref || github.ref }}
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test SQL Server transforms
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-sqlserver-transforms'
test-args: >-
:only-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
bucket: ${{ vars.AWS_S3_TEST_RESULTS_BUCKET }}
aws-access-key-id: ${{ secrets.AWS_TEST_RESULTS_ACCESS_KEY_ID }}
aws-secret-access-key: ${{ secrets.AWS_TEST_RESULTS_SECRET_ACCESS_KEY }}
aws-region: ${{ vars.AWS_REGION }}
trunk-api-token: ${{ secrets.TRUNK_API_TOKEN }}
- name: Cleanup python-runner
if: always()
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: SQL Server Transforms
transforms-stress-test-result:
needs:
- be-tests-bigquery-transforms
- be-tests-clickhouse-transforms
- be-tests-mongo-transforms
- be-tests-mysql-transforms
- be-tests-postgres-transforms
- be-tests-redshift-transforms
- be-tests-snowflake-transforms
- be-tests-sqlserver-transforms
runs-on: ubuntu-latest
timeout-minutes: 5
name: transforms-stress-test-result
if: always() && !cancelled()
steps:
- name: Check job status
uses: actions/github-script@v7
env:
needs: ${{ toJson(needs) }}
with:
script: |
const needs = JSON.parse(process.env.needs);
const jobs = Object.entries(needs).map(
([jobName, jobValues]) => ({
name: jobName,
result: jobValues.result
}));
if (jobs.every(job => (job.result === 'skipped' || job.result === 'success'))) {
console.log("All transforms tests have passed (or been skipped).");
process.exit(0);
}
console.log("Some transforms tests have failed:");
jobs.forEach((job) => {
if (job.result !== 'success' && job.result !== 'skipped') {
console.log(` ${job.name} - ${job.result}`);
}
});
process.exit(1);

View File

@@ -0,0 +1,50 @@
name: Crowdin Context Harvester
on:
workflow_dispatch:
schedule:
- cron: "30 6 * * 2" # Tuesday at 06:30 UTC, one hour after translation-update.yml
jobs:
harvest:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Harvest and write AI context to Crowdin
timeout-minutes: 60
env:
CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
OPENAI_KEY: ${{ secrets.CROWDIN_OPENAI_API_KEY }}
run: |
npx --yes crowdin-context-harvester@latest harvest \
--project="$CROWDIN_PROJECT_ID" \
--ai="openai" \
--model="gpt-5.1" \
--croql='not (context contains "✨ AI Context")' \
--output="crowdin" \
--concurrency=10
# We only want to trigger pre-translations, not wait for them to finish running upstream.
# Weirdly, Crowdin keeps this step running as long as it runs pre-translations on their servers.
# Hence, the three minute timeout and continue-on-error.
- name: Trigger pre-translations
timeout-minutes: 3
uses: crowdin/github-action@v2
# https://crowdin.github.io/crowdin-cli/commands/crowdin-pre-translate
with:
command: "pre-translate"
command_args: >-
--method ai
--ai-prompt ${{ secrets.CROWDIN_AI_PROMPT_ID }}
--translate-untranslated-only
--token ${{ secrets.CROWDIN_TOKEN }}
--project-id ${{ secrets.CROWDIN_PROJECT_ID }}
--config=locales/crowdin.yml
--no-progress
continue-on-error: true

View File

@@ -1,70 +0,0 @@
# This allows Tusk to manually run workflows to check lint/build/tests before creating a PR.
# If you have any questions, please reach out to support@usetusk.ai.
name: Tusk Sanity Check
on:
workflow_dispatch:
inputs:
taskId:
description: "Tusk Task ID"
required: true
runType:
description: "Tusk Run Type"
required: true
runId:
description: "Tusk Run ID"
required: true
jobs:
sanity_check:
runs-on: ubuntu-latest
steps:
- name: Log inputs
run: |
echo "Tusk Task ID: ${{ github.event.inputs.taskId }}"
echo "Tusk Run Type: ${{ github.event.inputs.runType }}"
echo "Tusk Run ID: ${{ github.event.inputs.runId }}"
echo "Current Branch: ${{ github.ref }}"
echo "Repository default branch: ${{ github.event.repository.default_branch }}"
- uses: actions/checkout@v4
with:
ref: ${{ github.ref }}
fetch-depth: 0
- name: Check which files changed
uses: dorny/paths-filter@v3.0.0
id: changes
with:
token: ${{ github.token }}
filters: .github/file-paths.yaml
# Similar to .github/workflows/frontend.yml
- name: Prepare front-end environment
if: steps.changes.outputs.frontend_all == 'true'
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- run: yarn build-pure:cljs
name: Compile CLJS
- name: Run lint-staged
if: steps.changes.outputs.frontend_all == 'true'
run: |
BASE_COMMIT=$(git merge-base origin/${{ github.event.repository.default_branch }} HEAD)
npx lint-staged --shell --no-stash --diff="$BASE_COMMIT...HEAD"
# You must include this step after running all auto-fixing steps
- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "fix(${{ github.run_id }}): auto linting" # The commit message MUST start with "fix(${{ github.run_id }}):"
commit_options: "--no-verify" # No verify because we already ran it above
skip_fetch: true
skip_checkout: true
status_options: "--untracked-files=no"
add_options: "--update"
- name: Check types
if: steps.changes.outputs.frontend_all == 'true'
run: yarn type-check-pure

View File

@@ -44,7 +44,8 @@ jobs:
continue-on-error: true
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
edition: ee
output-name: metabase-ee.jar
- name: Try to fetch existing OSS artifact
@@ -52,7 +53,8 @@ jobs:
continue-on-error: true
uses: ./.github/actions/fetch-artifact
with:
name: metabase-oss-${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
edition: oss
output-name: metabase-oss.jar
- name: Decide if build is needed
@@ -89,9 +91,11 @@ jobs:
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
sparse-checkout: |
release
.github
- name: Prepare release scripts
uses: ./.github/actions/prepare-release-scripts
- name: Get build dependencies
uses: actions/github-script@v7
id: dependencies
@@ -140,7 +144,7 @@ jobs:
- name: Prepare uberjar artifact
uses: ./.github/actions/prepare-uberjar-artifact
with:
name: metabase-${{ matrix.edition }}-${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}-uberjar
edition: ${{ matrix.edition }}
check-jar-health:
runs-on: ubuntu-22.04
@@ -171,7 +175,14 @@ jobs:
- name: Retrieve uberjar artifact
uses: ./.github/actions/fetch-artifact
with:
name: metabase-${{ matrix.edition }}-${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}-uberjar
commit: ${{ github.event.inputs.commit || github.event.pull_request.head.sha || github.sha }}
edition: ${{ matrix.edition }}
- name: Verify license files are present in uberjar
run: |
echo "Checking for license files in uberjar..."
unzip -l ./metabase.jar | grep -q "license-backend-third-party.txt" || (echo "ERROR: license-backend-third-party.txt not found in uberjar" && exit 1)
unzip -l ./metabase.jar | grep -q "license-frontend-third-party.txt" || (echo "ERROR: license-frontend-third-party.txt not found in uberjar" && exit 1)
echo "Both license files found in uberjar"
- name: Launch uberjar
run: >-
java --add-opens java.base/java.nio=ALL-UNNAMED -jar ./metabase.jar &

Some files were not shown because too many files have changed in this diff Show More