跳转到内容

CI/CD 集成

Framedash CLI 可以与任何 CI/CD 系统集成。本指南涵盖 JenkinsTeamCity 的即用示例。

  1. 在 CI 环境中安装 CLI:
Terminal window
npm install -g @framedash/cli
  1. 性能门禁示例使用 jqbc 进行 JSON 解析和阈值检查。请确保它们已安装在 CI 代理上。
  2. 在 Framedash 仪表盘中打开目标项目的 API 密钥 页面,并创建 Full 预设的 API 密钥。本指南示例包含 raw SQL 和地图上传,因此需要 data:adminresources:write scope。如果流水线还运行游戏 SDK 发送遥测数据,请为该阶段单独创建 Ingest 预设的密钥(参见 CI 性能分析)。
  3. 从项目页面 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

将 API 密钥存储为 Jenkins 凭据(Secret text):

  1. 进入 Manage Jenkins > Credentials > System > Global credentials
  2. 添加 ID 为 framedash-api-keySecret text 凭据
  3. 添加 ID 为 framedash-project-idSecret text 凭据

验证自动测试运行后游戏构建是否在发送遥测数据:

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
'''
}
}
}
}

当性能指标低于阈值时使构建失败:

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.'
}
}
}

在关卡构建后自动上传地图图像:

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
'''
}
}
}
}

将游戏数据与内容注册表同步:

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 共享库:

vars/framedashReport.groovy
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)
}
}
}
}

在构建配置中添加 Configuration Parameters

  1. 进入 Build Configuration > Parameters
  2. 添加参数 env.FRAMEDASH_API_KEY(类型:Password,spec:password display='hidden'
  3. 添加参数 env.FRAMEDASH_PROJECT_ID(类型:Text)

或在 项目 级别定义以在构建配置间共享。

添加一个 Command Line 构建步骤:

步骤名称: Verify Framedash Telemetry

#!/bin/bash
set -euo pipefail
echo "Verifying Framedash authentication..."
framedash auth
echo "Project status:"
framedash status --format table

添加一个 Command Line 构建步骤:

步骤名称: Framedash Performance Gate

#!/bin/bash
set -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 1
fi
echo "##teamcity[buildStatisticValue key='framedash.avgFps' value='$AVG_FPS']"
echo "Performance gate passed"

添加一个 Command Line 构建步骤:

步骤名称: Upload Map Captures

#!/bin/bash
set -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

添加一个 Command Line 构建步骤来追踪转化漏斗:

#!/bin/bash
set -euo pipefail
echo "Funnel analysis (7-day window):"
framedash funnel \
--steps "tutorial_start,tutorial_complete,first_purchase" \
--days 7 \
--format table

使用 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/bash
set -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 1
fi
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>

使用 framedash query 和 SQL 文件进行可重复的检查:

-- checks/fps-threshold.sql
SELECT
avg(fps) as avg_fps,
min(fps) as min_fps,
quantile(0.05)(fps) as p5_fps
FROM events
WHERE event_name = 'perf_heartbeat'
AND timestamp > now() - INTERVAL 1 DAY
Terminal window
framedash query --file checks/fps-threshold.sql --format json

CI 解析使用 --format json 配合 jq

Terminal window
# 提取单个值
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

Terminal window
framedash dashboard --days 7 --format table
framedash retention --days 30 --format table

调度夜间构建生成性能摘要:

#!/bin/bash
set -euo pipefail
echo "=== Framedash Nightly Report ==="
echo ""
echo "--- Project Status ---"
framedash status --format table
echo ""
echo "--- 7-Day Dashboard ---"
framedash dashboard --days 7 --format table
echo ""
echo "--- Player Retention ---"
framedash retention --days 30 --format table
echo ""
echo "--- Alert Rules ---"
framedash alerts list --format table

Error: Unauthorized (401)
  • 确认 FRAMEDASH_API_KEY 已设置且有效
  • 运行 framedash auth 测试密钥
  • 地图上传需要 resources:write scope。请使用 Read & Write 或 Full 预设的密钥。
Error: Too Many Requests (429)
  • 速率限制按账户(租户)计量,由该账户的所有项目和 API 密钥共享,因此并行的 CI 作业会消耗同一个每小时额度(免费计划为每小时 100 次请求,更高计划有所不同)
  • 每次遇到 429 时请遵循 Retry-After 响应头,而不要围绕 X-RateLimit-Reset 来安排重试。重置时间由滑动窗口计算得出,在所公布的重置时刻刚过之后,实际等待时间可能被低估
  • 如需更高限制请考虑升级计划

如果 CI 环境使用代理:

Terminal window
export HTTPS_PROXY=http://proxy.example.com:8080
framedash auth

确保 CLI 已安装在 CI 代理的 PATH 中:

Terminal window
# 验证安装
which framedash || npm install -g @framedash/cli
# 不进行全局安装使用 npx
npx @framedash/cli auth