开发指南
贡献文档
最新的文档和教程可在https://superset.apache.org/查阅。
文档网站使用Docusaurus 3构建,这是一个现代的静态网站生成器,其源代码位于./docs中。
本地开发
为文档网站设置带有热重载的本地开发环境
cd docs
yarn install # Installs NPM dependencies
yarn start # Starts development server at https://:3000
构建
创建和部署文档网站的生产版本
yarn build
yarn serve
部署
对master分支的提交会触发文档网站的重建和重新部署。提交修改文档的拉取请求时,请使用docs:前缀。
创建可视化插件
Superset中的可视化是用JavaScript或TypeScript实现的。Superset预装了几种可视化类型(以下简称“可视化插件”),可以在superset-frontend/plugins目录中找到。可视化插件被添加到superset-frontend/src/visualizations/presets/MainPreset.js中的应用程序中。Superset项目始终乐于审查高质量新可视化插件的提案。但是,对于高度自定义的可视化类型,建议维护Superset的分支,并手动添加自定义构建的可视化插件。
注意:关于创建和部署自定义可视化插件的社区生成资源,请访问Superset Wiki
先决条件
为了创建新的可视化插件,您需要以下内容:
- 运行MacOS或Linux(Windows不受官方支持,但可能有效)
- Node.js 16
- npm 7或8
还建议您熟悉React以及npm/Node系统。
创建一个简单的Hello World可视化插件
要开始使用,您需要Superset Yeoman生成器。建议使用与您正在使用的Superset版本一起提供的模板版本。这可以通过以下操作进行安装:
npm i -g yo
cd superset-frontend/packages/generator-superset
npm i
npm link
之后,您可以继续创建可视化插件。为您的可视化插件创建一个新目录,前缀为superset-plugin-chart,并运行Yeoman生成器
mkdir /tmp/superset-plugin-chart-hello-world
cd /tmp/superset-plugin-chart-hello-world
初始化可视化插件
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
要构建可视化插件,请运行以下命令
npm i --force
npm run build
或者,要在开发模式下运行可视化插件(即每当进行更改时都重新构建),请使用以下命令启动开发服务器
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';
以导入可视化插件,然后将以下内容添加到传递给plugins属性的数组中
new SupersetPluginChartHelloWorld().configure({ key: 'ext-hello-world' }),
之后,当您运行Superset时(例如开发服务器),可视化插件应该会显示出来
npm run dev-server
部署您的可视化插件
一旦您的插件完成,您需要将其部署到您的Superset实例中。
此步骤假定您正在运行自己的Docker镜像,如此处所述。其他类型的部署说明可能会有所不同。
如果您有自己的Superset Docker镜像,第一行很可能是:FROM apache/superset:latest或类似内容。您需要编译自己的"精简"镜像,并将此FROM行替换为您自己的镜像。
- 将您的图表插件发布到 npm:这使得构建过程更简单。
注意:如果您的图表未发布到 npm,那么在下面的 docker 构建中,您需要编辑默认的 Dockerfile,将您的插件源代码复制到容器构建环境中适当的位置。
- 使用
npm i <your_chart_package>在前端安装您的图表。 - 从 Superset 的基础版本开始。
git checkout tags/X.0.0
- 按照您在开发过程中遵循的说明安装您的图表。
- 导航到您的Superset目录的根目录。
- 运行
docker build -t apache/superset:mychart --target lean . - 使用
FROM apache/superset:mychart重新构建您的生产容器。
这将创建一个新的生产化的Superset容器,其中包含您新编译的图表。然后,您可以基于包含您的图表的Superset构建来重新创建您的自定义生产容器。
故障排除
- 如果出现以下NPM错误
npm error `npm ci` can only install packages when your package.json and package-lock.json
这是因为您的本地nodejs/npm版本与docker内部使用的版本不同。
您可以通过运行与容器构建过程使用的相同版本的npm install来解决此问题
将以下命令中的XYZ替换为Dockerfile中使用的node标签(在Dockerfile中搜索“node:”以找到该标签)。
docker run --rm -v $PWD/superset-frontend:/app node:XYZ /bin/bash -c "cd /app && npm i"
测试
Python 测试
我们建议通过pytest(由docker-compose后端支持)在本地运行测试。
对于更复杂的测试矩阵(针对不同的数据库后端、Python版本等),您可以简单地打开一个草稿拉取请求,依靠我们的GitHub Actions。
请注意,测试环境使用一个临时目录来定义SQLite数据库,该目录将在每次调用测试命令组之前被清除。
Superset 代码库中还包含一个实用脚本,用于运行 Python 集成测试。readme 在这里可以找到
例如,要运行所有集成测试,请从根目录运行此脚本
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://:15433/memory/default
前端测试
我们使用Jest和Enzyme来测试TypeScript/JavaScript。测试可以通过以下方式运行
cd superset-frontend
npm run test
运行单个测试文件
npm run test -- path/to/file.js
端到端集成测试
注意:我们正在从Cypress迁移到Playwright。请使用Playwright进行新测试。
Playwright (推荐 - 新)
对于Playwright的端到端测试,请使用相同的docker compose后端
CYPRESS_CONFIG=true docker compose up --build
后端设置是相同的——这会在端口8081上暴露一个可用于测试的Superset应用程序,具有独立的数据库模式(superset_cypress)、测试数据和配置。
现在在另一个终端中,运行Playwright测试
# Navigate to frontend directory (Playwright config is here)
cd superset-frontend
# Run all Playwright tests
npm run playwright:test
# or: npx playwright test
# Run with interactive UI for debugging
npm run playwright:ui
# or: npx playwright test --ui
# Run in headed mode (see browser)
npm run playwright:headed
# or: npx playwright test --headed
# Run specific test file
npx playwright test tests/auth/login.spec.ts
# Run with debug mode (step through tests)
npm run playwright:debug tests/auth/login.spec.ts
# or: npx playwright test --debug tests/auth/login.spec.ts
# Generate test report
npx playwright show-report
配置在superset-frontend/playwright.config.ts中。基本URL自动设置为https://:8088,但如果提供PLAYWRIGHT_BASE_URL,则会使用它。
Cypress (已废弃 - 将在第5阶段移除)
Cypress 正在逐步淘汰,转而使用 Playwright。所有新测试请使用 Playwright。
# Set base URL for Cypress
CYPRESS_BASE_URL=https://:8081
# superset-frontend/cypress-base is the base folder for everything Cypress-related
# It's essentially its own npm app, with its own dependencies, configurations and utilities
cd superset-frontend/cypress-base
npm install
# use interactive mode to run tests, while keeping memory usage contained
# this will fire up an interactive Cypress UI
# as you alter the code, the tests will re-run automatically, and you can visualize each
# and every step for debugging purposes
npx cypress open --config numTestsKeptInMemory=5
# to run the test suite on the command line using chrome (same as CI)
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
请参阅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中的以下翻译函数
gettext和lazy_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
我们使用ruff进行代码检查,可以通过以下方式调用
# auto-reformat using ruff
ruff format
# lint check with ruff
ruff check
# lint fix with ruff
ruff check --fix
Ruff 的配置位于我们的 (pyproject.toml)[https://github.com/apache/superset/blob/master/pyproject.toml]文件
所有这些都配置为在pre-commit钩子中运行,我们鼓励您使用pre-commit install进行设置
TypeScript
cd superset-frontend
npm ci
# run linting checks
npm run lint
# run tsc (typescript) checks
npm run type
如果使用带有vscode的eslint扩展,请将以下内容放入您的工作区settings.json文件中
"eslint.workingDirectories": [
"superset-frontend"
]
GitHub 临时环境
在 GitHub 上的任何拉取请求中,只需向 PR 添加标签 testenv-up 即可创建临时环境/部署。添加 testenv-up 标签后,将触发 GitHub Action,它将
- 构建一个docker镜像
- 将其部署到 EC2(由 Preset 的各位赞助)
- 在 PR 上写一条评论,附带临时环境的链接
对于更高级的用例,可以在PR正文中设置一个功能标志,该标志将在临时环境中生效。例如,如果您想将TAGGING_SYSTEM功能标志设置为true,您可以将以下行添加到PR正文/描述中
FEATURE_TAGGING_SYSTEM=true
同样,也可以通过以下方式禁用功能标志
FEATURE_TAGGING_SYSTEM=false