Как использовать Bencher в 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"
- Создайте файл
workflow
для GitHub Actions. (пример:.github/workflows/benchmark.yml
) - Запускайте при событиях
push
вmain
ветку. Подробнее см. в документации GitHub Actionson
и ниже в разделе Pull Requests. - Создайте
job
для GitHub Actions. (пример:benchmark_with_bencher
) - Проект уже должен существовать. Установите флаг
--project
или переменную средыBENCHER_PROJECT
на символическое имя или UUID проекта (пример:BENCHER_PROJECT: save-walter-white
). - API токен уже должен существовать. Добавьте
BENCHER_API_TOKEN
как секрет репозитория. (пример:Repo -> Settings -> Secrets and variables -> Actions -> New repository secret
) Установите флаг--token
или переменную средыBENCHER_API_TOKEN
на API токен. (пример:BENCHER_API_TOKEN: ${{ secrets.BENCHER_API_TOKEN }}
) - Необязательный шаг: установите флаг
--testbed
или переменную средыBENCHER_TESTBED
на символическое имя или UUID Testbed. (пример:BENCHER_TESTBED: ubuntu-latest
) Testbed должен уже существовать. Если это не задано, то будет использоваться Testbedlocalhost
. - Необязательный шаг: установите флаг
--adapter
или переменную средыBENCHER_ADAPTER
на желаемое имя адаптера. (пример:BENCHER_ADAPTER: json
) Если это не задано, то будет использоваться адаптерmagic
. Подробнее см. адаптеры для benchmark harness. - Произведите клонирование вашего исходниго кода. (пример:
uses: actions/checkout@v3
) - Установите Bencher CLI используя GitHub Action. (пример:
uses: bencherdev/bencher@main
) - Отслеживайте свои бенчмарки с помощью подкоманды CLI
bencher run
:- Необязательный шаг: установите флаг
--branch
или переменную средыBENCHER_BRANCH
на символическое имя или UUID ветки. (пример:--branch main
) Ветвь должна уже существовать. Если это не задано, то используется ветвьmain
. - Установите команду, чтобы она завершилась с ошибкой, если создано предупреждение. (пример:
--err
) Чтобы предупреждение было создано, требуется уже существующий порог. - Запустите бенчмарки и сгенерируйте отчет из результатов. (пример:
"bencher mock"
)
- Необязательный шаг: установите флаг
Pull Requests
Чтобы отследить регрессию производительности в Pull Requests, вам потребуется запустить ваши бенчмарки на PRs.
Если вы ожидаете PRs только из ветвей в рамках одного и того же репозитория, вы можете просто модифицировать пример выше, чтобы также запускать его on
pull_request
событиях.
⚠️ Это решение работает, только если все PRs из одного и того же репозитория! См. ниже Pull Requests from Forks.
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"
- Запускайте при событиях
push
вmain
ветку и наpull_request
событиях. Важно ограничить запуск при событииpush
только для выбранных ветвей (например,main
), чтобы предотвратить двойной запуск при пушах в ветки PR! - Вместо всегда использования ветки
main
, используйте переменные среды по умолчанию GitHub Action для:- Использование текущих данных ветки, если они уже существуют. (пример:
--if-branch "$GITHUB_REF_NAME"
) - Создания клонов данных целевой ветки PR и порогов, если они уже существуют. (пример:
--else-if-branch "$GITHUB_BASE_REF"
) - В других случаях создания клонов данных ветки
main
и порогов. (пример:--else-if-branch main
) - Есть несколько вариантов установки ветки проекта. Подробнее см. выбор ветви.
- Использование текущих данных ветки, если они уже существуют. (пример:
- Установите токен аутентификации на GitHub API. (пример:
--github-actions ${{ secrets.GITHUB_TOKEN }}
) При установке этой опции как часть pull request, результаты будут добавлены в pull request как комментарий. Используется переменная средыGITHUB_TOKEN
в GitHub Actions. - См. документацию bencher run для подробного обзора всех способов настройки комментария к pull request с помощью флагов
--ci-*
.
Pull Requests из форков
Если вы планируете принимать pull requests от форков, как это часто бывает в открытых проектах с открытым исходным кодом,
то вам придется немного иначе обрабатывать такие ситуации.
По соображениям безопасности, секреты типа вашего BENCHER_API_TOKEN
и GITHUB_TOKEN
недоступны в GitHub Actions для PR из форков.
То есть, если внешний участник открывает PR из форка, пример выше не будет работать.
Есть три варианта для PR из форков:
- Benchmark Fork PR from Target Branch
- Benchmark Fork PR from Target Branch with Required Reviewers
- Benchmark Fork PR and Upload from Default Branch
Benchmark Fork PR из целевой ветки
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"
- Запускайте на событиях
push
вmain
ветку и на событияхpull_request_target
. - Создайте
job
который запускается только для событийpush
вmain
ветку. За исключением условияif
, этотjob
почти идентичен оригинальному примеру выше. - Создайте
job
который запускается только для событийpull_request_target
.- Произведите клонирование ветки pull request.
- Передайте все секреты непосредственно. Используйте
--token ${{ secrets.BENCHER_API_TOKEN }}
вместо переменной средыBENCHER_API_TOKEN
. - Запустите бенчмарки вашего pull request и отслеживайте их с
bencher run
.
Эта установка работает, потому что pull_request_target
выполняется в контексте целевой ветки pull request,
где доступны секреты, такие как ваш BENCHER_API_TOKEN
и GITHUB_TOKEN
.
Поэтому, этот workflow будет запущен только если он существует на целевой ветке.
Избегайте установки любых секретов в переменных среды, таких как BENCHER_API_TOKEN
.
Вместо этого явно передавайте API токен в bencher run
. (пример: --token ${{ secrets.BENCHER_API_TOKEN }}
)
Смотрите GitHub Security Lab write up
и эту статью в блоге
о предотвращении запросов вредоносного контента для подробного обзора.
Benchmark Fork PR из целевой ветки с обязательными ревьюерами
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"
Эта установка точно такая же, как и Benchmark Fork PR из целевой ветки
с дополнительным требованием одобрения от Обязательного Ревьюера перед каждым запуском бенчмарка для pull request из форка.
Pull requests из того же репозитория не требуют одобрения.
Для настройки этого вам нужно создать два окружения GitHub Action
(пример: Repo -> Settings -> Environments -> New environment
).
Окружение internal
не должно иметь Deployment protection rules
.
Однако, окружение external
должно иметь установленными Required reviewers
тех, кто доверен для просмотра PR из форка перед бенчмаркингом.
Benchmark Fork PR и загрузка из ветки по умолчанию
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
- Создайте файл workflow
Run and Cache Benchmarks
. - Запустите ваши бенчмарки на событиях
pull_request
. - Сохраните результаты бенчмарков в файл и загрузите их как артефакт.
- Загрузите событие
pull_request
как артефакт. - Создайте второй файл workflow,
Track Benchmarks
. - Свяжите
Track Benchmarks
сRun and Cache Benchmarks
по событиюworkflow_run
. - Извлеките необходимые данные из закешированного события
pull_request
. - Отследите закешированные результаты бенчмарков с
bencher run
. - Создайте третий файл workflow и используйте оригинальный пример выше для запуска на событиях
push
вmain
ветку.
Эта установка работает, потому что workflow_run
выполняется в контексте ветки по умолчанию репозитория,
где доступны секреты, такие как ваш BENCHER_API_TOKEN
и GITHUB_TOKEN
.
Поэтому, эти workflow будут запущены только если они существуют на ветке по умолчанию.
Смотрите использование данных от запускающего workflow для подробного обзора.
Номер pull request, ветка шапки и основная ветка, использованные в исходном workflow, должны быть явно переданы, так как они недоступны внутри workflow_run
.
🐰 Поздравляем! Вы научились использовать Bencher в GitHub Actions! 🎉