開發環境
Metabase 應用程式有兩個基本元件
- 後端以 Clojure 撰寫,包含 REST API 以及所有與資料庫通訊和處理查詢的相關程式碼。
- 前端以 Javascript 單頁應用程式撰寫,提供 Web UI。
這兩個元件會建置並組裝成單一 JAR 檔案。在執行 JAR 的目錄中,您可以建立 JAR 檔案 (如果 Metabase 尚未建立),並在其中新增驅動程式 (驅動程式也是 JAR)。
快速入門
若要啟動開發環境,請執行
yarn dev
這會同時執行前端和後端。或者,您也可以在下方的兩個終端機工作階段中分別執行它們。
前端
Metabase 依賴第三方程式庫才能執行,因此您需要讓這些程式庫保持在最新狀態。Clojure CLI 會在需要時自動擷取相依性。但是,對於 JavaScript 相依性,您需要手動啟動安裝程序。
# javascript dependencies
$ yarn
使用下列指令啟動前端建置程序:
yarn build-hot
請參閱前端開發。
後端
使用下列指令執行後端開發伺服器:
clojure -M:run
請參閱後端開發。
前端開發
我們將這些技術用於 FE 建置程序,以便我們可以使用模組、es6 語法和 css 變數。
- webpack
- babel
- cssnext
前端工作是使用 yarn
執行。所有可用的工作都可以在 package.json
中的 scripts 下找到。
若要建置前端用戶端而不監看變更,您可以使用
$ yarn build
如果您直接在前端工作,您很可能想要在儲存時重新載入變更,如果是 React 元件,則在維護狀態時重新載入變更。若要啟動具有熱重新載入的建置,請使用
$ yarn build-hot
請注意,此時如果您變更 CSS 變數,則只有在重新啟動建置時才會擷取這些變更。
還有一個選項可以在儲存時重新載入變更,而不需要熱重新載入 (如果您偏好如此)。
$ yarn build-watch
某些系統可能無法偵測到前端檔案的變更。您可以取消註解 webpack.config.js
中的 watchOptions
子句來啟用檔案系統輪詢。如果您這樣做,可能值得讓 git 忽略 webpack 組態的變更,方法是使用 git update-index --assume-unchanged webpack.config.js
依預設,我們在開發模式中排除 ESLint 載入器,以加快七倍的初始建置速度。您可以藉由匯出環境變數來啟用它
$ USE_ESLINT=true yarn build-hot
依預設,這些建置程序依賴記憶體快取。啟用 ESLint 載入器的建置程序會使用大量記憶體,而且可能需要相當長的時間才能啟動 (1-2 分鐘或更久)。建議 FE 開發人員 (或任何經常重新啟動 FE 建置的人員) 使用 webpack 的檔案系統快取選項,以獲得更好的啟動效能
$ FS_CACHE=true yarn build-hot
使用 FS_CACHE=true
時,您可能需要移除 node_modules/.cache
目錄,以修正建置可能未正確快取的情況,而且您必須執行 rm -rf node_modules/.cache
,才能讓建置在開放原始碼和企業版程式碼庫之間交替時正常運作。
前端測試
使用下列指令執行所有單元測試和 Cypress 端對端測試:
yarn test
Cypress 測試和某些單元測試位於 frontend/test
目錄中。新的單元測試檔案會新增到它們測試的檔案旁邊。
如果您使用 FS_CACHE=true
,您也可以搭配 yarn test
使用 FS_CACHE=true
。
前端偵錯
依預設,我們使用針對速度最佳化的簡單來源對應選項。
如果您在斷點方面遇到問題,尤其是在 jsx 內部,請在執行伺服器之前將環境變數 BETTER_SOURCE_MAPS
設定為 true。
範例
BETTER_SOURCE_MAPS=true yarn dev
Cypress 端對端測試
端對端測試會模擬實際的使用者互動序列。深入了解我們如何使用 Cypress 進行端對端測試。
Cypress 端對端測試使用強制檔案命名慣例 <test-suite-name>.cy.spec.js
,將它們與單元測試分開。
Jest 單元測試
單元測試著重於隔離的業務邏輯部分。
單元測試使用強制檔案命名慣例 <test-suite-name>.unit.spec.js
,將它們與端對端測試分開。
yarn test-unit # Run all tests at once
yarn test-unit-watch # Watch for file changes
後端開發
Clojure REPL 是後端的主要開發工具。以下提供一些關於如何設定 REPL 以簡化開發的指示。
當然,您的 Jetty 開發伺服器也可以透過
clojure -M:run
您也可以透過其他方式 (例如,透過您的編輯器) 啟動 REPL,然後呼叫
(do (dev) (start!))
以啟動伺服器 (localhost:3000
)。這也會設定或移轉您的應用程式資料庫。若要實際使用 Metabase,請別忘了也啟動前端 (例如,使用 yarn build-hot
)。
應用程式資料庫
依預設,Metabase 會使用 H2 作為其應用程式資料庫,但我們建議使用 Postgres。這會使用多個屬性進行設定,這些屬性可以設定為環境變數或在 deps.edn
中設定。其中一種方法是
;; ~/.clojure/deps.edn
{:aliases
{:user
{:jvm-opts
["-Dmb.db.host=localhost"
"-Dmb.db.type=postgres"
"-Dmb.db.user=<username>"
"-Dmb.db.dbname=<dbname>"
"-Dmb.db.pass="]}}}
您也可以將完整的連線字串以 mb.db.connection.uri
傳遞進來
"-Dmb.db.connection.uri=postgres://<user>:<password>@localhost:5432/<dbname>"
除了使用環境變數之外,還有一個選項可以直接與組態程式庫 environ 介接。
此方法需要專案目錄中建立 .lein-env
檔案
{:mb-db-type "postgres"
:mb-db-host "localhost"
:mb-db-user "<username>"
:mb-db-dbname "<dbname>"
:mb-db-pass ""}
儘管名稱如此,此檔案仍可與 deps.edn
專案正常運作。相較於全域 deps.edn
方法,此方法的優點是它僅限於此專案。
僅限用於開發,不支援用於生產環境。 .gitignore
中已有項目,可防止您意外提交此檔案。
建置驅動程式
Metabase 用於連線至外部資料倉儲資料庫的大部分驅動程式都是 modules/
子目錄下的個別專案。透過 clojure
執行 Metabase 時,您需要建置這些驅動程式才能存取它們。您可以依照下列方式建置驅動程式
# Build the 'mongo' driver
./bin/build-driver.sh mongo
(或)
# Build all drivers
./bin/build-drivers.sh
包含驅動程式來源路徑以進行開發或其他工作
若要在執行各種 Clojure 工作時進行開發,您可以新增 drivers
和 drivers-dev
別名,以將驅動程式的相依性和來源路徑合併到 Metabase 專案中
# Install dependencies, including for drivers
clojure -P -X:dev:ci:drivers:drivers-dev
執行單元測試
使用下列指令執行單元測試:
# OSS tests only
clojure -X:dev:test
# OSS + EE tests
clojure -X:dev:ee:ee-dev:test
或使用下列指令執行特定測試 (或測試命名空間):
# run tests in only one namespace (pass in a symbol)
clojure -X:dev:test :only metabase.api.session-test
# run one specific test (pass in a qualified symbol)
clojure -X:dev:test :only metabase.api.session-test/my-test
# run tests in one specific folder (test/metabase/util in this example)
# pass arg in double-quotes so Clojure CLI interprets it as a string;
# our test runner treats strings as directories
clojure -X:dev:test :only '"test/metabase/util"'
如同任何 clojure.test 專案,您也可以從 REPL 執行單元測試。以下是一些執行測試的實用方式範例:
;; run a single test with clojure.test
some-ns=> (clojure.test/run-test metabase.util-test/add-period-test)
Testing metabase.util-test
Ran 1 tests containing 4 assertions.
0 failures, 0 errors.
{:test 1, :pass 4, :fail 0, :error 0, :type :summary}
;; run all tests in the namespace
some-ns=> (clojure.test/run-tests 'metabase.util-test)
Testing metabase.util-test
{:result true, :num-tests 100, :seed 1696600311261, :time-elapsed-ms 45, :test-var "pick-first-test"}
Ran 33 tests containing 195 assertions.
0 failures, 0 errors.
{:test 33, :pass 195, :fail 0, :error 0, :type :summary}
;; run tests for a set of namespaces related to a feature you are working on (eg pulses)
some-ns=> (let [namespaces '[metabase.pulse.markdown-test metabase.pulse.parameters-test]]
(apply require namespaces) ;; make sure the test namespaces are loaded
(apply clojure.test/run-tests namespaces))
Testing metabase.pulse.markdown-test
Testing metabase.pulse.parameters-test
Ran 5 tests containing 147 assertions.
0 failures, 0 errors.
{:test 5, :pass 147, :fail 0, :error 0, :type :summary}
;; but we also have a lovely test runner with lots of cool options
some-ns=> (metabase.test-runner/find-and-run-tests-repl {:namespace-pattern ".*pulse.*"})
Running tests with options {:mode :repl, :namespace-pattern ".*pulse.*", :exclude-directories ["classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000}
Excluding directory "dev/src"
Excluding directory "local/src"
Looking for test namespaces in directory test
Finding tests took 1.6 s.
Excluding directory "test_resources"
Excluding directory "enterprise/backend/src"
Looking for test namespaces in directory enterprise/backend/test
Excluding directory "src"
Excluding directory "resources"
Running 159 tests
...
;; you can even specify a directory if you're working on a subfeature like that
some-ns=> (metabase.test-runner/find-and-run-tests-repl {:only "test/metabase/pulse/"})
Running tests with options {:mode :repl, :namespace-pattern #"^metabase.*", :exclude-directories ["classes" "dev" "enterprise/backend/src" "local" "resources" "resources-ee" "src" "target" "test_config" "test_resources"], :test-warn-time 3000, :only "test/metabase/pulse/"}
Running tests in "test/metabase/pulse/"
Looking for test namespaces in directory test/metabase/pulse
Finding tests took 37.0 ms.
Running 65 tests
...
測試驅動程式
依預設,測試僅針對 h2
驅動程式執行。您可以使用環境變數 DRIVERS
指定要針對哪些驅動程式執行測試
DRIVERS=h2,postgres,mysql,mongo clojure -X:dev:drivers:drivers-dev:test
某些驅動程式在測試時需要額外的環境變數,因為它們無法在本機執行 (例如 Redshift 和 Bigquery)。如果需要,測試將會在啟動時失敗並告知您要提供的參數。
如果從 REPL 執行測試,您可以呼叫類似下列的指令
(mt/set-test-drivers! #{:postgres :mysql :h2})
大部分驅動程式都需要能夠載入一些資料 (少數驅動程式使用靜態資料集),而且所有驅動程式都需要能夠連線至該資料庫的執行個體。您可以在每個驅動程式的測試資料命名空間中找到所需的內容,該命名空間遵循 metabase.test.data.<driver>
模式。
應該要有 multimethod tx/dbdef->connection-details 的實作,其必須產生連線至資料庫的方式。您可以查看所需的內容。
以下是 metabase.test.data.postgres
中 postgres 的實作
(defmethod tx/dbdef->connection-details :postgres
[_ context {:keys [database-name]}]
(merge
{:host (tx/db-test-env-var-or-throw :postgresql :host "localhost")
:port (tx/db-test-env-var-or-throw :postgresql :port 5432)
:timezone :America/Los_Angeles}
(when-let [user (tx/db-test-env-var :postgresql :user)]
{:user user})
(when-let [password (tx/db-test-env-var :postgresql :password)]
{:password password})
(when (= context :db)
{:db database-name})))
您可以看到這會在環境中尋找
- 主機 (預設為「localhost」)
- 連接埠 (預設為 5432)
- 使用者
- 密碼
函式名稱表示它們是否會擲回例外狀況 (雖然在此情況下,會擲回例外狀況的函式也會提供預設值)。
(tx/db-test-env-var :postgresql :password)
將會在 env/env 對應中尋找 :mb-postgresql-test-password
,這會由環境變數 MB_POSTGRESQL_TEST_PASSWORD
設定。
some-ns=> (take 10 (keys environ.core/env))
(:mb-redshift-test-password
:java-class-path
:path
:mb-athena-test-s3-staging-dir
:iterm-profile
:mb-snowflake-test-warehouse
:mb-bigquery-cloud-sdk-test-service-account-json
:tmpdir
:mb-oracle-test-service-name
:sun-management-compiler)
執行檢查器
clj-kondo
必須個別安裝。
# Run Eastwood
clojure -X:dev:ee:ee-dev:drivers:drivers-dev:eastwood
# Run the namespace checker
clojure -X:dev:ee:ee-dev:drivers:drivers-dev:test:namespace-checker
# Run clj-kondo
./bin/kondo.sh
# Lint the migrations file (if you've written a database migration):
./bin/lint-migrations-file.sh
持續整合
所有前端和後端檢查器與測試都可以使用下列指令執行:
$ yarn ci
也可以分別執行前端和後端檢查
$ yarn ci-frontend
$ yarn ci-backend
閱讀 Metabase 其他版本的文件。