Compare commits
1 Commits
docs-json
...
remove-dea
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
754dd7725f |
@@ -1,8 +1,5 @@
|
||||
{:hooks
|
||||
{:analyze-call
|
||||
{next.jdbc/with-transaction
|
||||
hooks.com.github.seancorfield.next-jdbc/with-transaction
|
||||
next.jdbc/with-transaction+options
|
||||
hooks.com.github.seancorfield.next-jdbc/with-transaction+options}}
|
||||
:lint-as {next.jdbc/on-connection clojure.core/with-open
|
||||
next.jdbc/on-connection+options clojure.core/with-open}}
|
||||
hooks.com.github.seancorfield.next-jdbc/with-transaction}}
|
||||
:lint-as {next.jdbc/on-connection clojure.core/with-open}}
|
||||
@@ -16,19 +16,3 @@
|
||||
opts
|
||||
body))]
|
||||
{:node new-node})))
|
||||
|
||||
(defn with-transaction+options
|
||||
"Expands (with-transaction+options [tx expr opts] body)
|
||||
to (let [tx expr] opts body) per clj-kondo examples."
|
||||
[{:keys [:node]}]
|
||||
(let [[binding-vec & body] (rest (:children node))
|
||||
[sym val opts] (:children binding-vec)]
|
||||
(when-not (and sym val)
|
||||
(throw (ex-info "No sym and val provided" {})))
|
||||
(let [new-node (api/list-node
|
||||
(list*
|
||||
(api/token-node 'let)
|
||||
(api/vector-node [sym val])
|
||||
opts
|
||||
body))]
|
||||
{:node new-node})))
|
||||
|
||||
@@ -1,46 +1,13 @@
|
||||
{:config-paths ["macros"]
|
||||
:linters
|
||||
{:aliased-namespace-symbol {:level :warning}
|
||||
:invalid-arity {:skip-args [metabase.mbql.util.match/match]} ; TODO (cam): can we fix these?
|
||||
:keyword-binding {:level :warning}
|
||||
:main-without-gen-class {:level :warning}
|
||||
:misplaced-docstring {:level :warning}
|
||||
:missing-body-in-when {:level :warning}
|
||||
:missing-docstring {:level :warning}
|
||||
:missing-else-branch {:level :warning}
|
||||
:namespace-name-mismatch {:level :warning}
|
||||
:non-arg-vec-return-type-hint {:level :warning}
|
||||
:reduce-without-init {:level :warning}
|
||||
:redundant-fn-wrapper {:level :warning}
|
||||
:refer-all {:level :warning, :exclude [clojure.test]}
|
||||
:single-key-in {:level :warning}
|
||||
:unused-referred-var {:exclude {compojure.core [GET DELETE POST PUT]}}
|
||||
:use {:level :warning}
|
||||
:warn-on-reflection {:level :warning}
|
||||
|
||||
;;
|
||||
;; disabled linters
|
||||
;;
|
||||
|
||||
:unexpected-recur {:level :off} ; TODO (cam): I think we just need to tell it how to handle MBQL match and we can enable this?
|
||||
:used-underscored-binding {:level :off} ; false positives: see https://github.com/clj-kondo/clj-kondo/issues/2152
|
||||
|
||||
;;
|
||||
;; TODO (cam): here are some more linters we should experiment with enabling -- some might be useful.
|
||||
;;
|
||||
|
||||
;; :docstring-leading-trailing-whitespace {:level :warning}
|
||||
;; :docstring-no-summary {:level :warning}
|
||||
;; :shadowed-var {:level :warning}
|
||||
|
||||
:unresolved-symbol
|
||||
{:unresolved-symbol
|
||||
{:exclude
|
||||
[instaparse.core/transform
|
||||
(cljs.test/is [=? malli=])
|
||||
(cljs.test/is [=?])
|
||||
(clojure.core.logic/fresh)
|
||||
(clojure.core.logic/matcha)
|
||||
(clojure.core.logic/run)
|
||||
(clojure.test/is [query= sql= =? malli=])
|
||||
(clojure.test/is [query= sql= =?])
|
||||
(clojure.tools.macro/macrolet)
|
||||
(metabase.async.streaming-response/streaming-response)
|
||||
(metabase.driver.druid.query-processor-test/druid-query-returning-rows)
|
||||
@@ -58,6 +25,33 @@
|
||||
(taoensso.nippy/extend-freeze)
|
||||
(taoensso.nippy/extend-thaw)]}
|
||||
|
||||
:refer-all {:level :warning
|
||||
:exclude [clojure.test]}
|
||||
;; TODO (cam): I think we just need to tell it how to handle MBQL match and we can enable this?
|
||||
:unexpected-recur {:level :off}
|
||||
;; TODO (cam): can we fix these?
|
||||
:unused-referred-var {:exclude {compojure.core [GET DELETE POST PUT]}}
|
||||
:missing-else-branch {:level :warning}
|
||||
:misplaced-docstring {:level :warning}
|
||||
:non-arg-vec-return-type-hint {:level :warning}
|
||||
:missing-body-in-when {:level :warning}
|
||||
:missing-docstring {:level :warning}
|
||||
;; TODO (braden): This is useful, but it doesn't grok eg. enterprise/backend/src
|
||||
:namespace-name-mismatch {:level :off}
|
||||
:use {:level :warning}
|
||||
:redundant-fn-wrapper {:level :warning}
|
||||
:invalid-arity {:skip-args [metabase.mbql.util.match/match]}
|
||||
:warn-on-reflection {:level :warning}
|
||||
;; TODO (cam): here are some more linters we should experiment with enabling -- some might be useful.
|
||||
;; :docstring-no-summary {:level :warning}
|
||||
;; :docstring-leading-trailing-whitespace {:level :warning}
|
||||
;; :reduce-without-init {:level :warning}
|
||||
;; :used-underscored-binding {:level :warning}
|
||||
;; :single-key-in {:level :warning}
|
||||
;; :keyword-binding {:level :warning}
|
||||
;; :main-without-gen-class {:level :warning}
|
||||
;; :shadowed-var {:level :warning}
|
||||
|
||||
:deprecated-var
|
||||
{:exclude
|
||||
{metabase.cmd/dump {:namespaces ["metabase\\.cmd-test" "metabase-enterprise\\.serialization\\.cmd-test"]}
|
||||
@@ -65,6 +59,12 @@
|
||||
metabase.db.data-migrations/data-migrations {:namespaces ["metabase\\.db\\.data-migrations"]}
|
||||
metabase.db.data-migrations/defmigration {:namespaces ["metabase\\.db\\.data-migrations"]}
|
||||
metabase.db.data-migrations/run-migration-if-needed! {:namespaces ["metabase\\.db\\.data-migrations"]}
|
||||
metabase.driver.common/ThreadSafeSimpleDateFormat {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.driver.common/create-db-time-formatters {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.driver.common/current-db-time {:namespaces ["metabase.*"]}
|
||||
metabase.driver.common/current-db-time-date-formatters {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.driver.common/current-db-time-native-query {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.driver.common/first-successful-parse {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.driver.sql-jdbc.execute.old-impl/set-timezone-sql {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.driver.sql-jdbc.execute/set-time-zone-if-supported! {:namespaces ["metabase\\.driver.*"]}
|
||||
metabase.driver/current-db-time {:namespaces ["metabase.*"]}
|
||||
@@ -123,28 +123,47 @@
|
||||
schema.core/either {:namespaces ["metabase.*"]}}}
|
||||
|
||||
:discouraged-var
|
||||
{clojure.core/print {:message "Use metabase.util.log instead of clojure.core/print"}
|
||||
clojure.core/println {:message "Use metabase.util.log instead of clojure.core/println"}
|
||||
clojure.core/printf {:message "Use metabase.util.log instead of clojure.core/printf"}
|
||||
clojure.core/prn {:message "Use metabase.util.log instead of clojure.core/prn"}
|
||||
clojure.core/pr {:message "Use metabase.util.log instead of clojure.core/pr"}
|
||||
clojure.core/tap> {:message "Don't use tap> is source code"}
|
||||
clojure.core/time {:message "Don't use time in source code"}
|
||||
clojure.java.jdbc/get-connection {:message "Use sql-jdbc.execute/do-with-connection-with-options (for drivers) or t2/with-connection (for the app DB) instead of jdbc/get-connection"}
|
||||
clojure.java.jdbc/with-db-connection {:message "Use sql-jdbc.execute/do-with-connection-with-options (for drivers) or t2/with-connection (for the app DB) instead of jdbc/with-db-connection"}
|
||||
clojure.java.jdbc/with-db-metadata {:message "Use sql-jdbc.execute/do-with-connection-with-options + .getMetaData instead of jdbc/with-db-metadata"}
|
||||
clojure.pprint/pprint {:message "Use metabase.util.log instead of clojure.pprint/pprint"}
|
||||
clojure.string/lower-case {:message "Use metabase.util/lower-case-en instead of clojure.string/lower-case"}
|
||||
clojure.string/upper-case {:message "Use metabase.util/upper-case-en instead of clojure.string/upper-case"}
|
||||
honeysql.core/call {:message "Use hx/call instead because it is Honey SQL 2 friendly"}
|
||||
honeysql.core/raw {:message "Use hx/raw instead because it is Honey SQL 2 friendly"}
|
||||
java-time/with-clock {:message "Use mt/with-clock"}
|
||||
java.util.UUID/randomUUID {:message "Use clojure.core/random-uuid instead of java.util.UUID/randomUUID"}
|
||||
malli.core/explainer {:message "Use metabase.util.malli.registry/explainer instead of malli.core/explainer"}
|
||||
medley.core/random-uuid {:message "Use clojure.core/random-uuid instead of medley.core/random-uuid"}
|
||||
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"}}
|
||||
{clojure.core/print {:message "Use clojure.tools.logging instead of clojure.core/print"}
|
||||
clojure.core/println {:message "Use clojure.tools.logging instead of clojure.core/println"}
|
||||
clojure.core/printf {:message "Use clojure.tools.logging instead of clojure.core/printf"}
|
||||
clojure.core/prn {:message "Use clojure.tools.logging instead of clojure.core/prn"}
|
||||
clojure.core/pr {:message "Use clojure.tools.logging instead of clojure.core/pr"}
|
||||
clojure.pprint/pprint {:message "Use clojure.tools.logging instead of clojure.pprint/pprint"}
|
||||
clojure.string/lower-case {:message "Use metabase.util/lower-case-en instead of clojure.string/lower-case"}
|
||||
clojure.string/upper-case {:message "Use metabase.util/upper-case-en instead of clojure.string/upper-case"}
|
||||
honeysql.core/call {:message "Use hx/call instead because it is Honey SQL 2 friendly"}
|
||||
honeysql.core/raw {:message "Use hx/raw instead because it is Honey SQL 2 friendly"}
|
||||
java-time/with-clock {:message "Use mt/with-clock"}
|
||||
metabase.test/with-temp {:message "Use t2.with-temp/with-temp instead of metabase.test/with-temp"}
|
||||
;; metabase.test/with-temp* {:message "Use t2.with-temp/with-temp instead of metabase.test/with-temp*"}
|
||||
toucan.db/select {:message "Use t2/select instead of toucan.db/select"}
|
||||
toucan.db/select-one {:message "Use t2/select-one instead of toucan.db/select-one"}
|
||||
toucan.db/select-one-id {:message "Use t2/select-one-pk instead of toucan.db/select-one-id"}
|
||||
toucan.db/select-one-field {:message "Use t2/select-one-fn instead of toucan.db/select-one-field"}
|
||||
toucan.db/select-ids {:message "Use t2/select-pks-set instead of toucan.db/select-ids"}
|
||||
toucan.db/select-field {:message "Use t2/select-fn instead of toucan.db/select-field"}
|
||||
toucan.db/select-field->field {:message "Use t2/select-fn->fn instead of toucan.db/select-field->field"}
|
||||
toucan.db/select-field->id {:message "Use t2/select-fn->pk instead of toucan.db/select-field->id"}
|
||||
toucan.db/select-id->field {:message "Use t2/select-pk->field instead of toucan.db/select-id->field"}
|
||||
toucan.db/simple-insert! {:message "Use t2/insert-returning-pks! with table name instead of toucan.db/simple-insert!"}
|
||||
toucan.db/simple-insert-many! {:message "Use t2/insert-returning-pks! with table name instead of toucan.db/simple-insert-many!"}
|
||||
toucan.db/simple-delete! {:message "Use t2/delete! with table name instead of toucan.db/simple-delete!"}
|
||||
toucan.db/delete! {:message "Use t2/delete! instead of toucan.db/delete!"}
|
||||
toucan.db/insert! {:message "Use t2/insert-returning-instances! instead of toucan.db/insert!"}
|
||||
toucan.db/update! {:message "Use t2/update! instead of toucan.db/update!"}
|
||||
toucan.db/update-where! {:message "Use t2/update! instead of toucan.db/update-where!"}
|
||||
toucan.db/query {:message "Use mdb.query/query instead of toucan.db/query"}
|
||||
toucan.db/count {:message "Use t2/count instead of toucan.db/count"}
|
||||
toucan.db/exists? {:message "Use t2/exists? instead of toucan.db/exists?"}
|
||||
toucan.db/transaction {:message "Use t2/with-transaction instead of toucan.db/transaction"}
|
||||
toucan.db/with-call-counting {:message "Use t2/with-call-count instead of toucan.db/with-call-counting"}
|
||||
toucan.db/execute! {:message "Use t2/query-one instead of toucan.db/execute!"}
|
||||
toucan.db/reducible-query {:message "Use mdb.query/reducible-query instead of toucan.db/reducible-query"}
|
||||
toucan.db/resolve-model {:message "Use metabase.db.util/resolve-model instead of toucan.db/resolve-model"}
|
||||
toucan.models/primary-key {:message "Use metabase.db.util/primary-key instead of toucan.models/primary-key"}
|
||||
toucan.models/model? {:message "Use mdb.u/toucan-model? instead of toucan.models/model?"}
|
||||
toucan.util.test/with-temp {:message "Use t2.with-temp/with-temp instead of toucan.util.test/with-temp"}
|
||||
toucan.util.test/with-temp* {:message "Use t2.with-temp/with-temp instead of toucan.util.test/with-temp*"}}
|
||||
|
||||
:discouraged-namespace
|
||||
{camel-snake-kebab.core {:message "CSK is not Turkish-safe, use the versions in metabase.util instead."}
|
||||
@@ -247,7 +266,6 @@
|
||||
metabase.api.util api.util
|
||||
metabase.async.streaming-response.thread-pool thread-pool
|
||||
metabase.automagic-dashboards.core magic
|
||||
metabase.automagic-dashboards.dashboard-templates dashboard-templates
|
||||
metabase.automagic-dashboards.populate populate
|
||||
metabase.cmd.copy.h2 copy.h2
|
||||
metabase.config config
|
||||
@@ -296,7 +314,6 @@
|
||||
metabase.email-test et
|
||||
metabase.email.messages messages
|
||||
metabase.http-client client
|
||||
metabase.lib.util lib.util
|
||||
metabase.mbql.normalize mbql.normalize
|
||||
metabase.mbql.schema mbql.s
|
||||
metabase.mbql.util mbql.u
|
||||
@@ -334,7 +351,6 @@
|
||||
metabase.pulse.render.body body
|
||||
metabase.pulse.render.common common
|
||||
metabase.pulse.render.style style
|
||||
metabase.pulse.parameters params
|
||||
metabase.query-processor-test qp.test
|
||||
metabase.query-processor.context qp.context
|
||||
metabase.query-processor.error-type qp.error-type
|
||||
@@ -361,9 +377,6 @@
|
||||
metabase.query-processor.timezone qp.timezone
|
||||
metabase.query-processor.util qp.util
|
||||
metabase.related related
|
||||
metabase.search.config search.config
|
||||
metabase.search.filter search.filter
|
||||
metabase.search.util search.util
|
||||
metabase.search.scoring scoring
|
||||
metabase.server.middleware.auth mw.auth
|
||||
metabase.server.middleware.browser-cookie mw.browser-cookie
|
||||
@@ -402,7 +415,6 @@
|
||||
metabase.test.domain-entities test.de
|
||||
metabase.test.mock.util mock.util
|
||||
metabase.test.sync test.sync
|
||||
metabase.test.redefs test.redefs
|
||||
metabase.test.util.js test.js
|
||||
metabase.test.util.timezone test.tz
|
||||
metabase.timeseries-query-processor-test.util tqpt
|
||||
@@ -441,11 +453,7 @@
|
||||
ring.adapter.jetty9.servlet servlet
|
||||
saml20-clj.core saml
|
||||
toucan.db db
|
||||
toucan.models models}}
|
||||
|
||||
:metabase/validate-deftest {:level :warning}
|
||||
:metabase/missing-test-expr-requires-in-cljs {:level :warning}
|
||||
:metabase/i-like-making-cams-eyes-bleed-with-horrifically-long-tests {:level :warning}}
|
||||
toucan.models models}}}
|
||||
|
||||
:lint-as
|
||||
{clojure.core.logic/defne clj-kondo.lint-as/def-catch-all
|
||||
@@ -456,6 +464,7 @@
|
||||
metabase-enterprise.serialization.test-util/with-random-dump-dir clojure.core/let
|
||||
metabase.actions.test-util/with-actions clojure.core/let
|
||||
metabase.api.common/let-404 clojure.core/let
|
||||
metabase.api.dashboard-test/let-url 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
|
||||
@@ -489,20 +498,14 @@
|
||||
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-file clojure.core/let
|
||||
metabase.test/with-user-in-groups 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
|
||||
monger.operators/defoperator clojure.core/def
|
||||
potemkin.types/defprotocol+ clojure.core/defprotocol
|
||||
@@ -516,26 +519,20 @@
|
||||
|
||||
:hooks
|
||||
{:analyze-call
|
||||
{cljs.test/deftest hooks.clojure.test/deftest
|
||||
cljs.test/is hooks.clojure.test/is
|
||||
cljs.test/use-fixtures hooks.clojure.test/use-fixtures
|
||||
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.advanced-config.caching-test/with-temp-persist-models hooks.common/with-seven-bindings
|
||||
{clojure.test/deftest hooks.clojure.test/deftest
|
||||
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.serialization.test-util/with-temp-dpc hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase-enterprise.serialization.test-util/with-temp-dpc hooks.toucan.util.test/with-temp*
|
||||
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.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.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.common/defendpoint-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
|
||||
@@ -555,9 +552,6 @@
|
||||
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.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.mbql.schema.macros/defclause hooks.metabase.mbql.schemas.macros/defclause
|
||||
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
|
||||
@@ -600,10 +594,10 @@
|
||||
metabase.test/with-log-level hooks.common/with-ignored-first-arg
|
||||
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! hooks.toucan2.tools.with-temp/with-temp
|
||||
metabase.test/with-temp* hooks.toucan.util.test/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.test/with-temporary-setting-values hooks.metabase.test.util/with-temporary-setting-values
|
||||
toucan.util.test/with-temp* hooks.toucan.util.test/with-temp*}
|
||||
|
||||
:macroexpand
|
||||
{clojurewerkz.quartzite.jobs/build macros.quartz/build-job
|
||||
@@ -687,13 +681,7 @@
|
||||
;;
|
||||
;; Please keep this form updated when you change the generated regex! <3
|
||||
{:pattern "^metabase\\.(?!util\\.(?:(?:honeysql-extensions)|(?:honey-sql-1)))(?!query-processor-test)(?!(?:(?:driver)|(?:test\\.data))\\.(?:(?:sql(?:-jdbc)?)|(?:(?:sql(?:-jdbc)?))|(?:bigquery-cloud-sdk)|(?:presto(?:(?:(?:-common)|(?:-jdbc)))?)|(?:sqlserver))(?:-test)?(?:(?:\\.)|(?:$))).*"
|
||||
:name honey-sql-2-namespaces}
|
||||
;;
|
||||
;; QP source namespaces: `metabase.query-processor.*`, `metabase-enterprise.sandbox.query-processor.*`, and
|
||||
;; `metabase.driver.*`, excluding `-test` namespaces.
|
||||
;;
|
||||
{:pattern "metabase(?:(?:(?:-enterprise\\.sandbox)?\\.query-processor\\.)|(?:\\.driver\\.)).*(?<!-test)$"
|
||||
:name qp-and-driver-source-namespaces}]
|
||||
:name honey-sql-2-namespaces}]
|
||||
|
||||
:config-in-ns
|
||||
{test-namespaces
|
||||
@@ -706,8 +694,8 @@
|
||||
source-namespaces
|
||||
{:linters
|
||||
{:discouraged-var
|
||||
{clojure.core/with-redefs {:message "Don't use with-redefs outside of tests"}
|
||||
clojure.core/eval {:message "Don't use eval outside of tests"}}}}
|
||||
{clojure.core/with-redefs {:message "Don't use with-redefs"}
|
||||
clojure.core/eval {:message "Don't use eval"}}}}
|
||||
|
||||
printable-namespaces
|
||||
{:linters
|
||||
@@ -730,7 +718,9 @@
|
||||
metabase-lib
|
||||
{:linters
|
||||
{:docstring-leading-trailing-whitespace {:level :warning}
|
||||
:reduce-without-init {:level :warning}
|
||||
:used-underscored-binding {:level :warning}
|
||||
:single-key-in {:level :warning}
|
||||
:keyword-binding {:level :warning}
|
||||
:shadowed-var {:level :warning}
|
||||
:metabase/deftest-not-marked-parallel-or-synchronized {:level :warning}
|
||||
@@ -738,24 +728,5 @@
|
||||
;; eventually we should do this for the whole codebase, but the args are in the opposite order so switching them
|
||||
;; all at once isn't trivial, at least we can stop using it in new code.
|
||||
:discouraged-var
|
||||
{medley.core/map-keys {:message "Use clojure.core/update-keys"}
|
||||
medley.core/map-vals {:message "Use clojure.core/update-vals"}
|
||||
metabase.test/with-temp {:message "Don't use application database inside MLv2 code"}}
|
||||
|
||||
:discouraged-namespace
|
||||
{toucan.db {:message "Don't use application database inside MLv2 code"}
|
||||
toucan.models {:message "Don't use application database inside MLv2 code"}
|
||||
toucan.util.test {:message "Don't use application database inside MLv2 code"}
|
||||
toucan2.core {:message "Don't use application database inside MLv2 code"}}}}
|
||||
|
||||
qp-and-driver-source-namespaces
|
||||
{:linters
|
||||
{:discouraged-namespace
|
||||
{toucan.db {:message "Don't use application database directly in QP code; use QP Store/metadata provider"}
|
||||
toucan.models {:message "Don't use application database directly in QP code; use QP Store/metadata provider"}
|
||||
toucan.util.test {:message "Don't use application database directly in QP code; use QP Store/metadata provider"}
|
||||
toucan2.core {:message "Don't use application database directly in QP code; use QP Store/metadata provider"}}
|
||||
|
||||
:discouraged-var
|
||||
{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"}}}}}}
|
||||
{medley.core/map-keys {:message "Use clojure.core/update-keys"}
|
||||
medley.core/map-vals {:message "Use clojure.core/update-vals"}}}}}}
|
||||
|
||||
@@ -1,154 +1,27 @@
|
||||
(ns hooks.clojure.test
|
||||
(:require [clj-kondo.hooks-api :as hooks]
|
||||
[clojure.string :as str]))
|
||||
(:require [clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(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
|
||||
(def disallowed-parallel-forms
|
||||
'#{with-redefs
|
||||
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.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.timezone/with-system-timezone-id
|
||||
metabase.test.util/with-all-users-permission
|
||||
metabase.test.util/with-column-remappings
|
||||
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-column-remappings
|
||||
metabase.test/with-discarded-collections-perms-changes
|
||||
metabase.test/with-ensure-with-temp-no-transaction!
|
||||
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-system-timezone-id
|
||||
metabase.test/with-temp!
|
||||
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})
|
||||
mt/with-temporary-setting-values})
|
||||
|
||||
;;; 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.query-processor/process-query-and-save-execution!
|
||||
metabase.query-processor/process-query-and-save-with-max-results-constraints!
|
||||
metabase.query-processor.store/store-database!})
|
||||
|
||||
(defn- node->qualified-symbol [node]
|
||||
(try
|
||||
(when (hooks/token-node? node)
|
||||
(let [sexpr (hooks/sexpr node)]
|
||||
(when (symbol? sexpr)
|
||||
(when-let [resolved (hooks/resolve {:name sexpr})]
|
||||
(symbol (name (:ns resolved)) (name (:name resolved)))))))
|
||||
;; some symbols like `*count/Integer` aren't resolvable.
|
||||
(catch Exception _
|
||||
nil)))
|
||||
|
||||
(defn- warn-about-disallowed-parallel-forms [form]
|
||||
(letfn [(error! [form message]
|
||||
(hooks/reg-finding! (assoc (meta form)
|
||||
:message message
|
||||
:type :metabase/validate-deftest)))
|
||||
(f [form]
|
||||
(when-let [qualified-symbol (node->qualified-symbol form)]
|
||||
(cond
|
||||
(disallowed-parallel-forms qualified-symbol)
|
||||
(error! form (format "%s is not allowed inside a ^:parallel test or test fixture" 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 .clj-kondo/hooks/clojure/test.clj"
|
||||
qualified-symbol)))))
|
||||
(defn warn-about-disallowed-parallel-forms [form]
|
||||
(letfn [(f [form]
|
||||
(when-let [sexpr (and (hooks/token-node? form)
|
||||
(hooks/sexpr form))]
|
||||
(when (disallowed-parallel-forms sexpr)
|
||||
(hooks/reg-finding! (assoc (meta form)
|
||||
:message (format "%s is not allowed inside a ^:parallel test" sexpr)
|
||||
:type :metabase/validate-deftest)))))
|
||||
(walk [form]
|
||||
(f form)
|
||||
(doseq [child (:children form)]
|
||||
(walk child)))]
|
||||
(walk form)))
|
||||
|
||||
(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}]
|
||||
(defn deftest [{{[_ test-name & body] :children, :as node} :node}]
|
||||
(let [test-metadata (:meta test-name)
|
||||
metadata-sexprs (map hooks/sexpr test-metadata)
|
||||
combined-metadata (transduce
|
||||
@@ -175,71 +48,5 @@
|
||||
:type :metabase/deftest-not-marked-parallel-or-synchronized)))
|
||||
(when parallel?
|
||||
(doseq [form body]
|
||||
(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]
|
||||
(let [{:keys [row end-row]} (meta node)]
|
||||
(when (and row end-row)
|
||||
(let [num-lines (- end-row row)]
|
||||
(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 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))
|
||||
(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`
|
||||
;;; will come back as `nil` if they are not.
|
||||
(defn- approximately-equal-ns-required? []
|
||||
(= (:ns (hooks/resolve {:name 'metabase.test-runner.assert-exprs.approximately-equal/=?-report}))
|
||||
'metabase.test-runner.assert-exprs.approximately-equal))
|
||||
|
||||
(defn- malli-equals-ns-required? []
|
||||
(= (:ns (hooks/resolve {:name 'metabase.test-runner.assert-exprs.malli-equals/malli=-report}))
|
||||
'metabase.test-runner.assert-exprs.malli-equals))
|
||||
|
||||
(defn- warn-about-missing-test-expr-requires-in-cljs [{:keys [children], :as _is-node}]
|
||||
(let [[_is assertion-node] children]
|
||||
(when (hooks/list-node? assertion-node)
|
||||
(let [[assertion-symb-node] (:children assertion-node)]
|
||||
(when (hooks/token-node? assertion-symb-node)
|
||||
(let [assertion-symb-token (hooks/sexpr assertion-symb-node)
|
||||
warn! (fn [ns-to-require]
|
||||
(hooks/reg-finding!
|
||||
(assoc (meta assertion-symb-node)
|
||||
:message (format "You must require %s to use %s in ClojureScript"
|
||||
ns-to-require
|
||||
assertion-symb-token)
|
||||
:type :metabase/missing-test-expr-requires-in-cljs)))]
|
||||
(condp = assertion-symb-token
|
||||
'=?
|
||||
(when-not (approximately-equal-ns-required?)
|
||||
(warn! 'metabase.test-runner.assert-exprs.approximately-equal))
|
||||
|
||||
'malli=
|
||||
(when-not (malli-equals-ns-required?)
|
||||
(warn! 'metabase.test-runner.assert-exprs.malli-equals))
|
||||
|
||||
nil)))))))
|
||||
|
||||
(defn is [{:keys [node lang]}]
|
||||
(when (= lang :cljs)
|
||||
(warn-about-missing-test-expr-requires-in-cljs node))
|
||||
{:node node})
|
||||
|
||||
(defn use-fixtures [{:keys [node]}]
|
||||
(warn-about-disallowed-parallel-forms node)
|
||||
(warn-about-disallowed-parallel-forms form))))
|
||||
{:node node})
|
||||
|
||||
@@ -141,84 +141,6 @@
|
||||
body))]
|
||||
{:node node*}))
|
||||
|
||||
(defn with-five-bindings
|
||||
"Helper for macros that have a shape like
|
||||
|
||||
(my-macro [a b c d e]
|
||||
...)
|
||||
|
||||
=>
|
||||
|
||||
(let [a nil, b nil, c nil, d nil, e nil]
|
||||
...)
|
||||
|
||||
All bindings are optional and `_` will be substituted if not supplied."
|
||||
[{{[_ {[a b c d e] :children} & body] :children} :node}]
|
||||
(let [node* (hooks/list-node
|
||||
(list*
|
||||
(hooks/token-node 'let)
|
||||
(hooks/vector-node
|
||||
[(or a (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or b (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or c (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or d (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or e (hooks/token-node '_)) (hooks/token-node 'nil)])
|
||||
body))]
|
||||
{:node node*}))
|
||||
|
||||
(defn with-six-bindings
|
||||
"Helper for macros that have a shape like
|
||||
|
||||
(my-macro [a b c d e f]
|
||||
...)
|
||||
|
||||
=>
|
||||
|
||||
(let [a nil, b nil, c nil, d nil, e nil, f nil]
|
||||
...)
|
||||
|
||||
All bindings are optional and `_` will be substituted if not supplied."
|
||||
[{{[_ {[a b c d e f] :children} & body] :children} :node}]
|
||||
(let [node* (hooks/list-node
|
||||
(list*
|
||||
(hooks/token-node 'let)
|
||||
(hooks/vector-node
|
||||
[(or a (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or b (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or c (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or d (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or e (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or f (hooks/token-node '_)) (hooks/token-node 'nil)])
|
||||
body))]
|
||||
{:node node*}))
|
||||
|
||||
(defn with-seven-bindings
|
||||
"Helper for macros that have a shape like
|
||||
|
||||
(my-macro [a b c d e f g]
|
||||
...)
|
||||
|
||||
=>
|
||||
|
||||
(let [a nil, b nil, c nil, d nil, e nil, f nil, g nil]
|
||||
...)
|
||||
|
||||
All bindings are optional and `_` will be substituted if not supplied."
|
||||
[{{[_ {[a b c d e f g] :children} & body] :children} :node}]
|
||||
(let [node* (hooks/list-node
|
||||
(list*
|
||||
(hooks/token-node 'let)
|
||||
(hooks/vector-node
|
||||
[(or a (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or b (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or c (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or d (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or e (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or f (hooks/token-node '_)) (hooks/token-node 'nil)
|
||||
(or g (hooks/token-node '_)) (hooks/token-node 'nil)])
|
||||
body))]
|
||||
{:node node*}))
|
||||
|
||||
(defn with-one-top-level-binding
|
||||
"Helper for macros that have a shape like
|
||||
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
(ns hooks.metabase.api.automagic-dashboards-test
|
||||
(:require [clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(comment
|
||||
|
||||
(def input (hooks/parse-string
|
||||
"(with-indexed-model [{:keys [model model-index model-index-value]}
|
||||
{:query :some-query}]
|
||||
:foo :bar :body)"))
|
||||
|
||||
(println (hooks/sexpr input))
|
||||
|
||||
(let [f (load-file ".clj-kondo/hooks/metabase/api/automagic_dashboards_test.clj")]
|
||||
(f {:node input})))
|
||||
|
||||
(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-testing-model)
|
||||
query-info
|
||||
(hooks/list-node
|
||||
(list* (hooks/token-node 'fn)
|
||||
(hooks/vector-node [binding])
|
||||
body))])]
|
||||
#_(println (hooks/sexpr node*))
|
||||
{:node node*}))
|
||||
@@ -1,12 +0,0 @@
|
||||
(ns hooks.metabase.lib.test-util.macros
|
||||
(:require [clj-kondo.hooks-api :as hooks]))
|
||||
|
||||
(defn with-testing-against-standard-queries [{{[_ & args] :children} :node}]
|
||||
(let [[query-sym & body] args
|
||||
node* (hooks/list-node
|
||||
(list*
|
||||
(hooks/token-node 'let)
|
||||
(hooks/vector-node
|
||||
[query-sym (hooks/token-node 'nil)])
|
||||
body))]
|
||||
{:node node*}))
|
||||
@@ -1,3 +0,0 @@
|
||||
|
||||
{:hooks
|
||||
{:analyze-call {org.httpkit.server/with-channel httpkit.with-channel/with-channel}}}
|
||||
@@ -1,16 +0,0 @@
|
||||
(ns httpkit.with-channel
|
||||
(:require [clj-kondo.hooks-api :as api]))
|
||||
|
||||
(defn with-channel [{node :node}]
|
||||
(let [[request channel & body] (rest (:children node))]
|
||||
(when-not (and request channel) (throw (ex-info "No request or channel provided" {})))
|
||||
(when-not (api/token-node? channel) (throw (ex-info "Missing channel argument" {})))
|
||||
(let [new-node
|
||||
(api/list-node
|
||||
(list*
|
||||
(api/token-node 'let)
|
||||
(api/vector-node [channel (api/vector-node [])])
|
||||
request
|
||||
body))]
|
||||
|
||||
{:node new-node})))
|
||||
@@ -37,7 +37,6 @@
|
||||
~(macros.common/ignore-unused 'card-id-nested) nil
|
||||
~(macros.common/ignore-unused 'card-id-nested-query) nil
|
||||
~(macros.common/ignore-unused 'card-id-native-query) nil
|
||||
~(macros.common/ignore-unused 'card-id-pivot-table) nil
|
||||
~(macros.common/ignore-unused 'dashcard-id) nil
|
||||
~(macros.common/ignore-unused 'dashcard-top-level-click-id) nil
|
||||
~(macros.common/ignore-unused 'dashcard-with-click-actions) nil
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
;; prefer keeping source width about ~118, GitHub seems to cut off stuff at either 119 or 120 and it's nicer
|
||||
;; to look at code in GH when you don't have to scroll back and forth
|
||||
(fill-column . 118)
|
||||
(whitespace-line-column . 118)
|
||||
;; tell find-things-fast to always use this directory as project root regardless of presence of other
|
||||
;; deps.edn files
|
||||
(ftf-project-finders . (ftf-get-top-git-dir)))
|
||||
|
||||
@@ -1,2 +1 @@
|
||||
frontend/src/cljs
|
||||
frontend/src/cljs_release
|
||||
|
||||
53
.eslintrc
53
.eslintrc
@@ -13,25 +13,9 @@
|
||||
}
|
||||
],
|
||||
"no-empty": [1, { "allowEmptyCatch": true }],
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
"paths": [
|
||||
{
|
||||
"name": "moment",
|
||||
"message": "Moment is deprecated, please use dayjs"
|
||||
},
|
||||
{
|
||||
"name": "moment-timezone",
|
||||
"message": "Moment is deprecated, please use dayjs"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"curly": [1, "all"],
|
||||
"eqeqeq": [1, "smart"],
|
||||
"import/no-default-export": 2,
|
||||
"import/no-named-as-default": 0,
|
||||
"import/no-commonjs": 1,
|
||||
"import/order": [
|
||||
"error",
|
||||
@@ -73,7 +57,7 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-console": [2, { "allow": ["warn", "error"] }],
|
||||
"no-console": [2, {"allow": ["warn", "error"]}],
|
||||
"react/no-is-mounted": 2,
|
||||
"react/prefer-es6-class": 2,
|
||||
"react/display-name": 1,
|
||||
@@ -86,35 +70,14 @@
|
||||
"react/no-unescaped-entities": 2,
|
||||
"react/jsx-no-target-blank": 2,
|
||||
"react/jsx-key": 2,
|
||||
"react/forbid-component-props": [2, { "forbid": ["sx"] }],
|
||||
"react/forbid-component-props": [2, { "forbid": ["w", "h"] }],
|
||||
"react-hooks/exhaustive-deps": [
|
||||
"warn",
|
||||
{ "additionalHooks": "(useSyncedQueryString|useSafeAsyncFunction)" }
|
||||
],
|
||||
"prefer-const": [1, { "destructuring": "all" }],
|
||||
"no-useless-escape": 0,
|
||||
"no-only-tests/no-only-tests": [
|
||||
"error",
|
||||
{
|
||||
"block": [
|
||||
"describe",
|
||||
"it",
|
||||
"context",
|
||||
"test",
|
||||
"tape",
|
||||
"fixture",
|
||||
"serial",
|
||||
"Feature",
|
||||
"Scenario",
|
||||
"Given",
|
||||
"And",
|
||||
"When",
|
||||
"Then",
|
||||
"describeWithSnowplow",
|
||||
"describeEE"
|
||||
]
|
||||
}
|
||||
],
|
||||
"no-only-tests/no-only-tests": "error",
|
||||
"complexity": ["error", { "max": 54 }]
|
||||
},
|
||||
"globals": {
|
||||
@@ -137,16 +100,11 @@
|
||||
"plugin:react/jsx-runtime",
|
||||
"plugin:react-hooks/recommended",
|
||||
"plugin:import/errors",
|
||||
"plugin:import/warnings",
|
||||
"plugin:import/typescript"
|
||||
"plugin:import/warnings"
|
||||
],
|
||||
"settings": {
|
||||
"import/internal-regex": "^metabase/|^metabase-lib/",
|
||||
"import/resolver": {
|
||||
"webpack": {
|
||||
"typescript": true
|
||||
}
|
||||
},
|
||||
"import/resolver": "webpack",
|
||||
"import/ignore": ["\\.css$"],
|
||||
"react": {
|
||||
"version": "detect"
|
||||
@@ -170,7 +128,6 @@
|
||||
"@typescript-eslint/no-explicit-any": "off",
|
||||
"@typescript-eslint/no-this-alias": "off",
|
||||
"no-unused-vars": "off",
|
||||
"@typescript-eslint/consistent-type-imports": "error",
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
|
||||
24
.github/ISSUE_TEMPLATE/epic.md
vendored
24
.github/ISSUE_TEMPLATE/epic.md
vendored
@@ -1,24 +0,0 @@
|
||||
---
|
||||
name: Epic (Internal Use)
|
||||
about: This issue is used to track a feature/project that may span several days
|
||||
to weeks to implement. This is used by the core Metabase team to project plan
|
||||
and manage work.
|
||||
title: "[Epic] Title"
|
||||
labels: ".Epic"
|
||||
|
||||
---
|
||||
|
||||
**Links**
|
||||
- product doc: _link to product doc_
|
||||
- eng doc: _link to technical design doc, if any_
|
||||
- feature branch: `branch-name` _this should be the feature branch where this work will be done in. PRs will be delivered against this branch_
|
||||
- issue links: _related issues if any_
|
||||
|
||||
**Implementation Plan**
|
||||
|
||||
|
||||
***Milestone 1***
|
||||
_insert tasklist here_
|
||||
|
||||
***Milestone 2***
|
||||
|
||||
38
.github/ISSUE_TEMPLATE/feature-or-project-implementation.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/feature-or-project-implementation.md
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
---
|
||||
name: Feature or Project Implementation (Internal Use)
|
||||
about: This issue is used to track a feature implementation for a solution to a user
|
||||
problem that may span days to weeks to implement. This is used by the core Metabase
|
||||
team to project plan and manage work.
|
||||
title: X - Internal Use - Feature/Project X Implementation
|
||||
labels: ".Epic"
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<Insert feature / project description here>: Notes - This demonstrates a workflow and implementation plan around feature X that we can use in features that go out in a release. There should be a paragraph description of the problem we're trying to solve and a high level what the solution will be.
|
||||
|
||||
**Links**
|
||||
- product doc: _link to product doc_
|
||||
- eng doc: _link to technical design doc_
|
||||
- feature branch: `branch-name` _this should be the feature branch where this work will be done in. PRs will be delivered against this branch_
|
||||
- Issue links: _list of issues this should close when this is delivered_
|
||||
|
||||
**Implementation Plan**
|
||||
|
||||
|
||||
***Milestone 1*** )_(note, each milestone should correspond to a point at which product/design can jump in to apply polish, evaluate changes, etc)_
|
||||
- [x] step 1: #somePRnumber
|
||||
- [ ] step 2
|
||||
- [ ] step 3
|
||||
|
||||
***Milestone 2***
|
||||
- [ ] etc
|
||||
|
||||
***Mileston N*** _(we can put stuff like translations, docs, testing, etc)_
|
||||
- [ ] String translations
|
||||
- [ ] Write rough pass documents for handoff to customer success
|
||||
|
||||
|
||||
**How to Test This Feature Out**
|
||||
|
||||
_(include steps on how to test this project feature out, for someone unfamiliar with this work. please try to use the sample dataset when possible. this will serve as the basis for automated e2e tests, as well as the acceptance test to showcase the essence of this feature for bug bashes, etc)_
|
||||
14
.github/ISSUE_TEMPLATE/task.md
vendored
14
.github/ISSUE_TEMPLATE/task.md
vendored
@@ -1,14 +0,0 @@
|
||||
---
|
||||
name: Task (Internal Use)
|
||||
about: This issue is used to track a smaller feature/task that does not require
|
||||
being broken down to milestones. This is used by the core Metabase team to
|
||||
project plan and manage work.
|
||||
labels: ".Task"
|
||||
|
||||
---
|
||||
|
||||
**Context**
|
||||
|
||||
|
||||
- issue links: _related issues if any_
|
||||
|
||||
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
3
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,6 +1,3 @@
|
||||
> [!IMPORTANT]
|
||||
> 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.
|
||||
|
||||
> **Warning**
|
||||
>
|
||||
> If that is your first contribution to Metabase, please sign the [Contributor License Agreement](https://docs.google.com/a/metabase.com/forms/d/1oV38o7b9ONFSwuzwmERRMi9SYrhYeOrkbmNaq9pOJ_E/viewform) (unless it's a tiny documentation change). Also, if you're attempting to fix a translation issue, please submit your changes to our [POEditor project](https://poeditor.com/join/project/ynjQmwSsGh) instead of opening a PR.
|
||||
|
||||
64
.github/actions/build-e2e-matrix/action.yml
vendored
64
.github/actions/build-e2e-matrix/action.yml
vendored
@@ -1,64 +0,0 @@
|
||||
name: Build E2E Matrix
|
||||
description: Build and output a custom matrix for E2E tests.
|
||||
|
||||
outputs:
|
||||
matrix:
|
||||
description: Parameterized matrix in JSON format
|
||||
value: ${{ steps.matrix.outputs.result }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
id: matrix
|
||||
with:
|
||||
script: |
|
||||
const java = 11;
|
||||
|
||||
const defaultRunner = "ubuntu-22.04";
|
||||
const beefierRunner = "buildjet-2vcpu-ubuntu-2204";
|
||||
|
||||
const defaultOptions = {
|
||||
"java-version": java,
|
||||
runner: defaultRunner,
|
||||
edition: "ee",
|
||||
context: "folder"
|
||||
};
|
||||
|
||||
const testSets = [
|
||||
["actions", {} ],
|
||||
["admin", {} ],
|
||||
["admin-2", {} ],
|
||||
["binning", {} ],
|
||||
["collections", {} ],
|
||||
["custom-column", {} ],
|
||||
["dashboard", {} ],
|
||||
["dashboard-cards", {} ],
|
||||
["dashboard-filters", {} ],
|
||||
["embedding", {} ],
|
||||
["filters", {} ],
|
||||
["joins", {} ],
|
||||
["models", {} ],
|
||||
["native", {} ],
|
||||
["native-filters", {} ],
|
||||
["onboarding", {} ],
|
||||
["organization", {} ],
|
||||
["permissions", {} ],
|
||||
["question", {} ],
|
||||
["sharing", {} ],
|
||||
["visualizations", {} ],
|
||||
["oss-subset", { edition: 'oss', context: "special" } ],
|
||||
["slow", { runner: beefierRunner, context: "special" } ],
|
||||
["mongo", { context: "qa-database" } ],
|
||||
];
|
||||
|
||||
const config = testSets.map(([name, specialOptions]) => {
|
||||
return {
|
||||
...defaultOptions,
|
||||
...specialOptions,
|
||||
name,
|
||||
}
|
||||
});
|
||||
|
||||
const matrix = { include: config };
|
||||
return matrix;
|
||||
77
.github/actions/e2e-download-uberjar/action.yml
vendored
77
.github/actions/e2e-download-uberjar/action.yml
vendored
@@ -1,77 +0,0 @@
|
||||
name: Find and download uberjar for E2E tests
|
||||
description: Download previously built artifact from one of the previous commits.
|
||||
inputs:
|
||||
edition:
|
||||
description: Metabase edition.
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Download previously stored uberjar
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: | # js
|
||||
const fs = require('fs');
|
||||
const execSync = require("child_process").execSync;
|
||||
|
||||
const getCommit = (ref = "HEAD") => {
|
||||
const [commit] = execSync(`git rev-parse ${ref}`, { encoding: "utf8" }).split(
|
||||
"\n",
|
||||
);
|
||||
return commit;
|
||||
};
|
||||
|
||||
const baseConfig = {
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
};
|
||||
|
||||
async function getArtifact(commit, depth = 0) {
|
||||
if (depth > 20) {
|
||||
throw new Error("Couldn't find the artifact!");
|
||||
}
|
||||
|
||||
const artifactName = `metabase-${{ inputs.edition }}-${commit}-uberjar`;
|
||||
|
||||
const {
|
||||
data: { artifacts },
|
||||
} = await github.rest.actions.listArtifactsForRepo({
|
||||
...baseConfig,
|
||||
name: artifactName,
|
||||
per_page: 1,
|
||||
});
|
||||
|
||||
const [artifact] = artifacts;
|
||||
|
||||
if (!artifact) {
|
||||
const parentCommit = getCommit(`${commit}^`);
|
||||
console.log(`Didn't find ${artifactName}.\n`);
|
||||
console.log(`Switching to the parent commit: ${parentCommit}`);
|
||||
return getArtifact(parentCommit, depth + 1);
|
||||
} else {
|
||||
return artifact;
|
||||
}
|
||||
}
|
||||
|
||||
const currentCommit = "${{ github.event.pull_request.head.sha || github.sha }}";
|
||||
const { id } = await getArtifact(currentCommit);
|
||||
|
||||
const download = await github.rest.actions.downloadArtifact({
|
||||
...baseConfig,
|
||||
artifact_id: 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
|
||||
shell: bash
|
||||
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
cat version.properties
|
||||
mv version.properties resources/
|
||||
shell: bash
|
||||
@@ -1,87 +0,0 @@
|
||||
name: Prepare Docker containers
|
||||
description: Prepare Docker containers for E2E tests.
|
||||
inputs:
|
||||
username:
|
||||
description: DockerHub username
|
||||
required: true
|
||||
password:
|
||||
description: DockerHub password/token
|
||||
required: true
|
||||
maildev:
|
||||
description: Maildev
|
||||
required: true
|
||||
default: 'false'
|
||||
openldap:
|
||||
description: Maildev
|
||||
required: true
|
||||
default: 'false'
|
||||
postgres:
|
||||
description: Maildev
|
||||
required: true
|
||||
default: 'false'
|
||||
mysql:
|
||||
description: Maildev
|
||||
required: true
|
||||
default: 'false'
|
||||
mongo:
|
||||
description: Maildev
|
||||
required: true
|
||||
default: 'false'
|
||||
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
- name: Authenticate to prevent API rate limit
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ inputs.username }}
|
||||
password: ${{ inputs.password }}
|
||||
|
||||
- name: Start Containers
|
||||
run: |
|
||||
Y='\033[33m'
|
||||
G='\033[1;32m'
|
||||
|
||||
if ${{ inputs.maildev }}; then
|
||||
echo -e "${Y}Starting maildev container..." &&
|
||||
docker run -d -p 1080:1080 -p 1025:1025 maildev/maildev:2.0.5 &&
|
||||
while ! nc -z localhost 1080; do sleep 1; done &&
|
||||
while ! nc -z localhost 1025; do sleep 1; done &&
|
||||
echo -e "${G}Maildev is up and running!"
|
||||
fi
|
||||
|
||||
if ${{ inputs.openldap }}; then
|
||||
echo -e "${Y}Starting openldap container..." &&
|
||||
docker run -d -p 389:389 \
|
||||
--env LDAP_ADMIN_PASSWORD=adminpass \
|
||||
--env LDAP_USERS=user01@example.org,user02@example.org \
|
||||
--env LDAP_PASSWORDS=123456,123465 \
|
||||
--env LDAP_ROOT=dc=example,dc=org \
|
||||
--env LDAP_PORT_NUMBER=389 \
|
||||
bitnami/openldap:2.6.4 &&
|
||||
while ! nc -z localhost 389; do sleep 1; done &&
|
||||
echo -e "${G}Openldap is up and running!"
|
||||
fi
|
||||
|
||||
if ${{ inputs.postgres }}; then
|
||||
echo -e "${Y}Starting postgres container..." &&
|
||||
docker run -d -p 5404:5432 metabase/qa-databases:postgres-sample-12 &&
|
||||
while ! nc -z localhost 5404; do sleep 1; done &&
|
||||
echo -e "${G}Postgres is up and running!"
|
||||
fi
|
||||
|
||||
if ${{ inputs.mysql }}; then
|
||||
echo -e "${Y}Starting mysql container..." &&
|
||||
docker run -d -p 3304:3306 metabase/qa-databases:mysql-sample-8 &&
|
||||
while ! nc -z localhost 3304; do sleep 1; done &&
|
||||
echo -e "${G}MySQL is up and running!"
|
||||
fi
|
||||
|
||||
if ${{ inputs.mongo }}; then
|
||||
echo -e "${Y}Starting mongo container..." &&
|
||||
docker run -d -p 27004:27017 metabase/qa-databases:mongo-sample-4.4 &&
|
||||
while ! nc -z localhost 27004; do sleep 1; done &&
|
||||
echo -e "${G}Mongo is up and running!"
|
||||
fi
|
||||
shell: bash
|
||||
31
.github/actions/prepare-cypress/action.yml
vendored
31
.github/actions/prepare-cypress/action.yml
vendored
@@ -1,38 +1,7 @@
|
||||
name: Prepare cypress environment
|
||||
description: Cypress preparation steps
|
||||
inputs:
|
||||
is-replay-browser:
|
||||
description: Are we running E2E tests using Replay.io browser?
|
||||
required: false
|
||||
outputs:
|
||||
chrome-path:
|
||||
description: Custom Chrome install path
|
||||
value: ${{ steps.setup-chrome.outputs.chrome-path }}
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
# Browsers
|
||||
- name: Install Chrome v111
|
||||
if: ${{ inputs.is-replay-browser != 'true' }}
|
||||
uses: browser-actions/setup-chrome@v1
|
||||
with:
|
||||
# https://chromium.cypress.io/linux/stable/111.0.5563.146
|
||||
chrome-version: 1097615
|
||||
id: setup-chrome
|
||||
- name: Chrome install feedback
|
||||
if: ${{ inputs.is-replay-browser != 'true' }}
|
||||
run: |
|
||||
echo Installed chromium version: ${{ steps.setup-chrome.outputs.chrome-version }}
|
||||
${{ steps.setup-chrome.outputs.chrome-path }} --version
|
||||
shell: bash
|
||||
|
||||
- name: Install Replay.io browser
|
||||
if: ${{ inputs.is-replay-browser == 'true' }}
|
||||
run: npx @replayio/cypress install
|
||||
shell: bash
|
||||
|
||||
# Cypress-specific
|
||||
- name: Check to see if dependencies should be cached
|
||||
if: ${{ contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
run: echo "Commit message includes [ci nocache]; dependencies will NOT be cached"
|
||||
|
||||
5
.github/actions/prepare-frontend/action.yml
vendored
5
.github/actions/prepare-frontend/action.yml
vendored
@@ -5,7 +5,10 @@ runs:
|
||||
- name: Prepare Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version-file: '.nvmrc'
|
||||
# Please don't bump this version to anything higher.
|
||||
# See https://github.com/facebook/jest/issues/11956 for more details,
|
||||
# as a lot of people couldn't complete a jest run with any other versions.
|
||||
node-version: 16.10.0
|
||||
cache: 'yarn'
|
||||
- name: Check to see if dependencies should be cached
|
||||
if: ${{ contains(github.event.head_commit.message, '[ci nocache]') }}
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
name: Prepare Uberjar Artifact
|
||||
description: Prepare and upload Metabase JAR as a GitHub artifact.
|
||||
|
||||
inputs:
|
||||
name:
|
||||
required: true
|
||||
description: Artifact name
|
||||
|
||||
runs:
|
||||
using: "composite"
|
||||
steps:
|
||||
@@ -18,7 +11,7 @@ runs:
|
||||
- name: Upload JARs as artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: ${{ inputs.name }}
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
path: |
|
||||
./target/uberjar/metabase.jar
|
||||
./COMMIT-ID
|
||||
|
||||
24
.github/file-paths.yaml
vendored
24
.github/file-paths.yaml
vendored
@@ -3,7 +3,7 @@ default: &default
|
||||
- "bin/**"
|
||||
|
||||
ci: &ci
|
||||
- ".github/**/!(*.md|team.json)"
|
||||
- ".github/**/!(*.md)"
|
||||
|
||||
shared_sources: &shared_sources
|
||||
- "shared/src/**"
|
||||
@@ -12,11 +12,6 @@ shared_sources: &shared_sources
|
||||
shared_specs: &shared_specs
|
||||
- "shared/test/**"
|
||||
|
||||
frontend_ci: &frontend_ci
|
||||
- ".github/actions/prepare-frontend/**"
|
||||
- ".github/actions/prepare-backend/**"
|
||||
- ".github/workflows/frontend.yml"
|
||||
|
||||
frontend_sources: &frontend_sources
|
||||
- *shared_sources
|
||||
- "enterprise/frontend/!(test)**/**/{!(*.spec),}.{js,jsx,ts,tsx,css}"
|
||||
@@ -32,23 +27,15 @@ frontend_sources: &frontend_sources
|
||||
frontend_specs: &frontend_specs
|
||||
- *shared_specs
|
||||
- "frontend/test/**"
|
||||
- "frontend/**/tests/**"
|
||||
- "frontend/**/*.unit.*"
|
||||
- "jest.config.json"
|
||||
- "jest.unit.conf.json"
|
||||
- "jest.tz.unit.conf.json"
|
||||
|
||||
frontend_all: &frontend_all
|
||||
- *frontend_ci
|
||||
- *ci
|
||||
- *frontend_sources
|
||||
- *frontend_specs
|
||||
|
||||
backend_ci: &backend_ci
|
||||
- ".github/actions/prepare-frontend/**"
|
||||
- ".github/actions/prepare-backend/**"
|
||||
- ".github/actions/test-driver/**"
|
||||
- ".github/workflows/backend.yml"
|
||||
- ".github/workflows/drivers.yml"
|
||||
|
||||
backend_presto_kerberos:
|
||||
- "**/presto_jdbc/**"
|
||||
- "**/presto_jdbc.clj"
|
||||
@@ -73,9 +60,10 @@ backend_specs: &backend_specs
|
||||
|
||||
backend_all: &backend_all
|
||||
- *default
|
||||
- *backend_ci
|
||||
- *ci
|
||||
- *backend_sources
|
||||
- *backend_specs
|
||||
- *frontend_sources # keep it here until we detect static viz changes
|
||||
|
||||
sources: &sources
|
||||
- *shared_sources
|
||||
@@ -91,8 +79,8 @@ e2e_specs: &e2e_specs
|
||||
e2e_all:
|
||||
- *default
|
||||
- *ci
|
||||
- *sources
|
||||
- *e2e_specs
|
||||
- *sources
|
||||
|
||||
snowplow:
|
||||
- *ci
|
||||
|
||||
56
.github/team.json
vendored
56
.github/team.json
vendored
@@ -1,68 +1,46 @@
|
||||
{
|
||||
"teams": [
|
||||
{
|
||||
"name": "Query",
|
||||
"label": ".Team/Query",
|
||||
"name": "Team 42",
|
||||
"label": ".Team/42 :milky_way:",
|
||||
"members": [
|
||||
"ranquild",
|
||||
"WiNloSt",
|
||||
"deniskaber",
|
||||
"oisincoveney",
|
||||
"uladzimirdev",
|
||||
"tsmacdonald",
|
||||
"qnkhuat",
|
||||
"calherries",
|
||||
"kamilmielnik"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Embedding",
|
||||
"label": ".Team/Embedding",
|
||||
"members": [
|
||||
"WiNloSt",
|
||||
"deniskaber",
|
||||
"oisincoveney",
|
||||
"npretto"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "BEC",
|
||||
"label": ".Team/BackendComponents",
|
||||
"members": [
|
||||
"tsmacdonald",
|
||||
"qnkhuat",
|
||||
"calherries",
|
||||
"piranha"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Query Processor",
|
||||
"label": ".Team/QueryProcessor",
|
||||
"label": ".Team/QueryProcessor :hammer_and_wrench:",
|
||||
"members": [
|
||||
"camsaul",
|
||||
"kulyk",
|
||||
"snoe",
|
||||
"bshepherdson",
|
||||
"metamben",
|
||||
"lbrdnk"
|
||||
"john-metabase",
|
||||
"metamben"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Admin Webapp",
|
||||
"label": ".Team/AdminWebapp",
|
||||
"name": "Pixel Police",
|
||||
"label": ".Team/PixelPolice :police_officer:",
|
||||
"members": [
|
||||
"noahmoss",
|
||||
"escherize",
|
||||
"adam-james-v",
|
||||
"qwef",
|
||||
"alxnddr",
|
||||
"iethree",
|
||||
"npfitz",
|
||||
"shaunlebron",
|
||||
"johnswanson"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "DashViz",
|
||||
"label": ".Team/DashViz",
|
||||
"members": [
|
||||
"alxnddr",
|
||||
"EmmadUsmani",
|
||||
"JesseSDevaney",
|
||||
"kulyk",
|
||||
"markbastian",
|
||||
"adam-james-v"
|
||||
"shaunlebron"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
4
.github/workflows/auto-assign.yml
vendored
4
.github/workflows/auto-assign.yml
vendored
@@ -29,10 +29,6 @@ jobs:
|
||||
const prAuthor = context.payload.pull_request.user.login;
|
||||
const prNumber = context.payload.pull_request.number;
|
||||
|
||||
if (prAuthor.endsWith('[bot]')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Assign PR author
|
||||
await github.rest.issues.addAssignees({
|
||||
owner: context.repo.owner,
|
||||
|
||||
6
.github/workflows/auto-backport.yml
vendored
6
.github/workflows/auto-backport.yml
vendored
@@ -54,11 +54,13 @@ jobs:
|
||||
git checkout master
|
||||
git push -u origin ${BACKPORT_BRANCH}
|
||||
|
||||
BACKPORT_PR_URL=$(gh pr create --base "${TARGET_BRANCH}" --head "${BACKPORT_BRANCH}" --label "was-backported" --assignee "${GITHUB_ACTOR}" --title "🤖 backported \"${ORIGINAL_TITLE}\"" --body "#${ORIGINAL_PULL_REQUEST_NUMBER}")
|
||||
BACKPORT_PR_URL=$(hub pull-request -b "${TARGET_BRANCH}" -h "${BACKPORT_BRANCH}" -l "was-backported" -a "${GITHUB_ACTOR}" -F- <<<"🤖 backported \"${ORIGINAL_TITLE}\"
|
||||
|
||||
#${ORIGINAL_PULL_REQUEST_NUMBER}")
|
||||
|
||||
BACKPORT_PR_NUMBER=${BACKPORT_PR_URL##*/}
|
||||
|
||||
echo "backport_pr_number=$BACKPORT_PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
echo "New PR has been created"
|
||||
env:
|
||||
TARGET_BRANCH: ${{ steps.get_latest_release_branch.outputs.branch-name }}
|
||||
ORIGINAL_PULL_REQUEST_NUMBER: ${{ github.event.pull_request.number }}
|
||||
|
||||
339
.github/workflows/backend.yml
vendored
339
.github/workflows/backend.yml
vendored
@@ -3,8 +3,8 @@ name: Backend
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "release-**"
|
||||
- 'master'
|
||||
- 'release-**'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
@@ -13,13 +13,13 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
CLJ_KONDO_VERSION: "2023.09.07"
|
||||
CLJ_KONDO_VERSION: "2023.04.14"
|
||||
|
||||
jobs:
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
timeout-minutes: 3
|
||||
outputs:
|
||||
backend_all: ${{ steps.changes.outputs.backend_all }}
|
||||
steps:
|
||||
@@ -31,233 +31,181 @@ jobs:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
static-viz-files-changed:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.backend_all != 'true'
|
||||
name: Check whether static-viz files changed
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
outputs:
|
||||
static_viz: ${{ steps.static_viz.outputs.static_viz }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "files-changed"
|
||||
- name: Build static-viz frontend
|
||||
run: yarn build-static-viz
|
||||
- name: Upload Static Viz Bundle Artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: static-viz-bundle-${{ github.sha }}
|
||||
path: resources/frontend_client/app/dist
|
||||
|
||||
- name: Check for static viz changes
|
||||
uses: dorny/paths-filter@v2.11.1
|
||||
id: static_viz
|
||||
with:
|
||||
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'
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- 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@v3
|
||||
with:
|
||||
files: ./target/coverage/codecov.json
|
||||
flags: back-end
|
||||
- uses: actions/checkout@v3
|
||||
- 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@v3
|
||||
with:
|
||||
files: ./target/coverage/codecov.json
|
||||
flags: back-end
|
||||
|
||||
be-linter-clj-kondo:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
env:
|
||||
DOWNLOAD_URL: https://github.com/clj-kondo/clj-kondo/releases/download
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install clj-kondo
|
||||
run: |
|
||||
curl -OL ${DOWNLOAD_URL}/v${CLJ_KONDO_VERSION}/clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip
|
||||
curl -OL ${DOWNLOAD_URL}/v${CLJ_KONDO_VERSION}/clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip.sha256
|
||||
cat clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip.sha256 >> SHA256sum.txt
|
||||
echo " clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip" >> SHA256sum.txt
|
||||
sha256sum -c SHA256sum.txt
|
||||
unzip clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip
|
||||
- run: ./clj-kondo --version
|
||||
- name: Run clj-kondo
|
||||
run: >-
|
||||
./clj-kondo
|
||||
--config ./.clj-kondo/config.edn
|
||||
--config-dir ./.clj-kondo
|
||||
--parallel
|
||||
--lint
|
||||
./src
|
||||
./test
|
||||
./enterprise/backend/src
|
||||
./enterprise/backend/test
|
||||
./shared/src
|
||||
./shared/test
|
||||
./modules/drivers/athena/src
|
||||
./modules/drivers/athena/test
|
||||
./modules/drivers/bigquery-cloud-sdk/src
|
||||
./modules/drivers/bigquery-cloud-sdk/test
|
||||
./modules/drivers/druid/src
|
||||
./modules/drivers/druid/test
|
||||
./modules/drivers/googleanalytics/src
|
||||
./modules/drivers/googleanalytics/test
|
||||
./modules/drivers/mongo/src
|
||||
./modules/drivers/mongo/test
|
||||
./modules/drivers/oracle/src
|
||||
./modules/drivers/oracle/test
|
||||
./modules/drivers/presto-jdbc/src
|
||||
./modules/drivers/presto-jdbc/test
|
||||
./modules/drivers/redshift/src
|
||||
./modules/drivers/redshift/test
|
||||
./modules/drivers/snowflake/src
|
||||
./modules/drivers/snowflake/test
|
||||
./modules/drivers/sparksql/src
|
||||
./modules/drivers/sparksql/test
|
||||
./modules/drivers/sqlite/src
|
||||
./modules/drivers/sqlite/test
|
||||
./modules/drivers/sqlserver/src
|
||||
./modules/drivers/sqlserver/test
|
||||
./modules/drivers/vertica/src
|
||||
./modules/drivers/vertica/test
|
||||
- uses: actions/checkout@v3
|
||||
- name: Install clj-kondo
|
||||
run: |
|
||||
curl -OL ${DOWNLOAD_URL}/v${CLJ_KONDO_VERSION}/clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip
|
||||
curl -OL ${DOWNLOAD_URL}/v${CLJ_KONDO_VERSION}/clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip.sha256
|
||||
cat clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip.sha256 >> SHA256sum.txt
|
||||
echo " clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip" >> SHA256sum.txt
|
||||
sha256sum -c SHA256sum.txt
|
||||
unzip clj-kondo-${CLJ_KONDO_VERSION}-linux-static-amd64.zip
|
||||
- run: ./clj-kondo --version
|
||||
- name: Run clj-kondo
|
||||
run: >-
|
||||
./clj-kondo
|
||||
--config ./.clj-kondo/config.edn
|
||||
--config-dir ./.clj-kondo
|
||||
--parallel
|
||||
--lint
|
||||
./src
|
||||
./test
|
||||
./enterprise/backend/src
|
||||
./enterprise/backend/test
|
||||
./shared/src
|
||||
./shared/test
|
||||
./modules/drivers/athena/src
|
||||
./modules/drivers/athena/test
|
||||
./modules/drivers/bigquery-cloud-sdk/src
|
||||
./modules/drivers/bigquery-cloud-sdk/test
|
||||
./modules/drivers/druid/src
|
||||
./modules/drivers/druid/test
|
||||
./modules/drivers/googleanalytics/src
|
||||
./modules/drivers/googleanalytics/test
|
||||
./modules/drivers/mongo/src
|
||||
./modules/drivers/mongo/test
|
||||
./modules/drivers/oracle/src
|
||||
./modules/drivers/oracle/test
|
||||
./modules/drivers/presto-jdbc/src
|
||||
./modules/drivers/presto-jdbc/test
|
||||
./modules/drivers/redshift/src
|
||||
./modules/drivers/redshift/test
|
||||
./modules/drivers/snowflake/src
|
||||
./modules/drivers/snowflake/test
|
||||
./modules/drivers/sparksql/src
|
||||
./modules/drivers/sparksql/test
|
||||
./modules/drivers/sqlite/src
|
||||
./modules/drivers/sqlite/test
|
||||
./modules/drivers/sqlserver/src
|
||||
./modules/drivers/sqlserver/test
|
||||
./modules/drivers/vertica/src
|
||||
./modules/drivers/vertica/test
|
||||
|
||||
|
||||
|
||||
be-linter-eastwood:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "eastwood"
|
||||
- run: clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:eastwood
|
||||
name: Run Eastwood linter
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'eastwood'
|
||||
- run: clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:eastwood
|
||||
name: Run Eastwood linter
|
||||
|
||||
# Because it's not possible to conditionally run only `java-11-ee` test in the draft mode,
|
||||
# we have to extract that job manually here. Backend developers have requested that this
|
||||
# test runs at all times to give them an early warning sign is something is broken.
|
||||
be-tests-java-11-ee-pre-check:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == true &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == true && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-tests-java-11-ee-pre-check
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 35
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: java-11-ee-pre-check
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: java-11-ee-pre-check
|
||||
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
|
||||
- name: Run tests
|
||||
run: clojure -X:dev:ci:test:ee:ee-dev
|
||||
- name: Run tests
|
||||
run: clojure -X:dev:ci:test:ee:ee-dev
|
||||
|
||||
- name: Publish Test Report (JUnit)
|
||||
uses: dorny/test-reporter@v1
|
||||
if: failure()
|
||||
with:
|
||||
path: "target/junit/**/*_test.xml"
|
||||
name: JUnit Test Report be-tests-java-11-ee-pre-check
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
list-tests: failed
|
||||
fail-on-error: false
|
||||
- name: Publish Test Report (JUnit)
|
||||
uses: dorny/test-reporter@v1
|
||||
if: failure()
|
||||
with:
|
||||
path: 'target/junit/**/*_test.xml'
|
||||
name: JUnit Test Report be-tests-java-11-ee-pre-check
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
list-tests: failed
|
||||
fail-on-error: false
|
||||
|
||||
be-tests:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 35
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [11, 17]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: be-tests
|
||||
# Depending on which files changed, we might either have to build static-viz
|
||||
# from scratch or download the previously built artifact
|
||||
- name: Build static-viz frontend
|
||||
if: needs.files-changed.outputs.backend_all == 'true'
|
||||
run: yarn build-static-viz
|
||||
- name: Download Static Viz Bundle Artifact
|
||||
if: needs.static-viz-files-changed.outputs.static_viz == 'true'
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: static-viz-bundle-${{ github.sha }}
|
||||
path: resources/frontend_client/app/dist
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: be-tests
|
||||
|
||||
- name: Run tests
|
||||
if: matrix.java-version != 21
|
||||
run: clojure -X:dev:ci:test:${{ matrix.edition }}:${{ matrix.edition }}-dev
|
||||
- run: yarn install --frozen-lockfile --prefer-offline
|
||||
- name: Build static viz frontend
|
||||
run: yarn build-static-viz
|
||||
|
||||
- name: Run tests using Java 21 on `master` only
|
||||
if: matrix.java-version == 21 && github.ref_name == 'master'
|
||||
run: clojure -X:dev:ci:test:${{ matrix.edition }}:${{ matrix.edition }}-dev
|
||||
- name: Run tests
|
||||
run: clojure -X:dev:ci:test:${{ matrix.edition }}:${{ matrix.edition }}-dev
|
||||
|
||||
- name: Publish Test Report (JUnit)
|
||||
uses: dorny/test-reporter@v1
|
||||
if: failure()
|
||||
with:
|
||||
path: "target/junit/**/*_test.xml"
|
||||
name: JUnit Test Report be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
list-tests: failed
|
||||
fail-on-error: false
|
||||
- name: Publish Test Report (JUnit)
|
||||
uses: dorny/test-reporter@v1
|
||||
if: failure()
|
||||
with:
|
||||
path: 'target/junit/**/*_test.xml'
|
||||
name: JUnit Test Report be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
reporter: java-junit
|
||||
list-suites: failed
|
||||
list-tests: failed
|
||||
fail-on-error: false
|
||||
|
||||
be-tests-stub:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
needs: files-changed
|
||||
if: |
|
||||
always() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'false' && needs.static-viz-files-changed.outputs.static_viz == 'false')
|
||||
needs.files-changed.outputs.backend_all == 'false'
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-tests-java-${{ matrix.java-version }}-${{ matrix.edition }}
|
||||
timeout-minutes: 5
|
||||
@@ -265,7 +213,7 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [11, 17]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Didn't run due to conditional filtering"
|
||||
@@ -273,17 +221,14 @@ jobs:
|
||||
# checks that all the namespaces we actually ship can be compiled, without any dependencies that we don't ship (such
|
||||
# as `:dev` dependencies). See #27009 for more context.
|
||||
be-check:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'true' || needs.static-viz-files-changed.outputs.static_viz == 'true')
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-check-java-${{ matrix.java-version }}
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [11, 17, 19]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare backend
|
||||
@@ -294,17 +239,17 @@ jobs:
|
||||
run: clojure -M:ee:drivers:check
|
||||
|
||||
be-check-stub:
|
||||
needs: [files-changed, static-viz-files-changed]
|
||||
needs: files-changed
|
||||
if: |
|
||||
always() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
(needs.files-changed.outputs.backend_all == 'false' && needs.static-viz-files-changed.outputs.static_viz == 'false')
|
||||
needs.files-changed.outputs.backend_all == 'false'
|
||||
runs-on: ubuntu-22.04
|
||||
name: be-check-java-${{ matrix.java-version }}
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
java-version: [11, 17, 21]
|
||||
java-version: [11, 17, 19]
|
||||
steps:
|
||||
- run: |
|
||||
echo "Didn't run due to conditional filtering"
|
||||
|
||||
18
.github/workflows/backport-reminder.yml
vendored
18
.github/workflows/backport-reminder.yml
vendored
@@ -1,18 +0,0 @@
|
||||
name: Backport Reminder
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [auto_merge_enabled, review_requested, labeled, unlabeled, synchronize]
|
||||
branches:
|
||||
- "master"
|
||||
|
||||
jobs:
|
||||
backport-reminder:
|
||||
name: Decide whether to backport or not
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: jesusvasquez333/verify-pr-label-action@v1.4.0
|
||||
with:
|
||||
github-token: '${{ secrets.GITHUB_TOKEN }}'
|
||||
valid-labels: 'backport, no-backport'
|
||||
disable-reviews: true
|
||||
7
.github/workflows/backport.yml
vendored
7
.github/workflows/backport.yml
vendored
@@ -108,10 +108,13 @@ jobs:
|
||||
|
||||
git push origin "${BACKPORT_BRANCH}" --force-with-lease
|
||||
|
||||
if [[ $(gh pr list --base "${TARGET_BRANCH}" --head "${BACKPORT_BRANCH}" -s "open") ]]; then
|
||||
if [[ $(hub pr list -b "${TARGET_BRANCH}" -h "${BACKPORT_BRANCH}" -s "open") ]]; then
|
||||
echo "PR already exists"
|
||||
else
|
||||
BACKPORT_PR_URL=$(gh pr create --base "${TARGET_BRANCH}" --head "${BACKPORT_BRANCH}" --label "was-backported" --assignee "${GITHUB_ACTOR}" --title "🤖 backported \"${ORIGINAL_TITLE}\"" --body "#${ORIGINAL_PULL_REQUEST_NUMBER}")
|
||||
BACKPORT_PR_URL=$(hub pull-request -b "${TARGET_BRANCH}" -h "${BACKPORT_BRANCH}" -l "was-backported" -a "${GITHUB_ACTOR}" -F- <<<"🤖 backported \"${ORIGINAL_TITLE}\"
|
||||
|
||||
#${ORIGINAL_PULL_REQUEST_NUMBER}")
|
||||
|
||||
BACKPORT_PR_NUMBER=${BACKPORT_PR_URL##*/}
|
||||
|
||||
echo "backport_pr_number=$BACKPORT_PR_NUMBER" >> $GITHUB_OUTPUT
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
name: Bugs Slack Notification
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
- opened
|
||||
jobs:
|
||||
on-issue-opened:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
if: |
|
||||
contains(github.event.issue.labels.*.name, '.Needs Triage') &&
|
||||
contains(github.event.issue.labels.*.name, 'Type:Bug')
|
||||
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: Check for labels containing team name
|
||||
id: check_labels
|
||||
run: |
|
||||
labels_json=$(sed 's/&/\$/g' <<< '${{ toJson(github.event.issue.labels) }}')
|
||||
echo "has_team_label=false" >> "$GITHUB_OUTPUT"
|
||||
for label in "$labels_json"
|
||||
do
|
||||
if [[ $label == *".Team"* ]]; then
|
||||
echo "Label contains the team name."
|
||||
echo "has_team_label=true" >> "$GITHUB_OUTPUT"
|
||||
break
|
||||
fi
|
||||
done
|
||||
- name: Send the issue ${{ github.event.issue.number }} to Slack
|
||||
id: slack
|
||||
if: steps.check_labels.outputs.has_team_label == 'false'
|
||||
uses: slackapi/slack-github-action@v1.23.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_BUG_TRIAGE_WEBHOOK_URL }}
|
||||
SLACK_WEBHOOK_TYPE: INCOMING_WEBHOOK
|
||||
194
.github/workflows/build-for-release.yml
vendored
194
.github/workflows/build-for-release.yml
vendored
@@ -1,194 +0,0 @@
|
||||
name: Release 1 - Build Release Artifact
|
||||
run-name: Build ${{ 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-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@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Get Release Version
|
||||
uses: actions/github-script@v6
|
||||
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@v3
|
||||
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@v6
|
||||
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)
|
||||
|
||||
get-build-requirements:
|
||||
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 }}
|
||||
build_process: ${{ fromJson(steps.dependencies.outputs.result).build_process }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Get build dependencies
|
||||
uses: actions/github-script@v6
|
||||
id: dependencies
|
||||
with:
|
||||
script: | # js
|
||||
const { getBuildRequirements, getMajorVersion } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const version = '${{ inputs.version }}';
|
||||
|
||||
const requirements = getBuildRequirements(version);
|
||||
const build_process = getMajorVersion(version) < 46 ? 'legacy' : 'new';
|
||||
console.log('Build process:', build_process);
|
||||
|
||||
return {
|
||||
java_version: requirements.java,
|
||||
node_version: requirements.node,
|
||||
build_process,
|
||||
};
|
||||
|
||||
build-uberjar-for-release:
|
||||
needs: [check-version, check-commit, get-build-requirements]
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 50
|
||||
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 ${{ needs.get-build-requirements.outputs.java_version }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
distribution: 'temurin'
|
||||
java-version: ${{ needs.get-build-requirements.outputs.java_version }}
|
||||
- name: Setup Node.js ${{ needs.get-build-requirements.outputs.node_version }}
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ needs.get-build-requirements.outputs.node_version }}.x
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit }}
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
|
||||
- name: Build Metabase
|
||||
if: ${{ needs.get-build-requirements.outputs.build_process != 'legacy' }}
|
||||
run: ./bin/build.sh :edition :${{ matrix.edition }} :version $VERSION
|
||||
|
||||
- name: Build Metabase (legacy)
|
||||
if: ${{ needs.get-build-requirements.outputs.build_process == 'legacy' }}
|
||||
run: cd ./bin/build-mb && clojure -X build/build! :edition :${{ matrix.edition }} :version $VERSION
|
||||
|
||||
- name: Store commit's SHA-1 hash
|
||||
run: echo ${{ inputs.commit }} > COMMIT-ID
|
||||
shell: bash
|
||||
- run: mv ./target/uberjar/metabase.jar ./metabase.jar
|
||||
- name: Calculate SHA256 checksum
|
||||
run: sha256sum ./metabase.jar > SHA256.sum
|
||||
shell: bash
|
||||
- name: Upload JARs as artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ inputs.commit }}-uberjar
|
||||
path: |
|
||||
./metabase.jar
|
||||
./COMMIT-ID
|
||||
./SHA256.sum
|
||||
54
.github/workflows/chromatic.yml
vendored
54
.github/workflows/chromatic.yml
vendored
@@ -1,54 +0,0 @@
|
||||
name: Chromatic Storybook deployment
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
pull_request:
|
||||
types: [synchronize, labeled, unlabeled]
|
||||
|
||||
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:
|
||||
frontend_all: ${{ steps.changes.outputs.frontend_all }}
|
||||
e2e_specs: ${{ steps.changes.outputs.e2e_specs }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test which files changed
|
||||
uses: dorny/paths-filter@v2.11.1
|
||||
id: changes
|
||||
with:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
fe-chromatic:
|
||||
needs: files-changed
|
||||
if: contains(github.event.pull_request.labels.*.name, 'chromatic') || (github.ref_name == 'master' && needs.files-changed.outputs.frontend_all == 'true')
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Publish to Chromatic
|
||||
uses: chromaui/action@v1
|
||||
env:
|
||||
PUBLISH_CHROMATIC: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
STORYBOOK_BUILD_TIMEOUT: 900000
|
||||
if: env.PUBLISH_CHROMATIC != null
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
1
.github/workflows/codeql.yml
vendored
1
.github/workflows/codeql.yml
vendored
@@ -24,7 +24,6 @@ jobs:
|
||||
filters: .github/file-paths.yaml
|
||||
analyze:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.codeql == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
|
||||
226
.github/workflows/drivers.yml
vendored
226
.github/workflows/drivers.yml
vendored
@@ -7,9 +7,6 @@ on:
|
||||
- 'release-**'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
workflow_run:
|
||||
workflows: [External Trigger Filter]
|
||||
types: [completed]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.head_ref && github.ref || github.run_id }}
|
||||
@@ -33,11 +30,9 @@ jobs:
|
||||
|
||||
be-tests-athena-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: athena
|
||||
@@ -55,11 +50,9 @@ jobs:
|
||||
|
||||
be-tests-bigquery-cloud-sdk-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: bigquery-cloud-sdk
|
||||
@@ -79,11 +72,9 @@ jobs:
|
||||
|
||||
be-tests-druid-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: druid
|
||||
@@ -104,11 +95,9 @@ jobs:
|
||||
|
||||
be-tests-googleanalytics-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: googleanalytics
|
||||
@@ -122,11 +111,9 @@ jobs:
|
||||
|
||||
be-google-related-drivers-classpath-test:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: 'googleanalytics,bigquery-cloud-sdk'
|
||||
@@ -146,11 +133,9 @@ jobs:
|
||||
|
||||
be-tests-mariadb-10-2-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mysql
|
||||
@@ -174,11 +159,9 @@ jobs:
|
||||
|
||||
be-tests-mariadb-latest-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mysql
|
||||
@@ -200,13 +183,11 @@ jobs:
|
||||
with:
|
||||
junit-name: 'be-tests-mariadb-latest-ee'
|
||||
|
||||
be-tests-mongo-4-4-ee:
|
||||
be-tests-mongo-4-2-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mongo
|
||||
@@ -214,24 +195,22 @@ jobs:
|
||||
MB_MONGO_TEST_PASSWORD: metasample123
|
||||
services:
|
||||
mongodb:
|
||||
image: metabase/qa-databases:mongo-sample-4.4
|
||||
image: metabase/qa-databases:mongo-sample-4.2
|
||||
ports:
|
||||
- "27017:27017"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test MongoDB driver (4.4)
|
||||
- name: Test MongoDB driver (4.2)
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-mongo-4-4-ee'
|
||||
junit-name: 'be-tests-mongo-4-2-ee'
|
||||
test-args: ":exclude-tags '[:mb/once]'"
|
||||
|
||||
be-tests-mongo-4-4-ssl-ee:
|
||||
be-tests-mongo-4-2-ssl-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mongo
|
||||
@@ -241,7 +220,7 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Spin up Mongo docker container
|
||||
run: docker run -d -p 27017:27017 --name metamongo metabase/qa-databases:mongo-sample-4.4 mongod --dbpath /data/db2/ --tlsMode requireTLS --tlsCertificateKeyFile /etc/mongo/metamongo.pem --tlsCAFile /etc/mongo/metaca.crt
|
||||
run: docker run -d -p 27017:27017 --name metamongo metabase/qa-databases:mongo-sample-4.2 mongod --dbpath /data/db2/ --tlsMode requireTLS --tlsCertificateKeyFile /etc/mongo/metamongo.pem --tlsCAFile /etc/mongo/metaca.crt
|
||||
- name: Wait until the port 27017 is ready
|
||||
run: while ! nc -z localhost 27017; do sleep 1; done
|
||||
timeout-minutes: 5
|
||||
@@ -256,19 +235,17 @@ jobs:
|
||||
curl https://raw.githubusercontent.com/metabase/metabase-qa/master/dbs/mongo/certificates/metaca.crt \
|
||||
-o ./test_resources/ssl/mongo/metaca.crt
|
||||
|
||||
- name: Test MongoDB SSL driver (4.4)
|
||||
- name: Test MongoDB SSL driver (4.2)
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-mongo-4-4-ee'
|
||||
junit-name: 'be-tests-mongo-4-2-ee'
|
||||
test-args: ":exclude-tags '[:mb/once]'"
|
||||
|
||||
be-tests-mongo-5-0-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mongo
|
||||
@@ -289,11 +266,9 @@ jobs:
|
||||
|
||||
be-tests-mongo-5-0-ssl-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mongo
|
||||
@@ -326,11 +301,9 @@ jobs:
|
||||
|
||||
be-tests-mongo-latest-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mongo
|
||||
@@ -352,13 +325,11 @@ jobs:
|
||||
junit-name: 'be-tests-mongo-latest-ee'
|
||||
test-args: ":exclude-tags '[:mb/once]'"
|
||||
|
||||
be-tests-mysql-8-0-ee:
|
||||
be-tests-mysql-5-7-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mysql
|
||||
@@ -370,23 +341,21 @@ jobs:
|
||||
MB_MYSQL_TEST_USER: root
|
||||
services:
|
||||
mysql:
|
||||
image: cimg/mysql:8.0
|
||||
image: circleci/mysql:5.7.23
|
||||
ports:
|
||||
- "3306:3306"
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test MySQL driver (8.0)
|
||||
- name: Test MySQL driver (5.7)
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-mysql-8-0-ee'
|
||||
junit-name: 'be-tests-mysql-5-7-ee'
|
||||
|
||||
be-tests-mysql-latest-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: mysql
|
||||
@@ -422,11 +391,9 @@ jobs:
|
||||
|
||||
be-tests-oracle-18-4-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: oracle
|
||||
@@ -451,11 +418,9 @@ jobs:
|
||||
|
||||
be-tests-oracle-21-3-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: oracle
|
||||
@@ -489,43 +454,38 @@ jobs:
|
||||
|
||||
be-tests-postgres-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: postgres
|
||||
MB_DB_TYPE: postgres
|
||||
MB_DB_PORT: 5432
|
||||
MB_DB_HOST: localhost
|
||||
MB_DB_DBNAME: mb_test
|
||||
MB_DB_USER: mb_test
|
||||
MB_POSTGRESQL_TEST_USER: mb_test
|
||||
MB_DB_DBNAME: circle_test
|
||||
MB_DB_USER: circle_test
|
||||
MB_POSTGRESQL_TEST_USER: circle_test
|
||||
services:
|
||||
postgres:
|
||||
image: postgres:12-alpine
|
||||
image: circleci/postgres:9.6-alpine
|
||||
ports:
|
||||
- "5432:5432"
|
||||
env:
|
||||
POSTGRES_USER: mb_test
|
||||
POSTGRES_DB: mb_test
|
||||
POSTGRES_HOST_AUTH_METHOD: trust
|
||||
POSTGRES_USER: circle_test
|
||||
POSTGRES_DB: circle_test
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test Postgres driver (12)
|
||||
- name: Test Postgres driver (9.6)
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-postgres-ee'
|
||||
|
||||
be-tests-postgres-latest-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: postgres
|
||||
@@ -556,11 +516,9 @@ jobs:
|
||||
|
||||
be-tests-presto-jdbc-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: presto-jdbc
|
||||
@@ -608,11 +566,9 @@ jobs:
|
||||
|
||||
be-tests-redshift-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: redshift
|
||||
@@ -630,11 +586,9 @@ jobs:
|
||||
|
||||
be-tests-snowflake-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: snowflake
|
||||
@@ -654,11 +608,9 @@ jobs:
|
||||
|
||||
be-tests-sparksql-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: sparksql
|
||||
@@ -677,11 +629,9 @@ jobs:
|
||||
|
||||
be-tests-sqlite-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: sqlite
|
||||
@@ -693,13 +643,11 @@ jobs:
|
||||
junit-name: 'be-tests-sqlite-ee'
|
||||
test-args: ":exclude-tags '[:mb/once]'"
|
||||
|
||||
be-tests-sqlserver-2017-ee:
|
||||
be-tests-sqlserver-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: sqlserver
|
||||
@@ -717,49 +665,17 @@ jobs:
|
||||
MSSQL_MEMORY_LIMIT_MB: 1024
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test MS SQL Server 2017 driver
|
||||
- name: Test MS SQL Server driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-sqlserver-ee'
|
||||
test-args: ":exclude-tags '[:mb/once]'"
|
||||
|
||||
be-tests-sqlserver-2022-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: sqlserver
|
||||
MB_SQLSERVER_TEST_HOST: localhost
|
||||
MB_SQLSERVER_TEST_PASSWORD: 'P@ssw0rd'
|
||||
MB_SQLSERVER_TEST_USER: SA
|
||||
services:
|
||||
sqlserver:
|
||||
image: mcr.microsoft.com/mssql/server:2022-latest
|
||||
ports:
|
||||
- "1433:1433"
|
||||
env:
|
||||
ACCEPT_EULA: Y
|
||||
SA_PASSWORD: 'P@ssw0rd'
|
||||
MSSQL_MEMORY_LIMIT_MB: 1024
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Test MS SQL Server 2022 driver
|
||||
uses: ./.github/actions/test-driver
|
||||
with:
|
||||
junit-name: 'be-tests-sqlserver-2022-ee'
|
||||
test-args: ":exclude-tags '[:mb/once]'"
|
||||
|
||||
be-tests-vertica-ee:
|
||||
needs: files-changed
|
||||
if: |
|
||||
(github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true') &&
|
||||
(github.event.pull_request.head.repo.full_name == github.repository || github.event.workflow_run.conclusion == 'success')
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.backend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 90
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
CI: 'true'
|
||||
DRIVERS: vertica
|
||||
|
||||
10
.github/workflows/e2e-cross-version.yml
vendored
10
.github/workflows/e2e-cross-version.yml
vendored
@@ -28,6 +28,10 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- name: Set Metabase Enterprise License
|
||||
run: |
|
||||
echo "MB_PREMIUM_EMBEDDING_TOKEN=${{ secrets.ENTERPRISE_TOKEN }}" >> $GITHUB_ENV
|
||||
if: startsWith(matrix.version.source, 'v1') || startsWith(matrix.version.target, 'v1')
|
||||
- name: Set source Docker image to OSS
|
||||
run: |
|
||||
echo "DOCKER_SOURCE_IMAGE=metabase/metabase:${{ matrix.version.source }}" >> $GITHUB_ENV
|
||||
@@ -43,8 +47,7 @@ jobs:
|
||||
docker run -d \
|
||||
-v $PWD/my-metabase:/metabase.db \
|
||||
-p 3000:3000 \
|
||||
-e CYPRESS_ALL_FEATURES_TOKEN=${{ secrets.ENTERPRISE_TOKEN }} \
|
||||
-e CYPRESS_NO_FEATURES_TOKEN=${{ secrets.E2E_STARTER_TOKEN }} \
|
||||
-e MB_PREMIUM_EMBEDDING_TOKEN \
|
||||
--name metabase-${{ matrix.version.source }} \
|
||||
${{ env.DOCKER_SOURCE_IMAGE }}
|
||||
- name: Wait for Metabase to start on port 3000
|
||||
@@ -73,8 +76,7 @@ jobs:
|
||||
docker run -d \
|
||||
-v $PWD/my-metabase:/metabase.db \
|
||||
-p 3001:3000 \
|
||||
-e CYPRESS_ALL_FEATURES_TOKEN=${{ secrets.ENTERPRISE_TOKEN }} \
|
||||
-e CYPRESS_NO_FEATURES_TOKEN=${{ secrets.E2E_STARTER_TOKEN }} \
|
||||
-e MB_PREMIUM_EMBEDDING_TOKEN \
|
||||
--name metabase-${{ matrix.version.target }} \
|
||||
${{ env.DOCKER_TARGET_IMAGE }}
|
||||
- name: Wait for Metabase to start on port 3001
|
||||
|
||||
101
.github/workflows/e2e-stress-test-flake-fix.yml
vendored
101
.github/workflows/e2e-stress-test-flake-fix.yml
vendored
@@ -3,6 +3,10 @@ name: E2E Stress Test Flake Fix
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
artifact:
|
||||
description: 'Artifact ID'
|
||||
type: string
|
||||
required: true
|
||||
spec:
|
||||
description: 'Relative path of the target spec'
|
||||
type: string
|
||||
@@ -11,48 +15,71 @@ on:
|
||||
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'
|
||||
type: string
|
||||
required: false
|
||||
|
||||
jobs:
|
||||
stress-test-flake-fix:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 20
|
||||
name: Stress test E2E flake fix
|
||||
env:
|
||||
DISPLAY: ""
|
||||
QA_DB_ENABLED: true
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
MB_SNOWPLOW_URL: "http://localhost:9090" # Snowplow micro
|
||||
TERM: xterm
|
||||
TZ: US/Pacific # to make node match the instance tz
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
# Important because we need previous commits hashes to find and download the uberjar!
|
||||
fetch-depth: 20
|
||||
|
||||
- name: Prepare Docker containers
|
||||
uses: ./.github/actions/e2e-prepare-containers
|
||||
with:
|
||||
services:
|
||||
maildev:
|
||||
image: maildev/maildev:2.0.5
|
||||
ports:
|
||||
- "1080:1080"
|
||||
- "1025:1025"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
maildev: true
|
||||
openldap: true
|
||||
postgres: true
|
||||
mysql: true
|
||||
mongo: true
|
||||
|
||||
- name: Download Metabase ${{ matrix.edition }} uberjar
|
||||
uses: ./.github/actions/e2e-download-uberjar
|
||||
with:
|
||||
edition: 'ee'
|
||||
was-built: false
|
||||
|
||||
openldap:
|
||||
image: osixia/openldap:1.5.0
|
||||
ports:
|
||||
- "389:389"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
postgres-sample:
|
||||
image: metabase/qa-databases:postgres-sample-12
|
||||
ports:
|
||||
- "5404:5432"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
mongo-sample:
|
||||
image: metabase/qa-databases:mongo-sample-4.4
|
||||
ports:
|
||||
- 27004:27017
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
mysql-sample:
|
||||
image: metabase/qa-databases:mysql-sample-8
|
||||
ports:
|
||||
- 3304:3306
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Download Metabase uberjar from a previously stored artifact
|
||||
run: |
|
||||
curl -L \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "Authorization: Bearer $GITHUB_TOKEN" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
https://api.github.com/repos/metabase/metabase/actions/artifacts/$ARTIFACT_ID/zip \
|
||||
-o mb.zip
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
ARTIFACT_ID: ${{ github.event.inputs.artifact }}
|
||||
- name: Unzip Metabase artifact containing an uberjar
|
||||
run: unzip mb.zip
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare JDK 11
|
||||
@@ -61,21 +88,21 @@ 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
|
||||
|
||||
# For all options and fine-grained control, take a look at the documentation
|
||||
# https://github.com/cypress-io/cypress/tree/develop/npm/grep
|
||||
- name: Get Metabase version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
- name: Stress-test ${{ github.event.inputs.spec }} ${{ github.event.inputs.burn_in }} times
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--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 }}
|
||||
|
||||
--env burn=${{ github.event.inputs.burn_in }} \
|
||||
--config-file e2e/support/cypress-stress-test.config.js
|
||||
env:
|
||||
TERM: xterm
|
||||
- name: Upload Cypress Artifacts upon failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
|
||||
141
.github/workflows/e2e-tests-replay.yml
vendored
141
.github/workflows/e2e-tests-replay.yml
vendored
@@ -1,141 +0,0 @@
|
||||
name: E2E Tests using Replay.io browser
|
||||
|
||||
on:
|
||||
# We'll record runs using Replay.io and their browser on a schedule as an experiment
|
||||
schedule:
|
||||
- cron: '0 22 * * *'
|
||||
|
||||
jobs:
|
||||
test-run-id:
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
testRunId: ${{ steps.testRunId.outputs.testRunId }}
|
||||
steps:
|
||||
- id: testRunId
|
||||
run: echo testRunId=$(npx uuid) >> "$GITHUB_OUTPUT"
|
||||
|
||||
e2e-matrix-builder:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
matrix: ${{ steps.e2e-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Generate matrix for E2E tests
|
||||
id: e2e-matrix
|
||||
uses: ./.github/actions/build-e2e-matrix
|
||||
|
||||
|
||||
e2e-tests:
|
||||
needs: [test-run-id, e2e-matrix-builder]
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 90
|
||||
name: e2e-tests-${{ matrix.name }}-${{ matrix.edition }}
|
||||
env:
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
DISPLAY: ""
|
||||
QA_DB_ENABLED: true
|
||||
# Any env starting with `CYPRESS_` will be available to all Cypress tests via `Cypress.env()`
|
||||
# Example: you can get `CYPRESS_FOO` with `Cypress.env("FOO")`
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
MB_SNOWPLOW_URL: "http://localhost:9090" # Snowplow micro
|
||||
TZ: US/Pacific # to make node match the instance tz
|
||||
TERM: xterm
|
||||
CYPRESS_REPLAYIO_ENABLED: 1
|
||||
RECORD_REPLAY_METADATA_FILE: /tmp/replay-metadata.json
|
||||
RECORD_REPLAY_METADATA_TEST_RUN_ID: ${{ needs.test-run-id.outputs.testRunId }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(needs.e2e-matrix-builder.outputs.matrix) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
# Important in case we need to download uberjar from previous commits!
|
||||
fetch-depth: 20
|
||||
|
||||
- name: Prepare Docker containers
|
||||
uses: ./.github/actions/e2e-prepare-containers
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
maildev: true
|
||||
openldap: ${{ startsWith(matrix.name, 'admin') }}
|
||||
postgres: ${{ matrix.name != 'mongo'}}
|
||||
mysql: ${{ matrix.name != 'mongo'}}
|
||||
mongo: ${{ matrix.name == 'mongo'}}
|
||||
|
||||
- name: Download Metabase ${{ matrix.edition }} uberjar
|
||||
uses: ./.github/actions/e2e-download-uberjar
|
||||
with:
|
||||
edition: ${{ matrix.edition }}
|
||||
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare JDK ${{ matrix.java-version }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: ${{ matrix.java-version }}
|
||||
distribution: "temurin"
|
||||
|
||||
- name: Prepare Cypress environment
|
||||
id: cypress-prep
|
||||
uses: ./.github/actions/prepare-cypress
|
||||
with:
|
||||
is-replay-browser: true
|
||||
|
||||
- name: Run Snowplow micro
|
||||
uses: ./.github/actions/run-snowplow-micro
|
||||
|
||||
- name: Run OSS-specific Cypress tests
|
||||
if: matrix.edition == 'oss' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags=@OSS,grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js' \
|
||||
--browser "replay-chromium"
|
||||
|
||||
- name: Run slow and resource-intensive Cypress tests
|
||||
if: matrix.name == 'slow' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="@slow",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js' \
|
||||
--browser "replay-chromium"
|
||||
|
||||
- name: Run EE Cypress tests on ${{ matrix.name }}
|
||||
if: matrix.context == 'folder' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="-@slow+-@mongo --@quarantine",grepOmitFiltered=true \
|
||||
--folder ${{ matrix.name }} \
|
||||
--browser "replay-chromium"
|
||||
|
||||
- name: Run E2E tests that depend on Mongo
|
||||
if: matrix.name == 'mongo'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="@mongo --@quarantine",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js' \
|
||||
--browser "replay-chromium"
|
||||
env:
|
||||
CYPRESS_QA_DB_MONGO: true
|
||||
|
||||
- name: Upload Replay.io recordings
|
||||
if: github.event_name == 'schedule' && !cancelled()
|
||||
uses: replayio/action-upload@v0.5.1
|
||||
with:
|
||||
api-key: ${{ secrets.REPLAY_IO_TOKEN }}
|
||||
public: false
|
||||
|
||||
- name: Upload Cypress Artifacts upon failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: cypress-recording-${{ matrix.name }}-${{ matrix.edition }}
|
||||
path: |
|
||||
./cypress
|
||||
./logs/test.log
|
||||
if-no-files-found: ignore
|
||||
327
.github/workflows/e2e-tests.yml
vendored
327
.github/workflows/e2e-tests.yml
vendored
@@ -1,6 +1,9 @@
|
||||
name: E2E Tests
|
||||
|
||||
on:
|
||||
# We'll record runs using Replay.io and their browser on a schedule as an experiment
|
||||
schedule:
|
||||
- cron: '0 */8 * * *'
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
@@ -13,6 +16,13 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test-run-id:
|
||||
runs-on: ubuntu-22.04
|
||||
outputs:
|
||||
testRunId: ${{ steps.testRunId.outputs.testRunId }}
|
||||
steps:
|
||||
- id: testRunId
|
||||
run: echo testRunId=$(npx uuid) >> "$GITHUB_OUTPUT"
|
||||
files-changed:
|
||||
name: Check which files changed
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -28,24 +38,9 @@ jobs:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
e2e-matrix-builder:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
outputs:
|
||||
matrix: ${{ steps.e2e-matrix.outputs.matrix }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Generate matrix for E2E tests
|
||||
id: e2e-matrix
|
||||
uses: ./.github/actions/build-e2e-matrix
|
||||
|
||||
build:
|
||||
needs: [files-changed, e2e-matrix-builder]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
github.event.pull_request.draft == false &&
|
||||
needs.e2e-matrix-builder.result == 'success' &&
|
||||
needs.files-changed.outputs.e2e_all == 'true'
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.e2e_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 25
|
||||
strategy:
|
||||
@@ -68,175 +63,269 @@ jobs:
|
||||
|
||||
- name: Prepare uberjar artifact
|
||||
uses: ./.github/actions/prepare-uberjar-artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
e2e-tests:
|
||||
needs: [build, e2e-matrix-builder]
|
||||
needs: [build, files-changed, test-run-id]
|
||||
if: |
|
||||
!cancelled() && needs.build.result == 'success'
|
||||
runs-on: ${{ matrix.runner }}
|
||||
timeout-minutes: 90
|
||||
name: e2e-tests-${{ matrix.name }}-${{ matrix.edition }}
|
||||
always() &&
|
||||
needs.files-changed.outputs.e2e_all == 'true' &&
|
||||
needs.build.result == 'success'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
name: e2e-tests-${{ matrix.folder }}${{ matrix.context }}-${{ matrix.edition }}
|
||||
env:
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
DISPLAY: ""
|
||||
QA_DB_ENABLED: true
|
||||
# Any env starting with `CYPRESS_` will be available to all Cypress tests via `Cypress.env()`
|
||||
# Example: you can get `CYPRESS_FOO` with `Cypress.env("FOO")`
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
# Record runs using Deploysentinel except for the release branch
|
||||
CYPRESS_DEPLOYSENTINEL_KEY: ${{ !(startsWith(github.event.pull_request.base.ref, 'release')) && secrets.CYPRESS_DEPLOYSENTINEL_KEY || '' }}
|
||||
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
MB_SNOWPLOW_URL: "http://localhost:9090" # Snowplow micro
|
||||
ELECTRON_EXTRA_LAUNCH_ARGS: "--remote-debugging-port=40500" # deploysentinel
|
||||
TERM: xterm
|
||||
TZ: US/Pacific # to make node match the instance tz
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(needs.e2e-matrix-builder.outputs.matrix) }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare Docker containers
|
||||
uses: ./.github/actions/e2e-prepare-containers
|
||||
with:
|
||||
matrix:
|
||||
java-version: [11]
|
||||
edition: [ee]
|
||||
folder:
|
||||
- "admin"
|
||||
- "binning"
|
||||
- "collections"
|
||||
- "custom-column"
|
||||
- "dashboard"
|
||||
- "dashboard-filters"
|
||||
- "downloads"
|
||||
- "embedding"
|
||||
- "filters"
|
||||
- "joins"
|
||||
- "models"
|
||||
- "native"
|
||||
- "native-filters"
|
||||
- "onboarding"
|
||||
- "organization"
|
||||
- "permissions"
|
||||
- "question"
|
||||
- "sharing"
|
||||
- "visualizations"
|
||||
include:
|
||||
- edition: oss
|
||||
context: grep
|
||||
java-version: 11
|
||||
services:
|
||||
maildev:
|
||||
image: maildev/maildev:2.0.5
|
||||
ports:
|
||||
- "1080:1080"
|
||||
- "1025:1025"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
maildev: true
|
||||
openldap: ${{ startsWith(matrix.name, 'admin') }}
|
||||
postgres: ${{ matrix.name != 'mongo'}}
|
||||
mysql: ${{ matrix.name != 'mongo'}}
|
||||
mongo: ${{ matrix.name == 'mongo'}}
|
||||
|
||||
- name: Retrieve uberjar artifact for ${{ matrix.edition }}
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
- name: Get the version info
|
||||
openldap:
|
||||
image: osixia/openldap:1.5.0
|
||||
ports:
|
||||
- "389:389"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
postgres-sample:
|
||||
image: metabase/qa-databases:postgres-sample-12
|
||||
ports:
|
||||
- "5404:5432"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
mongo-sample:
|
||||
image: metabase/qa-databases:mongo-sample-4.4
|
||||
ports:
|
||||
- 27004:27017
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
mysql-sample:
|
||||
image: metabase/qa-databases:mysql-sample-8
|
||||
ports:
|
||||
- 3304:3306
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Record runs using Deploysentinel except for the release branch
|
||||
if: ${{ github.ref == 'refs/heads/master' || !(startsWith(github.event.pull_request.base.ref, 'release')) }}
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
|
||||
echo "CYPRESS_DEPLOYSENTINEL_KEY=${{ secrets.CYPRESS_DEPLOYSENTINEL_KEY }}" >> $GITHUB_ENV
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
|
||||
- name: Prepare JDK ${{ matrix.java-version }}
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: ${{ matrix.java-version }}
|
||||
distribution: "temurin"
|
||||
|
||||
- name: Prepare Cypress environment
|
||||
id: cypress-prep
|
||||
uses: ./.github/actions/prepare-cypress
|
||||
|
||||
- name: Run Snowplow micro
|
||||
uses: ./.github/actions/run-snowplow-micro
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve uberjar artifact for ${{ matrix.edition }}
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
|
||||
- name: Run OSS-specific Cypress tests
|
||||
if: matrix.edition == 'oss' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags=@OSS,grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Run slow and resource-intensive Cypress tests
|
||||
if: matrix.name == 'slow' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="@slow",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Run EE Cypress tests on ${{ matrix.name }}
|
||||
if: matrix.context == 'folder' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="-@slow+-@mongo --@quarantine",grepOmitFiltered=true \
|
||||
--folder ${{ matrix.name }} \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
|
||||
- name: Run E2E tests that depend on Mongo
|
||||
if: matrix.name == 'mongo'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="@mongo --@quarantine",grepOmitFiltered=true \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js' \
|
||||
--browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
--env grepTags=@OSS \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js'
|
||||
env:
|
||||
CYPRESS_QA_DB_MONGO: true
|
||||
TERM: xterm
|
||||
|
||||
- name: Run EE Cypress tests on ${{ matrix.folder }}
|
||||
if: matrix.edition == 'ee' && github.event_name != 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="-@quarantine" \
|
||||
--folder ${{ matrix.folder }}
|
||||
env:
|
||||
TERM: xterm
|
||||
|
||||
# REPLAY.IO specific jobs
|
||||
- name: Install Replay.io browser
|
||||
if: ${{ github.event_name == 'schedule' }}
|
||||
run: npx @replayio/cypress install
|
||||
|
||||
- name: Run OSS-specific Cypress tests using Replay.io browser
|
||||
if: matrix.edition == 'oss' && github.event_name == 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags=@OSS \
|
||||
--spec './e2e/test/scenarios/**/*.cy.spec.js' \
|
||||
--browser "replay-chromium"
|
||||
env:
|
||||
TERM: xterm
|
||||
CYPRESS_REPLAYIO_ENABLED: 1
|
||||
RECORD_REPLAY_METADATA_FILE: /tmp/replay-metadata.json
|
||||
RECORD_REPLAY_METADATA_TEST_RUN_ID: ${{ needs.test-run-id.outputs.testRunId }}
|
||||
|
||||
- name: Run EE Cypress tests on ${{ matrix.folder }} using Replay.io browser
|
||||
if: matrix.edition == 'ee' && github.event_name == 'schedule'
|
||||
run: |
|
||||
yarn run test-cypress-run \
|
||||
--env grepTags="-@quarantine" \
|
||||
--folder ${{ matrix.folder }} \
|
||||
--browser "replay-chromium"
|
||||
env:
|
||||
TERM: xterm
|
||||
CYPRESS_REPLAYIO_ENABLED: 1
|
||||
RECORD_REPLAY_METADATA_FILE: /tmp/replay-metadata.json
|
||||
RECORD_REPLAY_METADATA_TEST_RUN_ID: ${{ needs.test-run-id.outputs.testRunId }}
|
||||
|
||||
- name: Upload Replay.io recordings
|
||||
if: github.event_name == 'schedule' && always()
|
||||
uses: replayio/action-upload@v0.4.7
|
||||
with:
|
||||
api-key: rwk_gXbvYctIcR6RZyEzUvby3gtkO4esrB2L321lkY8FSuQ
|
||||
public: true
|
||||
|
||||
- name: Upload Cypress Artifacts upon failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: cypress-recording-${{ matrix.name }}-${{ matrix.edition }}
|
||||
name: cypress-recording-${{ matrix.folder }}${{ matrix.context }}-${{ matrix.edition }}
|
||||
path: |
|
||||
./cypress
|
||||
./logs/test.log
|
||||
if-no-files-found: ignore
|
||||
|
||||
e2e-tests-skipped-stub:
|
||||
needs: [e2e-tests, e2e-matrix-builder]
|
||||
needs: [build, files-changed]
|
||||
if: |
|
||||
!cancelled() &&
|
||||
needs.e2e-tests.result == 'skipped'
|
||||
runs-on: ${{ matrix.runner }}
|
||||
always() &&
|
||||
needs.files-changed.outputs.e2e_all == 'false' &&
|
||||
needs.build.result == 'skipped'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
name: e2e-tests-${{ matrix.name }}-${{ matrix.edition }}
|
||||
name: e2e-tests-${{ matrix.folder }}${{ matrix.context }}-${{ matrix.edition }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJSON(needs.e2e-matrix-builder.outputs.matrix) }}
|
||||
matrix:
|
||||
java-version: [11]
|
||||
edition: [ee]
|
||||
folder:
|
||||
- "admin"
|
||||
- "binning"
|
||||
- "collections"
|
||||
- "custom-column"
|
||||
- "dashboard"
|
||||
- "dashboard-filters"
|
||||
- "downloads"
|
||||
- "embedding"
|
||||
- "filters"
|
||||
- "joins"
|
||||
- "models"
|
||||
- "native"
|
||||
- "native-filters"
|
||||
- "onboarding"
|
||||
- "organization"
|
||||
- "permissions"
|
||||
- "question"
|
||||
- "sharing"
|
||||
- "visualizations"
|
||||
include:
|
||||
- edition: oss
|
||||
context: grep
|
||||
java-version: 11
|
||||
steps:
|
||||
- run: |
|
||||
echo "Didn't run due to conditional filtering"
|
||||
|
||||
visual-regression-tests:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 60
|
||||
needs: [build]
|
||||
if: |
|
||||
!cancelled() && needs.build.result == 'success'
|
||||
timeout-minutes: 45
|
||||
needs: build
|
||||
if: ${{ github.event_name != 'schedule' }}
|
||||
name: percy-visual-regression-tests
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
- name: Prepare Docker containers
|
||||
uses: ./.github/actions/e2e-prepare-containers
|
||||
with:
|
||||
env:
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
services:
|
||||
maildev:
|
||||
image: maildev/maildev:2.0.5
|
||||
ports:
|
||||
- "1080:1080"
|
||||
- "1025:1025"
|
||||
credentials:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
maildev: true
|
||||
|
||||
- name: Retrieve uberjar artifact for ${{ matrix.edition }}
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: metabase-ee-${{ github.event.pull_request.head.sha || github.sha }}-uberjar
|
||||
|
||||
- name: Get the version info
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Enable Percy recording on master only
|
||||
if: github.ref == 'refs/heads/master'
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
|
||||
echo "PERCY_TOKEN=${{ secrets.PERCY_TOKEN }}" >> $GITHUB_ENV
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
|
||||
- name: Prepare JDK 11
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: 11
|
||||
distribution: 'temurin'
|
||||
|
||||
- name: Prepare Cypress environment
|
||||
id: cypress-prep
|
||||
uses: ./.github/actions/prepare-cypress
|
||||
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve uberjar artifact for ee
|
||||
with:
|
||||
name: metabase-ee-uberjar
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
- name: Percy Test
|
||||
run: yarn run test-visual-run --browser ${{ steps.cypress-prep.outputs.chrome-path }}
|
||||
run: yarn run test-visual-run
|
||||
env:
|
||||
PERCY_TOKEN: ${{ github.ref == 'refs/heads/master' && secrets.PERCY_TOKEN || ''}}
|
||||
PERCY_TOKEN: ${{ env.PERCY_TOKEN }}
|
||||
|
||||
@@ -10,12 +10,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Format issue title (escape quotes)
|
||||
uses: actions/github-script@v6
|
||||
id: vars
|
||||
with:
|
||||
script: |
|
||||
core.setOutput('issue_title', ${{ toJson(github.event.issue.title) }}.replaceAll(/"/g, '\\"'));
|
||||
- name: Send escalated issue ${{ github.event.issue.number }} to Slack
|
||||
id: slack
|
||||
uses: slackapi/slack-github-action@v1.23.0
|
||||
@@ -27,7 +21,7 @@ jobs:
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": "🔥🔥🔥 ${{ steps.vars.outputs.issue_title }}\n${{ github.event.issue.html_url }}"
|
||||
"text": "🔥🔥🔥 ${{ github.event.issue.title }}\n${{ github.event.issue.html_url }}"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
17
.github/workflows/external-filter.yml
vendored
17
.github/workflows/external-filter.yml
vendored
@@ -1,17 +0,0 @@
|
||||
name: External Trigger Filter
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
branches:
|
||||
- 'master'
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 5
|
||||
if: github.event.pull_request.head.repo.full_name != github.repository
|
||||
steps:
|
||||
- run: echo 'Thank you for your contribution to Metabase!'
|
||||
130
.github/workflows/frontend.yml
vendored
130
.github/workflows/frontend.yml
vendored
@@ -3,8 +3,8 @@ name: Frontend
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- "master"
|
||||
- "release-**"
|
||||
- 'master'
|
||||
- 'release-**'
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, ready_for_review]
|
||||
|
||||
@@ -29,25 +29,33 @@ jobs:
|
||||
token: ${{ github.token }}
|
||||
filters: .github/file-paths.yaml
|
||||
|
||||
fe-lint:
|
||||
fe-linter-prettier:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.frontend_all == 'true' || needs.files-changed.outputs.e2e_specs == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- run: yarn run lint-prettier
|
||||
name: Run Prettier formatting linter
|
||||
|
||||
fe-linter-eslint:
|
||||
needs: files-changed
|
||||
if: needs.files-changed.outputs.frontend_all == 'true' || needs.files-changed.outputs.e2e_specs == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end 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
|
||||
- name: Run Prettier formatting linter
|
||||
run: yarn run lint-prettier-pure
|
||||
- name: Run ESLint linter
|
||||
run: yarn run lint-eslint-pure
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'cljs'
|
||||
- run: yarn run lint-eslint
|
||||
name: Run ESLint linter
|
||||
|
||||
fe-type-check:
|
||||
needs: files-changed
|
||||
@@ -55,43 +63,38 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
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
|
||||
- run: yarn type-check-pure
|
||||
name: Check types
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'cljs'
|
||||
- run: yarn build:cljs
|
||||
name: Compile CLJS
|
||||
- run: yarn type-check
|
||||
name: Check types
|
||||
|
||||
fe-tests-unit:
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.frontend_all == 'true'
|
||||
runs-on: buildjet-2vcpu-ubuntu-2204
|
||||
timeout-minutes: 60
|
||||
timeout-minutes: 30
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Run frontend unit tests and collect the code coverage information
|
||||
if: github.ref_name == 'master'
|
||||
run: yarn run test-unit --coverage --silent
|
||||
- name: Run frontend unit tests
|
||||
if: github.ref_name != 'master'
|
||||
run: yarn run test-unit --silent
|
||||
- name: Upload coverage to codecov.io
|
||||
if: github.ref_name == 'master'
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./coverage/lcov.info
|
||||
flags: front-end
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'cljs'
|
||||
- run: yarn run test-unit --coverage --silent
|
||||
name: Run frontend unit tests
|
||||
- name: Upload coverage to codecov.io
|
||||
uses: codecov/codecov-action@v3
|
||||
with:
|
||||
files: ./coverage/lcov.info
|
||||
flags: front-end
|
||||
|
||||
fe-tests-timezones:
|
||||
needs: files-changed
|
||||
@@ -99,12 +102,37 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 20
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'cljs'
|
||||
- run: yarn run test-timezones
|
||||
name: Run frontend timezones tests
|
||||
|
||||
fe-chromatic:
|
||||
needs: files-changed
|
||||
if: github.event.pull_request.draft == false && needs.files-changed.outputs.frontend_all == 'true'
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: "cljs"
|
||||
- name: Run frontend timezones tests
|
||||
run: yarn run test-timezones
|
||||
m2-cache-key: 'cljs'
|
||||
- name: Publish to Chromatic
|
||||
uses: chromaui/action@v1
|
||||
env:
|
||||
PUBLISH_CHROMATIC: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
STORYBOOK_BUILD_TIMEOUT: 900000
|
||||
if: env.PUBLISH_CHROMATIC != null
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
|
||||
8
.github/workflows/fuzzing.yml
vendored
8
.github/workflows/fuzzing.yml
vendored
@@ -1,18 +1,16 @@
|
||||
name: Fuzzing
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- 'master'
|
||||
- 'release-**'
|
||||
paths:
|
||||
- 'frontend/src/metabase-lib/expressions/**'
|
||||
pull_request:
|
||||
paths:
|
||||
- 'frontend/src/metabase-lib/expressions/**'
|
||||
paths-ignore:
|
||||
- 'docs/**'
|
||||
|
||||
jobs:
|
||||
|
||||
fe-fuzz-tokenizer:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
|
||||
11
.github/workflows/i18n.yml
vendored
11
.github/workflows/i18n.yml
vendored
@@ -14,7 +14,7 @@ concurrency:
|
||||
jobs:
|
||||
|
||||
verify-i18n-files:
|
||||
runs-on: ubuntu-22.04
|
||||
runs-on: ubuntu-20.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -24,13 +24,8 @@ jobs:
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: 'i18n'
|
||||
- name: Install xgettext if necessary
|
||||
run: |
|
||||
if ! command -v xgettext > /dev/null; then
|
||||
sudo apt install gettext
|
||||
fi
|
||||
- name: Check xgettext version
|
||||
run: xgettext --version
|
||||
- run: sudo apt install gettext
|
||||
|
||||
- name: Check i18n tags/make sure template can be built
|
||||
run: ./bin/i18n/update-translation-template
|
||||
- name: Verify i18n translations (.po files)
|
||||
|
||||
3
.github/workflows/percy-issue-comment.yml
vendored
3
.github/workflows/percy-issue-comment.yml
vendored
@@ -54,8 +54,7 @@ jobs:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MB_EDITION: ee
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
|
||||
3
.github/workflows/percy-visual-label.yml
vendored
3
.github/workflows/percy-visual-label.yml
vendored
@@ -14,8 +14,7 @@ jobs:
|
||||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MB_EDITION: ee
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Prepare front-end environment
|
||||
|
||||
277
.github/workflows/pre-release.yml
vendored
277
.github/workflows/pre-release.yml
vendored
@@ -1,89 +1,132 @@
|
||||
name: Release 2 - Pre-release testing
|
||||
run-name: Pre-release Testing of ${{ github.event.workflow_run.name }}
|
||||
name: Pre-release [WIP]
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: [Release 1 - Build Release Artifact]
|
||||
types: [completed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
commit:
|
||||
description: 'A full-length commit SHA-1 hash'
|
||||
required: true
|
||||
version:
|
||||
description: 'Intended version (e.g. v0.46.3)'
|
||||
required: true
|
||||
|
||||
env:
|
||||
MAX_HASH_LENGTH: 8
|
||||
CUSTOM_REPO: ${{ secrets.CUSTOM_RELEASE_REPO }}
|
||||
|
||||
jobs:
|
||||
release-artifact:
|
||||
if: ${{ github.event.workflow_run.conclusion == 'success' }}
|
||||
check-commit:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- name: Ensure that the intended version (${{ github.event.inputs.version }}) was never released before
|
||||
run: |
|
||||
if [[ "${{ github.event.inputs.version }}" = v* ]]; then
|
||||
echo "Checking if ${{ github.event.inputs.version }} conflicts with a past release..."
|
||||
else
|
||||
echo "ERROR: the intended version must start with 'v', e.g. 'v0.46.3."
|
||||
echo "ABORT!"
|
||||
exit -1
|
||||
fi
|
||||
CANONICAL_REFS=https://github.com/metabase/metabase/archive/refs
|
||||
URL=${CANONICAL_REFS}/tags/${{ github.event.inputs.version }}.zip
|
||||
HTTP_CODE=$(curl -s -L -o /dev/null --head -w "%{HTTP_CODE}" ${URL})
|
||||
if [[ $HTTP_CODE =~ "200" ]]; then
|
||||
echo "ERROR: that version was already released in the past."
|
||||
echo "ABORT!"
|
||||
exit -1
|
||||
else
|
||||
if [[ $HTTP_CODE =~ "404" ]]; then
|
||||
echo "That version has not been released yet."
|
||||
echo "Proceeding to the next step..."
|
||||
exit 0
|
||||
else
|
||||
echo "ERROR: Unhandled case of HTTP $HTTP_CODE while checking ${URL}"
|
||||
echo "ABORT!"
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Check out the code to verify the release branch
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # IMPORTANT! to get all the branches
|
||||
- name: Ensure that the specified commit exists in the latest release branch
|
||||
run: |
|
||||
echo "Checking if the specified commit is in a release branch..."
|
||||
COMMIT=${{ github.event.inputs.commit }}
|
||||
git branch -a --contains $COMMIT > branches.txt
|
||||
if [[ $(grep -c master branches.txt) =~ 1 ]]; then
|
||||
echo "Found in master branch. ABORT!"
|
||||
exit -1
|
||||
fi
|
||||
if [[ $(grep -c 'release-x' branches.txt) =~ 1 ]]; then
|
||||
echo "Found the commit $COMMIT in:"
|
||||
git branch -a --contains $COMMIT
|
||||
echo "Proceeding to the next step..."
|
||||
exit 0
|
||||
else
|
||||
echo "Commit $COMMIT is not found in a single release branch"
|
||||
echo "ABORT!."
|
||||
exit -1
|
||||
fi
|
||||
|
||||
build:
|
||||
if: ${{ github.repository }} != 'metabase/metabase'
|
||||
runs-on: ubuntu-22.04
|
||||
needs: check-commit
|
||||
name: Build Metabase ${{ matrix.edition }} @${{ github.event.inputs.commit }}
|
||||
timeout-minutes: 40
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
outputs:
|
||||
ee_version: ${{ steps.version-properties.outputs.ee_version }}
|
||||
oss_version: ${{ steps.version-properties.outputs.oss_version }}
|
||||
commit: ${{ steps.version-properties.outputs.commit }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
INTERACTIVE: false
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
- name: 'Download artifact'
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: |
|
||||
const fs = require('fs');
|
||||
- name: Fail early if custom docker release repo is missing
|
||||
if: ${{ env.CUSTOM_REPO == null }}
|
||||
run: exit 1
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ github.event.inputs.commit }}
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
with:
|
||||
m2-cache-key: pre-release-build
|
||||
|
||||
const allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: context.payload.workflow_run.id,
|
||||
});
|
||||
- name: Determine the canonical version ## EE is always v1.x.y, OSS is always v0.x.y
|
||||
uses: actions/github-script@v6
|
||||
id: canonical_version
|
||||
env:
|
||||
INTENDED_VERSION: ${{ github.event.inputs.version }}
|
||||
EDITION: ${{ matrix.edition }}
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
var canonical_version;
|
||||
const ver = process.env.INTENDED_VERSION;
|
||||
if (process.env.EDITION === "ee") {
|
||||
canonical_version = ver.replace(/^v0\./, "v1."); // always e.g. v1.47.2
|
||||
} else {
|
||||
canonical_version = ver.replace(/^v1\./, "v0."); // always e.g. v0.45.6
|
||||
}
|
||||
console.log("The canonical version of this", process.env.EDITION, "edition is", canonical_version);
|
||||
return canonical_version;
|
||||
|
||||
const matchArtifact = allArtifacts.data.artifacts.find((artifact) => {
|
||||
return artifact.name.includes('-${{ matrix.edition }}-');
|
||||
});
|
||||
- name: Build
|
||||
run: ./bin/build.sh :edition :${{ matrix.edition }} :version ${{ steps.canonical_version.outputs.result }}
|
||||
|
||||
if (!matchArtifact) {
|
||||
throw new Error('No artifact found');
|
||||
}
|
||||
|
||||
const download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: matchArtifact.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
|
||||
- name: Extract the version.properties file from the JAR
|
||||
run: |
|
||||
jar xf metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
- name: Reveal Metabase ${{ matrix.edition }} properties
|
||||
id: version-properties
|
||||
run: |
|
||||
cat ./resources/version.properties
|
||||
echo "commit=$(cat ./COMMIT-ID)" >> $GITHUB_OUTPUT
|
||||
|
||||
version=$(grep -o '^tag=.*' ./resources/version.properties | cut -d'=' -f2)
|
||||
|
||||
if [[ "${{ matrix.edition }}" == "ee" ]]; then
|
||||
echo "ee_version=$version" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "oss_version=$version" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
shell: bash
|
||||
- name: Upload Metabase ${{ matrix.edition }} JAR as artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
path: |
|
||||
./metabase.jar
|
||||
./COMMIT-ID
|
||||
./SHA256.sum
|
||||
- name: Prepare uberjar artifact
|
||||
uses: ./.github/actions/prepare-uberjar-artifact
|
||||
|
||||
check-uberjar-health:
|
||||
needs: [release-artifact]
|
||||
runs-on: ubuntu-22.04
|
||||
name: Is ${{ matrix.edition }} (java ${{ matrix.java-version }}) healthy?
|
||||
needs: build
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -102,25 +145,23 @@ jobs:
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Launch uberjar (and keep it running)
|
||||
run: java -jar ./metabase.jar &
|
||||
run: java -jar ./target/uberjar/metabase.jar &
|
||||
- name: Wait for Metabase to start
|
||||
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
|
||||
run-sanity-check:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 30
|
||||
needs: [release-artifact, check-uberjar-health]
|
||||
timeout-minutes: 15
|
||||
needs: check-uberjar-health
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
env:
|
||||
MB_EDITION: ${{ matrix.edition }}
|
||||
DISPLAY: ""
|
||||
CYPRESS_ALL_FEATURES_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
CYPRESS_NO_FEATURES_TOKEN: ${{ secrets.E2E_STARTER_TOKEN }}
|
||||
MB_PREMIUM_EMBEDDING_TOKEN: ${{ secrets.ENTERPRISE_TOKEN }}
|
||||
MB_SNOWPLOW_AVAILABLE: true
|
||||
MB_SNOWPLOW_URL: "http://localhost:9090" # Snowplow micro
|
||||
TERM: xterm
|
||||
services:
|
||||
maildev:
|
||||
image: maildev/maildev:2.0.5
|
||||
@@ -134,7 +175,7 @@ jobs:
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ needs.release-artifact.outputs.commit }}
|
||||
ref: ${{ github.event.inputs.commit }}
|
||||
- name: Prepare front-end environment
|
||||
uses: ./.github/actions/prepare-frontend
|
||||
- name: Prepare JDK 11
|
||||
@@ -152,13 +193,12 @@ jobs:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Get the version info
|
||||
run: |
|
||||
jar xf metabase.jar version.properties
|
||||
jar xf target/uberjar/metabase.jar version.properties
|
||||
mv version.properties resources/
|
||||
- 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 --folder onboarding
|
||||
|
||||
run: yarn test-cypress-run --folder onboarding
|
||||
env:
|
||||
TERM: xterm
|
||||
- name: Upload Cypress Artifacts upon failure
|
||||
uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
@@ -170,8 +210,8 @@ jobs:
|
||||
if-no-files-found: ignore
|
||||
|
||||
containerize:
|
||||
needs: [release-artifact, run-sanity-check]
|
||||
runs-on: ubuntu-22.04
|
||||
needs: run-sanity-check
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
@@ -181,26 +221,24 @@ jobs:
|
||||
image: registry:2
|
||||
ports:
|
||||
- 5000:5000
|
||||
outputs:
|
||||
image_tag: ${{ steps.target.outputs.image_tag }}
|
||||
steps:
|
||||
- name: Get the version
|
||||
run: |
|
||||
if [[ "${{ matrix.edition }}" == "ee" ]]; then
|
||||
echo "VERSION=${{ needs.release-artifact.outputs.ee_version }}" >> $GITHUB_ENV
|
||||
else
|
||||
echo "VERSION=${{ needs.release-artifact.outputs.oss_version }}" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Check out the code
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
ref: ${{ needs.release-artifact.outputs.commit }}
|
||||
ref: ${{ github.event.inputs.commit }}
|
||||
- name: Truncate commit hash
|
||||
run: |
|
||||
commit_id=${{ github.event.inputs.commit }}
|
||||
truncated_hash=${commit_id:0:${{ env.MAX_HASH_LENGTH }}}
|
||||
|
||||
echo "COMMIT_IDENTIFIER=$truncated_hash" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve uberjar artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Move the Uberjar to the context dir
|
||||
run: mv metabase.jar bin/docker/.
|
||||
run: mv ./target/uberjar/metabase.jar bin/docker/.
|
||||
- name: Set up Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
@@ -212,12 +250,12 @@ jobs:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64
|
||||
network: host
|
||||
tags: localhost:5000/local-metabase:${{ env.VERSION }}
|
||||
tags: localhost:5000/local-metabase:${{ env.COMMIT_IDENTIFIER }}-${{ matrix.edition }}
|
||||
no-cache: true
|
||||
push: true
|
||||
|
||||
- name: Launch container
|
||||
run: docker run --rm -dp 3000:3000 localhost:5000/local-metabase:${{ env.VERSION }}
|
||||
run: docker run --rm -dp 3000:3000 localhost:5000/local-metabase:${{ env.COMMIT_IDENTIFIER }}-${{ matrix.edition }}
|
||||
timeout-minutes: 5
|
||||
- name: Wait for Metabase to start
|
||||
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
@@ -228,53 +266,48 @@ jobs:
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_RELEASE_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
|
||||
- name: Retag and push container image to ${{ vars.DOCKERHUB_OWNER }} staging Docker Hub repo
|
||||
id: target
|
||||
- name: Determine the target Docker Hub repository
|
||||
run: |
|
||||
# SHA-1 truncated to 7 digits should be enough
|
||||
SHORT_HASH=${COMMIT:0:7}
|
||||
|
||||
IMAGE_TAG=$VERSION-$SHORT_HASH
|
||||
CONTAINER_IMAGE=${{ vars.DOCKERHUB_OWNER }}/${{ vars.DOCKERHUB_STAGING_REPO }}:$IMAGE_TAG
|
||||
|
||||
echo "image_tag=$IMAGE_TAG" >> $GITHUB_OUTPUT
|
||||
|
||||
echo "Retag local image for staging"
|
||||
docker tag localhost:5000/local-metabase:$VERSION $CONTAINER_IMAGE
|
||||
|
||||
echo "Pushing container image $CONTAINER_IMAGE ..."
|
||||
docker push $CONTAINER_IMAGE
|
||||
|
||||
echo "DOCKERHUB_REPO=${{ github.repository_owner }}/${{ env.CUSTOM_REPO }}" >> $GITHUB_ENV
|
||||
echo "IMAGE_NAME=${{ env.COMMIT_IDENTIFIER }}-${{ matrix.edition }}" >> $GITHUB_ENV
|
||||
- name: Retag and push container image to Docker Hub
|
||||
run: |
|
||||
echo "Pushing container image ${{ env.IMAGE_NAME}} to ${{ env.DOCKERHUB_REPO }} ..."
|
||||
docker tag localhost:5000/local-metabase:${{ env.IMAGE_NAME }} ${{ env.DOCKERHUB_REPO }}:${{ env.IMAGE_NAME }}
|
||||
docker push ${{ env.DOCKERHUB_REPO }}:${{ env.IMAGE_NAME }}
|
||||
echo "Finished!"
|
||||
shell: bash
|
||||
env:
|
||||
COMMIT: ${{ needs.release-artifact.outputs.commit }}
|
||||
|
||||
verify-docker-pull:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [release-artifact, containerize]
|
||||
needs: containerize
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
env:
|
||||
IMAGE_TAG: ${{ needs.containerize.outputs.image_tag }}
|
||||
steps:
|
||||
- name: Truncate commit hash
|
||||
run: |
|
||||
commit_id=${{ github.event.inputs.commit }}
|
||||
truncated_hash=${commit_id:0:${{ env.MAX_HASH_LENGTH }}}
|
||||
|
||||
echo "COMMIT_IDENTIFIER=$truncated_hash" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Login to Docker Hub # authenticated, to avoid being rate-throttled
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_RELEASE_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
|
||||
- name: Determine the container image to pull
|
||||
run: |
|
||||
echo "DOCKERHUB_REPO=${{ github.repository_owner }}/${{ env.CUSTOM_REPO }}" >> $GITHUB_ENV
|
||||
echo "IMAGE_NAME=${{ env.COMMIT_IDENTIFIER }}-${{ matrix.edition }}" >> $GITHUB_ENV
|
||||
- name: Pull the container image
|
||||
run: |
|
||||
CONTAINER_IMAGE=${{ vars.DOCKERHUB_OWNER }}/${{ vars.DOCKERHUB_STAGING_REPO }}:$IMAGE_TAG
|
||||
echo "Pulling container image $CONTAINER_IMAGE ..."
|
||||
docker pull $CONTAINER_IMAGE
|
||||
echo "Pulling container image ${{ env.DOCKERHUB_REPO }}:${{ env.IMAGE_NAME }} ..."
|
||||
docker pull ${{ env.DOCKERHUB_REPO }}:${{ env.IMAGE_NAME }}
|
||||
echo "Successful!"
|
||||
- name: Launch container
|
||||
run: |
|
||||
CONTAINER_IMAGE=${{ vars.DOCKERHUB_OWNER }}/${{ vars.DOCKERHUB_STAGING_REPO }}:$IMAGE_TAG
|
||||
docker run --rm -dp 3000:3000 $CONTAINER_IMAGE
|
||||
run: docker run --rm -dp 3000:3000 ${{ env.DOCKERHUB_REPO }}:${{ env.IMAGE_NAME }}
|
||||
timeout-minutes: 5
|
||||
- name: Wait for Metabase to start
|
||||
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
|
||||
650
.github/workflows/release.yml
vendored
650
.github/workflows/release.yml
vendored
@@ -1,259 +1,98 @@
|
||||
name: Release 3 - Publish Release
|
||||
run-name: Publish Release ${{ inputs.version }}
|
||||
name: Release [WIP]
|
||||
|
||||
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
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
jobs:
|
||||
check-version:
|
||||
|
||||
trigger-docs-update:
|
||||
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@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Get Release Version
|
||||
uses: actions/github-script@v6
|
||||
id: canonical_version
|
||||
with:
|
||||
script: |
|
||||
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;
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.DOCS_UPDATE_TOKEN }}
|
||||
script: |
|
||||
github.rest.repos.createDispatchEvent({
|
||||
owner: '${{ github.repository_owner }}',
|
||||
repo: '${{ secrets.DOCS_REPO }}',
|
||||
event_type: 'trigger-docs-update',
|
||||
client_payload: {
|
||||
version: '${{ github.ref_name }}'
|
||||
}
|
||||
});
|
||||
|
||||
download-uberjar:
|
||||
needs: check-version
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
steps:
|
||||
- name: find_release_artifact
|
||||
id: find_release_artifact
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
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) {
|
||||
throw new Error(`No artifacts found for ${{ inputs.commit }}`);
|
||||
}
|
||||
|
||||
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 uberjar artifact
|
||||
run: unzip mb.zip
|
||||
- name: Download Uberjar for ${{ github.ref_name }}
|
||||
run: |
|
||||
JAR_DOWNLOAD_URL=https://downloads.metabase.com/${{ github.ref_name }}/metabase.jar
|
||||
if [[ ${{ github.ref_name }} == v1* ]]; then
|
||||
JAR_DOWNLOAD_URL=https://downloads.metabase.com/enterprise/${{ github.ref_name }}/metabase.jar
|
||||
fi
|
||||
echo $JAR_DOWNLOAD_URL > url.txt
|
||||
echo "----- Downloading Uberjar from $JAR_DOWNLOAD_URL -----"
|
||||
curl -OL $JAR_DOWNLOAD_URL
|
||||
stat ./metabase.jar
|
||||
date | tee timestamp
|
||||
- name: Verify that this is a valid JAR file
|
||||
run: file --mime-type ./metabase.jar | grep "application/zip"
|
||||
- name: Reveal its version.properties
|
||||
run: jar xf metabase.jar version.properties && cat version.properties
|
||||
- name: Check JAR version properties
|
||||
run: |
|
||||
# ensure actual jar checksum matches checksum file
|
||||
grep -q $(sha256sum ./metabase.jar) SHA256.sum && echo "checksums match" || (echo "checksum mismatch" && exit 1)
|
||||
|
||||
# ensure stored commit-id file matches input commit
|
||||
grep -q ${{ inputs.commit }} COMMIT-ID && echo "commit ids match" || (echo "commit-id mismatch" && exit 1)
|
||||
|
||||
# ensure version.properties partial commit matches commit input
|
||||
grep -q $(cut -c 1-7 <<< ${{ inputs.commit }}) version.properties && echo "version.properties commit matches" || (echo "version.properties commit mismatch" && exit 1)
|
||||
|
||||
# ensure version.properties version number matches input version (without v0/v1 to make it ee/oss agnostic)
|
||||
grep -q $(cut -c 3-99 <<< ${{ inputs.version }}) version.properties && echo "version.properties version number matches" || (echo "version.properties version number mismatch" && exit 1)
|
||||
|
||||
# ensure the build is not a snapshot build
|
||||
grep -q "SNAPSHOT" version.properties && (echo "jar is a snapshot" && exit 1) || echo "jar is not a snapshot build"
|
||||
- name: Calculate SHA256 checksum
|
||||
run: sha256sum ./metabase.jar | tee SHA256.sum
|
||||
- name: Upload Uberjar as artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
name: metabase-uberjar-${{ github.ref_name }}
|
||||
path: |
|
||||
./metabase.jar
|
||||
./COMMIT-ID
|
||||
./url.txt
|
||||
./timestamp
|
||||
./SHA256.sum
|
||||
./version.properties
|
||||
|
||||
upload-to-s3:
|
||||
check-uberjar:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: download-uberjar
|
||||
timeout-minutes: 15
|
||||
timeout-minutes: 10
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
java-version: [11, 17]
|
||||
steps:
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v3
|
||||
- name: Prepare JRE (Java Run-time Environment)
|
||||
uses: actions/setup-java@v3
|
||||
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@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: prepare release scripts
|
||||
run: cd release && yarn && yarn build
|
||||
java-package: jre
|
||||
java-version: ${{ matrix.java-version }}
|
||||
distribution: 'temurin'
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve uberjar artifact
|
||||
name: Retrieve previously downloaded Uberjar
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Determine the upload path ## EE is always v1.x.y, OSS is always v0.x.y
|
||||
uses: actions/github-script@v6
|
||||
id: version_path
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const version = '${{ inputs.version }}';
|
||||
const edition = '${{ matrix.edition }}';
|
||||
|
||||
const version_path = edition === 'ee'
|
||||
? 'enterprise/' + version.replace(/^v0\./, "v1.") // always e.g. v1.47.2
|
||||
: version.replace(/^v1\./, "v0."); // always e.g. v0.45.6;
|
||||
|
||||
console.log("The download path for this", edition, "edition is", version_path);
|
||||
return version_path;
|
||||
- name: Determine if this is a latest version
|
||||
uses: actions/github-script@v6
|
||||
id: latest_path
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const { isLatestRelease, getCanonicalVersion } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const version = '${{ inputs.version }}';
|
||||
const edition = '${{ matrix.edition }}';
|
||||
|
||||
const canonical_version = getCanonicalVersion(version, edition);
|
||||
|
||||
const isLatest = await isLatestRelease({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: canonical_version,
|
||||
});
|
||||
|
||||
if (isLatest) {
|
||||
return edition === 'ee' ? 'enterprise/latest' : 'latest';
|
||||
}
|
||||
return "false";
|
||||
|
||||
- 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: ${{ steps.is_latest.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
|
||||
name: metabase-uberjar-${{ github.ref_name }}
|
||||
- name: Reveal its version.properties
|
||||
run: jar xf metabase.jar version.properties && cat version.properties
|
||||
- name: Display when and where it was downloaded
|
||||
run: |
|
||||
aws cloudfront create-invalidation \
|
||||
--distribution-id ${{ vars.AWS_CLOUDFRONT_DOWNLOADS_ID }} \
|
||||
--paths /${{ steps.version_path.outputs.result }}/metabase.jar
|
||||
|
||||
|
||||
verify-s3-download:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: upload-to-s3
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
steps:
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve uberjar artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Determine the download path ## EE is always v1.x.y, OSS is always v0.x.y
|
||||
uses: actions/github-script@v6
|
||||
id: version_path
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const version = '${{ inputs.version }}';
|
||||
const edition = '${{ matrix.edition }}';
|
||||
|
||||
const version_path = edition === 'ee'
|
||||
? 'enterprise/' + version.replace(/^v0\./, "v1.") // always e.g. v1.47.2
|
||||
: version.replace(/^v1\./, "v0."); // always e.g. v0.45.6;
|
||||
|
||||
console.log("The download path for this", edition, "edition is", version_path);
|
||||
return version_path;
|
||||
- name: Upload to S3
|
||||
run:
|
||||
curl -L http://${{ vars.AWS_S3_DOWNLOADS_BUCKET }}.s3.${{ vars.AWS_REGION }}.amazonaws.com/${{ steps.version_path.outputs.result }}/metabase.jar -o metabase-downloaded.jar
|
||||
- name: Verify Checksum
|
||||
run: grep -q $(sha256sum ./metabase-downloaded.jar) SHA256.sum && echo "checksums match" || exit 1
|
||||
cat timestamp
|
||||
cat url.txt
|
||||
- name: Show the checksum
|
||||
run: cat SHA256.sum
|
||||
- name: Launch Metabase Uberjar (and keep it running)
|
||||
run: java -jar ./metabase.jar &
|
||||
- name: Wait for Metabase to start
|
||||
run: while ! curl -s localhost:3000/api/health; do sleep 1; done
|
||||
timeout-minutes: 3
|
||||
- name: Check API health
|
||||
run: curl -s localhost:3000/api/health
|
||||
|
||||
containerize:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [check-version, download-uberjar]
|
||||
needs: check-uberjar
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
services:
|
||||
registry:
|
||||
image: registry:2
|
||||
@@ -263,45 +102,10 @@ jobs:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
fetch-depth: 0 # IMPORTANT! to get all the tags
|
||||
- name: prepare release scripts
|
||||
run: cd release && yarn && yarn build
|
||||
- name: Determine the docker version tag
|
||||
uses: actions/github-script@v6
|
||||
id: canonical_version
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const version = '${{ inputs.version }}';
|
||||
const edition = '${{ matrix.edition }}';
|
||||
|
||||
const canonical_version = edition === 'ee'
|
||||
? '${{ needs.check-version.outputs.ee }}'
|
||||
: '${{ needs.check-version.outputs.oss }}';
|
||||
|
||||
console.log("The canonical version of this Metabase", edition, "edition is", canonical_version);
|
||||
|
||||
return canonical_version;
|
||||
- name: Check if the container image should be tagged as latest
|
||||
uses: actions/github-script@v6
|
||||
id: latest_version_check
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const { execSync } = require("child_process");
|
||||
const { isLatestVersion } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const currentTag = '${{ inputs.version }}';
|
||||
const allTags = execSync("git tag -l").toString("utf-8").split("\n");
|
||||
|
||||
const isLatest = isLatestVersion(currentTag, allTags);
|
||||
|
||||
console.log("Latest version?", isLatest);
|
||||
|
||||
return isLatest ? "latest" : "not-latest";
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve previously downloaded Uberjar
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
name: metabase-uberjar-${{ github.ref_name }}
|
||||
- name: Move the Uberjar to the context dir
|
||||
run: mv ./metabase.jar bin/docker/.
|
||||
- name: Set up Docker Buildx
|
||||
@@ -315,12 +119,12 @@ jobs:
|
||||
context: bin/docker/.
|
||||
platforms: linux/amd64
|
||||
network: host
|
||||
tags: localhost:5000/local-metabase:${{ steps.canonical_version.outputs.result }}
|
||||
tags: localhost:5000/local-metabase:${{ github.ref_name }}
|
||||
no-cache: true
|
||||
push: true
|
||||
|
||||
- name: Launch container
|
||||
run: docker run --rm -dp 3000:3000 localhost:5000/local-metabase:${{ steps.canonical_version.outputs.result }}
|
||||
run: docker run --rm -dp 3000:3000 localhost:5000/local-metabase:${{ github.ref_name }}
|
||||
timeout-minutes: 5
|
||||
- name: Wait for Metabase to start
|
||||
run: while ! curl -s 'http://localhost:3000/api/health' | grep '{"status":"ok"}'; do sleep 1; done
|
||||
@@ -328,7 +132,7 @@ jobs:
|
||||
|
||||
- name: Determine the target Docker Hub repository
|
||||
run: |
|
||||
if [[ "${{ matrix.edition }}" == "ee" ]]; then
|
||||
if [[ ${{ github.ref_name }} == v1* ]]; then
|
||||
echo "Metabase EE: image is going to be pushed to ${{ github.repository_owner }}/metabase-enterprise"
|
||||
echo "DOCKERHUB_REPO=${{ github.repository_owner }}/metabase-enterprise" >> $GITHUB_ENV
|
||||
else
|
||||
@@ -343,16 +147,94 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
|
||||
- name: Retag and push container image to Docker Hub
|
||||
run: |
|
||||
echo "Pushing ${{ steps.canonical_version.outputs.result }} to ${{ env.DOCKERHUB_REPO }} ..."
|
||||
docker tag localhost:5000/local-metabase:${{ steps.canonical_version.outputs.result }} ${{ env.DOCKERHUB_REPO }}:${{ steps.canonical_version.outputs.result }}
|
||||
docker push ${{ env.DOCKERHUB_REPO }}:${{ steps.canonical_version.outputs.result }}
|
||||
echo "Pushing ${{ github.ref_name }} to ${{ env.DOCKERHUB_REPO }} ..."
|
||||
docker tag localhost:5000/local-metabase:${{ github.ref_name }} ${{ env.DOCKERHUB_REPO }}:${{ github.ref_name }}
|
||||
docker push ${{ env.DOCKERHUB_REPO }}:${{ github.ref_name }}
|
||||
echo "Finished!"
|
||||
|
||||
- name: Check if the container image should be tagged as latest
|
||||
uses: actions/github-script@v6
|
||||
id: latest_version_check
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const currentTag = context.payload.ref.replace("refs/tags/", "");
|
||||
|
||||
const { execSync } = require("child_process");
|
||||
|
||||
const isNumber = s => s.match(/\d+/) && s.match(/\d+/).shift() == s;
|
||||
|
||||
const parseVersion = version => {
|
||||
const parts = version.split(".");
|
||||
const prefix = parts[0];
|
||||
const isOSS = prefix === "v0";
|
||||
const isEE = prefix === "v1";
|
||||
const feature = parseInt(parts[1], 10);
|
||||
const maintenance = parseInt(parts[2], 10);
|
||||
const build = parseInt(parts[3], 10);
|
||||
const prerelease = parts[2] ? !isNumber(parts[2]) : false;
|
||||
return { prefix, feature, maintenance, build, isOSS, isEE, prerelease };
|
||||
}
|
||||
|
||||
const byVersions = (tag1, tag2) => {
|
||||
const v1 = parseVersion(tag1);
|
||||
const v2 = parseVersion(tag2);
|
||||
const order1 = v1.feature * 1e6 + v1.maintenance * 1e3 + (v1.build || 0);
|
||||
const order2 = v2.feature * 1e6 + v2.maintenance * 1e3 + (v2.build || 0);
|
||||
return order2 - order1;
|
||||
}
|
||||
|
||||
const currentVersion = parseVersion(currentTag);
|
||||
console.log("Current version for", currentTag, "is", currentVersion);
|
||||
if (currentVersion.prerelease) {
|
||||
console.log("This is a pre-release!");
|
||||
console.log("There is no need to tag the container image as latest.");
|
||||
return "not-latest";
|
||||
}
|
||||
|
||||
console.log();
|
||||
console.log("Enumerating all git tag...");
|
||||
const allTags = execSync("git tag -l").toString("utf-8").split("\n");
|
||||
console.log("Found total", allTags.length, "tags");
|
||||
|
||||
console.log();
|
||||
console.log("Filtering for", currentVersion.isOSS ? "OSS" : "EE");
|
||||
const relevantTags = allTags.filter(tag => {
|
||||
const { prefix } = parseVersion(tag);
|
||||
return prefix === currentVersion.prefix;
|
||||
});
|
||||
console.log("Found total", relevantTags.length, "filtered tags");
|
||||
if (relevantTags.length < 10) {
|
||||
console.error("Something is NOT RIGHT! Please check all git tags!!!");
|
||||
return "not-latest";
|
||||
}
|
||||
|
||||
console.log();
|
||||
console.log("Sorting tags to find the highest version numbers...");
|
||||
const sortedTags = relevantTags.sort(byVersions)
|
||||
console.log("Showing 20 tags with the highest versions...");
|
||||
const topTags = sortedTags.slice(0, 20);
|
||||
topTags.map(tag => {
|
||||
const marker = tag === currentTag ? "--->" : " ";
|
||||
console.log(marker, tag);
|
||||
});
|
||||
|
||||
const latestTag = topTags[0];
|
||||
const isLatest = latestTag === currentTag;
|
||||
console.log();
|
||||
if (isLatest) {
|
||||
console.log("Thus, the container image for ", currentTag, "must be marked as latest.");
|
||||
} else {
|
||||
console.log("The latest container image stays as", latestTag);
|
||||
console.log("There is no need to tag the", currentTag, "container image as latest.");
|
||||
}
|
||||
return isLatest ? "latest" : "not-latest";
|
||||
|
||||
- name: Tag the container image as 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
|
||||
docker tag localhost:5000/local-metabase:${{ github.ref_name }} ${{ env.DOCKERHUB_REPO }}:latest
|
||||
docker push ${{ env.DOCKERHUB_REPO }}:latest
|
||||
echo "Finished!"
|
||||
|
||||
@@ -360,9 +242,6 @@ jobs:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: containerize
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
steps:
|
||||
- name: Login to Docker Hub # authenticated, to avoid being rate-throttled
|
||||
uses: docker/login-action@v2
|
||||
@@ -371,245 +250,38 @@ jobs:
|
||||
password: ${{ secrets.DOCKERHUB_RELEASE_TOKEN }}
|
||||
- name: Determine the container image to pull
|
||||
run: |
|
||||
if [[ "${{ matrix.edition }}" = "ee" ]]; then
|
||||
if [[ ${{ github.ref_name }} == v1* ]]; then
|
||||
echo "DOCKERHUB_REPO=${{ github.repository_owner }}/metabase-enterprise" >> $GITHUB_ENV
|
||||
else
|
||||
echo "DOCKERHUB_REPO=${{ github.repository_owner }}/metabase" >> $GITHUB_ENV
|
||||
fi
|
||||
- name: Determine the docker version tag
|
||||
uses: actions/github-script@v6
|
||||
id: canonical_version
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const version = '${{ inputs.version }}';
|
||||
const edition = '${{ matrix.edition }}';
|
||||
|
||||
const canonical_version = edition === "ee"
|
||||
? version.replace(/^v0\./, "v1.") // always e.g. v1.47.2
|
||||
: version.replace(/^v1\./, "v0."); // always e.g. v0.47.2
|
||||
|
||||
console.log("The canonical version of this Metabase", edition, "edition is", canonical_version);
|
||||
|
||||
return canonical_version;
|
||||
- name: Pull the container image
|
||||
run: |
|
||||
echo "Pulling container image ${{ env.DOCKERHUB_REPO }}:${{ steps.canonical_version.outputs.result }} ..."
|
||||
docker pull ${{ env.DOCKERHUB_REPO }}:${{ steps.canonical_version.outputs.result }}
|
||||
echo "Pulling container image ${{ env.DOCKERHUB_REPO }}:${{ github.ref_name }} ..."
|
||||
docker pull ${{ env.DOCKERHUB_REPO }}:${{ github.ref_name }}
|
||||
echo "Successful!"
|
||||
- name: Launch container
|
||||
run: docker run --rm -dp 3000:3000 ${{ env.DOCKERHUB_REPO }}:${{ steps.canonical_version.outputs.result }}
|
||||
run: docker run --rm -dp 3000:3000 ${{ env.DOCKERHUB_REPO }}:${{ github.ref_name }}
|
||||
timeout-minutes: 5
|
||||
- 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
|
||||
|
||||
push-tags:
|
||||
permissions: write-all
|
||||
needs: [verify-s3-download, verify-docker-pull, check-version]
|
||||
publish-elastic-beanstalk-artifacts:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
needs: containerize
|
||||
timeout-minutes: 15
|
||||
env:
|
||||
NO_SLACK: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: prepare release scripts
|
||||
run: cd release && yarn && yarn build
|
||||
- name: Tag Release
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
result-encoding: string
|
||||
script: | # js
|
||||
const { tagRelease } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const OSSversion = '${{ needs.check-version.outputs.oss }}';
|
||||
const EEversion = '${{ needs.check-version.outputs.ee }}';
|
||||
|
||||
// push EE tag
|
||||
await tagRelease({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: EEversion,
|
||||
commitHash: '${{ inputs.commit }}',
|
||||
}).catch((err) => {
|
||||
console.error('Failed to tag release', EEversion, err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
// push OSS tag
|
||||
await tagRelease({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: OSSversion,
|
||||
commitHash: '${{ inputs.commit }}',
|
||||
}).catch((err) => {
|
||||
console.error('Failed to tag release', OSSversion, err);
|
||||
process.exit(1);
|
||||
});
|
||||
- name: Reorder release tags to put OSS first
|
||||
run: |
|
||||
git config user.name github-actions
|
||||
git config user.email github-actions@github.com
|
||||
$GITHUB_WORKSPACE/release/reorder-tags.sh ${{ needs.check-version.outputs.ee }} ${{ inputs.commit }}
|
||||
|
||||
trigger-docs-update:
|
||||
needs: push-tags
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 10
|
||||
steps:
|
||||
- uses: actions/github-script@v6
|
||||
with:
|
||||
github-token: ${{ secrets.DOCS_UPDATE_TOKEN }}
|
||||
script: |
|
||||
github.rest.repos.createDispatchEvent({
|
||||
owner: '${{ github.repository_owner }}',
|
||||
repo: '${{ secrets.DOCS_REPO }}',
|
||||
event_type: 'trigger-docs-update',
|
||||
client_payload: {
|
||||
version: '${{ inputs.version }}'
|
||||
}
|
||||
});
|
||||
|
||||
draft-release-notes:
|
||||
needs: push-tags
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
permissions: write-all
|
||||
env:
|
||||
AWS_S3_DOWNLOADS_BUCKET: ${{ vars.AWS_S3_DOWNLOADS_BUCKET }}
|
||||
DOCKERHUB_OWNER: ${{ vars.DOCKERHUB_OWNER }}
|
||||
DOCKERHUB_REPO: ${{ vars.DOCKERHUB_REPO }}
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: prepare release scripts
|
||||
run: cd release && yarn && yarn build
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve uberjar artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Read Checksum
|
||||
run: |
|
||||
CHECKSUM=$(cat SHA256.sum)
|
||||
echo "CHECKSUM=$CHECKSUM" >> $GITHUB_ENV
|
||||
- name: Publish draft release notes
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const { publishRelease, getCanonicalVersion } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const version = '${{ inputs.version }}';
|
||||
const edition = '${{ matrix.edition }}';
|
||||
|
||||
const canonical_version = getCanonicalVersion(version, edition);
|
||||
|
||||
await publishRelease({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: canonical_version,
|
||||
checksum: '${{ env.CHECKSUM }}',
|
||||
}).then(() => {
|
||||
console.log('Successfully published release notes', '${{ inputs.version }}');
|
||||
}).catch((err) => {
|
||||
console.error('Failed to publish release notes', '${{ inputs.version }}', err);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
publish-version-info:
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [push-tags, check-version]
|
||||
timeout-minutes: 15
|
||||
strategy:
|
||||
matrix:
|
||||
edition: [oss, ee]
|
||||
env:
|
||||
AWS_S3_STATIC_BUCKET: ${{ vars.AWS_S3_STATIC_BUCKET }}
|
||||
AWS_REGION: ${{ vars.AWS_REGION }}
|
||||
steps:
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v3
|
||||
- name: Prepare back-end environment
|
||||
uses: ./.github/actions/prepare-backend
|
||||
- name: Configure AWS credentials for S3
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
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@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Publish release notes
|
||||
uses: actions/github-script@v6
|
||||
id: new_version_info
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const { getVersionInfo } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
const fs = require('fs');
|
||||
|
||||
const edition = '${{ matrix.edition }}';
|
||||
|
||||
const canonical_version = edition === 'ee'
|
||||
? '${{ needs.check-version.outputs.ee }}'
|
||||
: '${{ needs.check-version.outputs.oss }}';
|
||||
|
||||
const newVersionInfo = await getVersionInfo({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version: canonical_version,
|
||||
});
|
||||
|
||||
fs.writeFileSync('version-info.json', JSON.stringify(newVersionInfo));
|
||||
- name: Upload new version-info.json to S3
|
||||
run: |
|
||||
if [[ "${{ matrix.edition }}" == "ee" ]]; then
|
||||
aws s3 cp version-info.json s3://${{ vars.AWS_S3_STATIC_BUCKET }}/version-info-ee.json
|
||||
else
|
||||
aws s3 cp version-info.json s3://${{ vars.AWS_S3_STATIC_BUCKET }}/version-info.json
|
||||
fi
|
||||
- name: Create cloudfront invalidation for version-info.json and version-info-ee.json
|
||||
run: |
|
||||
aws cloudfront create-invalidation \
|
||||
--distribution-id ${{ vars.AWS_CLOUDFRONT_STATIC_ID }} \
|
||||
--paths "/version-info.json" "/version-info-ee.json"
|
||||
|
||||
manage-issues:
|
||||
permissions: write-all
|
||||
runs-on: ubuntu-22.04
|
||||
needs: [publish-version-info, draft-release-notes]
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
with:
|
||||
sparse-checkout: release
|
||||
- name: Prepare build scripts
|
||||
run: cd ${{ github.workspace }}/release && yarn && yarn build
|
||||
- name: Update milestones
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: | # js
|
||||
const { closeMilestone, openNextMilestones } = require('${{ github.workspace }}/release/dist/index.cjs');
|
||||
|
||||
const version = '${{ inputs.version }}';
|
||||
|
||||
await closeMilestone({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version,
|
||||
});
|
||||
|
||||
await openNextMilestones({
|
||||
github,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
version,
|
||||
});
|
||||
aws-region: us-east-1
|
||||
- name: Publish Elastic Beanstalk artifacts
|
||||
run: ./bin/ebs.sh :version ${{ github.ref_name }}
|
||||
|
||||
55
.github/workflows/rerun-workflows.yml
vendored
55
.github/workflows/rerun-workflows.yml
vendored
@@ -4,17 +4,13 @@ on:
|
||||
workflow_run:
|
||||
workflows: [Backend, Driver Tests, E2E Tests, Frontend]
|
||||
types: [completed]
|
||||
branches: [master, 'release-x.**', 'backport-**']
|
||||
branches: [master, 'release-**']
|
||||
|
||||
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. 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 }}
|
||||
AUTHOR_NAME: ${{ github.event.workflow_run.head_commit.author.name }}
|
||||
if: ${{ github.event.workflow_run.conclusion == 'failure' }}
|
||||
steps:
|
||||
- name: Generate job summary
|
||||
run: |
|
||||
@@ -25,19 +21,19 @@ jobs:
|
||||
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: lts/Hydrogen # 18.x.x
|
||||
node-version: '16'
|
||||
- run: npm install @slack/web-api
|
||||
- name: Trigger a re-run
|
||||
uses: actions/github-script@v6
|
||||
with:
|
||||
script: | # js
|
||||
script: |
|
||||
const MAX_ATTEMPTS = 2;
|
||||
const ATTEMPT = "${{ github.event.workflow_run.run_attempt }}";
|
||||
const BRANCH = "${{ github.event.workflow_run.head_branch }}";
|
||||
const FAILED_RUN_URL = "${{ github.event.workflow_run.html_url }}";
|
||||
const FAILED_RUN_NAME = "${{ github.event.workflow_run.name }}";
|
||||
const AUTHOR = "${{ github.event.workflow_run.head_commit.author.name }}";
|
||||
const BREAKING_COMMIT = "${{ github.event.workflow_run.head_sha }}";
|
||||
const AUTHOR = process.env.AUTHOR_NAME;
|
||||
const BRANCH = process.env.BRANCH_NAME;
|
||||
|
||||
if (ATTEMPT <= MAX_ATTEMPTS) {
|
||||
github.rest.actions.reRunWorkflowFailedJobs({
|
||||
@@ -52,27 +48,58 @@ jobs:
|
||||
|
||||
await slack.chat.postMessage({
|
||||
channel: 'engineering-ci',
|
||||
text: 'Failing tests',
|
||||
blocks: [
|
||||
{
|
||||
"type": "header",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": `:warning: CI is failing on ${BRANCH}`,
|
||||
"text": `:alert: CI is failing on ${BRANCH} :alert:`,
|
||||
"emoji": true,
|
||||
}
|
||||
},
|
||||
],
|
||||
attachments: [{
|
||||
color: BRANCH === 'master' ? '#f85149' : "#ffce33",
|
||||
color: '#f85149',
|
||||
blocks: [
|
||||
{
|
||||
"type": "section",
|
||||
"text": {
|
||||
"type": "mrkdwn",
|
||||
"text": `Commit <https://github.com/metabase/metabase/commit/${BREAKING_COMMIT}|${BREAKING_COMMIT.slice(0,7)}> by ${AUTHOR} has failing <${FAILED_RUN_URL}|${FAILED_RUN_NAME}> tests on the <https://github.com/metabase/metabase/commits/${BRANCH}|\`${BRANCH}\`> branch. :sad-panda:`
|
||||
"text": `Commit <https://github.com/metabase/metabase/commit/${BREAKING_COMMIT}|${BREAKING_COMMIT.slice(0,7)}> by ${AUTHOR} has failing <${FAILED_RUN_URL}|${FAILED_RUN_NAME}> tests on the \`${BRANCH}\` branch . :sad-panda:\nPlease fix ASAP. \n\nEmoji this message when it's fixed.`
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "actions",
|
||||
"elements": [
|
||||
{
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "Failing Commit",
|
||||
"emoji": true
|
||||
},
|
||||
"url": `https://github.com/metabase/metabase/commit/${BREAKING_COMMIT}`
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": `Recent commits to ${BRANCH}`,
|
||||
"emoji": true
|
||||
},
|
||||
"url": `https://github.com/metabase/metabase/commits/${BRANCH}`
|
||||
},
|
||||
{
|
||||
"type": "button",
|
||||
"text": {
|
||||
"type": "plain_text",
|
||||
"text": "Failed CI Run",
|
||||
"emoji": true
|
||||
},
|
||||
"url": `${FAILED_RUN_URL}`
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}]
|
||||
});
|
||||
|
||||
61
.github/workflows/set-announce-url.yml
vendored
61
.github/workflows/set-announce-url.yml
vendored
@@ -1,61 +0,0 @@
|
||||
name: Set Announcement URL
|
||||
run-name: Set Announcement URL - ${{ inputs.announcement-url }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
announcement-url:
|
||||
description: 'The URL of the announcement'
|
||||
type: string
|
||||
required: true
|
||||
|
||||
jobs:
|
||||
set-announce-url:
|
||||
runs-on: ubuntu-22.04
|
||||
timeout-minutes: 15
|
||||
steps:
|
||||
- name: Validate input
|
||||
if: ${{ !startsWith(inputs.announcement-url, 'http') }}
|
||||
run: |
|
||||
echo "announcement url must be a valid URL, got: ${{ inputs.announcement-url }}"
|
||||
exit 1
|
||||
|
||||
- name: Configure AWS credentials
|
||||
uses: aws-actions/configure-aws-credentials@v3
|
||||
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 }}
|
||||
- name: Update announcement url
|
||||
uses: actions/github-script@v6
|
||||
id: announce_url
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
// TODO: move this to the release/ directory when it exists
|
||||
const fs = require('fs');
|
||||
|
||||
const announcementUrl = '${{ inputs.announcement-url }}';
|
||||
|
||||
const OSSversionInfo = await fetch(`http://${{ vars.AWS_S3_STATIC_BUCKET }}.s3.${{ vars.AWS_REGION }}.amazonaws.com/version-info.json`).then(r => r.json());
|
||||
const EEversionInfo = await fetch(`http://${{ vars.AWS_S3_STATIC_BUCKET }}.s3.${{ vars.AWS_REGION }}.amazonaws.com/version-info-ee.json`).then(r => r.json());
|
||||
|
||||
OSSversionInfo.latest.announcement_url = announcementUrl;
|
||||
EEversionInfo.latest.announcement_url = announcementUrl;
|
||||
|
||||
if (!OSSversionInfo.older.length || !EEversionInfo.older.length) {
|
||||
throw new Error('No older versions found in version-info.json');
|
||||
}
|
||||
|
||||
fs.writeFileSync('version-info.json', JSON.stringify(OSSversionInfo));
|
||||
fs.writeFileSync('version-info-ee.json', JSON.stringify(EEversionInfo));
|
||||
|
||||
- name: Upload new version-info.json to s3
|
||||
run: |
|
||||
aws s3 cp version-info.json s3://${{ vars.AWS_S3_STATIC_BUCKET }}/version-info.json
|
||||
aws s3 cp version-info-ee.json s3://${{ vars.AWS_S3_STATIC_BUCKET }}/version-info-ee.json
|
||||
- name: Create cloudfront invalidation for version-info.json and version-info-ee.json
|
||||
run: |
|
||||
aws cloudfront create-invalidation \
|
||||
--distribution-id ${{ vars.AWS_CLOUDFRONT_STATIC_ID }} \
|
||||
--paths "/version-info.json" "/version-info-ee.json"
|
||||
8
.github/workflows/uberjar.yml
vendored
8
.github/workflows/uberjar.yml
vendored
@@ -45,8 +45,6 @@ jobs:
|
||||
run: ./bin/build.sh
|
||||
- name: Prepare uberjar artifact
|
||||
uses: ./.github/actions/prepare-uberjar-artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
|
||||
check_jar_health:
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -68,7 +66,7 @@ jobs:
|
||||
- uses: actions/download-artifact@v3
|
||||
name: Retrieve uberjar artifact
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
- name: Launch uberjar
|
||||
run: java -jar ./target/uberjar/metabase.jar &
|
||||
- name: Wait for Metabase to start
|
||||
@@ -100,7 +98,7 @@ jobs:
|
||||
- name: Download uploaded artifacts to insert into container
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
path: bin/docker/
|
||||
- name: Move the ${{ matrix.edition }} uberjar to the context dir
|
||||
run: mv bin/docker/target/uberjar/metabase.jar bin/docker/.
|
||||
@@ -218,7 +216,7 @@ jobs:
|
||||
- name: Download uploaded artifacts to insert into container
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: metabase-${{ matrix.edition }}-${{ github.sha }}-uberjar
|
||||
name: metabase-${{ matrix.edition }}-uberjar
|
||||
path: bin/docker/
|
||||
- name: Move the ${{ matrix.edition }} uberjar to the context dir
|
||||
run: mv bin/docker/target/uberjar/metabase.jar bin/docker/.
|
||||
|
||||
15
.gitignore
vendored
15
.gitignore
vendored
@@ -12,7 +12,6 @@
|
||||
.eastwood
|
||||
.idea/
|
||||
.nrepl-port
|
||||
.portal
|
||||
.vscode
|
||||
/*.h2.db
|
||||
/*.lock.db
|
||||
@@ -26,7 +25,6 @@
|
||||
/.lein-repl-history
|
||||
/.sqlite.db
|
||||
/backend-checksums.txt
|
||||
/backend-docs/uberdoc.html
|
||||
/build.xml
|
||||
/checkouts
|
||||
/classes
|
||||
@@ -34,6 +32,7 @@
|
||||
/crate-*
|
||||
/cypress
|
||||
/deploy/artifacts/*
|
||||
/docs/uberdoc.html
|
||||
/frontend/test/snapshots/*
|
||||
/e2e/snapshots/*
|
||||
/lein-plugins/*/target
|
||||
@@ -75,25 +74,17 @@ xcuserdata
|
||||
dev/src/dev/nocommit/
|
||||
*~
|
||||
**/cypress_sample_database.json
|
||||
**/cypress_sample_instance_data.json
|
||||
/frontend/src/cljs
|
||||
/frontend/src/cljs_release
|
||||
.shadow-cljs
|
||||
.clerk
|
||||
|
||||
# lsp: ignore all but the config file
|
||||
.lsp/*
|
||||
!.lsp/config.edn
|
||||
modules/drivers/*/.lsp/*
|
||||
!modules/drivers/*/.lsp/config.edn
|
||||
**/.clj-kondo/.cache
|
||||
|
||||
# Editor- or environment-specific local files
|
||||
.clj-kondo/.cache
|
||||
*.code-workspace
|
||||
.java-version
|
||||
|
||||
.calva/
|
||||
|
||||
# malli + clj-kondo: ignore malli-types
|
||||
.clj-kondo/metosin/malli-types-clj
|
||||
|
||||
.github/static-viz-sources.yaml
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
{:keep-require-at-start? true
|
||||
:show-docs-arity-on-same-line? true
|
||||
:project-specs [{:project-path "deps.edn"
|
||||
:classpath-cmd ["clojure"
|
||||
"-A:dev:ee:ee-dev:drivers:drivers-dev:build:build/release:build/all"
|
||||
"-Spath"]}]
|
||||
:classpath-cmd ["clojure" "-A:dev:ee:ee-dev:drivers:drivers-dev" "-Spath"]}]
|
||||
:clean {:ns-inner-blocks-indentation :keep}
|
||||
:linters {:clojure-lsp/unused-public-var {:level :warning
|
||||
:exclude-when-defined-by
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||
const appConfig = require("../webpack.config");
|
||||
|
||||
module.exports = {
|
||||
@@ -16,7 +15,6 @@ module.exports = {
|
||||
],
|
||||
webpackFinal: storybookConfig => ({
|
||||
...storybookConfig,
|
||||
plugins: [...storybookConfig.plugins, new MiniCssExtractPlugin()],
|
||||
module: {
|
||||
...storybookConfig.module,
|
||||
rules: [
|
||||
|
||||
@@ -1,9 +1,5 @@
|
||||
<style>
|
||||
<style type="text/css">
|
||||
:root {
|
||||
--default-font-family: "Lato";
|
||||
--color-brand: #509ee3;
|
||||
--color-brand-alpha-04: rgba(80, 158, 227, 0.04);
|
||||
--color-brand-alpha-88: rgba(80, 158, 227, 0.88);
|
||||
--color-focus: #cbe2f7;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import React from "react";
|
||||
import "metabase/css/index.css";
|
||||
import "metabase/lib/dayjs";
|
||||
import { ThemeProvider } from "metabase/ui";
|
||||
|
||||
export const parameters = {
|
||||
actions: { argTypesRegex: "^on[A-Z].*" },
|
||||
@@ -12,7 +9,3 @@ export const parameters = {
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export const decorators = [
|
||||
renderStory => <ThemeProvider>{renderStory()}</ThemeProvider>,
|
||||
];
|
||||
16
.vscode/settings.json
vendored
16
.vscode/settings.json
vendored
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
"grunt.autoDetect": "off",
|
||||
"jake.autoDetect": "off",
|
||||
"gulp.autoDetect": "off",
|
||||
"npm.autoDetect": "off",
|
||||
"eslint.options": {
|
||||
"rulePaths": ["frontend/lint/eslint-rules/"]
|
||||
}
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
"grunt.autoDetect": "off",
|
||||
"jake.autoDetect": "off",
|
||||
"gulp.autoDetect": "off",
|
||||
"npm.autoDetect": "off",
|
||||
"eslint.options": {
|
||||
"rulePaths": ["frontend/lint/eslint-rules/"]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# STAGE 1: builder
|
||||
###################
|
||||
|
||||
FROM node:18-bullseye as builder
|
||||
FROM node:16-slim as builder
|
||||
|
||||
ARG MB_EDITION=oss
|
||||
|
||||
|
||||
35
README.md
35
README.md
@@ -33,40 +33,7 @@ Metabase can be run just about anywhere. Check out our [Installation Guides](htt
|
||||
|
||||
## Contributing
|
||||
|
||||
## Quick Setup: Dev environment
|
||||
|
||||
In order to spin up a development environment, you need to start the front end and the backend as follows:
|
||||
|
||||
### Frontend quick setup
|
||||
|
||||
The following command will install the Javascript dependencies:
|
||||
|
||||
```
|
||||
$ yarn install
|
||||
```
|
||||
|
||||
To build and run without watching changes:
|
||||
|
||||
```
|
||||
$ yarn build
|
||||
```
|
||||
|
||||
To build and run with hot-reload:
|
||||
|
||||
```
|
||||
$ yarn build-hot
|
||||
```
|
||||
|
||||
### Backend quick setup
|
||||
|
||||
In order to run the backend, you'll need to build the drivers first, and then start the backend:
|
||||
|
||||
```
|
||||
$ ./bin/build-drivers.sh
|
||||
$ clojure -M:run
|
||||
```
|
||||
|
||||
For a more detailed setup of a dev environment for Metabase, check out our [Developers Guide](./docs/developers-guide/start.md).
|
||||
To get started with a development installation of the Metabase, check out our [Developers Guide](https://www.metabase.com/docs/latest/developers-guide/start).
|
||||
|
||||
## Internationalization
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"@babel/preset-env",
|
||||
[
|
||||
"@babel/preset-react",
|
||||
{ "runtime": "automatic" }
|
||||
{ "runtime": "automatic", "importSource": "@emotion/react" }
|
||||
],
|
||||
"@babel/preset-typescript"
|
||||
],
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
"xalan" {:resource "apache2_0.txt"}}
|
||||
|
||||
"amalloy" {"ring-gzip-middleware" {:resource "MIT.txt"}}
|
||||
"buddy" {"buddy-core" {:resource "apache2_0.txt"}
|
||||
"buddy-sign" {:resource "apache2_0.txt"}}
|
||||
"buddy" {"buddy-core" {:resource "apache2_0.txt"}}
|
||||
"colorize" {"colorize" {:resource "EPL.txt"}}
|
||||
"com.github.jnr" {"jffi$native" {:resource "apache2_0.txt"}}
|
||||
"com.google.api-client" {"google-api-client" {:resource "apache2_0.txt"}}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
[build-drivers :as build-drivers]
|
||||
[build.licenses :as license]
|
||||
[build.uberjar :as uberjar]
|
||||
[build.version-properties :as version-properties]
|
||||
[build.version-info :as version-info]
|
||||
[clojure.edn :as edn]
|
||||
[clojure.java.io :as io]
|
||||
[clojure.string :as str]
|
||||
@@ -87,7 +87,7 @@
|
||||
(def all-steps
|
||||
(ordered-map/ordered-map
|
||||
:version (fn [{:keys [edition version]}]
|
||||
(version-properties/generate-version-properties-file! edition version))
|
||||
(version-info/generate-version-info-file! edition version))
|
||||
:translations (fn [_]
|
||||
(i18n/create-all-artifacts!))
|
||||
:frontend (fn [{:keys [edition]}]
|
||||
@@ -108,7 +108,7 @@
|
||||
:or {edition (edition-from-env-var)
|
||||
steps (keys all-steps)}}]
|
||||
(let [version (or version
|
||||
(version-properties/current-snapshot-version edition))]
|
||||
(version-info/current-snapshot-version edition))]
|
||||
(u/step (format "Running build steps for %s version %s: %s"
|
||||
(case edition
|
||||
:oss "Community (OSS) Edition"
|
||||
|
||||
@@ -64,20 +64,14 @@
|
||||
ns-decls))
|
||||
|
||||
(defn metabase-namespaces-in-topo-order [basis]
|
||||
(let [ns-decls (into []
|
||||
(comp (map io/file)
|
||||
(mapcat ns.find/find-ns-decls-in-dir))
|
||||
(all-paths basis))
|
||||
ns-symbols (into #{} (map ns.parse/name-from-ns-decl) ns-decls)
|
||||
sorted (->> (dependencies-graph ns-decls)
|
||||
ns.deps/topo-sort
|
||||
(filter ns-symbols))
|
||||
orphans (remove (set sorted) ns-symbols)
|
||||
all (concat orphans sorted)]
|
||||
(assert (contains? (set all) 'metabase.bootstrap))
|
||||
(when (contains? ns-symbols 'metabase-enterprise.core)
|
||||
(assert (contains? (set all) 'metabase-enterprise.core)))
|
||||
all))
|
||||
(let [ns-decls (mapcat
|
||||
(comp ns.find/find-ns-decls-in-dir io/file)
|
||||
(all-paths basis))
|
||||
ns-symbols (set (map ns.parse/name-from-ns-decl ns-decls))]
|
||||
(->> (dependencies-graph ns-decls)
|
||||
ns.deps/topo-sort
|
||||
(filter ns-symbols)
|
||||
(cons 'metabase.bootstrap))))
|
||||
|
||||
(defn compile-sources! [basis]
|
||||
(u/step "Compile Clojure source files"
|
||||
@@ -86,26 +80,27 @@
|
||||
ns-decls (u/step "Determine compilation order for Metabase files"
|
||||
(metabase-namespaces-in-topo-order basis))]
|
||||
(with-duration-ms [duration-ms]
|
||||
(b/compile-clj {:basis basis
|
||||
:src-dirs paths
|
||||
:class-dir class-dir
|
||||
:ns-compile ns-decls})
|
||||
(b/compile-clj {:basis basis
|
||||
:src-dirs paths
|
||||
:class-dir class-dir
|
||||
:ns-compile ns-decls
|
||||
:compile-opts {:direct-linking true}})
|
||||
(u/announce "Finished compilation in %.1f seconds." (/ duration-ms 1000.0))))))
|
||||
|
||||
(defn copy-resources! [edition basis]
|
||||
(u/step "Copy resources"
|
||||
;; technically we don't NEED to copy the Clojure source files but it doesn't really hurt anything IMO.
|
||||
(doseq [path (all-paths basis)]
|
||||
(when (not (#{"src" "shared/src" "enterprise/backend/src"} path))
|
||||
(u/step (format "Copy %s" path)
|
||||
(b/copy-dir {:target-dir class-dir, :src-dirs [path]}))))))
|
||||
(u/step (format "Copy %s" path)
|
||||
(b/copy-dir {:target-dir class-dir, :src-dirs [path]})))))
|
||||
|
||||
(defn create-uberjar! [basis]
|
||||
(u/step "Create uberjar"
|
||||
(with-duration-ms [duration-ms]
|
||||
(depstar/uber {:class-dir class-dir
|
||||
:uber-file uberjar-filename
|
||||
:basis basis
|
||||
:exclude [".*metabase.*.clj[c|s]?$"]})
|
||||
(depstar/uber {:class-dir class-dir
|
||||
:uber-file uberjar-filename
|
||||
:basis basis
|
||||
:compile-opts {:direct-linking true}})
|
||||
(u/announce "Created uberjar in %.1f seconds." (/ duration-ms 1000.0)))))
|
||||
|
||||
(def manifest-entries
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns build.version-properties
|
||||
(ns build.version-info
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[metabuild-common.core :as u]))
|
||||
@@ -32,6 +32,7 @@
|
||||
(str \v version)
|
||||
version)
|
||||
:hash (git-hash)
|
||||
:branch (git-branch)
|
||||
:date (git-last-commit-date)}]
|
||||
(str (name k) \= v))))
|
||||
|
||||
@@ -69,10 +70,10 @@
|
||||
(format "v%d.%d.%d-SNAPSHOT" major minor patch))
|
||||
"UNKNOWN")))
|
||||
|
||||
(defn generate-version-properties-file!
|
||||
(defn generate-version-info-file!
|
||||
"Generate version.properties file"
|
||||
([edition]
|
||||
(generate-version-properties-file! edition (current-snapshot-version edition)))
|
||||
(generate-version-info-file! edition (current-snapshot-version edition)))
|
||||
|
||||
([edition version]
|
||||
(u/delete-file-if-exists! version-properties-filename)
|
||||
@@ -61,7 +61,7 @@
|
||||
'metabase.shared.util.i18n/trs})
|
||||
|
||||
(def ^:private plural-translation-macro-names
|
||||
#{"trsn" "trun" "deferred-trsn" "deferred-trun"})
|
||||
#{"trsn" "trsu" "deferred-trsn" "deferred-trun"})
|
||||
|
||||
(s/def ::translate (s/and
|
||||
(complement vector?)
|
||||
@@ -90,7 +90,7 @@
|
||||
(apply str (rest i18n-string)))]
|
||||
(merge {:message message}
|
||||
(when (string? pl-i18n-string)
|
||||
{:message-pl pl-i18n-string})))))
|
||||
{:message-pl i18n-string})))))
|
||||
|
||||
(defn- analyze-translations
|
||||
"Takes roots to grasp returning a map of :file, :line, :original (the original form), and :message. If identifying the
|
||||
|
||||
@@ -40,6 +40,7 @@
|
||||
assert-file-exists
|
||||
copy-file!
|
||||
create-directory-unless-exists!
|
||||
delete-file!
|
||||
delete-file-if-exists!
|
||||
download-file!
|
||||
file-exists?
|
||||
|
||||
@@ -49,6 +49,12 @@
|
||||
([file & more]
|
||||
(dorun (map delete-file-if-exists! (cons file more)))))
|
||||
|
||||
(defn ^:deprecated delete-file!
|
||||
"Alias for `delete-file-if-exists!`. Here for backwards compatibility. Prefer `delete-file-if-exists!` going
|
||||
forward."
|
||||
[& args]
|
||||
(apply delete-file-if-exists! args))
|
||||
|
||||
(defn copy-file!
|
||||
"Copy a `source` file (or directory, recursively) to `dest`."
|
||||
[^String source ^String dest]
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
(:import
|
||||
(java.io BufferedReader File InputStreamReader)))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn- read-lines [^java.io.BufferedReader reader {:keys [quiet? err?]}]
|
||||
(loop [lines []]
|
||||
(if-let [line (.readLine reader)]
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
[release.common :as c]
|
||||
[release.common.slack :as slack]
|
||||
[release.draft-release :as draft-release]
|
||||
[release.elastic-beanstalk :as eb]
|
||||
[release.git-tags :as git-tags]
|
||||
[release.set-build-options :as set-build-options]
|
||||
[release.uberjar :as uberjar]
|
||||
@@ -21,6 +22,7 @@
|
||||
:upload-uberjar uberjar/upload-uberjar!
|
||||
:push-git-tags git-tags/push-tags!
|
||||
:publish-draft-release draft-release/create-draft-release!
|
||||
:publish-elastic-beanstalk-artifacts eb/publish-elastic-beanstalk-artifacts!
|
||||
:update-version-info version-info/update-version-info!))
|
||||
|
||||
(defn- do-steps! [steps]
|
||||
@@ -45,3 +47,12 @@
|
||||
(let [steps (or (seq (map u/parse-as-keyword steps))
|
||||
(keys steps*))]
|
||||
(do-steps! steps))))
|
||||
|
||||
(defn publish-ebs [args]
|
||||
(u/exit-when-finished-nonzero-on-exception
|
||||
(let [version (:version args)]
|
||||
(c/set-version! version)
|
||||
(c/set-edition! (if (str/starts-with? (c/version) "0") :oss :ee))
|
||||
(c/set-branch! "release-x.y.z") ;; FIXME: branch is irrelevant for CD run
|
||||
(u/announce (format "Preparing Elastic Beanstalk artifacts for version %s" (c/version)))
|
||||
(do-steps! [:publish-elastic-beanstalk-artifacts]))))
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
(defn github-api-request-headers []
|
||||
{"Content-Type" "application/json"
|
||||
"Authorization" (format "Bearer %s" (u/env-or-throw :github-token))})
|
||||
"Authorization" (format "token %s" (u/env-or-throw :github-token))})
|
||||
|
||||
(defn- GET [endpoint]
|
||||
(-> (http/get (str (github-api-base) endpoint) {:headers (github-api-request-headers)})
|
||||
|
||||
115
bin/build/src/release/elastic_beanstalk.clj
Normal file
115
bin/build/src/release/elastic_beanstalk.clj
Normal file
@@ -0,0 +1,115 @@
|
||||
(ns release.elastic-beanstalk
|
||||
"Code related to building and publishing Elastic Beanstalk artifacts."
|
||||
(:require
|
||||
[cheshire.core :as json]
|
||||
[clojure.core.cache :as cache]
|
||||
[metabuild-common.core :as u]
|
||||
[release.common :as c]
|
||||
[release.common.http :as common.http]
|
||||
[release.common.upload :as common.upload]
|
||||
[stencil.core :as stencil]
|
||||
[stencil.loader]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
;; Disable caching of our template files for easier REPL debugging, we're only rendering them once anyways
|
||||
(stencil.loader/set-cache (cache/ttl-cache-factory {} :ttl 0))
|
||||
|
||||
;; create a ZIP file with the contents
|
||||
;; metabase-aws-eb.zip
|
||||
;; ├─ Dockerrun.aws.json
|
||||
;; ├─ .ebextensions/
|
||||
;; ├─ 01_metabase.config
|
||||
;; ├─ metabase_config/
|
||||
;; ├─ (a bunch of other stuff)
|
||||
|
||||
(def ^:private eb-extensions-source
|
||||
"Source location of the .ebextensions directory"
|
||||
(u/assert-file-exists (u/filename c/root-directory "bin" "build" "src" "release" "elastic_beanstalk" ".ebextensions")))
|
||||
|
||||
(def ^:private eb-platform-source
|
||||
"Source location of the .ebextensions directory"
|
||||
(u/assert-file-exists (u/filename c/root-directory "bin" "build" "src" "release" "elastic_beanstalk" ".platform")))
|
||||
|
||||
(def ^:private archive-temp-dir
|
||||
"Path where we'll put the contents of the ZIP file before we create it."
|
||||
"/tmp/metabase-aws-eb")
|
||||
|
||||
(def ^:private archive-path "/tmp/metabase-aws-eb.zip")
|
||||
(def ^:private html-file-path "/tmp/launch-aws-eb.html")
|
||||
|
||||
(defn- validate-json-docker-tag []
|
||||
(u/step (format "Check that Dockerrun.aws.json Docker tag is %s" (c/docker-tag))
|
||||
(u/step "Download archive"
|
||||
(u/download-file! (c/artifact-download-url "metabase-aws-eb.zip") archive-path))
|
||||
(u/step "Unzip archive"
|
||||
(u/delete-file-if-exists! archive-temp-dir)
|
||||
(u/sh "unzip" (u/assert-file-exists archive-path) "-d" archive-temp-dir))
|
||||
(u/step "Validate JSON file"
|
||||
(let [json (-> (u/assert-file-exists (u/filename (u/assert-file-exists archive-temp-dir) "Dockerrun.aws.json"))
|
||||
slurp
|
||||
(json/parse-string true))
|
||||
tag (get-in json [:Image :Name])]
|
||||
(u/announce "Docker tag is %s" tag)
|
||||
(when-not (= tag (c/docker-tag))
|
||||
(throw (ex-info "Incorrect Docker tag." {:expected (c/docker-tag)
|
||||
:actual tag
|
||||
:json json})))))))
|
||||
|
||||
(defn- validate-elastic-beanstalk-artifacts []
|
||||
(u/step "Validate Elastic Beanstalk artifacts"
|
||||
(common.http/check-url-exists (c/artifact-download-url "launch-aws-eb.html"))
|
||||
(common.http/check-url-exists (c/artifact-download-url "metabase-aws-eb.zip"))
|
||||
(validate-json-docker-tag)
|
||||
(u/announce "Artifacts validated.")))
|
||||
|
||||
(defn- dockerrun-json-content []
|
||||
{:AWSEBDockerrunVersion "1"
|
||||
:Image {:Name (c/docker-tag)
|
||||
:Update "true"}
|
||||
:Ports [{:ContainerPort "3000"}]
|
||||
:Logging "/var/log/metabase"})
|
||||
|
||||
(defn- create-archive! []
|
||||
(u/step (format "Create metabase-aws-eb.zip for Docker image %s" (c/docker-tag))
|
||||
(u/step "Create temp dir"
|
||||
(u/delete-file-if-exists! archive-temp-dir)
|
||||
(u/create-directory-unless-exists! archive-temp-dir))
|
||||
(u/step "Generate Dockerrun.aws.json"
|
||||
(spit (u/filename archive-temp-dir "Dockerrun.aws.json")
|
||||
(json/generate-string (dockerrun-json-content) {:pretty true})))
|
||||
(u/step "Copy .ebextensions"
|
||||
(u/copy-file! eb-extensions-source (u/filename archive-temp-dir ".ebextensions")))
|
||||
(u/step "Copy .platform"
|
||||
(u/copy-file! eb-platform-source (u/filename archive-temp-dir ".platform")))
|
||||
(u/step "Create metabase-aws-eb.zip"
|
||||
(u/delete-file-if-exists! archive-path)
|
||||
(u/sh {:dir archive-temp-dir} "zip" "--recurse-paths" archive-path ".")
|
||||
(u/assert-file-exists archive-path))))
|
||||
|
||||
(def ^:private launch-template-filename
|
||||
(u/assert-file-exists (u/filename c/root-directory "bin" "build" "src" "release" "elastic_beanstalk" "launch-aws-eb.html.template")))
|
||||
|
||||
(defn- create-html-file! []
|
||||
(u/step (format "Create launch-aws-eb.html for Docker image %s" (c/docker-tag))
|
||||
(u/delete-file-if-exists! html-file-path)
|
||||
(spit html-file-path
|
||||
(stencil/render (slurp launch-template-filename)
|
||||
{:url (java.net.URLEncoder/encode (c/artifact-download-url "metabase-aws-eb.zip")
|
||||
"UTF-8")}))
|
||||
(u/assert-file-exists html-file-path)))
|
||||
|
||||
(defn- upload-artifacts! []
|
||||
(u/step "Upload Elastic Beanstalk artifacts"
|
||||
(u/step "Upload metabase-aws-eb.zip"
|
||||
(common.upload/upload-artifact! archive-path "metabase-aws-eb.zip"))
|
||||
(u/step "Upload launch-aws-eb.html"
|
||||
(common.upload/upload-artifact! html-file-path "launch-aws-eb.html"))))
|
||||
|
||||
;; TODO -- we should merge the EB build logic into this script, it's still an ancient bash script
|
||||
(defn publish-elastic-beanstalk-artifacts! []
|
||||
(u/step "Create and publish Elastic Beanstalk artifacts"
|
||||
(create-archive!)
|
||||
(create-html-file!)
|
||||
(upload-artifacts!))
|
||||
(validate-elastic-beanstalk-artifacts))
|
||||
@@ -0,0 +1,37 @@
|
||||
######
|
||||
# Metabase Report server Elastic Beanstalk configuration
|
||||
# Modify the environmental variables below to customize your installation
|
||||
# Comment out a variable to disable a feature
|
||||
#####
|
||||
|
||||
container_commands:
|
||||
01-persist_env_vars:
|
||||
command: ".ebextensions/metabase_config/metabase-setup.sh set_up_env_vars"
|
||||
ignoreErrors: false
|
||||
|
||||
02_install_papertrail:
|
||||
command: ".ebextensions/metabase_config/metabase-setup.sh install_papertrail"
|
||||
test: test $PAPERTRAIL_HOST
|
||||
ignoreErrors: true
|
||||
|
||||
03_try_papertrail:
|
||||
command: "/sbin/service remote_syslog restart"
|
||||
test: test -e /etc/log_files.yml
|
||||
ignoreErrors: true
|
||||
|
||||
04_install_inspector:
|
||||
command: yum -q list installed AwsAgent &>/dev/null && echo "Inspector installed, nothing to do here" || curl -O https://inspector-agent.amazonaws.com/linux/latest/install | sudo bash
|
||||
ignoreErrors: true
|
||||
|
||||
05-install_cloudwatch_agent:
|
||||
command: sudo yum update && sudo yum upgrade -y && yum -q list installed amazon-cloudwatch-agent &>/dev/null && echo "Cloudwatch agent installed, nothing to do here" || sudo yum -y install https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
|
||||
ignoreErrors: true
|
||||
|
||||
06-run_cloudwatch_agent:
|
||||
command: sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:.ebextensions/metabase_config/cloudwatch/config.json -s
|
||||
ignoreErrors: true
|
||||
|
||||
# NGINX will be disabled in future releases, this will make the trick
|
||||
#option_settings:
|
||||
# aws:elasticbeanstalk:environment:proxy:
|
||||
# ProxyServer: "none"
|
||||
@@ -0,0 +1,134 @@
|
||||
{
|
||||
"agent": {
|
||||
"metrics_collection_interval": 60
|
||||
},
|
||||
"metrics": {
|
||||
"namespace": "Metabase",
|
||||
"metrics_collected": {
|
||||
"cpu": {
|
||||
"measurement": [
|
||||
"time_active",
|
||||
"time_guest",
|
||||
"time_guest_nice",
|
||||
"time_idle",
|
||||
"time_iowait",
|
||||
"time_irq",
|
||||
"time_nice",
|
||||
"time_softirq",
|
||||
"time_steal",
|
||||
"time_system",
|
||||
"time_user",
|
||||
"usage_active",
|
||||
"usage_guest",
|
||||
"usage_guest_nice",
|
||||
"usage_idle",
|
||||
"usage_iowait",
|
||||
"usage_irq",
|
||||
"usage_nice",
|
||||
"usage_softirq",
|
||||
"usage_steal",
|
||||
"usage_system",
|
||||
"usage_user"
|
||||
],
|
||||
"totalcpu": false
|
||||
},
|
||||
"disk": {
|
||||
"measurement": [
|
||||
"free",
|
||||
"total",
|
||||
"used",
|
||||
"used_percent",
|
||||
"inodes_free",
|
||||
"inodes_used",
|
||||
"inodes_total"
|
||||
],
|
||||
"ignore_file_system_types": [
|
||||
"sysfs", "devtmpfs"
|
||||
] },
|
||||
"diskio": {
|
||||
"measurement": [
|
||||
"reads",
|
||||
"writes",
|
||||
"read_bytes",
|
||||
"write_bytes",
|
||||
"read_time",
|
||||
"write_time",
|
||||
"io_time",
|
||||
"iops_in_progress"
|
||||
]
|
||||
},
|
||||
"swap": {
|
||||
"measurement": [
|
||||
"free",
|
||||
"used",
|
||||
"used_percent"
|
||||
]
|
||||
},
|
||||
"mem": {
|
||||
"measurement": [
|
||||
"active",
|
||||
"available",
|
||||
"available_percent",
|
||||
"buffered",
|
||||
"cached",
|
||||
"free",
|
||||
"inactive",
|
||||
"total",
|
||||
"used",
|
||||
"used_percent"
|
||||
]
|
||||
},
|
||||
"net": {
|
||||
"measurement": [
|
||||
"bytes_sent",
|
||||
"bytes_recv",
|
||||
"drop_in",
|
||||
"drop_out",
|
||||
"err_in",
|
||||
"err_out",
|
||||
"packets_sent",
|
||||
"packets_recv"
|
||||
]
|
||||
},
|
||||
"netstat": {
|
||||
"measurement": [
|
||||
"tcp_close",
|
||||
"tcp_close_wait",
|
||||
"tcp_closing",
|
||||
"tcp_established",
|
||||
"tcp_fin_wait1",
|
||||
"tcp_fin_wait2",
|
||||
"tcp_last_ack",
|
||||
"tcp_listen",
|
||||
"tcp_none",
|
||||
"tcp_syn_sent",
|
||||
"tcp_syn_recv",
|
||||
"tcp_time_wait",
|
||||
"udp_socket"
|
||||
]
|
||||
},
|
||||
"processes": {
|
||||
"measurement": [
|
||||
"blocked",
|
||||
"dead",
|
||||
"idle",
|
||||
"paging",
|
||||
"running",
|
||||
"sleeping",
|
||||
"stopped",
|
||||
"total",
|
||||
"total_threads",
|
||||
"wait",
|
||||
"zombies"
|
||||
]
|
||||
}
|
||||
},
|
||||
"append_dimensions": {
|
||||
"ImageId": "${aws:ImageId}",
|
||||
"InstanceId": "${aws:InstanceId}",
|
||||
"InstanceType": "${aws:InstanceType}",
|
||||
"AutoScalingGroupName": "${aws:AutoScalingGroupName}"
|
||||
},
|
||||
"aggregation_dimensions" : [["InstanceId"], ["InstanceType"], ["InstanceId","InstanceType"]]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
#!/bin/bash
|
||||
####
|
||||
# Metabase Report server Elastic Beanstalk metabase-setup.sh
|
||||
# Modify the environmental variables to customize your installation
|
||||
# Unset a variable to disable a feature
|
||||
####
|
||||
|
||||
set_up_env_vars () {
|
||||
# /opt/elasticbeanstalk/bin/get-config environment | jq -r 'to_entries | .[] | "export \(.key)=\"\(.value)\""' > /etc/profile.d/sh.local
|
||||
if grep -q "Amazon Linux 2" /etc/os-release; then
|
||||
if [ ! -z "$RDS_HOSTNAME" ]; then
|
||||
# sed -i 's/RDS_HOSTNAME/MB_DB_HOST/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_HOSTNAME/MB_DB_HOST/' /opt/elasticbeanstalk/deployment/env.list
|
||||
# sed -i 's/RDS_USERNAME/MB_DB_USER/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_USERNAME/MB_DB_USER/' /opt/elasticbeanstalk/deployment/env.list
|
||||
# sed -i 's/RDS_PASSWORD/MB_DB_PASS/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_PASSWORD/MB_DB_PASS/' /opt/elasticbeanstalk/deployment/env.list
|
||||
# sed -i 's/RDS_PORT/MB_DB_PORT/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_PORT/MB_DB_PORT/' /opt/elasticbeanstalk/deployment/env.list
|
||||
# sed -i 's/RDS_DB_NAME/MB_DB_DBNAME/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_DB_NAME/MB_DB_DBNAME/' /opt/elasticbeanstalk/deployment/env.list
|
||||
if [ "$RDS_PORT" == "3306" ]; then
|
||||
# echo 'export MB_DB_TYPE="mysql"' >> /etc/profile.d/sh.local
|
||||
echo 'MB_DB_TYPE=mysql' >> /opt/elasticbeanstalk/deployment/env.list
|
||||
else
|
||||
# echo 'export MB_DB_TYPE="postgres"' >> /etc/profile.d/sh.local
|
||||
echo 'MB_DB_TYPE=postgres' >> /opt/elasticbeanstalk/deployment/env.list
|
||||
fi
|
||||
fi
|
||||
else
|
||||
if [ ! -z "$RDS_HOSTNAME" ]; then
|
||||
# sed -i 's/RDS_HOSTNAME/MB_DB_HOST/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_HOSTNAME/MB_DB_HOST/' /opt/elasticbeanstalk/deploy/configuration/containerconfiguration
|
||||
# sed -i 's/RDS_USERNAME/MB_DB_USER/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_USERNAME/MB_DB_USER/' /opt/elasticbeanstalk/deploy/configuration/containerconfiguration
|
||||
# sed -i 's/RDS_PASSWORD/MB_DB_PASS/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_PASSWORD/MB_DB_PASS/' /opt/elasticbeanstalk/deploy/configuration/containerconfiguration
|
||||
# sed -i 's/RDS_PORT/MB_DB_PORT/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_PORT/MB_DB_PORT/' /opt/elasticbeanstalk/deploy/configuration/containerconfiguration
|
||||
# sed -i 's/RDS_DB_NAME/MB_DB_DBNAME/' /etc/profile.d/sh.local
|
||||
sed -i 's/RDS_DB_NAME/MB_DB_DBNAME/' /opt/elasticbeanstalk/deploy/configuration/containerconfiguration
|
||||
if [ "$RDS_PORT" == "3306" ]; then
|
||||
# echo 'export MB_DB_TYPE="mysql"' >> /etc/profile.d/sh.local
|
||||
sed -i 's/}}}}/,"MB_DB_TYPE":"mysql"}}}}/' /opt/elasticbeanstalk/deploy/configuration/containerconfiguration
|
||||
else
|
||||
# echo 'export MB_DB_TYPE="postgres"' >> /etc/profile.d/sh.local
|
||||
sed -i 's/}}}}/,"MB_DB_TYPE":"postgres"}}}}/' /opt/elasticbeanstalk/deploy/configuration/containerconfiguration
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# add files to papertrail
|
||||
pt_files () {
|
||||
sed -i '/ - .*/d' /etc/log_files.yml
|
||||
set -f
|
||||
for file in $PAPERTRAIL_FILES; do
|
||||
sed -i 's|files:|files:\n - '$file'|' /etc/log_files.yml
|
||||
done
|
||||
set +f
|
||||
}
|
||||
|
||||
# papertail remote host
|
||||
pt_remote_host () {
|
||||
sed -i "s/.*host:.*/ host: $PAPERTRAIL_HOST/" /etc/log_files.yml
|
||||
}
|
||||
|
||||
# papertail remote port
|
||||
pt_port () {
|
||||
sed -i "s/.*port:.*/ port: $PAPERTRAIL_PORT/" /etc/log_files.yml
|
||||
}
|
||||
|
||||
# papertail local host
|
||||
pt_local_host () {
|
||||
eval export PAPERTRAIL_HOSTNAME=$PAPERTRAIL_HOSTNAME # expand vars like $HOSTNAME
|
||||
sed -i "s/.*hostname:.*/hostname: $PAPERTRAIL_HOSTNAME/" /etc/log_files.yml
|
||||
}
|
||||
|
||||
# download, install and configure papertrail
|
||||
install_papertrail () {
|
||||
cp .ebextensions/metabase_config/papertrail/log_files.yml /etc/log_files.yml && chmod 644 /etc/log_files.yml
|
||||
cp .ebextensions/metabase_config/papertrail/remote_syslog /etc/init.d/remote_syslog && chmod 555 /etc/init.d/remote_syslog
|
||||
cd /tmp/
|
||||
wget -q "https://github.com/papertrail/remote_syslog2/releases/download/v0.20/remote_syslog_linux_amd64.tar.gz" &&
|
||||
tar xzf remote_syslog_linux_amd64.tar.gz
|
||||
/sbin/service remote_syslog stop
|
||||
mv /tmp/remote_syslog/remote_syslog /usr/local/bin/
|
||||
rm -rf remote_syslog_linux_amd64.tar.gz remote_syslog
|
||||
# Setup Papertrail
|
||||
[[ "$PAPERTRAIL_HOST" ]] && pt_remote_host
|
||||
[[ "$PAPERTRAIL_PORT" ]] && pt_port
|
||||
[[ "$PAPERTRAIL_FILES" ]] && pt_files
|
||||
[[ "$PAPERTRAIL_HOSTNAME" ]] && pt_local_host
|
||||
}
|
||||
|
||||
case $1 in
|
||||
set_up_env_vars)
|
||||
set_up_env_vars
|
||||
;;
|
||||
install_papertrail)
|
||||
install_papertrail
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,12 @@
|
||||
# /etc/log_files.yml - Papertrail
|
||||
files:
|
||||
- /var/log/nginx/access.log
|
||||
- /var/log/nginx/error.log
|
||||
- /var/log/eb-*
|
||||
- /var/log/eb-docker/containers/*/*.log
|
||||
hostname:
|
||||
destination:
|
||||
host:
|
||||
port:
|
||||
protocol: tls
|
||||
new_file_check_interval: "10" # Check every 10 seconds
|
||||
@@ -0,0 +1,127 @@
|
||||
#!/bin/bash
|
||||
# /etc/init.d/remote_syslog
|
||||
#
|
||||
# remote_syslog This shell script takes care of starting and stopping
|
||||
# remote_syslog daemon
|
||||
#
|
||||
# chkconfig: - 58 74
|
||||
# description: papertrail/remote_syslog \
|
||||
# https://github.com/papertrail/remote_syslog2/blob/master/examples/remote_syslog.init.d
|
||||
|
||||
### BEGIN INIT INFO
|
||||
# Provides: remote_syslog
|
||||
# Required-Start: $network $local_fs $remote_fs
|
||||
# Required-Stop: $network $local_fs $remote_fs
|
||||
# Should-Start: $syslog $named ntpdate
|
||||
# Should-Stop: $syslog $named
|
||||
# Short-Description: start and stop remote_errolog
|
||||
# Description: papertrail/remote_syslog2
|
||||
# https://github.com/papertrail/remote_syslog2/blob/master/examples/remote_syslog.init.d
|
||||
### END INIT INFO
|
||||
|
||||
# Source function library.
|
||||
. /etc/init.d/functions
|
||||
|
||||
# Source networking configuration.
|
||||
. /etc/sysconfig/network
|
||||
|
||||
prog="/usr/local/bin/remote_syslog"
|
||||
config="/etc/log_files.yml"
|
||||
pid_dir="/var/run"
|
||||
|
||||
EXTRAOPTIONS=""
|
||||
|
||||
pid_file="$pid_dir/remote_syslog.pid"
|
||||
|
||||
PATH=/sbin:/bin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
|
||||
|
||||
RETVAL=0
|
||||
|
||||
is_running(){
|
||||
# Do we have PID-file?
|
||||
if [ -f "$pid_file" ]; then
|
||||
# Check if proc is running
|
||||
pid=`cat "$pid_file" 2> /dev/null`
|
||||
if [[ $pid != "" ]]; then
|
||||
exepath=`readlink /proc/"$pid"/exe 2> /dev/null`
|
||||
exe=`basename "$exepath"`
|
||||
if [[ $exe == "remote_syslog" ]]; then
|
||||
# Process is running
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
start(){
|
||||
echo -n $"Starting $prog: "
|
||||
unset HOME MAIL USER USERNAME
|
||||
$prog -c $config --pid-file=$pid_file $EXTRAOPTIONS
|
||||
RETVAL=$?
|
||||
echo
|
||||
return $RETVAL
|
||||
}
|
||||
|
||||
stop(){
|
||||
echo -n $"Stopping $prog: "
|
||||
if (is_running); then
|
||||
kill `cat $pid_file`
|
||||
RETVAL=$?
|
||||
echo
|
||||
return $RETVAL
|
||||
else
|
||||
echo "$pid_file not found"
|
||||
fi
|
||||
}
|
||||
|
||||
status(){
|
||||
echo -n $"Checking for $pid_file: "
|
||||
|
||||
if (is_running); then
|
||||
echo "found"
|
||||
else
|
||||
echo "not found"
|
||||
fi
|
||||
}
|
||||
|
||||
reload(){
|
||||
restart
|
||||
}
|
||||
|
||||
restart(){
|
||||
stop
|
||||
start
|
||||
}
|
||||
|
||||
condrestart(){
|
||||
is_running && restart
|
||||
return 0
|
||||
}
|
||||
|
||||
# See how we were called.
|
||||
case "$1" in
|
||||
start)
|
||||
start
|
||||
;;
|
||||
stop)
|
||||
stop
|
||||
;;
|
||||
status)
|
||||
status
|
||||
;;
|
||||
restart)
|
||||
restart
|
||||
;;
|
||||
reload)
|
||||
reload
|
||||
;;
|
||||
condrestart)
|
||||
condrestart
|
||||
;;
|
||||
*)
|
||||
echo $"Usage: $0 {start|stop|status|restart|condrestart|reload}"
|
||||
RETVAL=1
|
||||
esac
|
||||
|
||||
exit $RETVAL
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
if [[ "x$NGINX_FORCE_SSL" == "x1" ]]; then
|
||||
cp .platform/nginx/nginx-ssl.conf /etc/nginx/nginx.conf && nginx -t && /sbin/service nginx restart
|
||||
else
|
||||
cp .platform/nginx/nginx.conf /etc/nginx/nginx.conf && nginx -t && /sbin/service nginx restart
|
||||
fi
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
if [[ "x$NGINX_FORCE_SSL" == "x1" ]]; then
|
||||
cp .platform/nginx/nginx-ssl.conf /etc/nginx/nginx.conf && nginx -t && /sbin/service nginx restart
|
||||
else
|
||||
cp .platform/nginx/nginx.conf /etc/nginx/nginx.conf && nginx -t && /sbin/service nginx restart
|
||||
fi
|
||||
@@ -0,0 +1,58 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log;
|
||||
pid /var/run/nginx.pid;
|
||||
worker_rlimit_nofile 65936;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
include conf.d/*.conf;
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default "upgrade";
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
gzip on;
|
||||
gzip_comp_level 4;
|
||||
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
location / {
|
||||
if ($http_x_forwarded_proto != "https") {
|
||||
rewrite ^ https://$host$request_uri? permanent;
|
||||
}
|
||||
|
||||
proxy_pass http://docker;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
send_timeout 600;
|
||||
}
|
||||
|
||||
# Include the Elastic Beanstalk generated locations
|
||||
include conf.d/elasticbeanstalk/*.conf;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
user nginx;
|
||||
worker_processes auto;
|
||||
error_log /var/log/nginx/error.log;
|
||||
pid /var/run/nginx.pid;
|
||||
worker_rlimit_nofile 65936;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
access_log /var/log/nginx/access.log;
|
||||
|
||||
|
||||
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
|
||||
'$status $body_bytes_sent "$http_referer" '
|
||||
'"$http_user_agent" "$http_x_forwarded_for"';
|
||||
|
||||
include conf.d/*.conf;
|
||||
|
||||
map $http_upgrade $connection_upgrade {
|
||||
default "upgrade";
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
gzip on;
|
||||
gzip_comp_level 4;
|
||||
gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
access_log /var/log/nginx/access.log main;
|
||||
|
||||
location / {
|
||||
proxy_pass http://docker;
|
||||
proxy_http_version 1.1;
|
||||
|
||||
proxy_set_header Connection $connection_upgrade;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_connect_timeout 600;
|
||||
proxy_send_timeout 600;
|
||||
proxy_read_timeout 600;
|
||||
send_timeout 600;
|
||||
}
|
||||
|
||||
# Include the Elastic Beanstalk generated locations
|
||||
include conf.d/elasticbeanstalk/*.conf;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<!DOCTYPE html>
|
||||
<meta charset="utf-8" />
|
||||
<title>Redirecting...</title>
|
||||
<link
|
||||
rel="canonical"
|
||||
href="https://console.aws.amazon.com/elasticbeanstalk/home?region=us-east-1#/newApplication?applicationName=Metabase&tierName=WebServer&platform=Docker&environmentType=LoadBalancing&sourceBundleUrl={{url}}&instanceType=t3a.small"
|
||||
/>
|
||||
<meta
|
||||
http-equiv="refresh"
|
||||
content="0; url=https://console.aws.amazon.com/elasticbeanstalk/home?region=us-east-1#/newApplication?applicationName=Metabase&tierName=WebServer&platform=Docker&environmentType=LoadBalancing&sourceBundleUrl={{url}}&instanceType=t3a.small"
|
||||
/>
|
||||
<h1>Redirecting...</h1>
|
||||
<a
|
||||
href="https://console.aws.amazon.com/elasticbeanstalk/home?region=us-east-1#/newApplication?applicationName=Metabase&tierName=WebServer&platform=Docker&environmentType=LoadBalancing&sourceBundleUrl={{url}}&instanceType=t3a.small"
|
||||
>
|
||||
Click here if you are not redirected.
|
||||
</a>
|
||||
<script>
|
||||
location =
|
||||
"https://console.aws.amazon.com/elasticbeanstalk/home?region=us-east-1#/newApplication?applicationName=Metabase&tierName=WebServer&platform=Docker&environmentType=LoadBalancing&sourceBundleUrl={{url}}&instanceType=t3a.small";
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
(ns build.version-properties-test
|
||||
(ns build.version-info-test
|
||||
(:require
|
||||
[build.version-properties :as version-properties]
|
||||
[build.version-info :as version-info]
|
||||
[clojure.test :refer :all]))
|
||||
|
||||
(deftest tag-parts-test
|
||||
@@ -11,7 +11,7 @@
|
||||
tag [tag (str \v tag)]]
|
||||
(testing (str (pr-str (list 'tag-parts tag)) " => " (pr-str expected))
|
||||
(is (= expected
|
||||
(#'version-properties/tag-parts tag))))))
|
||||
(#'version-info/tag-parts tag))))))
|
||||
|
||||
(deftest current-snapshot-version-test
|
||||
(doseq [[branch edition->tag->expected] {"release-x.37.x" {:oss {nil "UNKNOWN"
|
||||
@@ -34,4 +34,4 @@
|
||||
[tag expected] tag->expected]
|
||||
(testing (str (pr-str (list 'current-snapshot-version edition branch tag)) " => " (pr-str expected))
|
||||
(is (= expected
|
||||
(version-properties/current-snapshot-version edition branch tag))))))
|
||||
(version-info/current-snapshot-version edition branch tag))))))
|
||||
@@ -8,6 +8,7 @@
|
||||
["1.36.1" "1.36.0" true]
|
||||
["1.36.0" "1.36.0" false]
|
||||
["1.37.0" "1.36.9" true]
|
||||
["1.37.0" "1.36.9" true]
|
||||
["1.37.0.1" "1.37.0" true]
|
||||
["1.37.1.1" "1.37.0.2" true]
|
||||
["1.37.10" "1.37.2" true]
|
||||
|
||||
11
bin/build/test/release/elastic_beanstalk_test.clj
Normal file
11
bin/build/test/release/elastic_beanstalk_test.clj
Normal file
@@ -0,0 +1,11 @@
|
||||
(ns release.elastic-beanstalk-test
|
||||
(:require
|
||||
[clojure.test :refer :all]
|
||||
[release.common :as c]
|
||||
[release.elastic-beanstalk :as release.eb]))
|
||||
|
||||
(deftest create-html-file-test
|
||||
(testing "Just make sure this doesn't barf."
|
||||
(binding [c/*build-options* (atom {:version "0.46.0-test"
|
||||
:edition :oss})]
|
||||
(is (string? (#'release.eb/create-html-file!))))))
|
||||
15
bin/ebs.sh
Executable file
15
bin/ebs.sh
Executable file
@@ -0,0 +1,15 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# switch to project root directory if we're not already there
|
||||
script_directory=`dirname "${BASH_SOURCE[0]}"`
|
||||
cd "$script_directory/.."
|
||||
|
||||
source "./bin/check-clojure-cli.sh"
|
||||
check_clojure_cli
|
||||
|
||||
source "./bin/clear-outdated-cpcaches.sh"
|
||||
clear_outdated_cpcaches
|
||||
|
||||
clojure -X:build:build/publish-ebs $@
|
||||
@@ -24,7 +24,7 @@ POT_NAME="locales/metabase.pot"
|
||||
POT_BACKEND_NAME="locales/metabase-backend.pot"
|
||||
# NOTE: hardcoded in .babelrc
|
||||
POT_FRONTEND_NAME="locales/metabase-frontend.pot"
|
||||
# NOTE: hardcoded in src/metabase/automagic_dashboards/dashboard_templates.clj
|
||||
# NOTE: hardcoded in src/metabase/automagic_dashboards/rules.clj
|
||||
POT_AUTODASH_NAME="locales/metabase-automatic-dashboards.pot"
|
||||
|
||||
mkdir -p "locales"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
set -euxo pipefail
|
||||
|
||||
# Convenience for running clj-kondo against all the appropriate directories.
|
||||
|
||||
|
||||
71
bin/update-version-info
Executable file
71
bin/update-version-info
Executable file
@@ -0,0 +1,71 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# Generate the version-info.json file which provides basic information about the latest versions of Metabase available.
|
||||
# This is used inside the Metabase application as a simple mechanism to be aware if an upgrade is available.
|
||||
|
||||
build() {
|
||||
echo '{
|
||||
"latest": {
|
||||
"version": "v0.18.0",
|
||||
"released": "2016-05-04T21:09:36.358Z",
|
||||
"patch": false,
|
||||
"highlights": [
|
||||
"Notifications about available Metabase updates"
|
||||
]
|
||||
},
|
||||
"older": [
|
||||
{
|
||||
"version": "v0.17.1",
|
||||
"released": "2016-05-04T21:09:36.358Z",
|
||||
"patch": true,
|
||||
"highlights": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "v0.17.0",
|
||||
"released": "2016-05-04T21:09:36.358Z",
|
||||
"patch": false,
|
||||
"highlights": [
|
||||
"Tags + Search for Saved Questions",
|
||||
"Calculated columns",
|
||||
"Faster Syncing of Metadata",
|
||||
"Lots of database driver improvements and bug fixes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "v0.16.1",
|
||||
"released": "2016-05-04T21:09:36.358Z",
|
||||
"patch": true,
|
||||
"highlights": [
|
||||
"Fixes for several time alignment issues (timezones)",
|
||||
"Resolved problem with SQL Server db connections"
|
||||
]
|
||||
},
|
||||
{
|
||||
"version": "v0.16.0",
|
||||
"released": "2016-05-04T21:09:36.358Z",
|
||||
"patch": false,
|
||||
"highlights": [
|
||||
"Fullscreen (and fabulous) Dashboards",
|
||||
"Say hello to Metabot in Slack"
|
||||
]
|
||||
}
|
||||
]
|
||||
}' > /tmp/version-info.json
|
||||
}
|
||||
|
||||
upload() {
|
||||
# send the current file to s3
|
||||
aws s3 cp /tmp/version-info.json "s3://static.metabase.com/version-info.json"
|
||||
}
|
||||
|
||||
publish() {
|
||||
build && upload && rm /tmp/version-info.json 2> /dev/null
|
||||
}
|
||||
|
||||
if [ "$1" ]; then
|
||||
$1
|
||||
else
|
||||
publish
|
||||
fi
|
||||
175
deps.edn
175
deps.edn
@@ -9,11 +9,11 @@
|
||||
org.clojure/clojurescript]}
|
||||
amalloy/ring-gzip-middleware {:mvn/version "0.1.4"} ; Ring middleware to GZIP responses if client can handle it
|
||||
bigml/histogram {:mvn/version "4.1.4"} ; Histogram data structure
|
||||
buddy/buddy-core {:mvn/version "1.11.423" ; various cryptographic functions
|
||||
buddy/buddy-core {:mvn/version "1.10.413" ; various cryptographic functions
|
||||
:exclusions [commons-codec/commons-codec
|
||||
org.bouncycastle/bcpkix-jdk15on
|
||||
org.bouncycastle/bcprov-jdk15on]}
|
||||
buddy/buddy-sign {:mvn/version "3.5.351"} ; JSON Web Tokens; High-Level message signing library
|
||||
buddy/buddy-sign {:mvn/version "3.4.333"} ; JSON Web Tokens; High-Level message signing library
|
||||
camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.3"} ; util functions for converting between camel, snake, and kebob case
|
||||
cheshire/cheshire {:mvn/version "5.11.0"} ; fast JSON encoding (used by Ring JSON middleware)
|
||||
clj-bom/clj-bom {:mvn/version "0.1.2"} ; handle BOMs in imported CSVs
|
||||
@@ -22,7 +22,7 @@
|
||||
:exclusions [commons-codec/commons-codec
|
||||
commons-io/commons-io
|
||||
slingshot/slingshot]}
|
||||
clojure.java-time/clojure.java-time {:mvn/version "1.3.0"} ; java.time utilities
|
||||
clojure.java-time/clojure.java-time {:mvn/version "1.2.0"} ; java.time utilities
|
||||
clojurewerkz/quartzite {:mvn/version "2.1.0" ; scheduling library
|
||||
:exclusions [c3p0/c3p0
|
||||
org.quartz-scheduler/quartz]}
|
||||
@@ -32,26 +32,26 @@
|
||||
:exclusions [it.unimi.dsi/fastutil
|
||||
org.slf4j/slf4j-api]}
|
||||
com.draines/postal {:mvn/version "2.0.5"} ; SMTP library
|
||||
com.github.seancorfield/honeysql {:mvn/version "2.4.1066"} ; Honey SQL 2. SQL generation from Clojure data maps
|
||||
com.github.seancorfield/honeysql {:mvn/version "2.4.1002"} ; Honey SQL 2. SQL generation from Clojure data maps
|
||||
com.github.seancorfield/next.jdbc {:git/url "https://github.com/seancorfield/next-jdbc.git"
|
||||
:sha "abd926cde3730087d3729dcea0ce0ab7ef1194f2"} ; for https://github.com/seancorfield/next-jdbc/issues/245; when this makes it to a release we can switch to that.
|
||||
com.github.vertical-blank/sql-formatter {:mvn/version "2.0.4"} ; Java SQL formatting library https://github.com/vertical-blank/sql-formatter
|
||||
com.google.guava/guava {:mvn/version "32.1.2-jre"} ; dep for BigQuery, Spark, and GA. Require here rather than letting different dep versions stomp on each other — see comments on #9697
|
||||
:sha "8f372917a4b8b55c893ef6586f9ffe8dce4cbc7e"} ; for https://github.com/seancorfield/next-jdbc/issues/245; when this makes it to a release we can switch to that.
|
||||
com.github.vertical-blank/sql-formatter {:mvn/version "2.0.3"} ; Java SQL formatting library https://github.com/vertical-blank/sql-formatter
|
||||
com.google.guava/guava {:mvn/version "31.1-jre"} ; dep for BigQuery, Spark, and GA. Require here rather than letting different dep versions stomp on each other — see comments on #9697
|
||||
com.fasterxml.jackson.core/jackson-databind
|
||||
{:mvn/version "2.15.2"} ; JSON processor used by snowplow-java-tracker
|
||||
com.fasterxml.woodstox/woodstox-core {:mvn/version "6.5.1"} ; trans dep of commons-codec (pinned version due to CVE-2022-40151)
|
||||
{:mvn/version "2.14.2"} ; JSON processor used by snowplow-java-tracker
|
||||
com.fasterxml.woodstox/woodstox-core {:mvn/version "6.5.0"} ; trans dep of commons-codec (pinned version due to CVE-2022-40151)
|
||||
com.h2database/h2 {:mvn/version "2.1.214"} ; embedded SQL database
|
||||
com.gfredericks/test.chuck {:mvn/version "0.2.14"} ; generating strings from regex
|
||||
com.snowplowanalytics/snowplow-java-tracker
|
||||
{:mvn/version "1.0.0" ; Snowplow analytics
|
||||
:exclusions [com.fasterxml.jackson.core/jackson-databind]}
|
||||
com.taoensso/nippy {:mvn/version "3.2.0"} ; Fast serialization (i.e., GZIP) library for Clojure
|
||||
com.vladsch.flexmark/flexmark {:mvn/version "0.64.8"} ; Markdown parsing
|
||||
com.vladsch.flexmark/flexmark {:mvn/version "0.64.0"} ; Markdown parsing
|
||||
com.vladsch.flexmark/flexmark-ext-autolink
|
||||
{:mvn/version "0.64.8"} ; Flexmark extension for auto-linking bare URLs
|
||||
{:mvn/version "0.64.0"} ; Flexmark extension for auto-linking bare URLs
|
||||
commons-fileupload/commons-fileupload {:mvn/version "1.5"} ; ring/ring-core 1.9.6 uses v1.4, but we want 1.5 due to a CVE. When we upgrade to the forthcoming ring/ring-core 1.10.0 we can remove this.
|
||||
commons-codec/commons-codec {:mvn/version "1.16.0"} ; Apache Commons -- useful codec util fns
|
||||
commons-io/commons-io {:mvn/version "2.13.0"} ; Apache Commons -- useful IO util fns
|
||||
commons-codec/commons-codec {:mvn/version "1.15"} ; Apache Commons -- useful codec util fns
|
||||
commons-io/commons-io {:mvn/version "2.11.0"} ; Apache Commons -- useful IO util fns
|
||||
commons-net/commons-net {:mvn/version "3.9.0"} ; Apache Commons -- useful network utils. Transitive dep of Snowplow, pinned due to CVE-2021-37533
|
||||
commons-validator/commons-validator {:mvn/version "1.7" ; Apache Commons -- useful validation util fns
|
||||
:exclusions [commons-beanutils/commons-beanutils
|
||||
@@ -67,36 +67,36 @@
|
||||
hiccup/hiccup {:mvn/version "1.0.5"} ; HTML templating
|
||||
honeysql/honeysql {:mvn/version "1.0.461" ; Transform Clojure data structures to SQL
|
||||
:exclusions [org.clojure/clojurescript]}
|
||||
inflections/inflections {:mvn/version "0.14.1"} ; Clojure/Script library used for prularizing words
|
||||
info.sunng/ring-jetty9-adapter {:mvn/version "0.22.3"} ; Drop-in replacement for official Ring Jetty adapter. Supports Jetty 11 webserver.
|
||||
info.sunng/ring-jetty9-adapter {:mvn/version "0.18.5"} ; Drop-in replacement for official Ring Jetty adapter. Supports Jetty 11 webserver.
|
||||
instaparse/instaparse {:mvn/version "1.4.12"} ; Make your own parser
|
||||
clj-commons/clj-yaml {:mvn/version "1.0.27"} ; Clojure wrapper for YAML library SnakeYAML
|
||||
io.github.camsaul/toucan2 {:mvn/version "1.0.524"}
|
||||
clj-commons/clj-yaml {:mvn/version "1.0.26"} ; Clojure wrapper for YAML library SnakeYAML
|
||||
io.github.camsaul/toucan2 {:mvn/version "1.0.520"}
|
||||
io.github.camsaul/toucan2-toucan1 {:mvn/version "1.0.520"}
|
||||
;; The 2.X line of Resilience4j requires Java 17, so we cannot upgrade this dependency until that is our minimum JVM version
|
||||
io.github.resilience4j/resilience4j-retry {:mvn/version "1.7.1"} ; Support for retrying operations
|
||||
io.prometheus/simpleclient_hotspot {:mvn/version "0.16.0"} ; prometheus jvm collector
|
||||
io.prometheus/simpleclient_jetty {:mvn/version "0.16.0"} ; prometheus jetty collector
|
||||
javax.servlet/servlet-api {:mvn/version "2.5"} ; used by ring's multipart-params (file upload)
|
||||
joda-time/joda-time {:mvn/version "2.12.5"}
|
||||
joda-time/joda-time {:mvn/version "2.12.2"}
|
||||
kixi/stats {:mvn/version "0.5.5" ; Various statistic measures implemented as transducers
|
||||
:exclusions [org.clojure/data.avl]}
|
||||
medley/medley {:mvn/version "1.4.0"} ; lightweight lib of useful functions
|
||||
metabase/connection-pool {:mvn/version "1.2.0"} ; simple wrapper around C3P0. JDBC connection pools
|
||||
metabase/saml20-clj {:mvn/version "2.2.4"} ; EE SAML integration.
|
||||
metabase/saml20-clj {:mvn/version "2.2.1"} ; EE SAML integration.
|
||||
metabase/throttle {:mvn/version "1.0.2"} ; Tools for throttling access to API endpoints and other code pathways
|
||||
metosin/malli {:mvn/version "0.11.0"} ; Data-driven Schemas for Clojure/Script and babashka
|
||||
metosin/malli {:mvn/version "0.10.2"} ; Data-driven Schemas for Clojure/Script and babashka
|
||||
nano-id/nano-id {:mvn/version "1.0.0"} ; NanoID generator for generating entity_ids
|
||||
net.cgrand/macrovich {:mvn/version "0.2.2"} ; utils for writing macros for both Clojure & ClojureScript
|
||||
net.clojars.wkok/openai-clojure {:mvn/version "0.9.0"} ; OpenAI
|
||||
net.cgrand/macrovich {:mvn/version "0.2.1"} ; utils for writing macros for both Clojure & ClojureScript
|
||||
net.clojars.wkok/openai-clojure {:mvn/version "0.5.0"} ; OpenAI
|
||||
net.i2p.crypto/eddsa {:mvn/version "0.3.0"} ; ED25519 key support (optional dependency for org.apache.sshd/sshd-core)
|
||||
net.redhogs.cronparser/cron-parser-core {:mvn/version "3.5" ; describe Cron schedule in human-readable language
|
||||
:exclusions [joda-time/joda-time ; exclude joda time 2.3 which has outdated timezone information
|
||||
org.slf4j/slf4j-api]}
|
||||
net.sf.cssbox/cssbox {:mvn/version "5.0.1" ; HTML / CSS rendering
|
||||
net.sf.cssbox/cssbox {:mvn/version "5.0.0" ; HTML / CSS rendering
|
||||
:exclusions [org.slf4j/slf4j-api]}
|
||||
net.thisptr/jackson-jq {:mvn/version "1.0.0-preview.20230409"} ; Java implementation of the JQ json query language
|
||||
org.apache.commons/commons-compress {:mvn/version "1.23.0"} ; compression utils
|
||||
org.apache.commons/commons-lang3 {:mvn/version "3.13.0"} ; helper methods for working with java.lang stuff
|
||||
net.thisptr/jackson-jq {:mvn/version "1.0.0-preview.20220705"} ; Java implementation of the JQ json query language
|
||||
org.apache.commons/commons-compress {:mvn/version "1.22"} ; compression utils
|
||||
org.apache.commons/commons-lang3 {:mvn/version "3.12.0"} ; helper methods for working with java.lang stuff
|
||||
org.apache.logging.log4j/log4j-1.2-api {:mvn/version "2.20.0"} ; apache logging framework
|
||||
org.apache.logging.log4j/log4j-api {:mvn/version "2.20.0"} ; add compatibility with log4j 1.2
|
||||
org.apache.logging.log4j/log4j-core {:mvn/version "2.20.0"} ; apache logging framework
|
||||
@@ -106,19 +106,17 @@
|
||||
{:mvn/version "2.20.0"} ; allows the slf4j2 API to work with log4j 2
|
||||
org.apache.logging.log4j/log4j-layout-template-json
|
||||
{:mvn/version "2.20.0"} ; allows the custom json logging format
|
||||
org.apache.poi/poi {:mvn/version "5.2.4"} ; Work with Office documents (e.g. Excel spreadsheets) -- newer version than one specified by Docjure
|
||||
org.apache.poi/poi {:mvn/version "5.2.3"} ; Work with Office documents (e.g. Excel spreadsheets) -- newer version than one specified by Docjure
|
||||
org.apache.poi/poi-ooxml {:mvn/version "5.2.3"
|
||||
:exclusions [org.bouncycastle/bcpkix-jdk15on
|
||||
org.bouncycastle/bcprov-jdk15on]}
|
||||
org.apache.sshd/sshd-core {:mvn/version "2.10.0" ; ssh tunneling and test server
|
||||
:exclusions [org.slf4j/slf4j-api
|
||||
org.slf4j/jcl-over-slf4j]}
|
||||
org.apache.xmlgraphics/batik-all {:mvn/version "1.17"} ; SVG -> image
|
||||
org.apache.sshd/sshd-core {:mvn/version "2.9.2"} ; ssh tunneling and test server
|
||||
org.apache.xmlgraphics/batik-all {:mvn/version "1.16"} ; SVG -> image
|
||||
org.clojars.pntblnk/clj-ldap {:mvn/version "0.0.17"} ; LDAP client
|
||||
org.bouncycastle/bcpkix-jdk15on {:mvn/version "1.70"} ; Bouncy Castle crypto library -- explicit version of BC specified to resolve illegal reflective access errors
|
||||
org.bouncycastle/bcprov-jdk15on {:mvn/version "1.70"}
|
||||
org.clojure/clojure {:mvn/version "1.11.1"}
|
||||
org.clojure/core.async {:mvn/version "1.6.681"
|
||||
org.clojure/core.async {:mvn/version "1.6.673"
|
||||
:exclusions [org.clojure/tools.reader]}
|
||||
org.clojure/core.logic {:mvn/version "1.0.1"} ; optimized pattern matching library for Clojure
|
||||
org.clojure/core.match {:mvn/version "1.0.1"}
|
||||
@@ -128,25 +126,25 @@
|
||||
org.clojure/java.classpath {:mvn/version "1.0.0"} ; examine the Java classpath from Clojure programs
|
||||
org.clojure/java.jdbc {:mvn/version "0.7.12"} ; basic JDBC access from Clojure
|
||||
org.clojure/java.jmx {:mvn/version "1.0.0"} ; JMX bean library, for exporting diagnostic info
|
||||
org.clojure/math.combinatorics {:mvn/version "0.2.0"} ; combinatorics functions
|
||||
org.clojure/math.combinatorics {:mvn/version "0.1.6"} ; combinatorics functions
|
||||
org.clojure/math.numeric-tower {:mvn/version "0.0.5"} ; math functions like `ceil`
|
||||
org.clojure/tools.cli {:mvn/version "1.0.219"} ; command-line argument parsing
|
||||
org.clojure/tools.cli {:mvn/version "1.0.214"} ; command-line argument parsing
|
||||
org.clojure/tools.logging {:mvn/version "1.2.4"} ; logging framework
|
||||
org.clojure/tools.macro {:mvn/version "0.1.5"} ; local macros
|
||||
org.clojure/tools.namespace {:mvn/version "1.4.4"}
|
||||
org.clojure/tools.reader {:mvn/version "1.3.6"}
|
||||
org.clojure/tools.trace {:mvn/version "0.7.11"} ; function tracing
|
||||
org.eclipse.jetty/jetty-server {:mvn/version "11.0.17"} ; web server
|
||||
org.flatland/ordered {:mvn/version "1.15.11"} ; ordered maps & sets
|
||||
org.graalvm.js/js {:mvn/version "22.3.3"} ; JavaScript engine
|
||||
org.liquibase/liquibase-core {:mvn/version "4.21.1" ; migration management (Java lib)
|
||||
org.eclipse.jetty/jetty-server {:mvn/version "11.0.14"} ; web server
|
||||
org.flatland/ordered {:mvn/version "1.15.10"} ; ordered maps & sets
|
||||
org.graalvm.js/js {:mvn/version "22.3.1"} ; JavaScript engine
|
||||
org.liquibase/liquibase-core {:mvn/version "4.11.0" ; migration management (Java lib)
|
||||
:exclusions [ch.qos.logback/logback-classic]}
|
||||
;; The 3.X line of development for mariadb-java-client only supports the jdbc:mariadb protocol, so use 2.X for now.
|
||||
org.mariadb.jdbc/mariadb-java-client {:mvn/version "2.7.10"} ; MySQL/MariaDB driver
|
||||
org.mariadb.jdbc/mariadb-java-client {:mvn/version "2.7.6"} ; MySQL/MariaDB driver
|
||||
org.mindrot/jbcrypt {:mvn/version "0.4"} ; Crypto library
|
||||
org.postgresql/postgresql {:mvn/version "42.6.0"} ; Postgres driver
|
||||
org.postgresql/postgresql {:mvn/version "42.5.4"} ; Postgres driver
|
||||
org.quartz-scheduler/quartz {:mvn/version "2.3.2"} ; Quartz job scheduler, provided by quartzite but this is a newer version.
|
||||
org.slf4j/slf4j-api {:mvn/version "2.0.7"} ; abstraction for logging frameworks -- allows end user to plug in desired logging framework at deployment time
|
||||
org.slf4j/slf4j-api {:mvn/version "2.0.6"} ; abstraction for logging frameworks -- allows end user to plug in desired logging framework at deployment time
|
||||
org.tcrawley/dynapath {:mvn/version "1.1.0"} ; Dynamically add Jars (e.g. Oracle or Vertica) to classpath
|
||||
org.threeten/threeten-extra {:mvn/version "1.7.2"} ; extra Java 8 java.time classes like DayOfMonth and Quarter
|
||||
potemkin/potemkin {:mvn/version "0.4.6" ; utility macros & fns
|
||||
@@ -155,7 +153,7 @@
|
||||
prismatic/schema {:mvn/version "1.4.1"} ; Data schema declaration and validation library
|
||||
redux/redux {:mvn/version "0.1.4"} ; Utility functions for building and composing transducers
|
||||
riddley/riddley {:mvn/version "0.2.0"} ; code walking lib -- used interally by Potemkin, manifold, etc.
|
||||
ring/ring-core {:mvn/version "1.10.0"} ; web server (Jetty wrapper)
|
||||
ring/ring-core {:mvn/version "1.9.6"} ; web server (Jetty wrapper)
|
||||
ring/ring-json {:mvn/version "0.5.1"} ; Ring middleware for reading/writing JSON automatically
|
||||
slingshot/slingshot {:mvn/version "0.12.2"} ; enhanced throw/catch, used by other deps
|
||||
stencil/stencil {:mvn/version "0.5.0"} ; Mustache templates for Clojure
|
||||
@@ -203,18 +201,16 @@
|
||||
;; (dev/start!)
|
||||
:dev
|
||||
{:extra-deps
|
||||
{clj-http-fake/clj-http-fake {:mvn/version "1.0.4"
|
||||
{clj-http-fake/clj-http-fake {:mvn/version "1.0.3"
|
||||
:exclusions [slingshot/slingshot]}
|
||||
clj-kondo/clj-kondo {:mvn/version "2023.09.07"} ; this is not for RUNNING kondo, but so we can hack on custom hooks code from the REPL.
|
||||
clj-kondo/clj-kondo {:mvn/version "2023.02.17"} ; this is not for RUNNING kondo, but so we can hack on custom hooks code from the REPL.
|
||||
cloverage/cloverage {:mvn/version "1.2.4"}
|
||||
com.gfredericks/test.chuck {:mvn/version "0.2.14"} ; generating strings from regexes (useful with malli)
|
||||
djblue/portal {:mvn/version "0.46.0"} ; ui for inspecting values
|
||||
djblue/portal {:mvn/version "0.40.0"} ; ui for inspecting values
|
||||
io.github.camsaul/humane-are {:mvn/version "1.0.2"}
|
||||
io.github.metabase/hawk {:sha "9c97bcb6d4de116325e651b40973fd0a75b7ae21"}
|
||||
jonase/eastwood {:mvn/version "1.4.0" ; inspects namespaces and reports possible problems using tools.analyzer
|
||||
:exclusions
|
||||
[org.ow2.asm/asm-all]}
|
||||
lambdaisland/deep-diff2 {:mvn/version "2.10.211"} ; way better diffs
|
||||
io.github.metabase/hawk {:sha "70611745e3cb8b95d5793a88581d5c330148715b"}
|
||||
jonase/eastwood {:mvn/version "1.3.0"} ; inspects namespaces and reports possible problems using tools.analyzer
|
||||
lambdaisland/deep-diff2 {:mvn/version "2.7.169"} ; way better diffs
|
||||
methodical/methodical {:mvn/version "0.15.1"} ; drop-in replacements for Clojure multimethods and adds several advanced features
|
||||
org.clojure/algo.generic {:mvn/version "0.1.3"}
|
||||
pjstadig/humane-test-output {:mvn/version "0.11.0"}
|
||||
@@ -283,8 +279,8 @@
|
||||
{:extra-paths ["enterprise/backend/src"]}
|
||||
|
||||
;; Include EE tests.
|
||||
;; for EE dev: `clojure -X:dev:ee:ee-dev`
|
||||
;; for EE tests: `clojure -X:dev:ee:ee-dev:test`
|
||||
;; for ee dev: :dev:ee:ee-dev
|
||||
;; for ee tests: clojure -X:dev:ee:ee-dev:test
|
||||
:ee-dev
|
||||
{:extra-paths ["enterprise/backend/test"]}
|
||||
|
||||
@@ -295,15 +291,6 @@
|
||||
:oss-dev
|
||||
{}
|
||||
|
||||
;; Generate BE documentation with
|
||||
;; clojure -M:marginalia
|
||||
:marginalia
|
||||
{:extra-deps
|
||||
{com.github.tsmacdonald/marginalia {:mvn/version "0.9.2"}}
|
||||
:main-opts ["-m" "marginalia.main" "-n" "Metabase" "-d" "backend-docs" "-D"
|
||||
"The simplest, fastest way to get business intelligence and analytics to everyone in your company 😋"
|
||||
"dev" "src" "shared/src" "enterprise/backend/src"]}
|
||||
|
||||
;; Find outdated versions of dependencies. Run with `clojure -M:outdated`
|
||||
:outdated {;; Note that it is `:deps`, not `:extra-deps`
|
||||
:deps {com.github.liquidz/antq {:mvn/version "RELEASE"}}
|
||||
@@ -312,18 +299,17 @@
|
||||
:cljs
|
||||
{:extra-paths ["test" "shared/test"]
|
||||
:extra-deps
|
||||
{binaryage/devtools {:mvn/version "1.0.7"}
|
||||
cider/cider-nrepl {:mvn/version "0.37.0"}
|
||||
{binaryage/devtools {:mvn/version "1.0.6"}
|
||||
cider/cider-nrepl {:mvn/version "0.30.0"}
|
||||
cider/piggieback {:mvn/version "0.5.3"}
|
||||
cljs-bean/cljs-bean {:mvn/version "1.9.0"}
|
||||
com.lambdaisland/glogi {:mvn/version "1.3.169"}
|
||||
io.github.metabase/hawk {:sha "9c97bcb6d4de116325e651b40973fd0a75b7ae21"}
|
||||
org.clojars.mmb90/cljs-cache {:mvn/version "0.1.4"}
|
||||
com.lambdaisland/glogi {:mvn/version "1.2.164"}
|
||||
io.github.metabase/hawk {:sha "70611745e3cb8b95d5793a88581d5c330148715b"}
|
||||
;; Forcibly targeting a newer release than ships by default with shadow-cljs 2.20.20.
|
||||
;; It fixes an issue where TypeScript can't parse the `cljs_env.js` output file.
|
||||
org.clojure/google-closure-library {:mvn/version "0.0-20230227-c7c0a541"}
|
||||
refactor-nrepl/refactor-nrepl {:mvn/version "3.9.0"}
|
||||
thheller/shadow-cljs {:mvn/version "2.25.7"}}}
|
||||
refactor-nrepl/refactor-nrepl {:mvn/version "3.6.0"}
|
||||
thheller/shadow-cljs {:mvn/version "2.22.2"}}}
|
||||
|
||||
;; for local dev -- include the drivers locally with :dev:drivers
|
||||
:drivers
|
||||
@@ -489,9 +475,7 @@
|
||||
["metabase\\.driver\\.mysql.*"
|
||||
"metabase\\.driver\\.postgres.*"]}
|
||||
;; different port from `:test` so you can run it at the same time as `:test`.
|
||||
:jvm-opts ["-Dmb.jetty.port=3002"
|
||||
;; default heap size is 1GB, we were getting OOM on CI so we need to bump this
|
||||
"-Xmx4g"]}
|
||||
:jvm-opts ["-Dmb.jetty.port=3002"]}
|
||||
|
||||
;;; building Uberjar, build and release scripts
|
||||
|
||||
@@ -505,7 +489,7 @@
|
||||
com.github.seancorfield/depstar {:mvn/version "2.1.303"}
|
||||
expound/expound {:mvn/version "0.9.0"} ; better output of spec validation errors
|
||||
io.github.borkdude/grasp {:mvn/version "0.1.4"}
|
||||
io.github.clojure/tools.build {:mvn/version "0.9.5"}
|
||||
io.github.clojure/tools.build {:git/tag "v0.9.4" :git/sha "76b78fe"}
|
||||
org.clojure/data.xml {:mvn/version "0.2.0-alpha8"}
|
||||
org.clojure/tools.deps.alpha {:mvn/version "0.15.1254"}
|
||||
org.fedorahosted.tennera/jgettext {:mvn/version "0.15.1"}}
|
||||
@@ -580,10 +564,18 @@
|
||||
;; :upload-uberjar
|
||||
;; :push-git-tags
|
||||
;; :publish-draft-release
|
||||
;; :publish-elastic-beanstalk-artifacts
|
||||
;; :update-version-info
|
||||
:build/release
|
||||
{:exec-fn release/release}
|
||||
|
||||
;; Only in the CI for now: publish EBS artifact
|
||||
;; FIXME: remove after full release automation on CI
|
||||
;;
|
||||
;; clojure -X:build:build/publish-ebs
|
||||
:build/publish-ebs
|
||||
{:exec-fn release/publish-ebs}
|
||||
|
||||
;; extra paths and deps for working on build scripts, or running the tests.
|
||||
:build-dev
|
||||
{:extra-paths ["bin/build/test"]
|
||||
@@ -613,8 +605,9 @@
|
||||
:exec-fn dev.h2-shell/shell
|
||||
:java-opts ["-Dfile.encoding=UTF-8"]}
|
||||
|
||||
;; clojure -M:generate-automagic-dashboards-pot
|
||||
:generate-automagic-dashboards-pot
|
||||
{:main-opts ["-m" "metabase.automagic-dashboards.dashboard-templates"]}
|
||||
{:main-opts ["-m" "metabase.automagic-dashboards.rules"]}
|
||||
|
||||
;; Start a Network REPL (nrepl) that you can connect your editor to.
|
||||
;;
|
||||
@@ -634,41 +627,9 @@
|
||||
;;
|
||||
;; clojure -M:liquibase dbDoc target/liquibase
|
||||
:liquibase
|
||||
{:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.11"}}
|
||||
{:extra-deps {ch.qos.logback/logback-classic {:mvn/version "1.4.6"}}
|
||||
:extra-paths ["dev/src"]
|
||||
:main-opts ["-m" "dev.liquibase"]}
|
||||
|
||||
;; the following aliases are convenience for running tests against certain parts of the codebase.
|
||||
;;
|
||||
;; clj -X:dev:ee:ee-dev:test:test/mbql
|
||||
|
||||
;; run tests against MLv2. Very fast since this is almost all ^:parallel
|
||||
:test/mlv2
|
||||
{:exec-args {:only ["test/metabase/lib"]}}
|
||||
|
||||
;; test the Query Processor
|
||||
;;
|
||||
;; clj -X:dev:ee:ee-dev:test:test/qp
|
||||
:test/qp
|
||||
{:exec-args {:only ["test/metadata/driver"
|
||||
"test/metabase/query_processor"
|
||||
"test/metabase/query_processor_test"
|
||||
metabase-enterprise.advanced-permissions.models.permissions.block-permissions-test
|
||||
metabase-enterprise.sandbox.query-processor.middleware.row-level-restrictions-test]}}
|
||||
|
||||
;; test all MBQL related stuff: MLv2, the legacy shared `metabase.mbql` code, and the QP
|
||||
;;
|
||||
;; clj -X:dev:ee:ee-dev:test:test/mbql
|
||||
:test/mbql
|
||||
{:exec-args {:only ["shared/test/mbql"
|
||||
"test/metabase/lib"
|
||||
"test/metadata/driver"
|
||||
"test/metabase/query_processor"
|
||||
"test/metabase/query_processor_test"
|
||||
metabase-enterprise.advanced-permissions.models.permissions.block-permissions-test
|
||||
metabase-enterprise.sandbox.query-processor.middleware.row-level-restrictions-test]}}}}
|
||||
|
||||
|
||||
:main-opts ["-m" "dev.liquibase"]}}}
|
||||
|
||||
;; TODO -- consider creating an alias that includes the `./bin` build-drivers & release code as well so we can work
|
||||
;; on them all from a single REPL process.
|
||||
|
||||
@@ -1,45 +1,9 @@
|
||||
;; # Metabase Backend Developer Documentation
|
||||
;;
|
||||
;; Welcome to Metabase! Here are links to useful resources.
|
||||
;;
|
||||
;; ## Project Management
|
||||
;;
|
||||
;; - [Engineering and Product Playbook](https://www.notion.so/metabase/Engineering-and-Product-Playbook-cd4bc1c0b8744470bebc0b979f8f5268)
|
||||
;; - [Weekly Tactical Board: how to](https://www.notion.so/metabase/Weekly-Tactical-Board-how-to-6e81f994a792493ba7ae430f2afa1673)
|
||||
;; - [The Escalations Process](https://www.notion.so/Escalating-a-bug-b876f78c801345f3bda8504d4a63ba80)
|
||||
;;
|
||||
;; ## Dev Environment
|
||||
;;
|
||||
;; - [Getting started with backend development](https://github.com/metabase/metabase/blob/master/docs/developers-guide/devenv.md#backend-development)
|
||||
;; - [Additional notes on using tools.deps](https://github.com/metabase/metabase/wiki/Migrating-from-Leiningen-to-tools.deps)
|
||||
;; - [Other tips](https://github.com/metabase/metabase/wiki/Metabase-Backend-Dev-Secrets)
|
||||
;;
|
||||
;; ## Important Parts of the Codebase
|
||||
;;
|
||||
;; - [API Endpoints](#metabase.api.common)
|
||||
;; - [Drivers](#metabase.driver)
|
||||
;; - [Permissions](#metabase.models.permissions)
|
||||
;; - [The Query Processor](#metabase.query-processor)
|
||||
;; - [Application Settings](#metabase.models.setting)
|
||||
;;
|
||||
;; ## Important Libraries
|
||||
;;
|
||||
;; - [Toucan 2](https://github.com/camsaul/toucan2/) to work with models
|
||||
;; - [Honey SQL](https://github.com/seancorfield/honeysql) (version 2) for SQL queries
|
||||
;; - [Liquibase](https://docs.liquibase.com/concepts/changelogs/changeset.html) for database migrations
|
||||
;; - [Compojure](https://github.com/weavejester/compojure) on top of [Ring](https://github.com/ring-clojure/ring) for our API
|
||||
;;
|
||||
;; <hr />
|
||||
|
||||
|
||||
(ns dev
|
||||
"Put everything needed for REPL development within easy reach"
|
||||
(:require
|
||||
[clojure.core.async :as a]
|
||||
[clojure.string :as str]
|
||||
[dev.debug-qp :as debug-qp]
|
||||
[dev.model-tracking :as model-tracking]
|
||||
[dev.explain :as dev.explain]
|
||||
[dev.debug-qp :as debug-qp]
|
||||
[honeysql.core :as hsql]
|
||||
[malli.dev :as malli-dev]
|
||||
[metabase.api.common :as api]
|
||||
@@ -60,11 +24,11 @@
|
||||
[metabase.test :as mt]
|
||||
[metabase.test.data.impl :as data.impl]
|
||||
[metabase.util :as u]
|
||||
[metabase.util.log :as log]
|
||||
[methodical.core :as methodical]
|
||||
[potemkin :as p]
|
||||
[toucan2.connection :as t2.connection]
|
||||
[toucan.db :as db]
|
||||
[toucan2.core :as t2]
|
||||
[toucan2.connection :as t2.connection]
|
||||
[toucan2.pipeline :as t2.pipeline]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
@@ -77,11 +41,7 @@
|
||||
(doto x tap>))
|
||||
|
||||
(p/import-vars
|
||||
[debug-qp
|
||||
process-query-debug
|
||||
pprint-sql]
|
||||
[dev.explain
|
||||
explain-query]
|
||||
[debug-qp process-query-debug]
|
||||
[model-tracking
|
||||
track!
|
||||
untrack!
|
||||
@@ -97,43 +57,18 @@
|
||||
(mbc/init!)
|
||||
(reset! initialized? true))
|
||||
|
||||
(defn deleted-inmem-databases
|
||||
"Finds in-memory Databases for which the underlying in-mem h2 db no longer exists."
|
||||
[]
|
||||
(let [h2-dbs (t2/select :model/Database :engine :h2)
|
||||
in-memory? (fn [db] (some-> db :details :db (str/starts-with? "mem:")))
|
||||
can-connect? (fn [db]
|
||||
(binding [metabase.driver.h2/*allow-testing-h2-connections* true]
|
||||
(try
|
||||
(driver/can-connect? :h2 (:details db))
|
||||
(catch org.h2.jdbc.JdbcSQLNonTransientConnectionException _
|
||||
false)
|
||||
(catch Exception e
|
||||
(log/error e "Error checking in-memory database for deletion")
|
||||
;; we don't want to delete these, so just pretend we could connect
|
||||
true))))]
|
||||
(remove can-connect? (filter in-memory? h2-dbs))))
|
||||
|
||||
(defn prune-deleted-inmem-databases!
|
||||
"Delete any in-memory Databases to which we can't connect (in order to trigger cleanup of their related tasks, which
|
||||
will otherwise spam logs)."
|
||||
[]
|
||||
(when-let [outdated-ids (seq (map :id (deleted-inmem-databases)))]
|
||||
(t2/delete! :model/Database :id [:in outdated-ids])))
|
||||
|
||||
(defn start!
|
||||
[]
|
||||
(server/start-web-server! #'handler/app)
|
||||
(when-not @initialized?
|
||||
(init!))
|
||||
(when config/is-dev?
|
||||
(prune-deleted-inmem-databases!)
|
||||
(with-out-str (malli-dev/start!))))
|
||||
(with-out-str (malli-dev/start!)))
|
||||
(when-not @initialized?
|
||||
(init!)))
|
||||
|
||||
(defn stop!
|
||||
[]
|
||||
(malli-dev/stop!)
|
||||
(server/stop-web-server!))
|
||||
(metabase.server/stop-web-server!))
|
||||
|
||||
(defn restart!
|
||||
[]
|
||||
@@ -207,17 +142,12 @@
|
||||
(try
|
||||
(driver/with-driver driver
|
||||
(letfn [(thunk []
|
||||
(let [db (mt/db)]
|
||||
(sql-jdbc.execute/do-with-connection-with-options
|
||||
driver
|
||||
db
|
||||
{:session-timezone (qp.timezone/report-timezone-id-if-supported driver db)}
|
||||
(fn [conn]
|
||||
(with-open [stmt (sql-jdbc.execute/prepared-statement driver conn sql params)
|
||||
rs (sql-jdbc.execute/execute-prepared-statement! driver stmt)]
|
||||
(let [rsmeta (.getMetaData rs)]
|
||||
{:cols (sql-jdbc.execute/column-metadata driver rsmeta)
|
||||
:rows (reduce conj [] (sql-jdbc.execute/reducible-rows driver rs rsmeta canceled-chan))}))))))]
|
||||
(with-open [conn (sql-jdbc.execute/connection-with-timezone driver (mt/db) (qp.timezone/report-timezone-id-if-supported driver (mt/db)))
|
||||
stmt (sql-jdbc.execute/prepared-statement driver conn sql params)
|
||||
rs (sql-jdbc.execute/execute-prepared-statement! driver stmt)]
|
||||
(let [rsmeta (.getMetaData rs)]
|
||||
{:cols (sql-jdbc.execute/column-metadata driver rsmeta)
|
||||
:rows (reduce conj [] (sql-jdbc.execute/reducible-rows driver rs rsmeta canceled-chan))})))]
|
||||
(if dataset
|
||||
(data.impl/do-with-dataset (data.impl/resolve-dataset-definition *ns* dataset) thunk)
|
||||
(thunk))))
|
||||
|
||||
@@ -6,8 +6,6 @@
|
||||
[clojure.walk :as walk]
|
||||
[lambdaisland.deep-diff2 :as ddiff]
|
||||
[medley.core :as m]
|
||||
[metabase.db.query :as mdb.query]
|
||||
[metabase.mbql.normalize :as mbql.normalize]
|
||||
[metabase.mbql.schema :as mbql.s]
|
||||
[metabase.mbql.util :as mbql.u]
|
||||
[metabase.models.field :refer [Field]]
|
||||
@@ -120,18 +118,18 @@
|
||||
(field-id->name-form [field-id]
|
||||
(list 'do (add-name-to-field-id field-id) field-id))]
|
||||
(mbql.u/replace form
|
||||
[:field (id :guard pos-int?) opts]
|
||||
[:field (id :guard integer?) opts]
|
||||
[:field id (add-name-to-field-id id) (cond-> opts
|
||||
(pos-int? (:source-field opts))
|
||||
(integer? (:source-field opts))
|
||||
(update :source-field field-id->name-form))]
|
||||
|
||||
(m :guard (every-pred map? (comp pos-int? :source-table)))
|
||||
(m :guard (every-pred map? (comp integer? :source-table)))
|
||||
(add-names* (update m :source-table add-table-id-name))
|
||||
|
||||
(m :guard (every-pred map? (comp pos-int? :metabase.query-processor.util.add-alias-info/source-table)))
|
||||
(m :guard (every-pred map? (comp integer? :metabase.query-processor.util.add-alias-info/source-table)))
|
||||
(add-names* (update m :metabase.query-processor.util.add-alias-info/source-table add-table-id-name))
|
||||
|
||||
(m :guard (every-pred map? (comp pos-int? :fk-field-id)))
|
||||
(m :guard (every-pred map? (comp integer? :fk-field-id)))
|
||||
(-> m
|
||||
(update :fk-field-id field-id->name-form)
|
||||
add-names*)
|
||||
@@ -516,7 +514,7 @@
|
||||
(_ :guard string?)
|
||||
(not (re-find #"\s+" x))
|
||||
|
||||
[:field (id :guard pos-int?) nil]
|
||||
[:field (id :guard integer?) nil]
|
||||
(every? can-symbolize? (field-and-table-name id))
|
||||
|
||||
[:field (field-name :guard string?) (opts :guard #(= (set (keys %)) #{:base-type}))]
|
||||
@@ -541,7 +539,7 @@
|
||||
(defn- expand [form table]
|
||||
(try
|
||||
(mbql.u/replace form
|
||||
([:field (id :guard pos-int?) nil] :guard can-symbolize?)
|
||||
([:field (id :guard integer?) nil] :guard can-symbolize?)
|
||||
(let [[table-name field-name] (field-and-table-name id)
|
||||
field-name (some-> field-name u/lower-case-en)
|
||||
table-name (some-> table-name u/lower-case-en)]
|
||||
@@ -569,19 +567,19 @@
|
||||
expansion (expand without-join-alias table)]
|
||||
[::& (:join-alias opts) expansion])
|
||||
|
||||
[:field (id :guard pos-int?) opts]
|
||||
[:field (id :guard integer?) opts]
|
||||
(let [without-opts [:field id nil]
|
||||
expansion (expand without-opts table)]
|
||||
(if (= expansion without-opts)
|
||||
&match
|
||||
[:field [::% (strip-$ expansion)] opts]))
|
||||
|
||||
(m :guard (every-pred map? (comp pos-int? :source-table)))
|
||||
(m :guard (every-pred map? (comp integer? :source-table)))
|
||||
(-> (update m :source-table (fn [table-id]
|
||||
[::$$ (some-> (t2/select-one-fn :name Table :id table-id) u/lower-case-en)]))
|
||||
(expand table))
|
||||
|
||||
(m :guard (every-pred map? (comp pos-int? :fk-field-id)))
|
||||
(m :guard (every-pred map? (comp integer? :fk-field-id)))
|
||||
(-> (update m :fk-field-id (fn [fk-field-id]
|
||||
(let [[table-name field-name] (field-and-table-name fk-field-id)
|
||||
field-name (some-> field-name u/lower-case-en)
|
||||
@@ -615,36 +613,29 @@
|
||||
[::$$ table-name]
|
||||
(symbol (format "$$%s" table-name))))
|
||||
|
||||
(defn- query-table-name [{:keys [source-table source-query], :as inner-query}]
|
||||
(defn- query-table-name [{:keys [source-table source-query]}]
|
||||
(cond
|
||||
(pos-int? source-table)
|
||||
(u/lower-case-en (or (t2/select-one-fn :name Table :id source-table)
|
||||
(throw (ex-info (format "Table %d does not exist!" source-table)
|
||||
{:source-table source-table, :inner-query inner-query}))))
|
||||
source-table
|
||||
(do
|
||||
(assert (integer? source-table))
|
||||
(u/lower-case-en (t2/select-one-fn :name Table :id source-table)))
|
||||
|
||||
source-query
|
||||
(recur source-query)))
|
||||
|
||||
(defn to-mbql-shorthand
|
||||
([query]
|
||||
(let [query (mbql.normalize/normalize query)]
|
||||
(to-mbql-shorthand query (query-table-name (:query query)))))
|
||||
(to-mbql-shorthand query (query-table-name (:query query))))
|
||||
|
||||
([query table-name]
|
||||
(let [symbolized (-> query (expand table-name) symbolize ->sorted-mbql-query-map)
|
||||
table-symb (some-> table-name symbol)]
|
||||
(if (:query symbolized)
|
||||
(list 'mt/mbql-query table-symb (cond-> (:query symbolized)
|
||||
table-name (dissoc :source-table)))
|
||||
(list 'mt/mbql-query table-symb (-> (:query symbolized)
|
||||
(dissoc :source-table)))
|
||||
(list 'mt/$ids table-symb symbolized)))))
|
||||
|
||||
(defn expand-symbolize [x]
|
||||
(-> x (expand "orders") symbolize))
|
||||
|
||||
;; tests are in [[dev.debug-qp-test]] (in `./dev/test/dev` dir)
|
||||
|
||||
(defn pprint-sql
|
||||
"Pretty print a SQL string."
|
||||
[driver sql]
|
||||
#_{:clj-kondo/ignore [:discouraged-var]}
|
||||
(println (mdb.query/format-sql sql driver)))
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
(ns dev.explain
|
||||
(:require
|
||||
[clojure.string :as str]
|
||||
[honey.sql :as sql]
|
||||
[toucan2.core :as t2]))
|
||||
|
||||
(defn explain-query
|
||||
"Explain a sql query or a honeysql query with option to analyze the query."
|
||||
([queryable]
|
||||
(explain-query queryable false))
|
||||
([queryable analyze?]
|
||||
(->> (t2/query
|
||||
(str/join
|
||||
" "
|
||||
(remove nil? ["EXPLAIN"
|
||||
(when analyze? "ANALYZE")
|
||||
"(" (if (map? queryable) (first (sql/format queryable {:inline true})) queryable) ")"])))
|
||||
(map #(get % (keyword "query plan"))))))
|
||||
@@ -1,15 +0,0 @@
|
||||
(ns dev.fe-helpers)
|
||||
|
||||
(defn redux-state []
|
||||
(let [root (js/document.querySelector "#root")
|
||||
store (.. root -_reactRootContainer -_internalRoot -current -child -memoizedProps -store)]
|
||||
(.getState store)))
|
||||
|
||||
(defn current-card []
|
||||
(.. (redux-state) -qb -card))
|
||||
|
||||
(defn current-legacy-query-js []
|
||||
(.-dataset_query (current-card)))
|
||||
|
||||
(defn current-query []
|
||||
(.-__MLv2_query js/window))
|
||||
@@ -1,17 +1,17 @@
|
||||
(ns dev.render-png
|
||||
"Improve feedback loop for dealing with png rendering code. Will create images using the rendering that underpins
|
||||
pulses and subscriptions and open those images without needing to send them to slack or email."
|
||||
(:require
|
||||
[clojure.java.io :as io]
|
||||
[clojure.java.shell :as sh]
|
||||
[hiccup.core :as hiccup]
|
||||
[metabase.models.card :as card]
|
||||
[metabase.models.user :as user]
|
||||
[metabase.pulse :as pulse]
|
||||
[metabase.pulse.render :as render]
|
||||
[metabase.pulse.render.test-util :as render.tu]
|
||||
[metabase.query-processor :as qp]
|
||||
[metabase.query-processor.middleware.permissions :as qp.perms]))
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.java.shell :as sh]
|
||||
[hiccup.core :as hiccup]
|
||||
[metabase.models.card :as card]
|
||||
[metabase.models.user :as user]
|
||||
[metabase.pulse :as pulse]
|
||||
[metabase.pulse.render :as render]
|
||||
[metabase.pulse.render.test-util :as render.tu]
|
||||
[metabase.query-processor :as qp]
|
||||
[metabase.query-processor.middleware.permissions :as qp.perms]
|
||||
[toucan.db :as db]))
|
||||
|
||||
;; taken from https://github.com/aysylu/loom/blob/master/src/loom/io.clj
|
||||
(defn- os
|
||||
@@ -56,9 +56,9 @@
|
||||
:context :pulse
|
||||
:card-id card-id}))
|
||||
png-bytes (render/render-pulse-card-to-png (pulse/defaulted-timezone card)
|
||||
card
|
||||
query-results
|
||||
1000)
|
||||
card
|
||||
query-results
|
||||
1000)
|
||||
tmp-file (java.io.File/createTempFile "card-png" ".png")]
|
||||
(with-open [w (java.io.FileOutputStream. tmp-file)]
|
||||
(.write w ^bytes png-bytes))
|
||||
@@ -91,5 +91,5 @@
|
||||
:custom-column-names {:names ["-A-" "-B-" "-C-" "-D-"]}
|
||||
:hidden-columns {:hide [0 2]}})
|
||||
:viz-tree
|
||||
open-hiccup-as-html))
|
||||
|
||||
open-hiccup-as-html)
|
||||
)
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
(ns user
|
||||
(:require
|
||||
[environ.core :as env]
|
||||
[humane-are.core :as humane-are]
|
||||
[mb.hawk.assert-exprs]
|
||||
[metabase.bootstrap]
|
||||
[metabase.test-runner.assert-exprs]
|
||||
[pjstadig.humane-test-output :as humane-test-output]))
|
||||
|
||||
;; Initialize Humane Test Output if it's not already initialized. Don't enable humane-test-output when running tests
|
||||
;; from the CLI, it breaks diffs. This uses [[env/env]] rather than [[metabase.config]] so we don't load that namespace
|
||||
;; before we load [[metabase.bootstrap]]
|
||||
(when-not (= (env/env :mb-run-mode) "test")
|
||||
(humane-test-output/activate!))
|
||||
|
||||
;;; Same for https://github.com/camsaul/humane-are
|
||||
(humane-are/install!)
|
||||
[metabase.test-runner.assert-exprs]))
|
||||
|
||||
(comment metabase.bootstrap/keep-me
|
||||
;; make sure stuff like `schema=` and what not are loaded
|
||||
|
||||
@@ -16,27 +16,27 @@
|
||||
(model-tracking/track! 'Collection)
|
||||
|
||||
(testing "insert"
|
||||
(t2/insert! Collection {:name "Test tracking" :description "My awesome collection"})
|
||||
(t2/insert! Collection {:name "Test tracking" :color "#000000"})
|
||||
(testing "should be tracked"
|
||||
(is (=? [{:name "Test tracking"
|
||||
:description "My awesome collection"}]
|
||||
:color "#000000"}]
|
||||
(get-in (model-tracking/changes) [:collection :insert]))))
|
||||
(testing "should take affects"
|
||||
(is (= 1 (t2/count Collection :name "Test tracking")))))
|
||||
|
||||
(testing "update"
|
||||
(t2/update! Collection {:name "Test tracking"} {:description "Amazing collection"})
|
||||
(t2/update! Collection {:name "Test tracking"} {:color "#ffffff"})
|
||||
(testing "changes should be tracked"
|
||||
(is (= [{:description "Amazing collection"}]
|
||||
(is (= [{:color "#ffffff"}]
|
||||
(get-in (model-tracking/changes) [:collection :update]))))
|
||||
(testing "should take affects"
|
||||
(is (= "Amazing collection" (t2/select-one-fn :description Collection :name "Test tracking")))))
|
||||
(is (= "#ffffff" (t2/select-one-fn :color Collection :name "Test tracking")))))
|
||||
|
||||
(testing "delete"
|
||||
(let [coll-id (t2/select-one-pk Collection :name "Test tracking")]
|
||||
(t2/delete! Collection coll-id)
|
||||
(testing "should be tracked"
|
||||
(is (=? [{:description "Amazing collection"
|
||||
(is (=? [{:color "#ffffff"
|
||||
:name "Test tracking",
|
||||
:id coll-id}]
|
||||
(get-in (model-tracking/changes) [:collection :delete]))))
|
||||
@@ -46,18 +46,18 @@
|
||||
(testing "untrack should stop all tracking for"
|
||||
(model-tracking/untrack-all!)
|
||||
(testing "insert"
|
||||
(t2/insert! Collection {:name "Test tracking" :description "My awesome collection"})
|
||||
(t2/insert! Collection {:name "Test tracking" :color "#000000"})
|
||||
(testing "changes not should be tracked"
|
||||
(is (empty? (model-tracking/changes))))
|
||||
(testing "should take affects"
|
||||
(is (= 1 (t2/count Collection :name "Test tracking")))))
|
||||
|
||||
(testing "update"
|
||||
(t2/update! Collection {:name "Test tracking"} {:description "Amazing collection"})
|
||||
(t2/update! Collection {:name "Test tracking"} {:color "#ffffff"})
|
||||
(testing "changes not should be tracked"
|
||||
(is (empty? (model-tracking/changes))))
|
||||
(testing "should take affects"
|
||||
(is (= "Amazing collection" (t2/select-one-fn :description Collection :name "Test tracking")))))
|
||||
(is (= "#ffffff" (t2/select-one-fn :color Collection :name "Test tracking")))))
|
||||
|
||||
(testing "delete"
|
||||
(let [coll-id (t2/select-one-pk Collection :name "Test tracking")]
|
||||
|
||||
@@ -58,7 +58,6 @@ Metabase's reference documentation.
|
||||
- [Encrypting your database connection](./databases/encrypting-details-at-rest.md)
|
||||
- [SSH tunneling](./databases/ssh-tunnel.md)
|
||||
- [SSL certificate](./databases/ssl-certificates.md)
|
||||
- [Uploading data](./databases/uploads.md)
|
||||
|
||||
### Questions
|
||||
|
||||
@@ -156,9 +155,9 @@ Metabase's reference documentation.
|
||||
|
||||
- [Embedding overview](./embedding/start.md)
|
||||
- [Embedding introduction](./embedding/introduction.md)
|
||||
- [Interactive embedding](./embedding/interactive-embedding.md)
|
||||
- [Static embedding](./embedding/static-embedding.md)
|
||||
- [Parameters for static embeds](./embedding/static-embedding-parameters.md)
|
||||
- [Full-app embedding](./embedding/full-app-embedding.md)
|
||||
- [Signed embedding](./embedding/signed-embedding.md)
|
||||
- [Parameters for signed embeds](./embedding/signed-embedding-parameters.md)
|
||||
|
||||
### Configuration
|
||||
|
||||
|
||||
@@ -56,12 +56,6 @@ See [Actions in dashboards](../dashboards/actions.md).
|
||||
|
||||
Because basic actions are made of magic, you cannot archive them. You can just toggle them on or off. From the model detail page, next to the **New action** button, click on the **...** menu and click **Disable basic actions**.
|
||||
|
||||
## Basic actions from object detail view
|
||||
|
||||
If you have basic actions enabled for a model, you can click on an individual record to view its object detail. From that object detail model, you can click on the ellipses (**...**) and select update or delete to modify that specific record.
|
||||
|
||||

|
||||
|
||||
## Further reading
|
||||
|
||||
- [Introduction to actions](./introduction.md)
|
||||
|
||||
@@ -118,6 +118,37 @@ VALUES (
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
### `INSERT` statement with optional fields
|
||||
|
||||
Though if you want to make a field optional in an `INSERT` statement, you need to get a little fancy. Metabase will only run an optional statement if a value is supplied to a variable in that optional statement, so the trick here is to use a SQL comment to sneak a variable into the optional column.
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
[[,expected_invoice -- {{ expected_invoice}}]]
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
So a full `INSERT` statement with an optional variable would look like so (note that the optional clauses for the `{% raw %}{{ expected_invoice}}{{% endraw %}` variable are in both the column and values lists):
|
||||
|
||||
```
|
||||
{% raw %}
|
||||
INSERT INTO invoices (
|
||||
account_id
|
||||
,payment
|
||||
[[,expected_invoice -- {{expected_invoice}}]]
|
||||
,plan
|
||||
,date_received
|
||||
)
|
||||
VALUES (
|
||||
{{ account_id }}
|
||||
,{{ payment }}
|
||||
[[,{{ expected_invoice }}]]
|
||||
,{{ plan }}
|
||||
,({{ date_received }}
|
||||
);
|
||||
{% endraw %}
|
||||
```
|
||||
|
||||
### Casting field values in actions
|
||||
|
||||
If you get a type error when you submit a form, you may need to `CAST` the data type in the query so it matches the data type of the target field in the database. Here we're casting a value to a `boolean`:
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user