mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
After family=m7 was removed from the default e2e_service runner in #12274, TablesDB inherits the bare 4cpu runner with no instance-family pinning. Under paratest_processes: 3 the databases worker can't create attributes fast enough for the polling loop, producing "Expected 'available', Actual 'processing'" flakes across unrelated PRs. Match the Databases service override to give TablesDB its own 8cpu runner.
866 lines
29 KiB
YAML
866 lines
29 KiB
YAML
name: CI
|
|
|
|
concurrency:
|
|
group: ci-${{ github.ref }}
|
|
cancel-in-progress: true
|
|
|
|
env:
|
|
COMPOSE_FILE: docker-compose.yml
|
|
IMAGE: appwrite-dev
|
|
REGISTRY_IMAGE: ghcr.io/${{ github.repository }}/appwrite-dev
|
|
K6_VERSION: '0.53.0'
|
|
|
|
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: ''
|
|
|
|
permissions:
|
|
contents: read
|
|
packages: write
|
|
|
|
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@c51854704019a247608d928f370c98740469d4b5" # v2.3.5
|
|
|
|
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 0
|
|
submodules: 'recursive'
|
|
|
|
- name: Build the Docker image
|
|
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
with:
|
|
context: .
|
|
push: false
|
|
load: true
|
|
tags: pr_image:${{ github.sha }}
|
|
target: production
|
|
|
|
- name: Run Trivy vulnerability scanner on image
|
|
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.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@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.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@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
|
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@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
|
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
|
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 2
|
|
|
|
- run: git checkout HEAD^2
|
|
if: github.event_name == 'pull_request'
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
|
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@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
|
with:
|
|
php-version: '8.3'
|
|
tools: composer:v2
|
|
coverage: none
|
|
|
|
- name: Install dependencies
|
|
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
|
|
|
|
- name: Cache PHPStan result cache
|
|
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
|
with:
|
|
path: .phpstan-cache
|
|
key: phpstan-${{ github.sha }}
|
|
restore-keys: |
|
|
phpstan-
|
|
|
|
- name: Run PHPStan
|
|
run: composer analyze -- --no-progress
|
|
|
|
specs:
|
|
name: Checks / Specs
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Check out the repo
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Setup PHP
|
|
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
|
with:
|
|
php-version: '8.3'
|
|
extensions: swoole
|
|
tools: composer:v2
|
|
coverage: none
|
|
|
|
- name: Install dependencies
|
|
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
|
|
|
|
- name: Generate specs
|
|
run: _APP_STORAGE_LIMIT=5368709120 php app/cli.php specs --version=latest --git=no
|
|
|
|
locale:
|
|
name: Checks / Locale
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Check out the repo
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Setup Node
|
|
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
|
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 }}
|
|
steps:
|
|
- name: Generate matrix
|
|
id: generate
|
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
with:
|
|
script: |
|
|
const allDatabases = ['MariaDB', 'PostgreSQL', 'MongoDB'];
|
|
const allModes = ['dedicated', 'shared'];
|
|
|
|
const defaultDatabases = ['MongoDB'];
|
|
const defaultModes = ['dedicated'];
|
|
|
|
const pr = context.payload.pull_request;
|
|
if (!pr) {
|
|
core.setOutput('databases', JSON.stringify(allDatabases));
|
|
core.setOutput('modes', JSON.stringify(allModes));
|
|
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 ? allDatabases : defaultDatabases));
|
|
core.setOutput('modes', JSON.stringify(databaseChanged ? allModes : defaultModes));
|
|
|
|
build:
|
|
name: Build
|
|
runs-on: ubuntu-latest
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
submodules: recursive
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Set up Docker Buildx
|
|
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
|
|
|
- name: Build and push Appwrite
|
|
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
|
with:
|
|
context: .
|
|
push: true
|
|
tags: ${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
|
cache-from: type=gha
|
|
cache-to: type=gha,mode=max
|
|
target: development
|
|
build-args: |
|
|
DEBUG=false
|
|
TESTING=true
|
|
VERSION=dev
|
|
|
|
unit:
|
|
name: Tests / Unit
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
packages: read
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Pull Docker Image
|
|
run: |
|
|
docker pull ${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
|
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
run: |
|
|
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
|
|
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
|
with:
|
|
max_attempts: 2
|
|
retry_wait_seconds: 60
|
|
timeout_minutes: 15
|
|
job_id: ${{ job.check_run_id }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
test_dir: tests/unit
|
|
command: >-
|
|
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 / General
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
packages: read
|
|
steps:
|
|
- name: checkout
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Pull Docker Image
|
|
run: |
|
|
docker pull ${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
|
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
run: |
|
|
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 General Tests
|
|
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
|
with:
|
|
max_attempts: 2
|
|
retry_wait_seconds: 60
|
|
timeout_minutes: 15
|
|
job_id: ${{ job.check_run_id }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
test_dir: tests/e2e/General
|
|
command: >-
|
|
docker compose exec -T
|
|
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}"
|
|
appwrite test /usr/src/code/tests/e2e/General
|
|
|
|
- name: Failure Logs
|
|
if: failure()
|
|
run: |
|
|
echo "=== Appwrite Logs ==="
|
|
docker compose logs
|
|
|
|
e2e_service:
|
|
name: Tests / E2E / ${{ matrix.database }} (${{ matrix.mode }}) / ${{ matrix.service }}
|
|
runs-on: ${{ matrix.runner || format('runs-on={0}/runner=4cpu-linux-x64/volume=120g/spot=false', github.run_id) }}
|
|
needs: [build, matrix]
|
|
permissions:
|
|
contents: read
|
|
pull-requests: write
|
|
packages: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
database: ${{ fromJSON(needs.matrix.outputs.databases) }}
|
|
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
|
service: [
|
|
Account,
|
|
Avatars,
|
|
Console,
|
|
Databases,
|
|
TablesDB,
|
|
Functions,
|
|
FunctionsSchedule,
|
|
GraphQL,
|
|
Health,
|
|
Locale,
|
|
Projects,
|
|
Realtime,
|
|
Sites,
|
|
Proxy,
|
|
Storage,
|
|
Tokens,
|
|
Teams,
|
|
Users,
|
|
ProjectWebhooks,
|
|
Webhooks,
|
|
VCS,
|
|
Messaging,
|
|
Migrations,
|
|
Project
|
|
]
|
|
include:
|
|
- service: Databases
|
|
runner: runs-on=${{ github.run_id }}/runner=8cpu-linux-x64/volume=120g/spot=false
|
|
paratest_processes: 3
|
|
timeout_minutes: 30
|
|
- service: TablesDB
|
|
runner: runs-on=${{ github.run_id }}/runner=8cpu-linux-x64/volume=120g/spot=false
|
|
paratest_processes: 3
|
|
timeout_minutes: 30
|
|
- service: Migrations
|
|
paratest_processes: 1
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Set environment
|
|
run: |
|
|
echo "_APP_OPTIONS_ROUTER_PROTECTION=enabled" >> $GITHUB_ENV
|
|
|
|
if [ "${{ matrix.database }}" = "MariaDB" ]; then
|
|
echo "COMPOSE_PROFILES=mariadb" >> $GITHUB_ENV
|
|
echo "_APP_DB_ADAPTER=mariadb" >> $GITHUB_ENV
|
|
echo "_APP_DB_HOST=mariadb" >> $GITHUB_ENV
|
|
echo "_APP_DB_PORT=3306" >> $GITHUB_ENV
|
|
elif [ "${{ matrix.database }}" = "MongoDB" ]; then
|
|
echo "COMPOSE_PROFILES=mongodb" >> $GITHUB_ENV
|
|
echo "_APP_DB_ADAPTER=mongodb" >> $GITHUB_ENV
|
|
echo "_APP_DB_HOST=mongodb" >> $GITHUB_ENV
|
|
echo "_APP_DB_PORT=27017" >> $GITHUB_ENV
|
|
elif [ "${{ matrix.database }}" = "PostgreSQL" ]; then
|
|
echo "COMPOSE_PROFILES=postgresql" >> $GITHUB_ENV
|
|
echo "_APP_DB_ADAPTER=postgresql" >> $GITHUB_ENV
|
|
echo "_APP_DB_HOST=postgresql" >> $GITHUB_ENV
|
|
echo "_APP_DB_PORT=5432" >> $GITHUB_ENV
|
|
fi
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Pull Docker Image
|
|
run: |
|
|
docker pull ${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
|
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}
|
|
|
|
- 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_DOCUMENTSDB_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'documentsdb_db_main' || '' }}
|
|
_APP_DATABASE_VECTORSDB_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'vectorsdb_db_main' || '' }}
|
|
run: |
|
|
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
|
|
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
|
with:
|
|
max_attempts: 2
|
|
retry_wait_seconds: 60
|
|
timeout_minutes: ${{ matrix.timeout_minutes || 20 }}
|
|
job_id: ${{ job.check_run_id }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
test_dir: tests/e2e/Services/${{ matrix.service }}
|
|
command: |
|
|
SERVICE_PATH="/usr/src/code/tests/e2e/Services/${{ matrix.service }}"
|
|
|
|
# Services that rely on sequential test method execution (shared static state)
|
|
FUNCTIONAL_FLAG="--functional"
|
|
case "${{ matrix.service }}" in
|
|
Databases|TablesDB|Functions|Realtime|GraphQL|ProjectWebhooks) FUNCTIONAL_FLAG="" ;;
|
|
esac
|
|
|
|
PARATEST_PROCESSES="${{ matrix.paratest_processes }}"
|
|
if [ -z "$PARATEST_PROCESSES" ]; then
|
|
PARATEST_PROCESSES="$(nproc)"
|
|
fi
|
|
|
|
docker compose exec -T \
|
|
-e _APP_E2E_RESPONSE_FORMAT="${{ github.event.inputs.response_format }}" \
|
|
-e _TESTS_OAUTH2_GITHUB_CLIENT_ID="${{ secrets.TESTS_OAUTH2_GITHUB_CLIENT_ID }}" \
|
|
-e _TESTS_OAUTH2_GITHUB_CLIENT_SECRET="${{ secrets.TESTS_OAUTH2_GITHUB_CLIENT_SECRET }}" \
|
|
appwrite vendor/bin/paratest --processes "$PARATEST_PROCESSES" $FUNCTIONAL_FLAG "$SERVICE_PATH" --exclude-group abuseEnabled --exclude-group screenshots --log-junit tests/e2e/Services/${{ matrix.service }}/junit.xml
|
|
|
|
- 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
|
|
packages: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Pull Docker Image
|
|
run: |
|
|
docker pull ${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
|
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}
|
|
|
|
- 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_DOCUMENTSDB_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'documentsdb_db_main' || '' }}
|
|
_APP_DATABASE_VECTORSDB_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'vectorsdb_db_main' || '' }}
|
|
run: |
|
|
docker compose pull --quiet --ignore-buildable
|
|
docker compose up -d --quiet-pull --wait
|
|
|
|
- name: Run tests
|
|
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
|
with:
|
|
max_attempts: 2
|
|
retry_wait_seconds: 60
|
|
timeout_minutes: 15
|
|
job_id: ${{ job.check_run_id }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
test_dir: tests/e2e
|
|
command: >-
|
|
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
|
|
packages: read
|
|
strategy:
|
|
fail-fast: false
|
|
matrix:
|
|
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Pull Docker Image
|
|
run: |
|
|
docker pull ${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
|
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}
|
|
|
|
- name: Load and Start Appwrite
|
|
timeout-minutes: 5
|
|
env:
|
|
_APP_DATABASE_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'database_db_main' || '' }}
|
|
_APP_DATABASE_DOCUMENTSDB_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'documentsdb_db_main' || '' }}
|
|
_APP_DATABASE_VECTORSDB_SHARED_TABLES: ${{ matrix.mode != 'dedicated' && 'vectorsdb_db_main' || '' }}
|
|
run: |
|
|
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
|
|
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
|
with:
|
|
max_attempts: 2
|
|
retry_wait_seconds: 60
|
|
timeout_minutes: 15
|
|
job_id: ${{ job.check_run_id }}
|
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
|
test_dir: tests/e2e/Services/Sites
|
|
command: >-
|
|
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
|
|
if: github.event_name == 'pull_request'
|
|
runs-on: ubuntu-latest
|
|
needs: build
|
|
permissions:
|
|
actions: read
|
|
contents: read
|
|
issues: write
|
|
pull-requests: write
|
|
packages: read
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
|
with:
|
|
fetch-depth: 1
|
|
|
|
- name: Login to Docker Hub
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
username: ${{ vars.DOCKERHUB_USERNAME }}
|
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
|
|
- name: Login to GHCR
|
|
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
|
with:
|
|
registry: ghcr.io
|
|
username: ${{ github.actor }}
|
|
password: ${{ secrets.GITHUB_TOKEN }}
|
|
|
|
- name: Pull Appwrite image
|
|
run: |
|
|
docker pull ${{ env.REGISTRY_IMAGE }}:${{ github.sha }}
|
|
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}
|
|
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}:after
|
|
|
|
- name: Setup k6
|
|
uses: grafana/setup-k6-action@db07bd9765aac508ef18982e52ab937fe633a065 # v1.2.1
|
|
with:
|
|
k6-version: ${{ env.K6_VERSION }}
|
|
|
|
- name: Prepare benchmark before
|
|
id: benchmark_before_prepare
|
|
continue-on-error: true
|
|
run: |
|
|
git fetch --depth=1 origin ${{ github.event.pull_request.base.sha }}
|
|
git worktree add --detach /tmp/appwrite-benchmark-before ${{ github.event.pull_request.base.sha }}
|
|
docker build \
|
|
--cache-from ${{ env.IMAGE }}:after \
|
|
--target development \
|
|
--build-arg DEBUG=false \
|
|
--build-arg TESTING=true \
|
|
--build-arg VERSION=dev \
|
|
--tag ${{ env.IMAGE }}:before \
|
|
/tmp/appwrite-benchmark-before
|
|
|
|
- name: Start before Appwrite
|
|
id: benchmark_before_start
|
|
if: steps.benchmark_before_prepare.outcome == 'success'
|
|
continue-on-error: true
|
|
working-directory: /tmp/appwrite-benchmark-before
|
|
env:
|
|
_APP_DOMAIN: localhost
|
|
_APP_CONSOLE_DOMAIN: localhost
|
|
_APP_DOMAIN_FUNCTIONS: functions.localhost
|
|
_APP_OPTIONS_ABUSE: disabled
|
|
run: |
|
|
docker tag ${{ env.IMAGE }}:before ${{ env.IMAGE }}
|
|
docker compose up -d --wait --no-build
|
|
|
|
- name: Prepare benchmark files
|
|
run: rm -f benchmark-before-summary.json benchmark-after-summary.json benchmark-before-samples.json benchmark-after-samples.json
|
|
|
|
- name: Benchmark before
|
|
if: steps.benchmark_before_start.outcome == 'success'
|
|
continue-on-error: true
|
|
uses: grafana/run-k6-action@de51a7390bdf0ac85a3bef493691bd71d4c7c158 # v1.4.0
|
|
env:
|
|
APPWRITE_ENDPOINT: 'http://localhost/v1'
|
|
APPWRITE_BENCHMARK_ITERATIONS: '5'
|
|
APPWRITE_BENCHMARK_VUS: '1'
|
|
APPWRITE_WORKER_TIMEOUT_MS: '120000'
|
|
APPWRITE_BENCHMARK_SUMMARY_PATH: 'benchmark-before-summary.json'
|
|
with:
|
|
path: tests/benchmarks/http.js
|
|
flags: --quiet --out json=benchmark-before-samples.json
|
|
cloud-comment-on-pr: false
|
|
debug: true
|
|
|
|
- name: Stop before Appwrite
|
|
if: always()
|
|
run: |
|
|
if [ -d /tmp/appwrite-benchmark-before ]; then
|
|
cd /tmp/appwrite-benchmark-before
|
|
docker compose down -v || true
|
|
fi
|
|
|
|
- name: Wait for benchmark ports
|
|
if: always()
|
|
run: |
|
|
for port in 80 443 8080 9503; do
|
|
for attempt in $(seq 1 30); do
|
|
if ! ss -ltn | awk '{print $4}' | grep -Eq "[:.]${port}$"; then
|
|
break
|
|
fi
|
|
sleep 1
|
|
done
|
|
|
|
if ss -ltn | awk '{print $4}' | grep -Eq "[:.]${port}$"; then
|
|
echo "Port ${port} is still in use after stopping the before stack"
|
|
ss -ltn
|
|
exit 1
|
|
fi
|
|
done
|
|
|
|
- name: Start after Appwrite
|
|
env:
|
|
_APP_DOMAIN: localhost
|
|
_APP_CONSOLE_DOMAIN: localhost
|
|
_APP_DOMAIN_FUNCTIONS: functions.localhost
|
|
_APP_OPTIONS_ABUSE: disabled
|
|
run: |
|
|
docker tag ${{ env.IMAGE }}:after ${{ env.IMAGE }}
|
|
docker compose up -d --wait --no-build
|
|
|
|
- name: Benchmark after
|
|
id: benchmark_after
|
|
continue-on-error: true
|
|
uses: grafana/run-k6-action@de51a7390bdf0ac85a3bef493691bd71d4c7c158 # v1.4.0
|
|
env:
|
|
APPWRITE_ENDPOINT: 'http://localhost/v1'
|
|
APPWRITE_BENCHMARK_ITERATIONS: '5'
|
|
APPWRITE_BENCHMARK_VUS: '1'
|
|
APPWRITE_WORKER_TIMEOUT_MS: '120000'
|
|
APPWRITE_BENCHMARK_PREVIOUS_SUMMARY_PATH: '../../benchmark-before-summary.json'
|
|
APPWRITE_BENCHMARK_SUMMARY_PATH: 'benchmark-after-summary.json'
|
|
with:
|
|
path: tests/benchmarks/http.js
|
|
flags: --quiet --out json=benchmark-after-samples.json
|
|
cloud-comment-on-pr: false
|
|
debug: true
|
|
|
|
- name: Stop after Appwrite
|
|
if: always()
|
|
run: docker compose down -v || true
|
|
|
|
- name: Comment on PR
|
|
if: always()
|
|
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
|
env:
|
|
BENCHMARK_BASE_REF: ${{ github.event.pull_request.base.ref }}
|
|
BENCHMARK_HEAD_REF: ${{ github.event.pull_request.head.ref }}
|
|
with:
|
|
script: |
|
|
const comment = require('./.github/workflows/benchmark-comment.js');
|
|
await comment({ github, context, core });
|
|
|
|
- name: Save results
|
|
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
|
if: ${{ !cancelled() }}
|
|
with:
|
|
name: benchmark-results
|
|
path: |
|
|
benchmark-comment.txt
|
|
benchmark-before-summary.json
|
|
benchmark-after-summary.json
|
|
benchmark-before-samples.json
|
|
benchmark-after-samples.json
|
|
retention-days: 7
|
|
|
|
- name: Fail benchmark
|
|
if: always() && steps.benchmark_after.outcome != 'success'
|
|
run: exit 1
|