CI/CD 集成
Framedash CLI 可以与任何 CI/CD 系统集成。本指南涵盖 Jenkins 和 TeamCity 的即用示例。
- 在 CI 环境中安装 CLI:
npm install -g @framedash/cli- 性能门禁示例使用
jq和bc进行 JSON 解析和阈值检查。请确保它们已安装在 CI 代理上。 - 在 Framedash 仪表盘中打开目标项目的 API 密钥 页面,并创建 Full 预设的 API 密钥。本指南示例包含 raw SQL 和地图上传,因此需要
data:admin与resources:writescope。如果流水线还运行游戏 SDK 发送遥测数据,请为该阶段单独创建 Ingest 预设的密钥(参见 CI 性能分析)。 - 从项目页面 URL(
/projects/{projectId})记录 项目 ID。
在 CI 系统的密钥管理中配置以下变量:
| 变量 | 必需 | 说明 |
|---|---|---|
FRAMEDASH_API_KEY | 是 | 具备所需 scope 的 API 密钥。本指南示例使用 Full 预设。仅发送游戏遥测时使用 Ingest(events:write)。 |
FRAMEDASH_PROJECT_ID | 是 | 目标项目 UUID |
FRAMEDASH_BASE_URL | 否 | 自定义 API 主机 URL(默认:https://app.framedash.dev) |
Jenkins
Section titled “Jenkins”将 API 密钥存储为 Jenkins 凭据(Secret text):
- 进入 Manage Jenkins > Credentials > System > Global credentials
- 添加 ID 为
framedash-api-key的 Secret text 凭据 - 添加 ID 为
framedash-project-id的 Secret text 凭据
声明式流水线
Section titled “声明式流水线”构建后遥测检查
Section titled “构建后遥测检查”验证自动测试运行后游戏构建是否在发送遥测数据:
pipeline { agent any
environment { FRAMEDASH_API_KEY = credentials('framedash-api-key') FRAMEDASH_PROJECT_ID = credentials('framedash-project-id') }
stages { stage('Build') { steps { sh 'your-game-build-command' } }
stage('Automated Test') { steps { sh 'your-automated-test-command' } }
stage('Verify Telemetry') { steps { sh ''' framedash auth framedash status --format json > status.json echo "Project status:" framedash status --format table ''' } } }}性能回归门禁
Section titled “性能回归门禁”当性能指标低于阈值时使构建失败:
pipeline { agent any
environment { FRAMEDASH_API_KEY = credentials('framedash-api-key') FRAMEDASH_PROJECT_ID = credentials('framedash-project-id') }
stages { stage('Build & Test') { steps { sh 'your-game-build-and-test-command' } }
stage('Performance Gate') { steps { sh ''' RESULT=$(framedash query \ "SELECT avg(fps) as avg_fps, \ avg(frame_time_ms) as avg_frame_time \ FROM events \ WHERE event_name = 'perf_heartbeat' \ AND timestamp > now() - INTERVAL 1 HOUR" \ --format json)
AVG_FPS=$(echo "$RESULT" | jq -r '.rows[0].avg_fps // 0')
echo "Average FPS: $AVG_FPS"
if [ "$(echo "$AVG_FPS < 30" | bc -l)" -eq 1 ]; then echo "FAILED: FPS below 30 threshold ($AVG_FPS)" exit 1 fi
echo "PASSED: FPS meets threshold" ''' } } }
post { failure { echo 'Performance regression detected. Check the Framedash dashboard for details.' } }}地图截图上传
Section titled “地图截图上传”在关卡构建后自动上传地图图像:
pipeline { agent any
environment { FRAMEDASH_API_KEY = credentials('framedash-api-key') FRAMEDASH_PROJECT_ID = credentials('framedash-project-id') }
stages { stage('Build Level') { steps { sh 'your-level-build-command' } }
stage('Capture Maps') { steps { sh 'your-map-capture-command --output-dir ./map_captures' } }
stage('Upload Maps') { steps { sh ''' framedash map-capture \ --input-dir ./map_captures \ --upload ''' } } }}内容注册表同步
Section titled “内容注册表同步”将游戏数据与内容注册表同步:
pipeline { agent any
environment { FRAMEDASH_API_KEY = credentials('framedash-api-key') FRAMEDASH_PROJECT_ID = credentials('framedash-project-id') }
stages { stage('Sync Content') { steps { sh ''' framedash content import ./game-content.json echo "Content registry updated" framedash content list --format table ''' } } }}对于拥有多个游戏项目的组织,可以创建 Jenkins 共享库:
def call(Map config = [:]) { def queryDays = config.get('days', 7)
withCredentials([ string(credentialsId: config.apiKeyCredentialId ?: 'framedash-api-key', variable: 'FRAMEDASH_API_KEY'), string(credentialsId: config.projectIdCredentialId ?: 'framedash-project-id', variable: 'FRAMEDASH_PROJECT_ID') ]) { sh """ echo "Framedash dashboard (${queryDays}-day summary):" framedash dashboard --days ${queryDays} --format table """ }}在 Jenkinsfile 中使用:
@Library('your-shared-lib') _
pipeline { agent any stages { stage('Framedash Report') { steps { framedashReport(days: 7) } } }}TeamCity
Section titled “TeamCity”在构建配置中添加 Configuration Parameters:
- 进入 Build Configuration > Parameters
- 添加参数
env.FRAMEDASH_API_KEY(类型:Password,spec:password display='hidden') - 添加参数
env.FRAMEDASH_PROJECT_ID(类型:Text)
或在 项目 级别定义以在构建配置间共享。
构建后遥测检查
Section titled “构建后遥测检查”添加一个 Command Line 构建步骤:
步骤名称: Verify Framedash Telemetry
#!/bin/bashset -euo pipefail
echo "Verifying Framedash authentication..."framedash auth
echo "Project status:"framedash status --format table性能回归门禁
Section titled “性能回归门禁”添加一个 Command Line 构建步骤:
步骤名称: Framedash Performance Gate
#!/bin/bashset -euo pipefail
echo "Querying performance metrics..."RESULT=$(framedash query \ "SELECT avg(fps) as avg_fps, \ avg(frame_time_ms) as avg_frame_time \ FROM events \ WHERE event_name = 'perf_heartbeat' \ AND timestamp > now() - INTERVAL 1 HOUR" \ --format json)
AVG_FPS=$(echo "$RESULT" | jq -r '.rows[0].avg_fps // 0')
echo "Average FPS: $AVG_FPS"
if [ "$(echo "$AVG_FPS < 30" | bc -l)" -eq 1 ]; then echo "##teamcity[buildProblem description='FPS below threshold: $AVG_FPS']" exit 1fi
echo "##teamcity[buildStatisticValue key='framedash.avgFps' value='$AVG_FPS']"echo "Performance gate passed"地图截图上传
Section titled “地图截图上传”添加一个 Command Line 构建步骤:
步骤名称: Upload Map Captures
#!/bin/bashset -euo pipefail
echo "Validating map captures..."framedash map-capture --input-dir ./map_captures --dry-run
echo "Uploading map captures..."framedash map-capture --input-dir ./map_captures --upload漏斗分析报告
Section titled “漏斗分析报告”添加一个 Command Line 构建步骤来追踪转化漏斗:
#!/bin/bashset -euo pipefail
echo "Funnel analysis (7-day window):"framedash funnel \ --steps "tutorial_start,tutorial_complete,first_purchase" \ --days 7 \ --format table构建配置模板(Kotlin DSL)
Section titled “构建配置模板(Kotlin DSL)”使用 Kotlin DSL 的 TeamCity 项目:
import jetbrains.buildServer.configs.kotlin.*import jetbrains.buildServer.configs.kotlin.buildSteps.script
object FramedashPerformanceGate : BuildType({ name = "Framedash Performance Gate"
params { password("env.FRAMEDASH_API_KEY", "", display = ParameterDisplay.HIDDEN) text("env.FRAMEDASH_PROJECT_ID", "") text("framedash.minFps", "30", label = "Minimum FPS Threshold") }
steps { script { name = "Install Framedash CLI" scriptContent = "npm install -g @framedash/cli" } script { name = "Performance Gate" scriptContent = """ #!/bin/bash set -euo pipefail
MIN_FPS=%framedash.minFps%
RESULT=${'$'}(framedash query \ "SELECT avg(fps) as avg_fps FROM events \ WHERE event_name = 'perf_heartbeat' \ AND timestamp > now() - INTERVAL 1 HOUR" \ --format json)
AVG_FPS=${'$'}(echo "${'$'}RESULT" | jq -r '.rows[0].avg_fps // 0')
echo "Average FPS: ${'$'}AVG_FPS (threshold: ${'$'}MIN_FPS)"
if [ "${'$'}(echo "${'$'}AVG_FPS < ${'$'}MIN_FPS" | bc -l)" -eq 1 ]; then echo "##teamcity[buildProblem description='FPS below threshold']" exit 1 fi
echo "##teamcity[buildStatisticValue key='framedash.avgFps' value='${'$'}AVG_FPS']" """.trimIndent() } }})创建可复用的元运行器。保存为项目 .teamcity/pluginData/metaRunners/ 目录下的 Framedash_Performance_Gate.xml:
<?xml version="1.0" encoding="UTF-8"?><meta-runner name="Framedash Performance Gate"> <description>Check game performance metrics via Framedash CLI</description> <settings> <parameters> <param name="framedash.minFps" value="30" spec="text description='Minimum acceptable FPS' label='Min FPS'" /> <param name="framedash.queryDays" value="7" spec="text description='Number of days to query' label='Query Days'" /> </parameters> <build-runners> <runner name="Framedash Performance Gate" type="simpleRunner"> <parameters> <param name="script.content"><![CDATA[#!/bin/bashset -euo pipefail
framedash auth
MIN_FPS=%framedash.minFps%
RESULT=$(framedash query \ "SELECT avg(fps) as avg_fps FROM events \ WHERE event_name = 'perf_heartbeat' \ AND timestamp > now() - INTERVAL %framedash.queryDays% DAY" \ --format json)
AVG_FPS=$(echo "$RESULT" | jq -r '.rows[0].avg_fps // 0')
echo "Average FPS: $AVG_FPS (threshold: $MIN_FPS)"
if [ "$(echo "$AVG_FPS < $MIN_FPS" | bc -l)" -eq 1 ]; then echo "##teamcity[buildProblem description='FPS below threshold: $AVG_FPS < $MIN_FPS']" exit 1fi
echo "##teamcity[buildStatisticValue key='framedash.avgFps' value='$AVG_FPS']"echo "Performance gate passed"]]></param> <param name="teamcity.step.mode" value="default" /> <param name="use.custom.script" value="true" /> </parameters> </runner> </build-runners> </settings></meta-runner>基于 SQL 的质量门禁
Section titled “基于 SQL 的质量门禁”使用 framedash query 和 SQL 文件进行可重复的检查:
-- checks/fps-threshold.sqlSELECT avg(fps) as avg_fps, min(fps) as min_fps, quantile(0.05)(fps) as p5_fpsFROM eventsWHERE event_name = 'perf_heartbeat' AND timestamp > now() - INTERVAL 1 DAYframedash query --file checks/fps-threshold.sql --format json输出格式的使用
Section titled “输出格式的使用”CI 解析使用 --format json 配合 jq:
# 提取单个值framedash dashboard --days 7 --format json | jq '.kpis.events'
# 检查项目状态framedash status --format json | jq '.project.name'CLI 已经解包了 API 响应的信封结构,因此请直接读取顶层字段(.kpis、.project),而不是 .data.*。dashboard 的 KPI 成员名是 events,而非 totalEvents。
构建日志的可读性使用 --format table:
framedash dashboard --days 7 --format tableframedash retention --days 30 --format table夜间性能报告
Section titled “夜间性能报告”调度夜间构建生成性能摘要:
#!/bin/bashset -euo pipefail
echo "=== Framedash Nightly Report ==="echo ""echo "--- Project Status ---"framedash status --format tableecho ""echo "--- 7-Day Dashboard ---"framedash dashboard --days 7 --format tableecho ""echo "--- Player Retention ---"framedash retention --days 30 --format tableecho ""echo "--- Alert Rules ---"framedash alerts list --format tableError: Unauthorized (401)- 确认
FRAMEDASH_API_KEY已设置且有效 - 运行
framedash auth测试密钥 - 地图上传需要
resources:writescope。请使用 Read & Write 或 Full 预设的密钥。
Error: Too Many Requests (429)- 速率限制按账户(租户)计量,由该账户的所有项目和 API 密钥共享,因此并行的 CI 作业会消耗同一个每小时额度(免费计划为每小时 100 次请求,更高计划有所不同)
- 每次遇到 429 时请遵循
Retry-After响应头,而不要围绕X-RateLimit-Reset来安排重试。重置时间由滑动窗口计算得出,在所公布的重置时刻刚过之后,实际等待时间可能被低估 - 如需更高限制请考虑升级计划
网络 / 代理
Section titled “网络 / 代理”如果 CI 环境使用代理:
export HTTPS_PROXY=http://proxy.example.com:8080framedash auth找不到 CLI
Section titled “找不到 CLI”确保 CLI 已安装在 CI 代理的 PATH 中:
# 验证安装which framedash || npm install -g @framedash/cli
# 不进行全局安装使用 npxnpx @framedash/cli auth