跳至主要內容
在 GitHub 上編輯此頁面

開發指南

貢獻文件

最新的文件和教學可在 https://superset.dev.org.tw/ 取得。

文件網站是使用 Docusaurus 2 建立的,這是一個現代靜態網站產生器,其原始碼位於 ./docs

本地開發

要為文件網站設定具有熱重載功能的本地開發環境

cd docs
yarn install # Installs NPM dependencies
yarn start # Starts development server at https://127.0.0.1:3000

建置

要建立並提供文件網站的生產版本

yarn build
yarn serve

部署

master 的提交會觸發文件網站的重建和重新部署。提交修改文件的 pull request 時,請加上 docs: 前綴。

建立視覺化外掛程式

Superset 中的視覺化效果是以 JavaScript 或 TypeScript 實作的。Superset 預先安裝了幾種視覺化類型(以下簡稱「viz 外掛程式」),可以在 superset-frontend/plugins 目錄下找到。Viz 外掛程式會被新增至 superset-frontend/src/visualizations/presets/MainPreset.js 中的應用程式。Superset 專案總是樂於審查新的高品質 viz 外掛程式的提案。但是,對於高度自訂的 viz 類型,建議維護 Superset 的分支,並手動新增自訂建置的 viz 外掛程式。

注意:有關建立和部署自訂視覺化外掛程式的其他社群產生資源,可以在 Superset Wiki 上找到

先決條件

為了建立新的 viz 外掛程式,您需要以下項目

  • 執行 MacOS 或 Linux(不正式支援 Windows,但可能可以運作)
  • Node.js 16
  • npm 7 或 8

還建議對 React 和 npm/Node 系統有基本的熟悉程度。

建立簡單的 Hello World viz 外掛程式

若要開始,您需要 Superset Yeoman Generator。建議使用與您使用的 Superset 版本一起發布的範本版本。可以透過執行以下操作來安裝:

npm i -g yo
cd superset-frontend/packages/generator-superset
npm i
npm link

之後,您可以繼續建立您的 viz 外掛程式。使用字首 superset-plugin-chart 為您的 viz 外掛程式建立新目錄,並執行 Yeoman 產生器

mkdir /tmp/superset-plugin-chart-hello-world
cd /tmp/superset-plugin-chart-hello-world

初始化 viz 外掛程式

yo @superset-ui/superset

之後,產生器會詢問幾個問題(預設值應該可以接受)

$ yo @superset-ui/superset
_-----_ ╭──────────────────────────╮
| | │ Welcome to the │
|--(o)--| │ generator-superset │
`---------´ │ generator! │
( _´U`_ ) ╰──────────────────────────╯
/___A___\ /
| ~ |
__'.___.'__
´ ` |° ´ Y `
? Package name: superset-plugin-chart-hello-world
? Description: Hello World
? What type of chart would you like? Time-series chart
create package.json
create .gitignore
create babel.config.js
create jest.config.js
create README.md
create tsconfig.json
create src/index.ts
create src/plugin/buildQuery.ts
create src/plugin/controlPanel.ts
create src/plugin/index.ts
create src/plugin/transformProps.ts
create src/types.ts
create src/SupersetPluginChartHelloWorld.tsx
create test/index.test.ts
create test/__mocks__/mockExportString.js
create test/plugin/buildQuery.test.ts
create test/plugin/transformProps.test.ts
create types/external.d.ts
create src/images/thumbnail.png

若要建置 viz 外掛程式,請執行以下命令

npm i --force
npm run build

或者,若要在開發模式下執行 viz 外掛程式(=每當變更時重新建置),請使用以下命令啟動開發伺服器

npm run dev

若要將套件新增至 Superset,請移至 Superset 原始碼資料夾中的 superset-frontend 子目錄,然後執行

npm i -S /tmp/superset-plugin-chart-hello-world

如果您將套件發布到 npm,您也可以直接從那裡安裝。在此之後,編輯 superset-frontend/src/visualizations/presets/MainPreset.js 並進行以下變更

import { SupersetPluginChartHelloWorld } from 'superset-plugin-chart-hello-world';

匯入 viz 外掛程式,稍後將以下內容新增至傳遞給 plugins 屬性的陣列

new SupersetPluginChartHelloWorld().configure({ key: 'ext-hello-world' }),

之後,當您執行 Superset(例如開發伺服器)時,viz 外掛程式應該會出現

npm run dev-server

測試

Python 測試

所有 python 測試都是在 tox 這個標準化的測試框架中進行的。可以使用 tox 的任何 環境來執行所有 python 測試,透過

tox -e <environment>

例如,

tox -e py38

或者,您可以使用以下方式在單一檔案中執行所有測試

tox -e <environment> -- tests/test_file.py

或使用以下方式針對特定測試

tox -e <environment> -- tests/test_file.py::TestClassName::test_method_name

請注意,測試環境會使用暫存目錄來定義 SQLite 資料庫,每次叫用測試命令群組之前都會清除這些資料庫。

Superset 程式碼庫中還包含一個公用程式指令碼,可以用於執行 python 整合測試。可以在這裡找到讀我檔案

例如,若要執行所有整合測試,請從根目錄執行此指令碼

scripts/tests/run.sh

您可以使用 pytest 執行在 './tests/unit_tests' 中找到的單元測試。這是一種執行不需要任何資料庫設定的隔離測試的簡單方法

pytest ./link_to_test.py

使用本地 Presto 連線進行測試

如果您碰巧變更 Presto/Trino 的資料庫引擎規格,您可以使用 Docker 執行本地 Presto 叢集

docker run -p 15433:15433 starburstdata/presto:350-e.6

然後更新 SUPERSET__SQLALCHEMY_EXAMPLES_URI 以指向本地 Presto 叢集

export SUPERSET__SQLALCHEMY_EXAMPLES_URI=presto://127.0.0.1:15433/memory/default

前端測試

我們使用 JestEnzyme 來測試 TypeScript/JavaScript。可以使用以下方式執行測試

cd superset-frontend
npm run test

若要執行單一測試檔案

npm run test -- path/to/file.js

e2e 整合測試

我們使用 Cypress 進行端對端整合測試。快速開始的一個簡單選項是利用 tox 在隔離的環境中執行整個套件。

tox -e cypress

或者,您可以按照以下步驟在開發環境中進行更低階的設定

首先設定 python/flask 後端

export SUPERSET_CONFIG=tests.integration_tests.superset_test_config
export SUPERSET_TESTENV=true
export CYPRESS_BASE_URL="https://127.0.0.1:8081"
superset db upgrade
superset load_test_users
superset init
superset load-examples --load-test-data
superset run --port 8081

在另一個終端機中,準備前端並執行 Cypress 測試

cd superset-frontend
npm run build-instrumented

cd cypress-base
npm install

# run tests via headless Chrome browser (requires Chrome 64+)
npm run cypress-run-chrome

# run tests from a specific file
npm run cypress-run-chrome -- --spec cypress/e2e/explore/link.test.ts

# run specific file with video capture
npm run cypress-run-chrome -- --spec cypress/e2e/dashboard/index.test.js --config video=true

# to open the cypress ui
npm run cypress-debug

# to point cypress to a url other than the default (https://127.0.0.1:8088) set the environment variable before running the script
# e.g., CYPRESS_BASE_URL="https://127.0.0.1:9000"
CYPRESS_BASE_URL=<your url> npm run cypress open

請參閱 superset-frontend/cypress_build.sh

作為替代方案,您可以使用 docker compose 環境進行測試

請確保您已將以下行新增至 /etc/hosts 檔案:127.0.0.1 db

如果您已經啟動 Docker 環境,請使用以下命令來確保有全新的資料庫執行個體:docker compose down -v

啟動環境

CYPRESS_CONFIG=true docker compose up

它將在連接埠 8088 上提供後端和前端。

執行 Cypress 測試

cd cypress-base
npm install
npm run cypress open

偵錯伺服器應用程式

請依照這些指示偵錯在 docker 容器內執行的 Flask 應用程式。

首先,將以下內容新增至 ./docker-compose.yaml 檔案

superset:
env_file: docker/.env
image: *superset-image
container_name: superset_app
command: ["/app/docker/docker-bootstrap.sh", "app"]
restart: unless-stopped
+ cap_add:
+ - SYS_PTRACE
ports:
- 8088:8088
+ - 5678:5678
user: "root"
depends_on: *superset-depends-on
volumes: *superset-volumes
environment:
CYPRESS_CONFIG: "${CYPRESS_CONFIG}"

照常啟動 Superset

docker compose up

將所需的程式庫和套件安裝到 docker 容器

進入 superset_app 容器

docker exec -it superset_app /bin/bash
root@39ce8cf9d6ab:/app#

在容器內執行以下命令

apt update
apt install -y gdb
apt install -y net-tools
pip install debugpy

尋找 Flask 程序的 PID。請務必使用第一個 PID。每當您變更任何 python 程式碼時,Flask 應用程式都會重新產生一個子程序。因此,使用第一個 PID 非常重要。

ps -ef

UID PID PPID C STIME TTY TIME CMD
root 1 0 0 14:09 ? 00:00:00 bash /app/docker/docker-bootstrap.sh app
root 6 1 4 14:09 ? 00:00:04 /usr/local/bin/python /usr/bin/flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0
root 10 6 7 14:09 ? 00:00:07 /usr/local/bin/python /usr/bin/flask run -p 8088 --with-threads --reload --debugger --host=0.0.0.0

將 debugpy 注入正在執行的 Flask 程序。在此範例中,PID 為 6。

python3 -m debugpy --listen 0.0.0.0:5678 --pid 6

驗證 debugpy 是否正在連接埠 5678 上接聽

netstat -tunap

Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:5678 0.0.0.0:* LISTEN 462/python
tcp 0 0 0.0.0.0:8088 0.0.0.0:* LISTEN 6/python

您現在已準備好將偵錯工具附加至程序。使用 VSCode,您可以設定類似以下的啟動設定檔案 .vscode/launch.json。

{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to Superset App in Docker Container",
"type": "python",
"request": "attach",
"connect": {
"host": "127.0.0.1",
"port": 5678
},
"pathMappings": [
{
"localRoot": "${workspaceFolder}",
"remoteRoot": "/app"
}
]
},
]
}

VSCode 不會立即在斷點處停止。我們已附加至 PID 6,但它還不知道任何子程序。為了「喚醒」偵錯工具,您需要修改 python 檔案。這會觸發 Flask 重新載入程式碼並建立新的子程序。VSCode 會偵測到此新的子程序,並啟動斷點。

在 Kubernetes 環境中偵錯伺服器應用程式

若要在 Kubernetes 叢集內的 POD 中偵錯執行的 Flask,您需要確保 pod 以 root 身份執行,並被授予 SYS_TRACE 功能。這些設定不應在生產環境中使用。

  securityContext:
capabilities:
add: ["SYS_PTRACE"]

請參閱 設定容器的功能 以取得更多詳細資訊。

一旦 pod 以 root 身分執行並具有 SYS_PTRACE 功能,它將能夠偵錯 Flask 應用程式。

您可以依照與 docker compose 相同的指示操作。進入 pod 並安裝所需的函式庫和套件:gdb、netstat 和 debugpy。

在 Kubernetes 環境中,節點通常無法從叢集外部存取。因此,VSCode 將無法遠端連線至 Kubernetes 節點上的 5678 連接埠。為了達成此目的,您需要建立一個通道,將 5678 連接埠轉發到您的本機。

kubectl port-forward  pod/superset-<some random id> 5678:5678

現在,您可以使用與上述相同的設定啟動 VSCode 偵錯工具。VSCode 將會連線至 127.0.0.1:5678,該連接埠會由 kubectl 轉發至您的遠端 Kubernetes POD。

Storybook

Superset 包含一個 Storybook,可預覽各種 Superset 元件的版面配置/樣式及其變化。要開啟和檢視 Storybook

cd superset-frontend
npm run storybook

當向 Superset 貢獻新的 React 元件時,請嘗試在元件的 jsx/tsx 檔案旁邊新增一個 Story。

貢獻翻譯

我們使用 Flask-Babel 來翻譯 Superset。在 Python 檔案中,我們使用來自 Flask-Babel 的以下 翻譯函式

  • gettextlazy_gettext(通常別名為 _):用於翻譯單數字串。
  • ngettext:用於翻譯可能變成複數的字串。
from flask_babel import lazy_gettext as _

然後將可翻譯的字串包裝在其中,例如 _('Translate me')。在擷取期間,傳遞給 _ 的字串文字將會新增到每個語言產生的 .po 檔案中,以供稍後翻譯。

在執行期間,_ 函式將會傳回目前語言給定字串的翻譯,如果沒有可用的翻譯,則傳回給定的字串本身。

在 TypeScript/JavaScript 中,技術類似:我們匯入 t(簡單翻譯)、tn(包含數字的翻譯)。

import { t, tn } from "@superset-ui/translation";

啟用語言選擇

LANGUAGES 變數新增至您的 superset_config.py。在其中加入一個以上的選項,將會在導覽列右側的 UI 中新增一個語言選擇下拉式選單。

LANGUAGES = {
'en': {'flag': 'us', 'name': 'English'},
'fr': {'flag': 'fr', 'name': 'French'},
'zh': {'flag': 'cn', 'name': 'Chinese'},
}

建立新的語言字典

首先,請檢查目標語言的語言代碼是否已存在。檢查您的目標語言的 雙字母 ISO 639-1 代碼 是否已存在於 superset/translations 目錄中

ls superset/translations | grep -E "^[a-z]{2}\/"

如果您的語言已經有預先存在的翻譯,請跳至下一節

以下語言已受到 Flask AppBuilder 的支援,將會更容易將應用程式翻譯成您的目標語言:Flask AppBuilder i18n 文件

若要為新語言建立字典,請先確認已安裝必要的相依性

pip install -r superset/translations/requirements.txt

然後執行以下命令,其中 LANGUAGE_CODE 會被取代為目標語言的語言代碼

pybabel init -i superset/translations/messages.pot -d superset/translations -l LANGUAGE_CODE

例如,若要為芬蘭語(語言代碼 fi)新增翻譯,請執行以下命令

pybabel init -i superset/translations/messages.pot -d superset/translations -l fi

擷取新的翻譯字串

在處理翻譯時,我們需要定期從後端和前端擷取字串,以編譯所有要翻譯的字串清單。這不會自動發生,而且是收集字串並將其放入 .po 檔案(可以在其中翻譯)的必要步驟,以便隨後編譯。

此指令碼的作用即是如此

./scripts/translations/babel_update.sh

更新語言檔案

執行以下命令,以使用新的擷取字串更新語言檔案。

 pybabel update -i superset/translations/messages.pot -d superset/translations --ignore-obsolete

然後,您可以翻譯位於 superset/translation 下的檔案中收集的字串,其中每個語言都有一個資料夾。您可以使用 Poedit 更方便地翻譯 po 檔案。以下是 教學課程

若要在 MacOS 上執行翻譯,您可以透過 Homebrew 安裝 poedit

brew install poedit

在此之後,只需啟動 poedit 應用程式並開啟 messages.po 檔案。以芬蘭語翻譯為例,這將是 superset/translations/fi/LC_MESSAGES/messages.po

套用翻譯

若要讓翻譯在前端可用,我們需要將 PO 檔案轉換為 JSON 檔案的集合。若要將所有 PO 檔案轉換為格式化的 JSON 檔案,您可以使用 build-translation 指令碼

# Install dependencies if you haven't already
cd superset-frontend/ && npm ci
# Compile translations for the frontend
npm run build-translation

最後,為了讓翻譯生效,我們需要使用 pybabel 將翻譯目錄編譯為後端的二進制 MO 檔案。

# inside the project root
pybabel compile -d superset/translations

程式碼檢查

Python

我們使用 Pylint 進行程式碼檢查,可以透過以下方式叫用

# for python
tox -e pylint

就最佳實務而言,請避免全域(透過 .pylintrc)或在檔案標頭的頂層全面停用 Pylint 訊息,儘管有一些例外情況。應內嵌停用,因為這樣可以防止遮蓋問題,並提供停用該訊息的原因。

此外,Python 程式碼會使用 Black 自動格式化,該程式碼會設定為預先提交勾點。還有許多 編輯器整合

TypeScript

cd superset-frontend
npm ci
# run eslint checks
npm run eslint -- .
# run tsc (typescript) checks
npm run type

如果使用 vscode 的 eslint 擴充功能,請將以下內容放入您的工作區 settings.json 檔案中

"eslint.workingDirectories": [
"superset-frontend"
]