Cómo usar Bencher en GitHub Actions
on:
push:
branches: main
jobs:
benchmark_with_bencher:
name: Continuous Benchmarking with Bencher
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
BENCHER_TESTBED: ubuntu-latest
BENCHER_ADAPTER: json
steps:
- uses: actions/checkout@v3
- uses: bencherdev/bencher@main
- name: Track Benchmarks with Bencher
run: |
bencher run \
--branch main \
--err \
"bencher mock"
- Crea un archivo de
workflow
de GitHub Actions. (p.ej:.github/workflows/benchmark.yml
) - Ejecuta
push
en eventos para la branchmain
. Consulta la documentación deon
de GitHub Actions para una visión general completa. También puedes ver Pull Requests a continuación. - Crea un
trabajo
de GitHub Actions. (p.ej:benchmark_with_bencher
) - El proyecto ya debe existir. Ajusta la opción
--project
o la variable de entornoBENCHER_PROJECT
al slug del proyecto o al UUID (p.ej:BENCHER_PROJECT: save-walter-white
). - El token de API ya debe existir. Agrega
BENCHER_API_TOKEN
como un secreto del Repositorio. (p.ej:Repo -> Configuración -> Secretos y variables -> Acciones -> Nuevo secreto del repositorio
) Ajusta la opción--token
o variable de entornoBENCHER_API_TOKEN
al token de API. (p.ej:BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
) - Opcional: Ajusta la opción
--testbed
o la variable de entornoBENCHER_TESTBED
al slug de Testbed o al UUID. (p.ej:BENCHER_TESTBED: ubuntu-latest
) El Testbed debe ya existir. Si esto no está ajustado, entonces el Testbedlocalhost
será usado. - Opcional: Ajusta la opción
--adapter
o la variable de entornoBENCHER_ADAPTER
al nombre del adaptador deseado. (p.ej:BENCHER_ADAPTER: json
) Si esto no está ajustado, entonces el Adaptermagic
será usado. Consulta los adaptadores de harness de benchmark para obtener una visión general completa. - Verifica tu código fuente. (p.ej:
uses: actions/checkout@v3
) - Instala la CLI de Bencher usando la Acción de GitHub. (p.ej:
uses: bencherdev/bencher@main
) - Monitorear tus benchmarks con el subcomando CLI de
bencher run
:- Opcional: Ajusta la opción
--branch
o la variable de entornoBENCHER_BRANCH
al slug de la Branch o al UUID. (p.ej:--branch main
) La Branch debe ya existir. Si esto no está ajustado, entonces la Branchmain
será usada. - Ajusta el comando para fallar si una Alerta es generada. (p.ej:
--err
) Para que una Alerta sea generada, un Umbral debe ya existir. - Ejecuta tus benchmarks y genera un Reporte desde los resultados. (p.ej:
"bencher mock"
)
- Opcional: Ajusta la opción
Pull Requests
Para detectar la regresión del rendimiento en los Pull Requests, necesitarás ejecutar tus benchmarks en PRs.
Si solo esperas tener PRs desde las branch dentro del mismo repositorio entonces simplemente puedes modificar el ejemplo de arriba para también ejecutar on
en pull_request
.
⚠️ ¡Esta solución solo funciona si todos los PRs son del mismo repositorio! Consulta Pull Requests desde Forks a continuación.
on:
push:
branches: main
pull_request:
jobs:
benchmark_with_bencher:
name: Continuous Benchmarking with Bencher
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
BENCHER_TESTBED: ubuntu-latest
BENCHER_ADAPTER: json
steps:
- uses: actions/checkout@v3
- uses: bencherdev/bencher@main
- name: Track Benchmarks with Bencher
run: |
bencher run \
--if-branch "$GITHUB_REF_NAME" \
--else-if-branch "$GITHUB_BASE_REF" \
--else-if-branch main \
--github-actions ${{ secrets.GITHUB_TOKEN }} \
--err \
"bencher mock"
- Ejecuta
push
en eventos para la branchmain
y enpull_request
. Es importante limitar la ejecución enpush
solo a seleccionar las branch (p.ej:main
) para prevenir pushs a las branch PR de ejecutar dos veces! - En lugar de siempre utilizar la branch
main
, usa las variables de entorno por defecto de la Acción de GitHub para:- Usa los datos de la branch actual si ya existen. (p.ej:
--if-branch "$GITHUB_REF_NAME"
) - Crea un clon de los datos y umbrales de la branch objetivo de PR si ya existen. (p.ej:
--else-if-branch "$GITHUB_BASE_REF"
) - De lo contrario, crea un clon de los datos y umbrales de la branch
main
. (p.ej:--else-if-branch main
) - Hay varias opciones para ajustar la branch del proyecto. Consulta selección de branch para una visión general completa.
- Usa los datos de la branch actual si ya existen. (p.ej:
- Ajusta el token de autenticación de GitHub API. (p.ej:
--github-actions ${{ secrets.GITHUB_TOKEN }}
) Cuando esta opción se ajusta como parte de un pull request, entonces los resultados serán adicionados al pull request como un comentario. Esto usa la variable de entornoGITHUB_TOKEN
de GitHub Actions. - Consulta la documentación de bencher run para una visión general completa de todas las maneras de configurar el comentario de pull request con las opciones
--ci-*
.
Pull Requests from Forks
Si planeas aceptar pull requests desde forks, como es a menudo el caso en proyectos de código abierto públicos,
entonces necesitarás manejar las cosas un poco diferente.
Por razones de seguridad, secretos como tu BENCHER_API_TOKEN
y el GITHUB_TOKEN
no están disponibles en GitHub Actions para los PRs de fork.
Es decir si un contribuyente externo abre un PR desde un fork el ejemplo de arriba no funcionará.
Hay tres opciones para los PRs de fork:
- Benchmark Fork PR desde Branch Objetivo
- Benchmark Fork PR desde Branch Objetivo con Revisores Requeridos
- Benchmark Fork PR y Subir desde Branch por Defecto
Benchmark Fork PR desde Branch Objetivo
on:
push:
branches: main
pull_request_target:
jobs:
benchmark_main_with_bencher:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Benchmark main with Bencher
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
BENCHER_TESTBED: ubuntu-latest
BENCHER_ADAPTER: json
steps:
- uses: actions/checkout@v3
- uses: bencherdev/bencher@main
- name: Track Benchmarks with Bencher
run: |
bencher run \
--branch main \
--err \
"bencher mock"
benchmark_pr_with_bencher:
if: github.event_name == 'pull_request_target'
name: Benchmark PR with Bencher
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_ADAPTER: json
BENCHER_TESTBED: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
persist-credentials: false
- uses: bencherdev/bencher@main
- name: Track Benchmarks with Bencher
run: |
bencher run \
--if-branch "${{ github.event.pull_request.head.ref }}" \
--else-if-branch "${{ github.event.pull_request.base.ref }}" \
--else-if-branch main \
--github-actions "${{ secrets.GITHUB_TOKEN }}" \
--token "${{ secrets.BENCHER_API_TOKEN }}" \
--err \
"bencher mock"
- Ejecuta
push
en eventos para la branchmain
y onpull_request_target
eventos. - Crea un
trabajo
que solo se ejecuta parapush
en eventos para la branchmain
. Aparte de la condiciónif
, este trabajo es casi idéntico al ejemplo original de arriba. - Crea un
trabajo
que solo se ejecuta parapull_request_target
eventos.- Verifica la branch del PR.
- Pasa todos los secretos directamente. Usa
--token ${{ secrets.BENCHER_API_TOKEN }}
en lugar de la variable de entornoBENCHER_API_TOKEN
. - Ejecuta y rastrea tus benchmarks de PR con
bencher run
.
Esta configuración funciona porque pull_request_target
se ejecuta en el contexto de la branch objetivo del PR,
donde los secretos como tu BENCHER_API_TOKEN
y el GITHUB_TOKEN
están disponibles.
Por lo tanto, este flujo de trabajo solo funcionará si existe en la branch objetivo.
Evita configurar cualquier secreto como variable de entorno, como BENCHER_API_TOKEN
.
En su lugar, pasa explícitamente el token de API a bencher run
. (p.ej: --token ${{ secrets.BENCHER_API_TOKEN }}
)
Consulta esta reseña del laboratorio de seguridad de GitHub
y este post de blog
sobre cómo prevenir peticiones pwn para una visión general completa.
Benchmark Fork PR desde Branch Objetivo con Revisores Requeridos
on:
push:
branches: main
pull_request_target:
jobs:
benchmark_main_with_bencher:
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
name: Benchmark main with Bencher
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
BENCHER_TESTBED: ubuntu-latest
BENCHER_ADAPTER: json
steps:
- uses: actions/checkout@v3
- uses: bencherdev/bencher@main
- name: Track Benchmarks with Bencher
run: |
bencher run \
--branch main \
--err \
"bencher mock"
benchmark_pr_requires_review:
if: github.event_name == 'pull_request_target'
environment:
${{ (github.event.pull_request.head.repo.full_name == github.repository && 'internal') || 'external' }}
runs-on: ubuntu-latest
steps:
- run: true
benchmark_pr_with_bencher:
needs: benchmark_pr_requires_review
name: Benchmark PR with Bencher
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_ADAPTER: json
BENCHER_TESTBED: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
ref: ${{ github.event.pull_request.head.sha }}
repository: ${{ github.event.pull_request.head.repo.full_name }}
persist-credentials: false
- uses: bencherdev/bencher@main
- name: Track Benchmarks with Bencher
run: |
bencher run \
--if-branch "${{ github.event.pull_request.head.ref }}" \
--else-if-branch "${{ github.event.pull_request.base.ref }}" \
--else-if-branch main \
--github-actions "${{ secrets.GITHUB_TOKEN }}" \
--token "${{ secrets.BENCHER_API_TOKEN }}" \
--err \
"bencher mock"
Esta configuración es exactamente la misma que Benchmark Fork PR desde Branch Objetivo
con el requisito adicional de aprobación de un revisor obligatorio antes de cada ejecución de PR de fork.
Los pull requests del mismo repositorio no requieren aprobación.
Para configurar esto, necesitas crear dos Ambientes de Acción de GitHub
(p.ej: Repo -> Configuración -> Ambientes -> Nuevo ambiente
).
El ambiente internal
no debe tener ninguna Regla de protección de despliegue
.
Sin embargo, el ambiente external
debe tener Revisores requeridos
ajustado a aquellos de confianza para revisar PR de fork antes del benchmarking.
Benchmark Fork PR y Subir desde Branch por Defecto
name: Run and Cache Benchmarks
on: pull_request
jobs:
benchmark:
name: Run Benchmarks
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Mock Benchmark
run: echo '{"bencher::mock_0": { "latency": { "value": 1.0 }}}' &> benchmark_results.txt
- uses: actions/upload-artifact@v3
with:
name: benchmark_results.txt
path: ./benchmark_results.txt
- uses: actions/upload-artifact@v3
with:
name: pr_event.json
path: ${{ env.GITHUB_EVENT_PATH }}
name: Track Benchmarks
on:
workflow_run:
workflows: [Run and Cache Benchmarks]
types:
- completed
jobs:
track_with_bencher:
if: ${{ github.event.workflow_run.conclusion == 'success' }}
runs-on: ubuntu-latest
env:
BENCHER_PROJECT: save-walter-white
BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
BENCHER_ADAPTER: json
BENCHER_TESTBED: ubuntu-latest
BENCHMARK_RESULTS: benchmark_results.txt
PR_EVENT: pr_event.json
steps:
- name: Download Benchmark Results
uses: actions/github-script@v6
with:
script: |
function downloadArtifact(artifactName) {
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name == artifactName
})[0];
if (!matchArtifact) {
core.setFailed(`Failed to find artifact: ${artifactName}`);
}
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/${artifactName}.zip`, Buffer.from(download.data));
}
downloadArtifact(process.env.BENCHMARK_RESULTS);
downloadArtifact(process.env.PR_EVENT);
- name: Unzip Benchmark Results
run: |
unzip $BENCHMARK_RESULTS.zip
unzip $PR_EVENT.zip
- name: Export PR Context
uses: actions/github-script@v6
with:
script: |
let fs = require('fs');
let prEvent = JSON.parse(fs.readFileSync(process.env.PR_EVENT, {encoding: 'utf8'}));
fs.appendFileSync(process.env.GITHUB_ENV, `PR_NUMBER=${prEvent.number}`);
fs.appendFileSync(process.env.GITHUB_ENV, `PR_HEAD=${prEvent.pull_request.head.ref}`);
fs.appendFileSync(process.env.GITHUB_ENV, `PR_BASE=${prEvent.pull_request.base.ref}`);
- uses: bencherdev/bencher@main
- name: Track Benchmarks with Bencher
run: |
bencher run \
--if-branch "${{ env.PR_HEAD }}" \
--else-if-branch "${{ env.PR_BASE }}" \
--else-if-branch main \
--github-actions "${{ secrets.GITHUB_TOKEN }}" \
--ci-number "${{ env.PR_NUMBER }}" \
--err \
--file $BENCHMARK_RESULTS
- Crea un archivo de flujo de trabajo
Run and Cache Benchmarks
. - Ejecuta tus benchmarks en
pull_request
eventos. - Guarda los resultados de benchmark en un archivo y sube como archivo de artefacto.
- Sube el evento
pull_request
como un archivo de artefacto. - Crea un segundo archivo de flujo de trabajo,
Track Benchmarks
. - Encadena
Track Benchmarks
aRun and Cache Benchmarks
con el eventoworkflow_run
. - Extrae los datos necesarios del evento
pull_request
almacenado en la caché. - Rastrea los resultados de benchmark almacenados en la caché con
bencher run
. - Crea un tercer archivo de flujo de trabajo y usa el ejemplo inicial de arriba para ejecutar en
push
eventos a la branchmain
.
Esta configuración funciona porque workflow_run
se ejecuta en el contexto de la branch por defecto del repositorio,
donde los secretos como tu BENCHER_API_TOKEN
y el GITHUB_TOKEN
están disponibles.
Por lo tanto, estos flujos de trabajo solo se ejecutarán si existen en la branch por defecto.
Consulta usando datos desde el flujo de trabajo que dispara para una visión general completa.
El número de pull request, la branch principal, y la branch base usadas en el flujo de trabajo inicial deben ser pasados explícitamente ya que no están disponibles dentro de workflow_run
.
🐰 ¡Felicidades! ¡Has aprendido cómo usar Bencher en GitHub Actions! 🎉