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"
  1. Crea un archivo de workflow de GitHub Actions. (p.ej: .github/workflows/benchmark.yml)
  2. Ejecuta push en eventos para la branch main. Consulta la documentación de on de GitHub Actions para una visión general completa. También puedes ver Pull Requests a continuación.
  3. Crea un trabajo de GitHub Actions. (p.ej: benchmark_with_bencher)
  4. El proyecto ya debe existir. Ajusta la opción --project o la variable de entorno BENCHER_PROJECT al slug del proyecto o al UUID (p.ej: BENCHER_PROJECT: save-walter-white).
  5. 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 entorno BENCHER_API_TOKEN al token de API. (p.ej: BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }})
  6. Opcional: Ajusta la opción --testbed o la variable de entorno BENCHER_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 Testbed localhost será usado.
  7. Opcional: Ajusta la opción --adapter o la variable de entorno BENCHER_ADAPTER al nombre del adaptador deseado. (p.ej: BENCHER_ADAPTER: json) Si esto no está ajustado, entonces el Adapter magic será usado. Consulta los adaptadores de harness de benchmark para obtener una visión general completa.
  8. Verifica tu código fuente. (p.ej: uses: actions/checkout@v3)
  9. Instala la CLI de Bencher usando la Acción de GitHub. (p.ej: uses: bencherdev/bencher@main)
  10. Monitorear tus benchmarks con el subcomando CLI de bencher run:
    1. Opcional: Ajusta la opción --branch o la variable de entorno BENCHER_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 Branch main será usada.
    2. Ajusta el comando para fallar si una Alerta es generada. (p.ej: --err) Para que una Alerta sea generada, un Umbral debe ya existir.
    3. Ejecuta tus benchmarks y genera un Reporte desde los resultados. (p.ej: "bencher mock")

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"
  1. Ejecuta push en eventos para la branch main y en pull_request. Es importante limitar la ejecución en push solo a seleccionar las branch (p.ej: main) para prevenir pushs a las branch PR de ejecutar dos veces!
  2. En lugar de siempre utilizar la branch main, usa las variables de entorno por defecto de la Acción de GitHub para:
    1. Usa los datos de la branch actual si ya existen. (p.ej: --if-branch "$GITHUB_REF_NAME")
    2. 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")
    3. De lo contrario, crea un clon de los datos y umbrales de la branch main. (p.ej: --else-if-branch main)
    4. Hay varias opciones para ajustar la branch del proyecto. Consulta selección de branch para una visión general completa.
  3. 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 entorno GITHUB_TOKEN de GitHub Actions.
  4. 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

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"
  1. Ejecuta push en eventos para la branch main y on pull_request_target eventos.
  2. Crea un trabajo que solo se ejecuta para push en eventos para la branch main. Aparte de la condición if, este trabajo es casi idéntico al ejemplo original de arriba.
  3. Crea un trabajo que solo se ejecuta para pull_request_target eventos.
    1. Verifica la branch del PR.
    2. Pasa todos los secretos directamente. Usa --token ${{ secrets.BENCHER_API_TOKEN }} en lugar de la variable de entorno BENCHER_API_TOKEN.
    3. 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
  1. Crea un archivo de flujo de trabajo Run and Cache Benchmarks.
  2. Ejecuta tus benchmarks en pull_request eventos.
  3. Guarda los resultados de benchmark en un archivo y sube como archivo de artefacto.
  4. Sube el evento pull_request como un archivo de artefacto.
  5. Crea un segundo archivo de flujo de trabajo, Track Benchmarks.
  6. Encadena Track Benchmarks a Run and Cache Benchmarks con el evento workflow_run.
  7. Extrae los datos necesarios del evento pull_request almacenado en la caché.
  8. Rastrea los resultados de benchmark almacenados en la caché con bencher run.
  9. Crea un tercer archivo de flujo de trabajo y usa el ejemplo inicial de arriba para ejecutar en push eventos a la branch main.

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! 🎉


Continúa: Visión General de los Benchmarks ➡

🤖 Este documento fue generado automáticamente por OpenAI GPT-4. Puede que no sea exacto y contenga errores. Si encuentra algún error, abra un problema en GitHub.