Compare commits
16 Commits
loading/ne
...
attach-ren
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ff11bd7f79 | ||
|
|
39c81419e8 | ||
|
|
0d95540349 | ||
|
|
f3a26b5135 | ||
|
|
a5c33e1756 | ||
|
|
b89f86c568 | ||
|
|
e108633f36 | ||
|
|
a54ef9bc99 | ||
|
|
9705d8976f | ||
|
|
a222ac98c0 | ||
|
|
520b1f6320 | ||
|
|
4a9d63ebc7 | ||
|
|
e16bfa4a76 | ||
|
|
d0148baa24 | ||
|
|
3e5d3985d8 | ||
|
|
6a61796277 |
@@ -20,143 +20,15 @@
|
||||
:use {:level :warning}
|
||||
:warn-on-reflection {:level :warning}
|
||||
|
||||
:metabase/defsetting-must-specify-export {:level :warning}
|
||||
:metabase/mbql-query-first-arg {:level :warning}
|
||||
:metabase/missing-test-expr-requires-in-cljs {:level :warning}
|
||||
:metabase/require-shape-checker {:level :warning}
|
||||
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning}
|
||||
:metabase/validate-logging {:level :warning}
|
||||
|
||||
:metabase/validate-deftest
|
||||
{:level :warning
|
||||
|
||||
;; calling these functions will result in an error in tests marked `^:parallel`
|
||||
;;
|
||||
;; TODO -- these should all be made thread safe if possible or renamed so they end in `!`. Then we can remove them
|
||||
;; from this list because by default anything ending in `!` is considered to be thread-unsafe
|
||||
:parallel/unsafe
|
||||
#{clojure.core/alter-var-root
|
||||
clojure.core/with-redefs
|
||||
clojure.core/with-redefs-fn
|
||||
metabase.actions.test-util/with-actions
|
||||
metabase.actions.test-util/with-actions-disabled
|
||||
metabase.actions.test-util/with-actions-enabled
|
||||
metabase.actions.test-util/with-actions-test-data
|
||||
metabase.actions.test-util/with-actions-test-data-and-actions-enabled
|
||||
metabase.actions.test-util/with-actions-test-data-tables
|
||||
metabase.analytics.snowplow-test/with-fake-snowplow-collector
|
||||
metabase.email-test/with-expected-messages
|
||||
metabase.email-test/with-fake-inbox
|
||||
metabase.test.data.users/with-group
|
||||
metabase.test.data.users/with-group-for-user
|
||||
metabase.test.data/with-empty-h2-app-db
|
||||
metabase.test.util.log/with-log-level
|
||||
metabase.test.util.misc/with-single-admin-user
|
||||
metabase.test.util/with-all-users-permission
|
||||
metabase.test.util/with-discarded-collections-perms-changes
|
||||
metabase.test.util/with-env-keys-renamed-by
|
||||
metabase.test.util/with-locale
|
||||
metabase.test.util/with-model-cleanup
|
||||
metabase.test.util/with-non-admin-groups-no-root-collection-for-namespace-perms
|
||||
metabase.test.util/with-non-admin-groups-no-root-collection-perms
|
||||
metabase.test.util/with-temp-env-var-value
|
||||
metabase.test.util/with-temp-vals-in-db
|
||||
metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test.util/with-temporary-setting-values
|
||||
metabase.test.util/with-user-in-groups
|
||||
metabase.test/with-actions
|
||||
metabase.test/with-actions-disabled
|
||||
metabase.test/with-actions-enabled
|
||||
metabase.test/with-actions-test-data
|
||||
metabase.test/with-actions-test-data-and-actions-enabled
|
||||
metabase.test/with-actions-test-data-tables
|
||||
metabase.test/with-all-users-permission
|
||||
metabase.test/with-discarded-collections-perms-changes
|
||||
metabase.test/with-empty-h2-app-db
|
||||
metabase.test/with-env-keys-renamed-by
|
||||
metabase.test/with-expected-messages
|
||||
metabase.test/with-fake-inbox
|
||||
metabase.test/with-group
|
||||
metabase.test/with-group-for-user
|
||||
metabase.test/with-locale
|
||||
metabase.test/with-log-level
|
||||
metabase.test/with-model-cleanup
|
||||
metabase.test/with-non-admin-groups-no-root-collection-for-namespace-perms
|
||||
metabase.test/with-non-admin-groups-no-root-collection-perms
|
||||
metabase.test/with-single-admin-user
|
||||
metabase.test/with-temp-env-var-value
|
||||
metabase.test/with-temp-vals-in-db
|
||||
metabase.test/with-temporary-raw-setting-values
|
||||
metabase.test/with-temporary-setting-values
|
||||
metabase.test/with-user-in-groups}
|
||||
|
||||
;; these functions are allowed in `^:parallel` tests even tho they end in `!`
|
||||
:parallel/safe
|
||||
#{clojure.core/assoc!
|
||||
clojure.core/compare-and-set!
|
||||
clojure.core/conj!
|
||||
clojure.core/disj!
|
||||
clojure.core/dissoc!
|
||||
clojure.core/persistent!
|
||||
clojure.core/pop!
|
||||
clojure.core/reset!
|
||||
clojure.core/reset-vals!
|
||||
clojure.core/run!
|
||||
clojure.core/swap!
|
||||
clojure.core/swap-vals!
|
||||
clojure.core/volatile!
|
||||
clojure.core/vreset!
|
||||
clojure.core/vswap!
|
||||
clojure.core.async/<!
|
||||
clojure.core.async/<!!
|
||||
clojure.core.async/>!
|
||||
clojure.core.async/>!!
|
||||
clojure.core.async/alt!
|
||||
clojure.core.async/alt!!
|
||||
clojure.core.async/alts!
|
||||
clojure.core.async/alts!!
|
||||
clojure.core.async/close!
|
||||
clojure.core.async/ioc-alts!
|
||||
clojure.core.async/offer!
|
||||
clojure.core.async/onto-chan!
|
||||
clojure.core.async/onto-chan!!
|
||||
clojure.core.async/poll!
|
||||
clojure.core.async/put!
|
||||
clojure.core.async/take!
|
||||
clojure.core.async/to-chan!
|
||||
clojure.core.async/to-chan!!
|
||||
metabase.driver.sql-jdbc.execute/execute-prepared-statement!
|
||||
metabase.pulse/send-pulse!
|
||||
metabase.query-processor.store/store-database!
|
||||
next.jdbc/execute!}}
|
||||
|
||||
:metabase/i-like-making-cams-eyes-bleed-with-horrifically-long-tests
|
||||
{:level :warning
|
||||
:max-length 180}
|
||||
|
||||
;; this is not enabled here, it is enabled below only for specific namespaces.
|
||||
:metabase/disallow-hardcoded-driver-names-in-tests
|
||||
;; don't include `:h2` since that will probably lead to a mountain of tests where we are specifically testing
|
||||
;; middleware or compilation behavior with just H2 since it's the default.
|
||||
{:drivers #{ ;; core drivers
|
||||
#_:h2
|
||||
:postgres
|
||||
:mysql
|
||||
;; module drivers
|
||||
:athena
|
||||
:bigquery-cloud-sdk
|
||||
:druid
|
||||
:druid-jdbc
|
||||
:googleanalytics
|
||||
:mongo
|
||||
:oracle
|
||||
:presto-jdbc
|
||||
:redshift
|
||||
:snowflake
|
||||
:sparksql
|
||||
:sqlite
|
||||
:sqlserver
|
||||
:vertica}}
|
||||
:metabase/defsetting-must-specify-export {:level :warning}
|
||||
:metabase/i-like-making-cams-eyes-bleed-with-horrifically-long-tests {:level :warning}
|
||||
:metabase/mbql-query-first-arg {:level :warning}
|
||||
:metabase/missing-test-expr-requires-in-cljs {:level :warning}
|
||||
:metabase/require-shape-checker {:level :warning}
|
||||
:metabase/test-helpers-use-non-thread-safe-functions {:level :warning}
|
||||
:metabase/validate-deftest {:level :warning}
|
||||
:metabase/validate-logging {:level :warning}
|
||||
:metabase/warn-about-schema= {:level :warning}
|
||||
|
||||
;;
|
||||
;; disabled linters
|
||||
@@ -181,7 +53,7 @@
|
||||
(clojure.core.logic/fresh)
|
||||
(clojure.core.logic/matcha)
|
||||
(clojure.core.logic/run)
|
||||
(clojure.test/is [query= =? malli= qv=])
|
||||
(clojure.test/is [query= =? malli=])
|
||||
(clojure.tools.macro/macrolet)
|
||||
instaparse.core/transform
|
||||
(metabase.async.streaming-response/streaming-response)
|
||||
@@ -235,7 +107,6 @@
|
||||
malli.core/explainer {:message "Use metabase.util.malli.registry/explainer instead of malli.core/explainer"}
|
||||
me.flowthing.pp/pprint {:message "Use metabase.util.log instead of me.flowthing.pp/pprint"}
|
||||
medley.core/random-uuid {:message "Use clojure.core/random-uuid instead of medley.core/random-uuid"}
|
||||
metabase.driver/database-supports? {:message "Use metabase.driver.util/supports? instead of metabase.driver/database-supports?"}
|
||||
metabase.lib.equality/find-column-indexes-for-refs {:message "Use lib.equality/closest-matches-in-metadata or lib.equality/find-closest-matches-for-refs instead of lib.equality/find-column-indexes-for-refs"}
|
||||
metabase.test/with-temp* {:message "Use mt/with-temp instead of mt/with-temp*"}
|
||||
toucan2.tools.with-temp {:message "Use mt/with-temp instead of t2.with-temp/with-temp"}}
|
||||
@@ -243,7 +114,6 @@
|
||||
:discouraged-namespace
|
||||
{camel-snake-kebab.core {:message "CSK is not Turkish-safe, use the versions in metabase.util instead."}
|
||||
clojure.tools.logging {:message "Use metabase.util.log instead of clojure.tools.logging directly"}
|
||||
grouper.core {:message "Use metabase.util.grouper instead of grouper.core"}
|
||||
honeysql.core {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}
|
||||
honeysql.format {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}
|
||||
honeysql.helpers {:message "Use Honey SQL 2. Honey SQL 1 is removed as a dependency in Metabase 49+."}
|
||||
@@ -265,7 +135,7 @@
|
||||
;; namespace(s). This is mostly a temporary placeholder until we go in and create module namespaces, which means
|
||||
;; you should go create one.
|
||||
;;
|
||||
;; 2. A set of namespace symbols. All namespaces in other modules will only be allowed to use namespaces from
|
||||
;; 2. A set of namespace symbols. All namespaces in other modules will only be allowed ;; to use namespaces from
|
||||
;; this set. Ideally this set should only have one namespace, but restricting it to a set of several is still
|
||||
;; better than `:any`.
|
||||
;;
|
||||
@@ -279,8 +149,7 @@
|
||||
{metabase.actions #{metabase.actions.core}
|
||||
metabase.analytics #{metabase.analytics.prometheus
|
||||
metabase.analytics.snowplow
|
||||
metabase.analytics.stats
|
||||
metabase.analytics.sdk} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.analytics.stats} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.analyze #{metabase.analyze}
|
||||
metabase.api #{metabase.api.common
|
||||
metabase.api.dataset
|
||||
@@ -289,10 +158,8 @@
|
||||
metabase.async #{metabase.async.streaming-response
|
||||
metabase.async.streaming-response.thread-pool
|
||||
metabase.async.util} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.audit #{metabase.audit}
|
||||
metabase.bootstrap #{metabase.bootstrap}
|
||||
metabase.cmd #{} ; there are no namespaces here since you shouldn't be using this in any other module.
|
||||
metabase.channel #{metabase.channel.core}
|
||||
metabase.config #{metabase.config}
|
||||
metabase.core #{metabase.core.initialization-status} ; TODO -- only namespace used outside of EE, this probably belongs in `metabase.server` anyway since that's the only place it's used.
|
||||
metabase.db #{metabase.db
|
||||
@@ -319,12 +186,14 @@
|
||||
metabase.metabot #{metabase.metabot}
|
||||
metabase.models :any ; TODO -- scream, 62 namespaces used elsewhere, but to be fair a lot of these don't *need* to be required.
|
||||
metabase.moderation #{metabase.moderation}
|
||||
metabase.native-query-analyzer #{metabase.native-query-analyzer}
|
||||
metabase.permissions #{metabase.permissions.util} ; TODO -- this is currently the only namespace in this module. Give it a real API namespace?
|
||||
metabase.plugins #{metabase.plugins
|
||||
metabase.plugins.classloader} ; TODO -- not 100% sure the classloader belongs here
|
||||
metabase.public-settings #{metabase.public-settings
|
||||
metabase.public-settings.premium-features}
|
||||
metabase.pulse #{metabase.pulse
|
||||
metabase.pulse.attachment
|
||||
metabase.pulse.markdown
|
||||
metabase.pulse.parameters
|
||||
metabase.pulse.preview
|
||||
@@ -333,8 +202,6 @@
|
||||
metabase.pulse.render.js-svg
|
||||
metabase.pulse.render.style} ; TODO -- consolidate these into a real API namespace.
|
||||
metabase.query-processor :any ; TODO omg scream, 29 namespaces used outside of the module. WHAT THE HECC
|
||||
metabase.query-analysis #{metabase.query-analysis
|
||||
metabase.query-analysis.failure-map}
|
||||
metabase.related #{metabase.related}
|
||||
metabase.sample-data #{metabase.sample-data}
|
||||
metabase.search #{metabase.search}
|
||||
@@ -393,12 +260,9 @@
|
||||
metabase.analyze :any
|
||||
metabase.api :any
|
||||
metabase.async :any
|
||||
metabase.audit :any
|
||||
metabase.auth-provider #{metabase.util}
|
||||
metabase.bootstrap #{}
|
||||
metabase.cmd :any
|
||||
metabase.compatibility :any
|
||||
metabase.channel :any
|
||||
metabase.config #{metabase.plugins}
|
||||
metabase.core :any
|
||||
metabase.db :any
|
||||
@@ -415,18 +279,11 @@
|
||||
metabase.metabot :any
|
||||
metabase.models :any
|
||||
metabase.moderation :any
|
||||
metabase.native-query-analyzer :any
|
||||
metabase.permissions :any
|
||||
metabase.plugins :any
|
||||
metabase.public-settings :any
|
||||
metabase.pulse :any
|
||||
metabase.query-analysis #{metabase.config
|
||||
metabase.driver
|
||||
metabase.legacy-mbql
|
||||
metabase.lib
|
||||
metabase.models
|
||||
metabase.public-settings
|
||||
metabase.query-processor
|
||||
metabase.util}
|
||||
metabase.query-processor :any
|
||||
metabase.related :any
|
||||
metabase.sample-data :any
|
||||
@@ -448,11 +305,11 @@
|
||||
;; this is mostly intended for excluding test namespaces or those rare 'glue' namespaces that glue multiple modules
|
||||
;; together, e.g. `metabase.lib.metadata.jvm`.
|
||||
:ignored-namespace-patterns
|
||||
#{"-test$" ; anything ending in `-test`
|
||||
"test[-.]util" ; anything that contains `test.util` or `test-util`
|
||||
"test\\.impl" ; anything that contains `test.impl`
|
||||
"^metabase\\.test" ; anything starting with `metabase.test`
|
||||
"^metabase\\.http-client$"}} ; `metabase.http-client` which is a test-only namespace despite its name.
|
||||
#{"-test$" ; anything ending in `-test`
|
||||
"test[-.]util" ; anything that contains `test.util` or `test-util`
|
||||
"test\\.impl" ; anything that contains `test.impl`
|
||||
"^metabase\\.test" ; anything starting with `metabase.test`
|
||||
"^metabase\\.http-client$"}} ; `metabase.http-client` which is a test-only namespace despite its name.
|
||||
|
||||
:consistent-alias
|
||||
{:aliases
|
||||
@@ -482,7 +339,11 @@
|
||||
hiccup.util hiccup.util
|
||||
honey.sql sql
|
||||
honey.sql.helpers sql.helpers
|
||||
java-time.api t
|
||||
honeysql.core hsql
|
||||
honeysql.format hformat
|
||||
honeysql.helpers hh
|
||||
honeysql.types htypes
|
||||
java-time t
|
||||
macaw.core macaw
|
||||
malli.core mc
|
||||
malli.error me
|
||||
@@ -495,7 +356,6 @@
|
||||
metabase-enterprise.audit-app.pages.common common
|
||||
metabase-enterprise.sandbox.api.table table
|
||||
metabase-enterprise.test met
|
||||
metabase.analytics.sdk sdk
|
||||
metabase.analytics.stats stats
|
||||
metabase.analyze.query-results qr
|
||||
metabase.analyze.classifiers.category classifiers.category
|
||||
@@ -550,7 +410,6 @@
|
||||
metabase.api.user api.user
|
||||
metabase.api.util api.util
|
||||
metabase.async.streaming-response.thread-pool thread-pool
|
||||
metabase.channel.core channel
|
||||
metabase.cmd.copy.h2 copy.h2
|
||||
metabase.config config
|
||||
metabase.config.file config.file
|
||||
@@ -625,8 +484,8 @@
|
||||
metabase.models.setting.cache setting.cache
|
||||
metabase.models.timeline timeline
|
||||
metabase.models.timeline-event timeline-event
|
||||
metabase.analysis.native-query-analyzer nqa
|
||||
metabase.analysis.native-query-analyzer.parameter-substitution nqa.sub
|
||||
metabase.native-query-analyzer query-analyzer
|
||||
metabase.native-query-analyzer.parameter-substitution nqa.sub
|
||||
metabase.plugins.initialize plugins.init
|
||||
metabase.public-settings public-settings
|
||||
metabase.public-settings.premium-features premium-features
|
||||
@@ -708,7 +567,6 @@
|
||||
metabase.util.encryption encryption
|
||||
metabase.util.encryption-test encryption-test
|
||||
metabase.util.files u.files
|
||||
metabase.util.grouper grouper
|
||||
metabase.util.honey-sql-2 h2x
|
||||
metabase.util.i18n i18n
|
||||
metabase.util.i18n.impl i18n.impl
|
||||
@@ -735,112 +593,109 @@
|
||||
toucan.models models}}}
|
||||
|
||||
: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
|
||||
clojurewerkz.quartzite.jobs/defjob clojure.core/defn
|
||||
metabase-enterprise.serialization.test-util/with-dbs clojure.core/fn
|
||||
metabase-enterprise.serialization.test-util/with-random-dump-dir clojure.core/let
|
||||
metabase.actions.test-util/with-actions clojure.core/let
|
||||
metabase.api.common/defroutes clojure.core/def
|
||||
metabase.api.common/let-404 clojure.core/let
|
||||
metabase.api.search-test/do-test-users clojure.core/let
|
||||
metabase.async.api-response-test/with-response clojure.core/let
|
||||
metabase.dashboard-subscription-test/with-dashboard-sub-for-card clojure.core/let
|
||||
metabase.db.custom-migrations/define-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.db.custom-migrations/define-reversible-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.db.data-migrations/defmigration clojure.core/def
|
||||
metabase.db.liquibase/with-liquibase clojure.core/let
|
||||
metabase.db.schema-migrations-test.impl/with-temp-empty-app-db clojure.core/let
|
||||
metabase.driver.mongo.connection/with-mongo-client clojure.core/let
|
||||
metabase.driver.mongo.connection/with-mongo-database clojure.core/let
|
||||
metabase.driver.mongo.query-processor/mongo-let clojure.core/let
|
||||
metabase.driver.sql-jdbc.actions/with-jdbc-transaction clojure.core/let
|
||||
metabase.driver.sql-jdbc.connection/with-connection-spec-for-testing-connection clojure.core/let
|
||||
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info clojure.core/fn
|
||||
metabase.integrations.ldap/with-ldap-connection clojure.core/fn
|
||||
metabase.models.collection-test/with-collection-in-location clojure.core/let
|
||||
metabase.models.json-migration/def-json-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.models.setting.multi-setting/define-multi-setting clojure.core/def
|
||||
metabase.models.setting/defsetting clj-kondo.lint-as/def-catch-all
|
||||
metabase.public-settings.premium-features/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
metabase.public-settings.premium-features/define-premium-feature clojure.core/def
|
||||
metabase.pulse-test/with-pulse-for-card clojure.core/let
|
||||
metabase.query-processor-test.pipeline-queries-test/pmbql-query clojure.core/->
|
||||
metabase.query-processor-test.pipeline-queries-test/run-pmbql-query clojure.core/->
|
||||
metabase.query-processor.error-type/deferror clojure.core/def
|
||||
metabase.query-processor.middleware.cache.impl/with-reducible-deserialized-results clojure.core/let
|
||||
metabase.query-processor.middleware.process-userland-query-test/with-query-execution! clojure.core/let
|
||||
metabase.query-processor.setup/with-qp-setup clojure.core/let
|
||||
metabase.shared.util.namespaces/import-fns potemkin/import-vars
|
||||
metabase.sync.util/sum-for clojure.core/for
|
||||
metabase.sync.util/with-emoji-progress-bar clojure.core/let
|
||||
metabase.test.data.interface/defdataset clojure.core/def
|
||||
metabase.test.data.interface/defdataset-edn clojure.core/def
|
||||
metabase.test/defdataset clojure.core/def
|
||||
metabase.test/let-url clojure.core/let
|
||||
metabase.test/with-actions clojure.core/let
|
||||
metabase.test/with-grouper-batches! clojure.core/fn
|
||||
metabase.test/with-open-channels clojure.core/let
|
||||
metabase.test/with-single-admin-user clojure.core/fn
|
||||
metabase.test/with-temp-dir clojure.core/let
|
||||
metabase.test/with-temp-empty-app-db clojure.core/let
|
||||
metabase.test/with-temp-file clojure.core/let
|
||||
metabase.test/with-user-in-groups clojure.core/let
|
||||
metabase.upload-test/with-upload-table! clojure.core/let
|
||||
metabase.util.files/with-open-path-to-resource clojure.core/let
|
||||
metabase.util.malli.defn/defn schema.core/defn
|
||||
metabase.util.malli.defn/defn- schema.core/defn
|
||||
metabase.util.malli.fn/fn schema.core/fn
|
||||
metabase.util.malli/defmethod schema.core/defmethod
|
||||
metabase.util.malli/defn schema.core/defn
|
||||
metabase.util.malli/defn- schema.core/defn
|
||||
metabase.util.malli/fn schema.core/fn
|
||||
metabase.util.ssh/with-ssh-tunnel clojure.core/let
|
||||
metabase.xrays.domain-entities.malli/defn schema.core/defn
|
||||
monger.operators/defoperator clojure.core/def
|
||||
potemkin.types/defprotocol+ clojure.core/defprotocol
|
||||
potemkin.types/defrecord+ clojure.core/defrecord
|
||||
potemkin.types/deftype+ clojure.core/deftype
|
||||
potemkin/defprotocol+ clojure.core/defprotocol
|
||||
potemkin/defrecord+ clojure.core/defrecord
|
||||
potemkin/deftype+ clojure.core/deftype
|
||||
toucan.db/with-call-counting clojure.core/fn
|
||||
toucan2.core/with-call-count clojure.core/fn}
|
||||
{clojure.core.logic/defne clj-kondo.lint-as/def-catch-all
|
||||
clojure.test.check.clojure-test/defspec clojure.test/deftest
|
||||
clojurewerkz.quartzite.jobs/defjob clojure.core/defn
|
||||
honeysql.helpers/defhelper clj-kondo.lint-as/def-catch-all
|
||||
honeysql.util/defalias clojure.core/def
|
||||
metabase-enterprise.serialization.test-util/with-random-dump-dir clojure.core/let
|
||||
metabase-enterprise.serialization.test-util/with-dbs clojure.core/fn
|
||||
metabase.actions.test-util/with-actions clojure.core/let
|
||||
metabase.api.common/let-404 clojure.core/let
|
||||
metabase.api.common/defroutes clojure.core/def
|
||||
metabase.api.search-test/do-test-users clojure.core/let
|
||||
metabase.async.api-response-test/with-response clojure.core/let
|
||||
metabase.dashboard-subscription-test/with-dashboard-sub-for-card clojure.core/let
|
||||
metabase.db.custom-migrations/define-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.db.custom-migrations/define-reversible-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.db.data-migrations/defmigration clojure.core/def
|
||||
metabase.db.liquibase/with-liquibase clojure.core/let
|
||||
metabase.db.schema-migrations-test.impl/with-temp-empty-app-db clojure.core/let
|
||||
metabase.driver.mongo.query-processor/mongo-let clojure.core/let
|
||||
metabase.driver.mongo.connection/with-mongo-client clojure.core/let
|
||||
metabase.driver.mongo.connection/with-mongo-database clojure.core/let
|
||||
metabase.driver.sql-jdbc.actions/with-jdbc-transaction clojure.core/let
|
||||
metabase.driver.sql-jdbc.connection/with-connection-spec-for-testing-connection clojure.core/let
|
||||
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info clojure.core/fn
|
||||
metabase.integrations.ldap/with-ldap-connection clojure.core/fn
|
||||
metabase.models.collection-test/with-collection-in-location clojure.core/let
|
||||
metabase.models.json-migration/def-json-migration clj-kondo.lint-as/def-catch-all
|
||||
metabase.models.setting.multi-setting/define-multi-setting clojure.core/def
|
||||
metabase.models.setting/defsetting clj-kondo.lint-as/def-catch-all
|
||||
metabase.public-settings.premium-features/defenterprise-schema clj-kondo.lint-as/def-catch-all
|
||||
metabase.public-settings.premium-features/define-premium-feature clojure.core/def
|
||||
metabase.pulse-test/with-pulse-for-card clojure.core/let
|
||||
metabase.query-processor.error-type/deferror clojure.core/def
|
||||
metabase.query-processor.setup/with-qp-setup clojure.core/let
|
||||
metabase.query-processor.middleware.cache.impl/with-reducible-deserialized-results clojure.core/let
|
||||
metabase.query-processor.middleware.process-userland-query-test/with-query-execution clojure.core/let
|
||||
metabase.query-processor-test.pipeline-queries-test/pmbql-query clojure.core/->
|
||||
metabase.query-processor-test.pipeline-queries-test/run-pmbql-query clojure.core/->
|
||||
metabase.shared.util.namespaces/import-fns potemkin/import-vars
|
||||
metabase.sync.util/sum-for clojure.core/for
|
||||
metabase.sync.util/with-emoji-progress-bar clojure.core/let
|
||||
metabase.test.data.interface/defdataset clojure.core/def
|
||||
metabase.test.data.interface/defdataset-edn clojure.core/def
|
||||
metabase.test/defdataset clojure.core/def
|
||||
metabase.test/let-url clojure.core/let
|
||||
metabase.test/with-actions clojure.core/let
|
||||
metabase.test/with-open-channels clojure.core/let
|
||||
metabase.test/with-single-admin-user clojure.core/fn
|
||||
metabase.test/with-temp-dir clojure.core/let
|
||||
metabase.test/with-temp-empty-app-db clojure.core/let
|
||||
metabase.test/with-temp-file clojure.core/let
|
||||
metabase.test/with-user-in-groups clojure.core/let
|
||||
metabase.upload-test/with-upload-table! clojure.core/let
|
||||
metabase.util.files/with-open-path-to-resource clojure.core/let
|
||||
metabase.util.malli.defn/defn schema.core/defn
|
||||
metabase.util.malli.fn/fn schema.core/fn
|
||||
metabase.util.malli/defmethod schema.core/defmethod
|
||||
metabase.util.malli/defn schema.core/defn
|
||||
metabase.util.malli/fn schema.core/fn
|
||||
metabase.util.ssh/with-ssh-tunnel clojure.core/let
|
||||
metabase.xrays.domain-entities.malli/defn schema.core/defn
|
||||
monger.operators/defoperator clojure.core/def
|
||||
potemkin.types/defprotocol+ clojure.core/defprotocol
|
||||
potemkin.types/defrecord+ clojure.core/defrecord
|
||||
potemkin.types/deftype+ clojure.core/deftype
|
||||
potemkin/defprotocol+ clojure.core/defprotocol
|
||||
potemkin/defrecord+ clojure.core/defrecord
|
||||
potemkin/deftype+ clojure.core/deftype
|
||||
toucan.db/with-call-counting clojure.core/fn
|
||||
toucan2.core/with-call-count clojure.core/fn}
|
||||
|
||||
:hooks
|
||||
{:analyze-call
|
||||
{cljs.test/deftest hooks.clojure.test/deftest
|
||||
{clojure.core/ns hooks.clojure.core/lint-ns
|
||||
cljs.test/deftest hooks.clojure.test/deftest
|
||||
cljs.test/is hooks.clojure.test/is
|
||||
cljs.test/use-fixtures hooks.clojure.test/use-fixtures
|
||||
clojure.core/ns hooks.clojure.core/lint-ns
|
||||
clojure.test/deftest hooks.clojure.test/deftest
|
||||
clojure.test/is hooks.clojure.test/is
|
||||
clojure.test/use-fixtures hooks.clojure.test/use-fixtures
|
||||
metabase-enterprise.cache.config-test/with-temp-persist-models hooks.common/with-seven-bindings
|
||||
metabase-enterprise.advanced-permissions.models.permissions.application-permissions-test/with-new-group-and-current-graph hooks.common/with-two-top-level-bindings
|
||||
metabase-enterprise.audit-app.pages-test/with-temp-objects hooks.common/with-one-binding
|
||||
metabase-enterprise.cache.config-test/with-temp-persist-models hooks.common/with-seven-bindings
|
||||
metabase-enterprise.serialization.test-util/with-temp-dpc hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.analytics.prometheus-test/with-prometheus-system! hooks.common/with-two-bindings
|
||||
metabase.api.alert-test/with-alert-in-collection! hooks.common/with-four-bindings
|
||||
metabase.api.automagic-dashboards-test/with-indexed-model! hooks.metabase.api.automagic-dashboards-test/with-indexed-model!
|
||||
metabase.api.card-test/with-card-param-values-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.card-test/with-persistence-setup! hooks.common/with-one-top-level-binding
|
||||
metabase.analytics.prometheus-test/with-prometheus-system hooks.common/with-two-bindings
|
||||
metabase.api.automagic-dashboards-test/with-indexed-model hooks.metabase.api.automagic-dashboards-test/with-indexed-model
|
||||
metabase.api.alert-test/with-alert-in-collection hooks.common/with-four-bindings
|
||||
metabase.api.card-test/with-persistence-setup hooks.common/with-one-top-level-binding
|
||||
metabase.api.card-test/with-temp-native-card! hooks.common/with-two-bindings
|
||||
metabase.api.card-test/with-temp-native-card-with-params! hooks.common/with-two-bindings
|
||||
metabase.api.collection-test/with-french-user-and-personal-collection! hooks.common/with-two-top-level-bindings
|
||||
metabase.api.collection-test/with-french-user-and-personal-collection hooks.common/with-two-top-level-bindings
|
||||
metabase.api.common/defendpoint hooks.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async hooks.metabase.api.common/defendpoint
|
||||
metabase.api.common/defendpoint-async-schema hooks.metabase.api.common/defendpoint
|
||||
metabase.api.dashboard-test/with-chain-filter-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.dashboard-test/with-simple-dashboard-with-tabs hooks.common/with-one-binding
|
||||
metabase.api.card-test/with-card-param-values-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.embed-test/do-response-formats hooks.common/with-two-bindings
|
||||
metabase.api.embed-test/with-chain-filter-fixtures! hooks.common/let-one-with-optional-value
|
||||
metabase.api.embed-test/with-chain-filter-fixtures hooks.common/let-one-with-optional-value
|
||||
metabase.api.embed-test/with-temp-card hooks.common/let-one-with-optional-value
|
||||
metabase.api.embed-test/with-temp-dashcard hooks.common/let-one-with-optional-value
|
||||
metabase.api.persist-test/with-setup! hooks.common/with-one-top-level-binding
|
||||
metabase.api.public-test/with-required-param-card! hooks.common/with-one-binding
|
||||
metabase.api.persist-test/with-setup hooks.common/with-one-top-level-binding
|
||||
metabase.api.public-test/with-required-param-card hooks.common/with-one-binding
|
||||
metabase.api.public-test/with-temp-public-card hooks.common/let-one-with-optional-value
|
||||
metabase.api.public-test/with-temp-public-dashboard hooks.common/let-one-with-optional-value
|
||||
metabase.api.public-test/with-temp-public-dashboard-and-card hooks.common/with-three-bindings
|
||||
@@ -848,34 +703,33 @@
|
||||
metabase.api.search-test/with-search-items-in-root-collection hooks.common/do*
|
||||
metabase.api.user-test/with-temp-user-email hooks.common/with-one-binding
|
||||
metabase.async.streaming-response-test/with-start-execution-chan hooks.common/with-one-binding
|
||||
metabase.dashboard-subscription-test/with-link-card-fixture-for-dashboard hooks.common/let-second
|
||||
metabase.db.schema-migrations-test.impl/test-migrations hooks.metabase.db.schema-migrations-test.impl/test-migrations
|
||||
metabase.dashboard-subscription-test/with-link-card-fixture-for-dashboard hooks.common/let-second
|
||||
metabase.driver.bigquery-cloud-sdk-test/calculate-bird-scarcity hooks.metabase.query-processor-test.expressions-test/calculate-bird-scarcity
|
||||
metabase.driver/register! hooks.metabase.driver/register!
|
||||
metabase.legacy-mbql.schema.macros/defclause hooks.metabase.legacy-mbql.schemas.macros/defclause
|
||||
metabase.lib.schema.mbql-clause/define-catn-mbql-clause hooks.metabase.lib.schema.mbql-clause/define-mbql-clause
|
||||
metabase.lib.schema.mbql-clause/define-mbql-clause hooks.metabase.lib.schema.mbql-clause/define-mbql-clause
|
||||
metabase.lib.schema.mbql-clause/define-catn-mbql-clause hooks.metabase.lib.schema.mbql-clause/define-mbql-clause
|
||||
metabase.lib.schema.mbql-clause/define-tuple-mbql-clause hooks.metabase.lib.schema.mbql-clause/define-mbql-clause
|
||||
metabase.lib.test-util.macros/$ids hooks.metabase.test.data/$ids
|
||||
metabase.lib.test-util.macros/mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.lib.test-util.macros/with-testing-against-standard-queries hooks.metabase.lib.test-util.macros/with-testing-against-standard-queries
|
||||
metabase.models.collection-test/with-collection-hierarchy! hooks.common/let-one-with-optional-value
|
||||
metabase.models.collection-test/with-collection-hierarchy hooks.common/let-one-with-optional-value
|
||||
metabase.models.collection-test/with-personal-and-impersonal-collections hooks.common/with-two-bindings
|
||||
metabase.models.dashboard-test/with-dash-in-collection hooks.common/with-three-bindings
|
||||
metabase.models.dashboard-tab-test/with-dashtab-in-personal-collection hooks.common/with-one-top-level-binding
|
||||
metabase.models.dashboard-test/with-dash-in-collection! hooks.common/with-three-bindings
|
||||
metabase.models.interface/define-batched-hydration-method hooks.metabase.models.interface/define-hydration-method
|
||||
metabase.models.interface/define-simple-hydration-method hooks.metabase.models.interface/define-hydration-method
|
||||
metabase.models.pulse-test/with-dashboard-subscription-in-collection! hooks.common/with-four-bindings
|
||||
metabase.models.pulse-test/with-pulse-in-collection! hooks.common/with-four-bindings
|
||||
metabase.models.interface/define-batched-hydration-method hooks.metabase.models.interface/define-hydration-method
|
||||
metabase.models.pulse-test/with-dashboard-subscription-in-collection hooks.common/with-four-bindings
|
||||
metabase.models.pulse-test/with-pulse-in-collection hooks.common/with-four-bindings
|
||||
metabase.models.setting.multi-setting/define-multi-setting hooks.metabase.models.setting/define-multi-setting
|
||||
metabase.models.setting/defsetting hooks.metabase.models.setting/defsetting
|
||||
metabase.public-settings.premium-features/defenterprise hooks.metabase.public-settings.premium-features/defenterprise
|
||||
metabase.pulse.test-util/checkins-query-card hooks.metabase.test.data/$ids
|
||||
metabase.query-processor-test.expressions-test/calculate-bird-scarcity hooks.metabase.query-processor-test.expressions-test/calculate-bird-scarcity
|
||||
metabase.query-processor-test.filter-test/count-with-filter-clause hooks.metabase.test.data/$ids
|
||||
metabase.query-processor.middleware.cache-test/with-mock-cache! hooks.common/with-two-bindings
|
||||
metabase.query-processor.middleware.cache-test/with-mock-cache hooks.common/with-two-bindings
|
||||
metabase.sample-data-test/with-temp-sample-database-db hooks.common/with-one-binding
|
||||
metabase.stale-test/with-stale-items hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.test.data.users/with-group hooks.common/let-one-with-optional-value
|
||||
metabase.test.data/$ids hooks.metabase.test.data/$ids
|
||||
metabase.test.data/dataset hooks.metabase.test.data/dataset
|
||||
@@ -883,6 +737,7 @@
|
||||
metabase.test.data/run-mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.test.util.async/with-open-channels hooks.common/let-with-optional-value-for-last-binding
|
||||
metabase.test.util.log/with-log-level hooks.common/with-ignored-first-arg
|
||||
metabase.test.util.log/with-log-messages-for-level hooks.common/with-ignored-first-arg
|
||||
metabase.test.util/discard-setting-changes hooks.common/with-ignored-first-arg
|
||||
metabase.test.util/with-column-remappings hooks.common/with-ignored-first-arg
|
||||
metabase.test.util/with-non-admin-groups-no-root-collection-perms hooks.common/do*
|
||||
@@ -893,70 +748,65 @@
|
||||
metabase.test/discard-setting-changes hooks.common/with-ignored-first-arg
|
||||
metabase.test/mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.test/query hooks.metabase.test.data/mbql-query
|
||||
metabase.test/run-mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.test/test-drivers hooks.common/do*
|
||||
metabase.test/run-mbql-query hooks.metabase.test.data/mbql-query
|
||||
metabase.test/with-column-remappings hooks.common/with-ignored-first-arg
|
||||
metabase.test/with-group hooks.common/let-one-with-optional-value
|
||||
metabase.test/with-log-level hooks.common/with-ignored-first-arg
|
||||
metabase.test/with-log-messages-for-level hooks.metabase.util.log.capture/with-log-messages-for-level
|
||||
metabase.test/with-log-messages-for-level hooks.common/with-ignored-first-arg
|
||||
metabase.test/with-non-admin-groups-no-root-collection-perms hooks.common/do*
|
||||
metabase.test/with-temp hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.test/with-temp-file hooks.metabase.test.util/with-temp-file
|
||||
metabase.test/with-temporary-setting-values hooks.metabase.test.util/with-temporary-setting-values
|
||||
metabase.util.log.capture/with-log-messages-for-level hooks.metabase.util.log.capture/with-log-messages-for-level
|
||||
metabase.util/format-color hooks.metabase.util/format-color
|
||||
metabase.util.log/trace hooks.metabase.util.log/info
|
||||
metabase.util.log/tracef hooks.metabase.util.log/infof
|
||||
metabase.util.log/debug hooks.metabase.util.log/info
|
||||
metabase.util.log/debugf hooks.metabase.util.log/infof
|
||||
metabase.util.log/info hooks.metabase.util.log/info
|
||||
metabase.util.log/infof hooks.metabase.util.log/infof
|
||||
metabase.util.log/warn hooks.metabase.util.log/info
|
||||
metabase.util.log/warnf hooks.metabase.util.log/infof
|
||||
metabase.util.log/error hooks.metabase.util.log/info
|
||||
metabase.util.log/errorf hooks.metabase.util.log/infof
|
||||
metabase.util.log/fatal hooks.metabase.util.log/info
|
||||
metabase.util.log/fatalf hooks.metabase.util.log/infof
|
||||
metabase.util.log/info hooks.metabase.util.log/info
|
||||
metabase.util.log/infof hooks.metabase.util.log/infof
|
||||
metabase.util.log/trace hooks.metabase.util.log/info
|
||||
metabase.util.log/tracef hooks.metabase.util.log/infof
|
||||
metabase.util.log/warn hooks.metabase.util.log/info
|
||||
metabase.util.log/warnf hooks.metabase.util.log/infof
|
||||
metabase.util.malli.registry/def hooks.metabase.util.malli.registry/def
|
||||
metabase.util/format-color hooks.metabase.util/format-color}
|
||||
metabase.util.malli.registry/def hooks.metabase.util.malli.registry/def}
|
||||
|
||||
:macroexpand
|
||||
{clojurewerkz.quartzite.jobs/build macros.quartz/build-job
|
||||
clojurewerkz.quartzite.schedule.cron/schedule macros.quartz/schedule
|
||||
clojurewerkz.quartzite.schedule.simple/schedule macros.quartz/simple-schedule
|
||||
clojurewerkz.quartzite.triggers/build macros.quartz/build-trigger
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.serialization.test-util/with-world macros.metabase-enterprise.serialization.test-util/with-world
|
||||
metabase-enterprise.test/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.test/with-gtaps-for-user! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.advanced-permissions.api.util-test/with-impersonations! macros.metabase-enterprise.advanced-permissions.api.util-test/with-impersonations!
|
||||
metabase-enterprise.query-reference-validation.api-test/with-test-setup! macros.metabase-enterprise.query-reference-validation.api-test/with-test-setup!
|
||||
metabase.api.card-test/with-ordered-items macros.metabase.api.card-test/with-ordered-items
|
||||
metabase.api.collection-test/with-collection-hierarchy! macros.metabase.api.collection-test/with-collection-hierarchy!
|
||||
metabase.api.collection-test/with-some-children-of-collection! macros.metabase.api.collection-test/with-some-children-of-collection!
|
||||
metabase.api.common/define-routes macros.metabase.api.common/define-routes
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing!
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing! macros.metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing!
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing! macros.metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing!
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing! macros.metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing!
|
||||
metabase.lib.filter/deffilter macros.metabase.lib.filter/deffilter
|
||||
metabase.lib.common/defop macros.metabase.lib.common/defop
|
||||
metabase.models.params.chain-filter-test/chain-filter macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.params.chain-filter-test/chain-filter-search macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.query-analysis-test/with-test-setup macros.metabase.models.query-analysis-test/with-test-setup
|
||||
metabase.models.user-test/with-groups macros.metabase.models.user-test/with-groups
|
||||
metabase.query-processor.streaming/streaming-response macros.metabase.query-processor.streaming/streaming-response
|
||||
metabase.related-test/with-world macros.metabase.related-test/with-world
|
||||
metabase.shared.util.namespaces/import-fn macros.metabase.shared.util.namespaces/import-fn
|
||||
metabase.task.setup.query-analysis-setup/with-test-setup! macros.metabase.task.setup.query-analysis-setup/with-test-setup!
|
||||
metabase.test.data.users/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test.util/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test.util/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test/with-persistence-enabled! macros.metabase.test.persistence/with-persistence-enabled!
|
||||
metabase.test/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.xrays.domain-entities.malli/define-getters-and-setters macros.metabase.xrays.domain-entities.malli/define-getters-and-setters}}
|
||||
{clojurewerkz.quartzite.jobs/build macros.quartz/build-job
|
||||
clojurewerkz.quartzite.schedule.cron/schedule macros.quartz/schedule
|
||||
clojurewerkz.quartzite.schedule.simple/schedule macros.quartz/simple-schedule
|
||||
clojurewerkz.quartzite.triggers/build macros.quartz/build-trigger
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.serialization.test-util/with-world macros.metabase-enterprise.serialization.test-util/with-world
|
||||
metabase-enterprise.test/with-gtaps! macros.metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.advanced-permissions.api.util-test/with-impersonations! macros.metabase-enterprise.advanced-permissions.api.util-test/with-impersonations!
|
||||
metabase.api.card-test/with-ordered-items macros.metabase.api.card-test/with-ordered-items
|
||||
metabase.api.collection-test/with-collection-hierarchy macros.metabase.api.collection-test/with-collection-hierarchy
|
||||
metabase.api.collection-test/with-some-children-of-collection macros.metabase.api.collection-test/with-some-children-of-collection
|
||||
metabase.api.common/define-routes macros.metabase.api.common/define-routes
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing macros.metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing macros.metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing macros.metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing macros.metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing
|
||||
metabase.lib.filter/deffilter macros.metabase.lib.filter/deffilter
|
||||
metabase.lib.common/defop macros.metabase.lib.common/defop
|
||||
metabase.models.params.chain-filter-test/chain-filter macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.params.chain-filter-test/chain-filter-search macros.metabase.models.params.chain-filter-test/chain-filter
|
||||
metabase.models.query-field-test/with-test-setup macros.metabase.models.query-field-test/with-test-setup
|
||||
metabase.models.user-test/with-groups macros.metabase.models.user-test/with-groups
|
||||
metabase.query-processor.streaming/streaming-response macros.metabase.query-processor.streaming/streaming-response
|
||||
metabase.related-test/with-world macros.metabase.related-test/with-world
|
||||
metabase.shared.util.namespaces/import-fn macros.metabase.shared.util.namespaces/import-fn
|
||||
metabase.test.data.users/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test.util/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test.util/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test/with-group-for-user macros.metabase.test.data.users/with-group-for-user
|
||||
metabase.test/with-persistence-enabled macros.metabase.test.persistence/with-persistence-enabled
|
||||
metabase.test/with-temp-env-var-value! macros.metabase.test.util/with-temp-env-var-value!
|
||||
metabase.test/with-temporary-raw-setting-values macros.metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.xrays.domain-entities.malli/define-getters-and-setters macros.metabase.xrays.domain-entities.malli/define-getters-and-setters}}
|
||||
|
||||
:config-in-comment
|
||||
{:linters {:unresolved-symbol {:level :off}}}
|
||||
@@ -986,19 +836,7 @@
|
||||
;; `metabase.driver.*`, excluding `-test` namespaces.
|
||||
;;
|
||||
{:pattern "metabase(?:(?:(?:-enterprise\\.sandbox)?\\.query-processor\\.)|(?:\\.driver\\.)).*(?<!-test)$"
|
||||
:name qp-and-driver-source-namespaces}
|
||||
;;
|
||||
;; driver namespaces
|
||||
;;
|
||||
{:pattern "metabase\\.driver.*$"
|
||||
:name driver-namespaces}
|
||||
;;
|
||||
;; general QP tests are ones that run across multiple drivers. Anything `metabase.query-processor*-test`,
|
||||
;; `metabase.driver.sql*-test` (excluding SQLServer and SQLite), or
|
||||
;; `metabase-enterprise.sandbox.query-processor*-test`
|
||||
;;
|
||||
{:pattern "^metabase(?:((?:-enterprise\\.sandbox)?\\.query-processor)|(?:\\.driver\\.sql(?!server)(?!ite))).*-test$"
|
||||
:name general-qp-and-driver-test-namespaces}]
|
||||
:name qp-and-driver-source-namespaces}]
|
||||
|
||||
:config-in-ns
|
||||
{test-namespaces
|
||||
@@ -1006,9 +844,7 @@
|
||||
{:inline-def {:level :off}
|
||||
:missing-docstring {:level :off}
|
||||
:private-call {:level :off}
|
||||
:metabase/defsetting-must-specify-export {:level :off}
|
||||
:discouraged-var {metabase.driver/database-supports? {:level :off}}}
|
||||
|
||||
:metabase/defsetting-must-specify-export {:level :off}}
|
||||
:hooks
|
||||
{:analyze-call
|
||||
{clojure.core/defmacro hooks.clojure.core/non-thread-safe-form-should-end-with-exclamation
|
||||
@@ -1058,11 +894,6 @@
|
||||
toucan.util.test {:message "Don't use application database inside MLv2 code"}
|
||||
toucan2.core {:message "Don't use application database inside MLv2 code"}}}}
|
||||
|
||||
driver-namespaces
|
||||
{:linters
|
||||
{:discouraged-var
|
||||
{metabase.driver/database-supports? {:level :off}}}}
|
||||
|
||||
qp-and-driver-source-namespaces
|
||||
{:linters
|
||||
{:discouraged-namespace
|
||||
@@ -1076,8 +907,4 @@
|
||||
{medley.core/map-keys {:message "Use clojure.core/update-keys"}
|
||||
medley.core/map-vals {:message "Use clojure.core/update-vals"}
|
||||
metabase.db.query/query {:message "Don't use application database directly in QP code; use QP Store/metadata provider"}
|
||||
metabase.db.query/reducible-query {:message "Don't use application database directly in QP code; use QP Store/metadata provider"}}}}
|
||||
|
||||
general-qp-and-driver-test-namespaces
|
||||
{:linters
|
||||
{:metabase/disallow-hardcoded-driver-names-in-tests {:level :warning}}}}}
|
||||
metabase.db.query/reducible-query {:message "Don't use application database directly in QP code; use QP Store/metadata provider"}}}}}}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
(ns macros.metabase.api.collection-test
|
||||
(:require [macros.common]))
|
||||
|
||||
(defmacro with-collection-hierarchy! [bindings & body]
|
||||
(defmacro with-collection-hierarchy [bindings & body]
|
||||
`(let [~(macros.common/ignore-unused 'a) nil
|
||||
~(macros.common/ignore-unused 'b) nil
|
||||
~(macros.common/ignore-unused 'c) nil
|
||||
@@ -12,6 +12,6 @@
|
||||
~bindings
|
||||
~@body))
|
||||
|
||||
(defmacro with-some-children-of-collection! [collection-or-id-or-nil & body]
|
||||
(defmacro with-some-children-of-collection [collection-or-id-or-nil & body]
|
||||
`(let [~(macros.common/ignore-unused '&ids) ~collection-or-id-or-nil]
|
||||
~@body))
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns macros.metabase.api.embed-test)
|
||||
|
||||
(defmacro with-embedding-enabled-and-temp-card-referencing!
|
||||
(defmacro with-embedding-enabled-and-temp-card-referencing
|
||||
[table-kw field-kw [card-binding] & body]
|
||||
`(let [~card-binding [~table-kw ~field-kw]]
|
||||
~@body))
|
||||
|
||||
(defmacro with-embedding-enabled-and-temp-dashcard-referencing!
|
||||
(defmacro with-embedding-enabled-and-temp-dashcard-referencing
|
||||
[table-kw field-kw [dash-binding card-binding dashcard-binding] & body]
|
||||
`(let [~dash-binding [~table-kw ~field-kw]
|
||||
~(or card-binding '_) nil
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
(ns macros.metabase.api.public-test)
|
||||
|
||||
(defmacro with-sharing-enabled-and-temp-card-referencing!
|
||||
(defmacro with-sharing-enabled-and-temp-card-referencing
|
||||
[table-kw field-kw [card-binding] & body]
|
||||
`(let [~card-binding [~table-kw ~field-kw]]
|
||||
~@body))
|
||||
|
||||
(defmacro with-sharing-enabled-and-temp-dashcard-referencing!
|
||||
(defmacro with-sharing-enabled-and-temp-dashcard-referencing
|
||||
[table-kw field-kw [dash-binding card-binding dashcard-binding] & body]
|
||||
`(let [~dash-binding [~table-kw ~field-kw]
|
||||
~(or card-binding '_) nil
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns macros.metabase.models.query-analysis-test
|
||||
(ns macros.metabase.models.query-field-test
|
||||
(:require [macros.common]))
|
||||
|
||||
(defmacro with-test-setup [& body]
|
||||
@@ -1,12 +0,0 @@
|
||||
(ns macros.metabase.task.setup.query-analysis-setup
|
||||
(:require [macros.common]))
|
||||
|
||||
(defmacro with-test-setup!
|
||||
"Set up the data required to test the Query Analysis related tasks"
|
||||
[& body]
|
||||
`(let [~(macros.common/ignore-unused 'c1) 1
|
||||
~(macros.common/ignore-unused 'c2) 2
|
||||
~(macros.common/ignore-unused 'c3) 3
|
||||
~(macros.common/ignore-unused 'c4) 4
|
||||
~(macros.common/ignore-unused 'arch) 5]
|
||||
~@body))
|
||||
@@ -1,5 +1,5 @@
|
||||
(ns macros.metabase.test.persistence)
|
||||
|
||||
(defmacro with-persistence-enabled! [[persist-fn-sym] & body]
|
||||
(defmacro with-persistence-enabled [[persist-fn-sym] & body]
|
||||
`(clojure.core/let [~persist-fn-sym (fn [])]
|
||||
~@body))
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
(ns macros.metabase-enterprise.query-reference-validation.api-test
|
||||
(:require [macros.common]))
|
||||
|
||||
(defmacro with-test-setup! [& body]
|
||||
`(let [~(macros.common/ignore-unused 'card-1) 1
|
||||
~(macros.common/ignore-unused 'card-2) 2
|
||||
~(macros.common/ignore-unused 'card-3) 3
|
||||
~(macros.common/ignore-unused 'card-4) 4
|
||||
~(macros.common/ignore-unused 'card-5) 5
|
||||
~(macros.common/ignore-unused 'coll-2) 100
|
||||
~(macros.common/ignore-unused 'coll-3) 200]
|
||||
~@body))
|
||||
@@ -1,11 +1,21 @@
|
||||
(ns hooks.clojure.core
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as hooks]
|
||||
[clojure.string :as str]
|
||||
[hooks.common]))
|
||||
[clojure.set :as set]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn- node->qualified-symbol [node]
|
||||
(try
|
||||
(when (hooks/token-node? node)
|
||||
(let [sexpr (hooks/sexpr node)]
|
||||
(when (symbol? sexpr)
|
||||
(let [resolved (hooks/resolve {:name sexpr})]
|
||||
(when-not (= :clj-kondo/unknown-namespace (:ns resolved))
|
||||
(symbol (name (:ns resolved)) (name (:name resolved))))))))
|
||||
;; some symbols like `*count/Integer` aren't resolvable.
|
||||
(catch Exception _
|
||||
nil)))
|
||||
|
||||
;;; TODO -- seems silly to maintain different blacklists and whitelists here than we use for the deftest `^:parallel`
|
||||
;;; checker... those lists live in the Clj Kondo config file
|
||||
(def ^:private symbols-allowed-in-fns-not-ending-in-an-exclamation-point
|
||||
'#{;; these toucan methods might actually set global values if it's used outside of a transaction,
|
||||
;; but since mt/with-temp runs in a transaction, so we'll ignore them in this case.
|
||||
@@ -141,7 +151,7 @@
|
||||
(str/ends-with? s "!"))
|
||||
|
||||
(defn- non-thread-safe-form-should-end-with-exclamation*
|
||||
[{[defn-or-defmacro form-name] :children, :as node} config]
|
||||
[{[defn-or-defmacro form-name] :children, :as node}]
|
||||
(when-not (and (:string-value form-name)
|
||||
(end-with-exclamation? (:string-value form-name)))
|
||||
(letfn [(walk [f form]
|
||||
@@ -149,12 +159,11 @@
|
||||
(doseq [child (:children form)]
|
||||
(walk f child)))]
|
||||
(walk (fn [form]
|
||||
(when-let [qualified-symbol (hooks.common/node->qualified-symbol form)]
|
||||
(when-let [qualified-symbol (node->qualified-symbol form)]
|
||||
(when (and (not (contains? symbols-allowed-in-fns-not-ending-in-an-exclamation-point qualified-symbol))
|
||||
(or (end-with-exclamation? qualified-symbol)
|
||||
(contains? (get-in config [:linters :metabase/validate-deftest :parallel/unsafe]) qualified-symbol)))
|
||||
(end-with-exclamation? qualified-symbol))
|
||||
(hooks/reg-finding! (assoc (meta form-name)
|
||||
:message (format "The name of this %s should end with `!` because it contains calls to non thread safe form `%s`. [:metabase/test-helpers-use-non-thread-safe-functions]"
|
||||
:message (format "The name of this %s should end with `!` because it contains calls to non thread safe form `%s`."
|
||||
(:string-value defn-or-defmacro) qualified-symbol)
|
||||
:type :metabase/test-helpers-use-non-thread-safe-functions)))))
|
||||
node))
|
||||
@@ -165,10 +174,10 @@
|
||||
A function or a macro can be defined as 'not thread safe' when their funciton name ends with a `!`.
|
||||
|
||||
Only used in tests to identify thread-safe/non-thread-safe test helpers. See #37126"
|
||||
[{:keys [node cljc lang config]}]
|
||||
[{:keys [node cljc lang]}]
|
||||
(when (or (not cljc)
|
||||
(= lang :clj))
|
||||
(non-thread-safe-form-should-end-with-exclamation* node config))
|
||||
(non-thread-safe-form-should-end-with-exclamation* node))
|
||||
{:node node})
|
||||
|
||||
(comment
|
||||
|
||||
@@ -4,7 +4,114 @@
|
||||
[clojure.string :as str]
|
||||
[hooks.common]))
|
||||
|
||||
(defn- warn-about-disallowed-parallel-forms [form config]
|
||||
(def ^:private disallowed-parallel-forms
|
||||
"Things you should not be allowed to use inside parallel tests. Besides these, anything ending in `!` not whitelisted
|
||||
in [[allowed-parallel-forms]] is not allowed."
|
||||
'#{clojure.core/alter-var-root
|
||||
clojure.core/with-redefs
|
||||
clojure.core/with-redefs-fn
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps!
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user!
|
||||
metabase-enterprise.sandbox.test-util/with-user-attributes
|
||||
metabase-enterprise.test/with-gtaps!
|
||||
metabase-enterprise.test/with-gtaps-for-user!
|
||||
metabase-enterprise.test/with-user-attributes
|
||||
metabase.actions.test-util/with-actions
|
||||
metabase.actions.test-util/with-actions-disabled
|
||||
metabase.actions.test-util/with-actions-enabled
|
||||
metabase.actions.test-util/with-actions-test-data
|
||||
metabase.actions.test-util/with-actions-test-data-and-actions-enabled
|
||||
metabase.actions.test-util/with-actions-test-data-tables
|
||||
metabase.analytics.snowplow-test/with-fake-snowplow-collector
|
||||
metabase.email-test/with-expected-messages
|
||||
metabase.email-test/with-fake-inbox
|
||||
metabase.test.data.users/with-group
|
||||
metabase.test.data.users/with-group-for-user
|
||||
metabase.test.persistence/with-persistence-enabled
|
||||
metabase.test.util.log/with-log-level
|
||||
metabase.test.util.log/with-log-messages-for-level
|
||||
metabase.test.util.misc/with-single-admin-user
|
||||
metabase.test.util/with-all-users-permission
|
||||
metabase.test.util/with-discarded-collections-perms-changes
|
||||
metabase.test.util/with-env-keys-renamed-by
|
||||
metabase.test.util/with-locale
|
||||
metabase.test.util/with-non-admin-groups-no-root-collection-for-namespace-perms
|
||||
metabase.test.util/with-non-admin-groups-no-root-collection-perms
|
||||
metabase.test.util/with-temp-env-var-value
|
||||
metabase.test.util/with-temp-vals-in-db
|
||||
metabase.test.util/with-temporary-raw-setting-values
|
||||
metabase.test.util/with-temporary-setting-values
|
||||
metabase.test.util/with-user-in-groups
|
||||
metabase.test/with-actions
|
||||
metabase.test/with-actions-disabled
|
||||
metabase.test/with-actions-enabled
|
||||
metabase.test/with-actions-test-data
|
||||
metabase.test/with-actions-test-data-and-actions-enabled
|
||||
metabase.test/with-actions-test-data-tables
|
||||
metabase.test/with-all-users-permission
|
||||
metabase.test/with-discarded-collections-perms-changes
|
||||
metabase.test/with-env-keys-renamed-by
|
||||
metabase.test/with-expected-messages
|
||||
metabase.test/with-fake-inbox
|
||||
metabase.test/with-group
|
||||
metabase.test/with-group-for-user
|
||||
metabase.test/with-locale
|
||||
metabase.test/with-log-level
|
||||
metabase.test/with-log-messages-for-level
|
||||
metabase.test/with-non-admin-groups-no-root-collection-for-namespace-perms
|
||||
metabase.test/with-non-admin-groups-no-root-collection-perms
|
||||
metabase.test/with-persistence-enabled
|
||||
metabase.test/with-single-admin-user
|
||||
metabase.test/with-temp-env-var-value
|
||||
metabase.test/with-temp-vals-in-db
|
||||
metabase.test/with-temporary-raw-setting-values
|
||||
metabase.test/with-temporary-setting-values
|
||||
metabase.test/with-user-in-groups})
|
||||
|
||||
;;; TODO -- we should disallow `metabase.test/user-http-request` with any method other than `:get`
|
||||
|
||||
(def ^:private allowed-parallel-forms
|
||||
"These fns are destructive, but are probably fine inside ^:parallel tests because it usually means you're doing
|
||||
something to an atom or something like that."
|
||||
'#{clojure.core/assoc!
|
||||
clojure.core/compare-and-set!
|
||||
clojure.core/conj!
|
||||
clojure.core/disj!
|
||||
clojure.core/dissoc!
|
||||
clojure.core/persistent!
|
||||
clojure.core/pop!
|
||||
clojure.core/reset!
|
||||
clojure.core/reset-vals!
|
||||
clojure.core/run!
|
||||
clojure.core/swap!
|
||||
clojure.core/swap-vals!
|
||||
clojure.core/volatile!
|
||||
clojure.core/vreset!
|
||||
clojure.core/vswap!
|
||||
clojure.core.async/<!
|
||||
clojure.core.async/<!!
|
||||
clojure.core.async/>!
|
||||
clojure.core.async/>!!
|
||||
clojure.core.async/alt!
|
||||
clojure.core.async/alt!!
|
||||
clojure.core.async/alts!
|
||||
clojure.core.async/alts!!
|
||||
clojure.core.async/close!
|
||||
clojure.core.async/ioc-alts!
|
||||
clojure.core.async/offer!
|
||||
clojure.core.async/onto-chan!
|
||||
clojure.core.async/onto-chan!!
|
||||
clojure.core.async/poll!
|
||||
clojure.core.async/put!
|
||||
clojure.core.async/take!
|
||||
clojure.core.async/to-chan!
|
||||
clojure.core.async/to-chan!!
|
||||
metabase.driver.sql-jdbc.execute/execute-prepared-statement!
|
||||
metabase.pulse/send-pulse!
|
||||
metabase.query-processor.store/store-database!
|
||||
next.jdbc/execute!})
|
||||
|
||||
(defn- warn-about-disallowed-parallel-forms [form]
|
||||
(letfn [(error! [form message]
|
||||
(hooks/reg-finding! (assoc (meta form)
|
||||
:message message
|
||||
@@ -12,12 +119,12 @@
|
||||
(f [form]
|
||||
(when-let [qualified-symbol (hooks.common/node->qualified-symbol form)]
|
||||
(cond
|
||||
(contains? (:parallel/unsafe config) qualified-symbol)
|
||||
(error! form (format "%s is not allowed inside a ^:parallel test or test fixture [:metabase/validate-deftest]" qualified-symbol))
|
||||
(disallowed-parallel-forms qualified-symbol)
|
||||
(error! form (format "%s is not allowed inside a ^:parallel test or test fixture" qualified-symbol))
|
||||
|
||||
(and (not (contains? (:parallel/safe config) qualified-symbol))
|
||||
(and (not (allowed-parallel-forms qualified-symbol))
|
||||
(str/ends-with? (name qualified-symbol) "!"))
|
||||
(error! form (format "destructive functions like %s are not allowed inside a ^:parallel test or test fixture. If this should be allowed, add it to the whitelist in the Kondo config file [:metabase/validate-deftest]"
|
||||
(error! form (format "destructive functions like %s are not allowed inside a ^:parallel test or test fixture. If this should be allowed, add it to the whitelist in .clj-kondo/hooks/clojure/test.clj"
|
||||
qualified-symbol)))))
|
||||
(walk [form]
|
||||
(f form)
|
||||
@@ -28,7 +135,7 @@
|
||||
(defn- deftest-check-parallel
|
||||
"1. Check if test is marked ^:parallel / ^:synchronized correctly
|
||||
2. Make sure disallowed forms are not used in ^:parallel tests"
|
||||
[{[_ test-name & body] :children, :as _node} config]
|
||||
[{[_ test-name & body] :children, :as _node}]
|
||||
(let [test-metadata (:meta test-name)
|
||||
metadata-sexprs (map hooks/sexpr test-metadata)
|
||||
combined-metadata (transduce
|
||||
@@ -45,9 +152,9 @@
|
||||
(hooks/reg-finding! (assoc (meta test-name)
|
||||
:message "Test should not be marked both ^:parallel and ^:synchronized"
|
||||
:type :metabase/validate-deftest)))
|
||||
;; only when the custom `:metabase/deftest-not-marked-parallel-or-synchronized` is enabled: complain if tests are
|
||||
;; not explicitly marked `^:parallel` or `^:synchronized`. This is mostly to encourage people to mark everything
|
||||
;; `^:parallel` in places like `metabase.lib` tests unless there is a really good reason not to.
|
||||
;; only when the custom `:metabase/deftest-not-marked-parallel` is enabled: complain if tests are not explicitly
|
||||
;; marked `^:parallel` or `^:synchronized`. This is mostly to encourage people to mark everything `^:parallel` in
|
||||
;; places like `metabase.lib` tests unless there is a really good reason not to.
|
||||
(when-not (or parallel? synchronized?)
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta test-name)
|
||||
@@ -55,65 +162,30 @@
|
||||
:type :metabase/deftest-not-marked-parallel-or-synchronized)))
|
||||
(when parallel?
|
||||
(doseq [form body]
|
||||
(warn-about-disallowed-parallel-forms form config)))))
|
||||
(warn-about-disallowed-parallel-forms form)))))
|
||||
|
||||
(def ^:private number-of-lines-for-a-test-to-be-considered-horrifically-long
|
||||
200)
|
||||
|
||||
(defn- deftest-check-not-horrifically-long
|
||||
[node {:keys [max-length], :as _config}]
|
||||
[node]
|
||||
(let [{:keys [row end-row]} (meta node)]
|
||||
(when (and row end-row)
|
||||
(let [num-lines (- end-row row)]
|
||||
(when (and max-length
|
||||
(>= num-lines max-length))
|
||||
(when (>= num-lines number-of-lines-for-a-test-to-be-considered-horrifically-long)
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message (str (format "This test is horrifically long, it's %d lines! 😱 " num-lines)
|
||||
"Do you really want to try to debug it if it fails? 💀 "
|
||||
"Split it up into smaller tests! 🥰")
|
||||
:type :metabase/i-like-making-cams-eyes-bleed-with-horrifically-long-tests)))))))
|
||||
|
||||
(defn- ignore? [node error-type]
|
||||
(when-let [ignores (some-> node meta :clj-kondo/ignore hooks/sexpr)]
|
||||
(when-let [ignores (cond
|
||||
(coll? ignores) (set ignores)
|
||||
(keyword? ignores) #{ignores})]
|
||||
(contains? ignores error-type))))
|
||||
|
||||
(defn deftest-check-no-driver-keywords [node {:keys [drivers], :as _config}]
|
||||
;; fail fast after we see the first error, where we see one hardcoded driver name there are likely several more and we
|
||||
;; don't need multiple warnings for a single test.
|
||||
(letfn [(f [node]
|
||||
(when (and (hooks/keyword-node? node)
|
||||
(set? drivers)
|
||||
(contains? drivers (hooks/sexpr node)))
|
||||
(hooks/reg-finding! (assoc (meta node)
|
||||
:message (format "Do not hardcode driver name %s in driver tests! [:metabase/disallow-hardcoded-driver-names-in-tests]"
|
||||
(hooks/sexpr node))
|
||||
:type :metabase/disallow-hardcoded-driver-names-in-tests))
|
||||
::error))
|
||||
(walk [node]
|
||||
(cond
|
||||
(ignore? node :metabase/disallow-hardcoded-driver-names-in-tests)
|
||||
nil
|
||||
|
||||
(= (f node) ::error)
|
||||
::error
|
||||
|
||||
:else
|
||||
(reduce
|
||||
(fn [_acc child]
|
||||
(when (= (walk child) ::error)
|
||||
(reduced ::error)))
|
||||
nil
|
||||
(:children node))))]
|
||||
(walk node)))
|
||||
|
||||
(defn deftest [{:keys [node cljc lang config]}]
|
||||
(defn deftest [{:keys [node cljc lang]}]
|
||||
;; run [[deftest-check-parallel]] only once... if this is a `.cljc` file only run it for the `:clj` analysis, no point
|
||||
;; in running it twice.
|
||||
(when (or (not cljc)
|
||||
(= lang :clj))
|
||||
(deftest-check-parallel node (get-in config [:linters :metabase/validate-deftest])))
|
||||
(deftest-check-not-horrifically-long node (get-in config [:linters :metabase/i-like-making-cams-eyes-bleed-with-horrifically-long-tests]))
|
||||
(deftest-check-no-driver-keywords node (get-in config [:linters :metabase/disallow-hardcoded-driver-names-in-tests]))
|
||||
(deftest-check-parallel node))
|
||||
(deftest-check-not-horrifically-long node)
|
||||
{:node node})
|
||||
|
||||
;;; this is a hacky way to determine whether these namespaces are required in the `ns` form or not... basically `:ns`
|
||||
@@ -150,11 +222,20 @@
|
||||
|
||||
nil)))))))
|
||||
|
||||
(defn- warn-about-schema= [{[_is assertion-node] :children, :as _is-node}]
|
||||
(let [{[assertion-symb-node] :children} assertion-node]
|
||||
(when (and (hooks/token-node? assertion-symb-node)
|
||||
(= (hooks/sexpr assertion-symb-node) 'schema=))
|
||||
(hooks/reg-finding! (assoc (meta assertion-symb-node)
|
||||
:message "Use =? or malli= instead of schema="
|
||||
:type :metabase/warn-about-schema=)))))
|
||||
|
||||
(defn is [{:keys [node lang]}]
|
||||
(when (= lang :cljs)
|
||||
(warn-about-missing-test-expr-requires-in-cljs node))
|
||||
(warn-about-schema= node)
|
||||
{:node node})
|
||||
|
||||
(defn use-fixtures [{:keys [node config]}]
|
||||
(warn-about-disallowed-parallel-forms node config)
|
||||
(defn use-fixtures [{:keys [node]}]
|
||||
(warn-about-disallowed-parallel-forms node)
|
||||
{:node node})
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
(comment
|
||||
|
||||
(def input (hooks/parse-string
|
||||
"(with-indexed-model! [{:keys [model model-index model-index-value]}
|
||||
{:query :some-query}]
|
||||
"(with-indexed-model [{:keys [model model-index model-index-value]}
|
||||
{:query :some-query}]
|
||||
:foo :bar :body)"))
|
||||
|
||||
(println (hooks/sexpr input))
|
||||
@@ -13,12 +13,12 @@
|
||||
(let [f (load-file ".clj-kondo/hooks/metabase/api/automagic_dashboards_test.clj")]
|
||||
(f {:node input})))
|
||||
|
||||
(defn with-indexed-model!
|
||||
(defn with-indexed-model
|
||||
[{node :node}]
|
||||
(let [[_macro-call binding-and-query-info & body] (:children node)
|
||||
[binding query-info] (:children binding-and-query-info)
|
||||
node* (hooks/list-node
|
||||
[(hooks/token-node 'do-with-indexed-model!)
|
||||
[(hooks/token-node 'do-with-testing-model)
|
||||
query-info
|
||||
(hooks/list-node
|
||||
(list* (hooks/token-node 'fn)
|
||||
|
||||
@@ -15,17 +15,16 @@
|
||||
[arg]
|
||||
(letfn [(update-defendpoint [node]
|
||||
(let [[_defendpoint method route & body] (:children node)]
|
||||
(-> (api/list-node
|
||||
(list
|
||||
(api/token-node 'do)
|
||||
(api/token-node (symbol "compojure.core" (str (api/sexpr method))))
|
||||
(-> (api/list-node
|
||||
(list*
|
||||
(api/token-node 'clojure.core/defn)
|
||||
(api/token-node (route-fn-name (api/sexpr method) (api/sexpr route)))
|
||||
body))
|
||||
(with-meta (meta node)))))
|
||||
(with-meta {:clj-kondo/ignore [:clojure-lsp/unused-public-var]}))))]
|
||||
(api/list-node
|
||||
(list
|
||||
(api/token-node 'do)
|
||||
(api/token-node (symbol "compojure.core" (str (api/sexpr method))))
|
||||
(-> (api/list-node
|
||||
(list*
|
||||
(api/token-node 'clojure.core/defn)
|
||||
(api/token-node (route-fn-name (api/sexpr method) (api/sexpr route)))
|
||||
body))
|
||||
(with-meta (meta node)))))))]
|
||||
(update arg :node update-defendpoint)))
|
||||
|
||||
(comment
|
||||
|
||||
@@ -11,10 +11,6 @@
|
||||
[]
|
||||
(not-empty (set (keys (:clj (hooks/ns-analysis 'metabase.test.data.dataset-definitions))))))
|
||||
|
||||
(defn- local-def?
|
||||
[ns* sexpr]
|
||||
(= ns* (:ns (hooks/resolve {:name sexpr}))))
|
||||
|
||||
(defn- dataset-type
|
||||
"`dataset` can be one of:
|
||||
|
||||
@@ -25,7 +21,7 @@
|
||||
|
||||
We can only determine if an unqualified symbol refers to something in the dataset definitions namespace if there are
|
||||
cached results available from [[global-dataset-symbols]]."
|
||||
[this-ns dataset]
|
||||
[dataset]
|
||||
(let [sexpr (hooks/sexpr dataset)
|
||||
global-defs (global-dataset-symbols)]
|
||||
(cond
|
||||
@@ -35,19 +31,20 @@
|
||||
(namespace sexpr)
|
||||
:qualified
|
||||
|
||||
(empty? global-defs)
|
||||
:unqualified/unknown
|
||||
|
||||
(contains? global-defs sexpr)
|
||||
:unqualified/from-dataset-defs-namespace
|
||||
|
||||
(local-def? this-ns sexpr)
|
||||
:unqualified/local-def
|
||||
|
||||
;; either something defined in the current namespace or let-bound in the current scope.
|
||||
:else
|
||||
:unqualified/unknown)))
|
||||
:unqualified/local-def)))
|
||||
|
||||
(defn dataset
|
||||
[{{[_ dataset & body] :children} :node this-ns :ns}]
|
||||
[{{[_ dataset & body] :children} :node}]
|
||||
(let [noop (constantly nil)
|
||||
body (case (dataset-type this-ns dataset)
|
||||
body (case (dataset-type dataset)
|
||||
;; non-symbol, qualified symbols, and unqualified symbols from the current namespace/let-bound can all
|
||||
;; get converted from something like
|
||||
;;
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
(ns hooks.metabase.util.log.capture
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]))
|
||||
|
||||
(defn with-log-messages-for-level [x]
|
||||
(letfn [(update-binding [[lhs-node _rhs-node]]
|
||||
[lhs-node (api/list-node
|
||||
(list
|
||||
(api/token-node 'clojure.core/fn)
|
||||
(api/vector-node [])))])
|
||||
(update-bindings [bindings-node]
|
||||
(-> (api/vector-node
|
||||
(into []
|
||||
(comp (partition-all 2)
|
||||
(mapcat update-binding))
|
||||
(:children bindings-node)))
|
||||
(with-meta (meta bindings-node))))
|
||||
(update-node [node]
|
||||
(let [[_with-log-messages-for-level bindings & body] (:children node)]
|
||||
(-> (api/list-node
|
||||
(list*
|
||||
(api/token-node 'clojure.core/let)
|
||||
(update-bindings bindings)
|
||||
body))
|
||||
(with-meta (meta node)))))]
|
||||
(update x :node update-node)))
|
||||
@@ -1,52 +0,0 @@
|
||||
(ns hooks.clojure.test-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clj-kondo.impl.utils]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.clojure.test]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn- deftest-warnings
|
||||
[form]
|
||||
(binding [clj-kondo.impl.utils/*ctx* {:config {:linters {:metabase/disallow-hardcoded-driver-names-in-tests {:level :warning}}}
|
||||
:ignores (atom nil)
|
||||
:findings (atom [])
|
||||
:namespaces (atom {})}]
|
||||
(hooks.clojure.test/deftest {:node (api/parse-string form)
|
||||
:config {:linters
|
||||
{:metabase/disallow-hardcoded-driver-names-in-tests
|
||||
{:drivers
|
||||
#{:athena}}}}})
|
||||
(mapv :message @(:findings clj-kondo.impl.utils/*ctx*))))
|
||||
|
||||
(deftest ^:parallel disallow-hardcoded-driver-names-in-tests-test
|
||||
(is (= []
|
||||
(deftest-warnings
|
||||
"(mt/test-drivers (mt/normal-drivers)
|
||||
(do-something))")))
|
||||
(is (= ["Do not hardcode driver name :athena in driver tests! [:metabase/disallow-hardcoded-driver-names-in-tests]"]
|
||||
(deftest-warnings
|
||||
"(mt/test-drivers (mt/normal-drivers)
|
||||
(when-not (= driver/*driver* :athena)
|
||||
(do-something)))")))
|
||||
(testing "make sure :clj-kondo/ignore is propagated correctly"
|
||||
(is (= []
|
||||
(deftest-warnings
|
||||
"(mt/test-drivers (mt/normal-drivers)
|
||||
#_{:clj-kondo/ignore [:metabase/disallow-hardcoded-driver-names-in-tests]}
|
||||
(when-not (= driver/*driver* :athena)
|
||||
(do-something)))")))))
|
||||
|
||||
(deftest ^:parallel check-driver-keywords-test
|
||||
(testing "Make sure we keep hooks.clojure.test/driver-keywords up to date"
|
||||
(let [driver-keywords (-> (slurp ".clj-kondo/config.edn")
|
||||
edn/read-string
|
||||
(get-in [:linters :metabase/disallow-hardcoded-driver-names-in-tests :drivers]))]
|
||||
(doseq [^java.io.File file (.listFiles (io/file "modules/drivers"))
|
||||
:when (.isDirectory file)
|
||||
:let [driver (keyword (.getName file))]]
|
||||
(is (contains? driver-keywords driver)
|
||||
(format "hooks.clojure.test/driver-keywords should contain %s, please add it" driver))))))
|
||||
@@ -1,19 +0,0 @@
|
||||
(ns hooks.metabase.util.log.capture-test
|
||||
(:require
|
||||
[clj-kondo.hooks-api :as api]
|
||||
[clojure.test :refer :all]
|
||||
[hooks.metabase.util.log.capture]))
|
||||
|
||||
(deftest ^:parallel with-log-messages-for-level-test
|
||||
(is (= '(clojure.core/let [messages-1 (clojure.core/fn [])
|
||||
messages-2 (clojure.core/fn [])]
|
||||
(concat (messages-1)
|
||||
(messages-2)))
|
||||
(-> (hooks.metabase.util.log.capture/with-log-messages-for-level
|
||||
{:node (-> '(with-log-messages-for-level [messages-1 [my.namespace :debug]
|
||||
messages-2 :info]
|
||||
(concat (messages-1) (messages-2)))
|
||||
pr-str
|
||||
api/parse-string)})
|
||||
:node
|
||||
api/sexpr))))
|
||||
369
.cljfmt.edn
@@ -1,338 +1,31 @@
|
||||
;; Cljfmt config. See https://github.com/weavejester/cljfmt#formatting-options
|
||||
{:sort-ns-references?
|
||||
true
|
||||
|
||||
:function-arguments-indentation
|
||||
:community
|
||||
|
||||
:parallel?
|
||||
true
|
||||
|
||||
:paths
|
||||
["src"
|
||||
"test"
|
||||
"enterprise/backend"
|
||||
"bin/build"
|
||||
"modules/drivers"
|
||||
#_"dev"]
|
||||
|
||||
;; See https://github.com/weavejester/cljfmt/blob/master/cljfmt/resources/cljfmt/indents/clojure.clj for the default
|
||||
;; definitions
|
||||
;;
|
||||
;; [[:block 0]]
|
||||
;; ^ number of special args
|
||||
;;
|
||||
;; `:block` indentation means format with all arguments indented 2 spaces except for the 'special' arguments which
|
||||
;; normally are supposed to go on the first line. e.g. `let` gets [[:block 1]] because it has one 'special' arg.
|
||||
;;
|
||||
;; [[:inner 0]]
|
||||
;; ^ depth
|
||||
;; [[:inner 2 0]]
|
||||
;; ^ argument index to restrict this rule to
|
||||
;;
|
||||
;; `:inner` indentation is like `:defn` indentation. `[[:inner 0]]` (default for `defn`) means all arguments at depth
|
||||
;; zero get indented 2 spaces if not on the first line regardless of number of elements on the first line.
|
||||
:extra-indents
|
||||
{;; clojure.core stuff
|
||||
fn* [[:inner 0]]
|
||||
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]]
|
||||
clojure.test.check/quick-check [[:block 1]]
|
||||
clojure.tools.macro/macrolet [[:block 1] [:inner 2 0]]
|
||||
clojurewerkz.quartzite.jobs/build [[:default]]
|
||||
clojurewerkz.quartzite.jobs/with-description [[:default]]
|
||||
clojurewerkz.quartzite.jobs/with-identity [[:default]]
|
||||
clojurewerkz.quartzite.schedule.cron/schedule [[:default]]
|
||||
clojurewerkz.quartzite.schedule.cron/with-misfire-handling-instruction-do-nothing [[:default]]
|
||||
clojurewerkz.quartzite.triggers/build [[:default]]
|
||||
clojurewerkz.quartzite.triggers/with-description [[:default]]
|
||||
clojurewerkz.quartzite.triggers/with-identity [[:default]]
|
||||
clojurewerkz.quartzite.triggers/with-priority [[:default]]
|
||||
clojurewerkz.quartzite.triggers/with-schedule [[:default]]
|
||||
def-map-type [[:block 2] [:inner 1]]
|
||||
defprotocol+ [[:block 1] [:inner 1]]
|
||||
defrecord+ [[:block 2] [:inner 1]]
|
||||
deftype+ [[:block 2] [:inner 1]]
|
||||
net.cgrand.macrovich/case [[:block 0]]
|
||||
potemkin.namespaces/import-vars [[:default]]
|
||||
potemkin.types/def-map-type [[:block 2] [:inner 1]]
|
||||
potemkin.types/defprotocol+ [[:block 1] [:inner 1]]
|
||||
potemkin.types/defrecord+ [[:block 2] [:inner 1]]
|
||||
potemkin.types/deftype+ [[:block 2] [:inner 1]]
|
||||
potemkin/def-map-type [[:block 2] [:inner 1]]
|
||||
potemkin/defprotocol+ [[:block 1] [:inner 1]]
|
||||
potemkin/defrecord+ [[:block 2] [:inner 1]]
|
||||
potemkin/deftype+ [[:block 2] [:inner 1]]
|
||||
potemkin/import-vars [[:default]]
|
||||
taoensso.nippy/extend-freeze [[:inner 0]]
|
||||
taoensso.nippy/extend-thaw [[:inner 0]]
|
||||
throttle.core/with-throttling [[:block 1]]
|
||||
;; the rest of the stuff in this list is generated automatically based on `:style/indent` specs
|
||||
;; by running [[dev.generate-cljfmt-config/specs]]... use that code to update this list
|
||||
metabase-enterprise.advanced-permissions.api.util-test/with-impersonations! [[:inner 0]]
|
||||
metabase-enterprise.cache.config-test/with-temp-persist-models [[:block 1]]
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps! [[:inner 0]]
|
||||
metabase-enterprise.sandbox.test-util/with-gtaps-for-user! [[:inner 0]]
|
||||
metabase-enterprise.sandbox.test-util/with-user-attributes [[:block 2]]
|
||||
metabase-enterprise.serialization.test-util/with-dbs [[:inner 0]]
|
||||
metabase-enterprise.serialization.test-util/with-random-dump-dir [[:block 1]]
|
||||
metabase-enterprise.serialization.test-util/with-world [[:block 0]]
|
||||
metabase-enterprise.sso.integrations.jwt-test/with-users-with-email-deleted [[:block 1]]
|
||||
metabase-enterprise.test/with-gtaps! [[:inner 0]]
|
||||
metabase-enterprise.test/with-gtaps-for-user! [[:inner 0]]
|
||||
metabase-enterprise.test/with-user-attributes [[:block 2]]
|
||||
metabase.actions-test/with-actions-test-data-and-actions-permissively-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions [[:block 1]]
|
||||
metabase.actions.test-util/with-actions-disabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-test-data [[:inner 0]]
|
||||
metabase.actions.test-util/with-actions-test-data-and-actions-enabled [[:block 0]]
|
||||
metabase.actions.test-util/with-actions-test-data-tables [[:block 1]]
|
||||
metabase.actions.test-util/with-empty-db [[:inner 0]]
|
||||
metabase.actions.test-util/with-temp-test-data [[:inner 0]]
|
||||
metabase.api.alert-test/with-alert-in-collection [[:block 1]]
|
||||
metabase.api.card-test/with-cards-in-readable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-cards-in-writeable-collection [[:block 1]]
|
||||
metabase.api.card-test/with-ordered-items [[:inner 0]]
|
||||
metabase.api.card-test/with-temp-native-card! [[:block 1]]
|
||||
metabase.api.card-test/with-temp-native-card-with-params! [[:block 1]]
|
||||
metabase.api.collection-test/with-collection-hierarchy [[:block 1]]
|
||||
metabase.api.collection-test/with-french-user-and-personal-collection [[:block 2]]
|
||||
metabase.api.collection-test/with-some-children-of-collection [[:block 1]]
|
||||
metabase.api.common/check [[:default]]
|
||||
metabase.api.common/define-routes [[:block 0]]
|
||||
metabase.api.common/let-404 [[:block 1]]
|
||||
metabase.api.common.internal/auto-coerce [[:block 1]]
|
||||
metabase.api.common.internal/auto-parse [[:block 1]]
|
||||
metabase.api.common.internal-test/no-route-regexes [[:block 0]]
|
||||
metabase.api.embed-test/do-response-formats [[:block 1]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.api.embed-test/with-embedding-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.api.embed-test/with-new-secret-key [[:block 0]]
|
||||
metabase.api.embed-test/with-temp-card [[:block 1]]
|
||||
metabase.api.embed-test/with-temp-dashcard [[:block 1]]
|
||||
metabase.api.preview-embed-test/with-embedding-enabled-and-new-secret-key [[:block 0]]
|
||||
metabase.api.preview-embed-test/with-new-secret-key [[:block 0]]
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-card-referencing [[:block 3]]
|
||||
metabase.api.public-test/with-sharing-enabled-and-temp-dashcard-referencing [[:block 3]]
|
||||
metabase.api.public-test/with-temp-public-card [[:block 1]]
|
||||
metabase.api.public-test/with-temp-public-dashboard [[:block 1]]
|
||||
metabase.api.public-test/with-temp-public-dashboard-and-card [[:block 1]]
|
||||
metabase.api.search-test/do-test-users [[:block 1]]
|
||||
metabase.api.session/http-401-on-error [[:block 0]]
|
||||
metabase.async.streaming-response/streaming-response [[:block 2]]
|
||||
metabase.async.streaming-response-test/with-streaming-response-thread-pool [[:block 0]]
|
||||
metabase.async.streaming-response-test/with-test-driver-db! [[:block 0]]
|
||||
metabase.async.util/cancelable-thread [[:block 0]]
|
||||
metabase.cmd.copy/step [[:block 1]]
|
||||
metabase.cmd.copy/with-connection-rollback-only [[:block 1]]
|
||||
metabase.cmd.copy/with-disabled-db-constraints [[:block 2]]
|
||||
metabase.config/build-type-case [[:block 0]]
|
||||
metabase.dashboard-subscription-test/with-link-card-fixture-for-dashboard [[:block 2]]
|
||||
metabase.db.liquibase/with-liquibase [[:block 1]]
|
||||
metabase.db.liquibase/with-scope-locked [[:block 1]]
|
||||
metabase.db.schema-migrations-test.impl/test-migrations [[:block 2]]
|
||||
metabase.db/with-application-db [[:inner 0]]
|
||||
metabase.driver.bigquery-cloud-sdk.query-processor/with-temporal-type [[:default]]
|
||||
metabase.driver.druid.client/DELETE [[:default]]
|
||||
metabase.driver.druid.client/GET [[:default]]
|
||||
metabase.driver.druid.client/POST [[:default]]
|
||||
metabase.driver.druid.query-processor-test/druid-query [[:block 0]]
|
||||
metabase.driver.druid.query-processor-test/druid-query-returning-rows [[:block 0]]
|
||||
metabase.driver.mongo.query-processor/mongo-let [[:block 1]]
|
||||
metabase.driver.sql-jdbc.actions/with-jdbc-transaction [[:block 1]]
|
||||
metabase.driver.sql-jdbc.connection/with-connection-spec-for-testing-connection [[:block 1]]
|
||||
metabase.driver.sql-jdbc.execute.diagnostic/capturing-diagnostic-info [[:block 1]]
|
||||
metabase.driver.sql.query-processor/apply-top-level-clause [[:default]]
|
||||
metabase.driver/with-driver [[:block 1]]
|
||||
metabase.lib.binning/with-binning [[:default]]
|
||||
metabase.lib.core/with-binning [[:default]]
|
||||
metabase.lib.core/with-join-alias [[:default]]
|
||||
metabase.lib.core/with-join-conditions [[:default]]
|
||||
metabase.lib.join/with-join-alias [[:default]]
|
||||
metabase.lib.join/with-join-conditions [[:default]]
|
||||
metabase.lib.test-util.macros/$ids [[:inner 0]]
|
||||
metabase.lib.test-util.macros/mbql-query [[:inner 0]]
|
||||
metabase.lib.util.match/match [[:inner 0]]
|
||||
metabase.lib.util.match/match-one [[:inner 0]]
|
||||
metabase.lib.util.match/replace [[:inner 0]]
|
||||
metabase.lib.util.match/replace-in [[:inner 0]]
|
||||
metabase.models.collection-test/with-collection-hierarchy [[:block 1]]
|
||||
metabase.models.collection-test/with-current-user-perms-for-collections [[:block 1]]
|
||||
metabase.models.collection-test/with-personal-and-impersonal-collections [[:block 1]]
|
||||
metabase.models.dashboard-test/with-dash-in-collection [[:inner 0]]
|
||||
metabase.models.interface/define-batched-hydration-method [[:inner 0]]
|
||||
metabase.models.interface/define-simple-hydration-method [[:inner 0]]
|
||||
metabase.models.params.chain-filter-test/with-clean-field-values-for-field [[:block 1]]
|
||||
metabase.models.params.chain-filter-test/with-fk-field-to-field-remapping [[:block 0]]
|
||||
metabase.models.params.chain-filter-test/with-human-readable-values-remapping [[:block 0]]
|
||||
metabase.models.pulse-test/with-dashboard-subscription-in-collection [[:block 1]]
|
||||
metabase.models.pulse-test/with-pulse-in-collection [[:inner 0]]
|
||||
metabase.models.setting/defsetting [[:block 1]]
|
||||
metabase.models.setting.multi-setting/define-multi-setting [[:inner 0]]
|
||||
metabase.models.task-history/with-task-history [[:block 1]]
|
||||
metabase.query-processor-test.pipeline-queries-test/pmbql-query [[:block 1]]
|
||||
metabase.query-processor-test.pipeline-queries-test/run-pmbql-query [[:block 1]]
|
||||
metabase.query-processor.debug/debug> [[:block 0]]
|
||||
metabase.query-processor.error-type/deferror [[:block 1]]
|
||||
metabase.query-processor.middleware.cache-backend.interface/with-cached-results [[:block 4]]
|
||||
metabase.query-processor.middleware.process-userland-query-test/with-query-execution [[:block 1]]
|
||||
metabase.query-processor.store/cached [[:block 1]]
|
||||
metabase.query-processor.store/with-metadata-provider [[:inner 0]]
|
||||
metabase.query-processor.streaming/streaming-response [[:block 1]]
|
||||
metabase.query-processor.test-util/format-rows-by [[:default]]
|
||||
metabase.sample-data-test/with-temp-sample-database-db [[:block 1]]
|
||||
metabase.server.middleware.session/as-admin [[:block 0]]
|
||||
metabase.server.middleware.session/with-current-user [[:inner 0]]
|
||||
metabase.shared.util.i18n/trs [[:default]]
|
||||
metabase.shared.util.i18n/trsn [[:default]]
|
||||
metabase.shared.util.i18n/tru [[:default]]
|
||||
metabase.shared.util.i18n/trun [[:default]]
|
||||
metabase.shared.util.namespaces/import-fns [[:default]]
|
||||
metabase.sync.fetch-metadata/log-if-error [[:block 1]]
|
||||
metabase.sync.sync-metadata.fields-test/with-test-db [[:block 0]]
|
||||
metabase.sync.util/do-with-start-and-finish-debug-logging [[:default]]
|
||||
metabase.sync.util/sum-for [[:block 1]]
|
||||
metabase.sync.util/sync-operation [[:block 3]]
|
||||
metabase.sync.util/with-db-logging-disabled [[:default]]
|
||||
metabase.sync.util/with-duplicate-ops-prevented [[:default]]
|
||||
metabase.sync.util/with-emoji-progress-bar [[:block 1]]
|
||||
metabase.sync.util/with-error-handling [[:block 1]]
|
||||
metabase.sync.util/with-start-and-finish-logging [[:default]]
|
||||
metabase.sync.util/with-start-and-finish-logging* [[:default]]
|
||||
metabase.sync.util/with-sync-events [[:default]]
|
||||
metabase.test/$ids [[:inner 0]]
|
||||
metabase.test/as-admin [[:inner 0]]
|
||||
metabase.test/dataset [[:inner 0]]
|
||||
metabase.test/discard-setting-changes [[:block 1]]
|
||||
metabase.test/format-rows-by [[:default]]
|
||||
metabase.test/let-url [[:block 1]]
|
||||
metabase.test/mbql-query [[:inner 0]]
|
||||
metabase.test/native-query [[:block 0]]
|
||||
metabase.test/query [[:block 1]]
|
||||
metabase.test/run-mbql-query [[:inner 0]]
|
||||
metabase.test/test-driver [[:inner 0]]
|
||||
metabase.test/test-drivers [[:inner 0]]
|
||||
metabase.test/test-helpers-set-global-values! [[:block 0]]
|
||||
metabase.test/throw-if-called! [[:block 1]]
|
||||
metabase.test/with-actions [[:block 1]]
|
||||
metabase.test/with-actions-disabled [[:block 0]]
|
||||
metabase.test/with-actions-enabled [[:block 0]]
|
||||
metabase.test/with-actions-test-data [[:inner 0]]
|
||||
metabase.test/with-actions-test-data-and-actions-enabled [[:block 0]]
|
||||
metabase.test/with-actions-test-data-tables [[:block 1]]
|
||||
metabase.test/with-additional-premium-features [[:block 1]]
|
||||
metabase.test/with-current-user [[:inner 0]]
|
||||
metabase.test/with-driver [[:block 1]]
|
||||
metabase.test/with-empty-db [[:inner 0]]
|
||||
metabase.test/with-empty-h2-app-db [[:block 0]]
|
||||
metabase.test/with-metadata-provider [[:inner 0]]
|
||||
metabase.test/with-premium-features [[:block 1]]
|
||||
metabase.test/with-temp [[:inner 0]]
|
||||
metabase.test/with-temp-copy-of-db [[:block 0]]
|
||||
metabase.test/with-temp-scheduler [[:block 0]]
|
||||
metabase.test/with-temp-test-data [[:inner 0]]
|
||||
metabase.test/with-temp-vals-in-db [[:block 3]]
|
||||
metabase.test/with-test-user [[:inner 0]]
|
||||
metabase.test/with-user-in-groups [[:inner 0]]
|
||||
metabase.test.data/$ids [[:inner 0]]
|
||||
metabase.test.data/dataset [[:inner 0]]
|
||||
metabase.test.data/mbql-query [[:inner 0]]
|
||||
metabase.test.data/native-query [[:block 0]]
|
||||
metabase.test.data/query [[:block 1]]
|
||||
metabase.test.data/run-mbql-query [[:inner 0]]
|
||||
metabase.test.data/with-empty-h2-app-db [[:block 0]]
|
||||
metabase.test.data/with-temp-copy-of-db [[:block 0]]
|
||||
metabase.test.data.datasets/test-driver [[:inner 0]]
|
||||
metabase.test.data.datasets/test-drivers [[:inner 0]]
|
||||
metabase.test.data.one-off-dbs/with-blank-db [[:block 0]]
|
||||
metabase.test.data.one-off-dbs/with-blueberries-db [[:block 0]]
|
||||
metabase.test.data.users/with-test-user [[:inner 0]]
|
||||
metabase.test.util/discard-setting-changes [[:block 1]]
|
||||
metabase.test.util/let-url [[:block 1]]
|
||||
metabase.test.util/throw-if-called! [[:block 1]]
|
||||
metabase.test.util/with-temp-scheduler [[:block 0]]
|
||||
metabase.test.util/with-temp-vals-in-db [[:block 3]]
|
||||
metabase.test.util/with-user-in-groups [[:inner 0]]
|
||||
metabase.test.util.public-settings/with-additional-premium-features [[:block 1]]
|
||||
metabase.test.util.public-settings/with-premium-features [[:block 1]]
|
||||
metabase.test.util.thread-local/test-helpers-set-global-values! [[:block 0]]
|
||||
metabase.timeseries-query-processor-test.util/test-timeseries-drivers [[:block 0]]
|
||||
metabase.timeseries-query-processor-test/run-mbql-query [[:inner 0]]
|
||||
metabase.upload-test/with-upload-table! [[:inner 0]]
|
||||
metabase.upload.types/with-currency [[:default]]
|
||||
metabase.upload.types/with-parens [[:default]]
|
||||
metabase.util/auto-retry [[:block 1]]
|
||||
metabase.util/ignore-exceptions [[:block 0]]
|
||||
metabase.util/or-with [[:block 1]]
|
||||
metabase.util/profile [[:block 1]]
|
||||
metabase.util/prog1 [[:inner 0]]
|
||||
metabase.util/varargs [[:inner 0]]
|
||||
metabase.util/with-us-locale [[:block 0]]
|
||||
metabase.util.date-2/with-time-zone-same-instant [[:default]]
|
||||
metabase.util.encryption-test/with-secret-key [[:block 1]]
|
||||
metabase.util.honey-sql-2/with-database-type-info [[:default]]
|
||||
metabase.util.i18n/deferred-trs [[:default]]
|
||||
metabase.util.i18n/deferred-tru [[:default]]
|
||||
metabase.util.i18n/trs [[:default]]
|
||||
metabase.util.i18n/tru [[:default]]
|
||||
metabase.util.jvm/auto-retry [[:block 1]]
|
||||
metabase.util.jvm/varargs [[:block 1]]
|
||||
metabase.util.jvm/with-us-locale [[:block 0]]
|
||||
metabase.util.malli/disable-enforcement [[:block 0]]
|
||||
metabase.util.malli/with [[:default]]
|
||||
metabase.util.malli/with-api-error-message [[:default]]
|
||||
metabuild-common.core/exit-when-finished-nonzero-on-exception [[:block 0]]
|
||||
metabuild-common.core/step [[:block 1]]
|
||||
metabuild-common.entrypoint/exit-when-finished-nonzero-on-exception [[:block 0]]
|
||||
metabuild-common.steps/step [[:block 1]]
|
||||
methodical.core/defmethod [[:inner 0]]
|
||||
methodical.core/defmulti [[:inner 0]]
|
||||
methodical.core/with-dispatcher [[:default]]
|
||||
methodical.core/with-method-table [[:default]]
|
||||
methodical.core/with-prefers [[:default]]
|
||||
methodical.interface/with-dispatcher [[:default]]
|
||||
methodical.interface/with-method-table [[:default]]
|
||||
methodical.interface/with-prefers [[:default]]
|
||||
methodical.macros/defmethod [[:inner 0]]
|
||||
methodical.macros/defmulti [[:inner 0]]
|
||||
saml20-clj.sp.response/validate-confirmation-datas [[:block 1]]
|
||||
toucan2.connection/with-transaction [[:block 1]]
|
||||
toucan2.core/build [[:block 0]]
|
||||
toucan2.core/compile [[:block 0]]
|
||||
toucan2.core/debug [[:block 0]]
|
||||
toucan2.core/define-after-insert [[:inner 0]]
|
||||
toucan2.core/define-after-select [[:inner 0]]
|
||||
toucan2.core/define-after-update [[:inner 0]]
|
||||
toucan2.core/define-before-delete [[:inner 0]]
|
||||
toucan2.core/define-before-insert [[:inner 0]]
|
||||
toucan2.core/define-before-select [[:inner 0]]
|
||||
toucan2.core/define-default-fields [[:inner 0]]
|
||||
toucan2.core/define-named-query [[:block 1]]
|
||||
toucan2.core/deftransforms [[:block 1]]
|
||||
toucan2.core/with-transaction [[:block 1]]
|
||||
toucan2.tools.after/define-after-impl [[:default]]
|
||||
toucan2.tools.after-insert/define-after-insert [[:inner 0]]
|
||||
toucan2.tools.after-select/define-after-select [[:inner 0]]
|
||||
toucan2.tools.after-update/define-after-update [[:inner 0]]
|
||||
toucan2.tools.before-delete/define-before-delete [[:inner 0]]
|
||||
toucan2.tools.before-insert/define-before-insert [[:inner 0]]
|
||||
toucan2.tools.before-select/define-before-select [[:inner 0]]
|
||||
toucan2.tools.compile/build [[:block 0]]
|
||||
toucan2.tools.compile/compile [[:block 0]]
|
||||
toucan2.tools.compile/resolved [[:block 0]]
|
||||
toucan2.tools.debug/debug [[:block 0]]
|
||||
toucan2.tools.default-fields/define-default-fields [[:inner 0]]
|
||||
toucan2.tools.named-query/define-named-query [[:block 1]]
|
||||
toucan2.tools.simple-out-transform/define-out-transform [[:inner 0]]
|
||||
toucan2.tools.transformed/deftransforms [[:block 1]]
|
||||
toucan2.tools.with-temp/with-temp [[:inner 0]]
|
||||
toucan2.util/try-with-error-context [[:inner 0]]}}
|
||||
;; https://github.com/weavejester/cljfmt/blob/master/cljfmt/resources/cljfmt/indents/clojure.clj
|
||||
{:extra-indents
|
||||
{auto-parse [[:inner 0]]
|
||||
cond-> [[:inner 0]]
|
||||
check [[:inner 0]]
|
||||
deferred-tru [[:inner 0]]
|
||||
defprotocol+ [[:block 1] [:inner 1]]
|
||||
potemkin/defprotocol+ [[:block 1] [:inner 1]]
|
||||
let-404 [[:block 1]]
|
||||
metabase.legacy-mbql.util/match-one [[:inner 0]]
|
||||
merge-with [[:inner 0]]
|
||||
metabase.test/dataset [[:inner 0]]
|
||||
metabase.test/formatted-rows [[:inner 0]]
|
||||
metabase.test/mbql-query [[:inner 0]]
|
||||
metabase.test/test-drivers [[:inner 0]]
|
||||
metabase.test/with-temporary-setting-values [[:block 1]]
|
||||
;; If we just treat these as functions we can ignore this, despite some files not being consistent
|
||||
;metabase.models.permissions/set-has-full-permissions-for-set? [[:inner 0]]
|
||||
;metabase.models.permissions/set-has-full-permissions? [[:inner 0]]
|
||||
;metabase.models.permissions/set-has-partial-permissions? [[:inner 0]]
|
||||
metabase.models.permissions/set-has-partial-permissions-for-set? [[:inner 0]]
|
||||
publish-event! [[:block 1]]
|
||||
metabase.query-processor.streaming/streaming-response [[:inner 0]]
|
||||
metabase.util/prog1 [[:inner 0]]
|
||||
metabase.util/select-keys-when [[:inner 0]]
|
||||
;; This supports a lot of existing formatting, but these are functions so the
|
||||
;; existing formatting is probably wrong.
|
||||
;toucan2.core/select [[:inner 0]]
|
||||
;toucan2.core/update! [[:inner 0]]
|
||||
}
|
||||
:sort-ns-references? true}
|
||||
|
||||
@@ -20,67 +20,67 @@
|
||||
(clojure-mode
|
||||
;; Specify which arg is the docstring for certain macros
|
||||
;; (Add more as needed)
|
||||
(eval . (put 'defendpoint-schema 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defendpoint 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defendpoint-async 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'define-premium-feature 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'api/defendpoint-schema 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'api/defendpoint 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'api/defendpoint-async 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defsetting 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'setting/defsetting 'clojure-doc-string-elt 2))
|
||||
(eval . (put 's/defn 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'p.types/defprotocol+ 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'methodical/defmethod 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'methodical/defmulti 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'mi/define-simple-hydration-method 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defendpoint-schema 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defendpoint 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defendpoint-async 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'define-premium-feature 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'api/defendpoint-schema 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'api/defendpoint 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'api/defendpoint-async 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'defsetting 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'setting/defsetting 'clojure-doc-string-elt 2))
|
||||
(eval . (put 's/defn 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'p.types/defprotocol+ 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'methodical/defmethod 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'methodical/defmulti 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'mi/define-simple-hydration-method 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'mi/define-batched-hydration-method 'clojure-doc-string-elt 3))
|
||||
(eval . (put 'mr/def 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'mu/defn 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'mr/def 'clojure-doc-string-elt 2))
|
||||
(eval . (put 'mu/defn 'clojure-doc-string-elt 2))
|
||||
;; Define custom indentation for functions inside metabase.
|
||||
;; This list isn't complete; add more forms as we come across them.
|
||||
;;
|
||||
;; `put-clojure-indent' is a safe-local-eval-function, so use a bunch of calls to that
|
||||
;; instead of one call to `define-clojure-indent'
|
||||
(eval . (put-clojure-indent 'api/let-404 1))
|
||||
(eval . (put-clojure-indent 'c/step 1))
|
||||
(eval . (put-clojure-indent 'impl/test-migrations 2))
|
||||
(eval . (put-clojure-indent 'let-404 0))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/match '(:defn)))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/match-one '(:defn)))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/replace '(:defn)))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/replace-in '(:defn)))
|
||||
(eval . (put-clojure-indent 'lib.util.match/replace '(:defn)))
|
||||
(eval . (put-clojure-indent 'macros/case 0))
|
||||
(eval . (put-clojure-indent 'match 1))
|
||||
(eval . (put-clojure-indent 'mt/dataset 1))
|
||||
(eval . (put-clojure-indent 'mt/format-rows-by '(:form)))
|
||||
(eval . (put-clojure-indent 'mt/query 1))
|
||||
(eval . (put-clojure-indent 'mt/test-driver 1))
|
||||
(eval . (put-clojure-indent 'mt/test-drivers 1))
|
||||
(eval . (put-clojure-indent 'mt/with-anaphora 1))
|
||||
(eval . (put-clojure-indent 'prop/for-all 1))
|
||||
(eval . (put-clojure-indent 'api/let-404 1))
|
||||
(eval . (put-clojure-indent 'c/step 1))
|
||||
(eval . (put-clojure-indent 'impl/test-migrations 2))
|
||||
(eval . (put-clojure-indent 'let-404 0))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/match 1))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/match-one 1))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/replace 1))
|
||||
(eval . (put-clojure-indent 'lib.schema.match/replace-in 2))
|
||||
(eval . (put-clojure-indent 'lib.util.match/replace 1))
|
||||
(eval . (put-clojure-indent 'macros/case 0))
|
||||
(eval . (put-clojure-indent 'match 1))
|
||||
(eval . (put-clojure-indent 'mi/define-methods '(:form)))
|
||||
(eval . (put-clojure-indent 'mt/dataset 1))
|
||||
(eval . (put-clojure-indent 'mt/format-rows-by 1))
|
||||
(eval . (put-clojure-indent 'mt/query 1))
|
||||
(eval . (put-clojure-indent 'mt/test-driver 1))
|
||||
(eval . (put-clojure-indent 'mt/test-drivers 1))
|
||||
(eval . (put-clojure-indent 'prop/for-all 1))
|
||||
(eval . (put-clojure-indent 'qp.streaming/streaming-response 1))
|
||||
(eval . (put-clojure-indent 'tc/quick-check 1))
|
||||
(eval . (put-clojure-indent 'u/profile 1))
|
||||
(eval . (put-clojure-indent 'u/prog1 1))
|
||||
(eval . (put-clojure-indent 'u/select-keys-when '(:form)))
|
||||
(eval . (put-clojure-indent 'with-meta '(:form)))
|
||||
(eval . (put-clojure-indent 'tc/quick-check 1))
|
||||
(eval . (put-clojure-indent 'u/profile 1))
|
||||
(eval . (put-clojure-indent 'u/prog1 1))
|
||||
(eval . (put-clojure-indent 'u/select-keys-when 1))
|
||||
(eval . (put-clojure-indent 'with-meta '(:form)))
|
||||
;; these ones have to be done with `define-clojure-indent' for now because of upstream bug
|
||||
;; https://github.com/clojure-emacs/clojure-mode/issues/600 once that's resolved we should use `put-clojure-indent'
|
||||
;; instead. Please don't add new entries unless they don't work with `put-clojure-indent'
|
||||
(eval . (define-clojure-indent
|
||||
(l/matcha '(1 (:defn)))
|
||||
(l/matche '(1 (:defn)))
|
||||
(l/matcha '(1 (:defn)))
|
||||
(l/matche '(1 (:defn)))
|
||||
(p.types/def-abstract-type '(1 (:defn)))
|
||||
(p.types/defprotocol+ '(1 (:defn)))
|
||||
(p.types/defrecord+ '(2 nil nil (:defn)))
|
||||
(p.types/deftype+ '(2 nil nil (:defn)))
|
||||
(p/def-map-type '(2 nil nil (:defn)))
|
||||
(p/defprotocol+ '(1 (:defn)))
|
||||
(p/defrecord+ '(2 nil nil (:defn)))
|
||||
(p/deftype+ '(2 nil nil (:defn)))
|
||||
(tools.macro/macrolet '(1 ((:defn)) :form))))
|
||||
(p.types/defprotocol+ '(1 (:defn)))
|
||||
(p.types/defrecord+ '(2 nil nil (:defn)))
|
||||
(p.types/deftype+ '(2 nil nil (:defn)))
|
||||
(p/def-map-type '(2 nil nil (:defn)))
|
||||
(p/defprotocol+ '(1 (:defn)))
|
||||
(p/defrecord+ '(2 nil nil (:defn)))
|
||||
(p/deftype+ '(2 nil nil (:defn)))
|
||||
(tools.macro/macrolet '(1 ((:defn)) :form))))
|
||||
(cider-clojure-cli-aliases . "dev:drivers:drivers-dev:ee:ee-dev:user")
|
||||
(clojure-indent-style . always-align)
|
||||
(cljr-favor-prefix-notation . nil)
|
||||
|
||||
30
.eslintrc.js
@@ -62,13 +62,6 @@ module.exports = {
|
||||
warnOnUnassignedImports: false,
|
||||
},
|
||||
],
|
||||
"sort-imports": [
|
||||
"error",
|
||||
{
|
||||
// allows this rule to work with import/order
|
||||
ignoreDeclarationSort: true,
|
||||
},
|
||||
],
|
||||
"no-console": [2, { allow: ["warn", "error", "errorBuffer"] }],
|
||||
"react/no-is-mounted": 2,
|
||||
"react/prefer-es6-class": 2,
|
||||
@@ -85,10 +78,9 @@ module.exports = {
|
||||
"react/forbid-component-props": [2, { forbid: ["sx"] }],
|
||||
"react-hooks/exhaustive-deps": [
|
||||
"warn",
|
||||
{ additionalHooks: "(useSafeAsyncFunction)" },
|
||||
{ additionalHooks: "(useSyncedQueryString|useSafeAsyncFunction)" },
|
||||
],
|
||||
"prefer-const": [1, { destructuring: "all" }],
|
||||
"no-restricted-globals": ["error", "close"],
|
||||
"no-useless-escape": 0,
|
||||
"no-only-tests/no-only-tests": [
|
||||
"error",
|
||||
@@ -141,7 +133,6 @@ module.exports = {
|
||||
"plugin:import/errors",
|
||||
"plugin:import/warnings",
|
||||
"plugin:import/typescript",
|
||||
"plugin:depend/recommended",
|
||||
],
|
||||
settings: {
|
||||
"import/internal-regex": "^metabase/|^metabase-lib/",
|
||||
@@ -169,17 +160,6 @@ module.exports = {
|
||||
rules: {
|
||||
"no-unconditional-metabase-links-render": "error",
|
||||
"no-literal-metabase-strings": "error",
|
||||
"depend/ban-dependencies": [
|
||||
"error",
|
||||
{
|
||||
allowed: [
|
||||
"underscore",
|
||||
"moment",
|
||||
"lodash.orderby",
|
||||
"lodash.debounce",
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -209,13 +189,7 @@ module.exports = {
|
||||
"@typescript-eslint/no-inferrable-types": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-this-alias": "off",
|
||||
"@typescript-eslint/consistent-type-imports": [
|
||||
"error",
|
||||
{
|
||||
fixStyle: "inline-type-imports",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-import-type-side-effects": "error",
|
||||
"@typescript-eslint/consistent-type-imports": "error",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
|
||||
6
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,5 +1,9 @@
|
||||
> [!IMPORTANT]
|
||||
> For those employed by Metabase: if you are merging into master, please add either a `backport` or a `no-backport` label to this PR. You will not be able to merge until you do this step. Refer to the section [Do I need to backport this PR?](https://www.notion.so/metabase/Metabase-Branching-Strategy-6eb577d5f61142aa960a626d6bbdfeb3?pvs=4#89f80d6f17714a0198aeb66c0efd1b71) in the Metabase Branching Strategy document for more details. If you're not employed by Metabase, this section does not apply to you, and the label will be taken care of by your reviewer.
|
||||
> For those employed by Metabase: if you are merging into master, please add either a `backport` or a `no-backport` label
|
||||
> to this PR. You will not be able to merge until you do this step. Refer to the section [Do I need to backport this
|
||||
> PR?](https://www.notion.so/metabase/Metabase-Branching-Strategy-6eb577d5f61142aa960a626d6bbdfeb3?pvs=4#89f80d6f17714a0198aeb66c0efd1b71)
|
||||
> in the Metabase Branching Strategy document for more details. If you're not employed by Metabase, this section does not
|
||||
> apply to you, and the label will be taken care of by your reviewer.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
|
||||
1
.github/actions/build-e2e-matrix/action.yml
vendored
@@ -35,7 +35,6 @@ runs:
|
||||
["dashboard-cards", {} ],
|
||||
["dashboard-filters", {} ],
|
||||
["embedding", {} ],
|
||||
["embedding-sdk", { context: "embedding-sdk" } ],
|
||||
["filters", {} ],
|
||||
["filters-reproductions", {}],
|
||||
["joins", {} ],
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
name: Cross-branch migration test
|
||||
|
||||
inputs:
|
||||
base-ref:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Check out base branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ inputs.base-ref }}
|
||||
|
||||
- name: Prepare backend environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: cross-branch-migrations
|
||||
|
||||
- name: Run backend on base branch
|
||||
run: |
|
||||
clojure -M:run:ee > metabase.log 2>&1 & echo $! > metabase_pid
|
||||
tail -F metabase.log &
|
||||
shell: bash
|
||||
|
||||
- name: Wait for Metabase to start
|
||||
run: |
|
||||
while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}' > /dev/null; do
|
||||
if ! kill -0 $(cat metabase_pid) 2>/dev/null; then
|
||||
cat metabase.log
|
||||
echo "Metabase process has exited."
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
shell: bash
|
||||
|
||||
- name: Stop Metabase on base branch
|
||||
run: kill $(cat metabase_pid)
|
||||
shell: bash
|
||||
|
||||
- name: Check out pull request branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: Run backend on pull request branch
|
||||
run: |
|
||||
clojure -M:run:ee > metabase.log 2>&1 & echo $! > metabase_pid
|
||||
tail -F metabase.log &
|
||||
shell: bash
|
||||
|
||||
- name: Wait for Metabase to start
|
||||
run: |
|
||||
while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}' > /dev/null; do
|
||||
if ! kill -0 $(cat metabase_pid) 2>/dev/null; then
|
||||
cat metabase.log
|
||||
echo "Metabase process has exited. Check that your migration changes work on an instance that has been previously initialized on your PR's target branch."
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
shell: bash
|
||||
|
||||
- name: Stop Metabase on pull request branch
|
||||
run: kill $(cat metabase_pid)
|
||||
shell: bash
|
||||
14
.github/actions/prepare-cypress/action.yml
vendored
@@ -1,20 +1,12 @@
|
||||
name: Prepare cypress environment
|
||||
description: Cypress preparation steps
|
||||
|
||||
outputs:
|
||||
chrome-path:
|
||||
description: Path to the custom Chrome executable
|
||||
value: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Install Chrome v111
|
||||
uses: browser-actions/setup-chrome@v1
|
||||
with:
|
||||
# https://chromium.cypress.io/linux/stable/111.0.5563.146
|
||||
chrome-version: 1097615
|
||||
id: setup-chrome
|
||||
- name: Install Replay.io browser
|
||||
run: npx @replayio/cypress install
|
||||
shell: bash
|
||||
|
||||
- name: Check to see if dependencies should be cached
|
||||
if: ${{ contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
|
||||
22
.github/actions/prepare-frontend/action.yml
vendored
@@ -1,17 +1,11 @@
|
||||
name: Prepare front-end environment
|
||||
inputs:
|
||||
node-version:
|
||||
description: "The version of Node.js to use, overriding .nvmrc"
|
||||
required: false
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Prepare Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: ${{ inputs.node-version }} # this overrides, if present
|
||||
node-version-file: ".nvmrc"
|
||||
|
||||
- name: Check to see if dependencies should be cached
|
||||
if: ${{ contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
run: |
|
||||
@@ -24,27 +18,11 @@ runs:
|
||||
with:
|
||||
path: ~/.m2
|
||||
key: ${{ runner.os }}-cljs-${{ hashFiles('**/shadow-cljs.edn') }}
|
||||
|
||||
- name: Get node_modules cache
|
||||
uses: actions/cache@v4
|
||||
id: node-modules-cache
|
||||
if: ${{ !contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
with:
|
||||
path: node_modules
|
||||
key: ${{ runner.os }}-node-modules-${{ hashFiles('**/yarn.lock', '**/patches/*.patch') }}
|
||||
|
||||
- name: Get yarn cache directory path
|
||||
id: yarn-cache-dir-path
|
||||
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
||||
run: echo "dir=$(yarn cache dir)" >> $GITHUB_OUTPUT
|
||||
shell: bash
|
||||
|
||||
- uses: actions/cache@v4
|
||||
if: steps.node-modules-cache.outputs.cache-hit != 'true'
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: ${{ runner.os }}-yarn-
|
||||
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
shell: bash
|
||||
|
||||
@@ -1,33 +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
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
|
||||
- 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
|
||||
6
.github/actions/test-driver/action.yml
vendored
@@ -2,7 +2,7 @@ name: Test database driver
|
||||
inputs:
|
||||
junit-name:
|
||||
required: true
|
||||
default: "driver"
|
||||
default: 'driver'
|
||||
test-args:
|
||||
required: false
|
||||
|
||||
@@ -14,7 +14,7 @@ runs:
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: driver
|
||||
m2-cache-key: driver-${{ inputs.junit-name }}
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
shell: bash
|
||||
@@ -25,7 +25,7 @@ runs:
|
||||
uses: dorny/test-reporter@v1
|
||||
if: failure()
|
||||
with:
|
||||
path: "target/junit/**/*_test.xml"
|
||||
path: 'target/junit/**/*_test.xml'
|
||||
name: JUnit Test Report ${{ inputs.junit-name }}
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
|
||||
17
.github/auto_request_review.yml
vendored
@@ -1,17 +0,0 @@
|
||||
# The reviewers configuration for the auto_request_review workflow
|
||||
# See https://github.com/necojackarc/auto-request-review/tree/master?tab=readme-ov-file#reviewers-configuration
|
||||
# for the spec
|
||||
|
||||
files:
|
||||
# migrations related files
|
||||
'resources/migrations/**':
|
||||
- team:core-backend-components
|
||||
'src/metabase/db/custom_migrations.clj':
|
||||
- team:core-backend-components
|
||||
|
||||
options:
|
||||
ignore_draft: true
|
||||
ignored_keywords:
|
||||
- DO NOT REVIEW
|
||||
- WIP
|
||||
enable_group_assignment: false
|
||||
15
.github/file-paths.yaml
vendored
@@ -35,22 +35,14 @@ frontend_specs: &frontend_specs
|
||||
- "frontend/test/**"
|
||||
- "frontend/**/tests/**"
|
||||
- "frontend/**/*.unit.*"
|
||||
- "jest.config.js"
|
||||
- "jest.config.json"
|
||||
- "jest.tz.unit.conf.json"
|
||||
|
||||
release_source: &release_sources
|
||||
- "release/**"
|
||||
|
||||
frontend_all: &frontend_all
|
||||
- *frontend_ci
|
||||
- *frontend_sources
|
||||
- *frontend_specs
|
||||
|
||||
frontend_loki_ci: &frontend_loki_ci
|
||||
- ".github/workflows/loki.yml"
|
||||
- ".loki/**"
|
||||
- ".storybook/**"
|
||||
|
||||
backend_ci: &backend_ci
|
||||
- ".github/actions/prepare-frontend/**"
|
||||
- ".github/actions/prepare-backend/**"
|
||||
@@ -61,7 +53,6 @@ backend_ci: &backend_ci
|
||||
backend_presto_kerberos:
|
||||
- "**/presto_jdbc/**"
|
||||
- "**/presto_jdbc.clj"
|
||||
- ".github/workflows/presto-kerberos-integration-test.yml"
|
||||
|
||||
backend_sources: &backend_sources
|
||||
- *shared_sources
|
||||
@@ -109,10 +100,6 @@ e2e_specs: &e2e_specs
|
||||
- "e2e/support/**"
|
||||
- "e2e/snapshot*/**"
|
||||
|
||||
e2e_cross_version: &e2e_cross_version
|
||||
- ".github/workflows/e2e-cross-version.yml"
|
||||
- "e2e/test/scenarios/cross-version/**"
|
||||
|
||||
e2e_all:
|
||||
- *default
|
||||
- *e2e_ci
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
"alexandermkinn": "U023UTA4MUL",
|
||||
"alexyarosh": "U06GXH3RVPU",
|
||||
"alxnddr": "U01S9BUHH8X",
|
||||
"appleby": "U07GRL255JL",
|
||||
"brunobergher": "U01M2JJVA80",
|
||||
"bshepherdson": "U03AK3B43GA",
|
||||
"calherries": "U03KFGJ7X8S",
|
||||
@@ -83,10 +82,5 @@
|
||||
"vbenedetti": "U04MRS3JTLH",
|
||||
"victoriaspek": "U02KD3E703E",
|
||||
"WiNloSt": "U02MYNXD605",
|
||||
"zbodi74": "U05EV72TPN2",
|
||||
"core-ems": "S053QF4U49G",
|
||||
"tech-writers": "S078147J78S",
|
||||
"successengineers": "S05AAL8PUA1",
|
||||
"growth": "S056LQCRQG5",
|
||||
"core-release": "S02UJK9DN59"
|
||||
"zbodi74": "U05EV72TPN2"
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
exports.updateComment = updateComment;
|
||||
|
||||
/** @param {import('@types/github-script').AsyncFunctionArguments} AsyncFunctionArguments */
|
||||
async function updateComment({ github, context }) {
|
||||
const githubUsername = context.payload.sender.login;
|
||||
const comment = `${CONVENTIONAL_COMMIT_REMINDER_COMMENT_IDENTIFIER}
|
||||
@${githubUsername} You have modified embedding SDK code. Please make sure the PR title follows [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) style.
|
||||
Here are all the supported types that will be shown in the changelog:
|
||||
- \`feat\`
|
||||
- \`fix\`
|
||||
- \`perf\`
|
||||
|
||||
These types \`docs\`, \`style\`, \`refactor\`, \`test\`, \`build\`, and \`ci\` are also encouraged for non-changelog related tasks.
|
||||
|
||||
Please also make sure to include \`sdk\` scope, otherwise, the changelog will not include this task.
|
||||
|
||||
For example, these are valid PR titles:
|
||||
- \`feat(sdk): Add interactive dashboard component\`
|
||||
- \`feat(sdk): Support theming pie chart\`
|
||||
- \`fix(sdk): Fix static dashboard crash\``;
|
||||
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
const pullRequestNumber = context.issue.number;
|
||||
const comments = await github.rest.issues.listComments({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pullRequestNumber,
|
||||
});
|
||||
|
||||
const existingComment = getExistingConventionalCommitReminderComment(
|
||||
comments.data,
|
||||
);
|
||||
|
||||
if (existingComment) {
|
||||
return await github.rest.issues.updateComment({
|
||||
owner,
|
||||
repo,
|
||||
comment_id: existingComment.id,
|
||||
body: comment,
|
||||
});
|
||||
} else {
|
||||
return await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pullRequestNumber,
|
||||
body: comment,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const CONVENTIONAL_COMMIT_REMINDER_COMMENT_IDENTIFIER =
|
||||
"<!---conventional commit reminder comment ID-->";
|
||||
/**
|
||||
* @typedef Comment
|
||||
* @property {string} body
|
||||
*
|
||||
* @param {Comment[]} comments
|
||||
*/
|
||||
function getExistingConventionalCommitReminderComment(comments) {
|
||||
for (const comment of comments) {
|
||||
if (
|
||||
comment.body.startsWith(CONVENTIONAL_COMMIT_REMINDER_COMMENT_IDENTIFIER)
|
||||
) {
|
||||
return comment;
|
||||
}
|
||||
}
|
||||
}
|
||||
37
.github/team.json
vendored
@@ -1,25 +1,16 @@
|
||||
{
|
||||
"teams": [
|
||||
{
|
||||
"name": "Querying",
|
||||
"label": ".Team/Querying",
|
||||
"projectUrl": "https://github.com/orgs/metabase/projects/97/views/1",
|
||||
"name": "Querying Components",
|
||||
"label": ".Team/QueryingComponents",
|
||||
"members": [
|
||||
"ranquild",
|
||||
"uladzimirdev",
|
||||
"kamilmielnik",
|
||||
"nemanjaglumac",
|
||||
"romeovs",
|
||||
"bshepherdson",
|
||||
"metamben",
|
||||
"lbrdnk",
|
||||
"appleby"
|
||||
"romeovs"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Drivers",
|
||||
"label": ".Team/Drivers",
|
||||
"members": ["snoe"]
|
||||
},
|
||||
{
|
||||
"name": "Embedding",
|
||||
"label": ".Team/Embedding",
|
||||
@@ -33,21 +24,28 @@
|
||||
"members": [
|
||||
"tsmacdonald",
|
||||
"qnkhuat",
|
||||
"calherries",
|
||||
"piranha",
|
||||
"crisptrutski"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Query Processor",
|
||||
"label": ".Team/QueryProcessor",
|
||||
"projectUrl": "https://github.com/orgs/metabase/projects/83/views/8",
|
||||
"members": ["camsaul", "snoe", "bshepherdson", "metamben", "lbrdnk"]
|
||||
},
|
||||
{
|
||||
"name": "Admin Webapp",
|
||||
"label": ".Team/AdminWebapp",
|
||||
"members": [
|
||||
"noahmoss",
|
||||
"escherize",
|
||||
"iethree",
|
||||
"npfitz",
|
||||
"johnswanson",
|
||||
"rafpaf",
|
||||
"sloansparger",
|
||||
"iethree"
|
||||
"sloansparger"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -56,17 +54,10 @@
|
||||
"members": [
|
||||
"alxnddr",
|
||||
"EmmadUsmani",
|
||||
"JesseSDevaney",
|
||||
"kulyk",
|
||||
"adam-james-v"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DevEx",
|
||||
"label": ".Team/DevEx",
|
||||
"members": [
|
||||
"camsaul",
|
||||
"uladzimirdev"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
2
.github/workflows/auto-backport.yml
vendored
@@ -92,7 +92,7 @@ jobs:
|
||||
if: ${{ steps.create_backport_pull_request.outputs.has-conflicts == 'false' }}
|
||||
uses: peter-evans/enable-pull-request-automerge@v2
|
||||
with:
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
token: ${{ steps.generate-token.outputs.token }}
|
||||
pull-request-number: ${{ steps.create_backport_pull_request.outputs.backport_pr_number }}
|
||||
merge-method: squash
|
||||
|
||||
|
||||
21
.github/workflows/auto-request-review.yml
vendored
@@ -1,21 +0,0 @@
|
||||
# Config is in .github/auto_request_review.yml
|
||||
name: Auto Request Review
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, ready_for_review, reopened, synchronize]
|
||||
|
||||
jobs:
|
||||
auto-request-review:
|
||||
# Don't run on forked repos
|
||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
name: Auto Request Review
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Request review based on files changes and/or groups the author belongs to
|
||||
uses: necojackarc/auto-request-review@v0.13.0
|
||||
with:
|
||||
token: '${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}'
|
||||
27
.github/workflows/backend-cloverage.yml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Backend-Cloverage
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 10 * * 1-5' # every weekday at 5am US eastern time
|
||||
|
||||
jobs:
|
||||
be-linter-cloverage:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cloverage"
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
- name: Collect the test coverage
|
||||
run: clojure -X:dev:ci:ee:ee-dev:test:cloverage
|
||||
- name: Upload coverage to codecov.io
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: ./target/coverage/codecov.json
|
||||
flags: back-end
|
||||
38
.github/workflows/backend.yml
vendored
@@ -63,6 +63,29 @@ jobs:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/static-viz-sources.yaml
|
||||
|
||||
be-linter-cloverage:
|
||||
needs: files-changed
|
||||
if: (github.ref_name == 'master' && needs.files-changed.outputs.backend_all == 'true')
|
||||
|| contains(github.event.pull_request.labels.*.name, 'run-cloverage')
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cloverage"
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
- name: Collect the test coverage
|
||||
run: clojure -X:dev:ci:ee:ee-dev:test:cloverage
|
||||
- name: Upload coverage to codecov.io
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
files: ./target/coverage/codecov.json
|
||||
flags: back-end
|
||||
|
||||
be-linter-clj-kondo:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
@@ -268,18 +291,3 @@ jobs:
|
||||
steps:
|
||||
- run: |
|
||||
echo "Didn't run due to conditional filtering"
|
||||
|
||||
be-cljfmt:
|
||||
needs: [files-changed]
|
||||
if: |
|
||||
!cancelled() && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'cljfmt'
|
||||
- name: Run cljfmt
|
||||
run: clojure -T:cljfmt check
|
||||
|
||||
19
.github/workflows/backport.yml
vendored
@@ -107,23 +107,8 @@ jobs:
|
||||
echo "PR has been merged, searching for a squashed commit in the base branch"
|
||||
echo "searching for a commit in a ${ORIGINAL_BASE_REF} that contains pull request number ${ORIGINAL_PULL_REQUEST_NUMBER}"
|
||||
SQUASHED_COMMIT=$(env -i git log ${ORIGINAL_BASE_REF} --grep="(#${ORIGINAL_PULL_REQUEST_NUMBER})" --format="%H")
|
||||
|
||||
if [ -n "${SQUASHED_COMMIT}" ]; then
|
||||
echo "found commit ${SQUASHED_COMMIT}"
|
||||
git cherry-pick ${SQUASHED_COMMIT}
|
||||
else
|
||||
echo "probably a PR wasn't merged with Squash And Merge button, searching again"
|
||||
SQUASHED_COMMIT=$(env -i git log ${ORIGINAL_BASE_REF} --grep="#${ORIGINAL_PULL_REQUEST_NUMBER}" --format="%H")
|
||||
|
||||
if [ -n "${SQUASHED_COMMIT}" ]; then
|
||||
echo "found commit ${SQUASHED_COMMIT}"
|
||||
git cherry-pick ${SQUASHED_COMMIT}
|
||||
else
|
||||
echo "No squashed commit found for PR #${ORIGINAL_PULL_REQUEST_NUMBER}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "found commit ${SQUASHED_COMMIT}"
|
||||
git cherry-pick ${SQUASHED_COMMIT}
|
||||
else
|
||||
echo "PR has not been merged, copying all commits"
|
||||
git cherry-pick ${ORIGINAL_BASE_SHA}..${ORIGINAL_HEAD_SHA}
|
||||
|
||||
32
.github/workflows/build-for-release.yml
vendored
@@ -17,52 +17,30 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Send build start message
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v6
|
||||
env:
|
||||
SLACK_RELEASE_CHANNEL: ${{ vars.SLACK_RELEASE_CHANNEL }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { sendPreReleaseMessage } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
const { sendReleaseMessage } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
await sendPreReleaseMessage({
|
||||
await sendReleaseMessage({
|
||||
stage: 'build-start',
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: '${{ inputs.version }}',
|
||||
runId: '${{ github.run_id }}',
|
||||
releaseSha: '${{ inputs.commit }}',
|
||||
userName: '${{ github.actor }}',
|
||||
channelName: '${{ vars.SLACK_RELEASE_CHANNEL }}',
|
||||
}).catch(console.error);
|
||||
|
||||
trigger-milestone-check:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
needs: start-message
|
||||
steps:
|
||||
- name: trigger pre-release milestone check
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'release-milestone-check.yml',
|
||||
ref: '${{ github.ref }}',
|
||||
inputs: {
|
||||
commit: '${{ inputs.commit }}',
|
||||
version: '${{ inputs.version }}',
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
check-version:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
|
||||
81
.github/workflows/check-milestone.yml
vendored
@@ -1,41 +1,80 @@
|
||||
name: Automatically set milestone
|
||||
run-name: Set milestone for ${{ github.event.head_commit.message }}
|
||||
name: Milestone Reminder
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches:
|
||||
- release-x.**
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
set-milestone:
|
||||
name: Automatically set milestone
|
||||
milestone-reminder:
|
||||
if: github.event.pull_request.merged == true
|
||||
name: Remind to set milestone
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
contents: read
|
||||
issues: read
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
ref: master # we want the logic from master, even though we're triggering on a release branch
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
const { setMilestoneForCommits } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
const owner = context.repo.owner;
|
||||
const repo = context.repo.repo;
|
||||
|
||||
const branchName = `${{ github.ref }}`;
|
||||
const commitMessage = context?.payload?.head_commit?.message ?? '';
|
||||
const pullNumber = '${{ github.event.pull_request.number }}';
|
||||
|
||||
await setMilestoneForCommits({
|
||||
github,
|
||||
// the github API doesn't expose linked issues, so we have to parse the body ourselves
|
||||
function getLinkedIssueId(pull) {
|
||||
// https://regexr.com/7sk94
|
||||
const match = pull.data.body.match(/(close(s|d)?|fixe?(s|d)?|resolve(s|d)?) (#|https?:\/\/github.com\/.+\/issues\/)(\d+)/i);
|
||||
return match && match?.[2];
|
||||
}
|
||||
|
||||
function getMilestone(pullOrIssue) {
|
||||
// pull has pull.data.milestone, issue has issue.milestone
|
||||
return pullOrIssue?.data?.milestone || pullOrIssue?.milestone;
|
||||
}
|
||||
|
||||
const pull = await github.rest.pulls.get({
|
||||
owner,
|
||||
repo,
|
||||
branchName,
|
||||
commitMessages: [commitMessage],
|
||||
pull_number: pullNumber,
|
||||
});
|
||||
|
||||
if (getMilestone(pull)) {
|
||||
console.log("Pull request has milestone", pull.data.milestone?.title);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
const issueId = getLinkedIssueId(pull);
|
||||
|
||||
if (issueId) {
|
||||
console.log('linked issue found', issueId);
|
||||
|
||||
const issue = await github.rest.issues.get({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: issueId,
|
||||
});
|
||||
|
||||
const milestone = getMilestone(issue);
|
||||
|
||||
if (milestone) {
|
||||
console.log("Linked issue has milestone", milestone.title);
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
console.log("No milestone found");
|
||||
|
||||
const author = pull.data.user.login;
|
||||
const guideLink = "https://www.notion.so/metabase/Metabase-Branching-Strategy-6eb577d5f61142aa960a626d6bbdfeb3?pvs=4#3dea255ffa3b4f74942a227844e889fa";
|
||||
const message = `@${author} Did you forget to add a milestone to the issue for this PR? _[When and where should I add a milestone?](${guideLink})_`;
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner,
|
||||
repo,
|
||||
issue_number: pullNumber,
|
||||
body: message,
|
||||
});
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
name: Conventional commit PR Title Reminder
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- master
|
||||
paths:
|
||||
- enterprise/frontend/src/embedding-sdk/**
|
||||
|
||||
jobs:
|
||||
pr-title-reminder:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Check if the PR title is already following Conventional Commits style
|
||||
uses: actions/github-script@v7
|
||||
id: is-conventional-commit
|
||||
with:
|
||||
result-encoding: string
|
||||
script: | # js
|
||||
const pullRequestTitle = context.payload.pull_request.title
|
||||
const conventionalCommitRegex = /^(?<type>\w+)\((?<scope>\w+)\):/
|
||||
const match = pullRequestTitle.match(conventionalCommitRegex)
|
||||
if (match) {
|
||||
const { type, scope } = match.groups
|
||||
return ['feat', 'fix', 'perf', 'docs', 'style', 'refactor', 'test', 'build', 'ci'].includes(type) && scope === 'sdk'
|
||||
}
|
||||
|
||||
- name: Checkout repository so `gh` CLI works
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: Remind PR authors to use conventional commit in the title
|
||||
if: ${{ steps.is-conventional-commit.outputs.result != 'true' }}
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
const { updateComment } = require(".github/scripts/conventional-commit-pr-title-reminder/utils.js")
|
||||
await updateComment({github, context})
|
||||
162
.github/workflows/cross-branch-migrations.yml
vendored
@@ -1,162 +0,0 @@
|
||||
name: Cross-branch migration tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
paths:
|
||||
- "resources/migrations/**"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
migrations-h2-ee:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_DB_TYPE: h2
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/cross-branch-migration-test
|
||||
with:
|
||||
base-ref: ${{ github.base_ref }}
|
||||
|
||||
migrations-postgres-12-ee:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_DB_TYPE: postgres
|
||||
MB_DB_PORT: 5432
|
||||
MB_DB_HOST: localhost
|
||||
MB_DB_DBNAME: circle_test
|
||||
MB_DB_USER: circle_test
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12-alpine
|
||||
ports:
|
||||
- "5432:5432"
|
||||
env:
|
||||
POSTGRES_USER: circle_test
|
||||
POSTGRES_DB: circle_test
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/cross-branch-migration-test
|
||||
with:
|
||||
base-ref: ${{ github.base_ref }}
|
||||
|
||||
migrations-postgres-latest-ee:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_DB_TYPE: postgres
|
||||
MB_DB_PORT: 5432
|
||||
MB_DB_HOST: localhost
|
||||
MB_DB_DBNAME: circle_test
|
||||
MB_DB_USER: circle_test
|
||||
services:
|
||||
postgres:
|
||||
image: circleci/postgres:latest
|
||||
ports:
|
||||
- "5432:5432"
|
||||
env:
|
||||
POSTGRES_USER: circle_test
|
||||
POSTGRES_DB: circle_test
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/cross-branch-migration-test
|
||||
with:
|
||||
base-ref: ${{ github.base_ref }}
|
||||
|
||||
migrations-mysql-8-0-ee:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_DB_TYPE: mysql
|
||||
MB_DB_HOST: localhost
|
||||
MB_DB_PORT: 3306
|
||||
MB_DB_DBNAME: circle_test
|
||||
MB_DB_USER: root
|
||||
services:
|
||||
mysql:
|
||||
image: cimg/mysql:8.0
|
||||
ports:
|
||||
- "3306:3306"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/cross-branch-migration-test
|
||||
with:
|
||||
base-ref: ${{ github.base_ref }}
|
||||
|
||||
migrations-mysql-latest-ee:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_DB_TYPE: mysql
|
||||
MB_DB_HOST: localhost
|
||||
MB_DB_PORT: 3306
|
||||
MB_DB_DBNAME: circle_test
|
||||
MB_DB_USER: root
|
||||
MB_MYSQL_TEST_USER: root
|
||||
services:
|
||||
mysql:
|
||||
image: mysql:latest
|
||||
env:
|
||||
MYSQL_ALLOW_EMPTY_PASSWORD: true
|
||||
MYSQL_DATABASE: circle_test
|
||||
ports:
|
||||
- "3306:3306"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/cross-branch-migration-test
|
||||
with:
|
||||
base-ref: ${{ github.base_ref }}
|
||||
|
||||
migrations-mariadb-10-2-ee:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_DB_TYPE: mysql
|
||||
MB_DB_HOST: localhost
|
||||
MB_DB_PORT: 3306
|
||||
MB_DB_DBNAME: circle_test
|
||||
MB_DB_USER: root
|
||||
services:
|
||||
mariadb:
|
||||
image: circleci/mariadb:10.2.23
|
||||
ports:
|
||||
- "3306:3306"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/cross-branch-migration-test
|
||||
with:
|
||||
base-ref: ${{ github.base_ref }}
|
||||
|
||||
migrations-mariadb-latest-ee:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
CI: 'true'
|
||||
MB_DB_TYPE: mysql
|
||||
MB_DB_HOST: localhost
|
||||
MB_DB_PORT: 3306
|
||||
MB_DB_DBNAME: circle_test
|
||||
MB_DB_USER: root
|
||||
services:
|
||||
mariadb:
|
||||
image: circleci/mariadb:latest
|
||||
ports:
|
||||
- "3306:3306"
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: ./.github/actions/cross-branch-migration-test
|
||||
with:
|
||||
base-ref: ${{ github.base_ref }}
|
||||
8
.github/workflows/drivers.yml
vendored
@@ -40,9 +40,6 @@ jobs:
|
||||
MB_ATHENA_TEST_ACCESS_KEY: ${{ secrets.MB_ATHENA_TEST_ACCESS_KEY }}
|
||||
MB_ATHENA_TEST_SECRET_KEY: ${{ secrets.MB_ATHENA_TEST_SECRET_KEY }}
|
||||
MB_ATHENA_TEST_S3_STAGING_DIR: ${{ secrets.MB_ATHENA_TEST_S3_STAGING_DIR }}
|
||||
# These credentials are used to test the driver when the user does not have the athena:GetTableMetadata permission
|
||||
MB_ATHENA_TEST_WITHOUT_GET_TABLE_METADATA_ACCESS_KEY: ${{ secrets.MB_ATHENA_TEST_WITHOUT_GET_TABLE_METADATA_ACCESS_KEY }}
|
||||
MB_ATHENA_TEST_WITHOUT_GET_TABLE_METADATA_SECRET_KEY: ${{ secrets.MB_ATHENA_TEST_WITHOUT_GET_TABLE_METADATA_SECRET_KEY }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Athena driver
|
||||
@@ -809,11 +806,6 @@ jobs:
|
||||
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 }}
|
||||
# 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
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Test Snowflake driver
|
||||
|
||||
52
.github/workflows/e2e-cross-version.yml
vendored
@@ -2,31 +2,12 @@ name: E2E Cross-version Tests
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 9 * * 1-5'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
- cron: '0 9 * * 0'
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
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
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
matrix:
|
||||
version: [
|
||||
@@ -71,12 +52,11 @@ jobs:
|
||||
- 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 }} \
|
||||
--browser chrome \
|
||||
--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 }}
|
||||
@@ -104,7 +84,7 @@ jobs:
|
||||
- name: Run Cypress on the target
|
||||
run: |
|
||||
yarn cypress run \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }} \
|
||||
--browser chrome \
|
||||
--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
|
||||
@@ -117,11 +97,20 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
notify-on-failure:
|
||||
needs: cross-version-testing
|
||||
if: ${{ always() && contains(needs.*.result, 'failure') && github.event_name == 'schedule' }}
|
||||
if: ${{ always() && contains(needs.*.result, 'failure') }}
|
||||
name: Cross-version test failure
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
BRANCH_NAME: ${{ github.event.workflow_run.head_branch }}
|
||||
AUTHOR_NAME: ${{ github.event.workflow_run.head_commit.author.name }}
|
||||
steps:
|
||||
- name: Generate job summary
|
||||
run: |
|
||||
echo "# ${{ github.event.workflow_run.name }} workflow failed! :x:" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "View the failed run attempt (#${{ github.event.workflow_run.run_attempt }}) using the following link:" >> $GITHUB_STEP_SUMMARY
|
||||
echo "${{ github.event.workflow_run.html_url }}" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/Hydrogen # 18.x.x
|
||||
@@ -130,8 +119,11 @@ jobs:
|
||||
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 }}";
|
||||
const FAILED_RUN_URL = "${{ github.event.workflow_run.html_url }}";
|
||||
const FAILED_RUN_NAME = "${{ github.event.workflow_run.name }}";
|
||||
const BREAKING_COMMIT = "${{ github.event.workflow_run.head_sha }}";
|
||||
const AUTHOR = process.env.AUTHOR_NAME;
|
||||
const BRANCH = process.env.BRANCH_NAME;
|
||||
|
||||
// notify slack of failure
|
||||
const { WebClient } = require('@slack/web-api');
|
||||
@@ -145,7 +137,7 @@ jobs:
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": `:broken_heart: Cross-version tests are failing on ${REF_NAME}`,
|
||||
"text": `:broken_heart: Cross-version tests are failing on ${BRANCH}`,
|
||||
"emoji": true,
|
||||
}
|
||||
},
|
||||
@@ -157,7 +149,7 @@ jobs:
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": `See <${FAILED_RUN_URL}|failing run details>.`
|
||||
"text": `Commit <https://github.com/metabase/metabase/commit/${BREAKING_COMMIT}|${BREAKING_COMMIT.slice(0,7)}> has failing <${FAILED_RUN_URL}|${FAILED_RUN_NAME}> tests on the <https://github.com/metabase/metabase/commits/${BRANCH}|\`${BRANCH}\`> branch.`
|
||||
}
|
||||
},
|
||||
]
|
||||
|
||||
24
.github/workflows/e2e-stress-test-flake-fix.yml
vendored
@@ -20,15 +20,6 @@ on:
|
||||
type: string
|
||||
required: false
|
||||
default: "ee"
|
||||
qa_db:
|
||||
description: 'Select the type of Database you want to run your tests with'
|
||||
type: choice
|
||||
required: true
|
||||
default: "none"
|
||||
options:
|
||||
- none
|
||||
- sql
|
||||
- mongo
|
||||
|
||||
jobs:
|
||||
workflow-summary:
|
||||
@@ -44,7 +35,6 @@ jobs:
|
||||
echo '- `spec`: ${{ inputs.spec }}' >> $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
|
||||
echo '' >> $GITHUB_STEP_SUMMARY
|
||||
echo 'triggered by: @${{ github.event.sender.login }}' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
@@ -54,8 +44,9 @@ jobs:
|
||||
name: Stress test E2E flake fix
|
||||
env:
|
||||
DISPLAY: ""
|
||||
QA_DB_ENABLED: ${{ contains(fromJSON('["sql", "mongo"]'), inputs.qa_db) }}
|
||||
CYPRESS_QA_DB_MONGO: ${{ inputs.qa_db == 'mongo' }}
|
||||
QA_DB_ENABLED: true
|
||||
CYPRESS_QA_DB_MONGO: true
|
||||
CYPRESS_REPLAYIO_ENABLED: 1
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
@@ -76,9 +67,9 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
maildev: true
|
||||
openldap: true
|
||||
postgres: ${{ inputs.qa_db == 'sql' }}
|
||||
mysql: ${{ inputs.qa_db == 'sql' }}
|
||||
mongo: ${{ inputs.qa_db == 'mongo' }}
|
||||
postgres: true
|
||||
mysql: true
|
||||
mongo: true
|
||||
|
||||
- name: Download Metabase ${{ matrix.edition }} uberjar
|
||||
uses: ./.github/actions/e2e-download-uberjar
|
||||
@@ -93,7 +84,6 @@ jobs:
|
||||
java-version: 11
|
||||
distribution: "temurin"
|
||||
- name: Prepare Cypress environment
|
||||
id: cypress-prep
|
||||
uses: ./.github/actions/prepare-cypress
|
||||
- name: Run Snowplow micro
|
||||
uses: ./.github/actions/run-snowplow-micro
|
||||
@@ -106,7 +96,7 @@ jobs:
|
||||
--spec '${{ github.event.inputs.spec }}' \
|
||||
--env burn=${{ github.event.inputs.burn_in }},grep='${{ github.event.inputs.grep }}' \
|
||||
--config-file e2e/support/cypress-stress-test.config.js \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
--browser 'replay-chromium'
|
||||
|
||||
- name: Upload Cypress Artifacts upon failure
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
80
.github/workflows/e2e-tests.yml
vendored
@@ -39,39 +39,8 @@ jobs:
|
||||
id: e2e-matrix
|
||||
uses: ./.github/actions/build-e2e-matrix
|
||||
|
||||
# if this is a test on a release branch, we need to check the build requirements
|
||||
get-build-requirements:
|
||||
if: |
|
||||
!cancelled() &&
|
||||
contains(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 version = getVersionFromReleaseBranch('${{ github.ref }}');
|
||||
const requirements = getBuildRequirements(version);
|
||||
|
||||
return {
|
||||
java_version: requirements.java,
|
||||
node_version: requirements.node,
|
||||
};
|
||||
|
||||
build:
|
||||
needs: [files-changed, e2e-matrix-builder, get-build-requirements]
|
||||
needs: [files-changed, e2e-matrix-builder]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
@@ -85,19 +54,14 @@ jobs:
|
||||
env:
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
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:
|
||||
m2-cache-key: uberjar
|
||||
java-version: "${{ needs.get-build-requirements.outputs.java_version || 11 }}"
|
||||
m2-cache-key: e2e-tests
|
||||
|
||||
- name: Build uberjar with ./bin/build.sh
|
||||
run: ./bin/build.sh
|
||||
@@ -126,8 +90,12 @@ jobs:
|
||||
COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title || github.event.head_commit.message || github.even.head.sha }}
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
MB_SNOWPLOW_URL: "http://localhost:9090" # Snowplow micro
|
||||
CYPRESS_REPLAYIO_ENABLED: 1
|
||||
CYPRESS_REPLAYIO_ENABLE_UPLOAD: 1
|
||||
RECORD_REPLAY_METADATA_FILE: /tmp/replay-metadata.json
|
||||
RECORD_REPLAY_METADATA_TEST_RUN_ID: ${{ github.run_id }}
|
||||
REPLAY_API_KEY: ${{ secrets.REPLAY_IO_TOKEN }}
|
||||
TZ: US/Pacific # to make node match the instance tz
|
||||
CYPRESS_CI: true
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(needs.e2e-matrix-builder.outputs.matrix) }}
|
||||
@@ -166,7 +134,6 @@ jobs:
|
||||
distribution: "temurin"
|
||||
|
||||
- name: Prepare Cypress environment
|
||||
id: cypress-prep
|
||||
uses: ./.github/actions/prepare-cypress
|
||||
|
||||
- name: Run Snowplow micro
|
||||
@@ -178,7 +145,7 @@ jobs:
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags=@OSS,grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
--browser 'replay-chromium'
|
||||
|
||||
- name: Run slow and resource-intensive Cypress tests
|
||||
if: matrix.name == 'slow' && github.event_name != 'schedule'
|
||||
@@ -186,7 +153,7 @@ jobs:
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="@slow",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
--browser 'replay-chromium'
|
||||
|
||||
- name: Run Flaky Cypress tests
|
||||
if: matrix.name == 'flaky' && github.event_name != 'schedule'
|
||||
@@ -194,7 +161,7 @@ jobs:
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="@flaky --@quarantine",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
--browser 'replay-chromium'
|
||||
|
||||
- name: Run EE Cypress tests on ${{ matrix.name }}
|
||||
if: matrix.context == 'folder' && github.event_name != 'schedule'
|
||||
@@ -202,7 +169,7 @@ jobs:
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="-@slow+-@mongo+-@flaky --@quarantine",grepOmitFiltered=true \
|
||||
--folder ${{ matrix.name }} \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
--browser 'replay-chromium'
|
||||
|
||||
- name: Run E2E tests that depend on Mongo
|
||||
if: matrix.name == 'mongo'
|
||||
@@ -210,25 +177,10 @@ jobs:
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="@mongo --@quarantine",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
--browser 'replay-chromium'
|
||||
env:
|
||||
CYPRESS_QA_DB_MONGO: true
|
||||
|
||||
- name: Run Embedding SDK Storybook
|
||||
if: matrix.context == 'embedding-sdk' && github.event_name != 'schedule'
|
||||
uses: ./.github/actions/run-embedding-sdk-storybook
|
||||
|
||||
- name: Run E2E tests for Embedding SDK
|
||||
if: matrix.context == 'embedding-sdk' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="-@slow+-@flaky --@quarantine",grepOmitFiltered=true \
|
||||
--folder 'embedding-sdk' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
env:
|
||||
CYPRESS_IS_EMBEDDING_SDK: true
|
||||
shell: bash
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: ./.github/actions/upload-test-results
|
||||
if: always()
|
||||
@@ -265,11 +217,3 @@ jobs:
|
||||
steps:
|
||||
- run: |
|
||||
echo "Didn't run due to conditional filtering"
|
||||
|
||||
pr-env:
|
||||
needs: [build]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
contains(github.event.pull_request.labels.*.name, 'PR-Env')
|
||||
uses: ./.github/workflows/pr-env.yml
|
||||
secrets: inherit
|
||||
|
||||
34
.github/workflows/flake-issue-creator.yml
vendored
@@ -1,34 +0,0 @@
|
||||
name: Flake Issue Creator
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 6 * * 1-5' # every weekday at 1am US eastern time
|
||||
|
||||
jobs:
|
||||
flake-issue-creator:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn --frozen-lockfile && yarn build
|
||||
- name: Update flake issues
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { updateFlakeIssues } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
if (!process.env.SLACK_BOT_TOKEN) {
|
||||
throw new Error('SLACK_BOT_TOKEN is required');
|
||||
}
|
||||
|
||||
await updateFlakeIssues({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
35
.github/workflows/flake-status.yml
vendored
@@ -1,35 +0,0 @@
|
||||
name: Flake Status Report
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 6 * * 2,5' # Tuesdays and Fridays at 1am US eastern time
|
||||
|
||||
jobs:
|
||||
flake-status-report:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn --frozen-lockfile && yarn build
|
||||
- name: Post Flake Status Report
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { summarizeFlakes } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
if (!process.env.SLACK_BOT_TOKEN) {
|
||||
throw new Error('SLACK_BOT_TOKEN is required');
|
||||
}
|
||||
|
||||
await summarizeFlakes({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
channelName: 'engineering-ci'
|
||||
});
|
||||
@@ -4,15 +4,15 @@ on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
spec:
|
||||
description: "Relative path of the target spec"
|
||||
description: 'Relative path of the target spec'
|
||||
type: string
|
||||
required: true
|
||||
burn_in:
|
||||
description: "Number of times to run the test (e.g. 20)"
|
||||
description: 'Number of times to run the test (e.g. 20)'
|
||||
type: string
|
||||
required: true
|
||||
grep:
|
||||
description: "Grep and filter tests to run in isolation"
|
||||
description: 'Grep and filter tests to run in isolation'
|
||||
type: string
|
||||
required: false
|
||||
|
||||
@@ -45,12 +45,10 @@ jobs:
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Build cljs
|
||||
run: yarn build:cljs
|
||||
- name: Stress-test ${{ github.event.inputs.spec }} ${{ github.event.inputs.burn_in }} times
|
||||
run: |
|
||||
for i in {1..${{ github.event.inputs.burn_in }}}; do
|
||||
yarn jest --runInBand --ci --silent --no-cache \
|
||||
yarn test-unit \
|
||||
--testPathPattern '${{ github.event.inputs.spec }}' \
|
||||
--testNamePattern '${{ github.event.inputs.grep }}'
|
||||
if [[ "$?" != 0 ]]; then
|
||||
|
||||
8
.github/workflows/loki-update.yml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
ref: ${{ github.head_ref }}
|
||||
@@ -27,9 +27,7 @@ jobs:
|
||||
run: yarn build-pure:cljs
|
||||
|
||||
- name: Build Storybook
|
||||
# We won't be able to use Storybook play's `userEvent` with production build
|
||||
# see https://github.com/storybookjs/storybook/issues/19758
|
||||
run: NODE_ENV=development yarn build-storybook
|
||||
run: yarn build-storybook
|
||||
|
||||
- name: Serve Storybook
|
||||
run: yarn http-server storybook-static -p 6006 &
|
||||
@@ -57,7 +55,7 @@ jobs:
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
- name: Remove 'loki-update' label
|
||||
uses: actions/github-script@v7
|
||||
uses: actions/github-script@v3
|
||||
with:
|
||||
github-token: ${{secrets.METABASE_AUTOMATION_USER_TOKEN}}
|
||||
script: |
|
||||
|
||||
27
.github/workflows/loki.yml
vendored
@@ -3,26 +3,7 @@ name: Loki Visual Regression Testing
|
||||
on: [pull_request]
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 3
|
||||
outputs:
|
||||
frontend_ci: ${{ steps.changes.outputs.frontend_ci }}
|
||||
frontend_sources: ${{ steps.changes.outputs.frontend_sources }}
|
||||
frontend_loki_ci: ${{ steps.changes.outputs.frontend_loki_ci }}
|
||||
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
|
||||
|
||||
visual-test:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.frontend_ci == 'true' || needs.files-changed.outputs.frontend_sources == 'true' || needs.files-changed.outputs.frontend_loki_ci == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
services:
|
||||
docker:
|
||||
@@ -38,7 +19,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare frontend environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
@@ -52,9 +33,7 @@ jobs:
|
||||
run: yarn build-pure:cljs
|
||||
|
||||
- name: Build Storybook
|
||||
# We won't be able to use Storybook play's `userEvent` with production build
|
||||
# see https://github.com/storybookjs/storybook/issues/19758
|
||||
run: NODE_ENV=development yarn build-storybook
|
||||
run: yarn build-storybook
|
||||
|
||||
- name: Serve Storybook
|
||||
run: yarn http-server storybook-static -p 6006 &
|
||||
@@ -71,7 +50,7 @@ jobs:
|
||||
|
||||
- name: Run Loki Visual Tests
|
||||
run: |
|
||||
yarn test-visual:loki
|
||||
yarn loki test
|
||||
|
||||
- name: Generate Visual Report on Failure
|
||||
if: failure()
|
||||
|
||||
18
.github/workflows/migrations.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Lint migrations
|
||||
name: Migrations
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -9,14 +9,14 @@ on:
|
||||
|
||||
jobs:
|
||||
|
||||
lint-migrations:
|
||||
check-migrations:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: lint-migrations
|
||||
- name: Verify Liquibase Migrations
|
||||
run: ./bin/lint-migrations-file.sh
|
||||
- uses: actions/checkout@v4
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: check-migrations
|
||||
- name: Verify Liquibase Migrations
|
||||
run: ./bin/lint-migrations-file.sh
|
||||
|
||||
48
.github/workflows/on-epic-close.yml
vendored
@@ -1,48 +0,0 @@
|
||||
name: A New Feature Slack Notification
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- closed
|
||||
|
||||
jobs:
|
||||
on-epic-closed:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
if: ${{ contains(github.event.issue.labels.*.name, '.Epic') || contains(github.event.issue.labels.*.name, 'Type:New Feature') }}
|
||||
steps:
|
||||
- name: Setting title
|
||||
uses: actions/github-script@v6
|
||||
id: vars
|
||||
with:
|
||||
script: |
|
||||
core.setOutput('issue_title', ${{ toJson(github.event.issue.title) }}.replaceAll(/"/g, '\\"'));
|
||||
- name: Extracting team name
|
||||
id: team_name
|
||||
run: |
|
||||
team_label=$(echo "${{ join(github.event.issue.labels.*.name, ',') }}" | grep -o '\.Team/[^,]*' | head -n 1)
|
||||
echo $team_label
|
||||
echo "team_label=${team_label}" >> "$GITHUB_OUTPUT"
|
||||
team_name=${team_label#*.Team/}
|
||||
echo $team_name
|
||||
echo "team_name=${team_name^^}_SLACK_EPIC_WEBHOOK_URL" >> "$GITHUB_OUTPUT"
|
||||
- name: Send the issue ${{ github.event.issue.number }} to Slack
|
||||
id: slack
|
||||
if: ${{ steps.team_name.outputs.team_label }}
|
||||
uses: slackapi/slack-github-action@v1.26.0
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "${{ steps.vars.outputs.issue_title }}\n${{ github.event.issue.html_url }}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets[steps.team_name.outputs.team_name] }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
17
.github/workflows/perf-test-labeled.yml
vendored
@@ -1,17 +0,0 @@
|
||||
name: Perf test command
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ labeled ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
run-perf-test:
|
||||
if: ${{ github.event.label.name == 'Run-perf' }}
|
||||
uses: ./.github/workflows/perf-test.yml
|
||||
with:
|
||||
wait_for_uberjar: true
|
||||
secrets: inherit
|
||||
150
.github/workflows/perf-test.yml
vendored
@@ -1,150 +0,0 @@
|
||||
name: CI for Perf tests
|
||||
run-name: Run perf test for ${{ github.ref_name }} by @${{ github.actor }}
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
wait_for_uberjar:
|
||||
description: "Wait for uberjar build"
|
||||
required: false
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
name: Build Metabase Docker image
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
actions: read
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
|
||||
role-session-name: GitHub_to_AWS_via_FederatedOIDC
|
||||
aws-region: us-east-1
|
||||
- name: Login to Amazon ECR
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
with:
|
||||
registries: "${{ secrets.PR_ENV_AWS_ACCOUNT_ID }}"
|
||||
- name: Wait for uberjar
|
||||
id: wait_for_uberjar
|
||||
if: ${{ inputs.wait_for_uberjar == true }}
|
||||
run: |
|
||||
## Get workflow run id for uberjar build
|
||||
curl -Ls --output e2e-tests.json \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/workflows/e2e-tests.yml/runs?head_sha=${{ github.event.pull_request.head.sha || github.sha }}
|
||||
ID=$(jq -r '.workflow_runs[0].id' e2e-tests.json)
|
||||
## Wait for uberjar build to complete
|
||||
while [ true ]; do
|
||||
curl -Ls --output uberjar.json \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/runs/${ID}/jobs?filter=latest
|
||||
jq -r '.jobs[] | select(.name == "build (ee)") | .steps[] | select(.name == "Prepare uberjar artifact") | .status' uberjar.json | grep -q "completed" && break
|
||||
echo "Waiting for uberjar build..."
|
||||
sleep 10
|
||||
done
|
||||
echo "run_id=$(jq -r '.workflow_runs[0].id' e2e-tests.json)" >> $GITHUB_OUTPUT
|
||||
- name: Retrieve uberjar artifact for ee
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ inputs.wait_for_uberjar && steps.wait_for_uberjar.outputs.run_id || github.run_id }}
|
||||
- name: Move uberjar to bin/docker
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar
|
||||
mv target/uberjar/metabase.jar bin/docker/metabase.jar
|
||||
- name: Build container
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: bin/docker/
|
||||
platforms: linux/amd64
|
||||
network: host
|
||||
tags: ${{ secrets.PR_ENV_AWS_ACCOUNT_ID }}.dkr.ecr.us-east-1.amazonaws.com/metabase-enterprise:pr${{ github.event.number }}
|
||||
push: true
|
||||
launch_perf_test:
|
||||
needs: [ build ]
|
||||
runs-on: ubuntu-latest
|
||||
name: Launch Perf Test
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
- name: Tailscale
|
||||
uses: tailscale/github-action@v2
|
||||
with:
|
||||
oauth-client-id: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_CLIENT_ID }}
|
||||
oauth-secret: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_SECRET }}
|
||||
tags: tag:ci
|
||||
version: 1.50.1
|
||||
sha256sum: d9fe6b480fb5078f0aa57dace686898dda7e2a768884271159faa74846bfb576
|
||||
- name: Create OIDC Token
|
||||
id: create-oidc-token
|
||||
shell: bash
|
||||
run: |
|
||||
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${{ secrets.PR_ENV_K8S_AUDIENCE }}"
|
||||
IDTOKEN=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" -H "Accept: application/json; api-version=2.0" "$OIDC_URL_WITH_AUDIENCE" | jq -r .value)
|
||||
echo "::add-mask::${IDTOKEN}"
|
||||
echo "idToken=${IDTOKEN}" >>$GITHUB_OUTPUT
|
||||
- name: Setup Kube Context
|
||||
uses: azure/k8s-set-context@v2
|
||||
with:
|
||||
method: kubeconfig
|
||||
kubeconfig: |
|
||||
kind: Config
|
||||
apiVersion: v1
|
||||
current-context: default
|
||||
clusters:
|
||||
- name: default
|
||||
cluster:
|
||||
certificate-authority-data: ${{ secrets.PR_ENV_K8S_CERTIFICATE_AUTHORITY_DATA }}
|
||||
server: ${{ secrets.PR_ENV_K8S_SERVER }}
|
||||
users:
|
||||
- name: oidc-token
|
||||
user:
|
||||
token: ${{ steps.create-oidc-token.outputs.IDTOKEN }}
|
||||
contexts:
|
||||
- name: default
|
||||
context:
|
||||
cluster: default
|
||||
namespace: default
|
||||
user: oidc-token
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
|
||||
role-session-name: GitHub_to_AWS_via_FederatedOIDC
|
||||
aws-region: us-east-1
|
||||
- name: Download Deployment YAML template
|
||||
run: aws s3 cp s3://metabase-pr-env/perf-test-pr.yml.tmpl ./perf-test-pr.yml.tmpl
|
||||
- name: Trim SHA
|
||||
env:
|
||||
SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
id: split
|
||||
run: echo "::set-output name=fragment::${SHA:5}"
|
||||
- name: Render Deployment YAML
|
||||
uses: nowactions/envsubst@v1
|
||||
with:
|
||||
input: ./perf-test-pr.yml.tmpl
|
||||
output: ./perf-test-pr.yml
|
||||
env:
|
||||
IMAGE_TAG: pr${{ github.event.number }}
|
||||
PR_NUMBER: ${{ github.event.number }}
|
||||
RUN_ID: ${{ steps.split.outputs.fragment }}
|
||||
SHA: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
TEST_NAME: test
|
||||
- name: Deploy PR Review ENV
|
||||
run: |
|
||||
kubectl apply -f ./perf-test-pr.yml
|
||||
15
.github/workflows/pr-env-close-unlabel.yml
vendored
@@ -1,15 +0,0 @@
|
||||
name: PR Closed or Unlabeled
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ closed, unlabeled ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
pr-env:
|
||||
if: ${{ github.event.action == 'closed' && contains(github.event.pull_request.labels.*.name, 'PR-Env') || github.event.label.name == 'PR-Env' }}
|
||||
uses: ./.github/workflows/pr-env-destroy.yml
|
||||
secrets: inherit
|
||||
71
.github/workflows/pr-env-destroy.yml
vendored
@@ -1,71 +0,0 @@
|
||||
name: CI for PR Review ENV Destroy
|
||||
run-name: Destroying Dynamic PR Environment for ${{ github.ref_name }} by @${{ github.actor }}
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
|
||||
jobs:
|
||||
destroy_pr:
|
||||
runs-on: ubuntu-latest
|
||||
name: PR Review ENV Destroy
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
- name: Tailscale
|
||||
uses: tailscale/github-action@v2
|
||||
with:
|
||||
oauth-client-id: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_CLIENT_ID }}
|
||||
oauth-secret: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_SECRET }}
|
||||
tags: tag:ci
|
||||
version: 1.50.1
|
||||
sha256sum: d9fe6b480fb5078f0aa57dace686898dda7e2a768884271159faa74846bfb576
|
||||
- name: Create OIDC Token
|
||||
id: create-oidc-token
|
||||
shell: bash
|
||||
run: |
|
||||
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${{ secrets.PR_ENV_K8S_AUDIENCE }}"
|
||||
IDTOKEN=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" -H "Accept: application/json; api-version=2.0" "$OIDC_URL_WITH_AUDIENCE" | jq -r .value)
|
||||
echo "::add-mask::${IDTOKEN}"
|
||||
echo "idToken=${IDTOKEN}" >>$GITHUB_OUTPUT
|
||||
- name: Setup Kube Context
|
||||
uses: azure/k8s-set-context@v2
|
||||
with:
|
||||
method: kubeconfig
|
||||
kubeconfig: |
|
||||
kind: Config
|
||||
apiVersion: v1
|
||||
current-context: default
|
||||
clusters:
|
||||
- name: default
|
||||
cluster:
|
||||
certificate-authority-data: ${{ secrets.PR_ENV_K8S_CERTIFICATE_AUTHORITY_DATA }}
|
||||
server: ${{ secrets.PR_ENV_K8S_SERVER }}
|
||||
users:
|
||||
- name: oidc-token
|
||||
user:
|
||||
token: ${{ steps.create-oidc-token.outputs.IDTOKEN }}
|
||||
contexts:
|
||||
- name: default
|
||||
context:
|
||||
cluster: default
|
||||
namespace: default
|
||||
user: oidc-token
|
||||
- name: Destroy PR Review ENV
|
||||
run: |
|
||||
kubectl delete metabase -n hosting-pr${{ github.event.number }} hosting-pr${{ github.event.number }}
|
||||
kubectl delete ns hosting-pr${{ github.event.number }}
|
||||
- name: Setup psql client
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y postgresql-client
|
||||
- name: Drop app database if exists
|
||||
run: |
|
||||
PGPASSWORD='${{ secrets.PR_ENV_DB_PASSWORD }}' \
|
||||
psql \
|
||||
-h ${{ secrets.PR_ENV_DB_HOST }} \
|
||||
-U ${{ secrets.PR_ENV_DB_USER }} \
|
||||
-d ${{ secrets.PR_ENV_DB_NAME }} \
|
||||
-c "DROP DATABASE IF EXISTS hosting_pr${{ github.event.number }};"
|
||||
17
.github/workflows/pr-env-labeled.yml
vendored
@@ -1,17 +0,0 @@
|
||||
name: PR-Env labeled
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [ labeled ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
pr-env:
|
||||
if: ${{ github.event.label.name == 'PR-Env' }}
|
||||
uses: ./.github/workflows/pr-env.yml
|
||||
with:
|
||||
wait_for_uberjar: true
|
||||
secrets: inherit
|
||||
169
.github/workflows/pr-env.yml
vendored
@@ -1,169 +0,0 @@
|
||||
name: CI for PR Review ENV
|
||||
run-name: Building Dynamic PR Environment for ${{ github.ref_name }} by @${{ github.actor }}
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
wait_for_uberjar:
|
||||
description: "Wait for uberjar build"
|
||||
required: false
|
||||
type: boolean
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
name: Build Metabase Docker image
|
||||
timeout-minutes: 60
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
actions: read
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
|
||||
role-session-name: GitHub_to_AWS_via_FederatedOIDC
|
||||
aws-region: us-east-1
|
||||
- name: Login to Amazon ECR
|
||||
uses: aws-actions/amazon-ecr-login@v2
|
||||
with:
|
||||
registries: "${{ secrets.PR_ENV_AWS_ACCOUNT_ID }}"
|
||||
- name: Wait for uberjar
|
||||
id: wait_for_uberjar
|
||||
if: ${{ inputs.wait_for_uberjar == true }}
|
||||
run: |
|
||||
## Get workflow run id for uberjar build
|
||||
curl -Ls --output e2e-tests.json \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/workflows/e2e-tests.yml/runs?head_sha=${{ github.event.pull_request.head.sha || github.sha }}
|
||||
ID=$(jq -r '.workflow_runs[0].id' e2e-tests.json)
|
||||
## Wait for uberjar build to complete
|
||||
while [ true ]; do
|
||||
curl -Ls --output uberjar.json \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/${{ github.repository }}/actions/runs/${ID}/jobs?filter=latest
|
||||
jq -r '.jobs[] | select(.name == "build (ee)") | .steps[] | select(.name == "Prepare uberjar artifact") | .status' uberjar.json | grep -q "completed" && break
|
||||
echo "Waiting for uberjar build..."
|
||||
sleep 10
|
||||
done
|
||||
echo "run_id=$(jq -r '.workflow_runs[0].id' e2e-tests.json)" >> $GITHUB_OUTPUT
|
||||
- name: Retrieve uberjar artifact for ee
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
run-id: ${{ inputs.wait_for_uberjar && steps.wait_for_uberjar.outputs.run_id || github.run_id }}
|
||||
- name: Move uberjar to bin/docker
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar
|
||||
mv target/uberjar/metabase.jar bin/docker/metabase.jar
|
||||
- name: Build container
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: bin/docker/
|
||||
platforms: linux/amd64
|
||||
network: host
|
||||
tags: ${{ secrets.PR_ENV_AWS_ACCOUNT_ID }}.dkr.ecr.us-east-1.amazonaws.com/metabase-enterprise:pr${{ github.event.number }}
|
||||
push: true
|
||||
deploy_pr:
|
||||
needs: [ build ]
|
||||
runs-on: ubuntu-latest
|
||||
name: PR Review ENV
|
||||
permissions:
|
||||
id-token: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout source code
|
||||
uses: actions/checkout@v4
|
||||
- name: Tailscale
|
||||
uses: tailscale/github-action@v2
|
||||
with:
|
||||
oauth-client-id: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_CLIENT_ID }}
|
||||
oauth-secret: ${{ secrets.PR_ENV_TAILSCALE_OAUTH_SECRET }}
|
||||
tags: tag:ci
|
||||
version: 1.50.1
|
||||
sha256sum: d9fe6b480fb5078f0aa57dace686898dda7e2a768884271159faa74846bfb576
|
||||
- name: Create OIDC Token
|
||||
id: create-oidc-token
|
||||
shell: bash
|
||||
run: |
|
||||
export OIDC_URL_WITH_AUDIENCE="$ACTIONS_ID_TOKEN_REQUEST_URL&audience=${{ secrets.PR_ENV_K8S_AUDIENCE }}"
|
||||
IDTOKEN=$(curl -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" -H "Accept: application/json; api-version=2.0" "$OIDC_URL_WITH_AUDIENCE" | jq -r .value)
|
||||
echo "::add-mask::${IDTOKEN}"
|
||||
echo "idToken=${IDTOKEN}" >>$GITHUB_OUTPUT
|
||||
- name: Setup Kube Context
|
||||
uses: azure/k8s-set-context@v2
|
||||
with:
|
||||
method: kubeconfig
|
||||
kubeconfig: |
|
||||
kind: Config
|
||||
apiVersion: v1
|
||||
current-context: default
|
||||
clusters:
|
||||
- name: default
|
||||
cluster:
|
||||
certificate-authority-data: ${{ secrets.PR_ENV_K8S_CERTIFICATE_AUTHORITY_DATA }}
|
||||
server: ${{ secrets.PR_ENV_K8S_SERVER }}
|
||||
users:
|
||||
- name: oidc-token
|
||||
user:
|
||||
token: ${{ steps.create-oidc-token.outputs.IDTOKEN }}
|
||||
contexts:
|
||||
- name: default
|
||||
context:
|
||||
cluster: default
|
||||
namespace: default
|
||||
user: oidc-token
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
role-to-assume: ${{ secrets.PR_ENV_IAM_ROLE }}
|
||||
role-session-name: GitHub_to_AWS_via_FederatedOIDC
|
||||
aws-region: us-east-1
|
||||
- name: Setup psql client
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y postgresql-client
|
||||
- name: Create app database if not exists
|
||||
run: |
|
||||
export PGPASSWORD='${{ secrets.PR_ENV_DB_PASSWORD }}'
|
||||
export PGUSER=${{ secrets.PR_ENV_DB_USER }}
|
||||
export PGHOST=${{ secrets.PR_ENV_DB_HOST }}
|
||||
export PGDATABASE=${{ secrets.PR_ENV_DB_NAME }}
|
||||
psql -tc "SELECT 1 FROM pg_database WHERE datname = 'hosting_pr${{ github.event.number }}'" \
|
||||
| grep -q 1 \
|
||||
|| psql -c "CREATE DATABASE hosting_pr${{ github.event.number }}"
|
||||
- name: Download Deployment YAML template
|
||||
run: aws s3 cp s3://metabase-pr-env/metabase.yml.tmpl ./metabase.yml.tmpl
|
||||
- name: Render Deployment YAML
|
||||
uses: nowactions/envsubst@v1
|
||||
with:
|
||||
input: ./metabase.yml.tmpl
|
||||
output: ./metabase.yml
|
||||
env:
|
||||
IMAGE_TAG: pr${{ github.event.number }}
|
||||
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 }}
|
||||
- name: Deploy PR Review ENV
|
||||
run: |
|
||||
kubectl apply -f ./metabase.yml
|
||||
preview_links:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [ deploy_pr ]
|
||||
steps:
|
||||
- uses: marocchino/sticky-pull-request-comment@v2
|
||||
with:
|
||||
recreate: true
|
||||
message: |
|
||||
👋 Deploying a preview environment for commit ${{ github.event.pull_request.head.sha || github.sha }}.
|
||||
✅ Preview:
|
||||
https://pr${{ github.event.number }}.coredev.metabase.com
|
||||
🗒️ [login instructions](https://www.notion.so/metabase/Ephemeral-PR-Environments-c74a3710c87a460dbf4fc0007a001458)
|
||||
89
.github/workflows/pre-release.yml
vendored
@@ -11,10 +11,6 @@ on:
|
||||
commit:
|
||||
description: "A full-length commit SHA-1 hash"
|
||||
required: true
|
||||
auto:
|
||||
description: 'auto-patch release DO NOT SET MANUALLY'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
release-artifact:
|
||||
@@ -114,32 +110,37 @@ jobs:
|
||||
run-sanity-check:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
needs: [release-artifact]
|
||||
needs: [release-artifact, check-uberjar-health]
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
folder: [onboarding, search]
|
||||
env:
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
DISPLAY: ""
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
CYPRESS_REPLAYIO_ENABLED: 1
|
||||
# disabled because of out of memory issues
|
||||
# probably related to https://github.com/cypress-io/cypress/issues/27415
|
||||
CYPRESS_NO_COMMAND_LOG: 1
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
MB_SNOWPLOW_URL: "http://localhost:9090" # Snowplow micro
|
||||
TERM: xterm
|
||||
services:
|
||||
maildev:
|
||||
image: maildev/maildev:2.0.5
|
||||
ports:
|
||||
- "1080:1080"
|
||||
- "1025:1025"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
steps:
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ needs.release-artifact.outputs.commit }}
|
||||
- name: Prepare Docker containers
|
||||
uses: ./.github/actions/e2e-prepare-containers
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
maildev: true
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare JDK 11
|
||||
@@ -148,7 +149,6 @@ jobs:
|
||||
java-version: 11
|
||||
distribution: "temurin"
|
||||
- name: Prepare Cypress environment
|
||||
id: cypress-prep
|
||||
uses: ./.github/actions/prepare-cypress
|
||||
- name: Run Snowplow micro
|
||||
uses: ./.github/actions/run-snowplow-micro
|
||||
@@ -163,10 +163,7 @@ jobs:
|
||||
- name: Run a few important Cypress tests as sanity check
|
||||
run: |
|
||||
mkdir -p ./target/uberjar && cp metabase.jar ./target/uberjar/metabase.jar
|
||||
yarn test-cypress-run \
|
||||
--env grepTags="@smoke",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.(js|ts)' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
yarn test-cypress-run --folder ${{ matrix.folder }}
|
||||
|
||||
- name: Upload Cypress Artifacts upon failure
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -179,7 +176,7 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
containerize:
|
||||
needs: [release-artifact]
|
||||
needs: [release-artifact, run-sanity-check]
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
@@ -288,61 +285,3 @@ jobs:
|
||||
- name: Wait for Metabase to start
|
||||
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
timeout-minutes: 3
|
||||
|
||||
trigger-auto-publish:
|
||||
if: ${{ inputs.auto }}
|
||||
needs: [run-sanity-check, check-uberjar-health, verify-docker-pull]
|
||||
permissions:
|
||||
actions: write
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: trigger auto publish
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'release.yml',
|
||||
ref: '${{ github.ref }}',
|
||||
inputs: {
|
||||
commit: '${{ inputs.commit }}',
|
||||
version: '${{ inputs.version }}',
|
||||
auto: true,
|
||||
}
|
||||
});
|
||||
|
||||
tests-complete-message:
|
||||
if: always()
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [run-sanity-check, check-uberjar-health, verify-docker-pull]
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Send tests complete message
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_RELEASE_CHANNEL: ${{ vars.SLACK_RELEASE_CHANNEL }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { sendTestsCompleteMessage } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const allJobsSuccessful =
|
||||
'${{ needs.run-sanity-check.result }}' === 'success' &&
|
||||
'${{ needs.check-uberjar-health.result }}' === 'success' &&
|
||||
'${{ needs.verify-docker-pull.result }}' === 'success';
|
||||
|
||||
await sendTestsCompleteMessage({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: '${{ inputs.version }}',
|
||||
runId: '${{ github.run_id }}',
|
||||
channelName: '${{ vars.SLACK_RELEASE_CHANNEL }}',
|
||||
testStatus: allJobsSuccessful ? 'success' : 'failure',
|
||||
}).catch(console.error);
|
||||
|
||||
@@ -1,8 +1,3 @@
|
||||
# this file uses MBA https://github.com/metabase/mba to spin up a Metabase
|
||||
# instance then runs the test script in the MBA instance sharing the same
|
||||
# network to interact with presto container
|
||||
# TODO: get rid of MBA and use actions/prepare-backend instead
|
||||
|
||||
name: Kerberized Presto Integration Test
|
||||
|
||||
on:
|
||||
@@ -10,10 +5,10 @@ on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- "release**"
|
||||
- "feature**"
|
||||
- 'release**'
|
||||
- 'feature**'
|
||||
tags:
|
||||
- "**"
|
||||
- '**'
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
@@ -57,7 +52,7 @@ jobs:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
path: presto-kerberos-docker
|
||||
- name: Bring up Presto+Kerberos cluster
|
||||
run: cd presto-kerberos-docker && docker compose up -d && cd ..
|
||||
run: cd presto-kerberos-docker && docker-compose up -d && cd ..
|
||||
- name: Run Presto test query from command line (sanity check)
|
||||
run: cd presto-kerberos-docker && ./test.sh && cd ..
|
||||
# Since we are managing the Docker containers from the GitHub action container, we need to copy all the
|
||||
@@ -68,7 +63,6 @@ jobs:
|
||||
run: docker cp presto-kerberos:/etc/krb5.conf resources
|
||||
- name: Copy client.keytab file to resources
|
||||
run: docker cp presto-kerberos:/home/presto/client.keytab resources
|
||||
|
||||
- name: Checkout mba
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
@@ -80,30 +74,11 @@ jobs:
|
||||
run: ls -latr mba-src
|
||||
- name: Symlink mba
|
||||
run: cd mba-src && sudo ln -s $(pwd)/src/main.clj /usr/local/bin/mba && chmod +x /usr/local/bin/mba && cd ..
|
||||
|
||||
- name: Ensure mba
|
||||
run: which mba
|
||||
|
||||
- name: Run Metabase via MBA
|
||||
run: mba --mb . --data-db postgres-data -n example.com compose config > mba-compose.yml
|
||||
|
||||
- name: Adjust generated docker-compose config
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | #js
|
||||
const fs = require("fs");
|
||||
const config = fs.readFileSync("mba-compose.yml", "utf8");
|
||||
const newConfig = config.replace(
|
||||
/name:\s+example.com/,
|
||||
"name: example.com\n external: true",
|
||||
);
|
||||
fs.writeFileSync("mba-compose.yml", newConfig);
|
||||
|
||||
- name: Print compose config
|
||||
run: cat mba-compose.yml
|
||||
|
||||
- name: Run mba
|
||||
run: docker compose -f mba-compose.yml up -d
|
||||
|
||||
run: /home/runner/work/metabase/metabase/mba-src/src/main.clj --mb . --data-db postgres-data -n example.com up
|
||||
- name: Run test script in MBA instance
|
||||
run: docker compose -f mba-compose.yml exec metabase .github/scripts/run-presto-kerberos-integration-test.sh
|
||||
run: >
|
||||
mba --mb . --data-db postgres-data -n example.com \
|
||||
run .github/scripts/run-presto-kerberos-integration-test.sh
|
||||
|
||||
80
.github/workflows/release-embedding-sdk.yml
vendored
@@ -9,7 +9,7 @@ on:
|
||||
type: string
|
||||
required: true
|
||||
git_ref:
|
||||
description: 'A git commit hash that will be used to build the SDK'
|
||||
description: 'Valid git reference e.g. branches, tags, hashes'
|
||||
type: string
|
||||
required: true
|
||||
|
||||
@@ -35,7 +35,7 @@ jobs:
|
||||
|
||||
- name: check tags
|
||||
run: |
|
||||
if [ $(git tag -l | grep $tag$) ]
|
||||
if [ $(git tag -l | grep $tag) ]
|
||||
then
|
||||
echo "::error::Tag '${{ env.tag }}' already exists. If you expect to run this workflow with the same tag, please remove the tag first and rerun this workflow again."
|
||||
exit 1
|
||||
@@ -89,13 +89,19 @@ jobs:
|
||||
./bin/embedding-sdk/release_utils.bash update_readme ${{ inputs.sdk_version }}
|
||||
|
||||
- name: Bump published npm package version
|
||||
# NOTE: this should happen before "Build SDK bundle" as we inject SDK version into the code during build step
|
||||
run: |
|
||||
./bin/embedding-sdk/release_utils.bash update_package_json_template ${{ inputs.sdk_version }}
|
||||
|
||||
# TODO: Remove this step after the build utils script is merged to master
|
||||
- name: Upload release utils script, so it can be used later on when checking out `master` branch
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-util
|
||||
path: ./bin/embedding-sdk/release_utils.bash
|
||||
|
||||
- name: Update changelog
|
||||
run: |
|
||||
yarn embedding-sdk:generate-changelog -o changelog-diff
|
||||
yarn embedding-sdk:generate-changelog
|
||||
|
||||
- name: Build SDK bundle
|
||||
run: yarn run build-embedding-sdk
|
||||
@@ -109,11 +115,11 @@ jobs:
|
||||
name: metabase-sdk
|
||||
path: ./resources/embedding-sdk
|
||||
|
||||
- name: Upload changelog diff
|
||||
- name: Upload changelog
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sdk-changelog-diff
|
||||
path: ./changelog-diff
|
||||
name: sdk-changelog
|
||||
path: ./enterprise/frontend/src/embedding-sdk/CHANGELOG.md
|
||||
|
||||
build-jar:
|
||||
needs: test
|
||||
@@ -162,8 +168,15 @@ jobs:
|
||||
|
||||
- name: Setup git user
|
||||
run: |
|
||||
git config --global user.email "github-automation@metabase.com"
|
||||
git config --global user.name "Metabase Automation"
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
# TODO: Remove this step after the build utils script is merged to master
|
||||
- name: Download release utils script
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: release-util
|
||||
path: ./bin/embedding-sdk/
|
||||
|
||||
- name: Update readme
|
||||
run: |
|
||||
@@ -173,17 +186,23 @@ jobs:
|
||||
run: |
|
||||
bash ./bin/embedding-sdk/release_utils.bash update_package_json_template ${{ inputs.sdk_version }}
|
||||
|
||||
- name: Retrieve SDK changelog diff
|
||||
- name: Retrieve SDK changelog
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: sdk-changelog-diff
|
||||
name: sdk-changelog
|
||||
|
||||
- name: Update changelog
|
||||
# We need to do this because it's impossible to download an artifact to an existing location
|
||||
- name: Move over the downloaded changelog
|
||||
run: |
|
||||
cat changelog-diff enterprise/frontend/src/embedding-sdk/CHANGELOG.md > new-changelog
|
||||
mv new-changelog enterprise/frontend/src/embedding-sdk/CHANGELOG.md
|
||||
mv CHANGELOG.md ./enterprise/frontend/src/embedding-sdk/CHANGELOG.md
|
||||
|
||||
- name: Create a PR updating readme + published version, and changelog (using GitHub Metabase Automation account)
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
|
||||
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Create a PR updating readme + published version, and changelog
|
||||
run: |
|
||||
git checkout -b update-sdk-version-${{ inputs.sdk_version }}
|
||||
git commit -a -m 'Update Readme version references and published npm version to ${{ inputs.sdk_version }}'
|
||||
@@ -192,33 +211,10 @@ jobs:
|
||||
--assignee "${GITHUB_ACTOR}"\
|
||||
--title "Update SDK version to ${{ inputs.sdk_version }}"\
|
||||
--body "Update Readme version references and published npm package version to ${{ inputs.sdk_version }}"
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
|
||||
- uses: actions/create-github-app-token@v1
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ secrets.METABASE_BOT_APP_ID }}
|
||||
private-key: ${{ secrets.METABASE_BOT_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Edit PR adding useful information (using Metabase bot app)
|
||||
run: |
|
||||
gh pr edit --add-reviewer @metabase/embedding --add-label no-backport
|
||||
gh pr edit --add-reviewer @metabase/embedding
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- name: Auto approve PR (using GitHub Actions account)
|
||||
run: |
|
||||
gh pr review --approve
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Enable Pull request auto-merge (using GitHub Metabase Automation account)
|
||||
run: |
|
||||
gh pr merge --auto --squash
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
|
||||
- name: Retrieve build SDK package artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
@@ -243,7 +239,11 @@ jobs:
|
||||
with:
|
||||
ref: ${{ inputs.git_ref }}
|
||||
|
||||
# Lightweight tags don't need committer name and email
|
||||
- name: Setup git user
|
||||
run: |
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
- name: Create a new git tag
|
||||
run: |
|
||||
git tag ${{ env.tag }}
|
||||
|
||||
43
.github/workflows/release-log.yml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Update Release Log
|
||||
run-name: Update Release Log ${{ inputs.version }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Major Metabase version (e.g. 45, 52, 68)'
|
||||
type: number
|
||||
required: true
|
||||
schedule:
|
||||
- cron: '45 * * * *' # hourly
|
||||
|
||||
jobs:
|
||||
update-release-log:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 5
|
||||
env:
|
||||
VERSION: ${{ github.event_name == 'workflow_dispatch' && inputs.version || 50 }} # Update this for the next major release
|
||||
steps:
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v4
|
||||
with:
|
||||
aws-access-key-id: ${{ secrets.AWS_S3_RELEASE_ACCESS_KEY_ID }}
|
||||
aws-secret-access-key: ${{ secrets.AWS_S3_RELEASE_SECRET_ACCESS_KEY }}
|
||||
aws-region: ${{ vars.AWS_REGION }}
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # we want all branches and tags
|
||||
- name: Install Dependencies
|
||||
run: yarn --cwd release --frozen-lockfile && npm i -g tsx
|
||||
- name: generate release Log
|
||||
run: cd release && tsx ./src/release-log.ts $VERSION > v$VERSION.html
|
||||
- name: upload release log to the web
|
||||
run: |
|
||||
aws s3 cp \
|
||||
release/v$VERSION.html \
|
||||
s3://${{ vars.AWS_S3_STATIC_BUCKET }}/release-log/v$VERSION.html
|
||||
- name: Create cloudfront invalidation
|
||||
run: |
|
||||
aws cloudfront create-invalidation \
|
||||
--distribution-id ${{ vars.AWS_CLOUDFRONT_STATIC_ID }} \
|
||||
--paths /release-log/v$VERSION.html
|
||||
52
.github/workflows/release-milestone-check.yml
vendored
@@ -1,52 +0,0 @@
|
||||
name: Release Milestone Check
|
||||
run-name: Pre-release Milestone check for ${{ inputs.version }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: "Metabase version (e.g. v0.46.3)"
|
||||
type: string
|
||||
required: true
|
||||
commit:
|
||||
description: "A full-length commit SHA-1 hash"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
check-milestone:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: yarn --cwd release --frozen-lockfile && yarn --cwd release build
|
||||
- uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_RELEASE_CHANNEL: ${{ vars.SLACK_RELEASE_CHANNEL }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const {
|
||||
checkMilestoneForRelease,
|
||||
sendMilestoneCheckMessage,
|
||||
} = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const version = '${{ inputs.version }}';
|
||||
const commitHash = '${{ inputs.commit }}';
|
||||
|
||||
const issueCount = await checkMilestoneForRelease({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version,
|
||||
commitHash,
|
||||
});
|
||||
|
||||
await sendMilestoneCheckMessage({
|
||||
channelName: process.env.SLACK_RELEASE_CHANNEL,
|
||||
issueCount,
|
||||
version,
|
||||
});
|
||||
55
.github/workflows/release-notes-preview.yml
vendored
@@ -1,55 +0,0 @@
|
||||
name: Release Notes Preview
|
||||
run-name: Preview ${{ inputs.version }} release notes
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Metabase version (e.g. v0.46.3)'
|
||||
type: string
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
preview-release-notes:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: Fail early on the incorrect version format
|
||||
if: ${{ !(startsWith(inputs.version,'v0.') || startsWith(inputs.version,'v1.')) }}
|
||||
run: |
|
||||
echo "The version format is invalid!"
|
||||
echo "It must start with either 'v0.' or 'v1.'."
|
||||
echo "Please, try again."
|
||||
exit 1
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Get Release Version
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
DOCKERHUB_OWNER: test_owner
|
||||
DOCKERHUB_REPO: test_repo
|
||||
AWS_S3_DOWNLOADS_BUCKET: test_bucket
|
||||
with:
|
||||
script: | # js
|
||||
const { getChangelog } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
const fs = require('fs');
|
||||
|
||||
const version = '${{ inputs.version }}';
|
||||
|
||||
const notes = await getChangelog({
|
||||
version,
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
});
|
||||
|
||||
fs.writeFileSync(`release-notes-preview-${version}.md`, notes);
|
||||
- name: Upload Release Notes
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: release-notes-preview-${{inputs.version}}.md
|
||||
path: |
|
||||
${{ github.workspace }}/release-notes-preview-*.md
|
||||
91
.github/workflows/release-patch.yml
vendored
@@ -1,91 +0,0 @@
|
||||
name: Release 1b - Auto Patch
|
||||
run-name: Patch Release ${{ inputs.version }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Major Metabase version (e.g. 45, 52, 68)'
|
||||
type: number
|
||||
required: true
|
||||
schedule:
|
||||
- cron: '15 0 * * 2-6' # every weekday at 7/8:15 pm Eastern Time
|
||||
|
||||
jobs:
|
||||
auto-patch-trigger:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: yarn --cwd release --frozen-lockfile && yarn --cwd release build
|
||||
- name: Trigger auto-patch
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
const {
|
||||
getLatestGreenCommit,
|
||||
getNextPatchVersion,
|
||||
hasCommitBeenReleased,
|
||||
} = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
// Don't forget to update this for the next major release 🤞
|
||||
const AUTO_RELEASE_VERSIONS = [49, 50];
|
||||
|
||||
async function releasePatchFor(majorVersion) {
|
||||
const nextPatch = await getNextPatchVersion({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
majorVersion,
|
||||
});
|
||||
|
||||
const goodCommit = await getLatestGreenCommit({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
branch: `release-x.${majorVersion}.x`,
|
||||
});
|
||||
|
||||
const hasBeenReleased = await hasCommitBeenReleased({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
ref: goodCommit,
|
||||
majorVersion: Number(majorVersion),
|
||||
});
|
||||
|
||||
if (nextPatch && goodCommit && !hasBeenReleased) {
|
||||
await github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'tag-for-release.yml',
|
||||
ref: 'refs/heads/master',
|
||||
inputs: {
|
||||
commit: goodCommit,
|
||||
version: nextPatch,
|
||||
auto: true,
|
||||
}
|
||||
});
|
||||
} else {
|
||||
console.log(
|
||||
{ nextPatch, goodCommit, hasBeenReleased }
|
||||
);
|
||||
console.error(`No new patch version or no green commit found for v${majorVersion}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (context.eventName === 'workflow_dispatch') {
|
||||
const inputVersion = Number(context.payload.inputs.version);
|
||||
|
||||
if (typeof inputVersion !== 'number') {
|
||||
console.log('Invalid version number', inputVersion);
|
||||
throw new Error(`Invalid version number: ${inputVersion}`);
|
||||
}
|
||||
|
||||
await releasePatchFor(inputVersion);
|
||||
} else { // scheduled release of AUTO_RELEASE_VERSIONS
|
||||
await Promise.all(AUTO_RELEASE_VERSIONS.map(releasePatchFor));
|
||||
}
|
||||
32
.github/workflows/release-status.yml
vendored
@@ -1,9 +1,9 @@
|
||||
name: Release and Backport Status Check
|
||||
name: Release Status Check
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 7 * * 1-5' # every weekday at 8am/9am Central European Time
|
||||
- cron: '0 11 * * 1-5' # every weekday at 6am US eastern time
|
||||
|
||||
jobs:
|
||||
check-release-status:
|
||||
@@ -38,31 +38,3 @@ jobs:
|
||||
repo: context.repo.repo,
|
||||
channelName: process.env.SLACK_RELEASE_CHANNEL,
|
||||
});
|
||||
|
||||
open-backport-reminder:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn --frozen-lockfile && yarn build
|
||||
- name: Check release status and post to Slack
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { checkOpenBackports } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
if (!process.env.SLACK_BOT_TOKEN) {
|
||||
throw new Error('SLACK_BOT_TOKEN is required');
|
||||
}
|
||||
|
||||
const ossReleased = await checkOpenBackports({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
channelName: 'engineering-ci',
|
||||
});
|
||||
|
||||
72
.github/workflows/release-tests.yml
vendored
@@ -1,72 +0,0 @@
|
||||
name: Release Code Tests
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
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:
|
||||
release_source: ${{ steps.changes.outputs.release_source }}
|
||||
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
|
||||
|
||||
release-type-check:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.release_source == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: "release"
|
||||
- name: prepare dependencies in release directory
|
||||
run: yarn --cwd release --frozen-lockfile
|
||||
- name: Run frontend type-check
|
||||
run: yarn --cwd release type-check
|
||||
|
||||
release-tests-unit:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.release_source == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: "release"
|
||||
- name: prepare dependencies in release directory
|
||||
run: yarn --cwd release --frozen-lockfile
|
||||
- name: Run release unit tests
|
||||
run: yarn --cwd release test:unit
|
||||
|
||||
release-test-build:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.release_source == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: "release"
|
||||
- name: prepare dependencies in release directory
|
||||
run: yarn --cwd release --frozen-lockfile
|
||||
- name: Build release bundle
|
||||
run: yarn --cwd release build
|
||||
- name: Smoke test release bundle
|
||||
run: node release/dist/index.cjs
|
||||
205
.github/workflows/release.yml
vendored
@@ -31,10 +31,6 @@ on:
|
||||
description: 'Skip publishing release notes'
|
||||
type: boolean
|
||||
default: false
|
||||
auto:
|
||||
description: 'auto-patch release DO NOT SET MANUALLY'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
check-version:
|
||||
@@ -94,34 +90,6 @@ jobs:
|
||||
|
||||
return versions;
|
||||
|
||||
publish-start-message:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [check-version]
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Send publish start message
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_RELEASE_CHANNEL: ${{ vars.SLACK_RELEASE_CHANNEL }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { sendPublishStartMessage } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
await sendPublishStartMessage({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: '${{ inputs.version }}',
|
||||
runId: '${{ github.run_id }}',
|
||||
channelName: '${{ vars.SLACK_RELEASE_CHANNEL }}',
|
||||
}).catch(console.error);
|
||||
|
||||
|
||||
download-uberjar:
|
||||
needs: check-version
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -260,7 +228,7 @@ jobs:
|
||||
- name: Upload to S3
|
||||
run: aws s3 cp ./metabase.jar s3://${{ vars.AWS_S3_DOWNLOADS_BUCKET }}/${{ steps.version_path.outputs.result }}/metabase.jar
|
||||
- name: Upload to s3 latest path
|
||||
if: ${{ !inputs.auto && steps.latest_path.outputs.result != 'false' }}
|
||||
if: ${{ steps.latest_path.outputs.result != 'false' }}
|
||||
run: aws s3 cp ./metabase.jar s3://${{ vars.AWS_S3_DOWNLOADS_BUCKET }}/${{ steps.latest_path.outputs.result }}/metabase.jar
|
||||
- name: Create cloudfront invalidation
|
||||
run: |
|
||||
@@ -406,7 +374,7 @@ jobs:
|
||||
echo "Finished!"
|
||||
|
||||
- name: Tag the container image as latest
|
||||
if: ${{ !inputs.auto && steps.latest_version_check.outputs.result == 'latest' }}
|
||||
if: ${{ steps.latest_version_check.outputs.result == 'latest' }}
|
||||
run: |
|
||||
echo "Pushing ${{ env.DOCKERHUB_REPO }}:latest ..."
|
||||
docker tag localhost:5000/local-metabase:${{ steps.canonical_version.outputs.result }} ${{ env.DOCKERHUB_REPO }}:latest
|
||||
@@ -514,25 +482,16 @@ jobs:
|
||||
$GITHUB_WORKSPACE/release/reorder-tags.sh ${{ needs.check-version.outputs.ee }} ${{ inputs.commit }}
|
||||
|
||||
trigger-docs-update:
|
||||
if: ${{ !inputs.auto && inputs.skip-release-notes != true }}
|
||||
needs:
|
||||
- push-tags
|
||||
- check-version
|
||||
if: ${{ inputs.skip-release-notes != true }}
|
||||
needs: push-tags
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
env:
|
||||
NEW_OSS_VERSION: ${{ needs.check-version.outputs.oss }}
|
||||
NEW_EE_VERSION: ${{ needs.check-version.outputs.ee }}
|
||||
GH_TOKEN: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
script: | # js
|
||||
await github.rest.repos.createDispatchEvent({
|
||||
github-token: ${{ secrets.DOCS_UPDATE_TOKEN }}
|
||||
script: |
|
||||
github.rest.repos.createDispatchEvent({
|
||||
owner: '${{ github.repository_owner }}',
|
||||
repo: '${{ secrets.DOCS_REPO }}',
|
||||
event_type: 'trigger-docs-update',
|
||||
@@ -540,96 +499,9 @@ jobs:
|
||||
version: '${{ inputs.version }}'
|
||||
}
|
||||
});
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
- name: update releases.md
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
script: | # js
|
||||
const fs = require('fs');
|
||||
|
||||
const releaseText = fs.readFileSync('./docs/releases.md', 'utf8');
|
||||
|
||||
const newReleaseText = releaseText
|
||||
.replace(
|
||||
/## Metabase Enterprise Edition releases\n\n/,
|
||||
`## Metabase Enterprise Edition releases\n\n- [${process.env.NEW_EE_VERSION}](https://github.com/metabase/metabase/releases/tag/${process.env.NEW_EE_VERSION})\n`
|
||||
)
|
||||
.replace(
|
||||
/## Metabase Open Source Edition releases\n\n/,
|
||||
`## Metabase Open Source Edition releases\n\n- [${process.env.NEW_OSS_VERSION}](https://github.com/metabase/metabase/releases/tag/${process.env.NEW_OSS_VERSION})\n`
|
||||
);
|
||||
|
||||
fs.writeFileSync('./docs/releases.md', newReleaseText);
|
||||
|
||||
- name: commit and push updates
|
||||
run: | # bash
|
||||
git config --global user.email "metabase-bot@metabase.com"
|
||||
git config --global user.name "Metabase bot"
|
||||
|
||||
git checkout -b docs-add-$NEW_OSS_VERSION
|
||||
cd docs/
|
||||
|
||||
git add releases.md
|
||||
git commit -m "Add $NEW_OSS_VERSION to the list of releases"
|
||||
git push origin docs-add-$NEW_OSS_VERSION --force
|
||||
|
||||
- name: open pr with updates
|
||||
run: | # bash
|
||||
gh pr create --fill \
|
||||
--body "Like it says on the tin 😁" \
|
||||
--label "Type:Documentation" \
|
||||
--label "backport" \
|
||||
--reviewer "jeff-bruemmer" \
|
||||
--assignee "jeff-bruemmer"
|
||||
|
||||
trigger-cloud-issues:
|
||||
needs: push-tags
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
script: | # js
|
||||
const version = '${{ inputs.version }}';
|
||||
const enterpriseVersion = version.replace(/^v0\./, "v1.");
|
||||
|
||||
github.rest.repos.createDispatchEvent({
|
||||
owner: '${{ github.repository_owner }}',
|
||||
repo: '${{ vars.OPS_REPO }}',
|
||||
event_type: 'create-release-issues',
|
||||
client_payload: {
|
||||
version: enterpriseVersion,
|
||||
}
|
||||
});
|
||||
|
||||
trigger-ee-extra-pr:
|
||||
needs: verify-s3-download
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/github-script@v7
|
||||
with:
|
||||
github-token: ${{ secrets.METABASE_AUTOMATION_USER_TOKEN }}
|
||||
script: | # js
|
||||
const version = '${{ inputs.version }}';
|
||||
const enterpriseVersion = version.replace(/^v0\./, "v1.");
|
||||
|
||||
github.rest.repos.createDispatchEvent({
|
||||
owner: '${{ github.repository_owner }}',
|
||||
repo: 'metabase-ee-extra',
|
||||
event_type: 'update-ee-extra-build',
|
||||
client_payload: {
|
||||
version: enterpriseVersion,
|
||||
auto: '${{ inputs.auto }}',
|
||||
}
|
||||
});
|
||||
|
||||
draft-release-notes:
|
||||
if: ${{ !inputs.auto && inputs.skip-release-notes != true }}
|
||||
if: ${{ inputs.skip-release-notes != true }}
|
||||
needs: push-tags
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
@@ -681,7 +553,7 @@ jobs:
|
||||
});
|
||||
|
||||
publish-version-info:
|
||||
if: ${{ !inputs.auto && inputs.skip-version-info != true }}
|
||||
if: ${{ inputs.skip-version-info != true }}
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [push-tags, check-version]
|
||||
timeout-minutes: 15
|
||||
@@ -739,66 +611,7 @@ jobs:
|
||||
--distribution-id ${{ vars.AWS_CLOUDFRONT_STATIC_ID }} \
|
||||
--paths "/version-info.json" "/version-info-ee.json"
|
||||
|
||||
publish-complete-message:
|
||||
if: ${{ !inputs.auto }}
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [draft-release-notes, verify-docker-pull, verify-s3-download, publish-version-info]
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Send publish complete message
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_RELEASE_CHANNEL: ${{ vars.SLACK_RELEASE_CHANNEL }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { sendPublishCompleteMessage } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
await sendPublishCompleteMessage({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: '${{ inputs.version }}',
|
||||
runId: '${{ github.run_id }}',
|
||||
channelName: '${{ vars.SLACK_RELEASE_CHANNEL }}',
|
||||
generalChannelName: 'general',
|
||||
}).catch(console.error);
|
||||
|
||||
auto-publish-complete-message:
|
||||
if: ${{ inputs.auto }}
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [push-tags, verify-docker-pull, verify-s3-download]
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Send auto publish complete message
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_RELEASE_CHANNEL: ${{ vars.SLACK_RELEASE_CHANNEL }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { sendPublishCompleteMessage } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
await sendPublishCompleteMessage({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: '${{ inputs.version }}',
|
||||
runId: '${{ github.run_id }}',
|
||||
channelName: '${{ vars.SLACK_RELEASE_CHANNEL }}',
|
||||
generalChannelName: '',
|
||||
}).catch(console.error);
|
||||
|
||||
manage-milestones:
|
||||
if: ${{ !inputs.auto }}
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [draft-release-notes, publish-version-info] # this will ensure that the milestone stays open until the release notes are published
|
||||
|
||||
4
.github/workflows/rerun-workflows.yml
vendored
@@ -2,7 +2,7 @@ name: Re-run Flaky Workflows
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [Backend, Driver Tests, E2E Tests, Frontend, Backend-Cloverage]
|
||||
workflows: [Backend, Driver Tests, E2E Tests, Frontend]
|
||||
types: [completed]
|
||||
branches: [master, 'release-x.**', 'backport-**']
|
||||
|
||||
@@ -10,7 +10,7 @@ jobs:
|
||||
rerun-on-failure:
|
||||
name: 'Re-run ''${{ github.event.workflow_run.name }}'' workflow'
|
||||
runs-on: ubuntu-22.04
|
||||
# Do not re-run scheduled workflow runs
|
||||
# Do not re-run scheduled workflow runs. That's only Replay.io E2E tests for now.
|
||||
if: github.event.workflow_run.conclusion == 'failure' && github.event.workflow_run.event != 'schedule'
|
||||
env:
|
||||
BRANCH_NAME: ${{ github.event.workflow_run.head_branch }}
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
name: Security Issue Slack Notification
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- labeled
|
||||
|
||||
jobs:
|
||||
on-issue-opened:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
if: github.event.label.name == 'SECURITY'
|
||||
steps:
|
||||
- name: Setting title
|
||||
uses: actions/github-script@v7
|
||||
id: vars
|
||||
with:
|
||||
script: |
|
||||
core.setOutput('issue_title', ${{ toJson(github.event.issue.title) }}.replaceAll(/"/g, '\\"'));
|
||||
- name: Send the issue ${{ github.event.issue.number }} to Slack
|
||||
id: slack
|
||||
uses: slackapi/slack-github-action@v1.26.0
|
||||
with:
|
||||
payload: |
|
||||
{
|
||||
"blocks": [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "${{ steps.vars.outputs.issue_title }}\n${{ github.event.issue.html_url }}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_SECURITY_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
257
.github/workflows/tag-for-release.yml
vendored
@@ -1,257 +0,0 @@
|
||||
name: Release 1a - Tag Release Artifact
|
||||
run-name: Tag ${{ inputs.version }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
version:
|
||||
description: 'Metabase version (e.g. v0.46.3)'
|
||||
type: string
|
||||
required: true
|
||||
commit:
|
||||
description: 'A full-length commit SHA-1 hash'
|
||||
required: true
|
||||
auto:
|
||||
description: 'auto-patch release DO NOT SET MANUALLY'
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
jobs:
|
||||
start-message:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Send build start message
|
||||
uses: actions/github-script@v7
|
||||
env:
|
||||
SLACK_RELEASE_CHANNEL: ${{ vars.SLACK_RELEASE_CHANNEL }}
|
||||
SLACK_BOT_TOKEN: ${{ secrets.SLACK_BOT_TOKEN }}
|
||||
with:
|
||||
script: | # js
|
||||
const { sendPreReleaseMessage } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
await sendPreReleaseMessage({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: '${{ inputs.version }}',
|
||||
runId: '${{ github.run_id }}',
|
||||
releaseSha: '${{ inputs.commit }}',
|
||||
userName: '${{ github.actor }}',
|
||||
channelName: '${{ vars.SLACK_RELEASE_CHANNEL }}',
|
||||
}).catch(console.error);
|
||||
|
||||
check-version:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
outputs:
|
||||
ee: ${{ fromJson(steps.canonical_version.outputs.result).ee }}
|
||||
oss: ${{ fromJson(steps.canonical_version.outputs.result).oss }}
|
||||
steps:
|
||||
- name: Fail early on the incorrect version format
|
||||
if: ${{ !(startsWith(inputs.version,'v0.') || startsWith(inputs.version,'v1.')) }}
|
||||
run: |
|
||||
echo "The version format is invalid!"
|
||||
echo "It must start with either 'v0.' or 'v1.'."
|
||||
echo "Please, try again."
|
||||
exit 1
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Get Release Version
|
||||
uses: actions/github-script@v7
|
||||
id: canonical_version
|
||||
with:
|
||||
script: | # js
|
||||
const { isValidVersionString, getCanonicalVersion, hasBeenReleased } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const version = '${{ inputs.version }}';
|
||||
|
||||
if (!isValidVersionString(version)) {
|
||||
throw new Error("The version format is invalid! It must start with either 'v0.' or 'v1.'.");
|
||||
}
|
||||
|
||||
const versions = {
|
||||
ee: getCanonicalVersion(version, 'ee'),
|
||||
oss: getCanonicalVersion(version, 'oss'),
|
||||
};
|
||||
|
||||
const ossReleased = await hasBeenReleased({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: versions.oss,
|
||||
});
|
||||
|
||||
const eeReleased = await hasBeenReleased({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: versions.ee,
|
||||
});
|
||||
|
||||
if (ossReleased || eeReleased) {
|
||||
throw new Error("This version has already been released!", version);
|
||||
}
|
||||
|
||||
return versions;
|
||||
|
||||
check-commit:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Check out the code to verify the release branch
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # IMPORTANT! to get all the branches
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Get Release Branch
|
||||
uses: actions/github-script@v7
|
||||
id: release_branch
|
||||
with:
|
||||
result_encoding: string
|
||||
script: | # js
|
||||
const { getReleaseBranch } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
const version = '${{ inputs.version }}';
|
||||
const releaseBranch = getReleaseBranch(version);
|
||||
return releaseBranch;
|
||||
- name: Ensure that the specified commit exists in the ${{ steps.release_branch.outputs.result }} release branch
|
||||
run: |
|
||||
RELEASE_BRANCH=${{ steps.release_branch.outputs.result }}
|
||||
git checkout $RELEASE_BRANCH
|
||||
git branch --contains ${{ inputs.commit }} | grep -q $RELEASE_BRANCH \
|
||||
&& echo "Commit found in correct release branch" \
|
||||
|| (echo "Commit not found in correct release branch" && exit 1)
|
||||
|
||||
tag-uberjar-for-release:
|
||||
needs: [check-version, check-commit]
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
env:
|
||||
INTERACTIVE: false
|
||||
steps:
|
||||
- name: Get correct version number
|
||||
run: | # bash
|
||||
if [ '${{matrix.edition}}' == 'ee' ]; then
|
||||
version='${{ needs.check-version.outputs.ee }}'
|
||||
else
|
||||
version='${{ needs.check-version.outputs.oss }}'
|
||||
fi
|
||||
|
||||
echo "VERSION=$version" >> $GITHUB_ENV
|
||||
- name: Setup Java
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: 17 # 11 throws an error on jar uf
|
||||
|
||||
- name: Retrieve test build uberjar artifact for ${{ matrix.edition }}
|
||||
id: find_release_artifact
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
result-encoding: string
|
||||
script: | # js
|
||||
const fs = require('fs');
|
||||
|
||||
const artifacts = await github.rest.actions.listArtifactsForRepo({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
name: `metabase-${{ matrix.edition }}-${{ inputs.commit }}-uberjar`,
|
||||
per_page: 1,
|
||||
});
|
||||
|
||||
if (!artifacts.data?.artifacts?.[0]?.id) {
|
||||
console.warn(`No existing artifacts found for ${{ inputs.commit }}, need to build jar`);
|
||||
|
||||
if ("${{matrix.edition}}" === 'oss') {
|
||||
// only trigger the build job on OSS, otherwise we'll get double builds
|
||||
github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'build-for-release.yml',
|
||||
ref: 'refs/heads/master',
|
||||
inputs: {
|
||||
commit: '${{ inputs.commit }}',
|
||||
version: '${{ inputs.version }}',
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error('aborting in favor of build script');
|
||||
}
|
||||
|
||||
const artifact_id = artifacts.data.artifacts[0].id;
|
||||
|
||||
const download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: artifact_id,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
|
||||
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/mb.zip`, Buffer.from(download.data));
|
||||
- name: Unzip Metabase artifact containing an uberjar
|
||||
run: |
|
||||
unzip mb.zip
|
||||
mv target/uberjar/metabase.jar metabase.jar
|
||||
|
||||
- name: Update version.properties in jar
|
||||
run: | # sh
|
||||
jar xf metabase.jar version.properties
|
||||
echo "Old version.properties:"
|
||||
cat version.properties
|
||||
sed -i "s/^tag=.*/tag=$VERSION/" version.properties
|
||||
echo "\n\nNew version.properties:"
|
||||
cat version.properties
|
||||
echo "\n\nUpdating metabase.jar with new version.properties"
|
||||
jar uf metabase.jar version.properties
|
||||
|
||||
- name: Store commit's SHA-1 hash
|
||||
run: echo ${{ inputs.commit }} > COMMIT-ID
|
||||
shell: bash
|
||||
- name: Calculate SHA256 checksum
|
||||
run: sha256sum ./metabase.jar > SHA256.sum
|
||||
shell: bash
|
||||
- name: Upload JARs as artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: metabase-release-${{ matrix.edition }}-${{ inputs.commit }}-uberjar
|
||||
path: |
|
||||
./metabase.jar
|
||||
./COMMIT-ID
|
||||
./SHA256.sum
|
||||
|
||||
trigger-tests:
|
||||
needs: [tag-uberjar-for-release]
|
||||
permissions:
|
||||
actions: write
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
steps:
|
||||
- name: trigger pre-release testing
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
github.rest.actions.createWorkflowDispatch({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
workflow_id: 'pre-release.yml',
|
||||
ref: '${{ github.ref }}',
|
||||
inputs: {
|
||||
commit: '${{ inputs.commit }}',
|
||||
version: '${{ inputs.version }}',
|
||||
auto: '${{ inputs.auto }}',
|
||||
}
|
||||
});
|
||||
134
.github/workflows/translation-update.yml
vendored
@@ -1,134 +0,0 @@
|
||||
name: Update Translations
|
||||
run-name: Update Translations for v${{ inputs.version }} - ${{ inputs.step }}
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
step:
|
||||
type: choice
|
||||
description: Upload untranslated strings | Download translated strings
|
||||
options:
|
||||
- upload
|
||||
- download
|
||||
required: true
|
||||
version:
|
||||
type: string
|
||||
description: "The version number for which to update translations (e.g. 43, 58.7)"
|
||||
required: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
upload-translations:
|
||||
name: Upload Translations
|
||||
if: ${{ inputs.step == 'upload' }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
POEDITOR_API_TOKEN: ${{ secrets.POEDITOR_API_TOKEN }}
|
||||
POEDITOR_PROJECT_ID: 200535
|
||||
VERSION: ${{ inputs.version }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: manage-translations
|
||||
- name: install gettext
|
||||
run: sudo apt-get install gettext
|
||||
|
||||
# TODO: check for untranslated strings
|
||||
|
||||
- name: Upload strings to be translated
|
||||
run: | # sh
|
||||
./bin/i18n/update-translation-template
|
||||
./bin/i18n/export-pot-to-poeditor
|
||||
echo "Strings uploaded to POEditor"
|
||||
|
||||
- name: Commit changes
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: | # sh
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
|
||||
BRANCH_NAME="update-translations-v$VERSION"
|
||||
|
||||
git checkout -b $BRANCH_NAME
|
||||
git add locales/
|
||||
|
||||
git commit -m "Add new strings for v$VERSION"
|
||||
git push -u origin $BRANCH_NAME
|
||||
|
||||
gh pr create \
|
||||
--reviewer "${GITHUB_ACTOR}" \
|
||||
--assignee "${GITHUB_ACTOR}" \
|
||||
--title "Update Translations for v$VERSION" \
|
||||
--body "Update translations from POEditor for v$VERSION
|
||||
|
||||
See [translation update documentation](https://www.notion.so/metabase/Process-for-updating-translations-421db70048fe400da1153ad0b61102f4)
|
||||
|
||||
## To Do
|
||||
|
||||
- [x] Upload new strings to POEditor
|
||||
- [ ] Message contributors on POEditor (manual)
|
||||
- [ ] Copy source strings to english language (manual)
|
||||
- [ ] Download translations from POEditor (github action)
|
||||
- [ ] Merge this PR and backport to the release branch (manual)
|
||||
" \
|
||||
--label "backport" \
|
||||
--label "Customization/i18n"
|
||||
|
||||
# TODO: notify contributors
|
||||
# TODO: copy source strings to english language
|
||||
|
||||
download-translations:
|
||||
name: Download Translations
|
||||
if: ${{ inputs.step == 'download' }}
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
env:
|
||||
POEDITOR_API_TOKEN: ${{ secrets.POEDITOR_API_TOKEN }}
|
||||
POEDITOR_PROJECT_ID: 200535
|
||||
VERSION: ${{ inputs.version }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
# assumes there's already a branch with that name from the upload step
|
||||
ref: update-translations-v${{inputs.VERSION}}
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: manage-translations
|
||||
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Automatically translate untranslated strings
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: | # js
|
||||
const { autoTranslateSupportedLanguages } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
await autoTranslateSupportedLanguages();
|
||||
|
||||
- name: Download translated strings
|
||||
run: | # sh
|
||||
cd ${{ github.workspace }}
|
||||
./bin/i18n/import-po-from-poeditor
|
||||
./bin/i18n/build-translation-resources
|
||||
- name: Commit changes
|
||||
run: | # sh
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
|
||||
BRANCH_NAME="update-translations-v$VERSION"
|
||||
|
||||
git add locales/
|
||||
|
||||
git commit -m "Update translations"
|
||||
git push -u origin $BRANCH_NAME
|
||||
72
.github/workflows/tusk-sanity-check.yml
vendored
@@ -1,72 +0,0 @@
|
||||
# This allows Tusk to manually run workflows to check lint/build/tests before creating a PR.
|
||||
# If you have any questions, please reach out to support@usetusk.ai.
|
||||
|
||||
name: Tusk Sanity Check
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
taskId:
|
||||
description: "Tusk Task ID"
|
||||
required: true
|
||||
runType:
|
||||
description: "Tusk Run Type"
|
||||
required: true
|
||||
runId:
|
||||
description: "Tusk Run ID"
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
sanity_check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Log inputs
|
||||
run: |
|
||||
echo "Tusk Task ID: ${{ github.event.inputs.taskId }}"
|
||||
echo "Tusk Run Type: ${{ github.event.inputs.runType }}"
|
||||
echo "Tusk Run ID: ${{ github.event.inputs.runId }}"
|
||||
echo "Current Branch: ${{ github.ref }}"
|
||||
echo "Repository default branch: ${{ github.event.repository.default_branch }}"
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ github.ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check which files changed
|
||||
uses: dorny/paths-filter@v3.0.0
|
||||
id: changes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
# Similar to .github/workflows/frontend.yml
|
||||
- name: Prepare front-end environment
|
||||
if: steps.changes.outputs.frontend_all == 'true'
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- run: yarn build-pure:cljs
|
||||
name: Compile CLJS
|
||||
|
||||
- name: Run lint-staged
|
||||
if: steps.changes.outputs.frontend_all == 'true'
|
||||
run: |
|
||||
BASE_COMMIT=$(git merge-base origin/${{ github.event.repository.default_branch }} HEAD)
|
||||
npx lint-staged --shell --no-stash --diff="$BASE_COMMIT...HEAD"
|
||||
|
||||
# You must include this step after running all auto-fixing steps
|
||||
- uses: stefanzweifel/git-auto-commit-action@v5
|
||||
with:
|
||||
commit_message: "fix(${{ github.run_id }}): auto linting" # The commit message MUST start with "fix(${{ github.run_id }}):"
|
||||
commit_options: "--no-verify" # No verify because we already ran it above
|
||||
skip_fetch: true
|
||||
skip_checkout: true
|
||||
status_options: "--untracked-files=no"
|
||||
add_options: "--update"
|
||||
|
||||
- name: Check types
|
||||
if: steps.changes.outputs.frontend_all == 'true'
|
||||
run: yarn type-check-pure
|
||||
3
.gitignore
vendored
@@ -112,6 +112,3 @@ modules/drivers/*/.lsp/*
|
||||
|
||||
# airgap
|
||||
/resources/airgap/
|
||||
|
||||
# swc
|
||||
.swc/
|
||||
|
||||
|
Before Width: | Height: | Size: 88 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 63 KiB |
|
Before Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 77 KiB |
|
Before Width: | Height: | Size: 82 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 75 KiB |