mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
953359a580
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
655 lines
22 KiB
YAML
655 lines
22 KiB
YAML
name: CI
|
|
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
COMPOSE_FILE: docker-compose.yml
|
|
IMAGE: appwrite-dev
|
|
|
|
on:
|
|
pull_request:
|
|
workflow_dispatch:
|
|
inputs:
|
|
response_format:
|
|
description: 'Response format version to test (e.g., 1.5.0, 1.4.0)'
|
|
required: false
|
|
type: string
|
|
default: ''
|
|
|
|
jobs:
|
|
dependencies:
|
|
name: Checks / Dependencies
|
|
if: github.event_name == 'pull_request'
|
|
permissions:
|
|
actions: read
|
|
security-events: write
|
|
contents: read
|
|
uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@v2.3.3"
|
|
|
|
security:
|
|
name: Checks / Image
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
permissions:
|
|
contents: read
|
|
security-events: write
|
|
steps:
|
|
- name: Check out code
|
|
uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 0
|
|
submodules: 'recursive'
|
|
|
|
- name: Build the Docker image
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
push: false
|
|
load: true
|
|
tags: pr_image:${{ github.sha }}
|
|
target: production
|
|
|
|
- name: Run Trivy vulnerability scanner on image
|
|
uses: aquasecurity/trivy-action@0.35.0
|
|
with:
|
|
image-ref: 'pr_image:${{ github.sha }}'
|
|
format: 'sarif'
|
|
output: 'trivy-image-results.sarif'
|
|
severity: 'CRITICAL,HIGH'
|
|
|
|
- name: Run Trivy vulnerability scanner on source code
|
|
uses: aquasecurity/trivy-action@0.35.0
|
|
with:
|
|
scan-type: 'fs'
|
|
scan-ref: '.'
|
|
format: 'sarif'
|
|
output: 'trivy-fs-results.sarif'
|
|
severity: 'CRITICAL,HIGH'
|
|
skip-setup-trivy: true
|
|
|
|
- name: Upload image scan results
|
|
uses: github/codeql-action/upload-sarif@v4
|
|
if: always() && hashFiles('trivy-image-results.sarif') != ''
|
|
with:
|
|
sarif_file: 'trivy-image-results.sarif'
|
|
category: 'trivy-image'
|
|
|
|
- name: Upload source code scan results
|
|
uses: github/codeql-action/upload-sarif@v4
|
|
if: always() && hashFiles('trivy-fs-results.sarif') != ''
|
|
with:
|
|
sarif_file: 'trivy-fs-results.sarif'
|
|
category: 'trivy-source'
|
|
|
|
composer:
|
|
name: Checks / Composer
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.3'
|
|
tools: composer:v2
|
|
coverage: none
|
|
|
|
- name: Validate
|
|
run: composer validate
|
|
|
|
- name: Install dependencies
|
|
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
|
|
|
|
- name: Audit
|
|
env:
|
|
COMPOSER_NO_AUDIT: 0
|
|
run: composer audit
|
|
|
|
format:
|
|
name: Checks / Format
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
with:
|
|
fetch-depth: 2
|
|
|
|
- run: git checkout HEAD^2
|
|
if: github.event_name == 'pull_request'
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.3'
|
|
tools: composer:v2
|
|
coverage: none
|
|
|
|
- name: Install dependencies
|
|
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
|
|
|
|
- name: Run Linter
|
|
run: composer lint
|
|
|
|
analyze:
|
|
name: Checks / Analyze
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Check out the repo
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@v2
|
|
with:
|
|
php-version: '8.3'
|
|
tools: composer:v2
|
|
coverage: none
|
|
|
|
- name: Install dependencies
|
|
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
|
|
|
|
- name: Run PHPStan
|
|
run: composer analyze
|
|
|
|
locale:
|
|
name: Checks / Locale
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Check out the repo
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@v4
|
|
with:
|
|
node-version: '24'
|
|
|
|
- name: Run Locale check
|
|
run: node .github/workflows/static-analysis/locale/index.js
|
|
|
|
matrix:
|
|
name: Tests / Matrix
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
databases: ${{ steps.generate.outputs.databases }}
|
|
modes: ${{ steps.generate.outputs.modes }}
|
|
services: ${{ steps.generate.outputs.services }}
|
|
steps:
|
|
- name: Generate matrix
|
|
id: generate
|
|
uses: actions/github-script@v8
|
|
with:
|
|
script: |
|
|
const databases = [
|
|
{ name: 'MariaDB', env: '.env,compose/mariadb.env', compose: 'docker-compose.yml:compose/mariadb.yml' },
|
|
{ name: 'PostgreSQL', env: '.env,compose/postgresql.env', compose: 'docker-compose.yml:compose/postgresql.yml' },
|
|
{ name: 'MongoDB', env: '.env', compose: 'docker-compose.yml' },
|
|
];
|
|
const modes = ['dedicated', 'shared_v1', 'shared_v2'];
|
|
|
|
const services = [
|
|
{ name: 'Account', parallel: true },
|
|
{ name: 'Avatars', parallel: true, runner: 'blacksmith-4vcpu-ubuntu-2404' },
|
|
{ name: 'Databases', runner: 'blacksmith-4vcpu-ubuntu-2404' },
|
|
{ name: 'TablesDB', runner: 'blacksmith-4vcpu-ubuntu-2404' },
|
|
{ name: 'Functions', runner: 'blacksmith-4vcpu-ubuntu-2404' },
|
|
{ name: 'FunctionsSchedule', parallel: true },
|
|
{ name: 'GraphQL', parallel: true },
|
|
{ name: 'Projects', parallel: true },
|
|
{ name: 'Realtime', runner: 'blacksmith-4vcpu-ubuntu-2404' },
|
|
{ name: 'Sites', parallel: true, runner: 'blacksmith-4vcpu-ubuntu-2404' },
|
|
{ name: 'Teams', parallel: true },
|
|
{ name: 'Users', parallel: true },
|
|
{ name: 'ProjectWebhooks', parallel: true },
|
|
{ name: 'Migrations', parallel: true },
|
|
{ name: 'Project', parallel: true },
|
|
];
|
|
core.setOutput('services', JSON.stringify(services));
|
|
|
|
const defaultDatabases = [databases.find(d => d.name === 'MongoDB')];
|
|
const defaultModes = ['dedicated'];
|
|
|
|
const pr = context.payload.pull_request;
|
|
if (!pr) {
|
|
core.setOutput('databases', JSON.stringify(databases));
|
|
core.setOutput('modes', JSON.stringify(modes));
|
|
return;
|
|
}
|
|
|
|
const getContent = (ref) => github.rest.repos.getContent({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
path: 'composer.lock',
|
|
ref,
|
|
});
|
|
|
|
const getDbVersion = (lock) => lock.packages?.find(p => p.name === 'utopia-php/database')?.version;
|
|
|
|
const [{ data: base }, { data: head }] = await Promise.all([
|
|
getContent(pr.base.sha),
|
|
getContent(pr.head.sha),
|
|
]);
|
|
|
|
const decode = (content) => JSON.parse(Buffer.from(content, 'base64').toString());
|
|
const databaseChanged = getDbVersion(decode(base.content)) !== getDbVersion(decode(head.content));
|
|
|
|
core.setOutput('databases', JSON.stringify(databaseChanged ? databases : defaultDatabases));
|
|
core.setOutput('modes', JSON.stringify(databaseChanged ? modes : defaultModes));
|
|
|
|
build:
|
|
name: Build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@v4
|
|
|
|
- name: Build Appwrite
|
|
uses: docker/build-push-action@v6
|
|
with:
|
|
context: .
|
|
push: false
|
|
tags: ${{ env.IMAGE }}
|
|
load: true
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
outputs: type=docker,dest=/tmp/${{ env.IMAGE }}.tar
|
|
target: development
|
|
build-args: |
|
|
DEBUG=false
|
|
TESTING=true
|
|
VERSION=dev
|
|
|
|
- name: Upload Docker Image
|
|
uses: actions/upload-artifact@v7
|
|
with:
|
|
name: ${{ env.IMAGE }}
|
|
path: /tmp/${{ env.IMAGE }}.tar
|
|
retention-days: 1
|
|
|
|
unit:
|
|
name: Tests / Unit
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Download Docker Image
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ env.IMAGE }}
|
|
path: /tmp
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
run: |
|
|
docker load --input /tmp/${{ env.IMAGE }}.tar
|
|
docker compose pull --quiet --ignore-buildable
|
|
docker compose up -d --quiet-pull --wait
|
|
|
|
- name: Environment Variables
|
|
run: docker compose exec -T appwrite vars
|
|
|
|
- name: Run Unit Tests
|
|
timeout-minutes: 15
|
|
run: >-
|
|
docker compose exec
|
|
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}"
|
|
appwrite test /usr/src/code/tests/unit
|
|
|
|
e2e_general:
|
|
name: Tests / E2E / ${{ matrix.database.name }} (${{ matrix.mode }}) / General
|
|
runs-on: ubuntu-latest
|
|
needs: [build, matrix]
|
|
env:
|
|
COMPOSE_FILE: ${{ matrix.database.compose }}
|
|
COMPOSE_ENV_FILES: ${{ matrix.database.env }}
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
database: ${{ fromJSON(needs.matrix.outputs.databases) }}
|
|
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Download Docker Image
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ env.IMAGE }}
|
|
path: /tmp
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
env:
|
|
_APP_BROWSER_HOST: http://invalid-browser/v1
|
|
_APP_DATABASE_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'database_db_main' || '' }}
|
|
_APP_DATABASE_SHARED_TABLES_V1: ${{ matrix.mode == 'shared_v1' && 'database_db_main' || '' }}
|
|
run: |
|
|
docker load --input /tmp/${{ env.IMAGE }}.tar
|
|
docker compose pull --quiet --ignore-buildable
|
|
docker compose up -d --quiet-pull --wait
|
|
|
|
- name: Wait for Open Runtimes
|
|
timeout-minutes: 3
|
|
run: |
|
|
while ! docker compose logs openruntimes-executor | grep -q "Executor is ready."; do
|
|
echo "Waiting for Executor to come online"
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run tests
|
|
timeout-minutes: 20
|
|
run: >-
|
|
docker compose exec -T
|
|
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}"
|
|
appwrite vendor/bin/paratest --processes $(nproc) --functional --testsuite GeneralGroup --exclude-group abuseEnabled --exclude-group screenshots
|
|
|
|
- name: Failure Logs
|
|
if: failure()
|
|
run: |
|
|
echo "=== Appwrite Logs ==="
|
|
docker compose logs
|
|
|
|
e2e_service:
|
|
name: Tests / E2E / ${{ matrix.database.name }} (${{ matrix.mode }}) / ${{ matrix.service.name }}
|
|
runs-on: ${{ matrix.service.runner || 'ubuntu-latest' }}
|
|
needs: [build, matrix]
|
|
env:
|
|
COMPOSE_FILE: ${{ matrix.database.compose }}
|
|
COMPOSE_ENV_FILES: ${{ matrix.database.env }}
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
database: ${{ fromJSON(needs.matrix.outputs.databases) }}
|
|
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
|
service: ${{ fromJSON(needs.matrix.outputs.services) }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Download Docker Image
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ env.IMAGE }}
|
|
path: /tmp
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
env:
|
|
_APP_BROWSER_HOST: http://invalid-browser/v1
|
|
_APP_DATABASE_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'database_db_main' || '' }}
|
|
_APP_DATABASE_SHARED_TABLES_V1: ${{ matrix.mode == 'shared_v1' && 'database_db_main' || '' }}
|
|
run: |
|
|
docker load --input /tmp/${{ env.IMAGE }}.tar
|
|
docker compose pull --quiet --ignore-buildable
|
|
docker compose up -d --quiet-pull --wait
|
|
|
|
- name: Wait for Open Runtimes
|
|
timeout-minutes: 3
|
|
run: |
|
|
while ! docker compose logs openruntimes-executor | grep -q "Executor is ready."; do
|
|
echo "Waiting for Executor to come online"
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run tests
|
|
timeout-minutes: 20
|
|
run: |
|
|
docker compose exec -T \
|
|
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \
|
|
appwrite vendor/bin/paratest --processes $(nproc) ${{ matrix.service.parallel && '--functional' || '' }} --testsuite ${{ matrix.service.name }} --exclude-group abuseEnabled --exclude-group screenshots
|
|
|
|
- name: Failure Logs
|
|
if: failure()
|
|
run: |
|
|
echo "=== Appwrite Logs ==="
|
|
docker compose logs
|
|
|
|
e2e_abuse:
|
|
name: Tests / E2E / Abuse (${{ matrix.mode }})
|
|
runs-on: ubuntu-latest
|
|
needs: [build, matrix]
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Download Docker Image
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ env.IMAGE }}
|
|
path: /tmp
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
env:
|
|
_APP_OPTIONS_ABUSE: enabled
|
|
_APP_DATABASE_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'database_db_main' || '' }}
|
|
_APP_DATABASE_SHARED_TABLES_V1: ${{ matrix.mode == 'shared_v1' && 'database_db_main' || '' }}
|
|
run: |
|
|
docker load --input /tmp/${{ env.IMAGE }}.tar
|
|
docker compose pull --quiet --ignore-buildable
|
|
docker compose up -d --quiet-pull --wait
|
|
|
|
- name: Run tests
|
|
timeout-minutes: 15
|
|
run: >-
|
|
docker compose exec -T
|
|
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}"
|
|
appwrite test /usr/src/code/tests/e2e --group=abuseEnabled
|
|
|
|
- name: Failure Logs
|
|
if: failure()
|
|
run: |
|
|
echo "=== Appwrite Logs ==="
|
|
docker compose logs
|
|
|
|
e2e_screenshots:
|
|
name: Tests / E2E / Screenshots (${{ matrix.mode }})
|
|
runs-on: ubuntu-latest
|
|
needs: [build, matrix]
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Download Docker Image
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ env.IMAGE }}
|
|
path: /tmp
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
env:
|
|
_APP_DATABASE_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'database_db_main' || '' }}
|
|
_APP_DATABASE_SHARED_TABLES_V1: ${{ matrix.mode == 'shared_v1' && 'database_db_main' || '' }}
|
|
run: |
|
|
docker load --input /tmp/${{ env.IMAGE }}.tar
|
|
docker compose pull --quiet --ignore-buildable
|
|
docker compose up -d --quiet-pull --wait
|
|
|
|
- name: Wait for Open Runtimes
|
|
timeout-minutes: 3
|
|
run: |
|
|
while ! docker compose logs openruntimes-executor | grep -q "Executor is ready."; do
|
|
echo "Waiting for Executor to come online"
|
|
sleep 1
|
|
done
|
|
|
|
- name: Run tests
|
|
timeout-minutes: 15
|
|
run: >-
|
|
docker compose exec -T
|
|
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}"
|
|
appwrite test /usr/src/code/tests/e2e/Services/Sites --group=screenshots
|
|
|
|
- name: Failure Logs
|
|
if: failure()
|
|
run: |
|
|
echo "=== Appwrite Logs ==="
|
|
docker compose logs
|
|
|
|
benchmark:
|
|
name: Benchmark
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
permissions:
|
|
pull-requests: write
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@v6
|
|
|
|
- name: Download Docker Image
|
|
uses: actions/download-artifact@v7
|
|
with:
|
|
name: ${{ env.IMAGE }}
|
|
path: /tmp
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@v4
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Load and Start Appwrite
|
|
run: |
|
|
sed -i 's/traefik/localhost/g' .env
|
|
docker load --input /tmp/${{ env.IMAGE }}.tar
|
|
docker compose up -d
|
|
sleep 10
|
|
|
|
- name: Install Oha
|
|
run: |
|
|
echo "deb [signed-by=/usr/share/keyrings/azlux-archive-keyring.gpg] http://packages.azlux.fr/debian/ stable main" | sudo tee /etc/apt/sources.list.d/azlux.list
|
|
sudo wget -O /usr/share/keyrings/azlux-archive-keyring.gpg https://azlux.fr/repo.gpg
|
|
sudo apt update
|
|
sudo apt install oha
|
|
oha --version
|
|
|
|
- name: Benchmark PR
|
|
run: 'oha -z 180s http://localhost/v1/health/version --output-format json > benchmark.json'
|
|
|
|
- name: Cleaning
|
|
run: docker compose down -v
|
|
|
|
- name: Installing latest version
|
|
run: |
|
|
rm docker-compose.yml
|
|
rm .env
|
|
curl https://appwrite.io/install/compose -o docker-compose.yml
|
|
curl https://appwrite.io/install/env -o .env
|
|
sed -i 's/_APP_OPTIONS_ABUSE=enabled/_APP_OPTIONS_ABUSE=disabled/g' .env
|
|
docker compose up -d
|
|
sleep 10
|
|
|
|
- name: Benchmark Latest
|
|
run: oha -z 180s http://localhost/v1/health/version --output-format json > benchmark-latest.json
|
|
|
|
- name: Prepare comment
|
|
run: |
|
|
echo '## :sparkles: Benchmark results' > benchmark.txt
|
|
echo ' ' >> benchmark.txt
|
|
echo "- Requests per second: $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
|
|
echo "- Requests with 200 status code: $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json)" >> benchmark.txt
|
|
echo "- P99 latency: $(jq -r '.latencyPercentiles.p99' benchmark.json )" >> benchmark.txt
|
|
echo " " >> benchmark.txt
|
|
echo " " >> benchmark.txt
|
|
echo "## :zap: Benchmark Comparison" >> benchmark.txt
|
|
echo " " >> benchmark.txt
|
|
echo "| Metric | This PR | Latest version | " >> benchmark.txt
|
|
echo "| --- | --- | --- | " >> benchmark.txt
|
|
echo "| RPS | $(jq -r '.summary.requestsPerSec|tonumber?|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.summary.requestsPerSec|tonumber|floor|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
|
|
echo "| 200 | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark.json) | $(jq -r '.statusCodeDistribution."200"|tostring|[while(length>0;.[:-3])|.[-3:]]|reverse|join(",")' benchmark-latest.json) | " >> benchmark.txt
|
|
echo "| P99 | $(jq -r '.latencyPercentiles.p99' benchmark.json ) | $(jq -r '.latencyPercentiles.p99' benchmark-latest.json ) | " >> benchmark.txt
|
|
|
|
- name: Save results
|
|
uses: actions/upload-artifact@v7
|
|
if: ${{ !cancelled() }}
|
|
with:
|
|
name: benchmark.json
|
|
path: benchmark.json
|
|
retention-days: 7
|
|
|
|
- name: Find Comment
|
|
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
uses: peter-evans/find-comment@v3
|
|
id: fc
|
|
with:
|
|
issue-number: ${{ github.event.pull_request.number }}
|
|
comment-author: 'github-actions[bot]'
|
|
body-includes: Benchmark results
|
|
|
|
- name: Comment on PR
|
|
if: github.event.pull_request.head.repo.full_name == github.repository
|
|
uses: peter-evans/create-or-update-comment@v4
|
|
with:
|
|
comment-id: ${{ steps.fc.outputs.comment-id }}
|
|
issue-number: ${{ github.event.pull_request.number }}
|
|
body-path: benchmark.txt
|
|
edit-mode: replace
|