Como usar o Bencher nas Ações do GitHub


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. Crie um arquivo de workflow das Ações do GitHub. (ex: .github/workflows/benchmark.yml)
  2. Execute em eventos de push para a branch main. Veja a documentação on das Ações do GitHub para uma visão geral completa. Veja também Pull Requests abaixo.
  3. Crie uma job das Ações do GitHub. (ex: benchmark_with_bencher)
  4. O Projeto já deve existir. Definir a flag --project ou a variável de ambiente BENCHER_PROJECT para o slug do Projeto ou UUID (ex: BENCHER_PROJECT: save-walter-white).
  5. O token API já deve existir. Adicione BENCHER_API_TOKEN como segredo do Repositório (ex: Repositório -> Configurações -> Segredos e variáveis -> Ações -> Novo segredo do repositório). Defina a flag --token ou a variável de ambiente BENCHER_API_TOKEN para o token API. (ex: BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }})
  6. Opcional: Definir a flag --testbed ou a variável de ambiente BENCHER_TESTBED para o slug do Testbed ou UUID. (ex: BENCHER_TESTBED: ubuntu-latest) O Testbed deve já existir. Se isso não for definido, então o Testbed localhost será usado.
  7. Opcional: Defina a flag --adapter ou a variável de ambiente BENCHER_ADAPTER para o nome do adaptador desejado. (ex: BENCHER_ADAPTER: json) Se isso não for definido, então o Adaptador magic será usado. Veja adaptadores de harness de benchmark para uma visão geral completa.
  8. Faça o checkout do seu código-fonte. (ex: uses: actions/checkout@v3)
  9. Instale o CLI Bencher usando a Ação do GitHub. (ex: uses: bencherdev/bencher@main)
  10. Monitore seus benchmarks com o subcomando CLI bencher run:
    1. Opcional: Defina a flag --branch ou a variável de ambiente BENCHER_BRANCH para o slug da Branch ou UUID. (ex: --branch main) A Branch deve já existir. Se isso não for definido, então a Branch main será usada.
    2. Definir o comando para falhar se um Alerta for gerado. (ex: --err) Para que um Alerta seja gerado, um Limite já deve existir.
    3. Execute seus benchmarks e gere um Relatório a partir dos resultados. (ex: "bencher mock")

Pull Requests

Para detectar regressão de desempenho em Pull Requests, você precisará executar seus benchmarks em PRs. Se você espera ter PRs apenas de branches dentro do mesmo repositório, então você pode simplesmente modificar o exemplo acima para também executar on eventos de pull_request.

⚠️ Esta solução só funciona se todos os PRs são do mesmo repositório! Veja Pull Requests de Forks abaixo.

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. Execute em eventos de push para a branch main e em eventos de pull_request. É importante limitar a execução em push apenas para as branches selecionadas (ex: main) para evitar que pushes para branches de PR sejam executados duas vezes!
  2. Em vez de sempre usar a branch main, use as variáveis de ambiente padrão das Ações do GitHub para:
    1. Use os dados da branch atual se já existirem. (ex: --if-branch "$GITHUB_REF_NAME")
    2. Crie um clone dos dados e limites da branch de destino do PR se já existirem. (ex: --else-if-branch "$GITHUB_BASE_REF")
    3. Caso contrário, crie um clone dos dados e limites da branch main. (ex: --else-if-branch main)
    4. Existem várias opções para definir a branch do projeto. Veja seleção de branch para uma visão geral completa.
  3. Defina o token de autenticação da API do GitHub. (ex: --github-actions ${{ secrets.GITHUB_TOKEN }}) Quando essa opção é definida como parte de um pull request, então os resultados serão adicionados ao pull request como um comentário. Isso usa a variável de ambiente GITHUB_TOKEN das Ações do GitHub.
  4. Veja a documentação do bencher run para uma visão geral completa de todas as maneiras de configurar o comentário do pull request com as flags --ci-*.

Pull Requests de Forks

Se você planeja aceitar pull requests de forks, como é frequentemente o caso em projetos de código aberto público, então você precisará lidar com as coisas de maneira um pouco diferente. Por motivos de segurança, segredos como seu BENCHER_API_TOKEN e o GITHUB_TOKEN não estão disponíveis nas Ações do GitHub para PRs de forks. Ou seja, se um colaborador externo abrir um PR a partir de um fork, o exemplo acima não funcionará. Existem três opções para PRs de forks:

Benchmark PR Fork da Branch Alvo

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. Execute em eventos de push para a branch main e em eventos de pull_request_target.
  2. Crie uma job que só é executada para eventos de push para a branch main. Além da condição if, esse trabalho é quase idêntico ao exemplo original acima.
  3. Crie uma job que só é executada para eventos de pull_request_target.
    1. Faça o checkout da branch do pull request.
    2. Passe todos os segredos diretamente. Use --token ${{ secrets.BENCHER_API_TOKEN }} em vez da variável de ambiente BENCHER_API_TOKEN.
    3. Execute e monitore seus benchmarks de pull request com bencher run.

Esta configuração funciona porque pull_request_target é executado no contexto da branch alvo do pull request, onde seus segredos como BENCHER_API_TOKEN e GITHUB_TOKEN estão disponíveis. Portanto, esse workflow só será executado se existir na branch alvo. Evite definir quaisquer segredos como variáveis de ambiente, como BENCHER_API_TOKEN. Em vez disso, passe explicitamente o token da API para bencher run. (ex: --token ${{ secrets.BENCHER_API_TOKEN }}) Veja este artigo do GitHub Security Lab e este post de blog sobre a prevenção de solicitações pwn para uma visão geral completa.

Benchmark PR Fork da Branch Alvo com Revisores Obrigatórios

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 configuração é exatamente a mesma que Benchmark PR Fork da Branch Alvo com a exigência adicional de aprovação de um Revisor Necessário antes de cada execução do fork do pull request. Pull requests do mesmo repositório não requerem aprovação. Para configurar isso, você precisa criar dois Ambientes de Ação do GitHub (ex: Repo -> Configurações -> Ambientes -> Novo ambiente). O ambiente interno não deve ter Regras de proteção de implantação. No entanto, o ambiente externo deve ter Revisores necessários definidos para aqueles confiáveis para revisar PRs de fork antes do benchmarking.

Benchmark PR Fork e Upload da Branch Padrão

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. Crie um arquivo de workflow Run and Cache Benchmarks.
  2. Execute seus benchmarks em eventos de pull_request.
  3. Salve os resultados dos benchmarks em um arquivo e faça o upload deles como um artefato.
  4. Faça o upload do evento pull_request como um artefato.
  5. Crie um segundo arquivo de workflow, Track Benchmarks.
  6. Encadeie Track Benchmarks a Run and Cache Benchmarks com o evento workflow_run.
  7. Extraia os dados necessários do evento pull_request armazenado em cache.
  8. Monitore os resultados do benchmark armazenado em cache com bencher run.
  9. Crie um terceiro arquivo de workflow e use o exemplo inicial acima para executar em eventos de push para a branch main.

Esta configuração funciona porque workflow_run é executado no contexto da branch padrão do repositório, onde seus segredos como BENCHER_API_TOKEN e GITHUB_TOKEN estão disponíveis. Portanto, esses workflows só serão executados se existirem na branch padrão. Veja usando dados do workflow que desencadeou para uma visão geral completa. O número do pull request, a branch de origem e a branch base usada no workflow inicial devem ser passados explicitamente, pois eles não estão disponíveis dentro do workflow_run.



🐰 Parabéns! Você aprendeu como usar o Bencher nas Ações do GitHub! 🎉


Continue: Visão Geral do Benchmarking ➡

🤖 Este documento foi gerado automaticamente pelo OpenAI GPT-4. Pode não ser preciso e pode conter erros. Se você encontrar algum erro, abra um problema no GitHub.