Compare commits

...

499 Commits

Author SHA1 Message Date
github-automation-metabase
6f82f1ebb9 🤖 backported "Remove old llms.txt superseded by Jekyll plugin on docs site" (#69134)
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

Co-authored-by: Phoomparin Mano <poom@metabase.com>
2026-02-12 03:47:47 +07:00
github-automation-metabase
27561a4aad 🤖 backported "Added MB_MONITOR_PERFORMANCE option" (#69362) 2026-02-10 16:50:28 -06:00
github-automation-metabase
625948debc 🤖 backported "Don't use the deprecated enable-query-caching value" (#69312)
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.

Co-authored-by: Nathan Voxland <nathan@metabase.com>
2026-02-10 16:20:53 +00:00
github-automation-metabase
13d037e0e3 🤖 backported "Do a rollback before discard all" (#69191) 2026-02-05 20:29:00 +00:00
github-automation-metabase
bb3c617e4e 🤖 backported "[Athena] Correctly recognize :base_type when db type is uppercase" (#69112)
[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.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2026-02-04 15:28:54 +00:00
Stas Gavrylov
8bfe4f9a7c OpenAPI->TS: Compile all changes from master to double-backport (#68841)
* OpenAPI->TS: Compile all changes from master to backport

* Update yarn.lock file

* OpenAPI->TS: Bring OpenAPI Check CI workflow

* Fix missing comma

* Remove unused field from openapi-ts config

* Bring docstring changes from api/common.clj

* Remove unrelated changes from open_api.clj

* Remove unrelated changes from open_api_test.clj

* Update OpenAPI schema (240dd55...d31f28d)

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
Co-authored-by: dpsutton <dan@dpsutton.com>
2026-02-04 11:29:19 +02:00
github-automation-metabase
95b9396a41 🤖 backported "Better error handling in queue listeners" (#69012) 2026-02-03 20:37:44 -06:00
github-automation-metabase
d073436357 🤖 backported "Keep field-values for detail-only fields" (#68817)
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

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
Co-authored-by: dpsutton <dan@dpsutton.com>
2026-02-04 01:00:52 +00:00
github-automation-metabase
0873f2e0c6 🤖 backported "Fix reindex connection management" (#69008)
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.

Co-authored-by: Nathan Voxland <nathan@metabase.com>
Co-authored-by: dpsutton <dan@dpsutton.com>
2026-02-04 00:24:55 +00:00
github-automation-metabase
2319a66e2f 🤖 backported "Bigquery and snowflake failing test QUE-3013" (#69016)
* 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.

* Whitespace

---------

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2026-02-03 17:03:50 -06:00
github-automation-metabase
320b04c0f3 🤖 backported "Search Indexing: Cache card schema upgrades" (#69035)
Search Indexing: Cache card schema upgrades (#68912)

Co-authored-by: Nathan Voxland <nathan@metabase.com>
2026-02-03 22:24:41 +00:00
github-automation-metabase
27df742758 🤖 backported "Case statements with/without defaults" QUE-3013 (#68850)
* 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.

* Fix import problem

---------

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2026-02-03 22:10:40 +00:00
github-automation-metabase
4257006930 🤖 backported "Change log level from info to debug for ignored params on qp" (#68832)
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

Co-authored-by: da <paoliniluis@gmail.com>
Co-authored-by: dpsutton <dan@dpsutton.com>
2026-02-03 19:10:53 +00:00
Nicola Mometto
707d411054 [manual backport] mysql insert-col->val fix (#69007)
backport mysql insert-col->val from a07c3b654e
2026-02-03 17:00:14 +00:00
github-automation-metabase
4e967623b6 🤖 backported "Delete fuzzing workflow" (#68888) 2026-02-03 14:24:58 +13:00
github-automation-metabase
673b299dfb 🤖 backported "implicit joins get implicit fields added" (#68747)
* 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.

* Fix bigquery implicit join tests

* rename dataset to fix caching

* bump tests

* update comments to account for data loading hacks

* make athena tests use current version of test-data

* revert comment changes because of other work

* bump tests

---------

Co-authored-by: William <william@metabase.com>
2026-02-02 08:46:41 -05:00
github-automation-metabase
240dd55dd5 🤖 backported "Flip mariadb during table editing support check" (#68736)
Flip mariadb during table editing support check (#68171)

Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
2026-01-27 17:08:22 +00:00
github-automation-metabase
b7c0de7541 🤖 backported "prometheus metrics for jvm startup" (#68735)
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

Co-authored-by: dpsutton <dan@dpsutton.com>
2026-01-27 16:40:52 +00:00
dpsutton
b0a2e3cdb8 more defensive checking (#68709)
I have a suspicion that the token check query is taking a long
time. Timestamps in some logs are

2026-01-27 00:06:11.561	{"m":"Checking with the MetaStore to see whether token...
2026-01-27 00:06:28.951	{"lvl":"INFO","lgr":"metabase.premium-features.token-check","cluster":"metabase-1","m":"Reporting Metabase stats:
2026-01-27 00:06:28.951
{"lvl":"INFO","lgr":"metabase.premium-features.token-check","cluster":"metabase-1","m":"Reporting
Metabase stats: Cannot throw exception because the return value of \"java.lang.Throwable.getCause()\" is null"

So:
I'm memoizing the token request stats for 2 minutes. This is not long
enough to affect reported numbers, just to make sure that we
successively checking we don't need to hit the db again

and don't rethrow an empty (.getCause e). I don't understand why it
would be empty at all but I'm defensive here and logging
2026-01-27 10:30:03 -06:00
github-automation-metabase
4e4ec4debf 🤖 backported "Don't duplicate uploads in admin page" (#68696)
Don't duplicate uploads in admin page (#68077)

Co-authored-by: Nathan Voxland <nathan@metabase.com>
2026-01-26 21:31:59 +00:00
github-automation-metabase
cae9e8f41c 🤖 backported "try to prevent deadlocks in impersonation tests" (#68694)
try to prevent deadlocks in impersonation tests (#68690)

Co-authored-by: dpsutton <dan@dpsutton.com>
2026-01-26 20:58:07 +00:00
github-automation-metabase
442578ab1b 🤖 backported "Better logging around token checks" (#68689)
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

Co-authored-by: dpsutton <dan@dpsutton.com>
2026-01-26 14:55:55 -06:00
github-automation-metabase
f574132a4d 🤖 backported "Delete from cache in batches of 1000" (#68686)
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.

Co-authored-by: William <william@metabase.com>
2026-01-26 18:06:51 +00:00
Timothy S. Dean
4bbb8e6337 👨 backported "Delete invalid source-card-ids on native SQL questions" (#68576)
* Delete invalid `source-card-id`s on native SQL questions (#68100)

When a user creates a question based on a model, `source_card_id` was set to the model's ID. If that question was later converted to native SQL, `source_card_id` wouldn't get cleared. This means that deleting the model would cause the question to be deleted even though they no longer have any relationship to one another.

The code fix won't help anyone whose data is already incorrect, so this adds a migration to correct the inconsistent data. I added an assertion to the t2 hook to catch this at dev time in the future. And ultimately, the delete cascade seems overkill, so there's a migration to replace that with SET NULL instead.

* Move 057 migrations to 056.
2026-01-24 00:08:06 +00:00
github-automation-metabase
26581fa3ec 🤖 backported "handle empty error message" (#68617)
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

Co-authored-by: dpsutton <dan@dpsutton.com>
2026-01-23 23:59:12 +00:00
github-automation-metabase
b6bfc67f8a 🤖 backported "Tweak data loading behavior for a test after MySQL 9.6.0 release" (#68644)
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.

Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>
2026-01-23 23:33:25 +00:00
github-automation-metabase
97636e8418 🤖 backported "If a dashboard is back to just one tab, auto-assign all cards to that tab" (#68637)
If a dashboard is back to just one tab, auto-assign all cards to that tab (#68201)

Co-authored-by: Nathan Voxland <nathan@metabase.com>
2026-01-23 21:00:22 +00:00
github-automation-metabase
d36ca222e3 🤖 backported "Bump toucan2 version to fix dashboards sometimes failing to load" (#68504)
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.

Co-authored-by: William <william@metabase.com>
2026-01-21 22:20:00 +00:00
github-automation-metabase
e26512d0fe 🤖 backported "Fix flaky test that uses readonly db that lacks permissions" (#68513)
Fix flaky test that uses readonly db that lacks permissions (#68417)

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2026-01-21 21:30:22 +00:00
github-automation-metabase
f848c870cd 🤖 backported "Deduplicate field refs by ignoring :source-field-name unless it matters" (#68486)
Deduplicate field refs by ignoring `:source-field-name` unless it matters (#68166)

* Tentative fix for #67808 -- deduplicate by ignoring :source-field-name if possible

* Make sure `:fields` remains a vector

* Add note

* cljfmt

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2026-01-21 17:54:29 +00:00
github-automation-metabase
f021e1d2af 🤖 backported "Transforms job runs keep trying other transforms if one fails." (#68317)
Transforms job runs keep trying other transforms if one fails. (#68141)

Previously, when running a transform job (e.g., daily), it would fail if a single transform in the run failed. This PR makes it so that the job continues to run transforms that don't depend on any failed transform. As previously, if any transform in the run fails, the job is marked as failed.

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2026-01-21 11:07:41 -06:00
github-automation-metabase
0ee8c79be2 🤖 backported "Fix Horror Show fingerprint OOMs" (#68437)
Fix Horror Show fingerprint OOMs (#68391)

* Fix Horror Show fingerprint OOMs

This may likely fix many OOMs that others are seeing. Anyone with large
schema will likely benefit from this.

```clojure
(let [database (toucan2.core/select-one :model/Database :id 2)]
  (metabase.sync.analyze.fingerprint/fingerprint-fields-for-db!
    database (fn [s t] (println "synced " s "for " (:name t)))))
```

This is how we fingerprint fields. DB 2 here is "Horror Show", a
database with 200 tables, each of which has 900 fields in it. This
database has zero rows in it, it it just a large schema.

Syncing this recently has caused huge cpu spikes and then OOM errors
until the instance is killed.

Profiling locally with

```
MB_JETTY_PORT=3091 java "$(socket-repl 6091)" -Xmx2g -jar metabase.jar
```
and visual vm hooked up, I run

```clojure
(let [database (toucan2.core/select-one :model/Database :id 2)]
  (metabase.sync.analyze.fingerprint/fingerprint-fields-for-db!
    database (fn [s t] (println "synced " s "for " (:name t)))))
```

And observe this behavior:
The ram usage approaches the 2gb limit and then bounces there. The CPU
begins to spike erratically and spend 10% of its time in GC.

Taking a heap dump we can see that we have 2.8 million ResultSetMetaData
objects occuping 183 Mb.

The ResultSetMetaData are closed over and kept in the metadata of the
snake hating maps stored in the cached metadata provider.

This brings into stark relief one simple way to fix this: don't use a
caching metadata provider. This PR just raising the body of the
fingerprint-tables-for-db function to not include
`(qp.store/with-metadata-provider (u/the-id database)` . There is no
benefit to caching here as this is an enumeration of the database. It is
by design not meant to reuse anything. If we didn't OOM we would end up
with 200 tables and 200*900 = 180,000 fields in the cache, each of which
was accessed only once.

That is what this PR fixes.

I also followed one other thread: why are we holding so many
ResultSetMetaData objects in memory. This seems to come about from a
change in https://github.com/metabase/metabase/pull/62330 specifically
this line:
https://github.com/metabase/metabase/blob/master/src/metabase/lib_be/metadata/jvm.clj#L63

```clojure
(mu/defn instance->metadata
  "Convert a (presumably) Toucan 2 instance of an application database model with `snake_case` keys to a MLv2 style
  metadata instance with `:lib/type` and `kebab-case` keys."
  [instance      :- :map
   metadata-type :- :keyword]
  (let [normalize (if-let [schema (get metadata-type->schema metadata-type)]
                    (fn [instance]
                      (lib.normalize/normalize schema instance))
                    identity)]
    (-> instance
        (perf/update-keys memoized-kebab-key)
        (assoc :lib/type metadata-type)
        normalize
        u.snake-hating-map/snake-hating-map
        ;; the line below here captures the result coming back from
        ;; toucan and has a closure over
        ;; toucan2.jdbc.read/make-column-thunk which has a closure over
        ;; (.getMetaData rset)
        (vary-meta assoc :metabase/toucan-instance instance))))
```

As it stands without any changes, the instance gets quite unstable and
falls over. If you comment out the `var-meta` form above, the graph
returns to a very normal sawtooth graph of memory usage and
reclaimation. But central to this is that it does not need to retain any
of this memory at all. But without this metadata containing the instance
and db classes, we only cache the table and field data and the
fingerprinting can finish. When we cache this stuff and also
inadvertently keep these db classes, we quite quickly run out of
headroom and the instance becomes unstable and falls over.

* fix kondo lint (removes a legacy usage as well :) 💰

Co-authored-by: dpsutton <dan@dpsutton.com>
2026-01-21 16:29:48 +00:00
github-automation-metabase
ef060d829c 🤖 backported "Prevent exception in cleanup masking the original exception" (#68472)
Prevent exception in cleanup masking the original exception (#68371)

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2026-01-21 15:28:51 +00:00
github-automation-metabase
d4cafa2108 🤖 backported "Custom ref schema that reuses the cache" (#68458)
Custom ref schema that reuses the cache (#68379)

Add ref schema caching

Introduces a custom :ref IntoSchema that permits
reuse of Schema objects for references when safe to do so.

Early tests indicate a dramatic reduction in heap retention, after
loading a single dashboard, I see a 10x resident heap reduction from ~300MB to ~30MB.

It should also act as knot tie / runtime combinatorics limiter, so we should not see 'leaky' growth at runtime.

More work could be done as there are still _some_ gaps here.
- Bare pointers (keywords) can still lead to exponential allocation
- We do not cache when :documentation is present on the ref
  (as it would specialise the Schema object delivered for that specific reference)

Co-authored-by: Dan Stone <wotbrew@gmail.com>
2026-01-21 11:01:01 +00:00
Edward Paget
ca329483c0 Fix: Actions attached to models inside of Library(synced collection) break remote sync (#68252) (#68430)
Fixes #68215

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

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Claude Code[bot] <noreply@anthropic.com>
Co-authored-by: Ed Paget <ed@metabse.coma>
2026-01-20 15:34:38 -08:00
github-automation-metabase
e948f51e30 🤖 backported: implicit join UNIX coercion fix (#67704) -&- implicit join breakout fix (#67480) (#68314)
Backport for both #67480 and #68164

Co-authored-by: Timothy Dean <timothy@timothydean.dev>
2026-01-19 10:32:50 -07:00
github-automation-metabase
215a22e578 🤖 backported "Report datetime insights even if columns is PK or FK" (#68359)
Report datetime insights even if columns is PK or FK (#67536)

Closes #35281

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2026-01-19 16:26:10 +00:00
github-automation-metabase
1b73e01f9f 🤖 backported "Use Soft/Weak references for malli cache entries" (#68340)
Use Soft/Weak references for malli cache entries (#68076)

Co-authored-by: Dan Stone <wotbrew@gmail.com>
2026-01-19 14:48:13 +00:00
github-automation-metabase
7b55c76cbe 🤖 backported "Fix flaky assertion for "sdk iframe embedding fires ready event after iframe is loaded"" (#68346)
Fix flaky assertion for "sdk iframe embedding fires ready event after iframe is loaded" (#68336)

Co-authored-by: Phoomparin Mano <poom@metabase.com>
2026-01-19 13:00:34 +00:00
github-automation-metabase
eadec9c77f 🤖 backported "Fix filters not closing properly on native SQL questions" (#68258)
Fix filters not closing properly on native SQL questions (#68216)

Co-authored-by: kevinkelleher12 <kevin.kelleher@metabase.com>
2026-01-15 21:36:31 +00:00
github-automation-metabase
38338eb110 🤖 backported "Log error instead of warning if a subscription is not sent through the channel rather than a warning" (#68245)
Log error instead of warning if a subscription is not sent through the channel rather than a warning (#68214)

* Why is it a warning when it should be an error?

* Fix error logging format in notification worker

* Improve error logging in notification send process

Fix silly mistakes that I do when I'm sleepy

Co-authored-by: da <paoliniluis@gmail.com>
2026-01-15 17:14:17 +00:00
github-automation-metabase
2d4fdacba1 🤖 backported "Cleanup additional space to properly build Sample Apps" (#68233)
Cleanup additional space to properly build Sample Apps (#68229)

Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2026-01-15 13:54:23 +00:00
github-automation-metabase
0b4d45a57e 🤖 backported "Uxw 2596 color range on table crashes it if values span a large scale" (#68134)
Uxw 2596 color range on table crashes it if values span a large scale (#68022)

# Conflicts:
#	e2e/test/scenarios/models/models-list-view.cy.spec.js
#	jest.config.js
#	jest.tz.unit.conf.js
#	yarn.lock

Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2026-01-15 10:36:56 +01:00
github-automation-metabase
4fedb3dc8f 🤖 backported "Increase verbosity in the caching middleware" (#68206)
Increase verbosity in the caching middleware (#68121)

* Increase verbosity in the caching middleware

* Fix linter

* Make it simpler

* Broke so many tests

* Make the linter happy

* Fix tests (going back to old implementation)

Co-authored-by: da <paoliniluis@gmail.com>
2026-01-14 21:42:36 +00:00
github-automation-metabase
f1c4f2d07a 🤖 backported "Cache Main App/Embed JS fonts" (#68203)
Cache Main App/Embed JS fonts (#68120)

Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2026-01-14 20:30:37 +00:00
Alexander Polyankin
ac345f85ff Fix: Having : as a special character in the DB name breaks the UI for Clickhouse (#68013)
Fix: Having : as a special character in the DB name breaks the UI for Clickhouse (#68013)
2026-01-14 13:44:13 -05:00
github-automation-metabase
891a14357b 🤖 backported "UXW-2586: Acquire locks before changing data permissions" (#68074)
UXW-2586: Acquire locks before changing data permissions (#67201)

* Acquire locks before changing data permissions

Data permission have a read-modify-write cycle:

- we read the existing permissions to see what's currently set
- then we decide what to do (e.g. delete the existing DB level
  permissions to write a granular table-level permission)
- then we do the write

This has a race condition if multiple Metabase instances are modifying
permissions at the same time.

For example, say we have:

Initial state: `{:db_id 1 :table_id nil :perm_value :unrestricted}`

Instance A: set table 1 to :blocked
Instance B: set database to :blocked

T1: A reads state, sees db-level permission, plans to expand to table-level
T2: B reads state, sees db-level permission, plans to replace it
T3: A deletes db-level, inserts table-level rows for all tables
T4: B deletes db-level (no-op), inserts new db-level :blocked

Result (CORRUPT):
```
{:db_id 1 :table_id 1 :perm_value :blocked}      ;; from A
{:db_id 1 :table_id 2 :perm_value :unrestricted} ;; from A
{:db_id 1 :table_id nil :perm_value :blocked}    ;; from B
```

Both db-level AND table-level permissions now exist.

For the permissions API, we take a cluster lock, but sync operations
bypassed this cluster lock. This PR creates a lower-level cluster lock
per `[database, group, perm-type]` so only one instance/thread can do
the read/decide/write cycle for a particular db/group/perm at a time.

* Add a test for race conditions setting data perms

This took a while before I was able to track down the fact that using
`(mt/with-temp )` caused both threads to share the same connection, so
they could obtain the lock simultaneously 🤦

* Use a slightly coarser lock

I realized that if an instance has a huge number of groups, we'll obtain
a lock and ask Postgres to maintain an active savepoint for each group,
which might be untenable.

I think the best solution here is to use slightly coarser locks. This
might increase contention slightly, since we won't be able to change
permissions for `db 1, group 1, perm type view-data` at the same time
that we change permissions for `db 1, group 2, perm type view-data`. But
I think the tradeoff here is necessary.

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-01-14 07:14:49 -08:00
github-automation-metabase
ffca85b8bb 🤖 backported "Disable regex lookaheads/lookbehinds for Snowflake driver" (#68094)
Disable regex lookaheads/lookbehinds for Snowflake driver (#68084)

Co-authored-by: bryan <bryan.maass@gmail.com>
2026-01-13 18:13:09 +00:00
github-automation-metabase
f60f26b5f2 🤖 backported "If the entity id is unknown when calling the export API, throw an error" (#68099)
If the entity id is unknown when calling the export API, throw an error (#68040)

Co-authored-by: Nathan Voxland <nathan@metabase.com>
2026-01-13 00:00:01 +00:00
github-automation-metabase
efed959587 🤖 backported "fix: limit can_run_adhoc_query hydration" (#68033)
fix: limit can_run_adhoc_query hydration (#68028)

We can't hydrate unbounded collections of cards with the
can_run_adhoc_query hydration since it linearly adds db queries to the
request. Users with > 10000k can have severe CPU/memory issues
processing this.

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2026-01-12 15:46:19 -06:00
github-automation-metabase
692749b697 🤖 backported "UXW-64 Fix table cell formatting for temporal breakout by week" (#68089)
UXW-64 Fix table cell formatting for temporal breakout by week (#67477)

* UXW-64 Fix table cell formatting for temporal breakout by week

* Review fixes

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2026-01-12 21:37:56 +00:00
github-automation-metabase
06acac4e8c 🤖 backported "Fix funnel viz to handle increasing data" (#68082)
Fix funnel viz to handle increasing data (#68031)

Co-authored-by: kevinkelleher12 <kevin.kelleher@metabase.com>
2026-01-12 18:31:46 +00:00
github-automation-metabase
cee02f53bb 🤖 backported "fix(sdk): fix crashes on React 19 due to findDOMNode on Gauge and Modal" (#68059)
fix(sdk): fix crashes on React 19 due to findDOMNode on Gauge and Modal (#67953)

Co-authored-by: Phoomparin Mano <poom@metabase.com>
2026-01-12 12:28:32 +00:00
github-automation-metabase
67a3c78675 🤖 backported "Avoid joins of remote_sync_object with actual tables" (#67655) 2026-01-09 12:12:58 -06:00
github-automation-metabase
b469b1271f perms for moving collections with archived kids (#67728) (#67987)
Previously if you had:

```
A (curate)
  B (curate)
    C (no permissions)
      D (curate)
```

Then if C was archived, you would be unable to move or archive A or
B.

Co-authored-by: John Swanson <john.swanson@metabase.com>
2026-01-09 16:51:33 +00:00
github-automation-metabase
72b5bf6305 Update llms.txt and llms-full.txt (release-x.57.x) (#67990)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <actions@github.com>
2026-01-09 15:51:45 +00:00
github-automation-metabase
b6ffcf55ef fix(embed-js, sdk): Properly handle restricted collection access in MetabaseBrowser (#67907)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2026-01-08 18:54:42 +04:00
github-automation-metabase
0c78cc4bd5 Fix flaky "shows a static dashboard using drills" e2e (#67874) (#67911)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2026-01-08 13:58:49 +00:00
Nicolò Pretto
67d1219642 chore(sdk): checklist steps for 58 release on the release 57 branch (#67861)
* chore(sdk): checklist steps for 58 release on the release 57 branch

* remove unused input

* fix typo

* remove from summary too
2026-01-08 14:10:48 +01:00
github-automation-metabase
b7b3ca2932 chore(sdk): move setting cypress baseUrl to global beforeEach for sdk tests (#66308) (#67547)
Co-authored-by: Nicolò Pretto <info@npretto.com>
2026-01-07 12:47:31 +01:00
github-automation-metabase
8086f8ccbb Fix pie chart label not visible on dark theme (#67639) (#67791)
* Fix `text-secondary` not working on dark theme on charts

* Support all colors so it's easier to reason about

* Add tests

* Fix type error

* Revert part of the code that's not used anymore

* Add test snapshots

* Make overriding font more consistency across environments

e.g. From storybook to SDK to the main app.

* Fix formatting

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
2026-01-07 02:40:45 +00:00
github-automation-metabase
fe1094c76d Add a tooltip message if model persistence is unsupported for a database (#67566) (#67828)
Co-authored-by: Phoomparin Mano <poom@metabase.com>
2026-01-06 21:39:25 +00:00
github-automation-metabase
3a3440afbc 🤖 backported "[Metabot] Metabot error boundary" (#67803)
* [Metabot] Metabot error boundary (#67749)

* fix icon sizing issue

---------

Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
Co-authored-by: Sloan Sparger <sloansparger@gmail.com>
2026-01-06 14:46:56 -06:00
github-automation-metabase
8208922941 Fix MB in an iframe running on a subpath (#67724) (#67788)
* fix MB in an iframe running on a subpath

* fix

* extracted out the util fn and added unit tests for it

* addressed comments

* fixed unit tests

Co-authored-by: Sébastien <sebastien@metabase.com>
2026-01-06 16:34:58 +01:00
github-automation-metabase
cfaa19f095 backported "fix(embed-js, sdk): Don't close InteractiveQuestion editor on Filters change"
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2026-01-06 13:07:11 +04:00
github-automation-metabase
2b7598d459 Fix parsing of :ERROR chunks in metabase-enterprise.metabot-v3.util/aisdk->messages (#67674) (#67758)
* Fix parsing of :ERROR chunks in metabase-enterprise.metabot-v3.util/aisdk->messages

There was a typo in the case expr where :ERROR chunks were being handled like :DATA chunks, but in fact should be
handled like :TEXT chunks. This was resulting in an error like

    1. Unhandled java.lang.ClassCastException
       class java.lang.String cannot be cast to class
       clojure.lang.Associative (java.lang.String is in module java.base
       of loader 'bootstrap'; clojure.lang.Associative is in unnamed
       module of loader 'app')
                       RT.java:  847  clojure.lang.RT/assoc
                      core.clj:  193  clojure.core/assoc
                      core.clj:  192  clojure.core/assoc
                      util.clj:   56  metabase-enterprise.metabot-v3.util/aisdk->messages/fn/fn
                      ...

whenever an :ERROR chunk was encountered as we tried to ASSOC a string where we were expecting a map.

https://v4.ai-sdk.dev/docs/ai-sdk-ui/stream-protocol#text-part
https://v4.ai-sdk.dev/docs/ai-sdk-ui/stream-protocol#error-part

059d904d6e/ai_service/ai_sdk.py (L50)
059d904d6e/ai_service/ai_sdk.py (L203)
059d904d6e/ai_service/ai_sdk.py (L324)

* Add some error chunk parsing tests to aisdk-line-parse-test

* Mark aisdk-line-parse-test as ^:parallel

This does io to read some files, but should be threadsafe as no other tests read or modify those files.

* Add make-mock-error-stream-response test util

And rename make-mock-stream-response to make-mock-text-stream-response

* Add client-error-test to test streaming-request with error chunks in response

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
2026-01-06 00:40:24 +00:00
github-automation-metabase
aa79ea6c20 Patch malli to avoid OOM related to recursive memoization (#67733) (#67743)
This is a temporary fix until https://github.com/metosin/malli/pull/1250 gets merged into Malli.
2026-01-06 00:42:30 +03:00
github-automation-metabase
6f267eb753 Handle unroutable token checks (#67698) (#67735)
We have a grace periods and circuit breakers for token checks. But one
issue is that if the token check doesn't throw an error we can't catch
it.

An easy way to see this is to use a local network address that won't
respond like 192.168.random.random (i used 192.168.40.40) then see the
behavior. Without the timeouts, the threads all just get stuck here and
the page never loads. With timeouts, you'll see a few stutters until the
circuit breaker steps in, at which point you have a non-enterprise
version.

https://www.loom.com/share/6ae056dc126b48c9abe8a7ad9366fd05

Co-authored-by: dpsutton <dan@dpsutton.com>
2026-01-05 21:41:37 +00:00
github-automation-metabase
9353943af9 [Metabot] Update Metabot icon (#67741) (#67751)
Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2026-01-05 19:59:20 +00:00
github-automation-metabase
11a1620ad6 Clarify permissions model for suggested prompts generation (#67656) (#67740)
* Run suggested prompts generator as admin & fix test

* Add a prompt suggestions GET perms test

* small cleanups

* use mbql5

Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
2026-01-05 19:51:07 +00:00
github-automation-metabase
736177bb59 Measure all columns to provide expand option (#67429) (#67509)
Co-authored-by: Fraser <fraser@metabase.com>
2026-01-05 23:22:27 +13:00
github-automation-metabase
62b0bcc458 Improve formatting and clarity in serialization.md (#67587) (#67690)
Updated curl command formatting and clarified instructions for exporting and importing Metabase data.

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2026-01-02 15:44:38 +00:00
github-automation-metabase
4b6908ba18 Extra remapped fields (#67601) (#67664)
* kick ci

* Disable remaps when calculating columns for a query.

* Add tests for result_metadata remappings

* Add comments

* Whitespace

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-31 20:25:53 +00:00
github-automation-metabase
fee4df8a63 [dashboards] Handle parallel FKs with dashboard filter values (#66287) (#67662)
Fixes #65838.

This issue was about dashboard filters showing the wrong value when
the filter was bound to an FK field from a table with multiple FKs to
the same foreign table. The dashboard parameters logic on the BE was
choosing which FK to use for the filter values arbitrarily, meaning that
binding the filter to one of them would work fine, but the other would
give incoherent results.

The fix is to be deliberate about selecting the parameter's column. That
doesn't solve all ambiguous cases, but we really can't help if there's
a multi-hop join that has parallel edges in the middle!

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-12-31 17:35:26 +00:00
github-automation-metabase
f2746fe3c9 Hopeful fix for the ooms that betterment is running into. (#67482) (#67589)
* Hopeful fix for the ooms that betterment is running into.

Note that this will only work once macaw is updated and metabase is using the new version of macaw.  Until that
happens, this change is a noop.

* bump macaw for context stripping

https://github.com/metabase/macaw/pull/123

here's the gist:

```clojure
core-test=> (let [base {:select [:a :b :c]
                        :from   [:foo]
                        :where  [:= :foo.a [:inline "baz"]]}]
              (-> {:union-all (for [_ (range 3)]
                                base)}
                  sql/format
                  first
                  (components {:strip-contexts? true})
                  :columns
                  ))
                  ;; replacing #{} with <set> so git doens't comment it out
<set>{{:component {:table "foo", :column "a"}}
  {:component {:table "foo", :column "b"}}
  {:component {:table "foo", :column "c"}}}
core-test=> (let [base {:select [:a :b :c]
                        :from   [:foo]
                        :where  [:= :foo.a [:inline "baz"]]}]
              (-> {:union-all (for [_ (range 3)]
                                base)}
                  sql/format
                  first
                  (components )
                  :columns
                  ))
                  ;; replacing #{} with <set> so git doesn't comment it out
 <set>{{:component {:table "foo", :column "b"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "a"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "a"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "a"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x4de719cd "com.metabase.macaw.AstWalker$ScopeInstance@4de719cd"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x76f86e4f "com.metabase.macaw.AstWalker$ScopeInstance@76f86e4f"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "c"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "b"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x1241e96a "com.metabase.macaw.AstWalker$ScopeInstance@1241e96a"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "a"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x542edf1d "com.metabase.macaw.AstWalker$ScopeInstance@542edf1d"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x2e474cfd "com.metabase.macaw.AstWalker$ScopeInstance@2e474cfd"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "b"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "a"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x459ed576 "com.metabase.macaw.AstWalker$ScopeInstance@459ed576"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x38a0b358 "com.metabase.macaw.AstWalker$ScopeInstance@38a0b358"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x1241e96a "com.metabase.macaw.AstWalker$ScopeInstance@1241e96a"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "c"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "a"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x1241e96a "com.metabase.macaw.AstWalker$ScopeInstance@1241e96a"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}
  {:component {:table "foo", :column "c"},
   :context
   (#object[com.metabase.macaw.AstWalker$ScopeInstance 0x1241e96a "com.metabase.macaw.AstWalker$ScopeInstance@1241e96a"]
    #object[com.metabase.m
acaw.AstWalker$ScopeInstance 0x6343d805 "com.metabase.macaw.AstWalker$ScopeInstance@6343d805"]
    #object[com.metabase.macaw.AstWalker$ScopeInstance 0x761965fc
    "com.metabase.macaw.AstWalker$ScopeInstance@761965fc"])}}
```

---------

Co-authored-by: William <william@metabase.com>
Co-authored-by: dan sutton <dan@dpsutton.com>
2025-12-30 15:04:13 -06:00
github-automation-metabase
0489d1d332 bumping deps: (#67638) (#67644)
- https://github.com/metabase/metabase/security/code-scanning/543
  about snowflake's of grpc netty shaded. We already have this
  version elsewhere so now it matches
- https://github.com/metabase/metabase/security/code-scanning/549
  and https://github.com/metabase/metabase/security/code-scanning/557
  issue in databricks. We bumped that and now it uses the new coordinate
  `at.yawk.lz4/lz4-java 1.10.1`
- https://github.com/metabase/metabase/security/code-scanning/496 bump commons-lang3.
  actually just exclude it from the driver jar so it will be found on parent
  classpath with coordinate from deps.edn: `{:mvn/version "3.19.0"}`

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-30 11:53:05 -06:00
github-automation-metabase
a20a359982 bump log4j (#67393) (#67641)
* bump log4j

* bump snowflake in hope of clearing advisory

https://github.com/metabase/metabase/security/code-scanning/543

> This file introduces a vulnerable io.grpc:grpc-netty-shaded package
> with a high severity vulnerability.

* bump netty shaded

https://github.com/metabase/metabase/security/code-scanning/543

* bump aws s3 for io.netty:netty-codec-http2

https://github.com/metabase/metabase/security/code-scanning/536

before bump:
    . io.netty/netty-codec-http2 4.1.126.Final

after dump:
❯ clj -X:deps tree :extra '{:deps {software.amazon.awssdk/s3 {:mvn/version "2.40.13"}}}' | grep http2
    . io.netty/netty-codec-http2 4.1.130.Final

* bump netty-codec-http

from software.amazon.awssdk/s3

before:
    . io.netty/netty-codec-http 4.1.126.Final

https://github.com/metabase/metabase/security/code-scanning/534

* bump athena to 3.7.0

ran workflow at
https://github.com/metabase/metabase/actions/runs/20439789522/job/58729767910

https://github.com/metabase/metabase/actions/workflows/athena.yml to
publish the 3.7.0 version

* include driver change to force running drivers

* sort deps edn

* attempt to solve l4z issues

weirdness is that this version might move some stuff? we'll see if it
works.

* Revert "attempt to solve l4z issues"

This reverts commit 03d845eeea.

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-30 11:33:44 -06:00
github-automation-metabase
d4fcaabb1e Normalize aggregation references, sort maps and remove all uuids (#67521) (#67611)
* Normalize aggregation references, sort maps and remove all uuids

Fixes QUE-2916

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-12-30 11:00:02 -05:00
github-automation-metabase
dd0eef05c7 Fix empty cards with no results making dashboard longer than expected (#67581) (#67633)
* Prevent unnecessary height calculation

* Prioritize local layout from `react-grid-layout` for height calculation

* Refix the issue for real

* Add tests

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-12-30 13:21:15 +00:00
github-automation-metabase
b3ddf95055 fix: hide editing toggle for unsupported engines (#67564) (#67629)
* fix: hide untested and unsupported db engines in table editing section

* move allowed engines to constants file

* test: add hidden editing toggle test case

Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2025-12-30 11:19:08 +00:00
github-automation-metabase
190ce77239 Update generated docs (release-x.57.x) (#67621)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-30 00:05:26 -05:00
github-automation-metabase
b2527d01ca Re-introduce: Upload failed e2e test artifacts for quarantined tests (#67600) (#67607)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-12-29 21:39:51 +00:00
github-automation-metabase
2166857f8d Fix model metadata e2e flake (#67522) (#67597)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-12-29 18:52:31 +00:00
github-automation-metabase
479fe86c3f Fix object detail flake #39477 (#67442) (#67596)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-12-29 18:47:23 +00:00
github-automation-metabase
1e04c9106b Default to base-type when it differs from effective type (#67486) (#67591)
* Default to base-type when it differs from effective type

* Make 'er parallel

* Does this clause make it better?

* Remove parallel.

* New test and fix for two literals

* Use y-type for effective type

* Update test to try number

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-29 18:26:42 +00:00
github-automation-metabase
bda89fc3c1 Disable nonworking email and URL extractions for BigQuery and 7 other broken drivers (#66982) (#67472)
* Add failing test for #63822, DEV-1190

* Add new feature flag

* Update FE config

* Fix tests 🔧

* Disable for 7 more drivers

* Fix MySQL + MariaDB

* Fix TypeScript

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-29 10:23:21 -08:00
github-automation-metabase
0688646ae1 fix: custom home page settings are not being exported (#67550) (#67579)
* fix: custom home page settings are not being exported

* fix: update seralization baseline test

Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2025-12-29 10:02:17 +00:00
github-automation-metabase
bffaefa18c Prevent black background loaded with light full-app embedding (#67544) (#67553)
* Prevent black background loaded with light full-app embedding

* Fix tests

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-12-26 13:53:23 +00:00
github-automation-metabase
f03c1a9dea note on SQL download perms (#67464) (#67558)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-26 13:06:12 +00:00
github-automation-metabase
513dd9ec43 fix(sdk-package, sdk-bundle, embed-js): Don't expose question in SDK's entityTypes (#67534) (#67543)
* Don't expose `question` in SDK's `entityTypes`

Because it's only applicable to staged picker

* Fix type

* Clarify the use of `question` in SDK's `entityTypes`

* Fix SDK not building

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-12-26 11:00:46 +00:00
github-automation-metabase
13aff097b0 Use actual metadata in a Notebook in Embedding SDK/Embed JS (#67453) (#67532)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-12-25 12:07:32 +00:00
github-automation-metabase
cb53bf6447 fix: add filter clauses to support min max required for age binning (#67448) (#67529)
Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2025-12-25 11:19:14 +00:00
github-automation-metabase
ed2066d458 Apply field settings to parameter field widget (#67428) (#67498)
Co-authored-by: Fraser <fraser@metabase.com>
2025-12-25 07:42:18 +00:00
github-automation-metabase
90d36153b7 Custom headers (#67502) (#67515)
* added vars
* added tests

Co-authored-by: Roman Abdulmanov <roman@metabase.com>
2025-12-24 15:05:34 +00:00
github-automation-metabase
5d27dfdd11 fix: respect time format in exclude date picker filter QUE-2611 (#67384) (#67505)
* fix: respect time format in exlude date picker filter QUE-2611

* rework: move constant out of function body

* test: fix failing tests due to lack of redux provider

* fix: add missing redux  provider in story

* test: improve testing logic for ExcludeDatePicker

* internal: use specialized useSetting hook

* test: adjust looping with async action

Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2025-12-24 10:14:21 +00:00
github-automation-metabase
338e01e925 Check that the number was parsed correctly (#67403) (#67459)
* Check that the number was parsed correctly

* Don't parse int columns that are remapped

* oops, remove old change

* Better fix and specific test

* kick ci

* kick ci

* Make sure it still hits the bigint branch

* Move check into parseNumber()

* Move check back to value.tsx

* Single describe in tests

* Add blank lines (fe-lint)

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-23 17:00:28 +00:00
metamben
bee49a0766 Add debug logging to the OOM path (#67455) 2025-12-23 16:28:55 +00:00
github-automation-metabase
2467fae4bb Docs: Metabot inline SQL editing (#67362) (#67434)
* Docs: inline SQL editing

* Optimized 1 images, saved 35.9 KB (13.6% smaller)

* typos

* Update docs/ai/metabot.md



* Update docs/ai/metabot.md



* Update docs/ai/metabot.md



* small edit

---------

Co-authored-by: Abed Habli <154609371+abdhabli@users.noreply.github.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-23 09:16:52 +00:00
github-automation-metabase
d8ca7ad088 Fix adding two DIFFERENT implicit joins with the SAME generated alias (#67411) (#67423)
* Fix adding two DIFFERENT implicit joins with the same generated alias

* Part 2 of #67411 fix

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-23 02:41:43 +00:00
github-automation-metabase
a390d266af Allow temporal args for - (#67397) (#67406)
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-23 00:28:55 +00:00
github-automation-metabase
31f72b07a4 [Metabot] Natural language query entry point (#66737) (#67383)
* prototype

* open chat sidebar on navigate

* update copy for new route

* use nlq profile and make sticky, redirect to empty query builder if no navigate_to is recieved

* responsiveness

* move code to enterprise folder

* imple error states, better loading state

* handle user leaving the page while a response is being loaded

* lint fix, change inline sql shortcut key, disable prompt suggestions and fade out once a prompt has been sent

* fix e2e test

* add test coverage, update copy

* fix failing e2e tests

* attempt to fix e2e flake

Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2025-12-22 17:48:12 -06:00
github-automation-metabase
c571d7d128 🤖 backported "fix: improve search performance with tables" (#67108)
* fix: improve search performance with tables (#67055)

* fixup! delete extra specs

---------

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
2025-12-22 14:37:18 -08:00
github-automation-metabase
e5d179f379 Log each entity as it gets dependency-backfilled at debug level (#67378) (#67398)
Log each entity (card) as its dependencies get backfilled by the job. This is to be able to see if there is a particular entity that's causing the OOM.

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-12-22 21:54:14 +00:00
github-automation-metabase
0c6e3db6fd Update generated docs (release-x.57.x) (#67353)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-22 12:41:19 -05:00
github-automation-metabase
4bbe7e98f1 Allow arbitrary expressions inside :is-null and :not-null in MBQL 4 schema (#67326) (#67348)
* Support arbitrary expressions inside `:is-null` and `:not-null`

* Remove unnecessary blank line in schema_test.cljc

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-21 23:13:22 +00:00
github-automation-metabase
89bced14da Allow :aggregation refs inside (aggregation) expressions in MBQL 4 schema (#67311) (#67343)
* Allow :aggregation refs inside expressions in MBQL 4 schema

* Test + Kondo fix

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-21 14:11:55 -08:00
github-automation-metabase
1857a7ac26 Use snake_case for MetabotCodeEdit and MetabotCodeEditorBufferContext fields (#67231) (#67335)
For consistency with other types shared between metabase and ai-service.

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
2025-12-20 00:48:29 +00:00
github-automation-metabase
c1652979f7 [Metabot] Inline SQL entry point (#66688) (#67329)
Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2025-12-19 18:17:58 -06:00
github-automation-metabase
b956d92a1a MBQL 4 => MBQL 5 conversion should ignore invalid expressions (#67305) (#67324)
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-20 00:06:35 +00:00
github-automation-metabase
18144d4d3c [Metabot] Multi-convo support (#66864) (#67313)
Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2025-12-19 17:12:35 -06:00
github-automation-metabase
481847ed1d Fix trend lines when aggregating by datetime (#65873) (#67299)
Co-authored-by: Nathan Voxland <nathan@metabase.com>
2025-12-19 21:03:03 +00:00
github-automation-metabase
8efc7029f9 Add mbql time schema test (#67182) (#67206)
* Add test

* Move test to temporal-test

* Openapi json

* Add second time string

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-19 17:30:07 +00:00
github-automation-metabase
1054d88ef2 Resolved conflicts (#67176)
Co-authored-by: Nathan Voxland <nathan@metabase.com>
2025-12-19 11:10:09 -06:00
github-automation-metabase
ecec82ba43 Don't do implicit joins through sensitive FKs (#67056) (#67193)
* WIP

* Working test! (it reproduces)

* Fhew! I found it!

* Remove printlns

* Also remove sensitive fks in calculation

* Remove stray marker comment

* Move tests to fields-test

* Exclude :retired too

* Move tests and add one for retired

* Add another retired

* Better tests

* Appease the kondo

* Fix broken test

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-19 16:22:30 +00:00
github-automation-metabase
9a7a8ad739 Cleanup docker build caches when building sample apps on CI (#67268) (#67286)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-12-19 16:20:33 +00:00
github-automation-metabase
b7e9d0aad9 Several MBQL 4 normalization fixes 🔧 (#67203) (#67233)
* Fix normalization of MBQL 4 `:aggregation-options` with a `nil` options map

* Update tests

* Fix normalization of Template Tag :options

* Allow raw values as expression definitions

* Automatically remove :ident from joins

* Properly handle aggregations expressions that contain `:if` (alias for `:case`)

* Allow `:coalesce`, `:if`, and `:case` as datetime exprs in MBQL 4

* Test & Kondo fixes 🔧

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-18 18:06:23 -08:00
github-automation-metabase
8fb3ddd4b6 Fix grammar of billing period for Metabase AI (#67191) (#67217)
Fixes: 2b76c38e1f
Closes: https://github.com/metabase/metabase/pull/67053#issuecomment-3671353062

Co-authored-by: Dennis Schridde <63082+devurandom@users.noreply.github.com>
2025-12-18 22:02:32 +00:00
github-automation-metabase
0e7e4a5319 Remove models and metrics section from settings (#67174) (#67198)
Removed section on adding models and metrics to Metabot collection.

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-18 18:56:53 +00:00
github-automation-metabase
fd6a2deadf Change Metabase AI price to be based on quantity for whole billing period (#67053) (#67187)
### Description

We want to communicate per-billing-period quantities with customer, instead of always communicate monthly quantities.  Invoiced totals will stay the same.

### How to verify

Describe the steps to verify that the changes are working as expected.

1. Ensure you have a token with the `offer-metabase-ai-tiered` feature, but without the `metabot-v3` feature.
2. Navigate to `/admin/metabot` and see the quantities as per billing period, and not per month.

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

Fixes: 2b76c38e1f
Closes: https://metaboat.slack.com/archives/C07RMUQ0GE5/p1765907134400039

Co-authored-by: Dennis Schridde <63082+devurandom@users.noreply.github.com>
2025-12-18 13:13:15 -05:00
github-automation-metabase
6cdc5d5768 Update generated docs (release-x.57.x) (#67144)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-18 02:45:15 +00:00
github-automation-metabase
5f4b2b02b2 collection-id only works with shallow=true (#64476) (#66971)
Document that we only use `collection-id` when `shallow=true`.

Co-authored-by: John Swanson <john.d.swanson@gmail.com>
2025-12-17 16:48:17 -08:00
github-automation-metabase
e8409d133d 🤖 backported "UXW-2451 Fix opposite light/dark mode colors leaking when table is present" (#67101)
* UXW-2451 Fix opposite light/dark mode colors leaking when table is present (#67017)

* WIP UXW-2451 Fixes issue where changing light/dark mode messes up color variables by removing nested providers in useBodyCellMeasure which probably breaks other things

* Update Loki Snapshots

---------

Co-authored-by: Metabase Automation <github-automation@metabase.com>

* Update Loki Snapshots

---------

Co-authored-by: Brad Anderson <brad@metabase.com>
2025-12-17 15:05:14 -05:00
github-automation-metabase
8121fba901 Manage Table Metadata permission is enough to sync table schema (#65866) (#67045) 2025-12-17 13:22:39 -06:00
github-automation-metabase
a2a85750cc [o11y] Log + metrics for lib.convert/clean making material changes (#67094) (#67098)
This generally indicates an MBQL 4 -> 5 conversion issue, and we need
the signal in the 57 rollout.

Also improves the detail of the logging for when `:dataset_query {}`.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-12-17 17:47:56 +00:00
github-automation-metabase
26b3151114 docs - australia (#67039) (#67092)
* Add Australia (Sydney) to available regions

Added Australia (Sydney) to the list of regions.

* Add Asia Pacific (Sydney) IP addresses to whitelist

Added IP addresses for the Asia Pacific (Sydney) region.

* Reorder South America IP addresses section

* Update cloud region list in change-region.md

Removed duplicate entry for Australia (Sydney) and updated Asia Pacific region.

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-12-17 15:05:59 +00:00
github-automation-metabase
5a45101c85 Revert "Quick ci test disabling (#63030)" (#66912) (#66950)
This reverts commit 9191713854.

used to do this in-house but now we use trunk for this. Old way has
ultimate flexibility. But trunk has some really nice workflows built
in (reporting, creating issues in linear, etc).

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-17 14:27:06 +00:00
github-automation-metabase
ef249e1602 fix: card serdes/descendants misses metrics (#67029) (#67062)
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2025-12-17 03:29:26 +00:00
github-automation-metabase
5eaae2e96b Skip fields with inactive table. (#66967) (#67018)
* Skip fields with inactive table.

* Remove redundant let

* Better fix.

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-16 17:18:26 -05:00
github-automation-metabase
ff735a653e Fix bad normalization for the :text function in MBQL 4 (#67031) (#67038)
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-16 14:20:02 -05:00
github-automation-metabase
d7c4d26075 Update generated docs (release-x.57.x) (#66996)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-16 10:30:52 -05:00
github-automation-metabase
8a2b64e372 Output container logs for Sample App CI (#67003) (#67016)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-12-16 14:55:09 +00:00
github-automation-metabase
727272c22e Fix clickhouse uuid filtering (#66852) (#66882)
* fix uuid filtering

* rewrite tests to be more structured

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-16 14:54:29 +00:00
github-automation-metabase
a16c977d15 Trust the model's FK semantic type even for MBQL models (#66788) (#66849)
* Trust the model's FK semantic type even for MBQL models

Fixes #48427

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-12-16 14:34:57 +00:00
github-automation-metabase
cc3ffc95b9 No 500 on deactivating user (#66621) (#66850)
Fixes https://github.com/metabase/metabase/issues/66599

Co-authored-by: John Swanson <john.swanson@metabase.com>
2025-12-16 14:09:49 +00:00
github-automation-metabase
698826e9c8 Don't offer drill-throughs when top-level column doesn't exist (#66907) (#66987)
The summary: we are offering drill-throughs on custom columns defined after aggregation, but those custom columns don't exist in the base query. The error presented in such a way that `lib.underlying/top-level-column` for a dimension was returning `nil`, and we were happily putting that `nil` into the query we constructed.

I created a utility to filter dimensions by whether or not the top-level-column can be resolved, and used this for the underlying-records drill-through (from the original issue) as well as the pivot drill-through (which behaved similarly). If no dimensions have a top-level column, the drill-through is not available. If some do, we offer the partial drill-through.

Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>
2025-12-16 00:12:47 +00:00
github-automation-metabase
91395e614d metadata.cljs: always prefer lib/source over source (#66858) (#66980)
`source` is a legacy key on the frontend that gets translated to `lib/source`. Some maps are using both `source` and `lib/source`, and the translation layer translates keys and values in completely separate steps. When the time comes to translate the legacy value of `source` into a valid value for `lib/source`, the code can't tell what the key was originally named. So already-valid values were going through the translation process, producing invalid values (e.g., `:source/source/aggregations`).

This adds a step to object parsing to detect that both keys are present; when they are, it sets an option to simply skip `source` during the parsing; secondly, it adds a step in the value parsing to check whether the value is already a keyword namespaced by `source/`.

Co-authored-by: Timothy S. Dean <timothy.dean@metabase.com>
2025-12-15 23:15:16 +00:00
github-automation-metabase
2af7273bd0 Normalize invalid :widget-types correctly (#66965) (#66975)
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-15 22:35:15 +00:00
github-automation-metabase
07f973850b remove orphan package.json (#66974) (#66979)
Co-authored-by: Ryan Laurie <30528226+iethree@users.noreply.github.com>
2025-12-15 22:24:44 +00:00
github-automation-metabase
47e2168aef Fix mongo native preview of queries with variables (#66959) (#66973)
* decode strings before formatting

* require lib.metadata

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-15 22:12:22 +00:00
github-automation-metabase
cb806c70e9 [perf] Fix a sneaky infinite loop in a prod-only error case (#66955) (#66962)
`util.perf/mapv` checks the `count` of all its collection args, so it's
not safe to call with an infinite `seq`.

`lib.metadata.result-metadata/merge-cols` was doing exactly that in the
case where there was a mismatch between the column counts from lib and
driver. It was passing `(concat short-list (repeat nil))` to `mapv` and
causing an infinite loop!

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-12-15 20:02:49 +00:00
Edward Paget
155cfbbf49 feat: support remote-syncs from 58 -> 57 (#66895) 2025-12-15 13:32:40 -06:00
github-automation-metabase
fc746f38d7 Restore theme preference after login (#66892) (#66956)
* fix: restore theme preference after login

* test: add theme restoring e2e sequence

* test: perform manual sign-in for better reproduction

* docs: explain new `useEffect` call on `ColorSchemeProvider.tsx`

* fix: experimentally replace colorscheme change listening method

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2025-12-15 19:10:51 +00:00
github-automation-metabase
167bba3276 Support relative-datetime in legacy mbql (#66214) (#66818)
Co-authored-by: Nathan Voxland <nathan@metabase.com>
2025-12-15 17:57:37 +00:00
github-automation-metabase
01e29d4be8 Update generated docs (release-x.57.x) (#66924)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-15 11:46:27 -05:00
github-automation-metabase
65bc5117c8 [o11y] Add a new metric to count unique cards with blank queries (#66903) (#66951)
Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-12-15 11:30:42 -05:00
github-automation-metabase
e2364db1be add input for the logs-artifact-suffix (#66738) (#66747)
also fix where the name comes from on the mysql job (it uses version not
job)

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-15 10:08:54 -06:00
github-automation-metabase
f0885f1c21 Trying to fix the infamous app palette loki flaky (#66935) (#66946)
* Trying to fix the infamous app palette loki flaky

* .

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-15 14:58:26 +00:00
Nicolò Pretto
fbfa02eed0 EMB-1129 on release 57 (#66889) 2025-12-15 10:05:53 +00:00
github-automation-metabase
e259ffed11 UXW-2484 fix chart tooltip color (#66855) (#66901)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-12-12 21:24:08 +00:00
github-automation-metabase
07f85e3b98 [perf] Add metric for lib.computed/weak-map size; speculative fixes (#66404) (#66883)
OOMs in cloud are linked to this weak map retaining too much. The
exported heap dump reports are suggestive but not conclusive, and I
can't reproduce locally.

Adds `:metabase-query-processor/computed-weak-map-queries` to measure
the size of the weak map. That should sawtooth with GCs as it
accumulates queries and then discards them, but we'll see if it rises
forever on the problem instances.

This also adjusts the caching for a `MetadataProvider`-level entity
(`:metadata/card`) from the weak map to the `MetadataProvider`'s
internal cache. That's speculative, since there's no evidence to link
it to the issue, but it should be at least as effective a cache and
there's less risk of accidentally retaining too much.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-12-12 19:08:53 +00:00
github-automation-metabase
dc421b317c 🤖 backported "fix: apply deep serialization sort for remote-sync" (#66879)
* fix: apply deep serialization sort for remote-sync (#66846)

* fixup! remove snapshot call

---------

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Edward Paget <ed.paget@gmail.com>
2025-12-12 16:59:14 +00:00
github-automation-metabase
b214449583 [retry] Rewrite metabase.util.retry to use diehard instead of resilience4j (#66177) (#66704)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-12-12 18:56:18 +02:00
github-automation-metabase
093b58e6db fix(sdk-bundle): Fix can't drill numeric string ID dashboard (#66819) (#66871)
* Fix can't drill numeric string ID dashboard

* Address when ID is an empty string

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-12-12 14:59:27 +00:00
github-automation-metabase
45a7b79e97 UXW-2537 fix row/bar viz crash after native query column rename (#66786) (#66856)
* UXW-2537 fix row/bar viz crash after native query column rename

* Fix unit tests

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-12-12 14:32:36 +00:00
github-automation-metabase
478f39d873 fixes a flaky (#66822) (#66873)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-12 12:27:18 +00:00
github-automation-metabase
506bf3dedf 🤖 backported "Show a spinner button for the Download button when exporting" (#66830)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-12-12 13:42:51 +04:00
github-automation-metabase
bac64a06ed Fix for the limit in the static embed context (#66811) (#66825)
Co-authored-by: Roman Abdulmanov <roman@metabase.com>
2025-12-12 09:06:16 +00:00
github-automation-metabase
c443d6a0a0 Embed necessary part of crypto-random dependency and remove it (#66016) (#66703)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-12-12 07:02:22 +00:00
github-automation-metabase
3af4595e6b Hide analytics-dev-mode setting from generated docs (#66794) (#66848)
docs scoop up all settings and has ways to avoid. In
`metabase.cmd.env-var-dox/avoid?` This had a docstring and then an extra
docstring. We can just copy the nice docstring to the docstring slot and
put `:doc false`.

```clojure
(defn- avoid?
  "Used to filter out environment variables with high foot-gun indices."
  [env-var]
  (or (false? (:doc env-var))
      (false? (:can-read-from-env? env-var))
              ;; Ideally, we'd move off of this list completely,
              ;; but not all environment variables are defsettings.
      (contains? env-vars-not-to-mess-with (format-prefix env-var))))
```

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-12 03:48:51 +00:00
dpsutton
54af30e62c use performance get-in (#66759)
Here's a handwavy sequence of events (i don't think being more precise
has benefits):

bronsa merges a pr using get-in at a time when it is fine
https://github.com/metabase/metabase/pull/66430. Sashko added a
performance get-in to
master (https://github.com/metabase/metabase/pull/65889).  Eric makes a
PR against master and sees random failing stuff fixes it
there (https://github.com/metabase/metabase/pull/66719). In eric’s
backport the backport of the performance get-in hasn’t made it back yet
so he has to fix this and not include
it (https://github.com/metabase/metabase/pull/66729/commits and
003a2305a3).
Sashko’s backport finally lands in 57 so just a dumb dance to
this. Nothing alarming and an easy fix
2025-12-11 15:43:46 -06:00
github-automation-metabase
e899eb8420 Don't add newline to commented out clauses in native query preview (#66700) (#66838)
* only replace clause if it's not commented

* add tests

* remove sql formatting on frontend

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-11 20:00:57 +00:00
github-automation-metabase
7b1a438dc9 Fix user attribute filters against implicitly joined tables that are also sandboxed (#66790) (#66799)
# Conflicts:
#	enterprise/backend/test/metabase_enterprise/sandbox/query_processor/middleware/sandboxing_test.clj

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-11 19:16:07 +00:00
github-automation-metabase
4efded0d3a 🤖 backported "UXW-285 filter not accessible questions in data picker" (#66774)
* UXW-285 filter not accessible questions in data picker (#66483)

* UXW-285 filter not accessible questions in data picker

# Conflicts:
#	frontend/src/metabase-types/api/collection.ts

* Fix CI

* Fix e2e

* Fix CI, add e2e

* Add fix for big picker

* fix: CI

* Fix e2e tests
# Conflicts:
#	e2e/support/helpers/e2e-ui-elements-helpers.js
#	e2e/test/scenarios/data-studio/table-collection-permissions.cy.spec.ts
#	frontend/src/metabase/common/components/Pickers/CollectionPicker/components/CollectionItemList.tsx
#	frontend/src/metabase/common/components/Pickers/DataPicker/utils.ts
#	frontend/src/metabase/common/components/Pickers/MiniPicker/components/MiniPickerItemList.tsx

* Fix CI

* Fix e2e test

---------

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-12-11 18:40:37 +00:00
github-automation-metabase
5e3b9c1289 fix broken text wrapping in tables in documents (#65254) (#66826)
* fix broken text wrapping in tables in documents

* render measure root in a portal

Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
2025-12-11 17:09:40 +00:00
github-automation-metabase
b7f53b8e45 Prevent looping past current-schema-version when already past it (#66785) (#66816)
* Prevent looping past current-schema-version when already past it.

* Add test for upgrade-card-schema-to-latest

* Make test parallel

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-11 12:04:01 -05:00
github-automation-metabase
e7bf5195b8 Optimize u/index-by when used with vf (#66800) (#66802)
Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
2025-12-11 13:32:38 +00:00
github-automation-metabase
9e9967c0e8 docs: debetify metabot (#66676) (#66793)
* metabot unbetaying

* Apply suggestions from code review



---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-10 23:21:27 +00:00
github-automation-metabase
e9e9771e26 🤖 backported "Treat postgres bit strings as text" (#66760)
* Treat postgres bit strings as text (#66618)

* treat bit strings as text

* Add tests

* cast bit string values instead of fields

* only use string value if bit type

* fix kondo

* Add comment

* kondo

---------

Co-authored-by: Riley Thompson <riley@metabase.com>
Co-authored-by: Riley Thompson <rileythompson99@gmail.com>
2025-12-10 16:36:29 -06:00
github-automation-metabase
2bdb301391 🤖 backported "Include segments in dependencies graph" (#66604)
* backport merge

* indent migrations

* kondo

* fix tests

* fix tests again

* fix fe

* remove fe test

---------

Co-authored-by: Riley Thompson <rileythompson99@gmail.com>
2025-12-10 20:36:54 +00:00
github-automation-metabase
85923ec9da handle uploads from matrix jobs (#66732) (#66734)
motivating example:
we ran the redshift tests, and had three failures: redshift 1, redshift
2, and redshift transforms.

redshifts 1 and 2 timedout at 60 minutes. But the log upload failed
because the python transform tests failed in 24 minutes and then
uploaded:

from the transform failure run:

```
Run actions/upload-artifact@v4
  with:
    name: test-logs-be-tests-redshift-ee
    path: logs/test-log.json
    retention-days: 1
    if-no-files-found: warn
    compression-level: 6
    overwrite: false
    include-hidden-files: false
  env:
    CI: true
    ...
With the provided path, there will be 1 file uploaded
Artifact name is valid!
Root directory input is valid!
Beginning upload of artifact content to blob storage
Uploaded bytes 1072768
Finished uploading artifact content to blob storage!
SHA256 digest of uploaded artifact zip is 267d4b085d49ca4d682fedca97832fecb603bbb5a52c0e1d99bd4daa49984ba3
Finalizing artifact upload
Artifact test-logs-be-tests-redshift-ee.zip successfully finalized. Artifact ID 4816135520
Artifact test-logs-be-tests-redshift-ee has been successfully uploaded! Final size is 1072768 bytes. Artifact ID is 4816135520
```

And then from the redshift tests:

```
Run actions/upload-artifact@v4
  with:
    name: test-logs-be-tests-redshift-ee
    path: logs/test-log.json
    retention-days: 1
    if-no-files-found: warn
    compression-level: 6
    overwrite: false
    include-hidden-files: false
  env:
    CI: true
    ...
With the provided path, there will be 1 file uploaded
Artifact name is valid!
Root directory input is valid!
Error: Failed to CreateArtifact: Received non-retryable error: Failed request: (409) Conflict: an artifact with this name already exists on the workflow run
```

The same happens on redshift part 1.

```
Error: Failed to CreateArtifact: Received non-retryable error: Failed
request: (409) Conflict: an artifact with this name already exists on
the workflow run
```

This just introduces on the driver action to look for a
logs-artifact-suffix and use it if present. And on driver jobs that use
a matrix include the matrix.job.name (or matrix.version.name depending
on the exact structure).

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-10 15:04:40 +00:00
github-automation-metabase
747434808b fix: format week of year ordinal string safely (#66667) (#66675)
* check if we should remove square brackets from week of year ordinal

* add tests

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-10 14:39:54 +00:00
github-automation-metabase
96aaaeae2b [perf] Add and use m.u.performance/get-in (#65889) (#66705)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-12-10 12:50:53 +00:00
github-automation-metabase
ade3e5cb91 note on metabot context (#66707) (#66755)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-10 12:50:31 +00:00
github-automation-metabase
b88ce88262 Fix query normalization issues in v57 (#66722) (#66731)
* Fix query normalization issues in v57

* Remain strict when saving a query

* replace bad dataset_query with legacy_query

* Test fixes 🔧

* Test/Kondo fix 🔧

---------

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
Co-authored-by: dan sutton <dan@dpsutton.com>
2025-12-09 20:34:06 -05:00
github-automation-metabase
ce28d036c6 🤖 backported "Make card schema upgrade 23 a no-op" (#66729)
* Make card schema upgrade 23 a no-op (#66719)

* Make card schema upgrade 23 a no-op

* Fix kondo error

* Yay, fix kondo error in other file

* Appease the module check

* Use clojure.core/get-in

* kick ci

* kick ci

---------

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-09 17:22:22 -05:00
github-automation-metabase
7cc52e04cc Fix #66585: Updates static embeds to omit color-scheme settings to preserve legacy transparent iframe behavior (#66662) (#66709)
* #66585 Updates static embeds to omit color-scheme settings to preserve legacy transparent iframe behavior

* support public embed too (#66693)

* support public embed too

* Imports isPublicEmbedding to prevent app crash

---------



---------

Co-authored-by: Brad Anderson <brad@metabase.com>
Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-12-09 22:03:45 +00:00
github-automation-metabase
21a7a0471f docs - note on Metabot usage (#66702) (#66730)
* note on Metabot usage

* clean up

* clarification

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-09 21:37:01 +00:00
github-automation-metabase
b1b9c78f55 Revert "Hide cursor in the readonly native editor (#63774)" (#66727) (#66728)
This reverts commit f901d08b1c.

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-09 21:02:14 +00:00
github-automation-metabase
fc3f70112c UXW-2448 fix untime error with viz settings (#66657) (#66724)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-12-09 19:54:30 +00:00
github-automation-metabase
f4854b4052 fix: strip some attached dwh config keys on update (#66594) (#66613)
We considered a few options before settling on this one:
1. replace usecase with private HM API
2. disallow db updates via config.yml
3. add config.yml update semantics
4. work around this particular use of config.yml for cloud dwh

1 would be a fair bit of work and testing, 2 could break existing
customers, 3 was a bit of a rabbit hole, and 4 was hacky.

We decided for 1 long term, 4 short term in https://metaboat.slack.com/archives/C010ZSXQY87/p1764869574808769.

Fix https://linear.app/metabase/issue/CLO-4581/metabase-cloud-storage-gets-set-by-default-in-the-upload-csv-everytime

Co-authored-by: Filipe Silva <filipematossilva@gmail.com>
2025-12-09 19:20:35 +00:00
github-automation-metabase
0e25fc64a3 Fix gauge trims decimal parts of ranges (#66714) (#66718)
* fix floating point numbers usage in gauge

* trigger change only if changed

Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
2025-12-09 19:20:03 +00:00
github-automation-metabase
817212a7f6 Show different copy on Metabot AI purchase page after trial (#66706) (#66716)
### Description

In https://github.com/metabase/metabase/pull/65343 we added a page to purchase Metabase AI (Metabot).  Now we are improving the text to:
* Show information about trial only if Metabot was not already trialed
* Improve wording regarding multiple questions / messages in chat

### How to verify

1. Ensure you have a token with the `offer-metabase-ai-tiered` feature, but without the `metabot-v3` feature.
2. Check that the subscription associated with the token had either with (test case 1) or without (test case 2) the `metabase-ai` or the `metabase-ai-tiered` add-on.
3. Navigate to `/admin/metabot` and see the page look like in the mock ups.

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

Closes: https://linear.app/metabase/issue/CLO-4673/show-different-copy-on-metabot-ai-purchase-page-after-trial
Closes: https://linear.app/metabase/issue/CLO-4688/copy-correction-in-the-admin-panel

Co-authored-by: Dennis Schridde <63082+devurandom@users.noreply.github.com>
2025-12-09 19:01:34 +00:00
github-automation-metabase
57c00fc2b3 Native query parsing understands queries with dependent ctes (#66139) (#66691)
If you have a query like "WITH query_a AS (...), query_b AS (select ... from query_a) SELECT ... from query_b",
native query parsing understood that query_b in the final query referred to query_b in the WITH, but it didn't realize
that query_a in query_b referred to query_a in the WITH.  Now, it should understand these sorts of depedent ctes.

Co-authored-by: William <william@metabase.com>
2025-12-09 19:00:58 +00:00
github-automation-metabase
264d2f9bca Editable usage analytics (#66430) (#66694)
* feat: db managemtn

* WIP: load yamls

* wip: transform

* feat: just toggle on load-analytics-content

* feat: export

* chore: user-email

* analytics-dev-mode

* wip: startup logic

* require ns for init

* kondo

* wip: export route

* wip

* fix api

* feat: download button

* refactor

* fix db yaml

* fix: skip db for import

* chore: move stuff around

* use is-audit-dev toggle

* internal setting

* tighter control on export

* lint FE

* perf

* lint fe

* jar aware

* feat: PR-Env-analytics-dev

* chore: use timer

* fail unless postgres

* tests

* fix tests

* throw out of future

* delete old shell command

* feat: mage commands

* fix: test

* fixes for mage commands

* chore: return schema

* cleanup

* fixes to mage commands

* fix: is-audit-dev can always connect, it's appdb

* update checked out analytics to latest format

* reset on teardown

* reinstate even if no edit

* add analytics:finalize for convenience

* exclude qrtz and liquidbase tables

* Update frontend/src/metabase/status/components/AnalyticsExportStatus/AnalyticsExportStatus.tsx



* Update frontend/src/metabase/collections/components/CollectionHeader/CollectionExportAnalytics.tsx



* Update frontend/src/metabase/collections/components/CollectionHeader/CollectionExportAnalytics.tsx



* address review comments

* relativize

* remove needless == true

* missing io/file

---------

Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
Co-authored-by: Uladzimir Havenchyk <uladzimir@metabase.com>
2025-12-09 18:58:01 +00:00
github-automation-metabase
53009fe5f9 Upgrade NextJS again (#66547) (#66699)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-12-09 17:08:47 +01:00
github-automation-metabase
58d923bede Replace a solitary usage of clojure.data.xml with clojure.xml (#66573) (#66639)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-12-09 16:04:16 +00:00
github-automation-metabase
e3fa177188 [equality] Implement faster inequality operation for Long arguments (#65642) (#66640)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-12-09 16:04:08 +00:00
github-automation-metabase
02e9e6cfde closes emb 1021 flaky test again (#66541) (#66708)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-09 16:02:33 +00:00
github-automation-metabase
a33d3ff509 Include "all entries for" in mt/all-entries-for (#66668) (#66682)
this should get all audit log entries for a given model and
model-id. but previously it was using t2/select-one. now it uses
t2/select. whoops

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-08 23:41:26 +00:00
github-automation-metabase
e06e09e669 Add schema 23 upgrade (#66601) (#66672)
* If dataset_query is empty and legacy_query is not, copy legacy query over

* Fix kondo errors and bump schema to 23

* Remove parens

* Baseline update

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-08 17:18:26 -06:00
github-automation-metabase
dc4b0b51d5 Fix issue where having a metabot block inside a document prevents it from loading when publicly shared (#66564) (#66628)
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-12-08 17:54:46 -05:00
github-automation-metabase
23b2efbeb6 add events when making cards/dash public or retracting (#64582) (#66666)
* add events when making cards/dash pubic or retracting

https://github.com/metabase/metabase/issues/64417

When we make a card public, we put a uuid on it and include
`made_public_by_id`. But when you retract the public link, we remove
both bits of information. This is a nice invariant but it removes
information about who publicized a card.

Imagine a card is discovered by have been public. Of course you want to
immediately remove it. But this erases the audit trail (so to speak) of
who made it public. It is not a great idea to delay remediation during
the investigation. Now you can just consult the audit log

* make events

* formatting

* clean up tests a bit

tests were a bit wack. We should have utility functions to get audit
events. Also noticed we are going off of the object id and ignoring the
object. Could lead to gross issues if there's dashboard with id 4 in
there and also card with id 4. so require model on new one

* fmt

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-08 20:31:12 +00:00
github-automation-metabase
e2a822d6c3 UXW-2257 fix theme override after table render (#66620) (#66647)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-12-08 19:45:34 +03:00
github-automation-metabase
d3234654c8 add starburst ssh (#66568) (#66650)
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-08 15:27:49 +00:00
github-automation-metabase
acdea2e127 backport merge (#66606)
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-08 14:48:05 +00:00
github-automation-metabase
bc1e202df2 handle users with no first or last names in document comments (#66468) (#66484)
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-12-08 09:40:48 -04:00
github-automation-metabase
2c05088ca9 [QP] If a :field ref by ID needs fallback metadata, include :join-alias (#66563) (#66591)
Fixes #66464.

This was a corner case in `lib.field.resolution` and `qp.util.add-alias-info`
that regressed in 57. It made the QP less smart about repairing a certain
class of broken queries, which regrettably exist in the wild.

The breakage in question was a `:field` ref in later stage, which had a
numeric field ID and a `:join-alias`. If that field ID was not actually
returned as part of the join anymore, fallback metadata would be
generated by looking up the field by ID. That "works" for non-joined
fields but for an explicitly joined field it would use
`source."SOME_FIELD"` rather than `"The Join Alias"."SOME_FIELD"`, which
causes SQL compilation to fail.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-12-08 12:08:18 +00:00
github-automation-metabase
50e5ecaed7 Bump org.apache.tika/tika-core from 3.2.2 to 3.2.3 (#63799) (#66635)
Inspect dependency changes here:

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-12-07 17:21:36 +00:00
github-automation-metabase
5b5725c24d bump the hive jdbc library (#66523) (#66626)
Co-authored-by: bryan <bryan.maass@gmail.com>
2025-12-06 01:28:47 +00:00
github-automation-metabase
ee916f0a72 implement driver.sql/json-field-length for druid-jdbc driver (#66525) (#66611)
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-05 21:28:56 +00:00
github-automation-metabase
d4eca926bf Cache trunk between runs (#66602) (#66616)
Trunk action supports `use-cache` that should prevent us hitting
GitHub's API rate limits.

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-12-05 20:51:38 +00:00
github-automation-metabase
6ca7573c9d Add :aggregation as valid argument to a filter. (#66560) (#66609)
Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-05 19:31:00 +00:00
Jeff Bruemmer
e2c5265428 update docker compose to pin postgres and add volume (#66608) 2025-12-05 13:26:50 -05:00
github-automation-metabase
7a3fbdd93b fix: add correct valueFormat for DateInput (GIT-8486, #65480) (#66298) (#66595)
* fix: add correct valueFormat for DateInput (GIT-8486, #65480)

* GIT-8486 add cleanup after changing locales

Co-authored-by: Egor Grushin <egorgrushin@gmail.com>
2025-12-05 16:10:31 +00:00
github-automation-metabase
d1123a2cb1 Adjust layout of Metabot purchase page and add video demo (#66580) (#66589)
### Description

In https://github.com/metabase/metabase/pull/65343 we added a page to purchase Metabase AI (Metabot).  Now we are improving the layout and content to better present the product.

### How to verify

1. Ensure you have a token with the `offer-metabase-ai-tiered` feature, but without the `metabot-v3` and `offer-metabase-ai` features.
2. Navigate to `/admin/metabot` and see the page look like in the mock ups.

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

Closes: https://linear.app/metabase/issue/CLO-4669/make-small-changes-to-ai-page-in-admin

Co-authored-by: Dennis Schridde <63082+devurandom@users.noreply.github.com>
2025-12-05 16:03:40 +00:00
github-automation-metabase
665a201ba5 🤖 backported "fix: show confirmation on escape, clickoutside and browser's back actions for SidebarCacheForm" (#66518)
🤖 backported "fix: show confirmation on escape, clickoutside and browser's back actions for SidebarCacheForm" (#66518)
2025-12-05 11:47:28 +00:00
github-automation-metabase
915bd811ce Closes EMB-1042 removed flaky e2e test and adds a unit test instead (#66424) (#66552)
* Closes EMB-1042 removed flaky e2e test and adds a unit test instead

* yeah no timeout

* fixed poor rebase

* better use of fetchmock in unit test

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-05 12:23:11 +01:00
github-automation-metabase
562fb5dc35 Remove transducers and core.logic deps (#66510) (#66570)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-12-05 01:26:23 +00:00
github-automation-metabase
11675fb536 docs - update quickstart (#66527) (#66565)
* fix up quickstart

* versions

* consolidate clones

* fix link

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-04 22:23:27 +00:00
github-automation-metabase
edb07af899 When setting settings, include 5 minute cookie of updated timestamp (#66338) (#66553)
* When setting settings, include 5 minute cookie of updated timestamp

if other instances have outdated settings cache, this cookie will let
them know what the requestor has seen. The instance can then know it is
out of date. This won't help for instances that aren't hit by the person
setting the setting.

Motivating example is someone who is doing an embedding onboarding
checklist. And then hits a new instance that hasn't yet loaded the "show
embedding homepage" setting so it flips back to the regular
homepage. The hope here is the person doing this checklist will let the
other instance know it is out of date, reload the settings cache and
then see the embedding setting.

* Interesting strategy here for cookies.

I hated that the route would would set a cookie at a particular key, do
timestamp stuff, etc. I know ring is a map and abstraction, but i added
a new paradigm:

```clojure
(defn- add-settings-last-updated-cookie
  "Add a cookie with the current settings-last-updated timestamp to the response."
  [response]
  (assoc-in response [:mb/cookies :cookie/settings-cache-timestamp] true))
```

This means that just the middleware is responsible for checking and
setting this key. This was largely driven by two different namespaces
having a private def of:

```clojure
(def ^:private settings-last-updated-cookie-name "metabase.SETTINGS_LAST_UPDATED")
```

And it's nice if the ring map can indicate to this middleware to handle
all the key and timestamp stuff and it just has to indicate to set this
with `cookie/settings-cache-timestamp`.

So the request looks like this:

```clojure
{:status 204
 :headers {"X-Frame-Options" "DENY"
           "X-XSS-Protection" "1; mode=block"
           "Last-Modified" "Mon, 1 Dec 2025 17:09:59 GMT"
           "Strict-Transport-Security" "max-age=31536000"
           "X-Permitted-Cross-Domain-Policies" "none"
           "Cache-Control" "max-age=0, no-cache, must-revalidate, proxy-revalidate"
           "X-Content-Type-Options" "nosniff"
           "Content-Security-Policy" "...<lots of junk>..."
           "Expires" "Tue, 03 Jul 2001 06:00:00 GMT"}
 :body nil
 :mb/cookies {:cookie/settings-cache-timestamp true} ;; <---- our new addition
 :cookies {"metabase.DEVICE" {:value "60ac9454-9dd1-439a-afa1-921ff029686d"
                              :http-only true
                              :path "/"
                              :expires "Fri, 1 Dec 2045 17:09:59 GMT"
                              :same-site :lax}}}
```

And then in practice, it looks like this:

Set the setting and get a cookie with the timestamp in response:

```
❯ http put :3000/api/setting/site-name value=foo x-api-key:$KEY
HTTP/1.1 204 No Content
...
Set-Cookie: metabase.SETTINGS_LAST_UPDATED=2025-12-01+17%3A28%3A15.450873%2B00; Path=/; Max-Age=300; SameSite=Lax
...
```

Simulate sending to another instance with a timestamp that exceeds the
currently know timestamp (i'll increment the hour based sent back in
this response)

```
❯ http get :3000/api/user/current x-api-key:$KEY Cookie:metabase.SETTINGS_LAST_UPDATED="2025-12-01+18%3A23%3A51.059155%2B00" | jq '.date_joined'
"2025-12-01T16:51:08.137822Z"
```
(note the 18 vs the 17)

And the logs are this:

```
INFO middleware.settings-cache :: Settings cookie indicates cache is out of date. Refreshing...
DEBUG middleware.log :: GET /api/user/current 200 19ms (11 DB calls) App DB connections: 0/4 Jetty threads: 5/50 (5 idle, 0 queued) (245 total active threads) Queries in flight: 0 (0 queued) {:metabase-user-id 346}
```

* fixes:

- logged known timestamp not weird cookie value
- timestamp is optional, so handle that
- typo in log konwn -> known

* Add tests, add functionality

tests:
ensure it (a) sets the cookie, (b) honors the cookie, and when it
restores the cache, to set the cookie so it doesn't keep thrashing. But
presumably it won't since it's up to date. My "in the future" version is
a bit synthetic.

Functionality wise, updating the cache now returns and this will saet
the header with the most recent cache setting

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-04 17:31:13 +00:00
github-automation-metabase
0c2f3c3ae5 Bump com.microsoft.sqlserver/mssql-jdbc from 13.2.0.jre11 to 13.2.1.jre11 (#64831) (#66524)
Inspect dependency changes here:
2025-12-03 20:50:20 +00:00
github-automation-metabase
bdbc7ccc3c 🤖 backported "Persist selected theme in account settings" (#66487)
* Persist selected theme in account settings (#66250)

* Persist selected theme in account settings

* Persist selected theme in account settings

* Add e2e

* Add e2e

* Review fixes

* Refactor initial value get to fix e2e tests

* fix e2e

* Fix BE module test

* Fix CI

---------

Co-authored-by: John Swanson <john.d.swanson@gmail.com>

* Fix CI

---------

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
Co-authored-by: John Swanson <john.d.swanson@gmail.com>
2025-12-03 20:38:57 +00:00
github-automation-metabase
e30dbf89f5 use json unquote (#66512) (#66520)
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-03 19:17:34 +00:00
github-automation-metabase
c429dd22f7 Renamed Library to Synced Collection (#65447) (#66515)
Renamed Library to Synced Collection

Co-authored-by: Nathan Voxland <nathan@metabase.com>
2025-12-03 18:34:32 +00:00
github-automation-metabase
4aeaa42ad8 Continue sync even if a table fails (#66432) (#66507)
* Add reproduction test

* Fix for clickhouse

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-03 17:45:47 +00:00
github-automation-metabase
a9704d2e51 Closes EMB-1069 create new embed -> embed (#66457) (#66508)
* Closes EMB-1069 create new embed - embed

* .

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-03 16:58:13 +00:00
github-automation-metabase
ad5a5e56d2 flaky flaky, eggs and baky (#66312) (#66509)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-03 16:51:11 +00:00
github-automation-metabase
e54c6f283a UXW-804 Fix collection name & description character limits (#66380) (#66479)
* feat: add `maxLength` attributes to collection `name` and `description`

* test: update suites for `CollectionHeader`

* feat: update max length validation for `CollectionInfoSidebar`

* feat: update max length validation for `NewCollectionDialog`

* test: update `CollectionInfoSidebar` and `CollectionCaption` tests

* style: update toast color

* refactor: remove unreachable checks & assertions

* test: remove unnecessary checks and render spread

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2025-12-03 14:47:31 +00:00
github-automation-metabase
faf6e3d5bc fix(sdk-cli): Fixes CLI quickstart not passing in the proper revision in query (#66493) (#66494)
* Fixes CLI quickstart not passing in the proper revision in query

* .

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-03 10:51:59 +00:00
github-automation-metabase
597a9421ac Fixes 60942 (#61080) (#66488)
Fixes https://github.com/metabase/metabase/issues/60942

Co-authored-by: LP <paoliniluis@gmail.com>
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-03 00:29:56 +00:00
github-automation-metabase
63b11ed233 UXW-2404 Remove toggle to disable anonymous analytics on cloud (#66469) (#66480)
* fix: hide anonymous tracking toggle on cloud plans

* test: update general settings page suite

* fix: feedback on testing & token feature extraction

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2025-12-02 20:24:43 +00:00
github-automation-metabase
c6883be6df Closes EMB-1055 static embedding without a theme defaults to dark mode or system settings (#66320) (#66476)
* Closes EMB-1055 static embedding without a theme defaults to dark mode or system settings

* types

* .

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-02 17:23:18 +00:00
github-automation-metabase
2536114ff7 🤖 backported "Lets not log when a user cancels a query" (#66470)
* Lets not log when a user cancels a query (#66292)

* Lets not log when a user cancels a query

look how gross this is

```
2025-11-25 23:03:09,543 ERROR middleware.catch-exceptions :: Error processing query: ERROR: canceling statement due to user request
{:database_id 613,
 :parameterized false,
 :started_at #t "2025-11-25T23:03:03.698696Z[UTC]",
 :via
 [{:status :failed,
   :class clojure.lang.ExceptionInfo,
   :error "Error executing query: ERROR: canceling statement due to user request",
   :stacktrace
   ["--> driver.sql_jdbc.execute$execute_reducible_query$fn__452061$fn__452062.invoke(execute.clj:772)"
    "driver.sql_jdbc.execute$execute_reducible_query$fn__452061.invoke(execute.clj:767)"
    "driver.sql_jdbc.execute$eval451741$fn__451742$fn__451743.invoke(execute.clj:422)"
    "driver.sql_jdbc.execute$fn__451652$do_with_resolved_connection451651__451653.invoke(execute.clj:347)"
    "driver.sql_jdbc.execute$fn__451652$fn__451658.invoke(execute.clj:327)"
    "driver.sql_jdbc.execute$eval451741$fn__451742.invoke(execute.clj:416)"
    "driver.sql_jdbc.execute$execute_reducible_query.invokeStatic(execute.clj:760)"
    "driver.sql_jdbc.execute$execute_reducible_query.invoke(execute.clj:749)"
    ...
     :state "57014",
 :error_type :invalid-query,
 :json_query
 {:lib/type "mbql/query",
  :stages [{:native "select 1, pg_sleep(40)", :lib/type "mbql.stage/native", :template-tags {}}],
  :database 613,
  :parameters [],
  :middleware {:js-int-to-string? true, :userland-query? true, :add-default-userland-constraints? true}},
 :status :failed,
 :class org.postgresql.util.PSQLException,
 :stacktrace
 ["org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2734)"
  "org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2421)"
  "org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:372)"
  "org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:518)"
  "org.postgresql.jdbc.PgStatement.execute(PgStatement.java:435)"
  "org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:357)"
  "org.postgresql.jdbc.PgStatement.executeCachedSql(PgStatement.java:342)"
  "org.postgresql.jdbc.PgStatement.executeWithFlags(PgStatement.java:318)"
  ...
    "query_processor.streaming$_streaming_response$fn__108781$fn__108782$fn__108783.invoke(streaming.clj:225)"
  "query_processor.streaming$_streaming_response$fn__108781$fn__108782.invoke(streaming.clj:223)"
  "query_processor.streaming$do_with_streaming_rff.invokeStatic(streaming.clj:214)"
  "query_processor.streaming$do_with_streaming_rff.invoke(streaming.clj:201)"
  "query_processor.streaming$_streaming_response$fn__108781.invoke(streaming.clj:220)"
  "server.streaming_response$do_f_STAR_.invokeStatic(streaming_response.clj:83)"
  "server.streaming_response$do_f_STAR_.invoke(streaming_response.clj:81)"
  "server.streaming_response$do_f_async$task__108307.invoke(streaming_response.clj:98)"],
 :card_id nil,
 :context :ad-hoc,
 :error "ERROR: canceling statement due to user request",
 :row_count 0,
 :running_time 0,
 :data {:rows [], :cols []}}

2025-11-25 23:03:09,570 DEBUG middleware.log :: POST /api/dataset 202 [ASYNC: canceled] 5888ms (8 DB calls) App DB connections: 0/6 Jetty threads: 5/50 (4 idle, 0 queued) (228 total active threads) Queries in flight: 0 (0 queued); postgres DB 613 connections: 0/1 (0 threads blocked) {:metabase-user-id 1}
```

how embarassing. we're just canceling a query. we don't need a stacktrace.

and after:

```
2025-11-25 23:39:40,197 DEBUG middleware.log :: POST /api/dataset 202 [ASYNC: canceled] 3076ms (8 DB calls) App DB connections: 1/10 Jetty threads: 4/50 (2 idle, 0 queued) (233 total active threads) Queries in flight: 0 (0 queued); postgres DB 613 connections: 0/2 (0 threads blocked) {:metabase-user-id 1}
```

note the post is cancelled but no big stack trace

* postgres test

* format file

* move postgres tests into postgres

* improve tests

---------

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-12-02 11:19:18 -06:00
github-automation-metabase
4343c39629 Update generated docs (release-x.57.x) (#66453)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-02 10:08:57 -05:00
github-automation-metabase
6d73d4b478 Closes EMB-1063 docs url (#66460) (#66463)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-12-02 14:47:28 +00:00
github-automation-metabase
ec54fec881 Use backfill specific event to prevent card revisions (#66401) (#66423)
* use backfill specific event

* fix kondo

* add test

* fix config modules

* add migration

* remove migrations

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-12-02 12:05:39 +00:00
github-automation-metabase
2c3e1ff6ce UXW-2310 Fix upsell CTA misalignment & stepper card overflow on custom fonts (#66443) (#66445)
* fix: avoid breaking spaces on upsell CTA link

* fix: exchange `h` for `mih` on stepper card components and allow for flexible height

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2025-12-01 23:51:35 +00:00
github-automation-metabase
800adad31d Update generated docs (release-x.57.x) (#66414)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-01 16:22:48 -05:00
github-automation-metabase
fcac869e99 remove env vars that now have defsettings (#66434) (#66436)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-12-01 20:19:46 +00:00
github-automation-metabase
d92f548398 Docs: DBs for editable tables (#66276) (#66435)
* Add Metabase Sample Database to editable tables support

Updated the list of databases that support editable tables to include Metabase Sample Database.

* Update docs/data-modeling/editable-tables.md

* Update docs/data-modeling/editable-tables.md

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-12-01 19:10:02 +00:00
github-automation-metabase
b645842b29 Update generated docs (release-x.57.x) (#66303)
Co-authored-by: github-actions <github-actions@github.com>
2025-12-01 13:44:05 -05:00
github-automation-metabase
51ced1920d Closed connection with many fields (#66051) (#66429)
Fix legacy path (for snowflake with large number of fields)

Co-authored-by: Eric Normand <ericwnormand@gmail.com>
2025-12-01 17:12:34 +00:00
github-automation-metabase
a868e1b529 Update selector for loki test in Palette.stories (#66333) (#66370)
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-12-01 11:14:04 -04:00
Timofey Kachalov
85f146f7a2 Don't show SDK settings in OSS version (#66402) 2025-12-01 19:06:51 +04:00
github-automation-metabase
3a2f3c3a57 [perf] More efficient validator-cache old key eviction (#65890) (#66408)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-29 19:07:00 +00:00
github-automation-metabase
bfd7e331ca [MBQL lib] Allow string literals as arg to aggregations like :max (#66220) (#66316)
Fixes #66199.

`metabase.legacy-mbql.schema`, now used for normalizing MBQL 4 in
place of the old bespoke normalization in earlier versions, regressed in
this weird but legitimate use case: Writing a custom aggregation like
`MAX("String Literal")`.

That's an odd thing to do, but it can be useful to provide a label in an
aggregated query. This is the MBQL equivalent of
`(SELECT ..., 'A' as label FROM ...) UNION ALL (SELECT ..., 'B' as label ...)`

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-11-28 14:00:01 +00:00
github-automation-metabase
919e4b9167 updating watermark svg color and opacity (#66339) (#66375)
* updating watermark svg color and opacity

* static viz development mark has same color and opacity as dynamic viz

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-11-27 17:24:31 +00:00
github-automation-metabase
ee07dee89f Fix broken PDF export layout due to CSP violation for inline styles (#66337) (#66371)
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
2025-11-27 14:44:32 +00:00
github-automation-metabase
22c711ea8f fix false positive logs (#66325) (#66366)
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
2025-11-27 14:39:24 +00:00
github-automation-metabase
a4b4f742e9 Make file-path triggers more robust (#66311) (#66367)
This pull request refactors and streamlines the configuration for CI workflows and file path groupings in .github/file-paths.yaml and updates related workflow logic in .github/workflows/run-tests.yml. The changes focus on consolidating shared configuration, improving maintainability, and removing redundant or unused path groups.

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-27 15:19:18 +01:00
github-automation-metabase
291a18dec6 UXW-1778 remove chart hover effects when exporting to png (#66200) (#66329)
* UXW-1778 remove chart hover effects when exporting to png

* Fix typing and unit tests

* review fix

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-26 21:13:16 -05:00
github-automation-metabase
b8d55429bf Add :database_type to metabot tools that return column metadata (#66302) (#66350)
* Add :database_type to metabot tools that return column metadata

Add :database_type to metabot tools that return column metadata in order to give metabot information about the real
database type when generating SQL.

Examples of places the :database_type now appears:

- :used_tables in :user_is_viewing context
- {table,card,metric}-details
- get-query-details
- enhanced-database-tables

* Fix test after rebase onto #66271

Fix get-table-details-database-type-test after rebase (1) use new field-id formatting (2) get-table-details no longer returns implicitly-joinable fields
in the top-level `:fields`.

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
2025-11-27 00:47:36 +00:00
github-automation-metabase
ddd6a8f3c7 Revised approach to related_tables and consistent field IDs for implicitly-joined fields (#66271) (#66346)
* More flexible approach to resolving columns from metabot field_ids

* fix one field-stats-test

* fix field-stats-test

* support nano-ids in field ids (?)

* remove some dead code

* Exclude implicitly joinable fields when fetching cols for table

* try switching field format to use dash

* fix field IDs in a number of tests

* Kondo

* add some unit tests for new field parsing & column lookup helper fns

* Fix more tests

* Fix more tests

* fix regex

* New approach -- use wide field IDs in related_tables and add a related_by field for each table

* Fix some tests

* remove unneeded table

* cleanup, new test

* Revert to passing in & matching on expected prefix

* Address tyler's comments

* accept a regex for the prefix as well

* add back small malli group-by fix from the last PR - removed unintentionally during revision

Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
2025-11-26 21:44:30 +00:00
github-automation-metabase
3f0396d1f7 Add warning for when mismatch in serdes version during loading (#66140) (#66344)
Co-authored-by: Nathan Voxland <nathan@metabase.com>
2025-11-26 21:14:18 +00:00
github-automation-metabase
c1fd52467e UXW-2228 Properly mention available subscription & alert channels for non-admins (#66273) (#66323)
* fix: add missing channels to copy & rendering logic

Mentioned webhooks and Slack where necessary to stay consistent with the
admin UI

* fix: standardize lowercase 'admin' & prefer 'email' over 'SMTP'

* fix: remove extra comma on wording

* test: adjust e2e test assertions

* test: add `DashboardSubscriptionMenuItem.unit.spec.tsx`

* test: extract single case from `describe` block

* test: fix subscriptions e2e case & text lookup on alert spec

Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2025-11-26 15:44:59 +00:00
github-automation-metabase
6448cc06b9 fix: anchor table info popover to bottom (#66226) (#66247)
Since `position` was set to `top`, the popover had little space to
expand upwards, and the box was cut-off before reaching the anchor
point.

Co-authored-by: Gabriel Moreno <gantoreno@gmail.com>
Co-authored-by: Gabriel Moreno <gabriel@metabase.com>
2025-11-26 15:44:44 +00:00
github-automation-metabase
6f045a11a1 Get user attributes from attributes map (#66274) (#66321)
* Get user attributes from attributes map

* fixup! e2e test

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2025-11-26 15:09:42 +00:00
github-automation-metabase
d63ee75f63 update file path to include tsx extension for component tests (#66254) (#66310)
Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-26 10:10:11 +00:00
github-automation-metabase
3446900d0a GDGT-1252: Respect show mini bar chart setting in list view (#66012) (#66241)
* GDGT-1252: Make list view consider mini-bar-chart setting

* GDGT-1252: Fix incorrect model settings update when changing columns settings

* GDGT-1252: e2e test

* GDGT-1252: Fix unit test for ListViewItem

* GDGT-1252: Address PR comments. Minor refactoring

* GDGT-1252: Refactor DatasetEditor to get rid of modelSettings hack

* GDGT-1252: Update e2e test to cover settings persistence

* Update Loki Snapshots

* Revert Loki update

---------

Co-authored-by: Stas Gavrylov <stas@metabase.com>
2025-11-26 08:44:13 +00:00
github-automation-metabase
1780161984 Split Redshift driver tests into two jobs (#66289) (#66290)
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-11-26 00:25:35 +00:00
github-automation-metabase
4575d505dc Always pass the input conditions to sdk jobs (#66269) (#66284)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-25 22:06:21 +00:00
github-automation-metabase
dacf4b3268 Update generated docs (release-x.57.x) (#66231)
Co-authored-by: github-actions <github-actions@github.com>
2025-11-25 21:35:10 +00:00
github-automation-metabase
78a9f634ca Add :database_engine to metabot table-details and card-details (#66227) (#66278)
These tools already included :database_id in the results; we now include the :database_engine as well, to give metabot
a reminder about which SQL dialect it should generate.

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
2025-11-25 21:21:01 +00:00
github-automation-metabase
85c6adb389 add deprecation support to defendpoint dox-gen (#66053) (#66268)
Co-authored-by: bryan <bryan.maass@gmail.com>
2025-11-25 19:53:53 +00:00
github-automation-metabase
4421e6e842 ci(sdk): only setup specific enterprise plugins in sdk unit tests as needed (#66238) (#66270)
Co-authored-by: Phoomparin Mano <poom@metabase.com>
2025-11-25 19:34:01 +00:00
github-automation-metabase
a150ca7cbc 🤖 backported "Run JAR health check only on master and release branches" (#66256)
* Run JAR health check only on master and release branches (#66237)

* Fix JAR health check condition logic (#66266)

Addresses this finding by the Claude code review:
https://github.com/metabase/metabase/pull/66237#discussion_r2560704357

---------

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-25 20:25:29 +01:00
github-automation-metabase
5a86603d43 Move audit installation before search initialization again (#66222) (#66260)
Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
2025-11-25 19:24:11 +00:00
github-automation-metabase
e12dd9c230 [QP] Allow one-sided :number/between parameter values (#65987) (#66019)
Fixes #65714.

These are sent as `:number/<=` or `:number/>=` and the validation was
too strict from 57 onward. Added a test for none, min, max, and both
ends of a Between filter.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-25 15:11:15 +00:00
github-automation-metabase
62185a439e chore(sdk): remove excessive logs in sdk fixup script (#66133) (#66146)
Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-25 14:37:15 +00:00
github-automation-metabase
492a74538f docs - fix docstring (#66134) (#66141)
* doc string

* edit

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-25 13:50:51 +00:00
github-automation-metabase
b1cc6c38b6 Fix purchase page for paid Metabase AI add-on for non-store users (#66086) (#66229)
### Description

Missing billing information is treated as an error for purposes of
displaying the purchase page with prices.  Non-store users cannot
retrieve billing information.  Thus, previously, they would always see
an error page: "Error fetching information about available add-ons."
With this change, they see the "Please ask a Metabase Store Admin" page
as intended.

We achieve this by splitting the page content for store users from that
of non-store users.  Only the former needs to load data (billing and
add-on information), so only that page needs `LoadingAndErrorWrapper`.
For store users we show no dynamic content that could fail to load
(apart from a store user's email address, which we gracefully omit if
it is missing).

### How to verify

1. Ensure you have a token with the `offer-metabase-ai-tiered`
   feature, but without the `metabot-v3` and `offer-metabase-ai`
   features.
2. As a Metabase user with an email address that *does not* match any
   of the token's organization's store user email addresses, navigate
   to `/admin/metabot` and see "Please ask a Metabase Store Admin".
3. As a Metabase user with an email address that *does* match any
   of the token's organization's store user email addresses, navigate
   to `/admin/metabot` and see the purchase page with tier selector.

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

Fixes: 2b76c38e1f
Closes: https://metaboat.slack.com/archives/C07RMUQ0GE5/p1763644357893079

Co-authored-by: Dennis Schridde <63082+devurandom@users.noreply.github.com>
2025-11-25 02:57:21 +00:00
github-automation-metabase
0d8a03e84e Improve how skipped SDK tests are handled (#66211) (#66224)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-24 22:52:57 +00:00
github-automation-metabase
cda078513d Move audit installation after search init; change some logs to debug (#66045) (#66195)
* Move audit installation after search init; change some logs to debug

* change another warn to debug

Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
2025-11-24 22:04:21 +00:00
github-automation-metabase
f285c79bfe Fix #65501 - Resets search back to first page when filters change (#66104) (#66218)
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-11-24 16:22:42 -05:00
github-automation-metabase
b08483c3d0 Cancel jobs in bigquery (#66054) (#66213)
* cancel bigquery jobs

* move .cancel to promise handling

* wrap .cancel in try catch finally

* use getqueryresults instead of .query

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-11-24 20:11:08 +00:00
github-automation-metabase
820b98d43c Two quality-of-life improvements for @-mentions (#66131) (#66216)
* QoL improvements for @-mentions

* Add a unit test for new tab click behavior

Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
2025-11-24 20:03:45 +00:00
github-automation-metabase
5c0a472444 Make sure 'Pull changes' button is not truncated on remote sync settings (#65932) (#65963)
Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
2025-11-24 19:36:14 +00:00
github-automation-metabase
4af5e3012f Fix trend viz dates diff calculation for a year unit (#65985) (#66201)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-24 16:46:55 +00:00
github-automation-metabase
666377d876 Fix uberjar fetching for SDK host-apps (#66194) (#66196)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-24 15:16:33 +00:00
github-automation-metabase
a3abc1e8f1 Add translation for boolean dash filter value (#66050) (#66191)
* Add translation for boolean dash filter value

* Fix CI

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-24 14:31:57 +00:00
github-automation-metabase
371be27f83 Fix timeseries value detection (#66161) (#66162)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-24 14:19:51 +00:00
github-automation-metabase
2824b0188a Prevent driver tests (#66156) (#66164)
Co-authored-by: dpsutton <dan@dpsutton.com>
Co-authored-by: Bryan Maass <bryan.maass@gmail.com>
2025-11-24 14:46:16 +01:00
github-automation-metabase
5dadd4d393 Closes EMB-1037 preview_embed endpoint for filter search (#66077) (#66115)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-24 12:21:43 +01:00
github-automation-metabase
5de1be6b3b Parallelize embedding SDK package and uberjar builds (#66122) (#66186)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-24 11:11:48 +00:00
Nemanja Glumac
5b81c3ef53 Manual backport of the recent caches changes (#66145) 2025-11-22 00:37:09 +01:00
github-automation-metabase
7856184a38 Clean up backend-test matrix (#66158) (#66160)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-22 00:33:30 +01:00
github-automation-metabase
4e0046b23f Fetch uberjar using a proper action (#66165) (#66166)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-21 23:27:30 +00:00
github-automation-metabase
f06c5d7d96 Fix flaky Remote Sync test (#65862) (#66159)
Co-authored-by: John Swanson <john.swanson@metabase.com>
2025-11-21 20:12:54 +00:00
github-automation-metabase
568dde39b2 Remove redundant static-viz files changed condition (#66138) (#66142)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-21 16:54:19 +00:00
github-automation-metabase
aff83af2e3 Add empty state to native query DB dropdown (#66090) (#66127)
* add global search to db dropdown

* Add tests

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-11-21 15:49:26 +00:00
github-automation-metabase
0f71481d47 docs - light weeding (#66023) (#66092)
* spelling

* docstring

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-21 08:59:53 -05:00
github-automation-metabase
17d40f681f Consolidate embedding CI workflows (#66075) (#66119)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-21 12:18:05 +00:00
github-automation-metabase
17b47b91fb Closes EMB-1038 wrong endpoint for embed maps preview (#66063) (#66114)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-21 08:46:42 +00:00
github-automation-metabase
35ee104a5d minimal tests to be run when the label is minimal-tests (#66024) (#66100)
* minimal tests to be run when the label is `minimal-tests`

* include enterprise tests, fix syntax

* bump CI

* don't fail if label is absent

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-20 21:45:21 +00:00
github-automation-metabase
2dc1acfd9f chore(sdk): fix sdk storybook (#66078) (#66085)
* chore(sdk): fix sdk storybook

* use rootRepoPath for appConfig

Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-20 18:26:53 +00:00
github-automation-metabase
9155867efa refactor(embed-js): Move EmbedJS + EmbedJS wizard files to OSS folder (#66067)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-20 16:47:04 +04:00
github-automation-metabase
2de6ecf19a chore(sdk,ci): fix stress tests for sdk tests (#66065) (#66068)
* chore(sdk,ci): fix stress tests for sdk tests

* fix baseUrl, cypress explodes if we pass it in ct test config

Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-20 11:18:32 +00:00
github-automation-metabase
03302b0086 Nicola/glossary creator api (#65961) (#65970)
* feat: glossary, actually add creator_id on create endpoints

* feat: add creator_id tests on api

Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
2025-11-20 10:54:41 +00:00
github-automation-metabase
d032ca1774 Add creator to transform content view, and include glossary (#65957) (#65960)
* feat: add creator_id to content view for transforms

* feat: add creator to glossary

* feat: glossary entries in content

* add creator test

* missing creator_id

Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
2025-11-20 10:03:54 +00:00
github-automation-metabase
2d94d4ab0b Add bottom padding for Attach results as files section (#62483) (#66064)
Co-authored-by: Ngoc Khuat <qn.khuat@gmail.com>
2025-11-20 10:00:03 +00:00
github-automation-metabase
48d495387a [Metabot] Request cancellation (#65511) (#66052)
* fix cut not removing text from input

* ensure we fetch all data for all possible models for smart links

* remove unused comment

* fixes smart links in metabot input sometimes degrading into their text representation and fixes some cases where wrong model name ("model" instead of "dataset") was used for metabot links

* fix unit tests

* ui for cancelling a request, handles state updates for canceled requests

* press esc to cancel metabot request, fix state being incorrect on requests after an aborted request

* add test coverage for ui, update test utils to enable aborting requests in unit tests, small bits of clean up

* add tests to processStream function

* update snapshot

Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2025-11-20 00:08:27 +00:00
github-automation-metabase
c074825e5c Change images for development and production settings (#66039) (#66041)
Updated images in the remote sync documentation to reflect new settings.

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-19 20:55:08 +00:00
github-automation-metabase
280ccdb0e0 Update plans-blockquote inclusion for documents (#66038) (#66040)
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-19 20:54:23 +00:00
github-automation-metabase
babb5a6357 fix: allow analytics collection perms to be set (#65927) (#65974)
* fix: allow analytics collection perms to be set

In #65098, we did not fully replicate the behavior of the old graph
endpoint where collection namespacing rules aren't applied to the
"analytics" namespace. Collections in this namespace can be modified as
though they are part of the root `nil` namespace. The bug was in
removing collections not part of the targetted namespace of the
`update-graph!` funciton from the graph to update.

This restores the old behavior by not excluding collection permissions
updates for collections in the "analytics" namespace in the
`remove-collections-from-other-namespaces` function.

it also updates our tests for the collection graph to make sure mock
analytics collections have the right namespace set rather than a `nil` namespace.

* fixup! reset revisions

* fixup! tests to EE module fix tests in EE module

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2025-11-19 18:13:19 +00:00
github-automation-metabase
a7cbdac451 fix(docs): fix sdk docs not being generated correctly (#66030) (#66031)
Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-19 12:15:20 -05:00
github-automation-metabase
a9e5197ba8 Fix incorrect tooltip metric sum in row chart (#65938) (#65969)
* Fix incorrect tooltip metric sum in row chart

* Review fixes

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-19 16:22:10 +00:00
github-automation-metabase
f8fec179a0 docs - X version note and cleanup (#65756) (#66017)
* X version note and cleanup

* note on hotfix x

* edit

* note on beta

* changelog link

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-19 14:19:02 +00:00
github-automation-metabase
699633dbdb Cache yarn in CI (#65946) (#66013)
Co-authored-by: Fraser <fraser@metabase.com>
2025-11-19 15:03:14 +01:00
github-automation-metabase
2d2126dfd0 De-clutter the Cypress (nodejs) Module runner (#65881) (#66000)
Running Cypress tests doesn't have to be hard.

This PR is moving us in a direction where (1) there's some logic that sets up the environment for e2e testing, and then (2) there's a simple command to invoke cypress (aka "decoupling" or "separation of concerns")

Cypress only needs to know which config to look at. It contains all the information it needs to run.

There are two ways to invoke Cypress:

1. Cypress cli
2. Cypress Module API (programmatic entry point)

They should be compatible and interchangeable. Anything you pass to the node module as options can be passed as individual flags to the cli.

```
npx cypress run --config-file path/to/some/config --spec path/to/spec.cy.spec.ts
```

is equivalent to

```
cypress.run({ configFile: "path/to/some/config", spec: "path/to/spec.cy.spec.ts" });
```

This PR removes all abstractions from the actual node module runner.

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-19 14:03:54 +01:00
github-automation-metabase
87af82b30c Closes EMB-982 embedding stuck on 404 when navigating with postMessage (#65662) (#65962)
* Closes EMB-982 postmessage 404

* actual fix

* .

* .

* .

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-19 12:55:25 +00:00
github-automation-metabase
ff97dff2ad Docs: reusing snippet parameters (#65723) (#66008)
* reusing snippet parameters

* Update docs/questions/native-editor/snippets.md



* updating the section

---------

Co-authored-by: Abed Habli <154609371+abdhabli@users.noreply.github.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-19 12:30:16 +00:00
github-automation-metabase
6b828bd31b Metabot tool endpoitns should support MBQL5 (#65844) (#66003)
* Metabot tool endpoitns should support MBQL5

* Update filter tool to work with MBQL 5

* Fix find-outliers-wrong-query-test

Was attempting to assoc-in/dissoc-in MBQL4 query keys on an MBQL5 query.

---------

Co-authored-by: Thomas Schmidt <thomas@metabase.com>
Co-authored-by: Mike Appleby <86076+appleby@users.noreply.github.com>
2025-11-19 11:52:18 +00:00
github-automation-metabase
539aa28a27 GDGT-1235 Fix flaky dashboard parameters test (#65902) (#65997)
* Fix flaky test

* Remove broken findDashCardAction helper

Co-authored-by: Kamil Mielnik <kamil@kamilmielnik.com>
2025-11-19 09:10:53 +00:00
github-automation-metabase
3cebdd609a Bump Malli to 0.20.0 (#65909) (#65971)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-19 07:44:28 +00:00
github-automation-metabase
edae47056d Closes EMB-1021 flaky test e2e tests metabase browser read only mode (#65851) (#65965)
* .

* .

* .

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-19 07:33:45 +00:00
github-automation-metabase
76447a8970 Update label placeholder text to Optional for Gauge visualization (#65989) (#65992)
* Update label placeholder text to Optional for Gauge visualization

* Update unit test

Co-authored-by: eliotmetabase <eliot@metabase.com>
2025-11-19 01:38:49 +00:00
github-automation-metabase
5b5e814d9e Turn off db routing for clickhouse and it's trick. (#65984) (#65990)
* Turn off db routing for clickhouse and it's trick.

DB routing needs a "degree of freedom" to run the exact same query
against a different schema/db/instance whatever. Clickhouse only has
database.table. so to db route on the same clickhouse instance you have
to omit the database and let it resolve during query time.

`select * from db.table` can't work. Have to do `select * from table`
and let the connection dictate db1 or db2.

In 56, tables look like this:

```clojure
{:name "upload_records_10k_20251118164620", :schema "db_eafc4346850f435e"}
```

In 57, now they look like this for single db clickhouse things:

```clojure
{:name "upload_records_10k_20251118164620", :schema nil}
```

There are two critical problems here:
1. When uploading, it's not aware to omit the schema. So a table is
created with that schema. During the next sync that table is archived
and a new one with a nil'd schema is created. So the model created for
the uploaded CSV would break as it points to an inactive table. This has
a further compounding issue because now there "appear" to be two schema:
the faked nil one and also a new one like `db_eafc...`.
2. But _all_ tables will be archived in the same manner which were
initially found in 56 or below. These tables will be marked as inactive
and new ones created. Meaning all mbql queries based on clickhouse will
fail.

I wanted to revert this change but there's actually a bit more in the PR
and some conflicts. It also does more than just enabling db-routing so I
think we can perhaps undo the damage in this way more easily.

* remove outdated test

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-19 00:30:58 +00:00
github-automation-metabase
4401e6cda7 Fix order by custom expression aggregations (#65937) (#65983)
* fix bigquery order by aggregate custom expression

* add import

* make test work for all drivers

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-11-18 19:46:58 +00:00
github-automation-metabase
49021029f2 🤖 backported "move sdk bundle code to the oss folder" (#65966)
* move sdk bundle code to the oss folder (#65753)

* move the actual sdk folders

* update rspack config and eslint config

* fix relative import in CommonSdkStoryWrapper

* allow default exports in preview.tsx

* update eslint config to allow imports from frontend/src/embedding-sdk-shared

* remove legacy eslint disable directive

* temporarily 'disable' eslint-disable-next-line no-external-references-for-sdk-package-code that has not been ported yet

* update rspack config to use new paths

* update jest config to use new paths

* add `embedding-sdk-package` to restricted imports

* copy eslint files to apply to the new sdk folders

* add eslint-disable-next-line no-restricted-imports to some places where we need emotion

* fix jest setup

* add and use setupEmbeddingSdkEnterprisePlugins

* use `useSetting` instead of `getApplicationColors` to remove enterprise import

* move defineMetabaseAuthConfig to embedding-sdk-shared

* move MetabotProvider to embedding-sdk-bundle

* fix docs generation issue about types

* fix prettier ignore file

* move back tests to ee folder

* remove ../../../ from imports

* fix eslint issues

* fix, again, jest config :sad:

* chore: empty commit to make ci restart

* chore: empty commit to make ci restart

---------

Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-18 19:07:53 +01:00
github-automation-metabase
bb0e49070b Revise quickstart options for Embedded Analytics SDK (#65830) (#65980)
Reorganized quickstart section for clarity based on user setup.

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-18 17:51:19 +00:00
github-automation-metabase
9a0b9d08b9 Allow content-disposition header in cross-origin requests (#65918) (#65951)
Co-authored-by: Phoomparin Mano <poom@metabase.com>
2025-11-18 08:54:21 +00:00
github-automation-metabase
a17766bcea Update snowflake string filtering (#65853) (#65939)
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-11-17 23:13:05 +00:00
github-automation-metabase
a33ecaec07 docs - remote sync rename (#65933) (#65940)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-17 22:32:29 +00:00
github-automation-metabase
a4e15a7fd2 Bump io.netty/netty-common from 4.1.124.Final to 4.2.7.Final (#64827) (#65935)
* Bump io.netty/netty-common from 4.1.124.Final to 4.2.7.Final

Inspect dependency changes here:

* Consolidate deps bumps

---------

Co-authored-by: Cam Saul <github@camsaul.com>
2025-11-17 22:27:32 +00:00
github-automation-metabase
d3c570c727 qp catches circular queries involving both sql and mbql cards (#65875) (#65934)
Co-authored-by: William <william@metabase.com>
2025-11-17 22:10:35 +00:00
github-automation-metabase
087e4ef815 [QP] Allow multiple dashboard/card params to exist, if only one is set (#64428) (#65930)
Fixes #64135.

Previously this code would throw if multiple dashboard and/or card
params were bound to the same SQL variable. Now multiple links are
allowed, provided that only one is actually given a value.

Actually, this logic de-duplicates the values, so if multiple filters
all set the same value, that also works.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-11-17 21:39:57 +00:00
github-automation-metabase
5b55d9bf7e Better human readable table-data-event for audit-log (#65907) (#65924)
* abstract action-v2-execute events behind table-data-edit for audit-log

* add test

* chore: still publish

Co-authored-by: Nicola Mometto <nicola.mometto@metabase.com>
2025-11-17 20:02:37 +00:00
github-automation-metabase
6cb0b37ac6 Run Codespell on docs/ (#65925) (#65926)
* Run Codespell on docs/

* Only run of docs/

Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-11-17 19:41:56 +00:00
github-automation-metabase
d04e2f913b Correctly sync routed databases in task (#65441) (#65921)
* Correctly sync routed databases in task

Before:

```clojure
(sync-and-analyze-database*! 598)
2025-11-04 21:30:48,550 INFO task.sync-databases :: Starting sync task for Database 598.
2025-11-04 21:30:48,626 INFO sync.util :: STARTING: Sync metadata for sqlite Database 598 ''airlines'' (free: 0.54G, total: 1.02G, ratio: 0.53)
2025-11-04 21:30:48,650 ERROR sync.fetch-metadata :: Error while fetching metadata with 'db-metadata'
clojure.lang.ExceptionInfo: Anonymous users cannot access a database with routing enabled.
	at
        metabase_enterprise.database_routing.common$router_db_or_id__GT_destination_db_id.invokeStatic(common.clj:30)
        ....
2025-11-04 21:30:48,660 WARN sync.util :: Error in sync step Sync metadata for sqlite Database 598 ''airlines''
clojure.lang.ExceptionInfo: Anonymous users cannot access a database with routing enabled.
2025-11-04 21:30:48,668 INFO sync.util :: FINISHED: Sync metadata for sqlite Database 598 ''airlines'' (42.6 ms) (free: 0.54G, total: 1.02G, ratio: 0.53)
2025-11-04 21:30:48,669 INFO sync.util :: STARTING: Analyze data for sqlite Database 598 ''airlines'' (free: 0.54G, total: 1.02G, ratio: 0.53)
2025-11-04 21:30:48,678 INFO sync.util :: STARTING: step ''fingerprint-fields'' for sqlite Database 598 ''airlines'' (free: 0.54G, total: 1.02G, ratio: 0.53)
```

And afterwards:

```clojure
2025-11-04 21:31:57,593 INFO task.sync-databases :: Starting sync task for Database 598.
2025-11-04 21:31:57,643 INFO sync.util :: STARTING: Sync metadata for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.50)
2025-11-04 21:31:57,666 INFO sql-jdbc.execute :: Obtaining a fresh resilient connection
2025-11-04 21:31:57,671 INFO sync.describe-database :: "Tweets": SELECT privileges confirmed
2025-11-04 21:31:57,684 INFO sync.util :: STARTING: step ''sync-dbms-version'' for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,693 INFO sync.util :: FINISHED: step ''sync-dbms-version'' for sqlite Database 598 ''airlines'' (9.0 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,693 INFO sync.util :: STARTING: step ''sync-timezone'' for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,696 INFO sync-metadata.sync-timezone :: :sqlite database 598 default timezone is "UTC"
2025-11-04 21:31:57,700 INFO sync.util :: FINISHED: step ''sync-timezone'' for sqlite Database 598 ''airlines'' (7.1 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,701 INFO sync.util :: STARTING: step ''sync-tables'' for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,706 INFO sync-metadata.tables :: :is_writable of Table 6058 ''Tweets'' changed from null to null
2025-11-04 21:31:57,715 INFO sync.util :: FINISHED: step ''sync-tables'' for sqlite Database 598 ''airlines'' (14.1 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,715 INFO sync.util :: STARTING: step ''sync-fields'' for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,743 INFO sync.util :: FINISHED: step ''sync-fields'' for sqlite Database 598 ''airlines'' (27.3 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,743 INFO sync.util :: STARTING: step ''sync-fks'' for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,755 INFO sync.util :: FINISHED: step ''sync-fks'' for sqlite Database 598 ''airlines'' (12.0 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,755 INFO sync.util :: STARTING: step ''sync-indexes'' for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,758 INFO sync.util :: FINISHED: step ''sync-indexes'' for sqlite Database 598 ''airlines'' (3.1 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,758 INFO sync.util :: STARTING: step ''sync-metabase-metadata'' for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,762 INFO sync.util :: FINISHED: step ''sync-metabase-metadata'' for sqlite Database 598 ''airlines'' (4.0 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,771 INFO sync.util :: FINISHED: Sync metadata for sqlite Database 598 ''airlines'' (128.4 ms) (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,771 INFO sync.util :: STARTING: Analyze data for sqlite Database 598 ''airlines'' (free: 0.50G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,783 INFO sync.util :: STARTING: step ''fingerprint-fields'' for sqlite Database 598 ''airlines'' (free: 0.49G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,794 INFO sync.analyze :: fingerprint-fields Analyzed [************······································] 😒   25% Table 6058 ''Tweets''
2025-11-04 21:31:57,801 INFO sync.util :: FINISHED: step ''fingerprint-fields'' for sqlite Database 598 ''airlines'' (17.8 ms) (free: 0.49G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,801 INFO sync.util :: STARTING: step ''classify-fields'' for sqlite Database 598 ''airlines'' (free: 0.49G, total: 1.02G, ratio: 0.49)
2025-11-04 21:31:57,806 INFO sync.analyze :: classify-fields Analyzed [*************************·························] 😬   50% Table 6058 ''Tweets''
2025-11-04 21:31:57,809 INFO sync.util :: FINISHED: step ''classify-fields'' for sqlite Database 598 ''airlines'' (7.7 ms) (free: 0.49G, total: 1.02G, ratio: 0.48)
2025-11-04 21:31:57,809 INFO sync.util :: STARTING: step ''classify-tables'' for sqlite Database 598 ''airlines'' (free: 0.49G, total: 1.02G, ratio: 0.48)
2025-11-04 21:31:57,817 INFO sync.analyze :: classify-tables Analyzed [*************************************·············] 😋   75% Table 6058 ''Tweets''
2025-11-04 21:31:57,822 INFO sync.util :: FINISHED: step ''classify-tables'' for sqlite Database 598 ''airlines'' (13.0 ms) (free: 0.49G, total: 1.02G, ratio: 0.48)
2025-11-04 21:31:57,827 INFO sync.util :: FINISHED: Analyze data for sqlite Database 598 ''airlines'' (55.4 ms) (free: 0.49G, total: 1.02G, ratio: 0.48)
```

* add a test

this was the best i could do at first. Whats annoying is that sync steps
are so resilient to errors that it's hard to get their return values. So
kinda hate that i'm checking the database log table for task history but
here we are.

* way better tests

* reorder requires

* update module config

* some cloud dbs have multiple tables in the same catalog

the definition of the dataset is:

```clojure
[["t"
  [{:field-name "f", :base-type :type/Text}]
  [["original-foo"]
   ["original-bar"]]]]
```

But cloud databases often fake the separation with things like
prepending the dataset name to the table name to simulate separation
while using only a single catalog or equivalent

* typo

* assert positive integer on total tables

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-17 19:03:19 +00:00
github-automation-metabase
7393384666 EAJS wizard should derive a lighter dashboard background color (#65547) (#65919)
Co-authored-by: Phoomparin Mano <poom@metabase.com>
2025-11-17 17:11:23 +00:00
github-automation-metabase
4c1ac01406 Remove custom embedding SDK cors config (#65910) (#65911)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-17 17:13:59 +01:00
github-automation-metabase
c1319ab25a Simplify Snowplow Cypress helpers (#65859) (#65899)
* Remove custom describeWithSnowplow constructs

* Update tests

* Update dev docs

* Log message when sending Snowplow request

* Rename empty describe to 'Snowplow analytics'

* Remove 'describeWithSnowplow' from ESLint rules

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-17 14:06:51 +01:00
github-automation-metabase
62d7ffc4f1 Fix dashboard.backgroundColor: transparent breaking dashboard PDF export (#65847) (#65894)
Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-11-17 10:19:34 +00:00
github-automation-metabase
f89b726e11 Preparation for moving sdk code to oss folder (#65428) (#65852)
* implement plugins for auth

* move some stuff to the oss folder as those file create issues later on

* make embedding-sdk:docs:generate pass

* move metabot to use plugins

* remove imports from package from other folders

Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-17 08:46:09 +00:00
github-automation-metabase
2edc17db37 Remove e2e tests for info popovers in field picker (#65883) (#65888)
Removed multiple tests related to info popovers for field picker options and saved questions.

This behavior is already covered with a unit test at:
`frontend/src/metabase/common/components/MetadataInfo/ColumnInfoIcon/ColumnInfoIcon.unit.spec.tsx`

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-17 00:11:45 +00:00
github-automation-metabase
4e6462dad2 Don't set last_used_param_values for public (#64432) (#65876)
Fixes UXW-216

Co-authored-by: John Swanson <john.swanson@metabase.com>
2025-11-15 00:22:23 +00:00
github-automation-metabase
a3c1f5c8ff Fix batch-upsert! method for heterogeneous entries (#65177) (#65877)
* Fix the update keys for postgres search idx upsert

The upsert keys were calculated by looking at the first entry we were
inserting and removing `:id`, `:model`, and `:model_id`.

But the entries are not necessarily homogeneous. In this case, the first
entry is a dashboard (has no `:dashboard_id`) and the second entry is a
card (yes `:dashboard_id`).

This meant we never actually updated the dashboard_id when updating a card.

I attempted to add a test for this:

```
(deftest updates-work-properly
  (mt/with-test-user :rasta
    (mt/with-temp [:model/Dashboard {dash-id :id} {}]
      (let [card-name (str (random-uuid))
            card-id-1 (:id (mt/user-http-request :rasta :post 200 "card/" {:name card-name
                                                                           :collection_id nil
                                                                           :database_id 1
                                                                           :display "table"
                                                                           :creator_id (mt/user->id :rasta)
                                                                           :visualization_settings {}
                                                                           :dataset_query {:type "native" :native {:query "select 123"}
                                                                                           :database 1}}))
            card-id-2 (:id (mt/user-http-request :rasta :post 200 "card/" {:name card-name
                                                                           :collection_id nil
                                                                           :database_id 1
                                                                           :display "table"
                                                                           :creator_id (mt/user->id :rasta)
                                                                           :visualization_settings {}
                                                                           :dataset_query {:type "native" :native {:query "select 123"}
                                                                                           :database 1}}))]
        (mt/user-http-request :rasta :put 200 (str "card/" card-id-1) {:dashboard_id dash-id})
        (is (= [card-name]
               (map :name (:data (mt/user-http-request :rasta :get 200 "search" :q card-name)))))))))
```

The good news is that this test passes after my change. The bad news is
that it also passes without my change. I think what's going on is that
the behavior is different with `*force-sync*` on/off: in async mode, we
get the full batch that contains the updates for `[dashboard, card]`.
In synchronous mode, we get separate batches for `[dashboard]` and then
`[card]`.

I think we might want to rework tests somehow - it would be quite nice
to be able to still run things asynchronously but drain the queue before
making assertions, so the behavior wouldn't be different between
tests/prod.

* add a test

Co-authored-by: John Swanson <john.swanson@metabase.com>
2025-11-15 00:13:19 +00:00
github-automation-metabase
d3168f6c68 Replace snowflake test password auth with key pair auth (#65522) (#65869)
* replace password with key pair auth

* re enable snowflake tests

* add private key env var

* update private key details for temp dbs

* small changes

* fix describe database test

* fix multi method params

* update test

* update test

* try fix

* check CI

i noticed that this tests pass if we don't put a connection-uri in
there. I'm not sure what the original intent was, but the following
works just fine:

```
{:url "jdbc❄️//<account>.snowflakecomputing.com/?schema=INFORMATION_SCHEMA",
 :properties {"use-password" "false",
              "connection-uri" "jdbc❄️//<account>.snowflakecomputing.com/?user=<user>CI&private_key_file=%2Fprivate%2Fvar%2Ffolders%2F1d%2F3ns5s1gs7xjgb09bh1yb6wpc0000gn%2FT%2Fmetabase-secret_8808579641027884666.tmp&schema=INFORMATION_SCHEMA",
              "client_session_keep_alive" "true",
              "timezone" "UTC",
              "warehouse" "<warehouse>",
              "user" "<user>",
              "ssl" "true",
              "private_key_file" "/var/folders/1d/3ns5s1gs7xjgb09bh1yb6wpc0000gn/T/metabase-secret_8808579641027884666.tmp",
              "week_start" "7",
              "application" "Metabase_Metabase",
              "account" "<account>",
              "db" "\"<db>\"",
              "time_output_format" "HH24:MI:SS.FF3",
              "client_metadata_request_use_connection_ctx" "true"}}
```

When it goes through clojure.java.jdbc. Somehow we are getting a
connection string that doesn't play nice. I _think_ it may just be an
issue with snowflake but i'm not positive.

* remove parallel test markers

* remove parallel marker

when running tests locally with these removed:

```clojure
(run/find-and-run-tests-repl {:only 'metabase.driver.snowflake-test})
...
Ran 49 tests in 116.525 seconds
502 assertions, 1 failure, 0 errors.
{:test 49, :pass 501, :fail 1, :error 0, :type :summary, :duration 116525.006833, :single-threaded 32, :parallel 17}
```
yields only one expected error. Previously using regular stuff also
worked

```clojure
snowflake-test=> (run-tests)

Testing metabase.driver.snowflake-test

Ran 49 tests containing 502 assertions.
1 failures, 0 errors.
{:test 49, :pass 501, :fail 1, :error 0, :type :summary}
```

(again the single test that failed). but using the CLI tool i would get
errors when running them in parallel.

* fixup stupid snowflake

1. i don't know why we are running into multithreading issues now. But
i've removed those tags and the issues are gone.
2.

```clojure
snowflake-test=> (let [spec {:connection-uri "jdbc❄️//account.snowflakecomputing.com/?schema=INFORMATION_SCHEMA&user=<user>&password=<password>&db=%22v5_airports%22"}]
                   [(jdbc/query spec ["select CURRENT_DATABASE() db"])
                    (jdbc/query spec ["select CURRENT_SCHEMA() db"])])
 [({:db "v5_airports"}) ({:db "INFORMATION_SCHEMA"})]
snowflake-test=> (let [spec {:connection-uri "jdbc❄️//account.snowflakecomputing.com/?schema=INFORMATION_SCHEMA&user=<user>&password=<password>&db=v5_airports"}]
                   [(jdbc/query spec ["select CURRENT_DATABASE() db"])
                    (jdbc/query spec ["select CURRENT_SCHEMA() db"])])
[({:db nil}) ({:db nil})]
```

In the above, note that putting the db in the connection string _and
url-encoding it_ (it's already quoted) is necessary.

* conditionally add db

in tests there's not a database so just be smart about it:

```clojure
{:warehouse "<warehouse>",
 :additional-options nil,
 :timezone "UTC",
 :db nil,
 :account "<account>",
 :use-password false,
 :time_output_format "HH24:MI:SS.FF3",
 :user "<user>",
 :subname "//<account>.snowflakecomputing.com/"}
```

* address pr comments

* remove outdated comment

pretty freaky comment eh? I added this when i commented out the
`handle-conn-uri` call underneath it and it caused tests to pass. That
was helpful in identifying the mechanism, but not a good solution. Put a
comment here so that that was not a final state, forgot to remove
comment when we got to a proper final state and `handle-conn-uri` was
fixed.

---------

Co-authored-by: Riley Thompson <riley@metabase.com>
Co-authored-by: dan sutton <dan@dpsutton.com>
2025-11-14 21:53:38 +00:00
github-automation-metabase
851a53b163 [QP] Only label remaps for columns that actually need it (#65860) (#65868)
Fixes #65726.

If you implicitly joined a field that happened to be the target of a
remapping, the QP was labeling it as `:remapped_from` the FK even
though (a) it wasn't really remapped and (b) there was no
corresponding FK column marked as `:remapped_to` the target column.

(Eg. `Orders.PRODUCT_ID` is remapped to `Products.TITLE`. Then I
implicitly join `Products.TITLE` directly and the QP marks it as
remapped from `Orders.PRODUCT_ID` even though it wasn't.)

That caused the FE to do odd things like drop and relabel columns.

This change adjusts the QP so it will ignore plausible remappings that
don't actually get returned from the last stage.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-11-14 19:48:36 +00:00
github-automation-metabase
0f37bd54c6 Suppress liquibase output (#65858) (#65864)
We get a bunch of this useless stuff in CI:

```
Placeholder until other changesets

UPDATE SUMMARY
Run:                        641
Previously run:               0
Filtered out:                69
-------------------------------
Total change sets:          710

FILTERED CHANGE SETS SUMMARY
DBMS mismatch:               69
```

Looking for this in liquibase this is not logged but printed to the
console :(.

It goes through this:

```java
    private static void writeMessage(String message, UpdateSummaryOutputEnum showSummaryOutput, OutputStream outputStream) throws LiquibaseException {
        switch (showSummaryOutput) {
            case CONSOLE:
                writeToOutput(outputStream, message);
                break;
            case LOG:
                writeToLog(message);
                break;
            default:
                writeToOutput(outputStream, message);
                writeToLog(message);
        }
    }
```

So we want that enum to be LOG.

```clojure
liquibase=> (clojure.reflect/reflect liquibase.Liquibase)
{:bases #{java.lang.Object java.lang.AutoCloseable},
 :flags #{:public},
 :members #{ ,,,
             #clojure.reflect.Method{:name setShowSummaryOutput,
                                    :return-type void,
                                    :declaring-class liquibase.Liquibase,
                                    :parameter-types [liquibase.UpdateSummaryOutputEnum],
                                    :exception-types [],
                                    :flags #{:public}}
          ,,,}}
```

So easy fix. Set this enum and hopefully it shuts up.

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-14 18:48:48 +00:00
github-automation-metabase
befd9bc11e Fix athena sync 65728 (#65777) (#65863)
* claude fix

* simplify

* handle nested fields for athena

* nfc have position 0

* set non leafs as details only

* clean up parser and add tests

* whitespace

* disable nested fields

* kondo

* kondo

* disable nested schema test

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-11-14 18:31:15 +00:00
github-automation-metabase
32f724e094 Fix append for CSVs with really long column names with shared prefixes (#65793) (#65856)
Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
2025-11-14 17:17:49 +00:00
github-automation-metabase
0f6df45cf4 docs - document links new charts (#65828) (#65861)
* links and new charts

* links

* edits

* Update docs/documents/introduction.md

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-14 17:14:40 +00:00
github-automation-metabase
f03f9fbd6b Revert param values from query results (#65841) (#65850)
* Revert "Adjust cards-with-filters to work with action cards (#65805)"

This reverts commit d6b857a2c6.

* Revert "Fix mapping of params to later query stages (#65651)"

This reverts commit c98e640426.

* Revert "Compute param values from card results (#64318)"

This reverts commit 2693173e7f.

Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
2025-11-14 15:05:56 +00:00
github-automation-metabase
dfdf323be1 fix(sdk-bundle): Fix EditableDashboard sometimes doesn't show the correct tab (#65802) (#65836)
* Fix SDK save dashboard question to not show collection/dashboard picker

* Fix EditableDashboard sometimes doesn't show the correct tab on first render

* Add an assertion

* left some breadcrumbs

* Update unit tests to be async

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-11-14 04:27:26 +00:00
github-automation-metabase
7521a727d7 remove flaky tag (#65741) (#65829)
Co-authored-by: Fraser <fraser@metabase.com>
2025-11-13 23:00:40 +00:00
github-automation-metabase
2a122f4720 Fix code that populates :used_tables in metabot context (#65787) (#65827)
* Fix code that populates :used_tables in metabot context

This was causing :used_tables to be absent in the :user_is_viewing
context, limiting metabot's ability to get sql fixing right without
information about the available tables and their fields.

Call lib-be/normalize-query and lib/native-only-query? in
metabase-enterprise.metabot-v3.context/query-for-sql-parsing and
likewise use lib funcs to get template-tags in
metabase-enterprise.metabot-v3.query-analyzer.parameter-substitution/replace-tags

* Update ai-sql-fixer and tests to work with MBQL5 queries

* Fix metabot-v3.table-utils-test to use MBQL5 queries

Conflicts:
	enterprise/backend/test/metabase_enterprise/metabot_v3/context_test.clj

Co-authored-by: appleby <86076+appleby@users.noreply.github.com>
2025-11-13 22:41:47 +00:00
github-automation-metabase
cfe47f65d8 Rename handleLink.tsx to handlelink.tsx (#65821) (#65822)
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-13 20:07:37 +00:00
github-automation-metabase
8f80d29ca5 🤖 backported "Add purchase page for paid Metabase AI add-on" (#65764)
In #62513 we added a page to offer a Metabase AI (Metabot) trial.  Now
we want to offer to purchase the paid Metabot add-on.

### How to verify

1. Ensure you have a token with the `offer-metabase-ai-tiered`
   feature, but without the `metabot-v3` and `offer-metabase-ai`
   features.
2. Ensure you have a Metabase API key linked to that same token.
3. Navigate to `/admin/metabot` and see a page offering you to purchase
   different quantities of Metabot queries.
4. Select a quantity (or go with the default of 500), check "I agree",
   then click "confirm purchase".
5. Confirm that your token now has the `metabot-v3` feature and the
   associated subscription has an appropriate Metabase AI product.

### Checklist

- [x] Tests have been added/updated to cover changes in this PR

### Notes

* Rename MetabotPurchasePage to MetabotTrialPage
  - and add the page for the purchase of the paid add-on as
    `MetabotPurchasePage`, to make the name more clearly represent the
    purpose (paid vs. trial).
* Move frontend client for /api/ee/cloud-add-ons into metabase-enterprise/api
* Use ts-pattern instead of hand-crafted type guards in Metabot trial page
* Don't swallow errors when submitting Metabot purchase form
* Create Redux selector to derive isStoreUser
* Test failures to purchase Metabot trial
* Adjust implementation of POST /api/ee/cloud-add-ons/:product-type to dashes instead of underscores
* Require accepting terms of service for Metabot trial
* Move RTK and Formik error handling for Metabot into utils.ts
* Avoid use of any type in Metabot Formik error handling
* Improve control flow with side effects
* Fix typo in log message

This also backports "Proxy apis for store to get plan and addons (#65423)",
but without the python-execution bits.

Closes: https://linear.app/metabase/issue/CLO-4423/allow-to-buy-metabase-ai-from-the-admin-under-a-token-feature
References: https://github.com/metabase/metabase/pull/62513
Co-authored-by: Benoit Vinay <ben@metabase.com>
Co-authored-by: Ngoc Khuat <ngoc@metabase.com>
2025-11-13 13:48:28 -06:00
github-automation-metabase
43ecb497ba Adjust cards-with-filters to work with action cards (#65805) (#65815)
* Fix cards-with-filters, not all cards have with mapped filters dataset_query

* Check also dataset-query

* Comments

* Test

* grammar

* Update src/metabase/parameters/dashboard.clj



---------

Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-11-13 18:56:35 +00:00
github-automation-metabase
40d36dca3e fix(sdk-bundle): Temporarily hide the incompatibility banner (#65813) (#65817)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-13 18:53:56 +00:00
github-automation-metabase
9bd81795d7 docs: click behavior limitation (#65809) (#65811)
* Add click behavior setup information to introduction

* Update docs/embedding/sdk/introduction.md



---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-13 17:10:13 +00:00
github-automation-metabase
4b6b34b243 🤖 backported "Update the delete button copy for better UX" (#65746)
* Update the delete button copy for better UX (#65688)

* Update the delete button copy for better UX

* Apply suggestions from code review

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

---------

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

* Update screen reader description to match the new menu copy (#65747)

* Update screen reader description to match the new menu copy

* Update frontend/src/metabase/embedding/components/ArchiveButton.tsx

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

---------

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

---------

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
Co-authored-by: Phoomparin Mano <poom@metabase.com>
Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>
2025-11-13 14:21:41 +00:00
github-automation-metabase
23cc43cfe0 Preserve document cards width on reorder (#65768) (#65776)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-13 14:12:02 +00:00
github-automation-metabase
708a98d0de Fix mapping of params to later query stages (#65651) (#65791)
* Fix nested field mapping

* whitespace

* Update src/metabase/lib/util.cljc



* Remarks

---------

Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-11-13 09:16:44 +00:00
github-automation-metabase
70c241c54b Closes EMB-988 flaky test (#65745) (#65795)
* closes EMB-988 flaky test

* .

* .

* .

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-13 09:06:26 +00:00
Oleksandr Solovyov
9076976e5b [backport] request cancellation (#65461) (#65538) (#65660) (#65790)
* metabot: handle (and propagate) request cancellation (#65461)

* metabot request cancelation (#65538)

this time it is actually working and tests are synchronized with real-world behavior

* request cancelation: this time for real (#65660)

Transfer-Encoding: chunked will cause Apache HttpClient to wrap body in ContentLengthInputStream,
which, in turn, quote: "NEVER closes the underlying stream".

So 'with-open' closing the stream was never propagated. And the new test with transfer-encoding
header captures that.
2025-11-13 10:56:07 +02:00
github-automation-metabase
589f4e828a docs(sdk): Update Readme version references and published npm version to 0.57.0 (#65792) 2025-11-13 08:25:04 +00:00
Mahatthana (Kelvin) Nomsawadi
69f9d59928 Correct the gold release version for real (#65789) 2025-11-13 07:52:27 +00:00
Mahatthana (Kelvin) Nomsawadi
38ea9f7461 Update package version, removing beta (#65784) 2025-11-13 07:17:13 +00:00
Mahatthana (Kelvin) Nomsawadi
8392dcfe11 Update release process (#65781) 2025-11-13 03:49:41 +00:00
github-automation-metabase
cbfee21573 Documents new questions (#65504) (#65775)
* Temp

* Add creation modal for structured questions

* Added full implementation for structured questions

* Added full implementation for structured questions

* Added full implementation for native questions

* Refactor question type picker to menu items

* Add proper keyboard navigation, add premissions check

* Add basic e2e tests

* Add basic e2e tests

* Fix types

* Fix types

* Fix types

* Self review

* Self review

* Review fixes - default display, native title

* Add e2e for viz

* Fix unit tests

* Fix e2e tests

* Fix e2e tests

* fix saving an empty question

* Review fixes

* Fix issue with keyboard trigger

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-13 00:17:09 +00:00
github-automation-metabase
fa13300e22 Remove unused mb_user_defaults env var (#65725) (#65770)
Cloud never used this to pre-fill the user on MB setup.
We have the same functionality with way less code available today, either way.

Instead of:
```
/setup/user_defaults#123456
```

do this:
```
/setup?first_name=John&last_name=Doe
```

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-12 22:42:06 +00:00
github-automation-metabase
407082383f Load plugin manifest in e2e run mode (#65729) (#65771)
When we introduced a new e2e run mode, we didn't realize this piece of code needs to be updated as well.
For people who were running the backend from source (but using e2e mode) some drivers might not have worked. Example:
```
"message": "No method in multimethod 'connection-properties' for dispatch value: :sqlite"
```

This commit fixes that.

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-12 22:21:47 +00:00
github-automation-metabase
70a18f22c9 docs: more new plugins + typechecked snippet for links (#65767) (#65769)
* new plugins

* Update docs/embedding/sdk/plugins.md



---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-12 21:23:02 +00:00
github-automation-metabase
c00c11a24e Feat: Document link editing (#65399) (#65766)
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-11-12 20:47:23 +00:00
github-automation-metabase
f26616f20e Allow return to focus body of Documents (#65732) (#65763)
Co-authored-by: Maz Ameli <maz@metabase.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-11-12 20:46:30 +00:00
github-automation-metabase
2c8548406b docs(sdk): Update Readme version references and published npm version to 0.57.0-beta.1 (#65762) 2025-11-12 19:41:39 +00:00
github-automation-metabase
0926566cc7 document MB_NOTIFICATION_TEMP_FILE_SIZE_MAX_BYTES (#65751) (#65757)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-12 19:28:45 +00:00
github-automation-metabase
ec2b517940 Update chart colors explanation in appearance.md (#65758) (#65759)
Clarified the explanation regarding the order of chart colors.

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-12 19:19:23 +00:00
github-automation-metabase
0f01091a3b docs: dependencies polish (#65754) (#65755)
* dependencies polish

* Optimized 2 images, saved 109.1 KB (48.5% smaller)

* reword

---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-12 18:11:47 +00:00
github-automation-metabase
3a59aab82f Fix static embedding or public embed outside iframe not working with #theme (#65740) (#65749)
* Fix static embedding or public embed outside iframe not working with #theme

* Add tests

* Make embedding prefix/suffix naming consistent

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-11-12 16:04:07 +00:00
github-automation-metabase
991dd69883 unstemmed words should still appear in search (#64560) (#65744)
This is done by putting them in the full-text index using a 'simple' stemmer, just with a lower priority than a normal
stemmed words are.

Fixes #60649

Co-authored-by: Oleksandr Solovyov <alexander@solovyov.net>
2025-11-12 11:31:10 +00:00
github-automation-metabase
b203488f1c Closes UXW-2237 click on admin logo error (#65581) (#65738)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-12 06:41:49 +00:00
github-automation-metabase
8536c5c60c Fix: UXW-2235 Prevents 403s from SmartLinks from hiding the whole document (#65609) (#65721)
* UXW-2235 Prevents 403s from SmartLinks from preventing the whole document from showing (SmartLink renders with "No access" version instead)

* UXW-2235 Adds e2e tests

Co-authored-by: Brad Anderson <brad@metabase.com>
2025-11-11 21:53:07 +00:00
github-automation-metabase
b5d440f44c changelog link (#65717) (#65722)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-11 21:30:50 +00:00
github-automation-metabase
50c6890b0c Add /livez and /readyz endpoints (#64479) (#65719)
* Add /livez and /readyz endpoints

* nit comment

* Update tests with new endpoints

* Update src/metabase/server/routes.clj



* bad bot

* fix tests

* fix license test failure

https://github.com/metabase/metabase/pull/65034 bumped some jetty deps
from 12.0.24 to 12.1.3. Along for the ride came a new org:

```
org.eclipse.jetty.ee9.websocket/jetty-ee9-websocket-jetty-server 12.1.3
  X org.eclipse.jetty.ee9/jetty-ee9-servlet 12.1.3 :use-top
  . org.eclipse.jetty.ee9/jetty-ee9-webapp 12.1.3
    . org.eclipse.jetty/jetty-xml 12.1.3
      . org.eclipse.jetty/jetty-util 12.1.3
      X org.slf4j/slf4j-api 2.0.17 :use-top
    . org.eclipse.jetty.ee/jetty-ee-webapp 12.1.3 <--- new
```

This has a new org of `org.eclipse.jetty.ee` and no discernable license
in the pom or the jar.

Refresher we look in the pom for things like

```
  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
```

or in the jar for some common names of licenses, like in this mysql
connector jar:

```
  -rw-r--r--     134  18-Sep-2023 19:11:56  INFO_SRC
  -rw-r--r--   71049  18-Sep-2023 19:11:56  LICENSE
  -rw-r--r--    1624  18-Sep-2023 19:11:56  README
  -rw-r--r--     846  18-Sep-2023 19:12:04  META-INF/INDEX.LIST
```

I didn't see a license at either of these spots, but consulted
https://mvnrepository.com/artifact/org.eclipse.jetty.ee/jetty-ee-webapp
to see it listed as Apache 2.0 and EPL 2.0

---------

Co-authored-by: Rodrigo López Dato <rodrigo@metabase.com>
Co-authored-by: metabase-bot[bot] <109303359+metabase-bot[bot]@users.noreply.github.com>
Co-authored-by: dan sutton <dan@dpsutton.com>
2025-11-11 21:30:23 +00:00
github-automation-metabase
f09aaf057f generate command docs (#65608) (#65711)
* generate command dox

* clean-up

* restore command.md

* clean-up

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-11 17:31:57 +00:00
github-automation-metabase
7d7af0545a [perf] Improve quadratic lookups in add-alias-info (#65595) (#65709)
Part of #64774.

Replaces quadratic (refs * columns) search in `add-alias-info` with map lookups
by ID and `:lib/source-column-alias`. They don't always succeed, but I ran the tests with a fallback case
that checked the old quadratic way too - in no case does the new match fail but the old way succeed.

- Speeds up the basic query of wide tables (see `qp.perf-test`) about 7x, from 8825ms to 1435ms.
- Reduces the big user query from #64774 from 205ms to 145ms on my machine.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-11-11 17:03:57 +00:00
github-automation-metabase
70ec7e7884 [perf] Remove unnecessary MBQL 4 -> 5 -> 4 round trips in SQL drivers (#65509) (#65698)
Part of #64774.

Now that most of the query processor machinery has been ported to use MBQL 5 and the `metabase.lib.core`
functionality, there were several needless round trips between MBQL 4 and 5.

The `driver.sql.qp/preprocess` function was converting queries from MBQL 5 to 4 up front,
and then each of three inner operations (now implemented in MBQL 5) were wrapped to convert 4 to 5 and back.

Removing this wasted effort reduced the time on my machine for the big user query from #64774 from 205ms to 145ms.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-11-11 16:21:37 +00:00
github-automation-metabase
cef18f9600 Fix flaky 'models.cy.spec.js' test (#65690) (#65696)
Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-11-11 15:16:42 +00:00
github-automation-metabase
d0baa1526b docs: Update api changelog (#65663) (#65694)
Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2025-11-11 14:53:01 +00:00
github-automation-metabase
4bac750de2 Remove unused metabase.util.formatting.numbers and metabase.util.formatting.time (#63791) (#65391)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-11 13:46:05 +01:00
github-automation-metabase
b914a342e2 [Metabot] Misc. bug fixes (#65255) (#65673)
* fix cut not removing text from input

* ensure we fetch all data for all possible models for smart links

* remove unused comment

* fixes smart links in metabot input sometimes degrading into their text representation and fixes some cases where wrong model name ("model" instead of "dataset") was used for metabot links

* fix unit tests

* fix phantom selection when cutting value from input (context: https://github.com/metabase/metabase/pull/65255\#pullrequestreview-3436250849)

Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2025-11-11 13:44:06 +01:00
github-automation-metabase
0712b14ddb fix(sdk): Accept an entity id as a target collection id for CreateQuestionModal (#64601) (#65617)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-11 12:30:09 +00:00
github-automation-metabase
4d510c6fc4 Close New Modals when pathname is changing (#65472) (#65656)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-11 11:26:27 +00:00
github-automation-metabase
cf7228e6b5 Avoid DDL races in redshift sync (relation does not exist error) (#65546) (#65587)
- catalog metadata is not transactional in redshift
- calls like pg_catalog.has_schema_privilege when using a string argument will resolve the oid of the schema/table etc
- if the oid cannot be resolved (e.g. table/schema does not exist) an error is thrown

We occasionally see sync failed due to relation does not exist, one cause might be concurrent test runs / cleanup deleting tables/schemas while running.

I have fixed the first half of the union to use the oid form of these calls which will result in NULL instead of an error while racing with DDL in other runs.

Need to research on external tables before changing the external table sub-query: probably want to join to svv_external_schemas and use the oid there, but not 100% yet.

Co-authored-by: Dan Stone <wotbrew@gmail.com>
2025-11-11 10:12:23 +00:00
github-automation-metabase
096b37cc1f fix: update harbormaster API use, and support public openapi schema (#65549) (#65650)
* fix: update harbormaster API use

The Harbormaster API was updated to use snake_case in all params
and returns in https://github.com/metabase/harbormaster/pull/6663.

There's an backwards compatible interim period where it will support both kebab-case and snake_case in params, and keep existing returns.
The changes in this PR will make Metabase forwards and backwards compatible with the Harbormaster API changes.

After the interim period, the Harbormaster API will only take and return snake_case data.

* feat: support missing api key on hm.client/call

The OpenAPI spec is now public and the api key is not mandatory.

Co-authored-by: Filipe Silva <filipematossilva@gmail.com>
2025-11-11 10:11:04 +00:00
github-automation-metabase
024336ad4b [perf] New MetadataProvider and query derived from a real perf issue (#65508) (#65606)
This has been a very valuable benchmark for processing complex queries,
especially large `:case` statements and nested aggregations.

Adding it with some REPL-able benchmarks in `query-processor.perf-test`.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-11-11 06:48:21 +00:00
github-automation-metabase
db24323e27 Drop clipboardy (#65675) (#65679)
Co-authored-by: Fraser <fraser@metabase.com>
2025-11-11 04:30:44 +00:00
github-automation-metabase
6cd419141b Fix postgres bytea truncation (#65569) (#65678)
* fix postgres bytea truncation

* use = over =?

* Add issue ref in test

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-11-10 23:37:10 +00:00
github-automation-metabase
30301eb32c Fix Collection Tree Collapsing (#65620) (#65659)
* actually just be smart

* consistent change detection

* remove dead code

Co-authored-by: Ryan Laurie <30528226+iethree@users.noreply.github.com>
2025-11-10 23:36:12 +00:00
github-automation-metabase
838be58fb3 Remove-replace cleans up empty first stages when reasonable (#65565) (#65670)
If you have an empty first stage followed by "real" later stages, the frontend produces duplicate buttons in the query
builder.  Cleaning those stages up removes those buttons.

Co-authored-by: William <william@metabase.com>
2025-11-10 23:18:56 +00:00
github-automation-metabase
0b4f0379aa Metabot /debug mode to show tool calls (#64811) (#65677)
* add debug message type for tool calls

* rename toolCalls -> activeToolCalls

* Basic debug mode slash command to hide/show tool calls

* ToolCallDetailsModal + better formatting

* Fix type

* Fix types, some simplification

* Address minor bot comments

* small changes

* move AgentToolCallMessage into its own file and add copy buttons + tool call id to modal

* fix copied value

* add unit tests

* move failure case further downstream to mitigate any possible customer issue

* ci fixes

---------

Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
Co-authored-by: Sloan Sparger <sloansparger@gmail.com>
2025-11-10 21:38:02 +00:00
github-automation-metabase
261a373ad1 Cell count for notifications temp storage (#65518) (#65671)
* ditch our manual batches of rows for bufferedwriter

Q: Why did we use a manual batch at first?
A: i noticed it was super slow and worked around this. Then realized i
was gzipping it so that was the actual slowdown. The batching was
already done and it didn't hurt anything.

Q: Why get rid of it then?
A: want to move to "cell" based counting. Rows are fine until they get
really wide and then 300 columns * 5,000 rows = 1,500,000 cells in
memory at once. Put some strings in there and we blow up. So lets switch
to cell counting rather than row counting. This is way easier if we only
care about number of rows or cells when holding them in memory. Don't
have to count the batch ourself when streaming. So if that goes row by
row, we just watch for the number of cells as the trigger to switch to
streaming and we are done.

```clojure
temp-storage-test=> (time
                      (mt/test-driver :postgres
                        (select-keys (mt/process-query (mt/native-query {:query "SELECT
    row_num AS id,
    -- Random Integer between 1 and 100000
    floor(random() * 100000 + 1)::INTEGER AS random_int,
    -- Random Float
    (random() * 1000)::NUMERIC(10, 4) AS random_float,
    -- Random Date within the last 5 years
    (current_date - (random() * 5 * 365)::INTEGER)::DATE AS random_date,
    -- Random Timestamp within the last 30 days
    (NOW() - (random() * 30 * '1 day'::interval)) AS random_timestamp,
    -- Random String: Generates a random alphanumeric string about 1000 characters long
    (
        SELECT string_agg(
            chr(
                (CASE WHEN random() < 0.5 THEN 65 ELSE 97 END) + (random() * 25)::INTEGER
            ),
            ''
        )
        FROM generate_series(1, 1000)
    ) AS random_string
FROM
    generate_series(1, 500000) AS row_num;"})
                                                       (temp-storage/notification-rff 2000 :testing))
                                     [:row_count :status :data.rows-file-size :notification/truncated?])))
"Elapsed time: 1457.921083 msecs"
{:row_count 15184,
 :status :completed,
 :data.rows-file-size 16369108,
 :notification/truncated? true}
```

* Switch to cell based counts, not rows

We found in practice some people might have queries with 300
columns. When we keep 5,000 of those in memory, we end up having
1,500,000 cells in memory at once. We then are open again to OOM
issues. So this swaps over to a cell basec count rather than rows to be
a bit more granular.

* Change from 2,000 rows to 20,000 cells

the thinking here is 2,000 rows with 10 values. It's pretty arbitrary though

* rename var for cells to disk threshold

* i have to delete this test because i used `time` in a comment block

* formatting fix

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-10 21:15:42 +00:00
github-automation-metabase
d53701ffe4 Display "previous results" when a join's conditions specify multiple lhs tables (#65239) (#65667)
When a join's conditions came from multiple tables, we used the first table as the table name, even though some of the cols came from a different table. We now display "Previous results" to denote that the lhs columns are from different tables.

Co-authored-by: William <william@metabase.com>
2025-11-10 18:37:00 +00:00
github-automation-metabase
3ea9af4582 fix: batch delete data perms (#65567) (#65657)
* fix: batch delete data perms

To workaround postgresql parameter limits in the delete query

* Update src/metabase/permissions/models/data_permissions.clj



* Update src/metabase/permissions/models/data_permissions.clj



* Update data_permissions.clj

---------

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
2025-11-10 15:35:29 +00:00
github-automation-metabase
aab36af6e0 Gdgt 910 rework look and feel of color settings in gauge (#65552) (#65629)
* updated segments ui

* sober up the needle

* setting up unit tests

* make gauge needle opaque

* remove key, update unit test

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-11-10 13:13:01 +00:00
Nicolò Pretto
ed601509bb remove embedding team from codeowners on release branch (#65648) 2025-11-10 10:14:10 +01:00
github-automation-metabase
d393b51aaa Fall back to the staging token check (#65474) (#65582)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-10 08:54:15 +01:00
github-automation-metabase
3899b067c6 Closes EMB-970 move some callbacks to MetabaseGlobalPluginsConfig (#65590) (#65634)
* Closes EMB-970 move some callbacks to MetabaseGlobalPluginsConfig

* types

Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-10 04:15:15 +00:00
github-automation-metabase
866c8bc215 [insights] Convert BigDecimals into Doubles early in the pipeline (#65234) (#65640)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-10 00:35:43 +00:00
github-automation-metabase
1b3bc1182e [normalize] Optimize metabase.lib.schema.util (#63470) (#65636)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-08 23:11:00 +00:00
github-automation-metabase
69327af9f7 [flake] Increase test timeout in metabase.app-db.liquibase-test (#64814) (#65488)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-08 21:30:30 +00:00
github-automation-metabase
51a17b7a1b [mage] Use Babashka to run cljfmt on staged files in git pre-commit hook (#65026) (#65489)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-08 21:21:55 +00:00
github-automation-metabase
075ae6649c Add creator_id for transform (#65388) (#65446)
* Add creator_id for transform

Closes QUE-2715

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-11-08 09:57:36 +00:00
github-automation-metabase
42197eabb1 Remove special embedding-sdk e2e test case (#65594) (#65619)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-08 00:15:23 +00:00
github-automation-metabase
68fe321aea docs: new sdk click and link behavior (#65627) (#65632)
* new click and link behavior

* Apply suggestions from code review



* handle handlelink

* fix typo

---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-07 23:27:51 +00:00
github-automation-metabase
2341bea438 Use transparency instead of white for table color ranges (#65426) (#65626)
* Use transparency instead of white for table color ranges

* adding visual tests

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-11-07 21:53:46 +00:00
github-automation-metabase
45b76ce7f6 docs - remote sync edit (#65625) (#65628)
* turning off remote sync

* theme toggling in command palette

* edtis

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-07 21:19:09 +00:00
github-automation-metabase
39e89ed0fa update color scheme for google button (#65558) (#65611)
* update color scheme for google button

* Adding a comment like I was supposed to

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-11-07 20:04:52 +00:00
github-automation-metabase
003d3c8d3c Document supported databases for model persistence (#65621) (#65622)
Added section listing databases that support model persistence.

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-07 19:26:45 +00:00
github-automation-metabase
8e6a3851e2 fix(modular): fix downloads on dashboards loaded by entityIds (#65613) (#65615)
* fix(modular): fix downloads on dashboards loaded by entityIds

* tests

Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-11-07 18:40:30 +00:00
github-automation-metabase
3a3afd037e UXW-2179 Replace 'Add to dashboard' modal with a toast (#65400) (#65570)
* UXW-2179 Replace 'Add to dashboard' modal with a toast

* fix some e2e tests

* Fix more e2e tests

* Fix more e2e tests

* Fix more e2e tests

* Design fix

* Fix e2e

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-07 17:10:06 +00:00
github-automation-metabase
4949afecc8 Update generated docs (release-x.57.x) (#65614)
Co-authored-by: github-actions <github-actions@github.com>
2025-11-07 17:02:30 +00:00
github-automation-metabase
d27b04c202 fixed flaky (#65599) (#65603)
Co-authored-by: Sébastien <sebastien@metabase.com>
2025-11-07 15:24:56 +00:00
github-automation-metabase
2db8cf4c7f Add flag to skip search reindexing on import (#65537) (#65554)
* Add flag to skip search reindexing when loading entities

* Test flag

Co-authored-by: Chris Truter <crisptrutski@users.noreply.github.com>
2025-11-07 08:44:28 -06:00
github-automation-metabase
da205abf6c fix(embed-js): black background is shown on systems with dark mode preferences (#65534) (#65591)
* reverts the color-scheme meta tag

* adds the color scheme meta tag if entry point is not embed-sdk

* add backend tests for color-scheme meta tags

* add a cypress test for color-scheme

Co-authored-by: Phoomparin Mano <poom@metabase.com>
2025-11-07 14:29:46 +00:00
github-automation-metabase
b0b0c5e927 Fix docs scalar version (#65553) (#65579)
* Fix docs

it throws an error in the js console about webassembly not having the
right permissions

Two ways to fix: give permissions, or rollback to a version that works.

I'm pinning to a version that works since we are close to a release.

39.2 breaks, 39.1 works.
I'm also including the recommended stylesheets

In the meantime, i'm going to investigate
resources/openapi/index_external.html.mustache as i'm not sure what uses
this and if it needs to be updated or deleted. Perhaps used by `clojure
-M:ee:doc api-documentation`?

* switch template to pinned 39.1 version

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-06 23:35:35 -05:00
github-automation-metabase
c2a115fcc6 docs - metabot can use the glossary (#65562) (#65563)
* metabot can use the glossary

* link to glossary

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-06 21:55:24 +00:00
github-automation-metabase
8e80912ffe docs: for for for for for for (#65559) (#65561)
* Fix typo in 'Checking for breaking changes' section

* Fix typo in 'Checking for breaking changes' section

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-06 21:16:40 +00:00
github-automation-metabase
e319751425 docs: dependencies on save (#65450) (#65557)
* Add breaking changes detection information

Added section on checking for breaking changes when saving questions, models, or metrics.

* Add breaking changes check to model editing documentation

Added section on checking for breaking changes when saving a model.

* Apply suggestions from code review



---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-06 20:26:40 +00:00
Ryan Laurie
56d583d251 backport release log workflow update (#65490) 2025-11-06 10:51:04 -07:00
github-automation-metabase
51a3de2534 docs - remote sync (#65443) (#65550)
* embedding collections

* image, edits, and embedding example

* various edits

* edits

* edits and images

* more edits

* Optimized 4 images, saved 235.2 KB (36.0% smaller)

* library to synced collection

* fix links

* Update docs/installation-and-operation/remote-sync.md



* Update docs/installation-and-operation/remote-sync.md



* edits

* edits



* edits

* more edits

* clean up

* edit

* clean up

* dev instance

---------

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-06 17:39:50 +00:00
github-automation-metabase
0809740cc5 feat: make metabot logo follow the bran colors (#65358) (#65483)
# Conflicts:
#	frontend/src/metabase/common/components/MetabotLogo/MetabotLogo.stories.tsx

# Conflicts:
#	loki.config.js

Co-authored-by: Jakub Chodorowicz <jakub.chodorowicz@metabase.com>
2025-11-06 13:09:04 -04:00
github-automation-metabase
4ff061dc0b use new library icon for remote-synced collections (#65251) (#65539)
* show new library icon

* UXW-2115 Address PR feedback - makes it so only the Library uses the synced collection icon, not the nested subdirectories

* UXW-2115 Fix getCollectionType condition

* UXW-2115 Removes unnecessary type changes

* UXW-2115 Reverts changes for synced collection icon

---------

Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-11-06 16:03:23 +00:00
github-automation-metabase
4bd67d9023 Update impersonation.md to include Starburst/Trino (#65542) (#65544)
Added Starburst/Trino to the list of supported databases for impersonation.

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
2025-11-06 15:40:12 +00:00
github-automation-metabase
8e837e295d Updates 35 SVG illustrations (#65232) (#65368)
* Updates 35 SVG illustrations

The same asset now works well for both light and dark mode.

* branding OnboardingIllustration, adding cloug and bug metabot to metabot logo

* PR Feedback

---------

Co-authored-by: AlessioLaiso <7041012+AlessioLaiso@users.noreply.github.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2025-11-06 14:56:06 +00:00
github-automation-metabase
b06c657757 🤖 backported "Removing new badge for move questions into their dashboards" (#65506)
* removing new badge for move questions into their dashboards (#65485)

* Remove unneeded tests after #65485 (#65517)

---------

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-06 09:30:47 -04:00
github-automation-metabase
ae408adb88 fix large command palette subtext elements, add loki testing (#65369) (#65429)
* fix large command palette subtext elements, add loki testing

* how did I miss this?

* updating Overlay demo

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-11-06 13:29:18 +00:00
github-automation-metabase
c31bb26f7f Enhance onBeforeRequest into onBeforeRequestHandlers for Api class (#65195) (#65527)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-06 10:04:23 +00:00
github-automation-metabase
0485c08293 spark failure fix (#65502) (#65515)
* spark failure fix

I cannot run spark locally so from CI:

```
FAIL in metabase.driver.sparksql-test/friendly-inline-strings-in-convert-to-sql-test (sparksql_test.clj:67)

:sparksql
 The native query returned in query results should use user-friendly splicing
expected: "SELECT COUNT(*) AS `count` FROM `test_data`.`venues` AS `t1` WHERE `t1`.`name` = 'wow'"
  actual: "SELECT COUNT(*) AS `count` FROM `test_data`.`venues` AS `t1` WHERE `t1`.`name` = 'wow'"
    diff:
expected: "SELECT COUNT(*) AS `count` FROM `test_data`.`venues` AS `t1` WHERE `t1`.`name` = 'wow'"
  actual: "SELECT COUNT(*) AS `count` FROM `test_data`.`venues` AS `t1` WHERE `t1`.`name` = decode(unhex('776f77'), 'utf-8')"
```

Locally hit this on an m1 mac:

```
impl.get-or-create :: create-database! failed; destroying :sparksql database “test-data” {mb-test=metabase.driver.sparksql-test/friendly-inline-strings-in-convert-to-sql-test}
java.util.concurrent.TimeoutException: Timed out after 30.0 mins
```

* fix license test failure

https://github.com/metabase/metabase/pull/65034 bumped some jetty deps
from 12.0.24 to 12.1.3. Along for the ride came a new org:

```
org.eclipse.jetty.ee9.websocket/jetty-ee9-websocket-jetty-server 12.1.3
  X org.eclipse.jetty.ee9/jetty-ee9-servlet 12.1.3 :use-top
  . org.eclipse.jetty.ee9/jetty-ee9-webapp 12.1.3
    . org.eclipse.jetty/jetty-xml 12.1.3
      . org.eclipse.jetty/jetty-util 12.1.3
      X org.slf4j/slf4j-api 2.0.17 :use-top
    . org.eclipse.jetty.ee/jetty-ee-webapp 12.1.3 <--- new
```

This has a new org of `org.eclipse.jetty.ee` and no discernable license
in the pom or the jar.

Refresher we look in the pom for things like

```
  <licenses>
    <license>
      <name>The Apache Software License, Version 2.0</name>
      <url>http://www.apache.org/licenses/LICENSE-2.0</url>
      <distribution>repo</distribution>
    </license>
  </licenses>
```

or in the jar for some common names of licenses, like in this mysql
connector jar:

```
  -rw-r--r--     134  18-Sep-2023 19:11:56  INFO_SRC
  -rw-r--r--   71049  18-Sep-2023 19:11:56  LICENSE
  -rw-r--r--    1624  18-Sep-2023 19:11:56  README
  -rw-r--r--     846  18-Sep-2023 19:12:04  META-INF/INDEX.LIST
```

I didn't see a license at either of these spots, but consulted
https://mvnrepository.com/artifact/org.eclipse.jetty.ee/jetty-ee-webapp
to see it listed as Apache 2.0 and EPL 2.0

Co-authored-by: dpsutton <dan@dpsutton.com>
2025-11-06 02:41:57 +00:00
github-automation-metabase
8237141ad5 Fix kondo failure in release-x.57.x branch (#65496) (#65510)
Co-authored-by: Cam Saul <1455846+camsaul@users.noreply.github.com>
2025-11-06 00:24:20 +01:00
github-automation-metabase
20eabf827b Make Trunk analytics always run (#65451) (#65512)
* Make Trunk analytics always run

This prevents false positives because Trunk analytics actio will now
always analyze test results, and compare them with their own test
quarantine list. It uses this information to know if it should fail the
job or let it pass.

* Introduce dry-run

When a PR is in a draft mode, we don't want to upload results but still
have to quarantine tests.

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-06 00:23:28 +01:00
github-automation-metabase
ab953c5f86 [perf] Add lib.computed, optimize wide tables and deep user queries (#65364) (#65435)
Part of #64774.

Hopefully this is sufficient to unblock users seeing the high CPU times
like in #64774. I discovered other, less significant performance issues
during this investigation that I'll be addressing in follow-up PRs.

The problem query and relevant table metadata from a helpful customer
was taking 950ms to preprocess and compile on my 2022 M1 Max, running
Metabase in dev mode but with Malli schema enforcement disabled.

The query is pretty big! It uses 3 tables with 200-300 columns each,
has several stages including some from a joined card, and ends up with
several stages doing two levels of aggregation. It also includes
several *huge* `:case` expressions.

The optimizations below have reduce the time required from 950ms to 310ms
on my machine. A 3x improvement, but I think there's more to be gained in
the follow-up PRs I mentioned.

Main optimizations:

- `lib.util/find-stage-index-and-clause-by-uuid` pre-computed and cached
  on each stage, saved 120ms on the above query.
- `lib.metadata.cached-provider/fields` attempts to pre-load the cache
  of individual `lib.metadata/field` calls, having just fetched them
  all, but it used the wrong key and they were all misses instead!
- `expression-metadata` and `aggregation-metadata` are recomputed over
  and over again by their stage and later stages; cache them by value
- `returned-columns` was cached at the top level and frequently missed
  because of dumb details like explicit stage 1 vs. -1 for last stage.
  - Switched it to caching on individual `returned-columns-method`s
    with more precise cache keys.

Both of the latter two are using a new caching approach: a weak map
using queries as keys. Since CLJ(S) maps are immutable, any change to
the query means a new pointer.

That's still far more eviction than optimal! Most edits to a query
don't actually invalidate most of the cached values! But it's a lot
better than what we had before, and because the map's keys are weak
references, the queries and their cached data are not retained any
longer than the query itself.

I also added a `qp.perf-test` namespace with some metadata providers
with 10-, 100-, 1000- and 10,000-column tables for testing.

So far the tests it performs are quite basic, though. I'll be adapting
the user-provided query into a test case in the future, since it's an
excellent real-world example of a complex but not pathological query.

Co-authored-by: Braden Shepherdson <braden@metabase.com>
2025-11-05 20:58:26 +00:00
github-automation-metabase
04e0b77b79 docs : clarify subscription settings (#65179) (#65495)
* Update wording for subscriptions and alerts section

* Update docs/permissions/application.md



---------

Co-authored-by: Alex Yarosh <alexandra@metabase.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-05 19:13:17 +00:00
github-automation-metabase
ddc804c8eb Fix #50044 - Updates dashcard loading state so it shows the correct title while it's loading (#65363) (#65424)
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-11-05 17:53:29 +00:00
github-automation-metabase
2d0457eb8b [qp] Reuse oridinarily compiled query as inline if it doesn't have params (#64651) (#65487)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-05 17:44:46 +00:00
github-automation-metabase
30c82bc82f [kondo] Encourage more m.util.performance functions in perf-sensitive namespaces (#65331) (#65338)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-05 17:31:05 +00:00
github-automation-metabase
938e4eeebb Toggle dark mode from command palette (#65359) (#65486)
* toggle dark mode from command palette

* I'm sorry I built this in a dumb way Ryan

---------

Co-authored-by: Ryan Laurie <30528226+iethree@users.noreply.github.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2025-11-05 17:22:23 +00:00
github-automation-metabase
7fb3e1c1ba upgrade to echarts v6 (#64139) (#65482)
* upgrade to echarts v6

* Update Loki Snapshots

* Fix BE test

* update gridlines helper function

* adjust test

---------

Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
Co-authored-by: Nick Fitzpatrick <nickfitz.582@gmail.com>
2025-11-05 17:12:52 +00:00
github-automation-metabase
d9459e71e2 docs(sdk): Update Readme version references and published npm version to 0.57.0-beta.0 (#65484) 2025-11-05 16:09:16 +00:00
Timofey Kachalov
c295a06a40 Adjust reviewers in sdk-release CI workflow (#65478) 2025-11-05 19:43:35 +04:00
github-automation-metabase
6c2d49633a Make sure /dirty is called when moving an entity out of the library (#65259) (#65476)
* Make sure /dirty is called when moving an entity out of the library

* Untouch embedding code / Clean up / Add some tests

* Check cache from both entities and RTK / Undo unnecessary changes

* Make sure getCollectionFromCollectionsTree gets collection from latest query

Co-authored-by: Anderson <ands.alves.nunes@gmail.com>
2025-11-05 15:08:31 +00:00
github-automation-metabase
6598a1a77f GDGT-1185: Columns appear twice in model list view until action taken (#65412) (#65475)
* List View: Fix incorrect bg color initialization

* GDGT-1185: Fix columns list initiation in ListView configuration screen

* GDGT-1185: Update e2e test

* GDGT-1185: Fix lint

* GDGT-1185: Fix unit tests

* GDGT-1185: Address PR comments

* GDGT-1185: Minor refactoring

Co-authored-by: Stas Gavrylov <stas@metabase.com>
2025-11-05 14:59:24 +00:00
github-automation-metabase
254e4fd3b9 Fix getNextSdkVersion helper (#65468)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-05 17:11:54 +04:00
github-automation-metabase
952045b2f1 Adjust parameter_mappings for a text dashcard when its variable is removed (#64463) (#65448)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-05 13:03:58 +00:00
Nicolò Pretto
144eb50221 57-beta changes for the sdk (#65420) 2025-11-05 10:31:25 +01:00
github-automation-metabase
4b781a0d48 Use stableStringify for PublicOrEmbedDashboardView story + add StrictUnion type (#65411) (#65460)
Co-authored-by: Timofey Kachalov <timofei@metabase.com>
2025-11-05 09:26:53 +00:00
github-automation-metabase
1a062c85f4 Stabilize and deduplicate eslint cache (#65410) (#65458)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-05 08:52:16 +00:00
github-automation-metabase
14eb4d0831 Remove parsing from file download e2e tests (#65081) (#65440)
* Make e2e download tests more lightweight

* Fix helper to handle redirects

Co-authored-by: Fraser <fraser@metabase.com>
2025-11-04 22:06:41 +00:00
github-automation-metabase
651e92600d Adding collection name to recent documents (#65376) (#65438)
* Adding collection name to recent documents

* re-arranging e2e test

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-11-04 21:42:33 +00:00
github-automation-metabase
f41b074b00 docs - various edits (#65422) (#65432)
* various edits

* edits

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-04 19:49:07 +00:00
github-automation-metabase
2d947df8fa remote sync analytics (#65129) (#65430)
Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
2025-11-04 19:13:30 +00:00
github-automation-metabase
9f8a16a21a [util] Explicitly test for BigDecimals in real-number? (#65202) (#65427)
Co-authored-by: Oleksandr Yakushev <alex@bytopia.org>
2025-11-04 17:16:51 +00:00
github-automation-metabase
ea356f765d allow disabling remote sync (#65175) (#65425)
Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
2025-11-04 17:04:11 +00:00
github-automation-metabase
6f78e22b2e skip flaky UpsellBigCard loki specs (#65404) (#65407)
* skip flaky UpsellBigCard loki specs

* Update Loki Snapshots

---------

Co-authored-by: Aleksandr Lesnenko <alxnddr@users.noreply.github.com>
2025-11-04 15:46:01 +00:00
github-automation-metabase
8f550db631 V57 docs: updating Alerts + Model view (#65353) (#65414)
* update screenshot

* Updating model list view

* updating screenshots to Model view

* Optimized 4 images, saved 406.0 KB (50.9% smaller)

---------

Co-authored-by: Abed Habli <154609371+abdhabli@users.noreply.github.com>
2025-11-04 11:20:59 +00:00
github-automation-metabase
051c949f63 Correct interactive embed query execution count (#65336) (#65345)
* Simplify the FE API code

* Exclude static embed preview from being counted in analytics

* Update frontend/src/metabase/lib/api.js



* Clarify comments

* Add tests

---------

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-04 03:17:59 +00:00
github-automation-metabase
f9827f2dc3 Recreate model index quartz triggers on job initialization when needed (#65394) (#65402)
* Recreate model index quartz triggers on job initialization when needed

* whitespace

* rename var + add comment

Co-authored-by: Noah Moss <32746338+noahmoss@users.noreply.github.com>
2025-11-04 01:26:52 +00:00
github-automation-metabase
2fd19bbdbe fix: allow stacktraces to be suppressed in API (#65215) (#65285)
* fix: allow stacktraces to be suppressed in API

Allows administrators to configure their metabase instance using
MB_HIDE_STACKTRACES to prevent stacktraces from appearing in API
response. For standard responses it replaces unhandled exceptiosn with a
generic message and 500 response. For streaming responses it leaves the
error message and strips out the trace/via keys to prevent exception
info from leaking.

* fixup! dissoc traces from map errors

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2025-11-03 23:54:13 +00:00
github-automation-metabase
2fda4a26a3 token data (#65396) (#65397)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-03 21:47:53 +00:00
github-automation-metabase
92b2990182 json from data-url (#65374) (#65381)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-11-03 20:22:32 +00:00
github-automation-metabase
3577f4f6e7 UXW-2182 fix codemirror editor suggestions styles in light mode (#65367) (#65383)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-03 19:46:09 +00:00
github-automation-metabase
81fd96c6fc UXW-2170 cleanup chart brush (#65313) (#65365)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-03 19:43:31 +00:00
github-automation-metabase
6b41783976 UXW-2172 UXW-2174 remove Document cards click actions (#65191) (#65351)
* UXW-2172 UXW-2174 remove Document cards click actions

* Fix e2e

* UXW-2172 fix broken click actions for Document cards

* Restore e2e

* Fix typecheck

* review fixes

Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-03 19:31:21 +00:00
github-automation-metabase
f71b169128 Restore calendar hover styles (#65361) (#65379)
* restore calendar hover styles

* fix calendar picker hover states

* remove unnecessary rule

Co-authored-by: Ryan Laurie <30528226+iethree@users.noreply.github.com>
2025-11-03 19:11:43 +00:00
github-automation-metabase
4709110720 Updates 6 illustrations for dark mode (#65375) (#65380)
Co-authored-by: AlessioLaiso <7041012+AlessioLaiso@users.noreply.github.com>
2025-11-03 19:05:44 +00:00
Jeff Bruemmer
409eb9638f Revert "Revert "docs -remote sync (#65009)" (#65305)" (#65377)
This reverts commit 70ac109c30.
2025-11-03 13:39:49 -05:00
github-automation-metabase
560aba706f Add archived flag to graph endpoints (#65366) (#65371)
Fixes QUE-2708

Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-11-03 17:29:56 +00:00
github-automation-metabase
400cca7fe5 filter for active fields (#65245) (#65360)
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-11-03 15:46:21 +00:00
github-automation-metabase
226ab1bf62 Fix suggested prompts schema and add test (#65299) (#65355)
Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
2025-11-03 15:38:56 +00:00
github-automation-metabase
a97dc5cf61 Compute param values from card results (#64318) (#65354)
* Compute param values from card results

seq for bool

Tests, multi-stage queries

Compute values also for params on nested stages

whitespace

Unused ns

Last stage check first

Docstring

Drop base query's last stage clauses

Address review remarks

Apply suggestions from code review



Remove redundant ops

Adjust for test

Search for col also in aggregated result columns

Look for breakoutable column only if source-uuid is present

* symb

* Rebase fix

* fix rebase, remove unused module

* post rebase, fix getting database id

* kondo

* Revamp

* limit

* Adjust the solution for impl joins

* Fix e2e

* Comment

* Cleanup

* Cleanup

* comment

* comment

* Update src/metabase/parameters/dashboard.clj



* indent

---------

Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-11-03 15:28:40 +00:00
github-automation-metabase
c05f5ec9eb UXW-175 Fix visualization mode switch for pivot table (#65252) (#65352)
Co-authored-by: Denis Berezin <denis.berezin@metabase.com>
2025-11-03 15:06:52 +00:00
Jeff Bruemmer
536e71d4cb docs - 57 api docs (#65308)
* api docs

* env var
2025-11-03 08:46:58 -05:00
github-automation-metabase
f04c507ac4 Disable CodeQL trap caching (#65275) (#65337)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-11-03 09:08:08 +00:00
github-automation-metabase
949cddcd2b Fix #64685 - Update brand colors in UI without needing refresh (#65292) (#65323)
* UXW-1991 Fixes various issues both new and old with the Branding page like the colors not updating until refresh and swatches not updating when setting colors back to their defaults

* UXW-1991 Uses hex format for brand colors placeholders

* UXW-1991 Fix persistence issues with setting/unsetting accent colors

Co-authored-by: Brad Anderson <brad@metabase.com>
2025-10-31 23:16:09 +00:00
github-automation-metabase
cc8e2c332a UXW-2183 Remove fullscreen dashboard night mode toggle (#65312) (#65321)
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-10-31 22:53:37 +00:00
Ryan Laurie
3ae7763a1b Update translations 2025-10-30 (#65213) (#65314)
* Update translation sources 2025-10-30

* Update translations

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
2025-10-31 23:48:39 +01:00
github-automation-metabase
3edc9d2259 Remove mention of "night mode" and image (#65318) (#65319)
* Remove mention of "night mode" and image

Removed mention of 'Night mode' from fullscreen dashboard instructions.

* Delete dark mode/night mode image

Co-authored-by: Robert Kosara <rkosara@me.com>
2025-10-31 21:50:02 +00:00
dpsutton
a0e7336119 Don't count app-db not setup errors in circuit breaker (#65300)
we want to not hammer the network when things are down. But during
startup we don't need to circuit break these errors that we throw before
the app-db is read
2025-10-31 16:33:34 -05:00
github-automation-metabase
d810202021 Implement connection impersonation for starburst (#64972) (#65306)
* implemenet impersonation driver methods

* replace starburst impersonation

* use user as default role

* clean up

* enable starburst tests

* mount files to container

* add config files

* fix rules.json

* add starburst impersonation tests

* try fix

* remove old tests

* debug

* Debug'

* add volumes original way

* try again

* revert

* try docker run

* remove services

* add back accessc control

* enable impersonation

* exclude starburst tests again

Co-authored-by: Riley Thompson <riley@metabase.com>
2025-10-31 20:14:50 +00:00
github-automation-metabase
82ede379eb Small edits to v57 docs about Glossary, dark mode, and progress bars (#65253) (#65309)
* Enhance glossary section with context for definitions

This is a smaller change than I expected, since glossary terms don't show up in searches yet. Might just cut this if it doesn't add anything useful. I also wasn't sure if we should mention Metabot here.

* Add dark mode options

Adds the available options and explains that you don't have to reload the page

* Add a little clarification to the computed goal example

This confused me, so I'm adding this little clarification

* Jeff's suggested change



* Remove the bit about LLMs again

---------

Co-authored-by: Robert Kosara <rkosara@me.com>
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-10-31 19:01:09 +00:00
Jeff Bruemmer
70ac109c30 Revert "docs -remote sync (#65009)" (#65305)
This reverts commit c257c954fb.
2025-10-31 14:49:32 -04:00
github-automation-metabase
9a277a649e Metabot glossary integration (#65223) (#65274)
* Return glossary with user info

* Test glossary in response

Co-authored-by: lbrdnk <lbrdnk@users.noreply.github.com>
2025-10-31 16:58:01 +01:00
Nemanja Glumac
c43fc5726e Fix logs upload for drivers (#65257) (#65289)
* Fix logs upload for drivers

When we introduced `continue-on-error` to the "test" step, we had to
update the conditionals for the test report steps as well. I've
introduced a bug by checking for a failure, instead of saying - upload
test reports whenever the job is not successful.

Hint: test.outcome means "step status BEFORE continue-on-error overrides
the exit code"
2025-10-31 16:40:55 +01:00
github-automation-metabase
b21072994c Remove superfluous python setup from H2 driver test (#65272) (#65284)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-10-31 16:23:40 +01:00
github-automation-metabase
9ab49864c1 fix: pivoting json values (#65183) (#65278)
* fix: pivoting json values

* fixup! kondos in test

* Update frontend/src/metabase/lib/data_grid.js



---------

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
Co-authored-by: Ryan Laurie <30528226+iethree@users.noreply.github.com>
2025-10-31 14:39:02 +00:00
github-automation-metabase
8e02fb7dd2 Fix: UXW-2171 Prevents "Edit Query" from clearing name on chart (#65224) (#65280)
Co-authored-by: Brad Anderson <brad@metabase.com>
2025-10-31 14:16:54 +00:00
github-automation-metabase
b53131f473 Sunset e2e cross-version tests (#65269) (#65277)
Context: https://metaboat.slack.com/archives/C0669P4AF9N/p1761905881175819

The requirements for new and updated attempt at solving this problem are documented in:
https://linear.app/metabase/issue/DEV-1042/design-reliable-cross-version-upgradedowngrade-test-strategy

Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-10-31 14:11:29 +00:00
github-automation-metabase
4805c9f244 Fix deleted documents were editable (#65136) (#65276)
* Prevent trashed documents from being edited

* Add test

* Soften the test name tone

* Disallow even updating document when archived via API

* Add BE test

* Fix Cypress test issue reference

* Update tests after merging master

* Only check for archived when not unarchiving

* Don't check archived documents when archiving or unarchiving them

* Add missing condition from merging

Co-authored-by: Mahatthana (Kelvin) Nomsawadi <me@bboykelvin.dev>
2025-10-31 12:59:29 +00:00
github-automation-metabase
894a2fb895 update hover colors in UserListElement (#65174) (#65243)
* update hover colors in UserListElement

* adjusting colors

* updating comment

Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-10-31 09:17:34 -03:00
github-automation-metabase
52517517f5 Fix env var doc gen (#65230) (#65270)
* fix issue with env var gen and some cleanup

* cleanup

Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-10-31 11:42:20 +00:00
github-automation-metabase
52aba51798 remove registry (#65242) (#65264)
Co-authored-by: Jeff Bruemmer <jeff.bruemmer@gmail.com>
2025-10-31 03:46:19 +00:00
github-automation-metabase
9a33050c61 Optimize graph API endpoints (#65172) (#65263)
Co-authored-by: metamben <103100869+metamben@users.noreply.github.com>
2025-10-31 02:55:16 +00:00
github-automation-metabase
381fa1fdbd Upgrade CodeQL action version (#65250) (#65261)
Co-authored-by: Nemanja Glumac <31325167+nemanjaglumac@users.noreply.github.com>
2025-10-31 01:16:46 +00:00
github-automation-metabase
bf17242cb9 [Metabot] Copy change for suggested prompts setting description (#65163) (#65237)
* update copy

* adjust copy for embedded metabot

* oops

* remove randomly

* fix test

* feedback

Co-authored-by: Sloan Sparger <sloansparger@users.noreply.github.com>
2025-10-30 21:06:31 +00:00
github-automation-metabase
f1336e039f update document title compare to determine dirty state (#65229) (#65246)
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-10-30 20:44:54 +00:00
github-automation-metabase
1233934a0d fix falsey check when removing card embed from document (#65222) (#65244)
Co-authored-by: Nick Fitzpatrick <nick@metabase.com>
2025-10-30 20:32:53 +00:00
github-automation-metabase
5bdc6d7000 fix(sdk): non-editable dashboard should not have "add a chart" button and title should be read-only (#65102) (#65241)
Co-authored-by: Phoomparin Mano <poom@metabase.com>
2025-10-30 20:21:24 +00:00
github-automation-metabase
81ac3c9ae5 return false instead of throw (#65225) (#65235)
Co-authored-by: Riley Thompson <riley@metabase.com>
2025-10-30 19:39:21 +00:00
github-automation-metabase
dba578efad GDGT-1083: Improve visual design for new List view in Stats before v57 (#64957) (#65226)
* GDGT-1083: Add new icons

* Remove subtitle column. Restyle inputs. Extend icon selection

* GDGT-1083: Fix minor tags input styling issues

* GDGT-1083: Replace semantic colors with accent colors

* GDGT-1083: Add image column selection option

* GDGT-1083: Add placeholder for image column icon. Fix bug with selected icon

* GDGT-1083: Update formatted column values rendering rules

* GDGT-1083: Fix incorrect entity icon initialization

* GDGT-1083: Add range viz rendering for quantity/score columns

* GDGT-1083: Fix drag from ListViewColumnsSidebar

* GDGT-1083: Fix list header grid

* GDGT-1083: Fix State column styling

* GDGT-1083: Fix incorrect rendering for boolean columns

* GDGT-1083: Fix incorrect column rendering for empty cells

* GDGT-1083: Address design review comments

* GDGT-1083: Fix TS error

* GDGT-1083: Fix image column rendering

* GDGT-1083: Minor refactoring

* GDGT-1083: Update e2e est

* GDGT-1083: Add unit test for ListViewItem component

* GDGT-1083: Fix linter

* Fix eslint

* GDGT-1083: Resolve metabot comments

* GDGT-1083: Get rid of split_currency setting

* wip

* GDGT-1083: Address PR comments

* GDGT-1083: Address PR comments

* GDGT-1083: Replace switch logic with fns. Fix header layout bug

* GDGT-1083: Fix badges cursor in list view

* GDGT-1083: Fix cursor styling when dragging over full tags input

* GDGT-1083: Remove max-width

* GDGT-1083: Fix linter

* GDGT-1083: Fix lint

* GDGT-1083: Fix incorrect imgURL/avatarURL column rendering after refactoring

* Fix incorrect icon background color

* Fix incorrect category columns rendering

* Update Loki Snapshots

---------

Co-authored-by: Stas Gavrylov <stas@metabase.com>
2025-10-30 19:38:02 +00:00
Denis Berezin
0d66452695 UXW-2091 user without collection access to Our Analytics can't save documents (#65159) (#65216)
* UXW-2091 user without collection access to Our Analytics can't save documents

* fix typecheck

* Fix types

* Add e2e tests

(cherry picked from commit 9f0f6eb78c)
2025-10-30 22:11:31 +03:00
dpsutton
9edb741033 Token grace period (#64938) (#65208)
* Add a grace period to token checks

There's more work on this namespace to be done i think, but this is a
first cut at it. There's a lot of control flow by exceptions which is
how we jump around in here. Fundamentally this should be far
simpler. Will take a crack at that shortly. I also don't love that this
just hammers the `fetch-token-status` function and then memoizes inside
of that. Would prefer simpler layout of `token-features` function and
that can be aware of population issues.

Adds a simple protocol: GracePeriod, which has two functions: save! and
retrieve. On successful token check, we `save!` the response. On errors,
we `retrieve` previous responses. This obviously can be nil in the case
we have never had a successful response, and will become nil once the
grace period's internal notion of time expires.

This implementation is based on guava's cache which has a nifty
expireafterwrite functionality.

```
 (*token-features*) ;; call this function to simulate the check of features
Checking with the MetaStore to see whether token 'f325...d01a' is valid...
Reporting Metabase stats: {... user counts etc}
 -> #{"features come back"}
 ;; meanwhile clear cache to simulate elapsing of 12 hours

 (*token-features*) ;; call function again to simulate check of features
2025-10-22 21:30:26,620 INFO premium-features.token-check :: Checking with the MetaStore to see whether token 'f325...d01a' is valid...
2025-10-22 21:30:26,622 ERROR premium-features.token-check :: Error fetching token status from https://token-check.metabase.com:
clojure.lang.ExceptionInfo: network issues ;; hit network issue

2025-10-22 21:30:26,632 INFO premium-features.token-check :: Using token from grace period
->> #{graceperiod network features}
...

;; here after 5 seconds (in real life will be 36 hours)
2025-10-22 21:31:00,064 WARN premium-features.token-check :: Removing token: f325...d01a from grace period cache {mb-quartz-job-type=Cache}
```

* tests that updating value populates grace period cache

* couple changes

protect against storing nil value. guava cache doesn't like it so gone
it is.

added some tests:

```clojure
(testing "Setting a new value populates the grace period cache"
    (let [new-token (tu/random-token)]
      (binding [http/request (fn [& _] {:status 200
                                        :body "{\"valid\":true,\"status\":\"fake\",\"features\":[\"fake\",\"features\"]}"})]
        (mt/discard-setting-changes [premium-embedding-token]
          (premium-features.settings/premium-embedding-token! new-token)
          (is (= #{"fake" "features"} (token-check/*token-features*)))
          (is (= {:valid true :status "fake" :features ["fake" "features"]}
                 (token-check/retrieve token-check/grace-period new-token)))))))
```

But this ended up leaving a setting table value for this value. i don't
feel like looking into discard setting changes so i'm gonna just remove it

* attempt to simplify the api a bit

the thee important functions are now `token-information`, `harness` and
`decode-token`.

Everyone should use token-information. Harness hooks up the grace period
and retry strategies, and `decode-token` only cares about decoding a
token. It should return the token-status map {:valid true ...} or throw.

* fixup test

* clean up tests and rename a bit

* remove comment block

* remove commented out grace period

* bit of cleanup

* fix with-random-premium-token! macro

* function composes them instead of caller

rather than a caller needing to know all of the layers, i thread them
for you and let you provide all arugments in one function call.

dynamic var for needing to customize layers in tests. largely for
removing the circuit-breaker which is stateful and hard to restart if
you want to simulate errors in tests

* rename test
2025-10-30 13:59:20 -05:00
github-automation-metabase
c62d68c201 Update error message for remote sync dep checking (#65148) (#65217)
* Update error message for remote sync dep checking

Try to make these error messages less jargony because they are presented
by the user interface when dependency checking content fails.

Closes UXW-2142 and UXW-1879.

* Update some missed tests

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2025-10-30 17:35:45 +00:00
github-automation-metabase
6390717ce9 fix: improve collections graph performance (#65098) (#65211)
* fix: improve collections graph performance

Fixes performance generating and updating a collection graph by avoiding
the cross join of all negative permissions (blocks) between groups and
collections. Instead it builds sparse graph where missing entries for
group/collection paris can be assumed to be :none permissions.

In practice this drops a collection permission update on a graph of 5K
groups and 5K collections from a greater than 10min operation on my
local machine against MySQL to a .5s operation.

* fixup! explicilty disj :root in other places

* fixup! improve some docs

* fixup! improve more docs

* fixup! seq checks

* fixup! blank lines

* fixup! convert raw sql concat into honeysql

* fixup! e2e test

Co-authored-by: Edward Paget <edpaget@users.noreply.github.com>
2025-10-30 17:10:19 +00:00
github-automation-metabase
27abb898a5 Create appdb tables in its own connection (#65171) (#65219)
Co-authored-by: Nathan Voxland <nathan@metabase.com>
2025-10-30 16:43:59 +00:00
Alex Yarosh
c70bd40481 remove transforms (#65221) 2025-10-30 11:53:29 -04:00
github-automation-metabase
2e9f645974 remove border from dashboard header where header=false and no tabs (#65161) (#65214)
* remove border from dashboard header where header=false and no tabs

* move css code up to keep no border in fullscreen

Co-authored-by: Nicolò Pretto <info@npretto.com>
2025-10-30 15:43:17 +00:00
2374 changed files with 698066 additions and 569929 deletions

View File

@@ -0,0 +1,420 @@
---
name: add-malli-schemas
description: Efficiently add Malli schemas to API endpoints in the Metabase codebase with proper patterns, validation timing, and error handling
---
# Add Malli Schemas to API Endpoints
This skill helps you efficiently and uniformly add Malli schemas to API endpoints in the Metabase codebase.
## Reference Files (Best Examples)
- `src/metabase/warehouses/api.clj` - Most comprehensive schemas, custom error messages
- `src/metabase/api_keys/api.clj` - Excellent response schemas
- `src/metabase/collections/api.clj` - Great named schema patterns
- `src/metabase/timeline/api/timeline.clj` - Clean, simple examples
## Quick Checklist
When adding Malli schemas to an endpoint:
- [ ] Route params have schemas
- [ ] Query params have schemas with `:optional true` and `:default` where appropriate
- [ ] Request body has a schema (for POST/PUT)
- [ ] Response schema is defined (using `:-` after route string)
- [ ] Use existing schema types from `ms` namespace when possible
- [ ] Consider creating named schemas for reusable or complex types
- [ ] Add contextual error messages for validation failures
## Basic Structure
### Complete Endpoint Example
```clojure
(mr/def ::Color [:enum "red" "blue" "green"])
(mr/def ::ResponseSchema
[:map
[:id pos-int?]
[:name string?]
[:color ::Color]
[:created_at ms/TemporalString]])
(api.macros/defendpoint :post "/:name" :- ::ResponseSchema
"Create a resource with a given name."
[;; Route Params:
{:keys [name]} :- [:map [:name ms/NonBlankString]]
;; Query Params:
{:keys [include archived]} :- [:map
[:include {:optional true} [:maybe [:= "details"]]]
[:archived {:default false} [:maybe ms/BooleanValue]]]
;; Body Params:
{:keys [color]} :- [:map [:color ::Color]]
]
;; endpoint implementation, ex:
{:id 99
:name (str "mr or mrs " name)
:color ({"red" "blue" "blue" "green" "green" "red"} color)
:created_at (t/format (t/formatter "yyyy-MM-dd'T'HH:mm:ssXXX") (t/zoned-date-time))}
)
```
## Common Schema Patterns
1. Route Params (the 5 in `api/user/id/5`)
2. Query Params (the sort+asc pair in `api/users?sort=asc`)
3. Body Params (the contents of a request body. Almost always decoded from json into edn)
4. The Raw Request map
Of the 4 arguments, deprioritize usage of the raw request unless necessary.
### Route Params
Always required, typically just a map with an ID:
```clojure
[{:keys [id]} :- [:map [:id ms/PositiveInt]]]
```
For multiple route params:
```clojure
[{:keys [id field-id]} :- [:map
[:id ms/PositiveInt]
[:field-id ms/PositiveInt]]]
```
### Query Params
Add properties for `{:optional true ...}` and `:default` values:
```clojure
{:keys [archived include limit offset]} :- [:map
[:archived {:default false} [:maybe ms/BooleanValue]]
[:include {:optional true} [:maybe [:= "tables"]]]
[:limit {:optional true} [:maybe ms/PositiveInt]]
[:offset {:optional true} [:maybe ms/PositiveInt]]]
```
### Request Body (POST/PUT)
```clojure
{:keys [name description parent_id]} :- [:map
[:name ms/NonBlankString]
[:description {:optional true} [:maybe ms/NonBlankString]]
[:parent_id {:optional true} [:maybe ms/PositiveInt]]]
```
### Response Schemas
#### Simple inline response:
```clojure
(api.macros/defendpoint :get "/:id" :- [:map
[:id pos-int?]
[:name string?]]
"Get a thing"
...)
```
#### Named schema for reuse:
```clojure
(mr/def ::Thing
[:map
[:id pos-int?]
[:name string?]
[:description [:maybe string?]]])
(api.macros/defendpoint :get "/:id" :- ::Thing
"Get a thing"
...)
(api.macros/defendpoint :get "/" :- [:sequential ::Thing]
"Get all things"
...)
```
## Common Schema Types
### From `metabase.util.malli.schema` (aliased as `ms`)
Prefer the schemas in the ms/* namespace, since they work better with our api infrastructure.
For example use `ms/PositiveInt` instead of `pos-int?`.
```clojure
ms/PositiveInt ;; Positive integer
ms/NonBlankString ;; Non-empty string
ms/BooleanValue ;; String "true"/"false" or boolean
ms/MaybeBooleanValue ;; BooleanValue or nil
ms/TemporalString ;; ISO-8601 date/time string (for REQUEST params only!)
ms/Map ;; Any map
ms/JSONString ;; JSON-encoded string
ms/PositiveNum ;; Positive number
ms/IntGreaterThanOrEqualToZero ;; 0 or positive
```
**IMPORTANT:** For response schemas, use `:any` for temporal fields, not `ms/TemporalString`!
Response schemas validate BEFORE JSON serialization, so they see Java Time objects.
### Built-in Malli Types
```clojure
:string ;; Any string
:boolean ;; true/false
:int ;; Any integer
:keyword ;; Clojure keyword
pos-int? ;; Positive integer predicate
[:maybe X] ;; X or nil
[:enum "a" "b" "c"] ;; One of these values
[:or X Y] ;; Schema that satisfies X or Y
[:and X Y] ;; Schema that satisfies X and Y
[:sequential X] ;; Sequential of Xs
[:set X] ;; Set of Xs
[:map-of K V] ;; Map with keys w/ schema K and values w/ schema V
[:tuple X Y Z] ;; Fixed-length tuple of schemas X Y Z
```
Avoid using sequence schemas unless completely necessary.
## Step-by-Step: Adding Schemas to an Endpoint
### Example: Adding return schema to `GET /api/field/:id/related`
**Before:**
```clojure
(api.macros/defendpoint :get "/:id/related"
"Return related entities."
[{:keys [id]} :- [:map [:id ms/PositiveInt]]]
(-> (t2/select-one :model/Field :id id) api/read-check xrays/related))
```
**Step 1:** Check what the function returns (look at `xrays/related`)
**Step 2:** Define response schema based on return type:
```clojure
(mr/def ::RelatedEntity
[:map
[:tables [:sequential [:map [:id pos-int?] [:name string?]]]]
[:fields [:sequential [:map [:id pos-int?] [:name string?]]]]])
```
**Step 3:** Add response schema to endpoint:
```clojure
(api.macros/defendpoint :get "/:id/related" :- ::RelatedEntity
"Return related entities."
[{:keys [id]} :- [:map [:id ms/PositiveInt]]]
(-> (t2/select-one :model/Field :id id) api/read-check xrays/related))
```
## Advanced Patterns
### Custom Error Messages
```clojure
(def DBEngineString
"Schema for a valid database engine name."
(mu/with-api-error-message
[:and
ms/NonBlankString
[:fn
{:error/message "Valid database engine"}
#(u/ignore-exceptions (driver/the-driver %))]]
(deferred-tru "value must be a valid database engine.")))
```
### Enum with Documentation
```clojure
(def PinnedState
(into [:enum {:error/message "pinned state must be 'all', 'is_pinned', or 'is_not_pinned'"}]
#{"all" "is_pinned" "is_not_pinned"}))
```
### Complex Nested Response
```clojure
(mr/def ::DashboardQuestionCandidate
[:map
[:id ms/PositiveInt]
[:name ms/NonBlankString]
[:description [:maybe string?]]
[:sole_dashboard_info
[:map
[:id ms/PositiveInt]
[:name ms/NonBlankString]
[:description [:maybe string?]]]]])
(mr/def ::DashboardQuestionCandidatesResponse
[:map
[:data [:sequential ::DashboardQuestionCandidate]]
[:total ms/PositiveInt]])
```
### Paginated Response Pattern
```clojure
(mr/def ::PaginatedResponse
[:map
[:data [:sequential ::Item]]
[:total integer?]
[:limit {:optional true} [:maybe integer?]]
[:offset {:optional true} [:maybe integer?]]])
```
## Common Pitfalls
### Don't: Forget `:maybe` for nullable fields
```clojure
[:description ms/NonBlankString] ;; WRONG - fails if nil
[:description [:maybe ms/NonBlankString]] ;; RIGHT - allows nil
```
### Don't: Forget `:optional true` for optional query params
```clojure
[:limit ms/PositiveInt] ;; WRONG - required but shouldn't be
[:limit {:optional true} [:maybe ms/PositiveInt]] ;; RIGHT
```
### Don't: Forget `:default` values for known params
```clojure
[:limit ms/PositiveInt] ;; WRONG - required but shouldn't be
[:limit {:optional true :default 0} [:maybe ms/PositiveInt]] ;; RIGHT
```
### Don't: Mix up route params, query params, and body
```clojure
;; WRONG - all in one map
[{:keys [id name archived]} :- [:map ...]]
;; RIGHT - separate destructuring
[{:keys [id]} :- [:map [:id ms/PositiveInt]]
{:keys [archived]} :- [:map [:archived {:default false} ms/BooleanValue]]
{:keys [name]} :- [:map [:name ms/NonBlankString]]]
```
### Don't: Use `ms/TemporalString` for Java Time objects in response schemas
```clojure
;; WRONG - Java Time objects aren't strings yet
[:date_joined ms/TemporalString]
;; RIGHT - schemas validate BEFORE JSON serialization
[:date_joined :any] ;; Java Time object, serialized to string by middleware
[:last_login [:maybe :any]] ;; Java Time object or nil
```
**Why:** Response schemas validate the internal Clojure data structures BEFORE they are serialized to JSON. Java Time objects like `OffsetDateTime` get converted to ISO-8601 strings by the JSON middleware, so the schema needs to accept the raw Java objects.
### Don't: Use `[:sequential X]` when the data is actually a set
```clojure
;; WRONG - group_ids is actually a set
[:group_ids {:optional true} [:sequential pos-int?]]
;; RIGHT - matches the actual data structure
[:group_ids {:optional true} [:maybe [:set pos-int?]]]
```
**Why:** Toucan hydration methods often return sets. The JSON middleware will serialize sets to arrays, but the schema validates before serialization.
### Don't: Create anonymous schemas for reused structures
Use `mr/def` for schemas used in multiple places:
```clojure
(mr/def ::User
[:map
[:id pos-int?]
[:email string?]
[:name string?]])
```
## Finding Return Types
1. **Look at the function being called**
```clojure
(api.macros/defendpoint :get "/:id"
[{:keys [id]}]
(t2/select-one :model/Field :id id)) ;; Returns a Field instance
```
2. **Check Toucan models for structure**
Look in `src/metabase/*/models/*.clj` for model definitions.
3. **Use clojure-mcp or REPL to inspect**
```bash
./bin/mage -repl '(require '\''metabase.xrays.core) (doc metabase.xrays.core/related)'
```
4. **Check tests**
Tests often show the expected response structure.
## Understanding Schema Validation Timing
**CRITICAL CONCEPT:** Schemas validate at different points in the request/response lifecycle:
### Request Parameter Schemas (Query/Body/Route)
- Validate AFTER JSON parsing
- Data is already deserialized (strings, numbers, booleans)
- Use `ms/TemporalString` for date/time inputs
- Use `ms/BooleanValue` for boolean query params
### Response Schemas
- Validate BEFORE JSON serialization
- Data is still in Clojure format (Java Time objects, sets, keywords)
- Use `:any` for Java Time objects
- Use `[:set X]` for sets
- Use `[:enum :keyword]` for keyword enums
### Serialization Flow
```
Request: JSON string → Parse → Coerce → Handler
Response: Handler → Schema Check → Encode → Serialize → JSON string
```
## Workflow Summary
1. **Read the endpoint** - understand what it does
2. **Identify params** - route, query, body
3. **Add parameter schemas** - use existing types from `ms`
4. **Determine return type** - check the implementation
5. **Define response schema** - inline or named with `mr/def`
6. **Test** - ensure the endpoint works and validates correctly
## Testing Your Schemas
After adding schemas, verify:
1. **Valid requests work** - test with correct data
2. **Invalid requests fail gracefully** - test with wrong types
3. **Optional params work** - test with/without optional params
4. **Error messages are clear** - check validation error responses
## Tips
- **Start simple** - begin with basic types, refine later
- **Reuse schemas** - if you see the same structure twice, make it a named schema
- **Be specific** - use `ms/PositiveInt` instead of `pos-int?`
- **Document intent** - add docstrings to named schemas
- **Follow conventions** - look at similar endpoints in the same namespace
- **Check the actual data** - use REPL to inspect what's actually returned before serialization
## Additional Resources
- [Malli Documentation](https://github.com/metosin/malli)
- Metabase Malli utilities: `src/metabase/util/malli/schema.clj`
- Metabase schema registry: `src/metabase/util/malli/registry.clj`

View File

@@ -229,9 +229,6 @@
{:exclude
[(build.uberjar/with-duration-ms)
(cljs.test/is [=? malli=])
(clojure.core.logic/fresh)
(clojure.core.logic/matcha)
(clojure.core.logic/run)
(clojure.test/is [=? malli= qv=])
(clojure.tools.macro/macrolet)
instaparse.core/transform
@@ -410,7 +407,6 @@
:lint-as
{cljs.cache/defcache clojure.core/deftype
clojure.core.cache/defcache clojure.core/deftype
clojure.core.logic/defne clj-kondo.lint-as/def-catch-all
clojure.test.check.clojure-test/defspec clojure.test/deftest
clojure.test.check.properties/for-all clojure.core/let
clojurewerkz.quartzite.jobs/defjob clojure.core/defn
@@ -902,16 +898,21 @@
performance-sensitive
{:linters
{:discouraged-var
{clojure.core/every? {:message "Use metabase.util.performance/every?"}
{clojure.core/empty? {:message "Use metabase.util.performance/empty?"}
clojure.core/not-empty {:message "Use metabase.util.performance/not-empty"}
clojure.core/every? {:message "Use metabase.util.performance/every?"}
clojure.core/mapv {:message "Use metabase.util.performance/mapv"}
clojure.core/run! {:message "Use metabase.util.performance/run!"}
clojure.core/get-in {:message "Use metabase.util.performance/get-in"}
clojure.core/select-keys {:message "Use metabase.util.performance/select-keys"}
clojure.core/some {:message "Use metabase.util.performance/some"}
clojure.core/update-keys {:message "Use metabase.util.performance/update-keys"}
clojure.walk/keywordize-keys {:message "Use metabase.util.performance/keywordize-keys"}
clojure.walk/postwalk {:message "Use metabase.util.performance/postwalk"}
clojure.walk/prewalk {:message "Use metabase.util.performance/prewalk"}
clojure.walk/walk {:message "Use metabase.util.performance/walk"}}}}
clojure.walk/walk {:message "Use metabase.util.performance/walk"}
clojure.walk/for {:message "Use metabase.util.performance/for"}
clojure.walk/doseq {:message "Use metabase.util.performance/doseq"}}}}
qp-and-driver-source-namespaces
{:linters

View File

@@ -160,7 +160,8 @@
api-routes
{:team "UX West"
:api #{metabase.api-routes.core}
:api #{metabase.api-routes.cmd
metabase.api-routes.core}
:uses :any}
app-db
@@ -330,6 +331,7 @@
{:team "UX West"
:api #{metabase.collections.api
metabase.collections.core
metabase.collections.init
metabase.collections.models.collection
metabase.collections.models.collection.root}
:uses #{api
@@ -349,6 +351,7 @@
request
revisions
search
settings
upload
util}}
@@ -605,12 +608,15 @@
:api #{metabase.lib.binning
metabase.lib.binning.util
metabase.lib.card
metabase.lib.computed ; temporarily so that `qp.compile` can use it as lib memoization evolves
metabase.lib.convert ; Only so [[metabase.queries.models.card]] can set dynamic vars.
metabase.lib.core
metabase.lib.equality
metabase.lib.field
metabase.lib.field.resolution
metabase.lib.filter
metabase.lib.filter.desugar.jvm ; only so [[metabase.legacy-mbql.jvm-util]] can use defined regexes
metabase.lib.hierarchy
metabase.lib.init
metabase.lib.join.util
metabase.lib.metadata
@@ -832,7 +838,8 @@
:api #{metabase.premium-features.api
metabase.premium-features.core
metabase.premium-features.init}
:uses #{api
:uses #{analytics
api
app-db
classloader
config
@@ -1142,6 +1149,7 @@
session
settings
system
users
util
enterprise/sso}}
@@ -1238,6 +1246,7 @@
app-db
audit-app
config
database-routing
driver
events
lib
@@ -1358,7 +1367,8 @@
metabase.users.init
metabase.users.models.user
metabase.users.models.user-parameter-value
metabase.users.schema}
metabase.users.schema
metabase.users.settings}
:uses #{analytics
api
appearance
@@ -1562,6 +1572,8 @@
:api #{metabase-enterprise.ai-sql-fixer.api}
:uses #{api
driver
lib
lib-be
query-processor
util
enterprise/metabot-v3}}
@@ -1608,6 +1620,8 @@
query-permissions
query-processor
settings
setup
startup
sync
users
util
@@ -1647,6 +1661,7 @@
:uses #{api
events
premium-features
store-api
util
enterprise/harbormaster}}
@@ -1727,7 +1742,6 @@
:uses #{analyze
api
collections
config
driver
events
graph
@@ -1735,6 +1749,7 @@
lib-be
models
native-query-snippets
permissions
premium-features
queries
query-processor
@@ -1903,7 +1918,7 @@
query-processor
util}}
enterprise/remote-sync
enterprise/remote-sync
{:team "UX West"
:api #{metabase-enterprise.remote-sync.api
metabase-enterprise.remote-sync.core
@@ -1999,6 +2014,7 @@
app-db
appearance
collections
config
logger
models
plugins
@@ -2061,6 +2077,7 @@
:uses #{analytics
api
app-db
channel
driver
events
lib
@@ -2070,6 +2087,7 @@
queries
query-processor
request
revisions
search
settings
sync

View File

@@ -119,10 +119,10 @@
reset-token-ttl-hours
retired-setting
retry-initial-interval
retry-max-attempts
retry-max-retries
retry-max-interval-millis
retry-multiplier
retry-randomization-factor
retry-jitter-factor
saml-application-name
saml-attribute-email
saml-attribute-firstname

View File

@@ -43,9 +43,6 @@
with-meta [[:default]]
;; library stuff. Libraries that specify their own `:style/indent` specs are included in the section after this
;; since it is generated automatically.
clojure.core.logic/fresh [[:block 1]]
clojure.core.logic/matcha [[:block 1]]
clojure.core.logic/run [[:block 2]]
clojure.core.match/match [[:block 1]]
clojure.test.check.properties/for-all [[:block 1]]
clojure.test.check.properties/for-all* [[:block 1]]

23
.codespellignore Normal file
View File

@@ -0,0 +1,23 @@
Brite
afterAll
ags
altho
cancelation
cancelations
datas
edn
eduction
hasTables
horizontalX
horizontalY
juxt
methodd
notIn
pass-thru
ser
serieses
sortings
trs
trsn
tru
trun

3
.codespellrc Normal file
View File

@@ -0,0 +1,3 @@
[codespell]
skip = *.csv,*.edn,*.geojson,*.json,*.tsv,*.xml,docs/developers-guide/drivers/driver-tests.md,docs/developers-guide/e2e-tests.md,docs/questions/query-builder/expressions-list.md,docs/questions/visualizations/country-codes.md,e2e/test/scenarios/admin/i18n/content-translation/constants.ts,frontend/src/cljs,frontend/src/metabase/querying/expressions/tokenizer/lezer.js,frontend/src/metabase/static-viz/constants/char-sizes.ts,frontend/src/metabase/visualizations/lib/mapping_codes.ts,modules/drivers/mongo/src/metabase/driver/mongo/operators.clj
ignore-words = .codespellignore

View File

@@ -118,7 +118,6 @@ module.exports = {
"And",
"When",
"Then",
"describeWithSnowplow",
],
},
],
@@ -348,5 +347,11 @@ module.exports = {
"import/no-commonjs": "off",
},
},
{
files: ["**/*.stories.tsx", "**/preview.tsx"],
rules: {
"import/no-default-export": "off",
},
},
],
};

12
.github/CODEOWNERS vendored
View File

@@ -1,12 +1,12 @@
# Before changing this file, make sure you have read how we use it:
# https://www.notion.so/metabase/Pull-Request-Code-Review-Guide-374f05df889748b69d67af753f9bc9b8?pvs=4#36550c04ceab40b5a8b8bee6264b090c
enterprise/frontend/src/embedding-sdk-package @metabase/embedding
enterprise/frontend/src/embedding-sdk-bundle @metabase/embedding
enterprise/frontend/src/embedding-sdk-shared @metabase/embedding
frontend/src/metabase/embedding-sdk @metabase/embedding
frontend/src/metabase/public/containers/PublicOrEmbeddedQuestion @metabase/embedding
frontend/src/metabase/public/containers/PublicOrEmbeddedDashboard @metabase/embedding
# enterprise/frontend/src/embedding-sdk-package @metabase/embedding
# enterprise/frontend/src/embedding-sdk-bundle @metabase/embedding
# enterprise/frontend/src/embedding-sdk-shared @metabase/embedding
# frontend/src/metabase/embedding-sdk @metabase/embedding
# frontend/src/metabase/public/containers/PublicOrEmbeddedQuestion @metabase/embedding
# frontend/src/metabase/public/containers/PublicOrEmbeddedDashboard @metabase/embedding
frontend/src/metabase/ui @metabase/core-frontend-ux-west
# snowplow/* @metabase/data
src/metabase/analytics/prometheus.clj @metabase/cloud-ops

View File

@@ -10,6 +10,12 @@ outputs:
node-cache-key:
description: "The cache key for the Node.js cache."
value: ${{ steps.keys-factory.outputs.node-cache-key }}
eslint-cache-key:
description: "The cache key for Eslint cache"
value: ${{ steps.keys-factory.outputs.eslint-cache-key }}
cypress-cache-key:
description: "The cache key for Cypress cache"
value: ${{ steps.keys-factory.outputs.cypress-cache-key }}
runs:
using: "composite"
@@ -19,9 +25,13 @@ runs:
run: |
M2_CACHE_PREFIX='M2'
NODE_CACHE_PREFIX='node-modules'
ESLINT_CACHE_PREFIX='eslint'
CYPRESS_CACHE_PREFIX='cypress'
WEEK_OF_YEAR=$(/bin/date "+%G-%V")
CACHE_SUFFIX="${{ runner.os }}-$WEEK_OF_YEAR"
echo "m2-cache-key=$M2_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
echo "node-cache-key=$NODE_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
echo "eslint-cache-key=$ESLINT_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
echo "cypress-cache-key=$CYPRESS_CACHE_PREFIX-$CACHE_SUFFIX" >> $GITHUB_OUTPUT
shell: bash

View File

@@ -0,0 +1,19 @@
name: Maximize disk space
description: Removes unused stuff from GH runner
runs:
using: "composite"
steps:
- name: Maximize build space
shell: bash
run: |
echo "-- Dotnet"
sudo rm -rf /usr/share/dotnet
echo "-- Android"
sudo rm -rf /usr/local/lib/android
echo "-- Haskell"
sudo rm -rf /opt/ghc
echo "-- CodeQL"
sudo rm -rf /opt/hostedtoolcache/CodeQL
df -h

View File

@@ -25,11 +25,6 @@ runs:
curl -O https://download.clojure.org/install/linux-install-${{ inputs.clojure-version }}.sh &&
sudo bash ./linux-install-${{ inputs.clojure-version }}.sh
- name: Fetch CI config
shell: bash
run: |
curl -o ci-test-config.json https://raw.githubusercontent.com/metabase/metabase/refs/heads/master/ci-test-config.json
- name: Get M2 cache key
uses: ./.github/actions/get-cache-keys
id: get-cache-keys

View File

@@ -22,16 +22,16 @@ runs:
chrome-version: 1097615
id: setup-chrome
- name: Get current week of year
id: get-date
run: |
echo "week-of-year=$(/bin/date "+%G-%V")" >> $GITHUB_OUTPUT
shell: bash
- name: Get cache keys
uses: ./.github/actions/get-cache-keys
id: get-cache-keys
- name: Get Cypress cache
uses: actions/cache@v4
uses: actions/cache/restore@v4
with:
path: ~/.cache/Cypress
key: ${{ runner.os }}-Cypress-${{ steps.get-date.outputs.week-of-year }}
key: ${{ steps.get-cache-keys.outputs.cypress-cache-key }}
- name: Ensure that Cypress executable is ready
run: |
yarn cypress install

View File

@@ -6,7 +6,7 @@ inputs:
apply-patches:
description: "Whether to patch frontend dependencies with patch-package."
required: true
default: 'true'
default: "true"
runs:
using: "composite"
steps:
@@ -28,11 +28,21 @@ runs:
~/.gitlibs
key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
- name: Get yarn cache directory
id: yarn-cache-dir
run: |
YARN_CACHE_DIR=$(yarn cache dir)
echo "Yarn cache directory: $YARN_CACHE_DIR"
echo "dir=$YARN_CACHE_DIR" >> $GITHUB_OUTPUT
shell: bash
- name: Restore node_modules cache
uses: actions/cache/restore@v4
id: node-modules-cache
with:
path: node_modules
path: |
${{ steps.yarn-cache-dir.outputs.dir }}
node_modules
key: ${{ steps.get-cache-keys.outputs.node-cache-key }}
# postinstall lifecycle hook can be dangerous in CI so we only run it locally (see package.json)

View File

@@ -1,31 +0,0 @@
name: Run Embedding SDK Storybook
runs:
using: "composite"
steps:
- name: Prepare frontend environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Compile CLJS
run: yarn build-pure:cljs
shell: bash
- name: Build Storybook
run: yarn build-storybook-embedding-sdk
shell: bash
- name: Serve Storybook
run: yarn http-server storybook-static -p 6006 &
shell: bash
- name: Wait for Storybook to become available
run: |
echo "Waiting for Storybook to be served..."
while ! curl --silent --fail http://localhost:6006; do
sleep 5
echo "Retrying..."
done
echo "Storybook is being served!"
shell: bash

View File

@@ -9,33 +9,71 @@ inputs:
build-static-viz:
required: true
default: false
logs-artifact-suffix:
required: false
description: Suffix to append to the test logs artifact name to avoid conflicts in matrix jobs
outputs:
quarantine-skipped:
description: Whether the driver test was skipped due to quarantine
value: ${{ steps.check-driver.outputs.skip }}
runs:
using: "composite"
steps:
- name: Check if driver is ignored
id: check-driver
shell: bash
run: |
# If DRIVERS env var is not set, proceed with tests
if [ -z "$DRIVERS" ]; then
echo "No DRIVERS env var set. Proceeding with tests."
echo "skip=false" >> $GITHUB_OUTPUT
exit 0
fi
# Fetch CI config and check if driver should be skipped
curl -sSf -o ci-test-config.json https://raw.githubusercontent.com/metabase/ci-test-config/refs/heads/master/ci-test-config.json || true
# Check if the driver is in the ignored list (gracefully handle missing/invalid config)
IS_IGNORED=$(jq --arg driver "$DRIVERS" '.ignored.drivers // [] | contains([$driver])' ci-test-config.json 2>/dev/null || echo "false")
if [ "$IS_IGNORED" = "true" ]; then
echo "⚠️ Driver '$DRIVERS' is in the ignored list. Skipping tests."
echo "View the ignored list here: https://github.com/metabase/ci-test-config/blob/master/ci-test-config.json"
echo "skip=true" >> $GITHUB_OUTPUT
else
echo "Driver '$DRIVERS' is not ignored. Proceeding with tests."
echo "skip=false" >> $GITHUB_OUTPUT
fi
- name: Prepare back-end environment
if: steps.check-driver.outputs.skip != 'true'
uses: ./.github/actions/prepare-backend
- name: Prepare front-end environment
if: ${{ steps.check-driver.outputs.skip != 'true' && inputs.build-static-viz == 'true' }}
uses: ./.github/actions/prepare-frontend
if: ${{ inputs.build-static-viz == 'true' }}
- name: Build static viz frontend
if: ${{ steps.check-driver.outputs.skip != 'true' && inputs.build-static-viz == 'true' }}
run: yarn build-static-viz
shell: bash
if: ${{ inputs.build-static-viz == 'true' }}
env:
MB_EDITION: ee
- name: Test database driver
if: steps.check-driver.outputs.skip != 'true'
run: clojure -X:dev:ci:ee:ee-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!
# 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.
# We only want to "continue on error" (ignore failures) when the Trunk upload is active - i.e. not on drafts!
continue-on-error: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true) }}
# 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.
continue-on-error: true
- name: Publish Test Report (JUnit)
uses: dorny/test-reporter@v1
if: ${{ steps.run-test.outcome == 'failure' }}
# As per the documentation: https://docs.github.com/en/actions/reference/workflows-and-actions/contexts#steps-context
# test.outcome gives us access to the result before `continue-on-error` overrides it and sets it to 'success'.
# We want test reports even if the test step gets cancelled (e.g. times out), hence we match anything that is not a 'success'.
if: ${{ steps.run-test.outcome != 'success' && steps.check-driver.outputs.skip != 'true' }}
with:
path: "target/junit/**/*_test.xml"
name: JUnit Test Report ${{ inputs.junit-name }}
@@ -44,10 +82,10 @@ runs:
list-tests: failed
fail-on-error: false
- name: Upload Logs on Failure
if: ${{ steps.run-test.outcome == 'failure' }}
if: always() && steps.run-test.outcome != 'success' && steps.check-driver.outputs.skip != 'true'
uses: actions/upload-artifact@v4
with:
name: test-logs-${{ github.job }}
name: ${{ format('test-logs-{0}{1}', github.job, (inputs.logs-artifact-suffix == '' || inputs.logs-artifact-suffix == null) && '' || 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

@@ -20,7 +20,7 @@ inputs:
required: true
variant:
required: false
default: ''
default: ""
runs:
using: "composite"
@@ -48,10 +48,12 @@ runs:
aws s3 cp ${OUTPUT_FILE}.zip s3://$BUCKET/$DATE/$GITHUB_RUN_ID/$GITHUB_RUN_ATTEMPT/
- name: Upload results to Trunk
if: ${{ always() && !(github.event_name == 'pull_request' && github.event.pull_request.draft == true) }}
if: always() # Important! This step must always run because it controls job's exit code.
uses: trunk-io/analytics-uploader@main
with:
junit-paths: ${{ inputs.input-path }}
variant: ${{ inputs.variant || inputs.output-name }}
org-slug: metabase
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

View File

@@ -1,3 +1,5 @@
version: 1
name: "Metabase CodeQL config"
paths-ignore:

View File

@@ -11,15 +11,19 @@ shared_specs: &shared_specs
- "test/**/*.cljc"
- "test/**/*.cljs"
frontend_ci: &frontend_ci
shared_ci: &shared_ci
- ".github/actions/prepare-frontend/**"
- ".github/actions/prepare-backend/**"
- ".github/workflows/frontend.yml"
- ".github/workflows/run-tests.yml"
frontend_embedding_sdk_ci: &frontend_embedding_sdk_ci
- ".github/actions/prepare-frontend/**"
- ".github/actions/prepare-backend/**"
- ".github/workflows/*embedding-sdk*.yml"
shared_e2e: &shared_e2e
- "e2e/runner/**"
- "e2e/snapshot-creators/**"
- "e2e/support/**"
frontend_ci: &frontend_ci
- *shared_ci
- ".github/workflows/frontend.yml"
frontend_configs: &frontend_configs
- "yarn.lock"
@@ -41,14 +45,12 @@ frontend_sources: &frontend_sources
- "enterprise/frontend/!(test)**/**/{!(*.spec),}.{js,jsx,ts,tsx,css}"
- "frontend/!(test)**/**/{!(*.spec),}.{js,jsx,ts,tsx,css}"
# Used only in .github/workflows/conventional-commit-pr-title-reminder.yml
frontend_embedding_sources:
- "enterprise/frontend/src/{embedding,embedding-*}/**/{!(*.spec),}.{js,jsx,ts,tsx,css}"
- "enterprise/frontend/src/metabase-enterprise/{embedding,embedding-*}**/{!(*.spec),}.{js,jsx,ts,tsx,css}"
frontend_embedding_sdk_sources:
- *frontend_configs
- "enterprise/frontend/!(test)**/**/{!(*.spec),}.{js,jsx,ts,tsx,css}"
# Used only in .github/workflows/embedding-sdk-labels-reminder.yml
frontend_embedding_sdk_package_sources:
- "enterprise/frontend/src/embedding-sdk-package/**/!(*.spec).{js,jsx,ts,tsx,css}"
@@ -76,8 +78,7 @@ frontend_loki_ci: &frontend_loki_ci
- ".storybook/**"
backend_ci: &backend_ci
- ".github/actions/prepare-frontend/**"
- ".github/actions/prepare-backend/**"
- *shared_ci
- ".github/actions/test-driver/**"
- ".github/workflows/backend.yml"
- ".github/workflows/drivers.yml"
@@ -117,9 +118,9 @@ sources: &sources
- *backend_sources
e2e_ci: &e2e_ci
- ".github/actions/prepare-frontend/**"
- ".github/actions/prepare-backend/**"
- *shared_ci
- ".github/actions/prepare-uberjar-artifact/**"
- ".github/actions/fetch-artifact/action.yml"
- ".github/actions/e2e-prepare-containers/**"
- ".github/actions/prepare-cypress/**"
- ".github/workflows/e2e-*"
@@ -127,22 +128,27 @@ e2e_ci: &e2e_ci
e2e_specs: &e2e_specs
- e2e/!(test-host-app)**/*.cy.*.{js,ts}
e2e_cross_version: &e2e_cross_version
- ".github/workflows/e2e-cross-version.yml"
- "e2e/test/scenarios/cross-version/**"
embedding_sdk_ci: &embedding_sdk_ci
- *shared_ci
- ".github/actions/prepare-uberjar-artifact/**"
- ".github/actions/fetch-artifact/action.yml"
- ".github/actions/prepare-cypress/**"
- ".github/workflows/embedding-sdk*.yml"
e2e_embedding_sdk:
- *frontend_embedding_sdk_ci
- *sources
- "e2e/component/**/*.cy.*.{js,ts}"
e2e_embedding_sdk_compatibility:
embedding_sdk_components:
- *default
- *frontend_embedding_sdk_ci
- *embedding_sdk_ci
- *sources
- *shared_e2e
- "e2e/test-component/**/*.cy.*.{js,jsx,ts,tsx}"
embedding_sdk_host_sample_apps:
- *default
- *embedding_sdk_ci
- *frontend_sources
- *backend_sources
- *shared_e2e
- "e2e/embedding-sdk-host-apps/**"
- "e2e/runner/embedding-sdk/**"
- "e2e/test-host-app/**/*.cy.*.{js,ts}"
snowplow: &snowplow
@@ -170,6 +176,7 @@ yaml:
- "**/*.yaml"
codeql:
- ".github/workflows/codeql.yml"
- "frontend/src/**"
- "enterprise/frontend/src/**"

View File

@@ -3,14 +3,8 @@
// grouping some specific tests together, other tests are split into chunks
const DEFAULT_SPEC_PATTERN = "./e2e/test/scenarios/**/*.cy.spec.*";
const EMBEDDING_SDK_SPEC_PATTERN =
"./e2e/test/scenarios/embedding-sdk/**.cy.spec.*";
const specialTestConfigs = [
{
name: "embedding-sdk",
specs: EMBEDDING_SDK_SPEC_PATTERN,
},
{
name: "oss-subset",
edition: "oss",

View File

@@ -11,7 +11,7 @@ describe("buildMatrix", () => {
it("should calculate correct regular chunks with default parameters", () => {
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 30);
expect(result.regularChunks).toBe(26);
expect(result.regularChunks).toBe(27);
});
it("should create correct number of configuration objects", () => {
@@ -23,7 +23,7 @@ describe("buildMatrix", () => {
it("should apply default specs path when empty entry is provided", () => {
const result = testBuildMatrix("", 6);
expect(result.regularChunks).toBe(2);
expect(result.regularChunks).toBe(3);
expect(result.config.length).toBe(6);
});
@@ -39,14 +39,13 @@ describe("buildMatrix", () => {
});
it("should handle case when input chunks equals special tests count", () => {
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 4);
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 3);
expect(result.regularChunks).toBe(0);
expect(result.config.length).toBe(4);
expect(result.config[0].name).toBe("embedding-sdk");
expect(result.config[1].name).toBe("oss-subset");
expect(result.config[2].name).toBe("mongo");
expect(result.config[3].name).toBe("python");
expect(result.config.length).toBe(3);
expect(result.config[0].name).toBe("oss-subset");
expect(result.config[1].name).toBe("mongo");
expect(result.config[2].name).toBe("python");
});
it("should correctly calculate regularChunks for non-default spec pattern", () => {
@@ -84,7 +83,6 @@ describe("buildMatrix", () => {
it("should return special test configs when default spec pattern is provided", () => {
const result = testBuildMatrix("./e2e/test/scenarios/**/*.cy.spec.*", 50);
expect(result.config[46].name).toBe("embedding-sdk");
expect(result.config[47].name).toBe("oss-subset");
expect(result.config[48].name).toBe("mongo");
expect(result.config[49].name).toBe("python");

View File

@@ -48,13 +48,11 @@ jobs:
- name: Enterprise Tests
edition: ee
test-group-name: ee
build-static-viz: 'false'
test-args: >-
:only '"enterprise/backend/test"'
- name: EE App DB Tests (Part 1)
edition: ee
test-group-name: ee-app-db-1
build-static-viz: 'true'
test-args: >-
:only '["test" ".clj-kondo/test"]'
:partition/total 2
@@ -62,7 +60,6 @@ jobs:
- name: EE App DB Tests (Part 2)
edition: ee
test-group-name: ee-app-db-2
build-static-viz: 'true'
test-args: >-
:only '["test" ".clj-kondo/test"]'
:partition/total 2
@@ -70,7 +67,6 @@ jobs:
- name: OSS App DB Tests (Part 1)
edition: oss
test-group-name: oss-app-db-1
build-static-viz: 'true'
test-args: >-
:only '["test" ".clj-kondo/test"]'
:partition/total 2
@@ -78,7 +74,6 @@ jobs:
- name: OSS App DB Tests (Part 2)
edition: oss
test-group-name: oss-app-db-2
build-static-viz: 'true'
test-args: >-
:only '["test" ".clj-kondo/test"]'
:partition/total 2
@@ -103,25 +98,15 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
if: ${{ matrix.job.build-static-viz == 'true' }}
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
with:
java-version: "${{ matrix.java-version }}"
# Depending on which files changed, we might either have to build static-viz
# from scratch or download the previously built artifact
- name: Build static-viz frontend
if: ${{ matrix.job.build-static-viz == 'true' && !inputs.skip }}
run: yarn build-static-viz
env:
MB_EDITION: ${{ matrix.job.edition }}
- name: Download Static Viz Bundle Artifact
if: ${{ matrix.job.build-static-viz == 'true' && !inputs.skip }}
uses: actions/download-artifact@v4
with:
name: static-viz-bundle-${{ github.sha }}
path: resources/frontend_client/app/dist
- name: "Test Java ${{ matrix.java-version }} ${{ matrix.job.name }}"
id: run-java-tests
@@ -130,10 +115,9 @@ jobs:
:exclude-tags '[:mb/driver-tests ${{ env.__ADDITIONAL_EXCLUDED_TAG__ }}]'
${{ matrix.job.test-args }}
# 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.
# We only want to "continue on error" (ignore failures) when the Trunk upload is active - i.e. not on drafts!
continue-on-error: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true) }}
# 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.
continue-on-error: true
- name: Upload Test Results
uses: ./.github/actions/upload-test-results

View File

@@ -30,8 +30,8 @@ name: Cache Generator
on:
schedule:
- cron: '0 3 * * 1' # Mondays at 03:00 UTC
workflow_dispatch: # manually update the cache
- cron: "0 3 * * 1" # Mondays at 03:00 UTC
workflow_dispatch: # manually update the cache
concurrency:
group: cache-generator
@@ -48,6 +48,8 @@ jobs:
outputs:
m2-cache-key: ${{ steps.get-cache-keys.outputs.m2-cache-key }}
node-cache-key: ${{ steps.get-cache-keys.outputs.node-cache-key }}
eslint-cache-key: ${{ steps.get-cache-keys.outputs.eslint-cache-key }}
cypress-cache-key: ${{ steps.get-cache-keys.outputs.cypress-cache-key }}
generate-m2-cache:
runs-on: ubuntu-22.04
@@ -62,7 +64,7 @@ jobs:
# Add or remove aliases to affect the cache size and its contents.
# Adjust to taste, then redeploy this workflow.
- name: Pre-resolve dependencies
- name: Pre-resolve Clojure dependencies
run: clojure -A:build:dev:ee:ee-dev:drivers:drivers-dev:cljs -P
- name: Update M2 cache
@@ -73,12 +75,14 @@ jobs:
~/.gitlibs
key: ${{ env.M2_CACHE_KEY }}
generate-node-modules-cache:
generate-frontend-caches:
runs-on: ubuntu-22.04
timeout-minutes: 15
needs: get-cache-keys
env:
NODE_CACHE_KEY: ${{ needs.get-cache-keys.outputs.node-cache-key }}
ESLINT_CACHE_KEY: ${{ needs.get-cache-keys.outputs.eslint-cache-key }}
CYPRESS_CACHE_KEY: ${{ needs.get-cache-keys.outputs.cypress-cache-key }}
steps:
- uses: actions/checkout@v4
# `prepare-frontend` action (1) prepares Node.js and (2) fetches the node_modules cache if it exists.
@@ -90,10 +94,39 @@ jobs:
- name: Install front-end dependencies
uses: ./.github/actions/prepare-frontend
with:
apply-patches: 'false'
apply-patches: "false"
- name: Get yarn cache directory
id: yarn-cache-dir
run: |
YARN_CACHE_DIR=$(yarn cache dir)
echo "Yarn cache directory: $YARN_CACHE_DIR"
echo "dir=$YARN_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
shell: bash
- name: Update node_modules cache
uses: ./.github/actions/update-cache
with:
path: node_modules
path: |
${{ steps.yarn-cache-dir.outputs.dir }}
node_modules
key: ${{ env.NODE_CACHE_KEY }}
- name: Update eslint cache
uses: ./.github/actions/update-cache
with:
path: ${{ github.workspace}}/.eslintcache
key: ${{ env.ESLINT_CACHE_KEY }}
- name: Update Cypress cache
uses: ./.github/actions/update-cache
with:
path: ~/.cache/Cypress
key: ${{ env.CYPRESS_CACHE_KEY }}

View File

@@ -30,9 +30,10 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v4
with:
languages: javascript
config-file: ./.github/codeql/codeql-config.yml
trap-caching: false
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v4

19
.github/workflows/codespell.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Codespell
on:
push:
branches:
- 'master'
- 'release-**'
pull_request:
jobs:
codespell:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: codespell-project/actions-codespell@v1
with:
# keep this list in sync with the list in `mage/src/mage/codespell.yml`
path: >-
docs

View File

@@ -85,6 +85,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Athena driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-athena-ee'
@@ -93,7 +94,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -144,9 +145,10 @@ jobs:
with:
junit-name: 'be-tests-bigquery-cloud-sdk-ee'
test-args: ${{ matrix.job.test-args }}
logs-artifact-suffix: ${{ matrix.job.name }}
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -214,9 +216,10 @@ jobs:
with:
junit-name: 'be-tests-clickhouse-ee'
test-args: ${{ matrix.job.test-args }}
logs-artifact-suffix: ${{ matrix.job.name }}
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -251,6 +254,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Druid driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-druid-ee'
@@ -259,7 +263,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -288,6 +292,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Druid JDBC driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-druid-jdbc-ee'
@@ -296,7 +301,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -325,6 +330,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Databricks driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-databricks-ee'
@@ -333,7 +339,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -363,6 +369,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Databricks driver with multi-catalog
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-databricks-multi-catalog-ee'
@@ -371,7 +378,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -390,10 +397,6 @@ jobs:
name: H2
steps:
- uses: actions/checkout@v4
- name: Setup python-runner
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test H2 driver
id: test-driver
uses: ./.github/actions/test-driver
@@ -404,7 +407,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -413,12 +416,6 @@ jobs:
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: ${{ matrix.job.name }} ${{ matrix.version.name }}
be-tests-mysql-mariadb:
if: ${{ !inputs.skip }}
@@ -521,12 +518,13 @@ jobs:
uses: ./.github/actions/test-driver
with:
junit-name: ${{ matrix.version.junit-name }}
logs-artifact-suffix: ${{ matrix.version.name }}
test-args: >-
${{ matrix.job.test-args }}
:exclude-tags '[ ${{ matrix.job.exclude-tag }} ${{ env.__ADDITIONAL_EXCLUDED_TAG__ }}]'
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -593,9 +591,10 @@ jobs:
with:
junit-name: ${{ matrix.version.junit-name }}
test-args: ${{ matrix.job.test-args }}
logs-artifact-suffix: ${{ matrix.job.name }}
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -658,6 +657,7 @@ jobs:
curl https://raw.githubusercontent.com/metabase/metabase-qa/master/dbs/mongo/certificates/metaca.crt \
-o ./test_resources/ssl/mongo/metaca.crt
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: ${{ matrix.version.junit-name }}
@@ -666,7 +666,7 @@ jobs:
:only-tags [:mb/driver-tests]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -693,6 +693,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test MongoDB driver (Sharded cluster)
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-mongo-sharded-cluster-ee'
@@ -700,7 +701,7 @@ jobs:
:only metabase.driver.mongo.sharded-cluster-test
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -765,15 +766,17 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test ${{ matrix.version.name }}
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: ${{ matrix.version.junit-name }}
logs-artifact-suffix: ${{ matrix.version.name }}
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()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -866,7 +869,7 @@ jobs:
:exclude-tags '[ ${{ matrix.job.exclude-tag }} ${{ env.__ADDITIONAL_EXCLUDED_TAG__ }}]'
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -934,6 +937,7 @@ jobs:
-file /tmp/presto-ssl-ca.der
-trustcacerts
- name: Test Presto JDBC driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-presto-jdbc-ee'
@@ -942,7 +946,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -965,12 +969,22 @@ jobs:
test-args: >-
:only-tags [:mb/upload-tests]
:fail-fast? true
- name: Redshift (Excluding Upload Tests)
- name: Redshift (Excluding Upload Tests) Part 1
skip: false
test-args: >-
:only-tags [:mb/driver-tests]
:exclude-tags '[:mb/upload-tests :mb/transforms-python-test]'
:fail-fast? true
:partition/total 2
:partition/index 0
- name: Redshift (Excluding Upload Tests) Part 2
skip: false
test-args: >-
:only-tags [:mb/driver-tests]
:exclude-tags '[:mb/upload-tests :mb/transforms-python-test]'
:fail-fast? true
:partition/total 2
:partition/index 1
- name: Redshift Transforms Python Tests
skip: false
test-args: >-
@@ -1002,9 +1016,10 @@ jobs:
junit-name: 'be-tests-redshift-ee'
test-args: >-
${{ matrix.job.test-args }}
logs-artifact-suffix: ${{ matrix.job.name }}
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: ${{ !matrix.job.skip && !cancelled() }}
if: ${{ !matrix.job.skip && !cancelled() && steps.test-driver.outputs.quarantine-skipped != 'true' }}
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -1020,75 +1035,75 @@ jobs:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: ${{ matrix.job.name }} ${{ matrix.version.name }}
# dan sutton 2025-10-23: disable snowflake because of account
# issues. https://linear.app/metabase/issue/DEV-997/reenable-snowflake-in-ci. Note that the transforms tests were
# disabled previously
# be-tests-snowflake-ee:
# if: ${{ !inputs.skip }}
# runs-on: ubuntu-22.04
# timeout-minutes: 60
# strategy:
# fail-fast: false
# matrix:
# job:
# - name: Driver Tests
# test-args: >-
# :only-tags [:mb/driver-tests]
# :exclude-tags [:mb/transforms-python-test]
be-tests-snowflake-ee:
runs-on: ubuntu-22.04
needs: determine-driver-skips
if: ${{ !inputs.skip && !(needs.determine-driver-skips.outputs.skip == 'true') }}
timeout-minutes: 60
strategy:
fail-fast: false
matrix:
job:
- name: Driver Tests
test-args: >-
:only-tags [:mb/driver-tests]
:exclude-tags [:mb/transforms-python-test]
# DS 2025-09-26 temporarily disabled while we diagnose flakes
# - name: Transforms Python Tests
# test-args: >-
# :only-tags [:mb/transforms-python-test]
# needs-python-runner: true
# 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_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 }}
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 }}
# # RSA Role testing:
# 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 ${{ matrix.job.name }}
# steps:
# - uses: actions/checkout@v4
# - name: Setup python-runner
# if: ${{ matrix.job.needs-python-runner == true }}
# uses: ./.github/actions/setup-python-runner
# with:
# metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
# - name: Test Snowflake driver
# id: test-driver
# uses: ./.github/actions/test-driver
# with:
# junit-name: 'be-tests-snowflake-ee'
# test-args: ${{ matrix.job.test-args }}
# - 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() && matrix.job.needs-python-runner == true }}
# uses: ./.github/actions/cleanup-python-runner
# with:
# upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
# logs-artifact-suffix: ${{ matrix.job.name }} ${{ matrix.version.name }}
# RSA Role testing:
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 ${{ matrix.job.name }}
steps:
- uses: actions/checkout@v4
- name: Setup python-runner
if: ${{ matrix.job.needs-python-runner == true }}
uses: ./.github/actions/setup-python-runner
with:
metabase-automation-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Test Snowflake driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-snowflake-ee'
test-args: ${{ matrix.job.test-args }}
logs-artifact-suffix: ${{ matrix.job.name }}
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
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() && matrix.job.needs-python-runner == true }}
uses: ./.github/actions/cleanup-python-runner
with:
upload-logs: ${{ steps.test-driver.outcome == 'failure' }}
logs-artifact-suffix: ${{ matrix.job.name }} ${{ matrix.version.name }}
be-tests-sparksql-ee:
needs: determine-driver-skips
@@ -1107,6 +1122,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test Spark driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-sparksql-ee'
@@ -1115,7 +1131,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -1137,6 +1153,7 @@ jobs:
steps:
- uses: actions/checkout@v4
- name: Test SQLite driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-sqlite-ee'
@@ -1145,7 +1162,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -1208,9 +1225,10 @@ jobs:
with:
junit-name: ${{ matrix.version.junit-name }}
test-args: ${{ matrix.job.test-args }}
logs-artifact-suffix: ${{ matrix.version.name }}
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -1317,6 +1335,7 @@ jobs:
- name: Make plugins directory
run: mkdir plugins
- name: Test Vertica driver
id: test-driver
uses: ./.github/actions/test-driver
with:
junit-name: 'be-tests-vertica-ee'
@@ -1325,7 +1344,7 @@ jobs:
:exclude-tags [:mb/transforms-python-test]
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
if: always() && steps.test-driver.outputs.quarantine-skipped != 'true'
with:
input-path: ./target/junit/
output-name: ${{ github.job }}
@@ -1352,8 +1371,7 @@ jobs:
- be-tests-postgres
- be-tests-presto-jdbc-ee
- be-tests-redshift-ee
# dan: disabled for account reasons. https://linear.app/metabase/issue/DEV-997/reenable-snowflake-in-ci
# - be-tests-snowflake-ee
- be-tests-snowflake-ee
- be-tests-sparksql-ee
- be-tests-sqlite-ee
- be-tests-sqlserver

View File

@@ -1,185 +0,0 @@
# This workflow does the backward compatibility tests
# between the Embedding SDK package of version N and Embedding SDK Bundle of version N - 1
# N - 1 is a target of a PR
name: Embedding SDK backward-compatibility E2E Component Tests
on:
workflow_call:
inputs:
cached-embedding-sdk-dist-artifact-name:
required: true
type: string
jobs:
files-changed:
name: "SDK backward-compatibility E2E > Check which files changed"
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
e2e_embedding_sdk: ${{ steps.changes.outputs.e2e_embedding_sdk }}
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
decide-target-ref:
runs-on: ubuntu-latest
outputs:
target-ref: ${{ steps.get-target-ref.outputs.value }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Decide ref to checkout
id: get-target-ref
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "value=${{ github.base_ref }}" >> "$GITHUB_OUTPUT"
else
echo "value=$(git rev-parse HEAD^1)" >> "$GITHUB_OUTPUT"
fi
# if this is a test on a release branch, we need to check the build requirements
get-build-requirements:
name: "SDK backward-compatibility E2E > [Backport only] Get build requirements"
needs: [decide-target-ref]
if: |
!cancelled() &&
contains(github.base_ref || github.ref, 'release-x')
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
java_version: ${{ fromJson(steps.dependencies.outputs.result).java_version }}
node_version: ${{ fromJson(steps.dependencies.outputs.result).node_version }}
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.decide-target-ref.outputs.target-ref }}
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
- name: Get build dependencies
uses: actions/github-script@v7
id: dependencies
with:
script: | # js
const {
getBuildRequirements,
getVersionFromReleaseBranch,
} = require('${{ github.workspace }}/release/dist/index.cjs');
const targetBranchName = '${{ github.base_ref || github.ref }}';
const version = getVersionFromReleaseBranch(targetBranchName);
const requirements = getBuildRequirements(version);
return {
java_version: requirements.java,
node_version: requirements.node,
};
e2e-tests:
name: "SDK backward-compatibility E2E > Run e2e tests"
needs: [files-changed, decide-target-ref, get-build-requirements]
if: |
!cancelled() &&
needs.files-changed.outputs.e2e_embedding_sdk == 'true'
runs-on: ubuntu-22.04
timeout-minutes: 45
env:
MB_EDITION: ee
DISPLAY: ""
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")`
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 }}
CYPRESS_MB_PRO_SELF_HOSTED_TOKEN: ${{ secrets.STAGING_MB_PRO_SELF_HOSTED_TOKEN }}
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message || github.event.head.sha }}
TZ: US/Pacific # to make node match the instance tz
CYPRESS_CI: true
steps:
- uses: actions/checkout@v4
with:
ref: ${{ needs.decide-target-ref.outputs.target-ref }}
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
with:
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
with:
node-version: "${{ needs.get-build-requirements.outputs.node_version }}"
- name: Build uberjar with ./bin/build.sh
run: ./bin/build.sh
- name: Retrieve Embedding SDK dist artifact
uses: actions/download-artifact@v4
with:
name: ${{ inputs.cached-embedding-sdk-dist-artifact-name }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Run Metabase
run: node e2e/runner/run_cypress_ci.js start
- name: Make app db snapshot
run: node e2e/runner/run_cypress_ci.js snapshot --browser ${{ steps.cypress-prep.outputs.chrome-path }}
- name: Run component tests for Embedding SDK
run: |
node e2e/runner/run_cypress_ci.js component \
--browser ${{ steps.cypress-prep.outputs.chrome-path }} \
--env grepTags="-@skip-backward-compatibility",grepOmitFiltered=true
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit
output-name: e2e-embedding-sdk
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: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-embedding-sdk-cross-version
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: Publish Summary
if: failure()
uses: actions/github-script@v7
with:
script: | #js
const {
generateReport,
parseReport,
formatSummary
} = require("./.github/scripts/handle-mochawesome-report.js");
const report = await generateReport();
const results = parseReport(report);
const summary = formatSummary(results);
await core.summary.addRaw(summary).write();

View File

@@ -1,204 +0,0 @@
name: E2E Component Tests for Embedding SDK
on:
workflow_call:
inputs:
cached-embedding-sdk-dist-artifact-name:
required: true
type: string
jobs:
files-changed:
name: "SDK e2e > Check which files changed"
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
e2e_embedding_sdk: ${{ steps.changes.outputs.e2e_embedding_sdk }}
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
# if this is a test on a release branch, we need to check the build requirements
get-build-requirements:
name: "SDK e2e > [Backport only] Get build requirements"
if: |
!cancelled() &&
contains(github.base_ref || github.ref, 'release-x')
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
java_version: ${{ fromJson(steps.dependencies.outputs.result).java_version }}
node_version: ${{ fromJson(steps.dependencies.outputs.result).node_version }}
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
- name: Get build dependencies
uses: actions/github-script@v7
id: dependencies
with:
script: | # js
const {
getBuildRequirements,
getVersionFromReleaseBranch,
} = require('${{ github.workspace }}/release/dist/index.cjs');
const targetBranchName = '${{ github.base_ref || github.ref }}';
const version = getVersionFromReleaseBranch(targetBranchName);
const requirements = getBuildRequirements(version);
return {
java_version: requirements.java,
node_version: requirements.node,
};
build-uberjar:
name: "SDK e2e > Build uberjar"
needs: [files-changed, get-build-requirements]
if: |
!cancelled() &&
needs.files-changed.outputs.e2e_embedding_sdk == 'true'
runs-on: ubuntu-22.04
timeout-minutes: 25
env:
MB_EDITION: ee
INTERACTIVE: false
# make sure that builds on release branches get licenses, because we use them for releases
SKIP_LICENSES: ${{ github.event_name == 'pull_request' }}
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
with:
node-version: "${{ needs.get-build-requirements.outputs.node_version }}"
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
with:
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
- name: Build uberjar with ./bin/build.sh
run: ./bin/build.sh
- name: Prepare uberjar artifact
uses: ./.github/actions/prepare-uberjar-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar-sdk-tests
e2e-tests:
name: "SDK e2e > Run e2e tests (React ${{ matrix.react-version }})"
needs: [get-build-requirements, build-uberjar]
if: |
!cancelled() &&
needs.build-uberjar.result == 'success'
runs-on: ubuntu-22.04
timeout-minutes: 45
strategy:
matrix:
react-version: [18, 19]
fail-fast: false
env:
MB_EDITION: ee
DISPLAY: ""
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")`
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 }}
CYPRESS_MB_PRO_SELF_HOSTED_TOKEN: ${{ secrets.STAGING_MB_PRO_SELF_HOSTED_TOKEN }}
CYPRESS_IS_EMBEDDING_SDK: "true"
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message || github.event.head.sha }}
TZ: US/Pacific # to make node match the instance tz
CYPRESS_CI: true
steps:
- uses: actions/checkout@v4
- name: Retrieve uberjar artifact for ee
uses: actions/download-artifact@v4
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar-sdk-tests
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare JDK ${{ needs.get-build-requirements.outputs.java_version || 21 }}
uses: actions/setup-java@v4
with:
java-version: ${{ needs.get-build-requirements.outputs.java_version || 21 }}
distribution: "temurin"
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Retrieve Embedding SDK dist artifact
uses: actions/download-artifact@v4
with:
name: ${{ inputs.cached-embedding-sdk-dist-artifact-name }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Run Metabase
run: node e2e/runner/run_cypress_ci.js start
- name: Make app db snapshot
run: node e2e/runner/run_cypress_ci.js snapshot --browser ${{ steps.cypress-prep.outputs.chrome-path }}
# Has to be run after the app db snapshot is made, as it is not compatible with React 19
- name: Change React version to ${{ matrix.react-version }}
run: ./bin/embedding-sdk/change-react-version.bash ${{ matrix.react-version }}
- name: Run component tests for Embedding SDK
run: node e2e/runner/run_cypress_ci.js component --browser ${{ steps.cypress-prep.outputs.chrome-path }}
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit
output-name: e2e-embedding-sdk-react-${{ matrix.react-version }}
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: "SDK e2e > Upload Cypress Artifacts upon failure"
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-embedding-sdk-react-${{ matrix.react-version }}
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: "SDK e2e > Publish Summary"
if: failure()
uses: actions/github-script@v7
with:
script: | #js
const {
generateReport,
parseReport,
formatSummary
} = require("./.github/scripts/handle-mochawesome-report.js");
const report = await generateReport();
const results = parseReport(report);
const summary = formatSummary(results);
await core.summary.addRaw(summary).write();

View File

@@ -1,175 +0,0 @@
name: E2E Cross-version Tests
on:
schedule:
- cron: '0 9 * * 1-5'
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
jobs:
files-changed:
name: Check which files changed
# don't run this workflow on a cron for forks
if: ${{ github.event_name != 'schedule' || github.repository == 'metabase/metabase' }}
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
e2e_cross_version: ${{ steps.changes.outputs.e2e_cross_version }}
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
cross-version-testing:
needs: files-changed
if: ${{ needs.files-changed.outputs.e2e_cross_version == 'true' || github.event_name == 'schedule'}}
runs-on: ubuntu-22.04
timeout-minutes: 20
strategy:
matrix:
version: [
# Major OSS upgrade
{ source: v0.42.2, target: v0.48.7 },
# OSS upgrade
{ source: v0.41.3.1, target: v0.42.2 },
# EE upgrade
{ source: v1.43.4, target: v1.44.0 },
# EE downgrade
{ source: v1.42.0, target: v1.41.3.1 },
# Cross-edition upgrade
{ source: v0.41.3.1, target: v1.42.2 }
]
fail-fast: false
env:
CROSS_VERSION_SOURCE: ${{ matrix.version.source }}
CROSS_VERSION_TARGET: ${{ matrix.version.target }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set source Docker image to OSS
run: |
echo "DOCKER_SOURCE_IMAGE=metabase/metabase:${{ matrix.version.source }}" >> $GITHUB_ENV
if: startsWith(matrix.version.source, 'v0')
- name: Set source Docker image to EE
run: |
echo "DOCKER_SOURCE_IMAGE=metabase/metabase-enterprise:${{ matrix.version.source }}" >> $GITHUB_ENV
if: startsWith(matrix.version.source, 'v1')
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Start Metabase ${{ matrix.version.source }}
run: |
docker run -d \
-v $PWD/my-metabase:/metabase.db \
-p 3000:3000 \
-e MB_RUN_MODE=e2e \
-e METASTORE_DEV_SERVER_URL=${{ secrets.METASTORE_DEV_SERVER_URL }} \
-e CYPRESS_MB_ALL_FEATURES_TOKEN=${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }} \
-e CYPRESS_MB_STARTER_CLOUD_TOKEN=${{ secrets.STAGING_MB_STARTER_CLOUD_TOKEN }} \
-e CYPRESS_MB_PRO_CLOUD_TOKEN=${{ secrets.STAGING_MB_PRO_CLOUD_TOKEN }} \
-e CYPRESS_MB_PRO_SELF_HOSTED_TOKEN=${{ secrets.STAGING_MB_PRO_SELF_HOSTED_TOKEN }} \
--name metabase-${{ matrix.version.source }} \
${{ env.DOCKER_SOURCE_IMAGE }}
- name: Wait for Metabase to start on port 3000
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Run Cypress on the source
run: |
yarn cypress run \
--browser ${{ steps.cypress-prep.outputs.chrome-path }} \
--config-file e2e/test/scenarios/cross-version/source/shared/cross-version-source.config.js \
--spec e2e/test/scenarios/cross-version/source/**/*.cy.spec.js
- name: Stop Metabase ${{ matrix.version.source }}
run: docker stop metabase-${{ matrix.version.source }}
- name: Set target Docker image to OSS
run: |
echo "DOCKER_TARGET_IMAGE=metabase/metabase:${{ matrix.version.source }}" >> $GITHUB_ENV
if: startsWith(matrix.version.source, 'v0')
- name: Set target Docker image to EE
run: |
echo "DOCKER_TARGET_IMAGE=metabase/metabase-enterprise:${{ matrix.version.source }}" >> $GITHUB_ENV
if: startsWith(matrix.version.source, 'v1')
- name: Start Metabase ${{ matrix.version.target }}
run: |
docker run -d \
-v $PWD/my-metabase:/metabase.db \
-p 3001:3000 \
-e MB_RUN_MODE=e2e \
-e METASTORE_DEV_SERVER_URL=${{ secrets.METASTORE_DEV_SERVER_URL }} \
-e CYPRESS_MB_ALL_FEATURES_TOKEN=${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }} \
-e CYPRESS_MB_STARTER_CLOUD_TOKEN=${{ secrets.STAGING_MB_STARTER_CLOUD_TOKEN }} \
-e CYPRESS_MB_PRO_CLOUD_TOKEN=${{ secrets.STAGING_MB_PRO_CLOUD_TOKEN }} \
-e CYPRESS_MB_PRO_SELF_HOSTED_TOKEN=${{ secrets.STAGING_MB_PRO_SELF_HOSTED_TOKEN }} \
--name metabase-${{ matrix.version.target }} \
${{ env.DOCKER_TARGET_IMAGE }}
- name: Wait for Metabase to start on port 3001
run: while ! curl -s 'http://localhost:3001/api/health' | grep '{"status":"ok"}'; do sleep 1; done
- name: Run Cypress on the target
run: |
yarn cypress run \
--browser ${{ steps.cypress-prep.outputs.chrome-path }} \
--config-file e2e/test/scenarios/cross-version/target/shared/cross-version-target.config.js \
--spec e2e/test/scenarios/cross-version/target/**/*.cy.spec.js
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-artifacts-${{ matrix.version.source}}-to-${{ matrix.version.target }}
path: |
./cypress
if-no-files-found: ignore
notify-on-failure:
needs: cross-version-testing
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }}
name: Cross-version test failure
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
- uses: actions/setup-node@v4
with:
node-version: lts/Jod # 22.x.x
- run: npm install @slack/web-api
- name: notify slack of failure
uses: actions/github-script@v7
with:
script: | # js
const FAILED_RUN_URL = "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}";
const REF_NAME = "${{ github.ref_name }}";
// notify slack of failure
const { WebClient } = require('@slack/web-api');
const slack = new WebClient('${{ secrets.SLACK_BOT_TOKEN }}');
await slack.chat.postMessage({
channel: 'engineering-ci',
text: 'Cross-version Tests Have Failed',
blocks: [
{
"type": "header",
"text": {
"type": "plain_text",
"text": `:broken_heart: Cross-version tests are failing on ${REF_NAME}`,
"emoji": true,
}
},
],
attachments: [{
color: "#BF40BF",
blocks: [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": `See <${FAILED_RUN_URL}|failing run details>.`
}
},
]
}]
});

View File

@@ -37,8 +37,26 @@ on:
default: true
jobs:
determine-test-type:
name: Determine test type
runs-on: ubuntu-22.04
timeout-minutes: 5
outputs:
type: ${{ steps.detect.outputs.type }}
steps:
- name: Detect test type from spec path
id: detect
run: |
SPEC='${{ inputs.spec }}'
if [[ "$SPEC" == e2e/test-component/scenarios/embedding-sdk/* ]]; then
echo "type=component" >> $GITHUB_OUTPUT
else
echo "type=e2e" >> $GITHUB_OUTPUT
fi
workflow-summary:
name: Stress test inputs
needs: [determine-test-type]
runs-on: ubuntu-22.04
timeout-minutes: 5
steps:
@@ -48,6 +66,7 @@ jobs:
echo '' >> $GITHUB_STEP_SUMMARY
echo '- `branch`: ${{ github.ref_name }}' >> $GITHUB_STEP_SUMMARY
echo '- `spec`: ${{ inputs.spec }}' >> $GITHUB_STEP_SUMMARY
echo '- `test_type` (inferred): ${{ needs.determine-test-type.outputs.type }}' >> $GITHUB_STEP_SUMMARY
echo '- `burn_in`: ${{ inputs.burn_in }}' >> $GITHUB_STEP_SUMMARY
echo '- `grep`: "${{ inputs.grep }}"' >> $GITHUB_STEP_SUMMARY
echo '- `qa_db`: "${{ inputs.qa_db }}"' >> $GITHUB_STEP_SUMMARY
@@ -56,6 +75,7 @@ jobs:
echo 'triggered by: @${{ github.event.sender.login }}' >> $GITHUB_STEP_SUMMARY
stress-test-flake-fix:
needs: [determine-test-type]
runs-on: ubuntu-22.04
timeout-minutes: 60
name: Stress test E2E flake fix
@@ -100,6 +120,16 @@ jobs:
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
if: ${{ needs.determine-test-type.outputs.type == 'component' }}
uses: ./.github/actions/prepare-backend
with:
m2-cache-key: "cljs"
- name: Build Embedding SDK package
if: ${{ needs.determine-test-type.outputs.type == 'component' }}
run: yarn build-embedding-sdk-package
- name: Prepare JDK 21
uses: actions/setup-java@v4
with:
@@ -118,12 +148,12 @@ jobs:
- name: Stress-test ${{ github.event.inputs.spec }} ${{ github.event.inputs.burn_in }} times
env:
GREP: ${{ github.event.inputs.grep }}
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: |
node e2e/runner/run_cypress_ci.js e2e \
node e2e/runner/run_cypress_ci.js ${{ needs.determine-test-type.outputs.type }} \
--spec '${{ github.event.inputs.spec }}' \
--env burn=${{ github.event.inputs.burn_in }} \
--config-file e2e/support/cypress-stress-test.config.js \
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
--config-file e2e/support/cypress-stress-test.config.js
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4

View File

@@ -59,7 +59,6 @@ jobs:
TZ: US/Pacific # to make node match the instance tz
CYPRESS_CI: true
CYPRESS_QA_DB_MONGO: ${{ inputs.name == 'mongo' }}
CYPRESS_IS_EMBEDDING_SDK: "${{ inputs.name == 'embedding-sdk' }}"
steps:
- uses: actions/checkout@v4
with:
@@ -85,10 +84,6 @@ jobs:
mysql: ${{ inputs.name != 'mongo' }}
mongo: ${{ inputs.name == 'mongo' }}
- name: Run Embedding SDK Storybook
if: inputs.name == 'embedding-sdk'
uses: ./.github/actions/run-embedding-sdk-storybook
- name: Retrieve uberjar artifact for ${{ inputs.edition }}
uses: ./.github/actions/fetch-artifact
with:
@@ -125,9 +120,12 @@ jobs:
run: node e2e/runner/run_cypress_ci.js start
- name: Generate database snapshots
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js snapshot
- name: Run auto-split Cypress tests on ${{ inputs.name }}
id: split-e2e
if: ${{ !inputs.specs }}
env:
SPLIT: ${{ inputs.total_chunks }}
@@ -138,35 +136,34 @@ jobs:
# do not write cypress-split summary to github
SPLIT_SUMMARY: false
SPEC_PATH: ${{ env.specs || inputs.specs }}
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
shell: bash
run: |
echo "Running tests with specs: $SPEC_PATH"
node e2e/runner/run_cypress_ci.js e2e \
--env grepTags="-@mongo+-@python+-@flaky+-@OSS+-@skip",grepOmitFiltered=true \
--spec "$SPEC_PATH" \
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
--env grepTags="-@mongo+-@python+-@OSS+-@skip" \
--spec "$SPEC_PATH"
# 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.
# We only want to "continue on error" (ignore failures) when the Trunk upload is active - i.e. not on drafts!
continue-on-error: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true) }}
# 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.
continue-on-error: true
- name: Run Tagged EE Cypress tests on ${{ inputs.name }}
id: tagged-e2e
if: ${{ inputs.specs }}
shell: bash
env:
SPEC_PATH: ${{ env.specs || inputs.specs }}
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: |
echo "Running tests with specs: $SPEC_PATH"
node e2e/runner/run_cypress_ci.js e2e \
--env grepTags="${{inputs.tags && format('{0}+-@skip', inputs.tags) || '-@skip'}}",grepOmitFiltered=true \
--spec "$SPEC_PATH" \
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
--env grepTags="${{inputs.tags && format('{0}+-@skip', inputs.tags) || '-@skip'}}" \
--spec "$SPEC_PATH"
# 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.
# We only want to "continue on error" (ignore failures) when the Trunk upload is active - i.e. not on drafts!
continue-on-error: ${{ !(github.event_name == 'pull_request' && github.event.pull_request.draft == true) }}
# 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.
continue-on-error: true
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
@@ -185,7 +182,8 @@ jobs:
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
if: |
!cancelled() && (steps.split-e2e.outcome == 'failure' || steps.tagged-e2e.outcome == 'failure')
with:
name: cypress-recording-${{ inputs.name }}-${{ inputs.edition }}
path: |
@@ -195,10 +193,12 @@ jobs:
- name: Upload Failed Tests
uses: actions/upload-artifact@v4
if: failure()
if: |
!cancelled() && (steps.split-e2e.outcome == 'failure' || steps.tagged-e2e.outcome == 'failure')
with:
name: failed-tests-${{ inputs.name }}-${{ inputs.edition }}
path: ./cypress/test-results
if-no-files-found: ignore
- name: Extract chunk-specific changed timings
id: extract-timings

View File

@@ -73,20 +73,6 @@ jobs:
tags: ${{ matrix.tags }}
runner: ${{ matrix.runner }}
# run this separately to make it non-blocking
flaky-e2e-tests:
name: Flaky e2e Tests
uses: ./.github/workflows/e2e-test.yml
needs:
- e2e-matrix-builder
# skip flaky test run if only e2e specs changed as an optimization
if: |
!cancelled() && !inputs.skip && needs.e2e-matrix-builder.outputs.isDefaultSpecPattern == 'true'
secrets: inherit
with:
name: Flaky
tags: "@flaky"
collect-timings:
name: Collect E2E Timings
runs-on: ubuntu-22.04
@@ -152,14 +138,12 @@ jobs:
e2e-tests-result:
needs:
- e2e-tests
- flaky-e2e-tests
runs-on: ubuntu-latest
timeout-minutes: 5
name: e2e-tests-result
if: always() && !cancelled()
env:
E2E_TESTS_RESULT: ${{ needs.e2e-tests.result }}
FLAKY_E2E_TESTS_RESULT: ${{ needs.flaky-e2e-tests.result }}
steps:
- name: Stub
if: ${{ needs.e2e-tests.result == 'skipped' }}
@@ -169,7 +153,6 @@ jobs:
if: ${{ needs.e2e-tests.result != 'skipped' }}
run: | # sh
echo "E2E Tests: ${{ needs.e2e-tests.result }}"
echo "Flaky E2E Tests: ${{ needs.flaky-e2e-tests.result }}"
if [ "${{ needs.e2e-tests.result }}" != "success" ]; then
echo "E2E Tests failed"

View File

@@ -0,0 +1,250 @@
name: Embedding SDK Component Tests
on:
workflow_call:
jobs:
sdk-component-tests:
name: "SDK component tests (React ${{ matrix.react-version }})"
runs-on: ubuntu-22.04
timeout-minutes: 45
strategy:
matrix:
react-version: [18, 19]
fail-fast: false
env:
MB_EDITION: ee
DISPLAY: ""
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")`
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 }}
CYPRESS_MB_PRO_SELF_HOSTED_TOKEN: ${{ secrets.STAGING_MB_PRO_SELF_HOSTED_TOKEN }}
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message || github.event.head.sha }}
TZ: US/Pacific # to make node match the instance tz
CYPRESS_CI: true
steps:
- uses: actions/checkout@v4
- name: Retrieve uberjar artifact for ee
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
extract-path: "target/uberjar"
output-name: "metabase.jar"
- name: Retrieve Embedding SDK dist artifact
uses: actions/download-artifact@v4
with:
name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Prepare JDK 21
uses: actions/setup-java@v4
with:
java-version: 21
distribution: "temurin"
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Run Metabase
run: node e2e/runner/run_cypress_ci.js start
- name: Make app db snapshot
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js snapshot
# Has to be run after the app db snapshot is made, as it is not compatible with React 19
- name: Change React version to ${{ matrix.react-version }}
run: ./bin/embedding-sdk/change-react-version.bash ${{ matrix.react-version }}
- name: Run component tests for Embedding SDK
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js component
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit
output-name: e2e-embedding-sdk-react-${{ matrix.react-version }}
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: "SDK component tests > Upload Cypress Artifacts upon failure"
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-embedding-sdk-react-${{ matrix.react-version }}
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: "SDK component tests > Publish Summary"
if: failure()
uses: actions/github-script@v7
with:
script: | #js
const {
generateReport,
parseReport,
formatSummary
} = require("./.github/scripts/handle-mochawesome-report.js");
const report = await generateReport();
const results = parseReport(report);
const summary = formatSummary(results);
await core.summary.addRaw(summary).write();
decide-target-ref:
runs-on: ubuntu-latest
outputs:
target-ref: ${{ steps.get-target-ref.outputs.value }}
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 2
- name: Decide ref to checkout
id: get-target-ref
run: |
if [[ "${{ github.event_name }}" == "pull_request" ]]; then
echo "value=${{ github.base_ref }}" >> "$GITHUB_OUTPUT"
else
echo "value=$(git rev-parse HEAD^1)" >> "$GITHUB_OUTPUT"
fi
# This job ensures that the Embedding SDK package from the current commit (N) works with the
# Embedding SDK Bundle (Metabase JAR) from the previous commit (N-1).
# N - 1 is a target of a pull request, or a literal previous commit when this job is run on push in a branch.
sdk-component-tests-backward-compatibility:
name: "SDK component tests (Backward compatibility)"
needs: [decide-target-ref]
runs-on: ubuntu-22.04
timeout-minutes: 45
env:
MB_EDITION: ee
DISPLAY: ""
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")`
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 }}
CYPRESS_MB_PRO_SELF_HOSTED_TOKEN: ${{ secrets.STAGING_MB_PRO_SELF_HOSTED_TOKEN }}
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message || github.event.head.sha }}
TZ: US/Pacific # to make node match the instance tz
CYPRESS_CI: true
steps:
- name: Check out the code from the previous commit
uses: actions/checkout@v4
with:
ref: ${{ needs.decide-target-ref.outputs.target-ref }}
- name: Get the actual commit SHA from the checked out branch
id: get-commit-sha
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
- name: Attempt to retrieve the ee uberjar artifact from the previous commit
id: download-uberjar
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ steps.get-commit-sha.outputs.sha }}-uberjar
extract-path: "target/uberjar"
output-name: "metabase.jar"
continue-on-error: true # do not break the whole job if this step doesn't succeed
# Build the uberjar from the previous commit only if we couldn't fetch it.
# `step.foo.OUTCOME` is important because it looks at the step status *before* continue-on-error is applied.
# Do not confuse it with the `step.foo.conclusion`.
- name: Build MB uberjar from the commit N-1
if: steps.download-uberjar.outcome != 'success'
run: ./bin/build.sh
- name: Retrieve Embedding SDK dist artifact built from the current commit N
uses: actions/download-artifact@v4
with:
name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
path: ${{ github.workspace }}/resources/embedding-sdk
- name: Prepare Cypress environment
id: cypress-prep
uses: ./.github/actions/prepare-cypress
- name: Run Metabase
run: node e2e/runner/run_cypress_ci.js start
- name: Make app db snapshot
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js snapshot
- name: Run component tests for Embedding SDK
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: |
node e2e/runner/run_cypress_ci.js component \
--env grepTags="-@skip-backward-compatibility"
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit
output-name: e2e-embedding-sdk
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: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
if: failure()
with:
name: cypress-recording-embedding-sdk-cross-version
path: |
./cypress
./logs/test.log
if-no-files-found: ignore
- name: Publish Summary
if: failure()
uses: actions/github-script@v7
with:
script: | #js
const {
generateReport,
parseReport,
formatSummary
} = require("./.github/scripts/handle-mochawesome-report.js");
const report = await generateReport();
const results = parseReport(report);
const summary = formatSummary(results);
await core.summary.addRaw(summary).write();

View File

@@ -1,78 +1,14 @@
name: "[NOT REQUIRED] SDK Compatibility tests"
on:
push:
branches:
- "master"
- "release-**"
pull_request:
types: [opened, synchronize, reopened]
branches:
- "master"
- "release-**"
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
workflow_call:
jobs:
files-changed:
name: Check which files changed
runs-on: ubuntu-22.04
timeout-minutes: 3
outputs:
e2e_embedding_sdk_compatibility: ${{ steps.changes.outputs.e2e_embedding_sdk_compatibility }}
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
# if this is a test on a release branch, we need to check the build requirements
get-build-requirements:
if: |
!cancelled() &&
contains(github.base_ref || github.ref, 'release-x')
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
java_version: ${{ fromJson(steps.dependencies.outputs.result).java_version }}
node_version: ${{ fromJson(steps.dependencies.outputs.result).node_version }}
steps:
- uses: actions/checkout@v4
with:
sparse-checkout: release
- name: Prepare build scripts
run: cd ${{ github.workspace }}/release && yarn && yarn build
- name: Get build dependencies
uses: actions/github-script@v7
id: dependencies
with:
script: | # js
const {
getBuildRequirements,
getVersionFromReleaseBranch,
} = require('${{ github.workspace }}/release/dist/index.cjs');
const targetBranchName = '${{ github.base_ref || github.ref }}';
const version = getVersionFromReleaseBranch(targetBranchName);
const requirements = getBuildRequirements(version);
return {
java_version: requirements.java,
node_version: requirements.node,
};
get-sample-apps-data:
if: |
!cancelled()
runs-on: ubuntu-22.04
timeout-minutes: 10
env:
# we must support last two stable releases
# we must support the last two stable releases
SUPPORTED_RELEASES_COUNT: 2
TEST_SUITES: |
[
@@ -145,51 +81,6 @@ jobs:
matrix: []
};
build:
needs: [files-changed, get-build-requirements, get-sample-apps-data]
if: |
!cancelled() &&
needs.files-changed.outputs.e2e_embedding_sdk_compatibility == 'true' &&
fromJSON(needs.get-sample-apps-data.outputs.matrix)[0] != null
runs-on: ubuntu-22.04
timeout-minutes: 25
env:
MB_EDITION: ee
INTERACTIVE: false
# make sure that builds on release branches get licenses, because we use them for releases
SKIP_LICENSES: ${{ github.event_name == 'pull_request' }}
steps:
- uses: actions/checkout@v4
- name: Prepare front-end environment
uses: ./.github/actions/prepare-frontend
with:
node-version: "${{ needs.get-build-requirements.outputs.node_version }}"
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
with:
java-version: "${{ needs.get-build-requirements.outputs.java_version || 21 }}"
- name: Build uberjar with ./bin/build.sh
run: ./bin/build.sh
- name: Prepare uberjar artifact
uses: ./.github/actions/prepare-uberjar-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
- name: Build Embedding SDK package
run: |
# 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
- name: Prepare Embedding SDK artifact
uses: actions/upload-artifact@v4
with:
name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
path: resources/embedding-sdk
# In order to check compatibility between Sample Apps and Embedding SDK, the job for each sample app:
# - pulls a Sample App
# - starts it
@@ -197,13 +88,13 @@ jobs:
# The job is not required, though if it's failing better to be sure that it's not caused by a breaking change.
# For more details see `Sample Apps compatibility with Embedding SDK tests` in `enterprise/frontend/src/embedding-sdk-package/dev.md`
e2e-sample-apps-tests:
needs: [get-build-requirements, get-sample-apps-data, build]
needs: [get-sample-apps-data]
strategy:
matrix:
test_suite: ${{ fromJSON(needs.get-sample-apps-data.outputs.matrix) }}
environment: ["production", "development"]
if: |
!cancelled() && needs.build.result == 'success'
!cancelled() && needs.get-sample-apps-data.result == 'success'
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-sample-app-${{ matrix.test_suite }}-tests-${{ matrix.environment }}-bundle
@@ -216,7 +107,6 @@ jobs:
MB_RUN_MODE: e2e
METASTORE_DEV_SERVER_URL: ${{ secrets.METASTORE_DEV_SERVER_URL }}
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
CYPRESS_IS_EMBEDDING_SDK: "true"
TZ: US/Pacific # to make node match the instance tz
CYPRESS_CI: true
SAMPLE_APP_BRANCH_NAME: ${{ needs.get-sample-apps-data.outputs.branch_name }}
@@ -227,6 +117,8 @@ jobs:
steps:
- uses: actions/checkout@v4
- 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
@@ -241,9 +133,11 @@ jobs:
echo "sample_app_name=${test_suite%-e2e}" >> "$GITHUB_OUTPUT"
- name: Retrieve uberjar artifact for ee
uses: actions/download-artifact@v4
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
extract-path: "target/uberjar"
output-name: "metabase.jar"
- name: Retrieve Embedding SDK dist artifact
uses: actions/download-artifact@v4
@@ -295,11 +189,19 @@ jobs:
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' && matrix.test_suite != 'shoppy-e2e' }}
run: npx tsx ./e2e/runner/embedding-sdk/sample-apps/start-ci.ts ${{ matrix.test_suite }}
- name: Prune build cache
run: docker builder prune -af
- name: Log free disk space
run: df -h /
- name: Run e2e tests for Sample App
id: run-e2e-tests
if: ${{ steps.check-sample-app-branch.outputs.sample_app_branch_exists == 'true' }}
continue-on-error: true
run: node e2e/runner/run_cypress_ci.js ${{ matrix.test_suite }} --browser ${{ steps.cypress-prep.outputs.chrome-path }}
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js ${{ matrix.test_suite }}
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4
@@ -323,7 +225,6 @@ jobs:
# The job is not required, though if it's failing better to be sure that it's not caused by a breaking change.
# For more details see `Embedding SDK integration tests with Host Apps` in `enterprise/frontend/src/embedding-sdk-package/dev.md`
e2e-host-apps-tests:
needs: [get-build-requirements, build]
strategy:
matrix:
test_suite:
@@ -334,8 +235,6 @@ jobs:
"angular-20-host-app-e2e",
]
environment: ["production", "development"]
if: |
!cancelled() && needs.build.result == 'success'
runs-on: ubuntu-22.04
timeout-minutes: 45
name: e2e-host-app-${{ matrix.test_suite }}-tests-${{ matrix.environment }}-bundle
@@ -348,7 +247,6 @@ jobs:
MB_RUN_MODE: e2e
METASTORE_DEV_SERVER_URL: ${{ secrets.METASTORE_DEV_SERVER_URL }}
CYPRESS_MB_ALL_FEATURES_TOKEN: ${{ secrets.STAGING_MB_ALL_FEATURES_TOKEN }}
CYPRESS_IS_EMBEDDING_SDK: "true"
TZ: US/Pacific # to make node match the instance tz
CYPRESS_CI: true
HOST_APP_ENVIRONMENT: ${{ matrix.environment }}
@@ -359,9 +257,11 @@ jobs:
- uses: actions/checkout@v4
- name: Retrieve uberjar artifact for ee
uses: actions/download-artifact@v4
uses: ./.github/actions/fetch-artifact
with:
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
extract-path: "target/uberjar"
output-name: "metabase.jar"
- name: Retrieve Embedding SDK dist artifact
uses: actions/download-artifact@v4
@@ -394,7 +294,9 @@ jobs:
- name: Run e2e tests for Host App
id: run-e2e-tests
continue-on-error: true
run: node e2e/runner/run_cypress_ci.js ${{ matrix.test_suite }} --browser ${{ steps.cypress-prep.outputs.chrome-path }}
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: node e2e/runner/run_cypress_ci.js ${{ matrix.test_suite }}
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4

View File

@@ -0,0 +1,31 @@
name: Embedding SDK Package Build
on:
workflow_call:
workflow_dispatch:
concurrency:
group: embedding-sdk-package-${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
jobs:
build-sdk-package:
runs-on: ubuntu-22.04
timeout-minutes: 25
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: Build Embedding SDK package
run: |
# 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
- name: Prepare Embedding SDK artifact
uses: actions/upload-artifact@v4
with:
name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
path: resources/embedding-sdk

View File

@@ -2,61 +2,39 @@ name: SDK
on:
workflow_call:
inputs:
cli-snippets-type-check:
description: "Whether to run cli snippets type check."
required: true
type: boolean
docs-snippets-type-check:
description: "Whether to run docs snippets type check."
required: true
type: boolean
documentation-validation:
description: "Whether to run documentation generation validation check."
required: true
type: boolean
component-tests:
description: "Whether to run component tests."
required: true
type: boolean
host-sample-apps-tests:
description: "Whether to run host and sample apps compatibility tests."
required: true
type: boolean
skip:
description: Whether to skip running tests due to one of the artifacts failing to build.
required: true
type: boolean
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:
e2e_embedding_sdk: ${{ steps.changes.outputs.e2e_embedding_sdk }}
frontend_embedding_sdk_sources: ${{ steps.changes.outputs.frontend_embedding_sdk_sources }}
embedding_documentation: ${{ steps.changes.outputs.embedding_documentation }}
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
build:
needs: [files-changed]
if: |
!cancelled() &&
(needs.files-changed.outputs.e2e_embedding_sdk == 'true' ||
needs.files-changed.outputs.frontend_embedding_sdk_sources == 'true' ||
needs.files-changed.outputs.embedding_documentation == 'true')
runs-on: ubuntu-22.04
timeout-minutes: 25
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: Build Embedding SDK package
run: |
# 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
- name: Prepare Embedding SDK artifact
uses: actions/upload-artifact@v4
with:
name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
path: resources/embedding-sdk
embedding-sdk-cli-snippets-type-check:
needs: [files-changed, build]
if: |
needs.files-changed.outputs.frontend_embedding_sdk_sources == 'true' &&
needs.build.result == 'success'
if: inputs.cli-snippets-type-check && !inputs.skip
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
@@ -72,10 +50,7 @@ jobs:
run: yarn run embedding-sdk:cli-snippets:type-check
embedding-sdk-docs-snippets-type-check:
needs: [files-changed, build]
if: |
needs.files-changed.outputs.embedding_documentation == 'true' &&
needs.build.result == 'success'
if: inputs.docs-snippets-type-check && !inputs.skip
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
@@ -91,10 +66,7 @@ jobs:
run: yarn run embedding-sdk:docs-snippets:type-check
embedding-sdk-api-documentation-generation-validation:
needs: [files-changed, build]
if: |
needs.files-changed.outputs.frontend_embedding_sdk_sources == 'true' &&
needs.build.result == 'success'
if: inputs.documentation-validation && !inputs.skip
runs-on: ubuntu-22.04
timeout-minutes: 20
steps:
@@ -140,29 +112,24 @@ jobs:
run: exit 1
# See `Component e2e tests` in `enterprise/frontend/src/embedding-sdk-package/dev.md`
sdk-e2e-tests:
name: "SDK e2e tests"
uses: ./.github/workflows/e2e-component-tests-embedding-sdk.yml
needs: [build]
embedding-sdk-component-tests:
name: "SDK component tests"
if: inputs.component-tests && !inputs.skip
uses: ./.github/workflows/embedding-sdk-component-tests.yml
secrets: inherit
with:
cached-embedding-sdk-dist-artifact-name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
e2e-component-tests-embedding-sdk-backward-compatibility:
name: "SDK e2e backward compatibility tests"
uses: ./.github/workflows/e2e-component-tests-embedding-sdk-backward-compatibility.yml
needs: [build]
not-required-embedding-sdk-apps-compatibility-tests:
name: "SDK e2e tests for compatibility with (host/sample) apps"
if: inputs.host-sample-apps-tests && !inputs.skip
uses: ./.github/workflows/embedding-sdk-host-sample-apps-tests.yml
secrets: inherit
with:
cached-embedding-sdk-dist-artifact-name: embedding-sdk-${{ github.event.pull_request.head.sha || github.sha }}
embedding-sdk-tests-result:
needs:
- embedding-sdk-cli-snippets-type-check
- embedding-sdk-docs-snippets-type-check
- embedding-sdk-api-documentation-generation-validation
- sdk-e2e-tests
- e2e-component-tests-embedding-sdk-backward-compatibility
- embedding-sdk-component-tests
if: always() && !cancelled()
runs-on: ubuntu-latest
timeout-minutes: 5

View File

@@ -35,13 +35,16 @@ jobs:
uses: ./.github/actions/prepare-frontend
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Get Eslint cache key
uses: ./.github/actions/get-cache-keys
id: get-cache-keys
- name: Restore ESLint cache
uses: actions/cache@v4
uses: actions/cache/restore@v4
with:
path: .eslintcache
key: eslintcache-${{ hashFiles('yarn.lock', '.eslintrc.js') }}
restore-keys: |
eslintcache-
path: ${{ github.workspace}}/.eslintcache
key: ${{ steps.get-cache-keys.outputs.eslint-cache-key }}
- name: Compile CLJS
run: yarn build-pure:cljs
- name: Find CSS variables that are used but never defined
@@ -88,8 +91,9 @@ jobs:
uses: ./.github/actions/prepare-backend
- name: Run frontend unit tests
run: yarn run test-unit --silent --shard=${{ matrix.shard }}/${{ env.SHARDS }}
# We want Trunk to still receive test reports even if this job fails.
# It will filter out the quarantined tests, and will control the job exit code based on the analysis.
# 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.
continue-on-error: true
- name: Upload Test Results
uses: ./.github/actions/upload-test-results

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

227
.github/workflows/minimal-tests.yml vendored Normal file
View File

@@ -0,0 +1,227 @@
name: Minimal Tests
on:
pull_request:
types: [opened, synchronize, reopened, labeled]
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
cancel-in-progress: true
jobs:
# Only run if the PR has the minimal-tests label
check-label:
runs-on: ubuntu-latest
timeout-minutes: 1
outputs:
should-run: ${{ steps.check.outputs.result }}
steps:
- name: Check for minimal-tests label
id: check
run: |
if [[ "${{ contains(github.event.pull_request.labels.*.name, 'minimal-tests') }}" == "true" ]]; then
echo "result=true" >> $GITHUB_OUTPUT
else
echo "result=false" >> $GITHUB_OUTPUT
fi
# Postgres app-db tests - single version, single job
postgres-app-db-test:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
runs-on: ubuntu-22.04
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 Latest EE App DB Tests (Part 1)
steps:
- uses: actions/checkout@v4
- name: Test Postgres App DB
uses: ./.github/actions/test-driver
with:
build-static-viz: true
junit-name: 'minimal-be-tests-postgres-ee'
test-args: >-
:only '["test" "enterprise/backend/test"]'
:exclude-tags '[:mb/driver-tests :mb/transforms-python-test]'
:partition/total 2
:partition/index 0
- 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 }}
# Postgres driver tests
postgres-driver-test:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
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 Latest Driver Tests
steps:
- uses: actions/checkout@v4
- name: Test Postgres Driver
uses: ./.github/actions/test-driver
with:
junit-name: 'minimal-be-tests-postgres-driver-ee'
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 }}
# Frontend unit tests
frontend-unit-tests:
needs: check-label
if: needs.check-label.outputs.should-run == 'true'
runs-on: ubuntu-22.04
timeout-minutes: 30
env:
JEST_JUNIT_OUTPUT_DIR: ./target/junit
JEST_JUNIT_OUTPUT_NAME: test-report-frontend-unit.xml
name: Frontend Unit Tests
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: Run frontend unit tests
run: yarn run test-unit --silent
continue-on-error: true
- name: Upload Test Results
uses: ./.github/actions/upload-test-results
if: always()
with:
input-path: ./target/junit
output-name: frontend-unit
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 }}
# Summary job
minimal-tests-result:
needs:
- postgres-app-db-test
- postgres-driver-test
- frontend-unit-tests
runs-on: ubuntu-latest
timeout-minutes: 5
name: minimal-tests-result
if: always() && !cancelled()
steps:
- name: Check job status
uses: actions/github-script@v7
env:
needs: ${{ toJson(needs) }}
with:
script: | # js
const needs = JSON.parse(process.env.needs);
const jobs = Object.entries(needs).map(
([jobName, jobValues]) => ({
name: jobName,
result: jobValues.result
}));
// Check if all jobs either succeeded or were skipped
// Skipped jobs are acceptable (they were intentionally skipped when the label is absent)
const allPassedOrSkipped = jobs.every(job =>
job.result === 'success' || job.result === 'skipped'
);
// Check if any jobs actually failed (not skipped, not cancelled)
const anyFailed = jobs.some(job =>
job.result === 'failure'
);
if (allPassedOrSkipped && !anyFailed) {
console.log("");
console.log(" _------. ");
console.log(" / , \_ ");
console.log(" / / /{}\ |o\_ ");
console.log(" / \ `--' /-' \ ");
console.log(" | \ \ | ");
console.log(" | |`-, | ");
console.log(" / /__/)/ ");
console.log(" | | ");
console.log("");
console.log("All minimal tests have passed. Fast feedback achieved!");
process.exit(0);
}
// otherwise, something failed
console.log("");
console.log(" .::::::::::. .::::::::::. ");
console.log(" .::::''''''::::. .::::''''''::::. ");
console.log(" .:::' `::::.... ....::::' `:::. ");
console.log(" .::' `:::::::| |:::::::' `::. ");
console.log(" .::| |::::::|_ ___ __|::::::| |::. ");
console.log(" `--' |::::::|_()__()_|::::::| `--' ");
console.log(" ::: |::-o::| |::o-::| ::: ");
console.log(" `::. .|::::::| |::::::|. .::' ");
console.log(" `:::. .::\-----' `-----/::. .:::' ");
console.log(" `::::......::::' `::::......::::' ");
console.log(" `::::::::::' `::::::::::' ");
console.log("");
console.log("Minimal tests have failed.");
jobs.forEach((job) => {
if (job.result !== 'success' && job.result !== 'skipped') {
console.log(`${job.name} - ${job.result}`);
}
});
process.exit(1);

44
.github/workflows/openapi-check.yml vendored Normal file
View File

@@ -0,0 +1,44 @@
name: OpenAPI Check
on:
pull_request:
types: [opened, synchronize, reopened, labeled, unlabeled]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true
jobs:
check-openapi-specs:
runs-on: ubuntu-22.04
timeout-minutes: 5
if: contains(github.event.pull_request.labels.*.name, 'openapi-self-healing')
steps:
- uses: actions/checkout@v4
with:
# we're intentionally using METABASE_AUTOMATION_USER_TOKEN to trigger the whole CI pipeline again
# after the self-healing commit is created
# if we used GITHUB_TOKEN, the self-healing commit would not trigger the CI pipeline again
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
# fetch full git history to allow fetching the latest base branch commit and comparing changes
fetch-depth: 0
- name: Setup Node.js 22
uses: actions/setup-node@v4
with:
node-version: 22.x
- name: Prepare back-end environment
uses: ./.github/actions/prepare-backend
- name: Generate version.properties
run: ./bin/build.sh :steps [:version]
- name: Get latest base branch commit
run: |
git fetch origin ${{ github.event.pull_request.base.ref }}
echo "LATEST_BASE_SHA=$(git rev-parse origin/${{ github.event.pull_request.base.ref }})" >> $GITHUB_ENV
- name: Check OpenAPI specs are up to date
env:
AUTO_COMMIT: "true"
PR_BRANCH: ${{ github.event.pull_request.head.ref }}
BASE_SHA: ${{ env.LATEST_BASE_SHA }}
HEAD_SHA: ${{ github.event.pull_request.head.sha }}
GITHUB_SHA: ${{ github.sha }}
run: ./bin/openapi-check.sh

View File

@@ -10,6 +10,15 @@ concurrency:
jobs:
pr-env:
if: ${{ github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'PR-Env') || github.event.label.name == 'PR-Env' }}
if: ${{ (github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'PR-Env') && !contains(github.event.pull_request.labels.*.name, 'PR-Env-analytics-dev')) || github.event.label.name == 'PR-Env' }}
uses: ./.github/workflows/pr-env-destroy.yml
secrets: inherit
with:
analytics_dev_mode: false
pr-env-analytics-dev:
if: ${{ (github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'PR-Env-analytics-dev')) || github.event.label.name == 'PR-Env-analytics-dev' }}
uses: ./.github/workflows/pr-env-destroy.yml
secrets: inherit
with:
analytics_dev_mode: false

View File

@@ -10,7 +10,7 @@ concurrency:
jobs:
uberjar:
if: ${{ github.event.label.name == 'PR-Env' }}
if: ${{ github.event.label.name == 'PR-Env' || github.event.label.name == 'PR-Env-analytics-dev' }}
uses: ./.github/workflows/uberjar.yml
secrets: inherit
@@ -19,3 +19,13 @@ jobs:
if: ${{ github.event.label.name == 'PR-Env' }}
uses: ./.github/workflows/pr-env.yml
secrets: inherit
with:
analytics_dev_mode: false
pr-env-analytics-dev:
needs: [uberjar]
if: ${{ github.event.label.name == 'PR-Env-analytics-dev' }}
uses: ./.github/workflows/pr-env.yml
secrets: inherit
with:
analytics_dev_mode: true

View File

@@ -3,6 +3,12 @@ run-name: Building Dynamic PR Environment for ${{ github.ref_name }} by @${{ git
on:
workflow_call:
inputs:
analytics_dev_mode:
description: 'Enable analytics development mode'
required: false
type: boolean
default: false
jobs:
build:
runs-on: ubuntu-latest
@@ -124,6 +130,7 @@ jobs:
PR_NUMBER: ${{ github.event.number }}
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.PR_ENV_MB_PREMIUM_EMBEDDING_TOKEN }}
SHA: ${{ github.event.pull_request.head.sha || github.sha }}
MB_ANALYTICS_DEV_MODE: ${{ inputs.analytics_dev_mode && 'true' || 'false' }}
- name: Deploy PR Review ENV
run: |
kubectl apply -f ./metabase.yml
@@ -139,3 +146,4 @@ jobs:
✅ Preview:
https://pr${{ github.event.number }}.coredev.metabase.com
🗒️ [login instructions](https://www.notion.so/metabase/Ephemeral-PR-Environments-c74a3710c87a460dbf4fc0007a001458)
📦 Deployment type: ${{ inputs.analytics_dev_mode && 'PR-Env-analytics-dev' || 'PR-Env' }}

View File

@@ -161,19 +161,21 @@ jobs:
- name: Run a few important OSS Cypress tests as sanity check
if: ${{ matrix.edition == 'oss' }}
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: |
node e2e/runner/run_cypress_ci.js e2e \
--env grepTags="@smoke+-@EE",grepOmitFiltered=true \
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
--env grepTags="@smoke+-@EE" \
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)'
- name: Run a few important EE Cypress tests as sanity check
if: ${{ matrix.edition == 'ee' }}
env:
CYPRESS_BROWSER: ${{ steps.cypress-prep.outputs.chrome-path }}
run: |
node e2e/runner/run_cypress_ci.js e2e \
--env grepTags="@smoke+-@OSS",grepOmitFiltered=true \
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
--env grepTags="@smoke+-@OSS" \
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)'
- name: Upload Cypress Artifacts upon failure
uses: actions/upload-artifact@v4

View File

@@ -8,9 +8,9 @@ on:
description: "Branch we want to release the SDK from (to release from other branches use the workflow from those branches)"
type: choice
required: true
default: "master"
default: release-x.57.x
options:
- master
- release-x.57.x
concurrency:
# We want to ensure only one job is running at a time per branch because
@@ -345,8 +345,9 @@ jobs:
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
- name: Edit PR adding useful information (using Metabase bot app)
# metabase/embedding team is added automatically as code owner of updated `package.template.json` file
run: |
gh pr edit --add-reviewer @metabase/embedding,albertoperdomo --add-label no-backport
gh pr edit --add-reviewer albertoperdomo --add-label no-backport
env:
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
@@ -368,42 +369,16 @@ jobs:
name: metabase-sdk
path: sdk
- name: Compute master tag
id: compute-tag
run: |
if [ -n "${{ needs.determine-sdk-version.outputs.pre_release_label }}" ]; then
echo "masterTag=${{ needs.determine-sdk-version.outputs.pre_release_label }}" >> $GITHUB_OUTPUT
else
echo "masterTag=nightly" >> $GITHUB_OUTPUT
fi
- name: Publish to NPM
working-directory: sdk
run: |
echo //registry.npmjs.org/:_authToken=${{ secrets.NPM_RELEASE_TOKEN }} > .npmrc
npm publish --tag 57-stable
TAG=$(jq -r --null-input \
--arg branch "${{ inputs.branch }}" \
--arg masterTag "${{ steps.compute-tag.outputs.masterTag }}" '
{
"master": $masterTag,
"release-x.51.x": "51-stable",
"release-x.52.x": "52-stable",
"release-x.53.x": "53-stable",
"release-x.54.x": "54-stable",
"release-x.55.x": "55-stable",
"release-x.56.x": "56-stable"
}[$branch]'
)
echo "Resolved npm tag: $TAG"
npm publish --tag "$TAG"
- name: Add `latest` tag to the latest release branch (`release-x.55.x`) deployment
if: ${{ inputs.branch == 'release-x.56.x' }}
working-directory: sdk
run: |
npm dist-tag add @metabase/embedding-sdk-react@${{ env.sdk_version }} latest
# - name: Add `latest` tag to the latest release branch deployment
# working-directory: sdk
# run: |
# npm dist-tag add @metabase/embedding-sdk-react@${{ env.sdk_version }} latest
git-tag:
needs: [publish-npm, determine-sdk-version]

View File

@@ -47,7 +47,7 @@ jobs:
with:
script: | # js
const {
getVersionFromReleaseBranch,
getMajorVersionFromRef,
getMajorVersion,
} = require('${{ github.workspace }}/release/dist/index.cjs');
@@ -60,11 +60,10 @@ jobs:
}
// otherwise, get the version from the release branch name
const branch = context.payload.ref;
const version = getVersionFromReleaseBranch(branch);
const majorVersion = getMajorVersion(version);
const ref = context.payload.ref;
const majorVersion = getMajorVersionFromRef(ref);
console.log({ branch, version, majorVersion });
console.log({ ref, majorVersion });
core.exportVariable('VERSION', majorVersion);
- name: generate release Log

View File

@@ -12,7 +12,7 @@ on:
jobs:
files-changed:
if: ${{ !contains(github.event.pull_request.labels.*.name,'ci skip') }}
if: ${{ !contains(github.event.pull_request.labels.*.name,'ci skip') && !contains(github.event.pull_request.labels.*.name,'minimal-tests') }}
name: Check which files changed
runs-on: ubuntu-22.04
timeout-minutes: 5
@@ -25,6 +25,10 @@ jobs:
frontend_all: ${{ steps.changes.outputs.frontend_all }}
frontend_sources: ${{ steps.changes.outputs.frontend_sources }}
documentation: ${{ steps.changes.outputs.documentation }}
embedding_documentation: ${{ steps.changes.outputs.embedding_documentation }}
embedding_sdk_components: ${{ steps.changes.outputs.embedding_sdk_components }}
embedding_sdk_host_sample_apps: ${{ steps.changes.outputs.embedding_sdk_host_sample_apps }}
embedding_sdk_ci: ${{ steps.changes.outputs.embedding_sdk_ci }}
steps:
- uses: actions/checkout@v4
- name: Test which files changed
@@ -36,49 +40,19 @@ jobs:
list-files: csv
filters: .github/file-paths.yaml
static-viz-files-changed:
name: Check whether static-viz files changed
if: ${{ !contains(github.event.pull_request.labels.*.name,'ci skip') }}
runs-on: ubuntu-22.04
timeout-minutes: 10
outputs:
static_viz: ${{ steps.static_viz.outputs.static_viz }}
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: Build static-viz frontend
run: yarn build-static-viz
env:
MB_EDITION: ee
- name: Upload Static Viz Bundle Artifact
uses: actions/upload-artifact@v4
with:
name: static-viz-bundle-${{ github.sha }}
path: resources/frontend_client/app/dist
- name: Check for static viz changes
uses: dorny/paths-filter@v3.0.0
id: static_viz
with:
token: ${{ github.token }}
filters: .github/static-viz-sources.yaml
uberjar:
needs: [files-changed, static-viz-files-changed]
needs: [files-changed]
if: ${{ !cancelled() && !(needs.files-changed.outputs.documentation == 'true' && needs.files-changed.outputs.backend_all == 'false' && needs.files-changed.outputs.frontend_all == 'false' && needs.files-changed.outputs.e2e_all == 'false') }}
uses: ./.github/workflows/uberjar.yml
secrets: inherit
backend-tests:
if: ${{ !cancelled() && needs.files-changed.result == 'success' }}
needs: [files-changed, static-viz-files-changed]
needs: [files-changed]
uses: ./.github/workflows/backend.yml
secrets: inherit
with:
skip: ${{ needs.files-changed.outputs.backend_all != 'true' && needs.static-viz-files-changed.outputs.static_viz != 'true' }}
skip: ${{ needs.files-changed.outputs.backend_all != 'true' }}
semantic-search-tests:
needs: files-changed
@@ -122,18 +96,50 @@ jobs:
# list of changed specs files, then only specs are changed and we can run only those specs
specs: ${{ needs.files-changed.outputs.e2e_all_files == needs.files-changed.outputs.e2e_specs_files && needs.files-changed.outputs.e2e_specs_files || '' }}
embedding-sdk-package:
needs: [files-changed]
if: |
!cancelled() &&
(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')
uses: ./.github/workflows/embedding-sdk-package-build.yml
secrets: inherit
sdk-tests:
needs: files-changed
needs: [uberjar, embedding-sdk-package, files-changed]
if: always()
uses: ./.github/workflows/embedding-sdk.yml
secrets: inherit
with:
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' }}
component-tests: ${{ needs.files-changed.outputs.embedding_sdk_components == 'true' }}
host-sample-apps-tests: ${{ needs.files-changed.outputs.embedding_sdk_host_sample_apps == 'true' }}
skip: ${{ needs.embedding-sdk-package.result != 'success' || needs.uberjar.result != 'success' }}
pr-env:
needs: [uberjar]
if: |
!cancelled() &&
contains(github.event.pull_request.labels.*.name, 'PR-Env')
contains(github.event.pull_request.labels.*.name, 'PR-Env') &&
!contains(github.event.pull_request.labels.*.name, 'PR-Env-analytics-dev')
uses: ./.github/workflows/pr-env.yml
secrets: inherit
with:
analytics_dev_mode: false
pr-env-analytics-dev:
needs: [uberjar]
if: |
!cancelled() &&
contains(github.event.pull_request.labels.*.name, 'PR-Env-analytics-dev')
uses: ./.github/workflows/pr-env.yml
secrets: inherit
with:
analytics_dev_mode: true
containerize:
needs: [uberjar]

View File

@@ -146,7 +146,13 @@ jobs:
runs-on: ubuntu-22.04
name: Is ${{ matrix.edition }} (java ${{ matrix.java-version }}) healthy?
needs: [build, check-existing-artifacts]
if: always() && !cancelled() && (needs.build.result == 'success' || (needs.check-existing-artifacts.outputs.should_build == 'false' && needs.check-existing-artifacts.outputs.ee_exists == 'true' && needs.check-existing-artifacts.outputs.oss_exists == 'true'))
# We only care about the explicit JAR health check on push to `master` and the `release-` branches.
# JARs created in random branches on PRs are 99% of the time treated as ephemeral, and used only in e2e tests.
# E2E tests already have a step where they wait for the instance health check.
if: |
always() && !cancelled() &&
(github.ref_name == 'master' || startsWith(github.ref_name, 'release-')) &&
(needs.build.result == 'success' || (needs.check-existing-artifacts.outputs.should_build == 'false' && needs.check-existing-artifacts.outputs.ee_exists == 'true' && needs.check-existing-artifacts.outputs.oss_exists == 'true'))
timeout-minutes: 10
strategy:
matrix:

1
.gitignore vendored
View File

@@ -104,6 +104,7 @@ dev/serialization_deltas/
*.tsbuildinfo
/trace-output/
/temp-types/
/frontend/src/metabase-types/openapi
**/cypress_sample_database.json
**/cypress_sample_instance_data.json

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 72 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 77 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 71 KiB

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 931 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 85 KiB

View File

@@ -2,4 +2,4 @@ frontend/src/cljs
docs/configuring-metabase/environment-variables.md
docs/api/*
docs/api-documentation.md
enterprise/frontend/src/embedding-sdk-shared/.storybook/msw-public/mockServiceWorker.js
frontend/src/embedding-sdk-shared/.storybook/msw-public/mockServiceWorker.js

View File

@@ -676,14 +676,11 @@ If you modify this Program, or any covered work, by linking or combining it with
* environ
* hiccup
* junit
* korma
* medley
* org.clojure/clojure
* org.clojure/clojurescript
* org.clojure/core.async
* org.clojure/core.cache
* org.clojure/core.incubator
* org.clojure/core.logic
* org.clojure/core.match
* org.clojure/core.memoize
* org.clojure/data.csv
@@ -702,10 +699,8 @@ If you modify this Program, or any covered work, by linking or combining it with
* org.tcrawley/dynapath
* quoin
* refactor-nrepl
* robert/hooke
* scout
* slingshot
* stencil
* swiss-arrows
* tigris
* instaparse

47
bb.edn
View File

@@ -2,7 +2,8 @@
;; we put path as bin, and everything is in the ./mage subdirectory,
;; so the namespaces are mage.cli, mage.format, etc.
:paths ["mage/src" "mage/test" "bin/lint-migrations-file/src"]
:deps {org.babashka/json {:mvn/version "0.1.6"}
:deps {dev.weavejester/cljfmt {:mvn/version "0.15.3"}
org.babashka/json {:mvn/version "0.1.6"}
metosin/malli {:mvn/version "0.17.0"}
table/table {:mvn/version "0.5.0"}
mvxcvi/puget {:mvn/version "1.3.4"}}
@@ -82,6 +83,18 @@
:requires [[mage.check]]
:task (task! (mage.check/check (:arguments parsed)))}
codespell
{:doc "Check for misspellings in the source code."
:examples [["./bin/mage codespell"]]
:requires [[mage.codespell]]
:task (task! (mage.codespell/codespell (:arguments parsed)))}
codespell-interactive
{:doc "Check for misspellings in the source code, and interactively prompt to fix them."
:examples [["./bin/mage codespell-interactive"]]
:requires [[mage.codespell]]
:task (task! (mage.codespell/codespell-interactive (:arguments parsed)))}
start-maildev
{:doc "Start Maildev"
:examples [["./bin/mage start-maildev -h" "print help for start-maildev"]]
@@ -196,6 +209,38 @@
:requires [[mage.util :as u]]
:task (task! (u/print-tasks parsed))}
analytics:setup
{:doc "Set up usage analytics development mode"
:examples [["./bin/mage analytics:setup" "Enable usage analytics dev mode and import content"]]
:requires [[mage.analytics :as analytics]]
:task (task! (analytics/setup!))}
analytics:export
{:doc "Export usage analytics content to YAML files"
:examples [["./bin/mage analytics:export" "Export to default location (resources/instance_analytics)"]
["./bin/mage analytics:export my-custom-dir" "Export to custom directory"]]
:arg-schema [:or
[:tuple]
[:tuple [:string {:description "Target directory for export"}]]]
:requires [[mage.analytics :as analytics]]
:task (task! (if-let [target-dir (first (:arguments parsed))]
(analytics/export! target-dir)
(analytics/export!)))}
analytics:teardown
{:doc "Tear down usage analytics development mode"
:examples [["./bin/mage analytics:teardown" "Remove usage analytics dev database and disable dev mode"]]
:requires [[mage.analytics :as analytics]]
:task (task! (analytics/teardown!))}
analytics:finalize
{:doc "Export usage analytics content and tear down development mode"
:examples [["./bin/mage analytics:finalize" "Export to default location and tear down"]]
:requires [[mage.analytics :as analytics]]
:task (task! (do
(analytics/export!)
(analytics/teardown!)))}
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Private Tasks:
;; These tasks are more for internal tooling, e.g. for use from git hooks etc.

View File

@@ -13,6 +13,7 @@
"org.apache.hadoop" {:resource "apache2_0.txt"}
"org.clojure" {:resource "EPL.txt"}
"org.eclipse.jetty" {:resource "apache2_0.txt"}
"org.eclipse.jetty.ee" {:resource "apache2_0.txt"}
"org.opensaml" {:resource "apache2_0.txt"}
"org.ow2.asm" {:resource "BSD.txt"}
"xalan" {:resource "apache2_0.txt"}}

View File

@@ -159,7 +159,7 @@
(catch Exception _ false))]
(cond success? ::done
(and (not success?) (< n max)) (recur (inc n))
:else (throw (ex-info (str "Could not succeed " step-name) {:max-attempts max}))))))
:else (throw (ex-info (str "Could not succeed " step-name) {:max-retries max}))))))
(deftest all-deps-have-licenses
(testing "All deps on the classpath have licenses"

View File

@@ -1,63 +0,0 @@
#!/usr/bin/env bash
set -eE -o errexit -o functrace
### Utility
failure() {
local lineno=$1
local msg=$2
echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR
err() {
echo "Error: $1"
exit 1
}
rename() {
dirname=$(dirname "$1")
basename=$(basename "$1")
target="${basename//$2/$3}"
mv "$1" "${dirname}/${target}"
}
### Main
main() {
target="${1}"
if [ -z "${target}" ]; then
echo "Usage: $0 path/to/export"
exit 0
fi
if [ ! -d "${target}/collections" ]; then
err "No 'collections' directory in '${target}'"
fi
find "${target}"/databases -maxdepth 1 -mindepth 1 \
-name audit_development_app_db -prune \
-o -exec rm -rf "{}" \;
find "${target}"/databases/audit_development_app_db/schemas/public/tables -maxdepth 1 -mindepth 1 \
-name "v_*" -prune \
-o -exec rm -rf "{}" \;
old_db="audit_development_app_db"
new_db="Internal Metabase Database"
old_coll="audit_internal_col_id"
new_coll="vG58R8k-QddHWA7_47umn"
# Replace database_name and collection_id
find "${target}" -depth -name "*${old_db}*" | while IFS= read -r path; do rename "${path}" "${old_db}" "${new_db}"; done
find "${target}" -depth -name "*${old_coll}*" | while IFS= read -r path; do rename "${path}" "${old_coll}" "${new_coll}"; done
find "${target}" -name '*.yaml' -exec sed -i '' "s/${old_db}/${new_db}/g" {} \;
find "${target}" -name '*.yaml' -exec sed -i '' "s/${old_coll}/${new_coll}/g" {} \;
}
main "$@"

View File

@@ -20,8 +20,9 @@ const REPLACES_MAP = {
"metabase-types": "frontend/src/metabase-types",
metabase: "frontend/src/metabase",
"embedding-sdk-package": "enterprise/frontend/src/embedding-sdk-package",
"embedding-sdk-bundle": "enterprise/frontend/src/embedding-sdk-bundle",
"embedding-sdk-shared": "enterprise/frontend/src/embedding-sdk-shared",
"embedding-sdk-bundle": "frontend/src/embedding-sdk-bundle",
"embedding-sdk-shared": "frontend/src/embedding-sdk-shared",
"embedding-sdk-ee": "enterprise/frontend/src/embedding-sdk-ee",
cljs: "target/cljs_release",
};
@@ -31,13 +32,15 @@ const API_EXTRACTOR_CONFIG_PATH = path.join(
);
const getLogger = (prefix) => {
const verbose = process.env.SDK_FIXUP_VERBOSE_LOGS === "true";
return {
verbose: (message) => verbose && console.log(`[${prefix}] ${message}`),
log: (message) => console.log(`[${prefix}] ${message}`),
error: (message) => console.error(`[${prefix}] ${message}`),
};
};
const { log } = getLogger("dts fixup");
const { log, verbose } = getLogger("dts fixup");
const getRelativePath = (fromPath, toPath) => {
const relativePath = path.relative(path.dirname(fromPath), toPath);
@@ -67,7 +70,7 @@ const replaceAliasedImports = (filePath) => {
});
fs.writeFileSync(filePath, fileContent, { encoding: "utf-8" });
log(`Edited file: ${filePath}`);
verbose(`Edited file: ${filePath}`);
};
const removeUnresolvedReexports = (filePath) => {
@@ -94,7 +97,7 @@ const removeUnresolvedReexports = (filePath) => {
!fs.existsSync(`${path.resolve(dirPath, target)}.d.ts`);
if (isUnresolved) {
log(`Removing unresolved re-export: ${line}`);
verbose(`Removing unresolved re-export: ${line}`);
isModified = true;
}
@@ -117,7 +120,7 @@ const fixupTypesAfterCompilation = ({ isWatchMode }) => {
removeUnresolvedReexports(filePath);
});
log("Done!");
console.log("[dts fixup] Done!");
if (!isWatchMode) {
generateDtsRollup();
@@ -176,7 +179,7 @@ const generateDtsRollup = () => {
});
});
log("Dts rollup done!");
console.log("[dts rollup] Dts rollup done!");
};
const watchFilesAndFixThem = () => {

View File

@@ -9,6 +9,6 @@
"express": "^5.0.1",
"express-session": "^1.18.1",
"jsonwebtoken": "^9.0.2",
"next": "^15.2.3"
"next": "^15.2.6"
}
}

View File

@@ -2,185 +2,204 @@
# yarn lockfile v1
"@emnapi/runtime@^1.4.3":
version "1.4.3"
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.4.3.tgz#c0564665c80dc81c448adac23f9dfbed6c838f7d"
integrity sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==
"@emnapi/runtime@^1.7.0":
version "1.7.1"
resolved "https://registry.yarnpkg.com/@emnapi/runtime/-/runtime-1.7.1.tgz#a73784e23f5d57287369c808197288b52276b791"
integrity sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==
dependencies:
tslib "^2.4.0"
"@img/sharp-darwin-arm64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.2.tgz#65049ef7c6be7857da742cd028f97602ce209635"
integrity sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg==
"@img/colour@^1.0.0":
version "1.0.0"
resolved "https://registry.yarnpkg.com/@img/colour/-/colour-1.0.0.tgz#d2fabb223455a793bf3bf9c70de3d28526aa8311"
integrity sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==
"@img/sharp-darwin-arm64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.5.tgz#6e0732dcade126b6670af7aa17060b926835ea86"
integrity sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==
optionalDependencies:
"@img/sharp-libvips-darwin-arm64" "1.1.0"
"@img/sharp-libvips-darwin-arm64" "1.2.4"
"@img/sharp-darwin-x64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.2.tgz#d37ff7c75c46d5a68a3756e3f1924ef7ca7b285e"
integrity sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g==
"@img/sharp-darwin-x64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.5.tgz#19bc1dd6eba6d5a96283498b9c9f401180ee9c7b"
integrity sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==
optionalDependencies:
"@img/sharp-libvips-darwin-x64" "1.1.0"
"@img/sharp-libvips-darwin-x64" "1.2.4"
"@img/sharp-libvips-darwin-arm64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz#843f7c09c7245dc0d3cfec2b3c83bb08799a704f"
integrity sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==
"@img/sharp-libvips-darwin-arm64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.4.tgz#2894c0cb87d42276c3889942e8e2db517a492c43"
integrity sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==
"@img/sharp-libvips-darwin-x64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz#1239c24426c06a8e833815562f78047a3bfbaaf8"
integrity sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==
"@img/sharp-libvips-darwin-x64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.4.tgz#e63681f4539a94af9cd17246ed8881734386f8cc"
integrity sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==
"@img/sharp-libvips-linux-arm64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz#20d276cefd903ee483f0441ba35961679c286315"
integrity sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==
"@img/sharp-libvips-linux-arm64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.4.tgz#b1b288b36864b3bce545ad91fa6dadcf1a4ad318"
integrity sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==
"@img/sharp-libvips-linux-arm@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz#067c0b566eae8063738cf1b1db8f8a8573b5465c"
integrity sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==
"@img/sharp-libvips-linux-arm@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.4.tgz#b9260dd1ebe6f9e3bdbcbdcac9d2ac125f35852d"
integrity sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==
"@img/sharp-libvips-linux-ppc64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz#682334595f2ca00e0a07a675ba170af165162802"
integrity sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==
"@img/sharp-libvips-linux-ppc64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.4.tgz#4b83ecf2a829057222b38848c7b022e7b4d07aa7"
integrity sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==
"@img/sharp-libvips-linux-s390x@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz#82fcd68444b3666384235279c145c2b28d8ee302"
integrity sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==
"@img/sharp-libvips-linux-riscv64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.2.4.tgz#880b4678009e5a2080af192332b00b0aaf8a48de"
integrity sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==
"@img/sharp-libvips-linux-x64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz#65b2b908bf47156b0724fde9095676c83a18cf5a"
integrity sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==
"@img/sharp-libvips-linux-s390x@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.4.tgz#74f343c8e10fad821b38f75ced30488939dc59ec"
integrity sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==
"@img/sharp-libvips-linuxmusl-arm64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz#72accf924e80b081c8db83b900b444a67c203f01"
integrity sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==
"@img/sharp-libvips-linux-x64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.4.tgz#df4183e8bd8410f7d61b66859a35edeab0a531ce"
integrity sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==
"@img/sharp-libvips-linuxmusl-x64@1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz#1fa052737e203f46bf44192acd01f9faf11522d7"
integrity sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==
"@img/sharp-libvips-linuxmusl-arm64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.4.tgz#c8d6b48211df67137541007ee8d1b7b1f8ca8e06"
integrity sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==
"@img/sharp-linux-arm64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.2.tgz#c9690fac5f3137eaab3f7ad6065390d10f66f1fa"
integrity sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q==
"@img/sharp-libvips-linuxmusl-x64@1.2.4":
version "1.2.4"
resolved "https://registry.yarnpkg.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.4.tgz#be11c75bee5b080cbee31a153a8779448f919f75"
integrity sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==
"@img/sharp-linux-arm64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.5.tgz#7aa7764ef9c001f15e610546d42fce56911790cc"
integrity sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==
optionalDependencies:
"@img/sharp-libvips-linux-arm64" "1.1.0"
"@img/sharp-libvips-linux-arm64" "1.2.4"
"@img/sharp-linux-arm@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.2.tgz#771dd2ec645f85f98441359bfc118afaf38cbd8b"
integrity sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ==
"@img/sharp-linux-arm@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.5.tgz#5fb0c3695dd12522d39c3ff7a6bc816461780a0d"
integrity sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==
optionalDependencies:
"@img/sharp-libvips-linux-arm" "1.1.0"
"@img/sharp-libvips-linux-arm" "1.2.4"
"@img/sharp-linux-s390x@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.2.tgz#82132d158abff57bd90b53574f2865f72f94e6c8"
integrity sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw==
"@img/sharp-linux-ppc64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.5.tgz#9c213a81520a20caf66978f3d4c07456ff2e0813"
integrity sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==
optionalDependencies:
"@img/sharp-libvips-linux-s390x" "1.1.0"
"@img/sharp-libvips-linux-ppc64" "1.2.4"
"@img/sharp-linux-x64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.2.tgz#d815fb87899d462b28b62a9252ad127f02fe0740"
integrity sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ==
"@img/sharp-linux-riscv64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.34.5.tgz#cdd28182774eadbe04f62675a16aabbccb833f60"
integrity sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==
optionalDependencies:
"@img/sharp-libvips-linux-x64" "1.1.0"
"@img/sharp-libvips-linux-riscv64" "1.2.4"
"@img/sharp-linuxmusl-arm64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.2.tgz#cfac45b2abbc04628f676e123bfe3aeb300266c7"
integrity sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA==
"@img/sharp-linux-s390x@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.5.tgz#93eac601b9f329bb27917e0e19098c722d630df7"
integrity sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-arm64" "1.1.0"
"@img/sharp-libvips-linux-s390x" "1.2.4"
"@img/sharp-linuxmusl-x64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.2.tgz#b876c23ff51d0fb6d9f3b0a07e2f4d1436c203ad"
integrity sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA==
"@img/sharp-linux-x64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.5.tgz#55abc7cd754ffca5002b6c2b719abdfc846819a8"
integrity sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-x64" "1.1.0"
"@img/sharp-libvips-linux-x64" "1.2.4"
"@img/sharp-wasm32@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.2.tgz#b1dd0bab547dccf517586eb1fa5852160bba3b82"
integrity sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ==
"@img/sharp-linuxmusl-arm64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.5.tgz#d6515ee971bb62f73001a4829b9d865a11b77086"
integrity sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-arm64" "1.2.4"
"@img/sharp-linuxmusl-x64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.5.tgz#d97978aec7c5212f999714f2f5b736457e12ee9f"
integrity sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==
optionalDependencies:
"@img/sharp-libvips-linuxmusl-x64" "1.2.4"
"@img/sharp-wasm32@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-wasm32/-/sharp-wasm32-0.34.5.tgz#2f15803aa626f8c59dd7c9d0bbc766f1ab52cfa0"
integrity sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==
dependencies:
"@emnapi/runtime" "^1.4.3"
"@emnapi/runtime" "^1.7.0"
"@img/sharp-win32-arm64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.2.tgz#f37bee0f60c167f825a09d2b8de6849b823e8b30"
integrity sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ==
"@img/sharp-win32-arm64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.5.tgz#3706e9e3ac35fddfc1c87f94e849f1b75307ce0a"
integrity sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==
"@img/sharp-win32-ia32@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.2.tgz#8fc30b6655bc6ff8910344a2020d334aa6361672"
integrity sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw==
"@img/sharp-win32-ia32@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.5.tgz#0b71166599b049e032f085fb9263e02f4e4788de"
integrity sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==
"@img/sharp-win32-x64@0.34.2":
version "0.34.2"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.2.tgz#ecf19250f8fe35de684aa2b0ec6f773b3447247b"
integrity sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw==
"@img/sharp-win32-x64@0.34.5":
version "0.34.5"
resolved "https://registry.yarnpkg.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.5.tgz#a81ffb00e69267cd0a1d626eaedb8a8430b2b2f8"
integrity sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==
"@next/env@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.3.2.tgz#7143eafa9b11cfdf3d3c7318b0facb9dfdb2948f"
integrity sha512-xURk++7P7qR9JG1jJtLzPzf0qEvqCN0A/T3DXf8IPMKo9/6FfjxtEffRJIIew/bIL4T3C2jLLqBor8B/zVlx6g==
"@next/env@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/env/-/env-15.5.7.tgz#4168db34ae3bc9fd9ad3b951d327f4cfc38d4362"
integrity sha512-4h6Y2NyEkIEN7Z8YxkA27pq6zTkS09bUSYC0xjd0NpwFxjnIKeZEeH591o5WECSmjpUhLn3H2QLJcDye3Uzcvg==
"@next/swc-darwin-arm64@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.2.tgz#1a7b36bf3c439f899065c878a580bc57a3630ec7"
integrity sha512-2DR6kY/OGcokbnCsjHpNeQblqCZ85/1j6njYSkzRdpLn5At7OkSdmk7WyAmB9G0k25+VgqVZ/u356OSoQZ3z0g==
"@next/swc-darwin-arm64@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.5.7.tgz#f0c9ccfec2cd87cbd4b241ce4c779a7017aed958"
integrity sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==
"@next/swc-darwin-x64@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.2.tgz#3742026344f49128cf1b0f43814c67e880db7361"
integrity sha512-ro/fdqaZWL6k1S/5CLv1I0DaZfDVJkWNaUU3un8Lg6m0YENWlDulmIWzV96Iou2wEYyEsZq51mwV8+XQXqMp3w==
"@next/swc-darwin-x64@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-darwin-x64/-/swc-darwin-x64-15.5.7.tgz#18009e9fcffc5c0687cc9db24182ddeac56280d9"
integrity sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==
"@next/swc-linux-arm64-gnu@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.2.tgz#fb29d45c034e3d2eef89b0e2801d62eb86155823"
integrity sha512-covwwtZYhlbRWK2HlYX9835qXum4xYZ3E2Mra1mdQ+0ICGoMiw1+nVAn4d9Bo7R3JqSmK1grMq/va+0cdh7bJA==
"@next/swc-linux-arm64-gnu@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.5.7.tgz#fe7c7e08264cf522d4e524299f6d3e63d68d579a"
integrity sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==
"@next/swc-linux-arm64-musl@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.2.tgz#396784ef312666600ab1ae481e34cb1f6e3ae730"
integrity sha512-KQkMEillvlW5Qk5mtGA/3Yz0/tzpNlSw6/3/ttsV1lNtMuOHcGii3zVeXZyi4EJmmLDKYcTcByV2wVsOhDt/zg==
"@next/swc-linux-arm64-musl@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.5.7.tgz#94228fe293475ec34a5a54284e1056876f43a3cf"
integrity sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==
"@next/swc-linux-x64-gnu@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.2.tgz#ac01fda376878e02bc6b57d1e88ab8ceae9f868e"
integrity sha512-uRBo6THWei0chz+Y5j37qzx+BtoDRFIkDzZjlpCItBRXyMPIg079eIkOCl3aqr2tkxL4HFyJ4GHDes7W8HuAUg==
"@next/swc-linux-x64-gnu@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.5.7.tgz#078c71201dfe7fcfb8fa6dc92aae6c94bc011cdc"
integrity sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==
"@next/swc-linux-x64-musl@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.2.tgz#327a5023003bcb3ca436efc08733f091bba2b1e8"
integrity sha512-+uxFlPuCNx/T9PdMClOqeE8USKzj8tVz37KflT3Kdbx/LOlZBRI2yxuIcmx1mPNK8DwSOMNCr4ureSet7eyC0w==
"@next/swc-linux-x64-musl@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.5.7.tgz#72947f5357f9226292353e0bb775643da3c7a182"
integrity sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==
"@next/swc-win32-arm64-msvc@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.2.tgz#ce3a6588bd9c020960704011ab20bd0440026965"
integrity sha512-LLTKmaI5cfD8dVzh5Vt7+OMo+AIOClEdIU/TSKbXXT2iScUTSxOGoBhfuv+FU8R9MLmrkIL1e2fBMkEEjYAtPQ==
"@next/swc-win32-arm64-msvc@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.5.7.tgz#397b912cd51c6a80e32b9c0507ecd82514353941"
integrity sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==
"@next/swc-win32-x64-msvc@15.3.2":
version "15.3.2"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.2.tgz#43cc36097ac27639e9024a5ceaa6e7727fa968c8"
integrity sha512-aW5B8wOPioJ4mBdMDXkt5f3j8pUr9W8AnlX0Df35uRWNT1Y6RIybxjnSUe+PhM+M1bwgyY8PHLmXZC6zT1o5tA==
"@swc/counter@0.1.3":
version "0.1.3"
resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9"
integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==
"@next/swc-win32-x64-msvc@15.5.7":
version "15.5.7"
resolved "https://registry.yarnpkg.com/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.5.7.tgz#e02b543d9dc6c1631d4ac239cb1177245dfedfe4"
integrity sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==
"@swc/helpers@0.5.15":
version "0.5.15"
@@ -310,13 +329,6 @@ buffer-equal-constant-time@1.0.1:
resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819"
integrity sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==
busboy@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/busboy/-/busboy-1.6.0.tgz#966ea36a9502e43cdb9146962523b92f531f6893"
integrity sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==
dependencies:
streamsearch "^1.1.0"
bytes@3.1.2, bytes@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5"
@@ -348,34 +360,6 @@ client-only@0.0.1:
resolved "https://registry.yarnpkg.com/client-only/-/client-only-0.0.1.tgz#38bba5d403c41ab150bff64a95c85013cf73bca1"
integrity sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==
color-convert@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
dependencies:
color-name "~1.1.4"
color-name@^1.0.0, color-name@~1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
color-string@^1.9.0:
version "1.9.1"
resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
dependencies:
color-name "^1.0.0"
simple-swizzle "^0.2.2"
color@^4.2.3:
version "4.2.3"
resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
dependencies:
color-convert "^2.0.1"
color-string "^1.9.0"
content-disposition@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2"
@@ -447,10 +431,10 @@ destroy@^1.2.0:
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
detect-libc@^2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.4.tgz#f04715b8ba815e53b4d8109655b6508a6865a7e8"
integrity sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==
detect-libc@^2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad"
integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==
dunder-proto@^1.0.1:
version "1.0.1"
@@ -665,11 +649,6 @@ ipaddr.js@1.9.1:
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
is-arrayish@^0.3.1:
version "0.3.2"
resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
is-promise@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3"
@@ -812,28 +791,26 @@ negotiator@^1.0.0:
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a"
integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==
next@^15.2.3:
version "15.3.2"
resolved "https://registry.yarnpkg.com/next/-/next-15.3.2.tgz#97510629e38a058dd154782a5c2ec9c9ab94d0d8"
integrity sha512-CA3BatMyHkxZ48sgOCLdVHjFU36N7TF1HhqAHLFOkV6buwZnvMI84Cug8xD56B9mCuKrqXnLn94417GrZ/jjCQ==
next@^15.2.6:
version "15.5.7"
resolved "https://registry.yarnpkg.com/next/-/next-15.5.7.tgz#4507700b2bbcaf2c9fb7a9ad25c0dac2ba4a9a75"
integrity sha512-+t2/0jIJ48kUpGKkdlhgkv+zPTEOoXyr60qXe68eB/pl3CMJaLeIGjzp5D6Oqt25hCBiBTt8wEeeAzfJvUKnPQ==
dependencies:
"@next/env" "15.3.2"
"@swc/counter" "0.1.3"
"@next/env" "15.5.7"
"@swc/helpers" "0.5.15"
busboy "1.6.0"
caniuse-lite "^1.0.30001579"
postcss "8.4.31"
styled-jsx "5.1.6"
optionalDependencies:
"@next/swc-darwin-arm64" "15.3.2"
"@next/swc-darwin-x64" "15.3.2"
"@next/swc-linux-arm64-gnu" "15.3.2"
"@next/swc-linux-arm64-musl" "15.3.2"
"@next/swc-linux-x64-gnu" "15.3.2"
"@next/swc-linux-x64-musl" "15.3.2"
"@next/swc-win32-arm64-msvc" "15.3.2"
"@next/swc-win32-x64-msvc" "15.3.2"
sharp "^0.34.1"
"@next/swc-darwin-arm64" "15.5.7"
"@next/swc-darwin-x64" "15.5.7"
"@next/swc-linux-arm64-gnu" "15.5.7"
"@next/swc-linux-arm64-musl" "15.5.7"
"@next/swc-linux-x64-gnu" "15.5.7"
"@next/swc-linux-x64-musl" "15.5.7"
"@next/swc-win32-arm64-msvc" "15.5.7"
"@next/swc-win32-x64-msvc" "15.5.7"
sharp "^0.34.3"
object-assign@^4:
version "4.1.1"
@@ -954,10 +931,10 @@ semver@^7.5.4:
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f"
integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==
semver@^7.7.2:
version "7.7.2"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58"
integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==
semver@^7.7.3:
version "7.7.3"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946"
integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==
send@^1.0.0, send@^1.1.0:
version "1.1.0"
@@ -992,36 +969,39 @@ setprototypeof@1.2.0:
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424"
integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==
sharp@^0.34.1:
version "0.34.2"
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.2.tgz#648bd639854dbe48047b0b420213c186d036b32d"
integrity sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg==
sharp@^0.34.3:
version "0.34.5"
resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.34.5.tgz#b6f148e4b8c61f1797bde11a9d1cfebbae2c57b0"
integrity sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==
dependencies:
color "^4.2.3"
detect-libc "^2.0.4"
semver "^7.7.2"
"@img/colour" "^1.0.0"
detect-libc "^2.1.2"
semver "^7.7.3"
optionalDependencies:
"@img/sharp-darwin-arm64" "0.34.2"
"@img/sharp-darwin-x64" "0.34.2"
"@img/sharp-libvips-darwin-arm64" "1.1.0"
"@img/sharp-libvips-darwin-x64" "1.1.0"
"@img/sharp-libvips-linux-arm" "1.1.0"
"@img/sharp-libvips-linux-arm64" "1.1.0"
"@img/sharp-libvips-linux-ppc64" "1.1.0"
"@img/sharp-libvips-linux-s390x" "1.1.0"
"@img/sharp-libvips-linux-x64" "1.1.0"
"@img/sharp-libvips-linuxmusl-arm64" "1.1.0"
"@img/sharp-libvips-linuxmusl-x64" "1.1.0"
"@img/sharp-linux-arm" "0.34.2"
"@img/sharp-linux-arm64" "0.34.2"
"@img/sharp-linux-s390x" "0.34.2"
"@img/sharp-linux-x64" "0.34.2"
"@img/sharp-linuxmusl-arm64" "0.34.2"
"@img/sharp-linuxmusl-x64" "0.34.2"
"@img/sharp-wasm32" "0.34.2"
"@img/sharp-win32-arm64" "0.34.2"
"@img/sharp-win32-ia32" "0.34.2"
"@img/sharp-win32-x64" "0.34.2"
"@img/sharp-darwin-arm64" "0.34.5"
"@img/sharp-darwin-x64" "0.34.5"
"@img/sharp-libvips-darwin-arm64" "1.2.4"
"@img/sharp-libvips-darwin-x64" "1.2.4"
"@img/sharp-libvips-linux-arm" "1.2.4"
"@img/sharp-libvips-linux-arm64" "1.2.4"
"@img/sharp-libvips-linux-ppc64" "1.2.4"
"@img/sharp-libvips-linux-riscv64" "1.2.4"
"@img/sharp-libvips-linux-s390x" "1.2.4"
"@img/sharp-libvips-linux-x64" "1.2.4"
"@img/sharp-libvips-linuxmusl-arm64" "1.2.4"
"@img/sharp-libvips-linuxmusl-x64" "1.2.4"
"@img/sharp-linux-arm" "0.34.5"
"@img/sharp-linux-arm64" "0.34.5"
"@img/sharp-linux-ppc64" "0.34.5"
"@img/sharp-linux-riscv64" "0.34.5"
"@img/sharp-linux-s390x" "0.34.5"
"@img/sharp-linux-x64" "0.34.5"
"@img/sharp-linuxmusl-arm64" "0.34.5"
"@img/sharp-linuxmusl-x64" "0.34.5"
"@img/sharp-wasm32" "0.34.5"
"@img/sharp-win32-arm64" "0.34.5"
"@img/sharp-win32-ia32" "0.34.5"
"@img/sharp-win32-x64" "0.34.5"
side-channel-list@^1.0.0:
version "1.0.0"
@@ -1063,13 +1043,6 @@ side-channel@^1.0.6, side-channel@^1.1.0:
side-channel-map "^1.0.1"
side-channel-weakmap "^1.0.2"
simple-swizzle@^0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
dependencies:
is-arrayish "^0.3.1"
source-map-js@^1.0.2:
version "1.2.1"
resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46"
@@ -1080,11 +1053,6 @@ statuses@2.0.1, statuses@^2.0.1:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
streamsearch@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764"
integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==
styled-jsx@5.1.6:
version "5.1.6"
resolved "https://registry.yarnpkg.com/styled-jsx/-/styled-jsx-5.1.6.tgz#83b90c077e6c6a80f7f5e8781d0f311b2fe41499"

94
bin/openapi-check.sh Executable file
View File

@@ -0,0 +1,94 @@
#!/usr/bin/env bash
set -euo pipefail
OPENAPI_SPEC="resources/openapi/openapi.json"
AUTO_COMMIT="${AUTO_COMMIT:-false}"
# Check that $OPENAPI_SPEC matches the current Malli schema definitions
if [[ -n "${GITHUB_SHA:-}" ]]; then
echo "Running OpenAPI check on commit: $GITHUB_SHA"
fi
# Generate the current OpenAPI spec from Malli schemas using write-openapi-spec-to-file!
# This creates $OPENAPI_SPEC directly
# Using the generate-openapi-spec command from metabase.cmd.core
yarn generate-openapi
ret=$?
if [[ $ret -ne 0 ]]; then
exit $ret
fi
if [[ ! -f "$OPENAPI_SPEC" ]]; then
echo "Error: $OPENAPI_SPEC does not exist!"
exit 1
fi
# Check if there are any differences between generated and committed versions
if ! git diff --exit-code "$OPENAPI_SPEC" >/dev/null 2>&1; then
echo "OpenAPI schema changes detected:"
git diff "$OPENAPI_SPEC"
if [[ "$AUTO_COMMIT" == "true" ]]; then
echo ""
echo "Auto-committing changes..."
# Require PR_BRANCH to be set for auto-commit
if [[ -z "${PR_BRANCH:-}" ]]; then
echo "Error: PR_BRANCH environment variable must be set for auto-commit"
exit 1
fi
# Stash the generated spec from the merge commit
echo "Stashing generated OpenAPI spec from merge commit..."
cp "$OPENAPI_SPEC" "${OPENAPI_SPEC}.tmp"
# Checkout the actual PR branch (in case we're on a merge commit)
echo "Checking out branch: $PR_BRANCH"
git checkout -f "$PR_BRANCH"
# Restore the generated spec from the merge commit
mv -f "${OPENAPI_SPEC}.tmp" "$OPENAPI_SPEC"
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
git add "$OPENAPI_SPEC"
# Build commit message with SHAs if available
COMMIT_MSG="Update OpenAPI schema"
if [[ -n "${BASE_SHA:-}" ]] && [[ -n "${HEAD_SHA:-}" ]]; then
BASE_SHORT="${BASE_SHA:0:7}"
HEAD_SHORT="${HEAD_SHA:0:7}"
COMMIT_MSG="Update OpenAPI schema (${BASE_SHORT}...${HEAD_SHORT})"
fi
git commit -m "$COMMIT_MSG"
if ! git push origin "$PR_BRANCH"; then
echo "Error: Failed to push OpenAPI schema update to $PR_BRANCH."
exit 1
fi
echo "OpenAPI schema updated and pushed to $PR_BRANCH."
exit 0
fi
echo "Error: OpenAPI specs are out of date!"
echo "The schema in $OPENAPI_SPEC does not match the current Malli schema definitions."
echo ""
echo "This can happen when:"
echo " 1. You added/modified API endpoints but didn't regenerate the OpenAPI spec"
echo " 2. Your branch is behind master, which has new API endpoints"
echo ""
echo "To fix this:"
echo " 1. Pull the latest changes from master: git pull origin master"
echo " 2. Run 'yarn generate-openapi' to update $OPENAPI_SPEC"
echo " 3. Commit the updated openapi.json file"
echo ""
echo "Differences:"
git diff "$OPENAPI_SPEC" || true
exit 1
fi
echo "OpenAPI specs are up to date."
exit 0

View File

@@ -47,8 +47,6 @@
com.github.jknack/handlebars ^:antq/exclude ; 4.4.0 requires java 17+
{:mvn/version "4.3.1"} ; templating engine
com.github.oliyh/martian-clj-http {:mvn/version "0.1.31"} ; openapi client
com.github.pangloss/transducers {:git/sha "c91d39046c8c64dc31b84ebb27154a8084fcda4c" ; like medley for transducers
:git/url "https://github.com/pangloss/transducers"}
com.github.seancorfield/honeysql {:mvn/version "2.7.1340"} ; Honey SQL 2. SQL generation from Clojure data maps
com.github.seancorfield/next.jdbc {:mvn/version "1.3.1070"} ; Talk to JDBC DBs
com.github.steffan-westcott/clj-otel-api {:mvn/version "0.2.8"} ; Telemetry library
@@ -76,7 +74,6 @@
commons-logging/commons-logging]}
compojure/compojure {:mvn/version "1.7.1" ; HTTP Routing library built on Ring
:exclusions [ring/ring-codec]}
crypto-random/crypto-random {:mvn/version "1.2.1"} ; library for generating cryptographically secure random bytes and strings
diehard/diehard {:mvn/version "0.12.0"}
dk.ative/docjure {:mvn/version "1.21.0" ; excel export
:exclusions [org.apache.poi/poi
@@ -85,14 +82,12 @@
hiccup/hiccup {:mvn/version "2.0.0"} ; HTML templating
inflections/inflections {:mvn/version "0.15.0"} ; Clojure/Script library used for prularizing words
instaparse/instaparse {:mvn/version "1.5.0"} ; Make your own parser
io.github.camsaul/toucan2 {:mvn/version "1.0.568"}
io.github.camsaul/toucan2 {:mvn/version "1.0.570"}
io.github.eerohele/pp {#_#_:git/tag "2024-11-13.77" ; super fast pretty-printing library
:git/sha "4998a1fdd9d3713d7034d04509e9212204773bf2"
:git/url "https://github.com/eerohele/pp"}
;; TODO: replace back to normal artifact
io.github.metabase/macaw {:mvn/version "0.2.29"} ; Parse native SQL queries
io.github.resilience4j/resilience4j-retry ^:antq/exclude ; 2.x do not support Java 8
{:mvn/version "1.7.1"} ; Support for retrying operations
io.github.metabase/macaw {:mvn/version "0.2.30"} ; Parse native SQL queries
io.netty/netty-codec-http {:mvn/version "4.2.9.Final"} ; override of transitive dep from aws s3
io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"} ; prometheus jvm collector
junegunn/grouper {:mvn/version "0.1.1"} ; Batch processing helper
kixi/stats {:mvn/version "0.5.7" ; Various statistic measures implemented as transducers
@@ -108,7 +103,8 @@
org.bouncycastle/bcprov-jdk18on]}
metabase/throttle {:mvn/version "1.0.2"} ; Tools for throttling access to API endpoints and other code pathways
methodical/methodical {:mvn/version "1.0.127"} ; drop-in replacements for Clojure multimethods and adds several advanced features
metosin/malli {:mvn/version "0.19.2"} ; Data-driven Schemas for Clojure/Script and babashka
metosin/malli {:git/url "https://github.com/metabase/malli" ; Data-driven Schemas for Clojure/Script and babashka
:git/sha "b4a2d78647a049870b316753d7aae7fb4ade3ae5"} ; patched to resolve an issue causing OOM
nano-id/nano-id {:mvn/version "1.1.0"} ; NanoID generator for generating entity_ids
net.cgrand/macrovich {:mvn/version "0.2.2"} ; utils for writing macros for both Clojure & ClojureScript
net.clojars.wkok/openai-clojure {:mvn/version "0.23.0"
@@ -120,12 +116,12 @@
junit/junit]}
net.thisptr/jackson-jq {:mvn/version "1.6.0"} ; Java implementation of the JQ json query language
org.apache.commons/commons-compress {:mvn/version "1.28.0"} ; compression utils
org.apache.commons/commons-lang3 {:mvn/version "3.18.0"} ; helper methods for working with java.lang stuff
org.apache.logging.log4j/log4j-1.2-api {:mvn/version "2.25.1"} ; apache logging framework
org.apache.logging.log4j/log4j-api {:mvn/version "2.25.1"} ; add compatibility with log4j 1.2
org.apache.logging.log4j/log4j-core {:mvn/version "2.25.1"} ; apache logging framework
org.apache.logging.log4j/log4j-jcl {:mvn/version "2.25.1"} ; allows the commons-logging API to work with log4j 2
org.apache.logging.log4j/log4j-jul {:mvn/version "2.25.1"} ; java.util.logging (JUL) -> Log4j2 adapter
org.apache.commons/commons-lang3 {:mvn/version "3.19.0"} ; helper methods for working with java.lang stuff
org.apache.logging.log4j/log4j-1.2-api {:mvn/version "2.25.3"} ; apache logging framework
org.apache.logging.log4j/log4j-api {:mvn/version "2.25.3"} ; add compatibility with log4j 1.2
org.apache.logging.log4j/log4j-core {:mvn/version "2.25.3"} ; apache logging framework
org.apache.logging.log4j/log4j-jcl {:mvn/version "2.25.3"} ; allows the commons-logging API to work with log4j 2
org.apache.logging.log4j/log4j-jul {:mvn/version "2.25.3"} ; java.util.logging (JUL) -> Log4j2 adapter
org.apache.logging.log4j/log4j-layout-template-json
{:mvn/version "2.25.1"} ; allows the custom json logging format
org.apache.logging.log4j/log4j-slf4j2-impl
@@ -138,7 +134,7 @@
org.apache.sshd/sshd-core {:mvn/version "2.16.0" ; ssh tunneling and test server
:exclusions [org.slf4j/slf4j-api
org.slf4j/jcl-over-slf4j]}
org.apache.tika/tika-core {:mvn/version "3.2.2"}
org.apache.tika/tika-core {:mvn/version "3.2.3"}
org.apache.xmlgraphics/batik-all {:mvn/version "1.19"} ; SVG -> image
org.bouncycastle/bcpkix-jdk18on {:mvn/version "1.81"} ; Bouncy Castle crypto library -- explicit version of BC specified to resolve illegal reflective access errors
org.bouncycastle/bcprov-jdk18on {:mvn/version "1.81"}
@@ -150,11 +146,9 @@
org.clojure/clojure {:mvn/version "1.12.2"}
org.clojure/core.async {:mvn/version "1.7.701"
:exclusions [org.clojure/tools.reader]}
org.clojure/core.logic {:mvn/version "1.1.0"} ; optimized pattern matching library for Clojure
org.clojure/core.match {:mvn/version "1.1.0"}
org.clojure/core.memoize {:mvn/version "1.1.266"} ; useful FIFO, LRU, etc. caching mechanisms
org.clojure/data.csv {:mvn/version "1.1.0"} ; CSV parsing / generation
org.clojure/data.xml {:mvn/version "0.2.0-alpha9"} ; XML parsing / generation
org.clojure/java.classpath {:mvn/version "1.1.0"} ; examine the Java classpath from Clojure programs
org.clojure/java.jdbc {:mvn/version "0.7.12"} ; basic JDBC access from Clojure
org.clojure/java.jmx {:mvn/version "1.1.0"} ; JMX bean library, for exporting diagnostic info
@@ -199,8 +193,8 @@
org.eclipse.jetty.ee9/jetty-ee9-servlet
org.eclipse.jetty.ee9.websocket/jetty-ee9-websocket-jetty-server]}
slingshot/slingshot {:mvn/version "0.12.2"} ; enhanced throw/catch, used by other deps
software.amazon.awssdk/s3 {:mvn/version "2.33.0"} ; AWS SDK v2 for S3
software.amazon.awssdk/sts {:mvn/version "2.33.0"} ; Required for S3 client to use service account
software.amazon.awssdk/s3 {:mvn/version "2.40.13"} ; AWS SDK v2 for S3
software.amazon.awssdk/sts {:mvn/version "2.36.2"} ; Required for S3 client to use service account
stencil/stencil {:mvn/version "0.5.0"} ; Mustache templates for Clojure
user-agent/user-agent {:mvn/version "0.1.1"} ; User-Agent string parser, for Login History page & elsewhere
weavejester/dependency {:mvn/version "1.0.0"} ; Dependency graphs and topological sorting
@@ -691,7 +685,7 @@
;;
;; ./bin/mage cljfmt-all -h for more info
:cljfmt
{:deps {io.github.weavejester/cljfmt {:git/sha "7de286008766127128a156275b9add3bf443d7e5"}}
{:deps {io.github.weavejester/cljfmt {:mvn/version "0.15.3"}}
:ns-default cljfmt.tool
:exec-fn cljfmt.tool/fix}

View File

@@ -355,8 +355,8 @@
([deps module-x module-y]
(let [module-x-ns->module-y-ns (->> (external-usages deps module-y)
(filter #(= (:module %) module-x))
(map (juxt :namespace :depends-on-namespace)))]
(filter #(= (:module %) module-x))
(map (juxt :namespace :depends-on-namespace)))]
(reduce
(fn [m [module-x-ns module-y-ns]]
(update m module-x-ns (fn [deps]

511
dev/src/dev/search_perf.clj Normal file
View File

@@ -0,0 +1,511 @@
(ns dev.search-perf
"Performance testing utilities for search with large numbers of tables,
users, and permission groups.
Example usage:
;; Run full benchmark with default settings (10000 tables, 10 groups, 100 users)
(run-full-benchmark!)
;; Run with custom settings
(run-full-benchmark! {:num-tables 10000
:num-groups 10
:num-users 100
:iterations 5})
;; Manual setup for interactive testing
(def test-env (create-test-environment! {:num-tables 1000
:num-groups 5
:num-users 50}))
(timed-search! \"table\" :user-id (:user-id test-env))
(cleanup-test-environment! test-env)"
(:require
[clojure.string :as str]
[dev.add-load :as add-load]
[metabase.api.common :as api]
[metabase.permissions.core :as perms]
[metabase.permissions.util :as perms-util]
[metabase.request.core :as request]
[metabase.search.config :as search.config]
[metabase.search.engine :as search.engine]
[metabase.search.impl :as search.impl]
[metabase.search.ingestion :as search.ingestion]
[metabase.util :as u]
[metabase.util.random :as u.random]
[toucan2.core :as t2]))
(set! *warn-on-reflection* true)
;;; -------------------------------------------- Setup Utilities: Database & Tables ------------------------------------
(defn- generate-table-name
"Generate a table name with a prefix and index for identification."
[prefix idx]
(format "%s_table_%05d" prefix idx))
(defn create-test-database!
"Create a test database for performance testing.
Returns the database ID."
[]
(let [{:keys [db-id]} (add-load/from-script
[[:model/Database {:?/db-id :id}
{:name (str "Search Perf Test DB " (u.random/random-name))
:engine :h2
:details {}}]])]
(perms/set-database-permission! (perms/all-users-group) db-id :perms/view-data :blocked)
(perms/set-database-permission! (perms/all-users-group) db-id :perms/create-queries :no)
db-id))
(defn create-tables-batch!
"Create a batch of tables for the given database.
Returns the number of tables created."
[db-id prefix start-idx cnt]
(let [script (vec
(for [i (range start-idx (+ start-idx cnt))]
[:model/Table {}
{:db_id db-id
:name (generate-table-name prefix i)
:description (format "Performance test table %d for search benchmarking" i)
:active true}]))]
(add-load/from-script script)
cnt))
(defn create-test-database-with-tables!
"Create a test database with the specified number of tables.
Tables are created in batches for better performance.
Options:
:batch-size - Number of tables per batch (default 500)
:prefix - Prefix for table names (default \"perf_test\")
Returns a map with :db-id and :table-ids."
([num-tables]
(create-test-database-with-tables! num-tables {}))
([num-tables {:keys [batch-size prefix]
:or {batch-size 500
prefix "perf_test"}}]
(let [db-id (create-test-database!)
num-batches (Math/ceil (/ num-tables batch-size))]
(println (format "Creating %d tables in %d batches of %d..."
num-tables (int num-batches) batch-size))
(let [timer (u/start-timer)]
(doseq [batch-num (range (int num-batches))]
(let [start-idx (* batch-num batch-size)
batch-count (min batch-size (- num-tables start-idx))]
(create-tables-batch! db-id prefix start-idx batch-count)
(when (zero? (mod (inc batch-num) 10))
(println (format " Created %d/%d tables..." (+ start-idx batch-count) num-tables)))))
(let [elapsed-ms (u/since-ms timer)
;; Get all table IDs for this database
table-ids (t2/select-pks-vec :model/Table :db_id db-id)]
(println (format "Created %d tables in %.2f seconds (%.1f tables/sec)"
num-tables
(/ elapsed-ms 1000.0)
(/ (* num-tables 1000.0) elapsed-ms)))
{:db-id db-id
:table-ids table-ids})))))
;;; -------------------------------------------- Setup Utilities: Groups & Users ---------------------------------------
(defn create-permission-groups!
"Create n permission groups for testing.
Returns a vector of group IDs."
[n run-id]
(println (format "Creating %d permission groups..." n))
(let [timer (u/start-timer)
prefix (str "Search Perf Group " run-id " ")
script (vec
(for [i (range n)]
[:model/PermissionsGroup {}
{:name (str prefix i)}]))
_ (add-load/from-script script)
;; Query for groups with our name pattern
group-ids (t2/select-pks-vec :model/PermissionsGroup :name [:like (str prefix "%")])
elapsed-ms (u/since-ms timer)]
(println (format "Created %d groups in %.2f seconds" n (/ elapsed-ms 1000.0)))
group-ids))
(defn create-users-with-memberships!
"Create n users and assign them to permission groups.
Each user is assigned to a subset of groups based on their index.
Users are also added to the All Users group automatically by the model.
Returns a vector of user IDs."
[n group-ids run-id]
(println (format "Creating %d users with group memberships..." n))
(let [timer (u/start-timer)
num-groups (count group-ids)
email-domain (str "perftest" run-id ".example.com")
;; Create users first
user-script (vec
(for [i (range n)]
[:model/User {}
{:first_name (format "PerfUser%d" i)
:last_name "Test"
:email (format "user%d@%s" i email-domain)
:password "password123"}]))
_ (add-load/from-script user-script)
;; Query for users by email pattern
user-ids (t2/select-pks-vec :model/User :email [:like (str "%@" email-domain)])]
;; Create group memberships - assign each user to some groups
;; User i gets assigned to groups where (mod i num-groups) matches certain patterns
(println " Assigning users to groups...")
(let [membership-script
(vec
(for [user-idx (range n)
group-idx (range num-groups)
;; Assign user to ~30% of groups based on a deterministic pattern
:when (zero? (mod (+ user-idx group-idx) 3))]
[:model/PermissionsGroupMembership {}
{:user_id (nth user-ids user-idx)
:group_id (nth group-ids group-idx)}]))]
(when (seq membership-script)
(add-load/from-script membership-script)))
(let [elapsed-ms (u/since-ms timer)]
(println (format "Created %d users with memberships in %.2f seconds" n (/ elapsed-ms 1000.0))))
user-ids))
(defn grant-table-permissions-to-groups!
"Grant table-level permissions to groups.
Each group gets permissions to a subset of tables based on deterministic assignment.
This creates a realistic permission scenario where different groups have access
to different tables.
Assignment strategy:
- Each group gets access to ~5% of tables
- Tables are assigned based on (mod table-idx 20) pattern with group offset
- This ensures overlapping but distinct permission sets"
[table-ids group-ids]
(println (format "Granting table-level permissions to %d groups for %d tables..."
(count group-ids) (count table-ids)))
(let [timer (u/start-timer)
num-groups (count group-ids)
;; Build permission assignments
;; Each group gets ~5% of tables (1 in 20) with offset based on group index
assignments (for [group-idx (range num-groups)
:let [group-id (nth group-ids group-idx)
;; Each group gets ~5% of tables with some overlap
;; Using mod 20 gives 5%, offset by group-idx for variation
assigned-tables (filterv
(fn [table-idx]
;; Deterministic pattern: group gets every 20th table
;; offset by group index to create variation between groups
(zero? (mod (+ table-idx group-idx) 20)))
(range (count table-ids)))]]
{:group-id group-id
:group-idx group-idx
:table-indices assigned-tables
:num-tables (count assigned-tables)})]
;; Grant permissions - batch by group for efficiency
(doseq [{:keys [group-id table-indices]} assignments]
(let [table-perms-view (into {} (for [tidx table-indices]
[(nth table-ids tidx) :unrestricted]))
table-perms-query (into {} (for [tidx table-indices]
[(nth table-ids tidx) :query-builder]))]
;; Use batch permission setting
(when (seq table-perms-view)
(perms/set-table-permissions! group-id :perms/view-data table-perms-view)
(perms/set-table-permissions! group-id :perms/create-queries table-perms-query))))
(let [elapsed-ms (u/since-ms timer)]
(println (format "Granted table permissions in %.2f seconds" (/ elapsed-ms 1000.0))))))
;;; -------------------------------------------- Test Environment Management -------------------------------------------
(defn create-test-environment!
"Create a complete test environment with database, tables, groups, users, and permissions.
Options:
:num-tables - Number of tables to create (default 10000)
:num-groups - Number of permission groups (default 10)
:num-users - Number of users (default 100)
:prefix - Table name prefix (default \"perf_test\")
Returns a map containing:
:db-id - Database ID
:table-ids - Vector of table IDs
:group-ids - Vector of group IDs
:user-ids - Vector of user IDs
:user-id - ID of a sample non-admin user for testing
:run-id - Unique identifier for this test run"
([]
(create-test-environment! {}))
([{:keys [num-tables num-groups num-users prefix]
:or {num-tables 10000
num-groups 10
num-users 100
prefix "perf_test"}}]
(println "\n=== Creating Test Environment ===")
(let [timer (u/start-timer)
run-id (u.random/random-name)
;; Create database and tables
{:keys [db-id table-ids]} (create-test-database-with-tables! num-tables {:prefix prefix})
;; Create permission groups
group-ids (create-permission-groups! num-groups run-id)
;; Grant table-level permissions to groups
_ (grant-table-permissions-to-groups! table-ids group-ids)
;; Create users with group memberships
user-ids (create-users-with-memberships! num-users group-ids run-id)
;; Pick a user in the middle for testing
test-user-id (nth user-ids (quot num-users 2))
elapsed-ms (u/since-ms timer)]
(println (format "Test environment created in %.2f seconds" (/ elapsed-ms 1000.0)))
(println (format " Run ID: %s" run-id))
(println (format " Database: %d" db-id))
(println (format " Tables: %d" num-tables))
(println (format " Groups: %d" num-groups))
(println (format " Users: %d" num-users))
(println (format " Test user ID: %d" test-user-id))
{:db-id db-id
:table-ids table-ids
:group-ids group-ids
:user-ids user-ids
:user-id test-user-id
:run-id run-id
:num-tables num-tables})))
(defn cleanup-test-environment!
"Delete all resources created by create-test-environment!"
[{:keys [db-id group-ids user-ids]}]
(println "\n=== Cleaning Up Test Environment ===")
(let [timer (u/start-timer)]
;; Delete group memberships first (foreign key constraints)
(when (seq user-ids)
(println (format "Deleting memberships for %d users..." (count user-ids)))
(t2/delete! :model/PermissionsGroupMembership :user_id [:in user-ids] :group_id [:<> 1]))
;; Delete users
(when (seq user-ids)
(println (format "Deleting %d users..." (count user-ids)))
(t2/delete! :model/User :id [:in user-ids]))
;; Delete data permissions for groups
(when (seq group-ids)
(println (format "Deleting permissions for %d groups..." (count group-ids)))
(t2/delete! :model/DataPermissions :group_id [:in group-ids]))
;; Delete groups
(when (seq group-ids)
(println (format "Deleting %d groups..." (count group-ids)))
(t2/delete! :model/PermissionsGroup :id [:in group-ids]))
;; Delete tables and database
(when db-id
(let [table-count (t2/count :model/Table :db_id db-id)]
(println (format "Deleting database %d and %d tables..." db-id table-count))
(t2/delete! :model/Table :db_id db-id)
(t2/delete! :model/Database :id db-id)))
(let [elapsed-ms (u/since-ms timer)]
(println (format "Cleanup completed in %.2f seconds" (/ elapsed-ms 1000.0))))))
;;; ------------------------------------------------ Search Utilities -----------------------------------------------
(defn- search-context-for-user
"Build a search context for a specific user."
[user-id search-string models]
(request/with-current-user user-id
(search.impl/search-context
{:current-user-id api/*current-user-id*
:current-user-perms @api/*current-user-permissions-set*
:is-superuser? api/*is-superuser?*
:is-impersonated-user? (perms-util/impersonated-user?)
:is-sandboxed-user? (perms-util/impersonated-user?)
:archived false
:context :default
:search-string search-string
:models models
:model-ancestors? false})))
(defn search!
"Execute a search and return the results.
Options:
:user-id - User ID to run search as (required)
:models - Models to search (default all models)"
[search-string & {:keys [user-id models]
:or {models search.config/all-models}}]
(assert user-id "user-id is required for search!")
(let [ctx (search-context-for-user user-id search-string models)]
(search.engine/results ctx)))
(defn timed-search!
"Execute a search and return timing information along with result count.
Options:
:user-id - User ID to run search as (required)
:models - Models to search (default all models)
Returns {:elapsed-ms <time> :result-count <count>}"
[search-string & {:keys [user-id models]
:or {models search.config/all-models}}]
(assert user-id "user-id is required for timed-search!")
(let [timer (u/start-timer)
results (search! search-string :user-id user-id :models models)
elapsed (u/since-ms timer)]
{:elapsed-ms elapsed
:result-count (count results)}))
;;; ------------------------------------------------ Benchmark Functions --------------------------------------------
(defn run-search-benchmark!
"Run a search benchmark with the given search string.
Options:
:user-id - User ID to run search as (required)
:iterations - Number of search iterations (default 5)
:models - Models to search (default all models)
:warmup - Number of warmup iterations (default 2)
Returns a map with benchmark statistics."
([search-string opts]
(let [{:keys [user-id iterations warmup models]
:or {iterations 5
warmup 2
models search.config/all-models}} opts]
(assert user-id "user-id is required for benchmark!")
(println (format "\nRunning search benchmark for: \"%s\" (user-id: %d)" search-string user-id))
(println (format " Warmup iterations: %d" warmup))
(println (format " Benchmark iterations: %d" iterations))
;; Warmup
(when (pos? warmup)
(println " Warming up...")
(dotimes [_ warmup]
(search! search-string :user-id user-id :models models)))
;; Benchmark
(println " Running benchmark...")
(let [results (vec (for [i (range iterations)]
(let [result (timed-search! search-string :user-id user-id :models models)]
(println (format " Iteration %d: %.2fms (%d results)"
(inc i)
(:elapsed-ms result)
(:result-count result)))
result)))
times (mapv :elapsed-ms results)
avg (/ (reduce + times) (count times))
min-t (apply min times)
max-t (apply max times)
sorted (sort times)
p50 (nth sorted (int (* 0.5 (count sorted))))
p95 (nth sorted (int (* 0.95 (dec (count sorted)))))]
(println "\n Results:")
(println (format " Average: %.2fms" avg))
(println (format " Min: %.2fms" min-t))
(println (format " Max: %.2fms" max-t))
(println (format " P50: %.2fms" p50))
(println (format " P95: %.2fms" p95))
{:search-string search-string
:user-id user-id
:iterations iterations
:result-count (:result-count (first results))
:avg-ms avg
:min-ms min-t
:max-ms max-t
:p50-ms p50
:p95-ms p95
:all-times-ms times}))))
(defn run-full-benchmark!
"Run a full benchmark suite with multiple search queries.
Creates a test environment with database, tables, groups, and users,
runs benchmarks with various search patterns using a non-admin user,
and optionally cleans up the test data.
Options:
:num-tables - Number of tables to create (default 10000)
:num-groups - Number of permission groups (default 10)
:num-users - Number of users (default 100)
:iterations - Benchmark iterations per query (default 5)
:cleanup? - Whether to cleanup after (default true)
:prefix - Table name prefix (default \"perf_test\")
Returns benchmark results for all queries."
([]
(run-full-benchmark! {}))
([{:keys [num-tables num-groups num-users iterations cleanup? prefix]
:or {num-tables 10000
num-groups 10
num-users 100
iterations 5
cleanup? true
prefix "perf_test"}}]
(println (format "\n%s" (str/join (repeat 60 "="))))
(println "SEARCH PERFORMANCE BENCHMARK (Non-Admin User)")
(println (str/join (repeat 60 "=")))
(println "\nConfiguration:")
(println (format " Tables: %d" num-tables))
(println (format " Permission Groups: %d" num-groups))
(println (format " Users: %d" num-users))
(println (format " Iterations per query: %d" iterations))
(let [test-env (create-test-environment! {:num-tables num-tables
:num-groups num-groups
:num-users num-users
:prefix prefix})
user-id (:user-id test-env)
;; Wait for search index to update if using async indexing
_ (binding [search.ingestion/*force-sync* true]
(Thread/sleep 1000))
queries [;; Exact prefix match
(str prefix "_table_00001")
;; Partial prefix match
(str prefix "_table")
;; Generic term that should match descriptions
"performance test"
;; Broad search
"table"
;; Very specific search
(str prefix "_table_05000")]]
(try
(let [results (vec (for [query queries]
(run-search-benchmark! query {:user-id user-id
:iterations iterations})))]
(println (format "\n%s" (str/join (repeat 60 "="))))
(println "SUMMARY")
(println (str/join (repeat 60 "=")))
(doseq [{:keys [search-string avg-ms result-count]} results]
(println (format " \"%s\": %.2fms avg, %d results"
search-string avg-ms result-count)))
{:results results
:test-env test-env})
(finally
(when cleanup?
(cleanup-test-environment! test-env)))))))
(comment
;; Example usage:
;; Quick test with fewer tables/users
(run-full-benchmark! {:num-tables 1
:num-groups 5
:num-users 4
:iterations 1})
;; Full benchmark with 10,000 tables
(run-full-benchmark! {:num-tables 10000
:num-groups 25
:num-users 100
:iterations 10})
;; {:p95-ms 539.613833, :result-count 10000, :avg-ms 536.6528708, :min-ms 529.310541, :all-times-ms [548.471834 534.8465 538.846875 536.401583 535.707 ...], ...}
;; {:p95-ms 366.195458, :result-count 10000, :avg-ms 360.5523999, :min-ms 352.951208, :all-times-ms [355.839542 366.195458 352.951208 356.9155 362.09225 ...], ...}
;; {:p95-ms 110.475333, :result-count 4000, :avg-ms 108.0612666, :min-ms 105.713041, :all-times-ms [112.747333 108.450292 107.548208 105.93625 108.159375 ...], ...}
;; Manual setup for interactive testing
(def test-env (create-test-environment! {:num-tables 1000
:num-groups 35
:num-users 200}))
;; Run individual searches with the non-admin user
(e/explain
(timed-search! "perf_test_table" :user-id (:user-id test-env)))
(timed-search! "table" :user-id (:user-id test-env) :models #{"table"})
(require '[dev.explain-analyze :as e])
;; Try with different users
(e/explain
(timed-search! "table" :user-id (first (:user-ids test-env))))
(timed-search! "table" :user-id (last (:user-ids test-env)))
;; Cleanup
(cleanup-test-environment! test-env))

View File

@@ -37,7 +37,7 @@ The core team runs a pretty well defined product process. It is actively being t
### A) Identify product needs from the community
We actively look for new feature ideas from our community, user base and our own use of Metabase internally. We concentrate on the underlying _problem_ or _need_ as opposed to requests for specific features. While sometimes suggested features are built as requested, often we find that they involve changes to existing features, and perhaps an entirely different solution to the underlying problem. These will typically be collected in a number of issues, and tagged [Proposal](https://github.com/metabase/metabase/labels/.Proposal)
We actively look for new feature ideas from our community, user base and our own use of Metabase internally. We concentrate on the underlying _problem_ or _need_ as opposed to requests for specific features. While sometimes suggested features are built as requested, often we find that they involve changes to existing features, and potentially an entirely different solution to the underlying problem. These will typically be collected in a number of issues, and tagged [Proposal](https://github.com/metabase/metabase/labels/.Proposal)
### B) Synthesize these needs into a concrete feature
@@ -107,4 +107,4 @@ Generally speaking, any issue in [Help Wanted](https://github.com/metabase/metab
### #YOLO JUST SUBMIT A PR
If you come up with something really cool, and want to share it with us, just submit a PR. If it hasn't gone through the above process, we probably won't merge it as is, but if it's compelling, we're more than willing to help you via code review, design review and generally OCD nitpicking so that it fits into the rest of our codebase.
If you come up with something cool, and want to share it with us, just submit a PR. If it hasn't gone through the above process, we probably won't merge it as is, but if it's compelling, we're more than willing to help you via code review, design review and generally OCD nitpicking so that it fits into the rest of our codebase.

View File

@@ -55,7 +55,7 @@ There are multiple ways to run actions:
Just something to clarify here: actions, even though they are added to models, make their changes to the underlying table that a model queries. Which means that anyone who has access to the underlying table, or to questions or other models based on that table, will be able to see the effects of an action. Tools other than Metabase that are connected to that database will also pick up these changes.
In this sense, models are containers for actions; models are a way to organize actions. In fact, you could (in theory) add a [custom action](./custom.md) to a model that performs some update unrelated to its model's data. For example, you could write a custom action that updates the `Accounts` table, and add that action to a model that only queries an unrelated table (e.g., the `Orders` table). But, you know, maybe don't do that (unless you have a really good reason). [Basic actions](./basic.md), however, are only be available for models that wrap a single raw table.
In this sense, models are containers for actions; models are a way to organize actions. In fact, you could (in theory) add a [custom action](./custom.md) to a model that performs some update unrelated to its model's data. For example, you could write a custom action that updates the `Accounts` table, and add that action to a model that only queries an unrelated table (e.g., the `Orders` table). But, you know, maybe don't do that (unless you have a good reason). [Basic actions](./basic.md), however, are only be available for models that wrap a single raw table.
Before using actions in production, consider playing around with actions on some sample data (like the Sample Database included with Metabase) to get a feel for how they work.

Binary file not shown.

After

Width:  |  Height:  |  Size: 228 KiB

View File

@@ -5,14 +5,14 @@ summary: Metabot is Metabase's AI assistant that helps you analyze data, create
# Metabot - Metabase's AI assistant
{% include beta-blockquote.html
message="For now, <a href='https://www.metabase.com/features/metabot-ai'>Metabot</a> is only available as an add-on for Pro and Enterprise plans on Metabase Cloud."
%}
> Metabot is only available as an add-on on Metabase Cloud.
![Meet Metabot](./images/metabot.png)
Metabot helps you analyze your data by creating charts from natural language, generating SQL queries, fixing query errors, and analyzing existing visualizations.
## Set up Metabot
To set up Metabot, see [Metabot settings](./settings.md).
## What Metabot can do
@@ -21,6 +21,7 @@ Metabot can help you to:
- [Create a chart using the query builder](#how-metabot-uses-the-query-builder) from a natural language query.
- [Generate SQL in the native editor](../questions/native-editor/writing-sql.md) from natural language. (Currently, only SQL is supported.)
- [Edit SQL directly in the native editor](#inline-sql-editing).
- [Analyze a chart](#analyze-charts-with-metabot).
- [Fix errors in SQL code](#have-metabot-fix-sql-queries).
- Answer questions from our documentation (as in, the literature you're reading right now).
@@ -46,6 +47,7 @@ Some tips:
- Whenever you want Metabot to do something completely different, you should reset the conversation, as Metabot might find that irrelevant historical context to be confusing.
- Once Metabot creates a question for you, you can follow up with more questions or take over yourself. You can drill through the chart or step into the editor to tweak the query (both in the query builder and the SQL editor).
- Metabot works best with English prompts. While it might understand other languages, you'll get the most reliable results by asking your questions in English.
- Define domain-specific terms in the [glossary](../exploration-and-organization/data-model-reference.md#glossary) to help Metabot understand your organization's terminology.
### Metabot response menu
@@ -92,6 +94,17 @@ If you don't specify a specific table in a natural language question, Metabot wi
When you get an error in a SQL query, you can click the **Have Metabot fix it** button, and Metabot will try to correct the query. You can also ask Metabot to fix your SQL in the chat.
## Inline SQL editing
![Using inline SQL editing](./images/inline-sql.png)
You can ask Metabot to generate or edit code in the SQL editor, without using the [chat sidebar](#the-metabot-chat-sidebar):
1. Open the [SQL editor](../questions/native-editor/writing-sql.md).
2. Press Cmd+; on Mac or Ctrl+; on Windows.
3. Describe the SQL you want to generate or modify.
4. Review the generated code and accept or reject it.
## Navigating after Metabot creates a chart
If Metabot creates a query or takes you to a new item but you want to return to the previous screen, you can navigate using your browser's back button.

View File

@@ -5,9 +5,7 @@ summary: Configure Metabot settings, including which collections Metabot can acc
# Metabot AI settings
{% include beta-blockquote.html
message="For now, <a href='https://www.metabase.com/features/metabot-ai'>Metabot</a> is only available as an add-on for Pro and Enterprise plans on Metabase Cloud."
%}
> Metabot is only available as an add-on on Metabase Cloud.
_Settings > Admin settings > AI_
@@ -15,17 +13,33 @@ This page covers admin settings for Metabase's AI assistant, [Metabot](./metabot
![Admin settings for AI Metabot](./images/ai-settings.png)
Before using Metabot in your Metabase, you'll need to add the Metabot add-on to your instance in Metabase Store.
## Add Metabot from the Metabase Store
For now, Metabot is only available for Metabase Cloud. Before you can set up Metabot in your Metabase, you'll need to add Metabot to your subscription from the Metabase Store.
1. Go to [store.metabase.com](https://store.metabase.com).
2. Log in with your **Metabase Store account** (distinct from the account you use to log into your Metabase).
3. In the **Instances** tab, find the instance you'd like to add Metabot to, and click "Add Metabot AI".
4. Pick the plan based on the number of requests you expect you'll need.
A "request" is any message anyone in your Metabase sends to Metabot. Several messages sent within the same chat session are counted as separate requests. Requests are added across the entire instance.
5. Read through the [terms of service](https://www.metabase.com/license/hosting) and click **Add Metabot AI**.
Once you've added Metabot AI in the Metabase store, you can log into your Metabase and configure it in _Admin settings > AI_.
## Verified content
Admins on Pro and Enterprise plans can tell Metabot to only work with [models](../data-modeling/models.md) and [metrics](../data-modeling/metrics.md) that have been [verified](../exploration-and-organization/content-verification.md).
Restricting Metabot to verified models and metrics (and only models and metrics) can help Metabot produce more reliable answers, since you know someone has at least vetted the data Metabot can use.
Restricting Metabot to verified models and metrics (and only models and metrics) helps Metabot produce more reliable answers, since you know someone has at least vetted the data Metabot can use.
## When embedding Metabot, you can pick a collection for Metabot to have access to
When embedding Metabot in your app, you can select a collection for Metabot:
1. Go to **Settings** > **Admin settings** > **AI**.
2. Click **Embedded Metabot**.
3. In the **Collection Embedded Metabot can use** section, click **Pick a collection**.
4. Select the collection that contains the models and metrics you want Metabot to use.
@@ -38,17 +52,11 @@ Alternatively (or additionally), you can restrict Metabot to [verified content](
The best thing you can do to improve Metabot's performance is to prep your data like you would for onboarding a new (human) hire to your data. In practice, this means you should:
- [Add models and metrics to your Metabot collection](#add-models-and-metrics-to-your-metabot-collection)
- [Add descriptions for your data and content](#add-descriptions-for-your-data-and-content)
- [Make sure the semantic types for each field are correct](#make-sure-the-semantic-types-for-each-field-are-correct)
- [Define domain-specific terms in the glossary](#define-domain-specific-terms-in-the-glossary)
- [Curate prompt suggestions](#curate-prompt-suggestions)
### Add models and metrics to your Metabot collection
Create models that make it easy for Metabot to find answers to the kinds of questions you expect people to ask about your data. Create metrics that capture key business calculations that people frequently need to reference. Add these models and metrics to the collection you've designated for Metabot to learn from.
For example, if people often ask questions about customer lifetime value (LTV), create a model that joins customer data with order history and calculates LTV. Or if people frequently need to know monthly active users (MAU), create a metric that defines exactly how MAU should be calculated.
### Add descriptions for your data and content
Add descriptions to your [models](../data-modeling/models.md#add-metadata-to-columns-in-a-model), [metrics](../data-modeling/metrics.md), [dashboards](../dashboards/introduction.md), and [questions](../questions/introduction.md). Write descriptions to provide context, define terms, and explain business logic.
@@ -69,6 +77,12 @@ Make sure the semantic types for each field accurately describe the field's "mea
Metabase will try to set semantic types automatically, but you should confirm that each field has the relevant semantic type. See [Data types and semantic types](../data-modeling/semantic-types.md). You can also set semantic types for [models](../data-modeling/models.md#add-metadata-to-columns-in-a-model).
### Define domain-specific terms in the glossary
Add your organization's terminology, acronyms, and business-specific terms to the [glossary](../exploration-and-organization/data-model-reference.md#glossary). When Metabot receives a prompt, it can look up terms in the glossary to better understand your request.
For example, if you define "MRR" as "Monthly Recurring Revenue" in your glossary, Metabot will know what you mean when you ask "What's our MRR for Q4?" This is especially helpful for industry-specific jargon, internal product names, or abbreviations unique to your organization.
### Curate prompt suggestions
When you select a collection for Metabot to "learn", Metabot will suggest a series of prompts based on the content it finds in that collection. These prompts just give people a feel for the kinds of things people can ask Metabot to do.
@@ -81,9 +95,17 @@ Metabot inherits the permissions of the current user, so you don't need to set p
In other words, to restrict what data Metabot can see for each person, simply apply [data](../permissions/data.md) and [collection](../permissions/collections.md) permissions to their groups as you would normally, and those permissions will apply to their use of Metabot as well.
## Metabot is only available instance-wide, not per person
## Viewing Metabot usage
Currently, Metabot will be available to everyone who uses your Metabase.
You can see how many Metabot requests people have made this month by going to **Admin settings > Settings > License**.
If you aren't logged into the [Metabase Store](../cloud/accounts-and-billing.md).(, you'll need to log in to the store before you can view the usage. Once logged in to the store, go back to your Metabase and view the license page.
The **Metabot AI requests used, this month (updated daily)** field shows how many requests your Metabase has used this month. Each message sent to Metabot counts as a request.
## Metabot can't be enabled per person
Currently, Metabot is available to everyone who uses your Metabase.
## Metabot uses a variety of generative AI models to answer your questions
@@ -99,7 +121,7 @@ We've intentionally limited what Metabot can do. Metabot lacks access to API key
Metabot has access to your Metabase metadata and some data values to help answer your questions:
- **Table, Question, Model, Dashboard, and Metric metadata**: Metabot can see the structure and configuration of your content
- **Table, Question, Model, Dashboard, and Metric metadata**: Metabot can see the structure and configuration of your content.
- **Sample field values**: When you ask questions like "Filter everyone from Wisconsin," Metabot might check the values in the state field to understand how the data is stored (like "WI" vs "Wisconsin"). See [syncs](../databases/sync-scan.md).
- **Timeseries data**: For chart analysis, Metabot might see the timeseries data used to draw certain visualizations, depending on the chart type.

View File

@@ -4,9 +4,7 @@ title: "AI in Metabase"
# AI in Metabase
{% include beta-blockquote.html %}
> For now, [Metabot](https://www.metabase.com/features/metabot-ai) is only available as an add-on for Pro and Enterprise plans on Metabase Cloud.
> Metabot is only available as an add-on for Metabase Cloud.
## [Metabot](./metabot.md)

File diff suppressed because one or more lines are too long

30754
docs/api.json Normal file

File diff suppressed because one or more lines are too long

View File

@@ -30,6 +30,7 @@ To change regions, go to your [Metabase Store page](https://store.metabase.com/)
- US East (North Virginia)
- Europe (Frankfurt)
- Asia Pacific (Singapore)
- Asia Pacific (Sydney)
- South America (São Paulo)
## Add the relevant IP addresses to your whitelist

View File

@@ -34,7 +34,7 @@ Here's how to set it up:
5. Give the service account **Viewer** permissions. Metabase will only have access to this folder or sheet; it won't have access to any other files in your Google Drive. If you select folder, Metabase will also sync any sheets it finds in any subfolders.
6. Click **Send** to share the folder with the Metabase service account.
7. Copy the sharing link for the folder or sheet.
8. Return to Metabase and paste the sharing link into the field that asks for "the sharing link for this folder/file".
8. Return to Metabase and paste the sharing link into "the sharing link for this folder/file" field.
**If you synced a Google Drive folder**, Metabase will sync with the Google Drive folder (and its subfolders) and import all Google Sheets, creating a new table in your Metabase Cloud Storage database for each sheet. For sheets with multiple tabs, Metabase will create a table for each tab. Metabase will only sync Google Sheets; it'll ignore other file types in the folder. After the initial sync, Metabase will sync every 15 minutes.

Some files were not shown because too many files have changed in this diff Show More