mirror of
https://github.com/appwrite/appwrite.git
synced 2026-05-26 13:51:13 +00:00
Merge branch '1.9.x' into migrate-away-from-blacksmith-based-runners
This commit is contained in:
@@ -25,6 +25,6 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: AI Moderator
|
||||
uses: github/ai-moderator@v1
|
||||
uses: github/ai-moderator@81159c370785e295c97461ade67d7c33576e9319 # v1.1.4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Issue Labeler
|
||||
uses: github/issue-labeler@v3.4
|
||||
uses: github/issue-labeler@c1b0f9f52a63158c4adc09425e858e87b32e9685 # v3.4
|
||||
with:
|
||||
configuration-path: .github/labeler.yml
|
||||
enable-versioned-regex: false
|
||||
|
||||
+52
-52
@@ -32,7 +32,7 @@ jobs:
|
||||
actions: read
|
||||
security-events: write
|
||||
contents: read
|
||||
uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@v2.3.3"
|
||||
uses: "google/osv-scanner-action/.github/workflows/osv-scanner-reusable-pr.yml@c51854704019a247608d928f370c98740469d4b5" # v2.3.5
|
||||
|
||||
security:
|
||||
name: Checks / Image
|
||||
@@ -43,13 +43,13 @@ jobs:
|
||||
security-events: write
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 0
|
||||
submodules: 'recursive'
|
||||
|
||||
- name: Build the Docker image
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
push: false
|
||||
@@ -58,7 +58,7 @@ jobs:
|
||||
target: production
|
||||
|
||||
- name: Run Trivy vulnerability scanner on image
|
||||
uses: aquasecurity/trivy-action@0.35.0
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
image-ref: 'pr_image:${{ github.sha }}'
|
||||
format: 'sarif'
|
||||
@@ -66,7 +66,7 @@ jobs:
|
||||
severity: 'CRITICAL,HIGH'
|
||||
|
||||
- name: Run Trivy vulnerability scanner on source code
|
||||
uses: aquasecurity/trivy-action@0.35.0
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
scan-ref: '.'
|
||||
@@ -76,14 +76,14 @@ jobs:
|
||||
skip-setup-trivy: true
|
||||
|
||||
- name: Upload image scan results
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
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@v4
|
||||
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
if: always() && hashFiles('trivy-fs-results.sarif') != ''
|
||||
with:
|
||||
sarif_file: 'trivy-fs-results.sarif'
|
||||
@@ -94,10 +94,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
||||
with:
|
||||
php-version: '8.3'
|
||||
tools: composer:v2
|
||||
@@ -119,7 +119,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
|
||||
@@ -127,7 +127,7 @@ jobs:
|
||||
if: github.event_name == 'pull_request'
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
||||
with:
|
||||
php-version: '8.3'
|
||||
tools: composer:v2
|
||||
@@ -144,10 +144,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
||||
with:
|
||||
php-version: '8.3'
|
||||
tools: composer:v2
|
||||
@@ -157,7 +157,7 @@ jobs:
|
||||
run: composer install --prefer-dist --no-progress --ignore-platform-reqs
|
||||
|
||||
- name: Cache PHPStan result cache
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
|
||||
with:
|
||||
path: .phpstan-cache
|
||||
key: phpstan-${{ github.sha }}
|
||||
@@ -172,10 +172,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
uses: shivammathur/setup-php@accd6127cb78bee3e8082180cb391013d204ef9f # 2.37.0
|
||||
with:
|
||||
php-version: '8.3'
|
||||
extensions: swoole
|
||||
@@ -193,10 +193,10 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out the repo
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: '24'
|
||||
|
||||
@@ -212,7 +212,7 @@ jobs:
|
||||
steps:
|
||||
- name: Generate matrix
|
||||
id: generate
|
||||
uses: actions/github-script@v8
|
||||
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
|
||||
with:
|
||||
script: |
|
||||
const allDatabases = ['MariaDB', 'PostgreSQL', 'MongoDB'];
|
||||
@@ -253,28 +253,28 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
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@v4
|
||||
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@v4
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Build and push Appwrite
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
@@ -297,16 +297,16 @@ jobs:
|
||||
packages: read
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
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@v4
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -327,7 +327,7 @@ jobs:
|
||||
run: docker compose exec -T appwrite vars
|
||||
|
||||
- name: Run Unit Tests
|
||||
uses: itznotabug/php-retry@v3
|
||||
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
||||
with:
|
||||
max_attempts: 2
|
||||
retry_wait_seconds: 60
|
||||
@@ -350,16 +350,16 @@ jobs:
|
||||
packages: read
|
||||
steps:
|
||||
- name: checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
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@v4
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -385,7 +385,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Run General Tests
|
||||
uses: itznotabug/php-retry@v3
|
||||
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
||||
with:
|
||||
max_attempts: 2
|
||||
retry_wait_seconds: 60
|
||||
@@ -464,7 +464,7 @@ jobs:
|
||||
paratest_processes: 1
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set environment
|
||||
run: |
|
||||
@@ -488,13 +488,13 @@ jobs:
|
||||
fi
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
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@v4
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -525,7 +525,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Run tests
|
||||
uses: itznotabug/php-retry@v3
|
||||
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
||||
with:
|
||||
max_attempts: 2
|
||||
retry_wait_seconds: 60
|
||||
@@ -573,18 +573,18 @@ jobs:
|
||||
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
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@v4
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -607,7 +607,7 @@ jobs:
|
||||
docker compose up -d --quiet-pull --wait
|
||||
|
||||
- name: Run tests
|
||||
uses: itznotabug/php-retry@v3
|
||||
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
||||
with:
|
||||
max_attempts: 2
|
||||
retry_wait_seconds: 60
|
||||
@@ -640,16 +640,16 @@ jobs:
|
||||
mode: ${{ fromJSON(needs.matrix.outputs.modes) }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
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@v4
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -679,7 +679,7 @@ jobs:
|
||||
done
|
||||
|
||||
- name: Run tests
|
||||
uses: itznotabug/php-retry@v3
|
||||
uses: itznotabug/php-retry@d6bef45a8bff490babfb613e33b00d133e4062f0 # v3
|
||||
with:
|
||||
max_attempts: 2
|
||||
retry_wait_seconds: 60
|
||||
@@ -711,18 +711,18 @@ jobs:
|
||||
packages: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v4
|
||||
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@v4
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
@@ -735,7 +735,7 @@ jobs:
|
||||
docker tag ${{ env.REGISTRY_IMAGE }}:${{ github.sha }} ${{ env.IMAGE }}:after
|
||||
|
||||
- name: Setup k6
|
||||
uses: grafana/setup-k6-action@ffe7d7290dfa715e48c2ccc924d068444c94bde2
|
||||
uses: grafana/setup-k6-action@db07bd9765aac508ef18982e52ab937fe633a065 # v1.2.1
|
||||
with:
|
||||
k6-version: ${{ env.K6_VERSION }}
|
||||
|
||||
@@ -774,7 +774,7 @@ jobs:
|
||||
- name: Benchmark before
|
||||
if: steps.benchmark_before_start.outcome == 'success'
|
||||
continue-on-error: true
|
||||
uses: grafana/run-k6-action@a15e2072ede004e8d46141e33d7f7dad8ad08d9d
|
||||
uses: grafana/run-k6-action@de51a7390bdf0ac85a3bef493691bd71d4c7c158 # v1.4.0
|
||||
env:
|
||||
APPWRITE_ENDPOINT: 'http://localhost/v1'
|
||||
APPWRITE_BENCHMARK_ITERATIONS: '5'
|
||||
@@ -826,7 +826,7 @@ jobs:
|
||||
- name: Benchmark after
|
||||
id: benchmark_after
|
||||
continue-on-error: true
|
||||
uses: grafana/run-k6-action@a15e2072ede004e8d46141e33d7f7dad8ad08d9d
|
||||
uses: grafana/run-k6-action@de51a7390bdf0ac85a3bef493691bd71d4c7c158 # v1.4.0
|
||||
env:
|
||||
APPWRITE_ENDPOINT: 'http://localhost/v1'
|
||||
APPWRITE_BENCHMARK_ITERATIONS: '5'
|
||||
@@ -846,7 +846,7 @@ jobs:
|
||||
|
||||
- name: Comment on PR
|
||||
if: always()
|
||||
uses: actions/github-script@v8
|
||||
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 }}
|
||||
@@ -856,7 +856,7 @@ jobs:
|
||||
await comment({ github, context, core });
|
||||
|
||||
- name: Save results
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
if: ${{ !cancelled() }}
|
||||
with:
|
||||
name: benchmark-results
|
||||
|
||||
@@ -15,7 +15,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Cleanup
|
||||
run: |
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
@@ -47,14 +47,14 @@ jobs:
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -68,4 +68,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
|
||||
@@ -10,13 +10,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: recursive
|
||||
- name: Build the Docker image
|
||||
run: DOCKER_BUILDKIT=1 docker build . --target production -t appwrite_image:latest
|
||||
- name: Run Trivy vulnerability scanner on image
|
||||
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
image-ref: 'appwrite_image:latest'
|
||||
format: 'sarif'
|
||||
@@ -24,7 +24,7 @@ jobs:
|
||||
ignore-unfixed: 'false'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
- name: Upload Docker Image Scan Results
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
if: always() && hashFiles('trivy-image-results.sarif') != ''
|
||||
with:
|
||||
sarif_file: 'trivy-image-results.sarif'
|
||||
@@ -35,16 +35,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
- name: Run Trivy vulnerability scanner on filesystem
|
||||
uses: aquasecurity/trivy-action@57a97c7e7821a5776cebc9bb87c984fa69cba8f1 # v0.35.0
|
||||
uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 # v0.36.0
|
||||
with:
|
||||
scan-type: 'fs'
|
||||
format: 'sarif'
|
||||
output: 'trivy-fs-results.sarif'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
- name: Upload Code Scan Results
|
||||
uses: github/codeql-action/upload-sarif@v4
|
||||
uses: github/codeql-action/upload-sarif@e46ed2cbd01164d986452f91f178727624ae40d7 # v4.35.3
|
||||
if: always() && hashFiles('trivy-fs-results.sarif') != ''
|
||||
with:
|
||||
sarif_file: 'trivy-fs-results.sarif'
|
||||
|
||||
@@ -12,33 +12,33 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
fetch-depth: 2
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
||||
with:
|
||||
images: appwrite/cloud
|
||||
tags: |
|
||||
type=ref,event=tag
|
||||
|
||||
- name: Build & Publish to DockerHub
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
@@ -20,20 +20,20 @@ jobs:
|
||||
submodules: recursive
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
username: ${{ vars.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels) for Docker
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
||||
with:
|
||||
images: appwrite/appwrite
|
||||
tags: |
|
||||
@@ -42,7 +42,7 @@ jobs:
|
||||
type=semver,pattern={{major}}
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set SDK type
|
||||
id: set-sdk
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
docker compose exec appwrite sdks --platform=${{ steps.set-sdk.outputs.platform }} --sdk=${{ steps.set-sdk.outputs.sdk_type }} --version=latest --git=no
|
||||
sudo chown -R $USER:$USER ./app/sdks/${{ steps.set-sdk.outputs.platform }}-${{ steps.set-sdk.outputs.sdk_type }}
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
submodules: recursive
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/stale@v10
|
||||
- uses: actions/stale@b5d41d4e1d5dceea10e7104786b73624c18a190f # v10.2.0
|
||||
with:
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
stale-issue-message: "This issue has been labeled as a 'question', indicating that it requires additional information from the requestor. It has been inactive for 7 days. If no further activity occurs, this issue will be closed in 14 days."
|
||||
|
||||
@@ -1246,6 +1246,26 @@ return [
|
||||
'description' => 'The specified database type is not supported for CSV import or export operations.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::MIGRATION_SOURCE_PROJECT_ID_REQUIRED => [
|
||||
'name' => Exception::MIGRATION_SOURCE_PROJECT_ID_REQUIRED,
|
||||
'description' => 'A source projectId is required for Appwrite migrations. Provide it in the migration credentials.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::MIGRATION_SOURCE_PROJECT_NOT_FOUND => [
|
||||
'name' => Exception::MIGRATION_SOURCE_PROJECT_NOT_FOUND,
|
||||
'description' => 'The source project for the provided projectId was not found. Verify the projectId and the API key has access to it.',
|
||||
'code' => 404,
|
||||
],
|
||||
Exception::MIGRATION_SOURCE_TYPE_INVALID => [
|
||||
'name' => Exception::MIGRATION_SOURCE_TYPE_INVALID,
|
||||
'description' => 'The migration source type is invalid. Use one of the supported source types.',
|
||||
'code' => 400,
|
||||
],
|
||||
Exception::MIGRATION_DESTINATION_TYPE_INVALID => [
|
||||
'name' => Exception::MIGRATION_DESTINATION_TYPE_INVALID,
|
||||
'description' => 'The migration destination type is invalid. Use one of the supported destination types.',
|
||||
'code' => 400,
|
||||
],
|
||||
|
||||
/** Realtime */
|
||||
Exception::REALTIME_MESSAGE_FORMAT_INVALID => [
|
||||
|
||||
@@ -320,6 +320,26 @@ return [
|
||||
'repoBranch' => 'main',
|
||||
'changelog' => \realpath(__DIR__ . '/../../docs/sdks/claude-plugin/CHANGELOG.md'),
|
||||
],
|
||||
[
|
||||
'key' => 'codex-plugin',
|
||||
'name' => 'CodexPlugin',
|
||||
'version' => '0.1.0',
|
||||
'url' => 'https://github.com/appwrite/codex-plugin.git',
|
||||
'enabled' => true,
|
||||
'beta' => false,
|
||||
'dev' => false,
|
||||
'hidden' => false,
|
||||
'spec' => 'static',
|
||||
'family' => APP_SDK_PLATFORM_STATIC,
|
||||
'prism' => 'codex-plugin',
|
||||
'source' => \realpath(__DIR__ . '/../sdks/static-codex-plugin'),
|
||||
'gitUrl' => 'git@github.com:appwrite/codex-plugin.git',
|
||||
'gitRepoName' => 'codex-plugin',
|
||||
'gitUserName' => 'appwrite',
|
||||
'gitBranch' => 'dev',
|
||||
'repoBranch' => 'main',
|
||||
'changelog' => \realpath(__DIR__ . '/../../docs/sdks/codex-plugin/CHANGELOG.md'),
|
||||
],
|
||||
],
|
||||
],
|
||||
|
||||
|
||||
@@ -332,15 +332,15 @@ Http::post('/v1/account')
|
||||
throw new Exception(Exception::GENERAL_INVALID_EMAIL);
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
throw new Exception(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
throw new Exception(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
@@ -1676,15 +1676,15 @@ Http::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
$failureRedirect(Exception::GENERAL_INVALID_EMAIL);
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
$failureRedirect(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
$failureRedirect(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
$failureRedirect(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
@@ -1817,15 +1817,15 @@ Http::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||
$failureRedirect(Exception::GENERAL_INVALID_EMAIL);
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
$failureRedirect(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
$failureRedirect(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
$failureRedirect(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
@@ -2175,15 +2175,15 @@ Http::post('/v1/account/tokens/magic-url')
|
||||
throw new Exception(Exception::GENERAL_INVALID_EMAIL);
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
throw new Exception(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
throw new Exception(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
@@ -2496,15 +2496,15 @@ Http::post('/v1/account/tokens/email')
|
||||
throw new Exception(Exception::GENERAL_INVALID_EMAIL);
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
throw new Exception(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
throw new Exception(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
@@ -3417,15 +3417,15 @@ Http::patch('/v1/account/email')
|
||||
throw new Exception(Exception::GENERAL_INVALID_EMAIL);
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && $emailMetadata['emailIsDisposable']) {
|
||||
throw new Exception(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && $emailMetadata['emailIsCanonical'] === false) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && $emailMetadata['emailIsFree']) {
|
||||
throw new Exception(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
|
||||
@@ -131,15 +131,15 @@ function createUser(Hash $hash, string $userId, ?string $email, ?string $passwor
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && ($emailMetadata['emailIsDisposable'] ?? false)) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && ($emailMetadata['emailIsDisposable'] ?? false)) {
|
||||
throw new Exception(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && ($emailMetadata['emailIsCanonical'] ?? true) === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && ($emailMetadata['emailIsCanonical'] ?? true) === false) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && ($emailMetadata['emailIsFree'] ?? false)) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && ($emailMetadata['emailIsFree'] ?? false)) {
|
||||
throw new Exception(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
@@ -1563,15 +1563,15 @@ Http::patch('/v1/users/:userId/email')
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && ($emailMetadata['emailIsDisposable'] ?? false)) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && ($emailMetadata['emailIsDisposable'] ?? false)) {
|
||||
throw new Exception(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && ($emailMetadata['emailIsCanonical'] ?? true) === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && ($emailMetadata['emailIsCanonical'] ?? true) === false) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && ($emailMetadata['emailIsFree'] ?? false)) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && ($emailMetadata['emailIsFree'] ?? false)) {
|
||||
throw new Exception(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
use Appwrite\Auth\Key;
|
||||
use Appwrite\Auth\MFA\Type\TOTP;
|
||||
use Appwrite\Bus\Events\RequestCompleted;
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Context\Audit as AuditContext;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
@@ -20,6 +19,8 @@ use Appwrite\Event\Webhook;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Extend\Exception as AppwriteException;
|
||||
use Appwrite\Functions\EventProcessor;
|
||||
use Appwrite\Platform\Modules\Storage\Config\CacheControl;
|
||||
use Appwrite\Platform\Modules\Storage\Config\StorageCacheControl;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\Usage\Context;
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
@@ -489,7 +490,6 @@ Http::init()
|
||||
->inject('auditContext')
|
||||
->inject('queueForDeletes')
|
||||
->inject('queueForDatabase')
|
||||
->inject('queueForBuilds')
|
||||
->inject('usage')
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForMails')
|
||||
@@ -503,7 +503,8 @@ Http::init()
|
||||
->inject('telemetry')
|
||||
->inject('platform')
|
||||
->inject('authorization')
|
||||
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, Messaging $queueForMessaging, AuditContext $auditContext, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Context $usage, Func $queueForFunctions, Mail $queueForMails, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform, Authorization $authorization) {
|
||||
->inject('cacheControlForStorage')
|
||||
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, Messaging $queueForMessaging, AuditContext $auditContext, Delete $queueForDeletes, EventDatabase $queueForDatabase, Context $usage, Func $queueForFunctions, Mail $queueForMails, Database $dbForProject, callable $timelimit, Document $resourceToken, string $mode, ?Key $apiKey, array $plan, Document $devKey, Telemetry $telemetry, array $platform, Authorization $authorization, callable $cacheControlForStorage) {
|
||||
|
||||
$response->setUser($user);
|
||||
$request->setUser($user);
|
||||
@@ -618,12 +619,10 @@ Http::init()
|
||||
$queueForDatabase->setProject($project);
|
||||
$queueForMessaging->setProject($project);
|
||||
$queueForFunctions->setProject($project);
|
||||
$queueForBuilds->setProject($project);
|
||||
$queueForMails->setProject($project);
|
||||
|
||||
/* Auto-set platforms */
|
||||
$queueForFunctions->setPlatform($platform);
|
||||
$queueForBuilds->setPlatform($platform);
|
||||
$queueForMails->setPlatform($platform);
|
||||
|
||||
$useCache = $route->getLabel('cache', false);
|
||||
@@ -643,6 +642,7 @@ Http::init()
|
||||
$data = $cache->load($key, $timestamp);
|
||||
|
||||
if (! empty($data) && ! $cacheLog->isEmpty()) {
|
||||
$cacheControl = \sprintf('private, max-age=%d', $timestamp);
|
||||
$parts = explode('/', $cacheLog->getAttribute('resourceType', ''));
|
||||
$type = $parts[0];
|
||||
|
||||
@@ -695,6 +695,21 @@ Http::init()
|
||||
])));
|
||||
}
|
||||
}
|
||||
|
||||
if ($isImageTransformation) {
|
||||
$cacheControl = $cacheControlForStorage(new StorageCacheControl(
|
||||
source: CacheControl::SOURCE_CACHE,
|
||||
user: $user,
|
||||
maxAge: $timestamp,
|
||||
project: $project,
|
||||
bucket: $bucket,
|
||||
file: $file,
|
||||
resourceToken: $resourceToken,
|
||||
fileSecurity: $fileSecurity,
|
||||
cacheLog: $cacheLog,
|
||||
route: $route,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
$accessedAt = $cacheLog->getAttribute('accessedAt', '');
|
||||
@@ -707,7 +722,7 @@ Http::init()
|
||||
}
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', sprintf('private, max-age=%d', $timestamp))
|
||||
->addHeader('Cache-Control', $cacheControl)
|
||||
->addHeader('X-Appwrite-Cache', 'hit')
|
||||
->setContentType($cacheLog->getAttribute('mimeType'));
|
||||
$storageCacheOperationsCounter->add(1, ['result' => 'hit']);
|
||||
@@ -800,7 +815,6 @@ Http::shutdown()
|
||||
->inject('publisherForUsage')
|
||||
->inject('queueForDeletes')
|
||||
->inject('queueForDatabase')
|
||||
->inject('queueForBuilds')
|
||||
->inject('queueForMessaging')
|
||||
->inject('queueForFunctions')
|
||||
->inject('queueForWebhooks')
|
||||
@@ -812,7 +826,7 @@ Http::shutdown()
|
||||
->inject('bus')
|
||||
->inject('apiKey')
|
||||
->inject('mode')
|
||||
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Audit $publisherForAudits, Context $usage, UsagePublisher $publisherForUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Build $queueForBuilds, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization, callable $timelimit, EventProcessor $eventProcessor, Bus $bus, ?Key $apiKey, string $mode) use ($parseLabel) {
|
||||
->action(function (Http $utopia, Request $request, Response $response, Document $project, User $user, Event $queueForEvents, AuditContext $auditContext, Audit $publisherForAudits, Context $usage, UsagePublisher $publisherForUsage, Delete $queueForDeletes, EventDatabase $queueForDatabase, Messaging $queueForMessaging, Func $queueForFunctions, Event $queueForWebhooks, Realtime $queueForRealtime, Database $dbForProject, Authorization $authorization, callable $timelimit, EventProcessor $eventProcessor, Bus $bus, ?Key $apiKey, string $mode) use ($parseLabel) {
|
||||
|
||||
$responsePayload = $response->getPayload();
|
||||
|
||||
@@ -961,10 +975,6 @@ Http::shutdown()
|
||||
$queueForDatabase->trigger();
|
||||
}
|
||||
|
||||
if (! empty($queueForBuilds->getType())) {
|
||||
$queueForBuilds->trigger();
|
||||
}
|
||||
|
||||
if (! empty($queueForMessaging->getType())) {
|
||||
$queueForMessaging->trigger();
|
||||
}
|
||||
|
||||
@@ -2,12 +2,14 @@
|
||||
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Publisher\Audit as AuditPublisher;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Event\Publisher\Certificate as CertificatePublisher;
|
||||
use Appwrite\Event\Publisher\Execution as ExecutionPublisher;
|
||||
use Appwrite\Event\Publisher\Migration as MigrationPublisher;
|
||||
use Appwrite\Event\Publisher\Screenshot as ScreenshotPublisher;
|
||||
use Appwrite\Event\Publisher\StatsResources as StatsResourcesPublisher;
|
||||
use Appwrite\Event\Publisher\Usage as UsagePublisher;
|
||||
use Appwrite\Platform\Modules\Storage\Config\StorageCacheControl;
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
use Executor\Executor;
|
||||
use Utopia\Abuse\Adapters\TimeLimit\Redis as TimeLimitRedis;
|
||||
@@ -112,6 +114,10 @@ $container->set('publisherForStatsResources', fn (Publisher $publisher) => new S
|
||||
$publisher,
|
||||
new Queue(System::getEnv('_APP_STATS_RESOURCES_QUEUE_NAME', Event::STATS_RESOURCES_QUEUE_NAME))
|
||||
), ['publisher']);
|
||||
$container->set('publisherForBuilds', fn (Publisher $publisher) => new BuildPublisher(
|
||||
$publisher,
|
||||
new Queue(System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME))
|
||||
), ['publisher']);
|
||||
|
||||
/**
|
||||
* Platform configuration
|
||||
@@ -198,6 +204,10 @@ $container->set('cache', function (Group $pools, Telemetry $telemetry) {
|
||||
return $cache;
|
||||
}, ['pools', 'telemetry']);
|
||||
|
||||
$container->set('cacheControlForStorage', fn () => function (StorageCacheControl $config): string {
|
||||
return \sprintf('private, max-age=%d', $config->maxAge);
|
||||
});
|
||||
|
||||
$container->set('redis', function () {
|
||||
$host = System::getEnv('_APP_REDIS_HOST', 'localhost');
|
||||
$port = System::getEnv('_APP_REDIS_PORT', 6379);
|
||||
|
||||
@@ -4,7 +4,6 @@ use Ahc\Jwt\JWT;
|
||||
use Ahc\Jwt\JWTException;
|
||||
use Appwrite\Auth\Key;
|
||||
use Appwrite\Databases\TransactionState;
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Context\Audit as AuditContext;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
@@ -123,9 +122,6 @@ return function (Container $container): void {
|
||||
$container->set('queueForMails', function (Publisher $publisher) {
|
||||
return new Mail($publisher);
|
||||
}, ['publisher']);
|
||||
$container->set('queueForBuilds', function (Publisher $publisher) {
|
||||
return new Build($publisher);
|
||||
}, ['publisher']);
|
||||
$container->set('queueForDatabase', function (Publisher $publisher) {
|
||||
return new EventDatabase($publisher);
|
||||
}, ['publisher']);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
<?php
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Database as EventDatabase;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
@@ -342,10 +341,6 @@ return function (Container $container): void {
|
||||
return new Mail($publisher);
|
||||
}, ['publisher']);
|
||||
|
||||
$container->set('queueForBuilds', function (Publisher $publisher) {
|
||||
return new Build($publisher);
|
||||
}, ['publisher']);
|
||||
|
||||
$container->set('queueForDeletes', function (Publisher $publisher) {
|
||||
return new Delete($publisher);
|
||||
}, ['publisher']);
|
||||
|
||||
@@ -881,6 +881,13 @@ $hostPath = rtrim($this->getParam('hostPath', ''), '/');
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_DOMAIN
|
||||
- _APP_CONSOLE_DOMAIN
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_MIGRATION_HOST
|
||||
- _APP_CONSOLE_SCHEMA
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
@@ -909,6 +916,13 @@ $hostPath = rtrim($this->getParam('hostPath', ''), '/');
|
||||
- _APP_ENV
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_DOMAIN
|
||||
- _APP_CONSOLE_DOMAIN
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_MIGRATION_HOST
|
||||
- _APP_CONSOLE_SCHEMA
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
|
||||
+2
-2
@@ -68,11 +68,11 @@
|
||||
"utopia-php/dns": "1.6.*",
|
||||
"utopia-php/dsn": "0.2.1",
|
||||
"utopia-php/http": "0.34.*",
|
||||
"utopia-php/fetch": "0.5.*",
|
||||
"utopia-php/fetch": "^1.1",
|
||||
"utopia-php/validators": "0.2.*",
|
||||
"utopia-php/image": "0.8.*",
|
||||
"utopia-php/locale": "0.8.*",
|
||||
"utopia-php/logger": "0.6.*",
|
||||
"utopia-php/logger": "0.8.*",
|
||||
"utopia-php/messaging": "0.22.*",
|
||||
"utopia-php/migration": "1.*",
|
||||
"utopia-php/platform": "0.13.*",
|
||||
|
||||
Generated
+87
-77
@@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "ec2ad489c60f0102f0dfab223b6d1fe4",
|
||||
"content-hash": "4ef65b015dba97e91f6571b061787653",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adhocore/jwt",
|
||||
@@ -2641,16 +2641,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/deprecation-contracts",
|
||||
"version": "v3.6.0",
|
||||
"version": "v3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/deprecation-contracts.git",
|
||||
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62"
|
||||
"reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||
"reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62",
|
||||
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/50f59d1f3ca46d41ac911f97a78626b6756af35b",
|
||||
"reference": "50f59d1f3ca46d41ac911f97a78626b6756af35b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2663,7 +2663,7 @@
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
"dev-main": "3.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2688,7 +2688,7 @@
|
||||
"description": "A generic function and convention to trigger deprecation notices",
|
||||
"homepage": "https://symfony.com",
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0"
|
||||
"source": "https://github.com/symfony/deprecation-contracts/tree/v3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2699,12 +2699,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-09-25T14:21:43+00:00"
|
||||
"time": "2026-04-13T15:52:40+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client",
|
||||
@@ -2809,16 +2813,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/http-client-contracts",
|
||||
"version": "v3.6.0",
|
||||
"version": "v3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/http-client-contracts.git",
|
||||
"reference": "75d7043853a42837e68111812f4d964b01e5101c"
|
||||
"reference": "4a2d00c37651c0bdc2b9e1c773487a8bf4edb12d"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/75d7043853a42837e68111812f4d964b01e5101c",
|
||||
"reference": "75d7043853a42837e68111812f4d964b01e5101c",
|
||||
"url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/4a2d00c37651c0bdc2b9e1c773487a8bf4edb12d",
|
||||
"reference": "4a2d00c37651c0bdc2b9e1c773487a8bf4edb12d",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -2831,7 +2835,7 @@
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
"dev-main": "3.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -2867,7 +2871,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/http-client-contracts/tree/v3.6.0"
|
||||
"source": "https://github.com/symfony/http-client-contracts/tree/v3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -2878,12 +2882,16 @@
|
||||
"url": "https://github.com/fabpot",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/nicolas-grekas",
|
||||
"type": "github"
|
||||
},
|
||||
{
|
||||
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-04-29T11:18:49+00:00"
|
||||
"time": "2026-03-06T13:17:50+00:00"
|
||||
},
|
||||
{
|
||||
"name": "symfony/polyfill-mbstring",
|
||||
@@ -3212,16 +3220,16 @@
|
||||
},
|
||||
{
|
||||
"name": "symfony/service-contracts",
|
||||
"version": "v3.6.1",
|
||||
"version": "v3.7.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/service-contracts.git",
|
||||
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43"
|
||||
"reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/45112560a3ba2d715666a509a0bc9521d10b6c43",
|
||||
"reference": "45112560a3ba2d715666a509a0bc9521d10b6c43",
|
||||
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/d25d82433a80eba6aa0e6c24b61d7370d99e444a",
|
||||
"reference": "d25d82433a80eba6aa0e6c24b61d7370d99e444a",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -3239,7 +3247,7 @@
|
||||
"name": "symfony/contracts"
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.6-dev"
|
||||
"dev-main": "3.7-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@@ -3275,7 +3283,7 @@
|
||||
"standards"
|
||||
],
|
||||
"support": {
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.6.1"
|
||||
"source": "https://github.com/symfony/service-contracts/tree/v3.7.0"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@@ -3295,7 +3303,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2025-07-15T11:30:57+00:00"
|
||||
"time": "2026-03-28T09:44:51+00:00"
|
||||
},
|
||||
{
|
||||
"name": "tbachert/spi",
|
||||
@@ -3403,21 +3411,21 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/agents",
|
||||
"version": "1.2.1",
|
||||
"version": "1.2.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/agents.git",
|
||||
"reference": "052227953678a30ecc4b5467401fcb0b2386471e"
|
||||
"reference": "0703f4cae02261e09a1bf0d39a4b1ce649cae634"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/agents/zipball/052227953678a30ecc4b5467401fcb0b2386471e",
|
||||
"reference": "052227953678a30ecc4b5467401fcb0b2386471e",
|
||||
"url": "https://api.github.com/repos/utopia-php/agents/zipball/0703f4cae02261e09a1bf0d39a4b1ce649cae634",
|
||||
"reference": "0703f4cae02261e09a1bf0d39a4b1ce649cae634",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.3",
|
||||
"utopia-php/fetch": "0.5.*"
|
||||
"utopia-php/fetch": "^1.1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.18",
|
||||
@@ -3450,9 +3458,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/agents/issues",
|
||||
"source": "https://github.com/utopia-php/agents/tree/1.2.1"
|
||||
"source": "https://github.com/utopia-php/agents/tree/1.2.2"
|
||||
},
|
||||
"time": "2026-02-24T06:03:55+00:00"
|
||||
"time": "2026-05-08T10:38:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/analytics",
|
||||
@@ -3502,22 +3510,22 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/audit",
|
||||
"version": "2.2.2",
|
||||
"version": "2.2.3",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/audit.git",
|
||||
"reference": "90886c202e7983999e6b6a8201004d5ab61d4b57"
|
||||
"reference": "95e9961fa286d2fdb6bf3eaa198f21d51bf58d9c"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/90886c202e7983999e6b6a8201004d5ab61d4b57",
|
||||
"reference": "90886c202e7983999e6b6a8201004d5ab61d4b57",
|
||||
"url": "https://api.github.com/repos/utopia-php/audit/zipball/95e9961fa286d2fdb6bf3eaa198f21d51bf58d9c",
|
||||
"reference": "95e9961fa286d2fdb6bf3eaa198f21d51bf58d9c",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/database": "5.*",
|
||||
"utopia-php/fetch": "0.5.*",
|
||||
"utopia-php/fetch": "^1.1",
|
||||
"utopia-php/validators": "0.2.*"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -3545,9 +3553,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/audit/issues",
|
||||
"source": "https://github.com/utopia-php/audit/tree/2.2.2"
|
||||
"source": "https://github.com/utopia-php/audit/tree/2.2.3"
|
||||
},
|
||||
"time": "2026-05-04T06:48:58+00:00"
|
||||
"time": "2026-05-08T10:38:23+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/auth",
|
||||
@@ -4172,22 +4180,21 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/emails",
|
||||
"version": "0.6.9",
|
||||
"version": "0.6.10",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/emails.git",
|
||||
"reference": "3a59fb392a03a88f5497e5fdb0ea84a252a4dfdf"
|
||||
"reference": "2e397754ce68c2ba918564b9f31d9923c0a90429"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/emails/zipball/3a59fb392a03a88f5497e5fdb0ea84a252a4dfdf",
|
||||
"reference": "3a59fb392a03a88f5497e5fdb0ea84a252a4dfdf",
|
||||
"url": "https://api.github.com/repos/utopia-php/emails/zipball/2e397754ce68c2ba918564b9f31d9923c0a90429",
|
||||
"reference": "2e397754ce68c2ba918564b9f31d9923c0a90429",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0",
|
||||
"utopia-php/domains": "^1.0",
|
||||
"utopia-php/fetch": "^0.5",
|
||||
"utopia-php/validators": "0.*"
|
||||
},
|
||||
"require-dev": {
|
||||
@@ -4195,7 +4202,8 @@
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.3",
|
||||
"utopia-php/cli": "^0.22",
|
||||
"utopia-php/console": "0.*"
|
||||
"utopia-php/console": "0.*",
|
||||
"utopia-php/fetch": "^1.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -4227,22 +4235,22 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/emails/issues",
|
||||
"source": "https://github.com/utopia-php/emails/tree/0.6.9"
|
||||
"source": "https://github.com/utopia-php/emails/tree/0.6.10"
|
||||
},
|
||||
"time": "2026-03-14T13:52:56+00:00"
|
||||
"time": "2026-05-08T10:16:22+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/fetch",
|
||||
"version": "0.5.1",
|
||||
"version": "1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/fetch.git",
|
||||
"reference": "a96a010e1c273f3888765449687baf58cbc61fcd"
|
||||
"reference": "64f2b3a789480f1deb102ce684dac4217d8e98d5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/fetch/zipball/a96a010e1c273f3888765449687baf58cbc61fcd",
|
||||
"reference": "a96a010e1c273f3888765449687baf58cbc61fcd",
|
||||
"url": "https://api.github.com/repos/utopia-php/fetch/zipball/64f2b3a789480f1deb102ce684dac4217d8e98d5",
|
||||
"reference": "64f2b3a789480f1deb102ce684dac4217d8e98d5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4251,7 +4259,8 @@
|
||||
"require-dev": {
|
||||
"laravel/pint": "^1.5.0",
|
||||
"phpstan/phpstan": "^1.10",
|
||||
"phpunit/phpunit": "^9.5"
|
||||
"phpunit/phpunit": "^9.5",
|
||||
"swoole/ide-helper": "^6.0"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@@ -4266,9 +4275,9 @@
|
||||
"description": "A simple library that provides an interface for making HTTP Requests.",
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/fetch/issues",
|
||||
"source": "https://github.com/utopia-php/fetch/tree/0.5.1"
|
||||
"source": "https://github.com/utopia-php/fetch/tree/1.1.2"
|
||||
},
|
||||
"time": "2025-12-18T16:25:10+00:00"
|
||||
"time": "2026-04-29T11:19:19+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/http",
|
||||
@@ -4426,20 +4435,21 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/logger",
|
||||
"version": "0.6.2",
|
||||
"version": "0.8.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/logger.git",
|
||||
"reference": "25b5bd2ad8bb51292f76332faa7034644fd0941d"
|
||||
"reference": "132236c42222cd614cb882938a48f8729ef3118b"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/logger/zipball/25b5bd2ad8bb51292f76332faa7034644fd0941d",
|
||||
"reference": "25b5bd2ad8bb51292f76332faa7034644fd0941d",
|
||||
"url": "https://api.github.com/repos/utopia-php/logger/zipball/132236c42222cd614cb882938a48f8729ef3118b",
|
||||
"reference": "132236c42222cd614cb882938a48f8729ef3118b",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=8.0"
|
||||
"php": ">=8.1",
|
||||
"utopia-php/fetch": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.2.*",
|
||||
@@ -4474,9 +4484,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/logger/issues",
|
||||
"source": "https://github.com/utopia-php/logger/tree/0.6.2"
|
||||
"source": "https://github.com/utopia-php/logger/tree/0.8.0"
|
||||
},
|
||||
"time": "2024-10-14T16:02:49+00:00"
|
||||
"time": "2026-05-05T06:04:27+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/messaging",
|
||||
@@ -4531,16 +4541,16 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/migration",
|
||||
"version": "1.10.0",
|
||||
"version": "1.10.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/migration.git",
|
||||
"reference": "55f4863d690e775f44fec3cae4bd1f4491fed5ea"
|
||||
"reference": "211d01b90ccab9729029151c6c61f543bd755c2e"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/55f4863d690e775f44fec3cae4bd1f4491fed5ea",
|
||||
"reference": "55f4863d690e775f44fec3cae4bd1f4491fed5ea",
|
||||
"url": "https://api.github.com/repos/utopia-php/migration/zipball/211d01b90ccab9729029151c6c61f543bd755c2e",
|
||||
"reference": "211d01b90ccab9729029151c6c61f543bd755c2e",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -4580,9 +4590,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/migration/issues",
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.10.0"
|
||||
"source": "https://github.com/utopia-php/migration/tree/1.10.2"
|
||||
},
|
||||
"time": "2026-05-06T04:35:32+00:00"
|
||||
"time": "2026-05-08T06:25:47+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/mongo",
|
||||
@@ -5228,23 +5238,23 @@
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/vcs",
|
||||
"version": "3.2.0",
|
||||
"version": "3.2.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/utopia-php/vcs.git",
|
||||
"reference": "44a84ab52b42fc12f812b4d7331286b519d39db3"
|
||||
"reference": "03ccd12b75d67d29094eb760b468fddde4b6b5e5"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/44a84ab52b42fc12f812b4d7331286b519d39db3",
|
||||
"reference": "44a84ab52b42fc12f812b4d7331286b519d39db3",
|
||||
"url": "https://api.github.com/repos/utopia-php/vcs/zipball/03ccd12b75d67d29094eb760b468fddde4b6b5e5",
|
||||
"reference": "03ccd12b75d67d29094eb760b468fddde4b6b5e5",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"adhocore/jwt": "^1.1",
|
||||
"php": ">=8.0",
|
||||
"utopia-php/cache": "1.0.*",
|
||||
"utopia-php/fetch": "0.5.*"
|
||||
"utopia-php/fetch": "^1.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"laravel/pint": "1.*.*",
|
||||
@@ -5271,9 +5281,9 @@
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/utopia-php/vcs/issues",
|
||||
"source": "https://github.com/utopia-php/vcs/tree/3.2.0"
|
||||
"source": "https://github.com/utopia-php/vcs/tree/3.2.1"
|
||||
},
|
||||
"time": "2026-04-08T16:00:31+00:00"
|
||||
"time": "2026-05-08T10:13:53+00:00"
|
||||
},
|
||||
{
|
||||
"name": "utopia-php/websocket",
|
||||
@@ -5466,16 +5476,16 @@
|
||||
"packages-dev": [
|
||||
{
|
||||
"name": "appwrite/sdk-generator",
|
||||
"version": "1.27.5",
|
||||
"version": "1.28.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/appwrite/sdk-generator.git",
|
||||
"reference": "9faa38b48d422f3da764a719712905c83b3922cb"
|
||||
"reference": "e363fffd220172c5f1a5032038fa3fdafeeb2dfb"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/9faa38b48d422f3da764a719712905c83b3922cb",
|
||||
"reference": "9faa38b48d422f3da764a719712905c83b3922cb",
|
||||
"url": "https://api.github.com/repos/appwrite/sdk-generator/zipball/e363fffd220172c5f1a5032038fa3fdafeeb2dfb",
|
||||
"reference": "e363fffd220172c5f1a5032038fa3fdafeeb2dfb",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@@ -5511,9 +5521,9 @@
|
||||
"description": "Appwrite PHP library for generating API SDKs for multiple programming languages and platforms",
|
||||
"support": {
|
||||
"issues": "https://github.com/appwrite/sdk-generator/issues",
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.27.5"
|
||||
"source": "https://github.com/appwrite/sdk-generator/tree/1.28.0"
|
||||
},
|
||||
"time": "2026-05-05T12:09:40+00:00"
|
||||
"time": "2026-05-08T03:37:44+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brianium/paratest",
|
||||
|
||||
+15
-1
@@ -1114,6 +1114,13 @@ services:
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_POOL_ADAPTER
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_DOMAIN
|
||||
- _APP_CONSOLE_DOMAIN
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_MIGRATION_HOST
|
||||
- _APP_CONSOLE_SCHEMA
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
@@ -1145,6 +1152,13 @@ services:
|
||||
- _APP_WORKER_PER_CORE
|
||||
- _APP_POOL_ADAPTER
|
||||
- _APP_OPENSSL_KEY_V1
|
||||
- _APP_OPTIONS_FORCE_HTTPS
|
||||
- _APP_DOMAIN
|
||||
- _APP_CONSOLE_DOMAIN
|
||||
- _APP_DOMAIN_FUNCTIONS
|
||||
- _APP_DOMAIN_SITES
|
||||
- _APP_MIGRATION_HOST
|
||||
- _APP_CONSOLE_SCHEMA
|
||||
- _APP_REDIS_HOST
|
||||
- _APP_REDIS_PORT
|
||||
- _APP_REDIS_USER
|
||||
@@ -1478,4 +1492,4 @@ volumes:
|
||||
appwrite-sites:
|
||||
appwrite-builds:
|
||||
appwrite-config:
|
||||
appwrite-models:
|
||||
appwrite-models:
|
||||
|
||||
@@ -1 +1 @@
|
||||
Get a list of all branches from a GitHub repository in your installation. This endpoint returns the names of all branches in the repository and their total count. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work.
|
||||
Get a list of branches from a GitHub repository in your installation. This endpoint supports filtering by a search term and pagination using query strings such as `Query.limit()`, `Query.offset()`, `Query.cursorAfter()`, and `Query.cursorBefore()`. It returns branch names along with the total number of matches. The GitHub installation must be properly configured and have access to the requested repository for this endpoint to work.
|
||||
|
||||
@@ -72,7 +72,7 @@ class Google extends OAuth2
|
||||
'https://oauth2.googleapis.com/token?' . \http_build_query([
|
||||
'code' => $code,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'redirect_uri' => $this->callback,
|
||||
'scope' => null,
|
||||
'grant_type' => 'authorization_code'
|
||||
@@ -95,7 +95,7 @@ class Google extends OAuth2
|
||||
'https://oauth2.googleapis.com/token?' . \http_build_query([
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $this->appID,
|
||||
'client_secret' => $this->appSecret,
|
||||
'client_secret' => $this->getClientSecret(),
|
||||
'grant_type' => 'refresh_token'
|
||||
])
|
||||
), true);
|
||||
@@ -177,4 +177,37 @@ class Google extends OAuth2
|
||||
|
||||
return $this->user;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extracts the Client Secret from the JSON stored in appSecret
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function getClientSecret(): string
|
||||
{
|
||||
$secret = $this->getAppSecret();
|
||||
|
||||
return $secret['clientSecret'] ?? $this->appSecret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the JSON stored in appSecret.
|
||||
* Falls back to treating the raw string as the client secret for backwards compatibility.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getAppSecret(): array
|
||||
{
|
||||
try {
|
||||
$secret = \json_decode($this->appSecret, true, 512, JSON_THROW_ON_ERROR);
|
||||
} catch (\Throwable $th) {
|
||||
return ['clientSecret' => $this->appSecret];
|
||||
}
|
||||
|
||||
if (!\is_array($secret)) {
|
||||
return ['clientSecret' => $this->appSecret];
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Event;
|
||||
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\System\System;
|
||||
|
||||
class Build extends Event
|
||||
{
|
||||
protected string $type = '';
|
||||
protected ?Document $resource = null;
|
||||
protected ?Document $deployment = null;
|
||||
protected ?Document $template = null;
|
||||
|
||||
public function __construct(protected Publisher $publisher)
|
||||
{
|
||||
parent::__construct($publisher);
|
||||
|
||||
$this
|
||||
->setQueue(System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME))
|
||||
->setClass(System::getEnv('_APP_BUILDS_CLASS_NAME', Event::BUILDS_CLASS_NAME));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets template for the build event.
|
||||
*
|
||||
* @param Document $template
|
||||
* @return self
|
||||
*/
|
||||
public function setTemplate(Document $template): self
|
||||
{
|
||||
$this->template = $template;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets resource document for the build event.
|
||||
*
|
||||
* @param Document $resource
|
||||
* @return self
|
||||
*/
|
||||
public function setResource(Document $resource): self
|
||||
{
|
||||
$this->resource = $resource;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns set resource document for the build event.
|
||||
*
|
||||
* @return null|Document
|
||||
*/
|
||||
public function getResource(): ?Document
|
||||
{
|
||||
return $this->resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets deployment for the build event.
|
||||
*
|
||||
* @param Document $deployment
|
||||
* @return self
|
||||
*/
|
||||
public function setDeployment(Document $deployment): self
|
||||
{
|
||||
$this->deployment = $deployment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns set deployment for the build event.
|
||||
*
|
||||
* @return null|Document
|
||||
*/
|
||||
public function getDeployment(): ?Document
|
||||
{
|
||||
return $this->deployment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets type for the build event.
|
||||
*
|
||||
* @param string $type Can be `BUILD_TYPE_DEPLOYMENT` or `BUILD_TYPE_RETRY`.
|
||||
* @return self
|
||||
*/
|
||||
public function setType(string $type): self
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns set type for the function event.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getType(): string
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare payload for queue.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function preparePayload(): array
|
||||
{
|
||||
$platform = $this->platform;
|
||||
if (empty($platform)) {
|
||||
$platform = Config::getParam('platform', []);
|
||||
}
|
||||
|
||||
return [
|
||||
'project' => $this->project,
|
||||
'resource' => $this->resource,
|
||||
'deployment' => $this->deployment,
|
||||
'type' => $this->type,
|
||||
'template' => $this->template,
|
||||
'platform' => $platform,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets event.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public function reset(): self
|
||||
{
|
||||
$this->type = '';
|
||||
$this->resource = null;
|
||||
$this->deployment = null;
|
||||
$this->template = null;
|
||||
$this->platform = [];
|
||||
parent::reset();
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Event\Message;
|
||||
|
||||
use Utopia\Config\Config;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
final class Build extends Base
|
||||
{
|
||||
public function __construct(
|
||||
public readonly Document $project,
|
||||
public readonly Document $resource,
|
||||
public readonly Document $deployment,
|
||||
public readonly string $type,
|
||||
public readonly ?Document $template = null,
|
||||
public readonly array $platform = [],
|
||||
) {
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$platform = !empty($this->platform) ? $this->platform : Config::getParam('platform', []);
|
||||
|
||||
return [
|
||||
'project' => $this->project->getArrayCopy(),
|
||||
'resource' => $this->resource->getArrayCopy(),
|
||||
'deployment' => $this->deployment->getArrayCopy(),
|
||||
'type' => $this->type,
|
||||
'template' => $this->template?->getArrayCopy(),
|
||||
'platform' => $platform,
|
||||
];
|
||||
}
|
||||
|
||||
public static function fromArray(array $data): static
|
||||
{
|
||||
return new self(
|
||||
project: new Document($data['project'] ?? []),
|
||||
resource: new Document($data['resource'] ?? []),
|
||||
deployment: new Document($data['deployment'] ?? []),
|
||||
type: $data['type'] ?? '',
|
||||
template: !empty($data['template']) ? new Document($data['template']) : null,
|
||||
platform: $data['platform'] ?? [],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Event\Publisher;
|
||||
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Utopia\Queue\Publisher;
|
||||
use Utopia\Queue\Queue;
|
||||
|
||||
readonly class Build extends Base
|
||||
{
|
||||
public function __construct(
|
||||
Publisher $publisher,
|
||||
protected Queue $queue
|
||||
) {
|
||||
parent::__construct($publisher);
|
||||
}
|
||||
|
||||
public function enqueue(BuildMessage $message, ?Queue $queue = null): string|bool
|
||||
{
|
||||
return $this->publish($queue ?? $this->queue, $message);
|
||||
}
|
||||
|
||||
public function getSize(bool $failed = false, ?Queue $queue = null): int
|
||||
{
|
||||
return $this->getQueueSize($queue ?? $this->queue, $failed);
|
||||
}
|
||||
}
|
||||
@@ -348,6 +348,10 @@ class Exception extends \Exception
|
||||
public const string MIGRATION_IN_PROGRESS = 'migration_in_progress';
|
||||
public const string MIGRATION_PROVIDER_ERROR = 'migration_provider_error';
|
||||
public const string MIGRATION_DATABASE_TYPE_UNSUPPORTED = 'migration_database_type_unsupported';
|
||||
public const string MIGRATION_SOURCE_PROJECT_ID_REQUIRED = 'migration_source_project_id_required';
|
||||
public const string MIGRATION_SOURCE_PROJECT_NOT_FOUND = 'migration_source_project_not_found';
|
||||
public const string MIGRATION_SOURCE_TYPE_INVALID = 'migration_source_type_invalid';
|
||||
public const string MIGRATION_DESTINATION_TYPE_INVALID = 'migration_destination_type_invalid';
|
||||
|
||||
/** Realtime */
|
||||
public const string REALTIME_MESSAGE_FORMAT_INVALID = 'realtime_message_format_invalid';
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Compute;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Filter\BranchDomain as BranchDomainFilter;
|
||||
use Appwrite\Platform\Action;
|
||||
@@ -57,7 +58,7 @@ class Base extends Action
|
||||
return $allowedSpecifications[0] ?? APP_COMPUTE_SPECIFICATION_DEFAULT;
|
||||
}
|
||||
|
||||
public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, string $referenceType = 'branch', string $reference = ''): Document
|
||||
public function redeployVcsFunction(Request $request, Document $function, Document $project, Document $installation, Database $dbForProject, BuildPublisher $publisherForBuilds, Document $template, GitHub $github, bool $activate, array $platform = [], string $referenceType = 'branch', string $reference = ''): Document
|
||||
{
|
||||
$deploymentId = ID::unique();
|
||||
$entrypoint = $function->getAttribute('entrypoint', '');
|
||||
@@ -150,16 +151,19 @@ class Base extends Action
|
||||
'latestDeploymentStatus' => $deployment->getAttribute('status', ''),
|
||||
]));
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setTemplate($template);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $function,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
template: $template,
|
||||
platform: $platform,
|
||||
));
|
||||
|
||||
return $deployment;
|
||||
}
|
||||
|
||||
public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, Build $queueForBuilds, Document $template, GitHub $github, bool $activate, Authorization $authorization, array $platform, string $referenceType = 'branch', string $reference = ''): Document
|
||||
public function redeployVcsSite(Request $request, Document $site, Document $project, Document $installation, Database $dbForProject, Database $dbForPlatform, BuildPublisher $publisherForBuilds, Document $template, GitHub $github, bool $activate, Authorization $authorization, array $platform, string $referenceType = 'branch', string $reference = ''): Document
|
||||
{
|
||||
$deploymentId = ID::unique();
|
||||
$providerInstallationId = $installation->getAttribute('providerInstallationId', '');
|
||||
@@ -358,11 +362,14 @@ class Base extends Action
|
||||
|
||||
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform, $authorization);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($site)
|
||||
->setDeployment($deployment)
|
||||
->setTemplate($template);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $site,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
template: $template,
|
||||
platform: $platform,
|
||||
));
|
||||
|
||||
return $deployment;
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Functions\Http\Deployments;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
@@ -87,9 +88,10 @@ class Create extends Action
|
||||
->inject('project')
|
||||
->inject('deviceForFunctions')
|
||||
->inject('deviceForLocal')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('plan')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -106,9 +108,10 @@ class Create extends Action
|
||||
Document $project,
|
||||
Device $deviceForFunctions,
|
||||
Device $deviceForLocal,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
array $plan,
|
||||
Authorization $authorization
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
) {
|
||||
$activate = \strval($activate) === 'true' || \strval($activate) === '1';
|
||||
|
||||
@@ -272,10 +275,13 @@ class Create extends Action
|
||||
}
|
||||
|
||||
// Start the build
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $function,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
platform: $platform,
|
||||
));
|
||||
} else {
|
||||
if ($deployment->isEmpty()) {
|
||||
$deployment = $dbForProject->createDocument('deployments', new Document([
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Duplicate;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
@@ -61,8 +62,10 @@ class Create extends Action
|
||||
->inject('response')
|
||||
->inject('dbForProject')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('deviceForFunctions')
|
||||
->inject('project')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -73,8 +76,10 @@ class Create extends Action
|
||||
Response $response,
|
||||
Database $dbForProject,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
Device $deviceForFunctions
|
||||
BuildPublisher $publisherForBuilds,
|
||||
Device $deviceForFunctions,
|
||||
Document $project,
|
||||
array $platform
|
||||
) {
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
@@ -127,10 +132,13 @@ class Create extends Action
|
||||
'latestDeploymentStatus' => $function->getAttribute('latestDeploymentStatus'),
|
||||
]));
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $function,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
platform: $platform,
|
||||
));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('functionId', $function->getId())
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Template;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
@@ -76,9 +77,10 @@ class Create extends Base
|
||||
->inject('dbForPlatform')
|
||||
->inject('queueForEvents')
|
||||
->inject('project')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('gitHub')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -96,9 +98,10 @@ class Create extends Base
|
||||
Database $dbForPlatform,
|
||||
Event $queueForEvents,
|
||||
Document $project,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
GitHub $github,
|
||||
Authorization $authorization
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
) {
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
@@ -127,10 +130,11 @@ class Create extends Base
|
||||
project: $project,
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
publisherForBuilds: $publisherForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
activate: $activate,
|
||||
platform: $platform,
|
||||
referenceType: $type,
|
||||
reference: $reference
|
||||
);
|
||||
@@ -184,11 +188,14 @@ class Create extends Base
|
||||
|
||||
$this->updateEmptyManualRule($project, $function, $deployment, $dbForPlatform, $authorization);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setTemplate($template);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $function,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
template: $template,
|
||||
platform: $platform,
|
||||
));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('functionId', $function->getId())
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Functions\Http\Deployments\Vcs;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
@@ -70,8 +70,9 @@ class Create extends Base
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('gitHub')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -86,8 +87,9 @@ class Create extends Base
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
GitHub $github,
|
||||
array $platform,
|
||||
) {
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
|
||||
@@ -105,10 +107,11 @@ class Create extends Base
|
||||
project: $project,
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
publisherForBuilds: $publisherForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
activate: $activate,
|
||||
platform: $platform,
|
||||
reference: $reference,
|
||||
referenceType: $type
|
||||
);
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Functions\Http\Functions;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Event\Realtime;
|
||||
use Appwrite\Event\Validator\FunctionEvent;
|
||||
use Appwrite\Event\Webhook;
|
||||
@@ -115,7 +116,7 @@ class Create extends Base
|
||||
->inject('timelimit')
|
||||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('queueForRealtime')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('queueForFunctions')
|
||||
@@ -157,7 +158,7 @@ class Create extends Base
|
||||
callable $timelimit,
|
||||
Document $project,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
Realtime $queueForRealtime,
|
||||
Webhook $queueForWebhooks,
|
||||
Func $queueForFunctions,
|
||||
@@ -326,10 +327,11 @@ class Create extends Base
|
||||
project: $project,
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
publisherForBuilds: $publisherForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
activate: true,
|
||||
platform: $platform,
|
||||
reference: $providerBranch,
|
||||
referenceType: 'branch'
|
||||
);
|
||||
@@ -367,11 +369,14 @@ class Create extends Base
|
||||
'latestDeploymentStatus' => $deployment->getAttribute('status', ''),
|
||||
]));
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($function)
|
||||
->setDeployment($deployment)
|
||||
->setTemplate($template);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $function,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
template: $template,
|
||||
platform: $platform,
|
||||
));
|
||||
}
|
||||
|
||||
$functionsDomain = $platform['functionsDomain'];
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Functions\Http\Functions;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Event\Validator\FunctionEvent;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
@@ -105,11 +105,12 @@ class Update extends Base
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('dbForPlatform')
|
||||
->inject('gitHub')
|
||||
->inject('executor')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -139,11 +140,12 @@ class Update extends Base
|
||||
Database $dbForProject,
|
||||
Document $project,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
Database $dbForPlatform,
|
||||
GitHub $github,
|
||||
Executor $executor,
|
||||
Authorization $authorization
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
) {
|
||||
// TODO: If only branch changes, re-deploy
|
||||
$function = $dbForProject->getDocument('functions', $functionId);
|
||||
@@ -281,7 +283,7 @@ class Update extends Base
|
||||
|
||||
// Redeploy logic
|
||||
if (!$isConnected && !empty($providerRepositoryId)) {
|
||||
$this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $queueForBuilds, new Document(), $github, true);
|
||||
$this->redeployVcsFunction($request, $function, $project, $installation, $dbForProject, $publisherForBuilds, new Document(), $github, true, $platform);
|
||||
}
|
||||
|
||||
// Inform scheduler if function is still active
|
||||
|
||||
@@ -109,9 +109,7 @@ class Screenshots extends Action
|
||||
throw new \Exception("Rule for deployment not found");
|
||||
}
|
||||
|
||||
$client = new FetchClient();
|
||||
$client->setTimeout(\intval($site->getAttribute('timeout', '15')) * 1000);
|
||||
$client->addHeader('content-type', FetchClient::CONTENT_TYPE_APPLICATION_JSON);
|
||||
$timeout = \intval($site->getAttribute('timeout', '15')) * 1000;
|
||||
|
||||
$bucket = $dbForPlatform->getDocument('buckets', 'screenshots');
|
||||
|
||||
@@ -162,8 +160,8 @@ class Screenshots extends Action
|
||||
]);
|
||||
|
||||
$screenshotError = null;
|
||||
$screenshots = batch(\array_map(function ($key) use ($configs, $apiKey, $site, $client, &$screenshotError) {
|
||||
return function () use ($key, $configs, $apiKey, $site, $client, &$screenshotError) {
|
||||
$screenshots = batch(\array_map(function ($key) use ($configs, $apiKey, $site, $timeout, &$screenshotError) {
|
||||
return function () use ($key, $configs, $apiKey, $site, $timeout, &$screenshotError) {
|
||||
try {
|
||||
$config = $configs[$key];
|
||||
|
||||
@@ -179,6 +177,10 @@ class Screenshots extends Action
|
||||
}
|
||||
|
||||
$browserEndpoint = System::getEnv('_APP_BROWSER_HOST', 'http://appwrite-browser:3000/v1');
|
||||
$client = new FetchClient();
|
||||
$client->setTimeout($timeout);
|
||||
$client->addHeader('content-type', FetchClient::CONTENT_TYPE_APPLICATION_JSON);
|
||||
|
||||
$fetchResponse = $client->fetch(
|
||||
url: $browserEndpoint . '/screenshots',
|
||||
method: 'POST',
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Health\Http\Health\Queue\Builds;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Platform\Modules\Health\Http\Health\Queue\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
@@ -42,16 +42,16 @@ class Get extends Base
|
||||
contentType: ContentType::JSON
|
||||
))
|
||||
->param('threshold', 5000, new Integer(true), 'Queue size threshold. When hit (equal or higher), endpoint returns server error. Default value is 5000.', true)
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('response')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
public function action(int|string $threshold, Build $queueForBuilds, Response $response): void
|
||||
public function action(int|string $threshold, BuildPublisher $publisherForBuilds, Response $response): void
|
||||
{
|
||||
$threshold = (int) $threshold;
|
||||
|
||||
$size = $queueForBuilds->getSize();
|
||||
$size = $publisherForBuilds->getSize();
|
||||
|
||||
$this->assertQueueThreshold($size, $threshold);
|
||||
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Health\Http\Health\Queue\Failed;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Database;
|
||||
use Appwrite\Event\Delete;
|
||||
use Appwrite\Event\Event;
|
||||
@@ -10,6 +9,7 @@ use Appwrite\Event\Func;
|
||||
use Appwrite\Event\Mail;
|
||||
use Appwrite\Event\Messaging;
|
||||
use Appwrite\Event\Publisher\Audit;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Event\Publisher\Certificate;
|
||||
use Appwrite\Event\Publisher\Migration as MigrationPublisher;
|
||||
use Appwrite\Event\Publisher\Screenshot;
|
||||
@@ -83,7 +83,7 @@ class Get extends Base
|
||||
->inject('publisherForUsage')
|
||||
->inject('queueForWebhooks')
|
||||
->inject('publisherForCertificates')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('queueForMessaging')
|
||||
->inject('publisherForMigrations')
|
||||
->inject('publisherForScreenshots')
|
||||
@@ -103,7 +103,7 @@ class Get extends Base
|
||||
UsagePublisher $publisherForUsage,
|
||||
Webhook $queueForWebhooks,
|
||||
Certificate $publisherForCertificates,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
Messaging $queueForMessaging,
|
||||
MigrationPublisher $publisherForMigrations,
|
||||
Screenshot $publisherForScreenshots,
|
||||
@@ -120,7 +120,7 @@ class Get extends Base
|
||||
System::getEnv('_APP_STATS_USAGE_QUEUE_NAME', Event::STATS_USAGE_QUEUE_NAME) => $publisherForUsage,
|
||||
System::getEnv('_APP_WEBHOOK_QUEUE_NAME', Event::WEBHOOK_QUEUE_NAME) => $queueForWebhooks,
|
||||
System::getEnv('_APP_CERTIFICATES_QUEUE_NAME', Event::CERTIFICATES_QUEUE_NAME) => $publisherForCertificates,
|
||||
System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME) => $queueForBuilds,
|
||||
System::getEnv('_APP_BUILDS_QUEUE_NAME', Event::BUILDS_QUEUE_NAME) => $publisherForBuilds,
|
||||
System::getEnv('_APP_SCREENSHOTS_QUEUE_NAME', Event::SCREENSHOTS_QUEUE_NAME) => $publisherForScreenshots,
|
||||
System::getEnv('_APP_MESSAGING_QUEUE_NAME', Event::MESSAGING_QUEUE_NAME) => $queueForMessaging,
|
||||
System::getEnv('_APP_MIGRATIONS_QUEUE_NAME', Event::MIGRATIONS_QUEUE_NAME) => $publisherForMigrations,
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Sites\Http\Deployments;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
@@ -85,7 +86,7 @@ class Create extends Action
|
||||
->inject('queueForEvents')
|
||||
->inject('deviceForSites')
|
||||
->inject('deviceForLocal')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('plan')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
@@ -107,7 +108,7 @@ class Create extends Action
|
||||
Event $queueForEvents,
|
||||
Device $deviceForSites,
|
||||
Device $deviceForLocal,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
array $plan,
|
||||
Authorization $authorization,
|
||||
array $platform,
|
||||
@@ -315,10 +316,13 @@ class Create extends Action
|
||||
}
|
||||
|
||||
// Start the build
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($site)
|
||||
->setDeployment($deployment);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $site,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
platform: $platform,
|
||||
));
|
||||
} else {
|
||||
if ($deployment->isEmpty()) {
|
||||
$deployment = $dbForProject->createDocument('deployments', new Document([
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Sites\Http\Deployments\Duplicate;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
@@ -63,7 +64,7 @@ class Create extends Action
|
||||
->inject('dbForProject')
|
||||
->inject('dbForPlatform')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('deviceForSites')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
@@ -79,7 +80,7 @@ class Create extends Action
|
||||
Database $dbForProject,
|
||||
Database $dbForPlatform,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
Device $deviceForSites,
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
@@ -177,10 +178,13 @@ class Create extends Action
|
||||
]))
|
||||
);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($site)
|
||||
->setDeployment($deployment);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $site,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
platform: $platform,
|
||||
));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('siteId', $site->getId())
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Sites\Http\Deployments\Template;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
@@ -77,7 +78,7 @@ class Create extends Base
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('gitHub')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
@@ -98,7 +99,7 @@ class Create extends Base
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
GitHub $github,
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
@@ -130,7 +131,7 @@ class Create extends Base
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
dbForPlatform: $dbForPlatform,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
publisherForBuilds: $publisherForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
activate: $activate,
|
||||
@@ -223,11 +224,14 @@ class Create extends Base
|
||||
|
||||
$this->updateEmptyManualRule($project, $site, $deployment, $dbForPlatform, $authorization);
|
||||
|
||||
$queueForBuilds
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($site)
|
||||
->setDeployment($deployment)
|
||||
->setTemplate($template);
|
||||
$publisherForBuilds->enqueue(new BuildMessage(
|
||||
project: $project,
|
||||
resource: $site,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
template: $template,
|
||||
platform: $platform,
|
||||
));
|
||||
|
||||
$queueForEvents
|
||||
->setParam('siteId', $site->getId())
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Sites\Http\Deployments\Vcs;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\SDK\AuthType;
|
||||
@@ -71,7 +71,7 @@ class Create extends Base
|
||||
->inject('dbForPlatform')
|
||||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('gitHub')
|
||||
->inject('authorization')
|
||||
->inject('platform')
|
||||
@@ -89,7 +89,7 @@ class Create extends Base
|
||||
Database $dbForPlatform,
|
||||
Document $project,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
GitHub $github,
|
||||
Authorization $authorization,
|
||||
array $platform
|
||||
@@ -111,7 +111,7 @@ class Create extends Base
|
||||
installation: $installation,
|
||||
dbForProject: $dbForProject,
|
||||
dbForPlatform: $dbForPlatform,
|
||||
queueForBuilds: $queueForBuilds,
|
||||
publisherForBuilds: $publisherForBuilds,
|
||||
template: $template,
|
||||
github: $github,
|
||||
activate: $activate,
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\Sites\Http\Sites;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Modules\Compute\Base;
|
||||
use Appwrite\Platform\Modules\Compute\Validator\Specification;
|
||||
@@ -99,10 +99,11 @@ class Update extends Base
|
||||
->inject('dbForProject')
|
||||
->inject('project')
|
||||
->inject('queueForEvents')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('dbForPlatform')
|
||||
->inject('gitHub')
|
||||
->inject('executor')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -133,10 +134,11 @@ class Update extends Base
|
||||
Database $dbForProject,
|
||||
Document $project,
|
||||
Event $queueForEvents,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
Database $dbForPlatform,
|
||||
GitHub $github,
|
||||
Executor $executor
|
||||
Executor $executor,
|
||||
array $platform
|
||||
) {
|
||||
if (!empty($adapter)) {
|
||||
$configFramework = Config::getParam('frameworks')[$framework] ?? [];
|
||||
@@ -279,7 +281,7 @@ class Update extends Base
|
||||
|
||||
// Redeploy logic
|
||||
if (!$isConnected && !empty($providerRepositoryId)) {
|
||||
$this->redeployVcsFunction($request, $site, $project, $installation, $dbForProject, $queueForBuilds, new Document(), $github, true);
|
||||
$this->redeployVcsFunction($request, $site, $project, $installation, $dbForProject, $publisherForBuilds, new Document(), $github, true, $platform);
|
||||
}
|
||||
|
||||
$queueForEvents->setParam('siteId', $site->getId());
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Config;
|
||||
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
use Utopia\Http\Route;
|
||||
|
||||
class CacheControl
|
||||
{
|
||||
public const SOURCE_ACTION = 'action';
|
||||
public const SOURCE_CACHE = 'cache';
|
||||
|
||||
public function __construct(
|
||||
public readonly string $source,
|
||||
public readonly User $user,
|
||||
public readonly int $maxAge,
|
||||
public readonly ?Route $route = null,
|
||||
) {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Platform\Modules\Storage\Config;
|
||||
|
||||
use Appwrite\Utopia\Database\Documents\User;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Http\Route;
|
||||
|
||||
final class StorageCacheControl extends CacheControl
|
||||
{
|
||||
public function __construct(
|
||||
string $source,
|
||||
User $user,
|
||||
int $maxAge,
|
||||
public readonly Document $project,
|
||||
public readonly Document $bucket,
|
||||
public readonly Document $file,
|
||||
public readonly Document $resourceToken,
|
||||
public readonly bool $fileSecurity,
|
||||
public readonly ?Document $cacheLog = null,
|
||||
?Route $route = null,
|
||||
) {
|
||||
parent::__construct(
|
||||
source: $source,
|
||||
user: $user,
|
||||
maxAge: $maxAge,
|
||||
route: $route,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,8 @@ namespace Appwrite\Platform\Modules\Storage\Http\Buckets\Files\Preview;
|
||||
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\OpenSSL\OpenSSL;
|
||||
use Appwrite\Platform\Modules\Storage\Config\CacheControl;
|
||||
use Appwrite\Platform\Modules\Storage\Config\StorageCacheControl;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\ContentType;
|
||||
use Appwrite\SDK\Method;
|
||||
@@ -94,6 +96,7 @@ class Get extends Action
|
||||
->inject('project')
|
||||
->inject('authorization')
|
||||
->inject('user')
|
||||
->inject('cacheControlForStorage')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
|
||||
@@ -120,7 +123,8 @@ class Get extends Action
|
||||
Device $deviceForLocal,
|
||||
Document $project,
|
||||
Authorization $authorization,
|
||||
User $user
|
||||
User $user,
|
||||
callable $cacheControlForStorage
|
||||
) {
|
||||
|
||||
if (!\extension_loaded('imagick')) {
|
||||
@@ -241,28 +245,43 @@ class Get extends Action
|
||||
throw new Exception(Exception::STORAGE_FILE_TYPE_UNSUPPORTED, $e->getMessage());
|
||||
}
|
||||
|
||||
$image->crop((int) $width, (int) $height, $gravity);
|
||||
if ($width > 0 || $height > 0 || $gravity !== Image::GRAVITY_CENTER) {
|
||||
Span::add('storage.transform.crop.width', $width);
|
||||
Span::add('storage.transform.crop.height', $height);
|
||||
Span::add('storage.transform.crop.gravity', $gravity);
|
||||
$image->crop($width, $height, $gravity);
|
||||
}
|
||||
|
||||
if (!empty($opacity)) {
|
||||
if ($opacity !== 1.0) {
|
||||
Span::add('storage.transform.opacity', $opacity);
|
||||
$image->setOpacity($opacity);
|
||||
}
|
||||
|
||||
if (!empty($background)) {
|
||||
Span::add('storage.transform.background', $background);
|
||||
$image->setBackground('#' . $background);
|
||||
}
|
||||
|
||||
if (!empty($borderWidth)) {
|
||||
if ($borderWidth > 0) {
|
||||
Span::add('storage.transform.border.width', $borderWidth);
|
||||
Span::add('storage.transform.border.color', $borderColor);
|
||||
$image->setBorder($borderWidth, '#' . $borderColor);
|
||||
}
|
||||
|
||||
if (!empty($borderRadius)) {
|
||||
if ($borderRadius > 0) {
|
||||
Span::add('storage.transform.borderRadius', $borderRadius);
|
||||
$image->setBorderRadius($borderRadius);
|
||||
}
|
||||
|
||||
if (!empty($rotation)) {
|
||||
if ($rotation !== 0) {
|
||||
Span::add('storage.transform.rotation', $rotation);
|
||||
$image->setRotation(($rotation + 360) % 360);
|
||||
}
|
||||
|
||||
if ($quality !== -1) {
|
||||
Span::add('storage.transform.quality', $quality);
|
||||
}
|
||||
|
||||
$data = $image->output($output, $quality);
|
||||
|
||||
$renderingTime = \microtime(true) - $startTime - $downloadTime - $decryptionTime - $decompressionTime;
|
||||
@@ -294,8 +313,20 @@ class Get extends Action
|
||||
}
|
||||
}
|
||||
|
||||
$maxAge = 2592000; // 30 days
|
||||
$cacheControl = $cacheControlForStorage(new StorageCacheControl(
|
||||
source: CacheControl::SOURCE_ACTION,
|
||||
user: $user,
|
||||
maxAge: $maxAge,
|
||||
project: $project,
|
||||
bucket: $bucket,
|
||||
file: $file,
|
||||
resourceToken: $resourceToken,
|
||||
fileSecurity: $fileSecurity,
|
||||
));
|
||||
|
||||
$response
|
||||
->addHeader('Cache-Control', 'private, max-age=2592000') // 30 days
|
||||
->addHeader('Cache-Control', $cacheControl)
|
||||
->setContentType($contentType)
|
||||
->file($data);
|
||||
|
||||
|
||||
@@ -189,15 +189,15 @@ class Create extends Action
|
||||
} catch (\Throwable) {
|
||||
}
|
||||
|
||||
if (($plan['supportsDisposableEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && ($emailMetadata['emailIsDisposable'] ?? false)) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsDisposableEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['disposableEmails'] ?? false) && ($emailMetadata['emailIsDisposable'] ?? false)) {
|
||||
throw new Exception(Exception::USER_EMAIL_DISPOSABLE);
|
||||
}
|
||||
|
||||
if (($plan['supportsCanonicalEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && ($emailMetadata['emailIsCanonical'] ?? true) === false) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsCanonicalEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['canonicalEmails'] ?? false) && ($emailMetadata['emailIsCanonical'] ?? true) === false) {
|
||||
throw new Exception(Exception::USER_EMAIL_NOT_CANONICAL);
|
||||
}
|
||||
|
||||
if (($plan['supportsFreeEmailValidation'] ?? false) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && ($emailMetadata['emailIsFree'] ?? false)) {
|
||||
if ((($project->getId() === 'console') || ($plan['supportsFreeEmailValidation'] ?? false)) && ($project->getAttribute('auths', [])['freeEmails'] ?? false) && ($emailMetadata['emailIsFree'] ?? false)) {
|
||||
throw new Exception(Exception::USER_EMAIL_FREE);
|
||||
}
|
||||
|
||||
|
||||
+4
-4
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\VCS\Http\GitHub\Authorize\External;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\VCS\Http\GitHub\Deployment;
|
||||
@@ -60,7 +60,7 @@ class Update extends Action
|
||||
->inject('dbForPlatform')
|
||||
->inject('authorization')
|
||||
->inject('getProjectDB')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
@@ -75,7 +75,7 @@ class Update extends Action
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
callable $getProjectDB,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
array $platform
|
||||
) {
|
||||
$installation = $dbForPlatform->getDocument('installations', $installationId);
|
||||
@@ -130,7 +130,7 @@ class Update extends Action
|
||||
$providerCommitAuthor = $commitDetails["commitAuthor"] ?? '';
|
||||
$providerCommitAuthorUrl = $commitDetails["commitAuthorUrl"] ?? '';
|
||||
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, true, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, true, $dbForPlatform, $authorization, $publisherForBuilds, $getProjectDB, $platform);
|
||||
|
||||
$response->noContent();
|
||||
}
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\VCS\Http\GitHub;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Event;
|
||||
use Appwrite\Event\Message\Build as BuildMessage;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Filter\BranchDomain as BranchDomainFilter;
|
||||
use Appwrite\Vcs\Comment;
|
||||
@@ -43,7 +44,7 @@ trait Deployment
|
||||
bool $external,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
callable $getProjectDB,
|
||||
array $platform,
|
||||
) {
|
||||
@@ -528,14 +529,16 @@ trait Deployment
|
||||
|
||||
$queueName = $this->getBuildQueueName($project, $dbForPlatform, $authorization);
|
||||
|
||||
$queueForBuilds
|
||||
->setQueue($queueName)
|
||||
->setType(BUILD_TYPE_DEPLOYMENT)
|
||||
->setResource($resource)
|
||||
->setDeployment($deployment)
|
||||
->setProject($project); // set the project because it won't be set for git deployments
|
||||
|
||||
$queueForBuilds->trigger(); // must trigger here so that we create a build for each function/site
|
||||
$publisherForBuilds->enqueue(
|
||||
new BuildMessage(
|
||||
project: $project,
|
||||
resource: $resource,
|
||||
deployment: $deployment,
|
||||
type: BUILD_TYPE_DEPLOYMENT,
|
||||
platform: $platform,
|
||||
),
|
||||
new \Utopia\Queue\Queue($queueName)
|
||||
);
|
||||
|
||||
Span::add("{$logBase}.build.triggered", 'true');
|
||||
//TODO: Add event?
|
||||
@@ -545,8 +548,6 @@ trait Deployment
|
||||
}
|
||||
}
|
||||
|
||||
$queueForBuilds->reset(); // prevent shutdown hook from triggering again
|
||||
|
||||
if (!empty($errors)) {
|
||||
throw new Exception(Exception::GENERAL_UNKNOWN, \implode("\n", $errors));
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Appwrite\Platform\Modules\VCS\Http\GitHub\Events;
|
||||
|
||||
use Appwrite\Event\Build;
|
||||
use Appwrite\Event\Publisher\Build as BuildPublisher;
|
||||
use Appwrite\Extend\Exception;
|
||||
use Appwrite\Platform\Action;
|
||||
use Appwrite\Platform\Modules\VCS\Http\GitHub\Deployment;
|
||||
@@ -41,7 +41,7 @@ class Create extends Action
|
||||
->inject('dbForPlatform')
|
||||
->inject('authorization')
|
||||
->inject('getProjectDB')
|
||||
->inject('queueForBuilds')
|
||||
->inject('publisherForBuilds')
|
||||
->inject('platform')
|
||||
->callback($this->action(...));
|
||||
}
|
||||
@@ -53,7 +53,7 @@ class Create extends Action
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
callable $getProjectDB,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
array $platform
|
||||
) {
|
||||
$this->preprocessEvent($request);
|
||||
@@ -78,8 +78,8 @@ class Create extends Action
|
||||
|
||||
match ($event) {
|
||||
$github::EVENT_INSTALLATION => $this->handleInstallationEvent($parsedPayload, $dbForPlatform, $authorization),
|
||||
$github::EVENT_PUSH => $this->handlePushEvent($parsedPayload, $githubAppId, $privateKey, $github, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform),
|
||||
$github::EVENT_PULL_REQUEST => $this->handlePullRequestEvent($parsedPayload, $privateKey, $githubAppId, $github, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform),
|
||||
$github::EVENT_PUSH => $this->handlePushEvent($parsedPayload, $githubAppId, $privateKey, $github, $dbForPlatform, $authorization, $publisherForBuilds, $getProjectDB, $platform),
|
||||
$github::EVENT_PULL_REQUEST => $this->handlePullRequestEvent($parsedPayload, $privateKey, $githubAppId, $github, $dbForPlatform, $authorization, $publisherForBuilds, $getProjectDB, $platform),
|
||||
default => null,
|
||||
};
|
||||
|
||||
@@ -129,7 +129,7 @@ class Create extends Action
|
||||
GitHub $github,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
callable $getProjectDB,
|
||||
array $platform,
|
||||
) {
|
||||
@@ -164,7 +164,7 @@ class Create extends Action
|
||||
|
||||
// Create new deployment only on push (not committed by us) and not when branch is deleted
|
||||
if ($providerCommitAuthorEmail !== APP_VCS_GITHUB_EMAIL && !$providerBranchDeleted) {
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthorName, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, '', false, $dbForPlatform, $authorization, $publisherForBuilds, $getProjectDB, $platform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -175,7 +175,7 @@ class Create extends Action
|
||||
GitHub $github,
|
||||
Database $dbForPlatform,
|
||||
Authorization $authorization,
|
||||
Build $queueForBuilds,
|
||||
BuildPublisher $publisherForBuilds,
|
||||
callable $getProjectDB,
|
||||
array $platform,
|
||||
) {
|
||||
@@ -216,7 +216,7 @@ class Create extends Action
|
||||
Query::orderDesc('$createdAt')
|
||||
]));
|
||||
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $authorization, $queueForBuilds, $getProjectDB, $platform);
|
||||
$this->createGitDeployments($github, $providerInstallationId, $repositories, $providerBranch, $providerBranchUrl, $providerRepositoryName, $providerRepositoryUrl, $providerRepositoryOwner, $providerCommitHash, $providerCommitAuthor, $providerCommitAuthorUrl, $providerCommitMessage, $providerCommitUrl, $providerPullRequestId, $external, $dbForPlatform, $authorization, $publisherForBuilds, $getProjectDB, $platform);
|
||||
} elseif ($action == "closed") {
|
||||
// Allowed external contributions cleanup
|
||||
|
||||
|
||||
+51
-1
@@ -7,9 +7,12 @@ use Appwrite\Platform\Action;
|
||||
use Appwrite\SDK\AuthType;
|
||||
use Appwrite\SDK\Method;
|
||||
use Appwrite\SDK\Response as SDKResponse;
|
||||
use Appwrite\Utopia\Database\Validator\Queries\Branches;
|
||||
use Appwrite\Utopia\Response;
|
||||
use Utopia\Database\Database;
|
||||
use Utopia\Database\Document;
|
||||
use Utopia\Database\Exception\Query as QueryException;
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Platform\Scope\HTTP;
|
||||
use Utopia\System\System;
|
||||
use Utopia\Validator\Text;
|
||||
@@ -49,6 +52,8 @@ class XList extends Action
|
||||
))
|
||||
->param('installationId', '', new Text(256), 'Installation Id')
|
||||
->param('providerRepositoryId', '', new Text(256), 'Repository Id')
|
||||
->param('search', '', new Text(256), 'Search term to filter your list results. Max length: 256 chars.', true)
|
||||
->param('queries', [], new Branches(), 'Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Only supported methods are limit, offset, cursorAfter, and cursorBefore', true)
|
||||
->inject('gitHub')
|
||||
->inject('response')
|
||||
->inject('dbForPlatform')
|
||||
@@ -58,10 +63,18 @@ class XList extends Action
|
||||
public function action(
|
||||
string $installationId,
|
||||
string $providerRepositoryId,
|
||||
string $search,
|
||||
array $queries,
|
||||
GitHub $github,
|
||||
Response $response,
|
||||
Database $dbForPlatform
|
||||
) {
|
||||
try {
|
||||
$queries = Query::parseQueries($queries);
|
||||
} catch (QueryException $e) {
|
||||
throw new Exception(Exception::GENERAL_QUERY_INVALID, $e->getMessage());
|
||||
}
|
||||
|
||||
$installation = $dbForPlatform->getDocument('installations', $installationId);
|
||||
|
||||
if ($installation->isEmpty()) {
|
||||
@@ -85,11 +98,48 @@ class XList extends Action
|
||||
|
||||
$branches = $github->listBranches($owner, $repositoryName);
|
||||
|
||||
if (!empty($search)) {
|
||||
$branches = \array_values(\array_filter($branches, fn (string $branch) => \stripos($branch, $search) !== false));
|
||||
}
|
||||
|
||||
$total = \count($branches);
|
||||
[
|
||||
'limit' => $limit,
|
||||
'offset' => $offset,
|
||||
] = Query::groupByType($queries);
|
||||
$cursorQuery = \current(Query::getCursorQueries($queries, false));
|
||||
|
||||
$limit ??= APP_LIMIT_LIST_DEFAULT;
|
||||
$offset ??= 0;
|
||||
|
||||
if ($cursorQuery instanceof Query) {
|
||||
$cursor = $cursorQuery->getValue();
|
||||
$cursorDirection = $cursorQuery->getMethod() === Query::TYPE_CURSOR_AFTER
|
||||
? Database::CURSOR_AFTER
|
||||
: Database::CURSOR_BEFORE;
|
||||
|
||||
$cursorIndex = \array_search($cursor, $branches, true);
|
||||
if ($cursorIndex === false) {
|
||||
throw new Exception(Exception::GENERAL_CURSOR_NOT_FOUND, "Branch '{$cursor}' for the 'cursor' value not found.");
|
||||
}
|
||||
|
||||
$offset += $cursorDirection === Database::CURSOR_AFTER ? $cursorIndex + 1 : 0;
|
||||
|
||||
if ($cursorDirection === Database::CURSOR_BEFORE) {
|
||||
$start = \max(0, $cursorIndex - $limit);
|
||||
$branches = \array_slice($branches, $start, $cursorIndex - $start);
|
||||
} else {
|
||||
$branches = \array_slice($branches, $offset, $limit);
|
||||
}
|
||||
} else {
|
||||
$branches = \array_slice($branches, $offset, $limit);
|
||||
}
|
||||
|
||||
$response->dynamic(new Document([
|
||||
'branches' => \array_map(function ($branch) {
|
||||
return new Document(['name' => $branch]);
|
||||
}, $branches),
|
||||
'total' => \count($branches),
|
||||
'total' => $total,
|
||||
]), Response::MODEL_BRANCH_LIST);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use Appwrite\SDK\Language\Android;
|
||||
use Appwrite\SDK\Language\Apple;
|
||||
use Appwrite\SDK\Language\ClaudePlugin;
|
||||
use Appwrite\SDK\Language\CLI;
|
||||
use Appwrite\SDK\Language\CodexPlugin;
|
||||
use Appwrite\SDK\Language\CursorPlugin;
|
||||
use Appwrite\SDK\Language\Dart;
|
||||
use Appwrite\SDK\Language\Deno;
|
||||
@@ -455,6 +456,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
case 'claude-plugin':
|
||||
$config = new ClaudePlugin();
|
||||
break;
|
||||
case 'codex-plugin':
|
||||
$config = new CodexPlugin();
|
||||
break;
|
||||
default:
|
||||
throw new \Exception('Language "' . $language['key'] . '" not supported');
|
||||
}
|
||||
|
||||
@@ -197,13 +197,13 @@ class Migrations extends Action
|
||||
$projectDB = null;
|
||||
$useAppwriteApiSource = false;
|
||||
if ($source === SourceAppwrite::getName() && empty($credentials['projectId'])) {
|
||||
throw new \Exception('Source projectId is required for Appwrite migrations');
|
||||
throw new Exception(Exception::MIGRATION_SOURCE_PROJECT_ID_REQUIRED);
|
||||
}
|
||||
|
||||
if (! empty($credentials['projectId'])) {
|
||||
$this->sourceProject = $this->dbForPlatform->getDocument('projects', $credentials['projectId']);
|
||||
if ($this->sourceProject->isEmpty()) {
|
||||
throw new \Exception('Source project not found for provided projectId');
|
||||
throw new Exception(Exception::MIGRATION_SOURCE_PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$sourceRegion = $this->sourceProject->getAttribute('region', 'default');
|
||||
@@ -266,7 +266,7 @@ class Migrations extends Action
|
||||
$this->deviceForMigrations,
|
||||
$this->dbForProject,
|
||||
),
|
||||
default => throw new \Exception('Invalid source type'),
|
||||
default => throw new Exception(Exception::MIGRATION_SOURCE_TYPE_INVALID),
|
||||
};
|
||||
|
||||
$resources = $migration->getAttribute('resources', []);
|
||||
@@ -312,7 +312,7 @@ class Migrations extends Action
|
||||
$options['filename'],
|
||||
$options['columns'] ?? [],
|
||||
),
|
||||
default => throw new \Exception('Invalid destination type'),
|
||||
default => throw new Exception(Exception::MIGRATION_DESTINATION_TYPE_INVALID),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -438,6 +438,7 @@ class Migrations extends Action
|
||||
|
||||
$transfer = $source = $destination = null;
|
||||
$aggregatedResources = [];
|
||||
$caughtError = null;
|
||||
|
||||
$host = System::getEnv('_APP_MIGRATION_HOST');
|
||||
if (empty($host)) {
|
||||
@@ -531,7 +532,6 @@ class Migrations extends Action
|
||||
if (!empty($sourceErrors) || ! empty($destinationErrors)) {
|
||||
$migration->setAttribute('status', 'failed');
|
||||
$migration->setAttribute('stage', 'finished');
|
||||
$migration->setAttribute('errors', $this->sanitizeErrors($sourceErrors, $destinationErrors));
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -546,35 +546,69 @@ class Migrations extends Action
|
||||
$migration->setAttribute('status', 'failed');
|
||||
$migration->setAttribute('stage', 'finished');
|
||||
|
||||
call_user_func($this->logError, $th, 'appwrite-worker', 'appwrite-queue-' . self::getName(), [
|
||||
'migrationId' => $migration->getId(),
|
||||
'source' => $migration->getAttribute('source') ?? '',
|
||||
'destination' => $migration->getAttribute('destination') ?? '',
|
||||
]);
|
||||
$caughtError = $th;
|
||||
|
||||
// Mirror general.php's HTTP-error pattern: typed AppwriteException uses its
|
||||
// registry-driven isPublishable() flag; library-thrown Migration\Exception is
|
||||
// always user-facing; anything else is unknown and surfaced to Sentry.
|
||||
if ($th instanceof Exception) {
|
||||
$publish = $th->isPublishable();
|
||||
} elseif ($th instanceof MigrationException) {
|
||||
$publish = false;
|
||||
} else {
|
||||
$publish = true;
|
||||
}
|
||||
|
||||
if ($publish) {
|
||||
call_user_func($this->logError, $th, 'appwrite-worker', 'appwrite-queue-' . self::getName(), [
|
||||
'migrationId' => $migration->getId(),
|
||||
'source' => $migration->getAttribute('source') ?? '',
|
||||
'destination' => $migration->getAttribute('destination') ?? '',
|
||||
]);
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
$sourceErrors = $source?->getErrors() ?? [];
|
||||
$destinationErrors = $destination?->getErrors() ?? [];
|
||||
|
||||
if ($caughtError !== null) {
|
||||
if ($caughtError instanceof MigrationException) {
|
||||
// library-thrown, message constructed by us
|
||||
$bubbled = $caughtError;
|
||||
} elseif ($caughtError instanceof Exception) {
|
||||
// typed AppwriteException — message comes from the curated registry
|
||||
$bubbled = new MigrationException(
|
||||
resourceName: '',
|
||||
resourceGroup: '',
|
||||
message: $caughtError->getMessage(),
|
||||
code: $caughtError->getCode(),
|
||||
previous: $caughtError,
|
||||
);
|
||||
} else {
|
||||
// unknown throwable — raw message may embed internal hostnames,
|
||||
// DSNs, tokens, etc. Replace with a generic user-facing string;
|
||||
// the original is preserved on `previous:` for Sentry.
|
||||
$bubbled = new MigrationException(
|
||||
resourceName: '',
|
||||
resourceGroup: '',
|
||||
message: 'Migration failed due to an unexpected error.',
|
||||
code: $caughtError->getCode() ?: 500,
|
||||
previous: $caughtError,
|
||||
);
|
||||
}
|
||||
$destinationErrors[] = $bubbled;
|
||||
}
|
||||
|
||||
$migration->setAttribute('errors', $this->sanitizeErrors(
|
||||
$sourceErrors,
|
||||
$destinationErrors,
|
||||
));
|
||||
|
||||
$this->updateMigrationDocument($migration, $project, $queueForRealtime);
|
||||
|
||||
if ($migration->getAttribute('status', '') === 'failed') {
|
||||
Console::error('Migration(' . $migration->getSequence() . ':' . $migration->getId() . ') failed, Project(' . $this->project->getSequence() . ':' . $this->project->getId() . ')');
|
||||
|
||||
$sourceErrors = $source?->getErrors() ?? [];
|
||||
$destinationErrors = $destination?->getErrors() ?? [];
|
||||
|
||||
foreach ([...$sourceErrors, ...$destinationErrors] as $error) {
|
||||
/** @var MigrationException $error */
|
||||
if ($error->getCode() === 0 || $error->getCode() >= 500) {
|
||||
($this->logError)($error, 'appwrite-worker', 'appwrite-queue-' . self::getName(), [
|
||||
'migrationId' => $migration->getId(),
|
||||
'source' => $migration->getAttribute('source') ?? '',
|
||||
'destination' => $migration->getAttribute('destination') ?? '',
|
||||
'resourceName' => $error->getResourceName(),
|
||||
'resourceGroup' => $error->getResourceGroup(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
$source?->error();
|
||||
$destination?->error();
|
||||
}
|
||||
|
||||
@@ -524,6 +524,7 @@ class OpenAPI3 extends Format
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Identities::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Indexes::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Installations::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Branches::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Memberships::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Messages::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Migrations::class:
|
||||
@@ -755,7 +756,18 @@ class OpenAPI3 extends Format
|
||||
$node['schema']['default'] = $param['default'];
|
||||
}
|
||||
|
||||
if (false !== \strpos($url, ':' . $name)) { // Param is in URL path
|
||||
$pathAliases = [$name, ...($param['aliases'] ?? [])];
|
||||
$pathAliasMap = \array_flip($pathAliases);
|
||||
$isPathParam = false;
|
||||
|
||||
foreach (\explode('/', $url) as $segment) {
|
||||
if ($segment !== '' && $segment[0] === ':' && isset($pathAliasMap[\substr($segment, 1)])) {
|
||||
$isPathParam = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isPathParam) { // Param is in URL path (directly or through alias)
|
||||
$node['in'] = 'path';
|
||||
$temp['parameters'][] = $node;
|
||||
} elseif ($route->getMethod() == 'GET') { // Param is in query
|
||||
@@ -796,7 +808,14 @@ class OpenAPI3 extends Format
|
||||
}
|
||||
}
|
||||
|
||||
$url = \str_replace(':' . $name, '{' . $name . '}', $url);
|
||||
$segments = \explode('/', $url);
|
||||
foreach ($segments as &$segment) {
|
||||
if ($segment !== '' && $segment[0] === ':' && isset($pathAliasMap[\substr($segment, 1)])) {
|
||||
$segment = '{' . $name . '}';
|
||||
}
|
||||
}
|
||||
unset($segment);
|
||||
$url = \implode('/', $segments);
|
||||
}
|
||||
|
||||
if (!empty($bodyRequired)) {
|
||||
|
||||
@@ -511,6 +511,7 @@ class Swagger2 extends Format
|
||||
case \Utopia\Database\Validator\Queries::class:
|
||||
case \Utopia\Database\Validator\Queries\Document::class:
|
||||
case \Utopia\Database\Validator\Queries\Documents::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Branches::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Columns::class:
|
||||
case \Appwrite\Utopia\Database\Validator\Queries\Tables::class:
|
||||
$node['type'] = 'array';
|
||||
@@ -722,7 +723,18 @@ class Swagger2 extends Format
|
||||
$node['default'] = $param['default'];
|
||||
}
|
||||
|
||||
if (\str_contains($url, ':' . $name)) { // Param is in URL path
|
||||
$pathAliases = [$name, ...($param['aliases'] ?? [])];
|
||||
$pathAliasMap = \array_flip($pathAliases);
|
||||
$isPathParam = false;
|
||||
|
||||
foreach (\explode('/', $url) as $segment) {
|
||||
if ($segment !== '' && $segment[0] === ':' && isset($pathAliasMap[\substr($segment, 1)])) {
|
||||
$isPathParam = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($isPathParam) { // Param is in URL path (directly or through alias)
|
||||
$node['in'] = 'path';
|
||||
$temp['parameters'][] = $node;
|
||||
} elseif ($route->getMethod() == 'GET') { // Param is in query
|
||||
@@ -767,7 +779,14 @@ class Swagger2 extends Format
|
||||
}
|
||||
}
|
||||
|
||||
$url = \str_replace(':' . $name, '{' . $name . '}', $url);
|
||||
$segments = \explode('/', $url);
|
||||
foreach ($segments as &$segment) {
|
||||
if ($segment !== '' && $segment[0] === ':' && isset($pathAliasMap[\substr($segment, 1)])) {
|
||||
$segment = '{' . $name . '}';
|
||||
}
|
||||
}
|
||||
unset($segment);
|
||||
$url = \implode('/', $segments);
|
||||
}
|
||||
|
||||
if (!empty($bodyRequired)) {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Queries;
|
||||
|
||||
use Appwrite\Utopia\Database\Validator\Query\BranchCursor;
|
||||
use Utopia\Database\Validator\Queries;
|
||||
use Utopia\Database\Validator\Query\Limit;
|
||||
use Utopia\Database\Validator\Query\Offset;
|
||||
|
||||
class Branches extends Queries
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct([
|
||||
new Limit(),
|
||||
new Offset(),
|
||||
new BranchCursor(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Appwrite\Utopia\Database\Validator\Query;
|
||||
|
||||
use Utopia\Database\Query;
|
||||
use Utopia\Database\Validator\Query\Base;
|
||||
use Utopia\Validator\Text;
|
||||
|
||||
class BranchCursor extends Base
|
||||
{
|
||||
public function isValid($value): bool
|
||||
{
|
||||
if (!$value instanceof Query) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$method = $value->getMethod();
|
||||
|
||||
if (!\in_array($method, [Query::TYPE_CURSOR_AFTER, Query::TYPE_CURSOR_BEFORE], true)) {
|
||||
$this->message = 'Invalid query method: ' . $method;
|
||||
return false;
|
||||
}
|
||||
|
||||
$cursor = $value->getValue();
|
||||
|
||||
$validator = new Text(256);
|
||||
if (!$validator->isValid($cursor)) {
|
||||
$this->message = 'Invalid cursor: ' . $validator->getDescription();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getMethodType(): string
|
||||
{
|
||||
return self::METHOD_TYPE_CURSOR;
|
||||
}
|
||||
}
|
||||
@@ -50,6 +50,8 @@ class Comment
|
||||
|
||||
protected string $statePrefix = '[appwrite]: #';
|
||||
|
||||
protected ?string $tip = null;
|
||||
|
||||
/**
|
||||
* @var mixed[] $builds
|
||||
*/
|
||||
@@ -81,7 +83,14 @@ class Comment
|
||||
|
||||
public function generateComment(): string
|
||||
{
|
||||
$json = \json_encode($this->builds);
|
||||
if ($this->tip === null) {
|
||||
$this->tip = $this->tips[\array_rand($this->tips)];
|
||||
}
|
||||
|
||||
$json = \json_encode([
|
||||
'builds' => $this->builds,
|
||||
'tip' => $this->tip,
|
||||
]);
|
||||
|
||||
$text = $this->statePrefix . \base64_encode($json) . "\n\n";
|
||||
|
||||
@@ -226,8 +235,7 @@ class Comment
|
||||
$i++;
|
||||
}
|
||||
|
||||
$tip = $this->tips[array_rand($this->tips)];
|
||||
$text .= "\n<br>\n\n> [!TIP]\n> $tip\n\n";
|
||||
$text .= "\n<br>\n\n> [!TIP]\n> {$this->tip}\n\n";
|
||||
|
||||
return $text;
|
||||
}
|
||||
@@ -252,8 +260,15 @@ class Comment
|
||||
|
||||
$json = \base64_decode($state);
|
||||
|
||||
$builds = \json_decode($json, true);
|
||||
$this->builds = \is_array($builds) ? $builds : [];
|
||||
$data = \json_decode($json, true);
|
||||
|
||||
if (\is_array($data) && \array_key_exists('builds', $data)) {
|
||||
$this->builds = \is_array($data['builds']) ? $data['builds'] : [];
|
||||
$this->tip = $data['tip'] ?? null;
|
||||
} else {
|
||||
// Backward compatibility with old state format (builds array only)
|
||||
$this->builds = \is_array($data) ? $data : [];
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ namespace Tests\E2E\Services\GraphQL;
|
||||
|
||||
use CURLFile;
|
||||
use Utopia\Console;
|
||||
use Utopia\Image\Image;
|
||||
|
||||
trait Base
|
||||
{
|
||||
@@ -516,6 +517,21 @@ trait Base
|
||||
}
|
||||
';
|
||||
|
||||
protected function assertFilePreviewResponse(array $file): void
|
||||
{
|
||||
$this->assertEquals(200, $file['headers']['status-code']);
|
||||
$this->assertEquals('image/png', $file['headers']['content-type']);
|
||||
$this->assertNotEmpty($file['body']);
|
||||
|
||||
$image = new Image($file['body']);
|
||||
$dimensions = \getimagesizefromstring($file['body']);
|
||||
|
||||
$this->assertNotEmpty($image->output('png'));
|
||||
$this->assertIsArray($dimensions);
|
||||
$this->assertEquals(100, $dimensions[0]);
|
||||
$this->assertEquals(100, $dimensions[1]);
|
||||
}
|
||||
|
||||
public function getQuery(string $name): string
|
||||
{
|
||||
switch ($name) {
|
||||
@@ -2388,8 +2404,8 @@ trait Base
|
||||
}
|
||||
}';
|
||||
case self::GET_FILE_PREVIEW:
|
||||
return 'query getFilePreview($bucketId: String!, $fileId: String!) {
|
||||
storageGetFilePreview(bucketId: $bucketId, fileId: $fileId) {
|
||||
return 'query getFilePreview($bucketId: String!, $fileId: String!, $width: Int, $height: Int) {
|
||||
storageGetFilePreview(bucketId: $bucketId, fileId: $fileId, width: $width, height: $height) {
|
||||
status
|
||||
}
|
||||
}';
|
||||
|
||||
@@ -200,7 +200,7 @@ class StorageClientTest extends Scope
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertEquals(46719, \strlen($file['body']));
|
||||
$this->assertFilePreviewResponse($file);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
@@ -262,7 +262,7 @@ class StorageServerTest extends Scope
|
||||
'x-appwrite-project' => $projectId,
|
||||
], $this->getHeaders()), $gqlPayload);
|
||||
|
||||
$this->assertEquals(46719, \strlen($file['body']));
|
||||
$this->assertFilePreviewResponse($file);
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
@@ -957,6 +957,68 @@ trait StorageBase
|
||||
$this->assertNotEquals($imageBefore->getImageBlob(), $imageAfter->getImageBlob());
|
||||
}
|
||||
|
||||
public function testFilePreviewCacheControlOnCacheHit(): void
|
||||
{
|
||||
$data = $this->setupBucketFile();
|
||||
$bucketId = $data['bucketId'];
|
||||
$file = $this->client->call(Client::METHOD_POST, '/storage/buckets/' . $bucketId . '/files', array_merge([
|
||||
'content-type' => 'multipart/form-data',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'fileId' => ID::unique(),
|
||||
'file' => new CURLFile(realpath(__DIR__ . '/../../../resources/logo.png'), 'image/png', 'logo.png'),
|
||||
'permissions' => [
|
||||
Permission::read(Role::any()),
|
||||
Permission::update(Role::any()),
|
||||
Permission::delete(Role::any()),
|
||||
],
|
||||
]);
|
||||
$this->assertEquals(201, $file['headers']['status-code']);
|
||||
$this->assertNotEmpty($file['body']['$id']);
|
||||
|
||||
$fileId = $file['body']['$id'];
|
||||
$params = [
|
||||
'width' => 123,
|
||||
'height' => 45,
|
||||
'output' => 'png',
|
||||
'quality' => 80,
|
||||
];
|
||||
$headers = array_merge([
|
||||
'content-type' => 'application/json',
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders());
|
||||
|
||||
$preview = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview',
|
||||
$headers,
|
||||
$params
|
||||
);
|
||||
|
||||
$this->assertEquals(200, $preview['headers']['status-code']);
|
||||
$this->assertEquals('image/png', $preview['headers']['content-type']);
|
||||
$this->assertEquals('private, max-age=2592000', $preview['headers']['cache-control']);
|
||||
$this->assertEquals('miss', $preview['headers']['x-appwrite-cache']);
|
||||
$this->assertNotEmpty($preview['body']);
|
||||
|
||||
$cachedPreview = [];
|
||||
$this->assertEventually(function () use (&$cachedPreview, $bucketId, $fileId, $headers, $params) {
|
||||
$cachedPreview = $this->client->call(
|
||||
Client::METHOD_GET,
|
||||
'/storage/buckets/' . $bucketId . '/files/' . $fileId . '/preview',
|
||||
$headers,
|
||||
$params
|
||||
);
|
||||
|
||||
$this->assertEquals('hit', $cachedPreview['headers']['x-appwrite-cache']);
|
||||
});
|
||||
|
||||
$this->assertEquals(200, $cachedPreview['headers']['status-code']);
|
||||
$this->assertEquals('image/png', $cachedPreview['headers']['content-type']);
|
||||
$this->assertStringStartsWith('private, max-age=', $cachedPreview['headers']['cache-control']);
|
||||
$this->assertEquals($preview['body'], $cachedPreview['body']);
|
||||
}
|
||||
|
||||
public function testFilePreviewZstdCompression(): void
|
||||
{
|
||||
$data = $this->setupZstdCompressionBucket();
|
||||
|
||||
@@ -513,6 +513,59 @@ class VCSConsoleClientTest extends Scope
|
||||
$this->assertEquals($repositoryBranches['body']['branches'][0]['name'], 'main');
|
||||
$this->assertEquals($repositoryBranches['body']['branches'][1]['name'], 'test');
|
||||
|
||||
$repositoryBranches = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories/' . $this->providerRepositoryId . '/branches', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'search' => 'tes',
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $repositoryBranches['headers']['status-code']);
|
||||
$this->assertEquals($repositoryBranches['body']['total'], 1);
|
||||
$this->assertCount(1, $repositoryBranches['body']['branches']);
|
||||
$this->assertEquals($repositoryBranches['body']['branches'][0]['name'], 'test');
|
||||
|
||||
$repositoryBranches = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories/' . $this->providerRepositoryId . '/branches', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::offset(1)->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $repositoryBranches['headers']['status-code']);
|
||||
$this->assertEquals($repositoryBranches['body']['total'], 2);
|
||||
$this->assertCount(1, $repositoryBranches['body']['branches']);
|
||||
$this->assertEquals($repositoryBranches['body']['branches'][0]['name'], 'test');
|
||||
|
||||
$repositoryBranches = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories/' . $this->providerRepositoryId . '/branches', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::cursorAfter(new \Utopia\Database\Document(['$id' => 'main']))->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $repositoryBranches['headers']['status-code']);
|
||||
$this->assertEquals($repositoryBranches['body']['total'], 2);
|
||||
$this->assertCount(1, $repositoryBranches['body']['branches']);
|
||||
$this->assertEquals($repositoryBranches['body']['branches'][0]['name'], 'test');
|
||||
|
||||
$repositoryBranches = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories/' . $this->providerRepositoryId . '/branches', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::limit(1)->toString(),
|
||||
Query::cursorBefore(new \Utopia\Database\Document(['$id' => 'test']))->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(200, $repositoryBranches['headers']['status-code']);
|
||||
$this->assertEquals($repositoryBranches['body']['total'], 2);
|
||||
$this->assertCount(1, $repositoryBranches['body']['branches']);
|
||||
$this->assertEquals($repositoryBranches['body']['branches'][0]['name'], 'main');
|
||||
|
||||
/**
|
||||
* Test for FAILURE
|
||||
*/
|
||||
@@ -522,6 +575,16 @@ class VCSConsoleClientTest extends Scope
|
||||
], $this->getHeaders()));
|
||||
|
||||
$this->assertEquals(404, $repositoryBranches['headers']['status-code']);
|
||||
|
||||
$repositoryBranches = $this->client->call(Client::METHOD_GET, '/vcs/github/installations/' . $installationId . '/providerRepositories/' . $this->providerRepositoryId . '/branches', array_merge([
|
||||
'x-appwrite-project' => $this->getProject()['$id'],
|
||||
], $this->getHeaders()), [
|
||||
'queries' => [
|
||||
Query::cursorAfter(new \Utopia\Database\Document(['$id' => 'missing-branch']))->toString(),
|
||||
],
|
||||
]);
|
||||
|
||||
$this->assertEquals(400, $repositoryBranches['headers']['status-code']);
|
||||
}
|
||||
|
||||
public function testCreateFunctionUsingVCS(): void
|
||||
|
||||
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit\Vcs;
|
||||
|
||||
use Appwrite\Vcs\Comment;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Utopia\Database\Document;
|
||||
|
||||
class CommentTest extends TestCase
|
||||
{
|
||||
public function testTipIsPreservedAcrossMultipleGenerations(): void
|
||||
{
|
||||
$comment = new Comment(['consoleHostname' => 'localhost']);
|
||||
$comment->addBuild(
|
||||
new Document(['$id' => 'project1', 'name' => 'Test Project', 'region' => 'default']),
|
||||
new Document(['$id' => 'func1', 'name' => 'Test Function']),
|
||||
'function',
|
||||
'ready',
|
||||
'dep1',
|
||||
['type' => 'logs'],
|
||||
''
|
||||
);
|
||||
|
||||
$first = $comment->generateComment();
|
||||
$firstTip = $this->extractTip($first);
|
||||
|
||||
$this->assertNotNull($firstTip);
|
||||
$this->assertNotEmpty($firstTip);
|
||||
|
||||
$second = $comment->generateComment();
|
||||
$secondTip = $this->extractTip($second);
|
||||
|
||||
$this->assertEquals($firstTip, $secondTip);
|
||||
}
|
||||
|
||||
public function testTipIsRestoredFromParsedComment(): void
|
||||
{
|
||||
$comment = new Comment(['consoleHostname' => 'localhost']);
|
||||
$comment->addBuild(
|
||||
new Document(['$id' => 'project1', 'name' => 'Test Project', 'region' => 'default']),
|
||||
new Document(['$id' => 'func1', 'name' => 'Test Function']),
|
||||
'function',
|
||||
'ready',
|
||||
'dep1',
|
||||
['type' => 'logs'],
|
||||
''
|
||||
);
|
||||
|
||||
$original = $comment->generateComment();
|
||||
$originalTip = $this->extractTip($original);
|
||||
|
||||
$parsed = new Comment(['consoleHostname' => 'localhost']);
|
||||
$parsed->parseComment($original);
|
||||
$parsed->addBuild(
|
||||
new Document(['$id' => 'project1', 'name' => 'Test Project', 'region' => 'default']),
|
||||
new Document(['$id' => 'func2', 'name' => 'Another Function']),
|
||||
'function',
|
||||
'building',
|
||||
'dep2',
|
||||
['type' => 'logs'],
|
||||
''
|
||||
);
|
||||
|
||||
$regenerated = $parsed->generateComment();
|
||||
$regeneratedTip = $this->extractTip($regenerated);
|
||||
|
||||
$this->assertEquals($originalTip, $regeneratedTip);
|
||||
}
|
||||
|
||||
public function testBackwardCompatibilityWithOldStateFormat(): void
|
||||
{
|
||||
$oldBuilds = [
|
||||
'project1_func1' => [
|
||||
'projectName' => 'Test Project',
|
||||
'projectId' => 'project1',
|
||||
'region' => 'default',
|
||||
'resourceName' => 'Test Function',
|
||||
'resourceId' => 'func1',
|
||||
'resourceType' => 'function',
|
||||
'buildStatus' => 'ready',
|
||||
'deploymentId' => 'dep1',
|
||||
'action' => ['type' => 'logs'],
|
||||
'previewUrl' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$oldState = '[appwrite]: #' . \base64_encode(\json_encode($oldBuilds)) . "\n\n";
|
||||
$oldState .= "> [!TIP]\n> Old tip that should be ignored\n\n";
|
||||
|
||||
$comment = new Comment(['consoleHostname' => 'localhost']);
|
||||
$comment->parseComment($oldState);
|
||||
|
||||
$new = $comment->generateComment();
|
||||
$newTip = $this->extractTip($new);
|
||||
|
||||
$this->assertNotNull($newTip);
|
||||
$this->assertNotEquals('Old tip that should be ignored', $newTip);
|
||||
$this->assertContains($newTip, $this->getTips());
|
||||
}
|
||||
|
||||
public function testParseOldStateFormatWithOnlyBuilds(): void
|
||||
{
|
||||
$oldBuilds = [
|
||||
'project1_func1' => [
|
||||
'projectName' => 'Test Project',
|
||||
'projectId' => 'project1',
|
||||
'region' => 'default',
|
||||
'resourceName' => 'Test Function',
|
||||
'resourceId' => 'func1',
|
||||
'resourceType' => 'function',
|
||||
'buildStatus' => 'ready',
|
||||
'deploymentId' => 'dep1',
|
||||
'action' => ['type' => 'logs'],
|
||||
'previewUrl' => '',
|
||||
],
|
||||
];
|
||||
|
||||
$state = '[appwrite]: #' . \base64_encode(\json_encode($oldBuilds)) . "\n\n";
|
||||
|
||||
$comment = new Comment(['consoleHostname' => 'localhost']);
|
||||
$comment->parseComment($state);
|
||||
|
||||
$this->assertEquals(false, $comment->isEmpty());
|
||||
|
||||
$first = $comment->generateComment();
|
||||
$firstTip = $this->extractTip($first);
|
||||
|
||||
$this->assertNotNull($firstTip);
|
||||
$this->assertNotEmpty($firstTip);
|
||||
$this->assertContains($firstTip, $this->getTips());
|
||||
|
||||
$second = $comment->generateComment();
|
||||
$secondTip = $this->extractTip($second);
|
||||
|
||||
$this->assertEquals($firstTip, $secondTip);
|
||||
}
|
||||
|
||||
private function extractTip(string $comment): ?string
|
||||
{
|
||||
if (\preg_match('/> \[!TIP\]\n> (.+)/', $comment, $matches)) {
|
||||
return $matches[1];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private function getTips(): array
|
||||
{
|
||||
$reflection = new \ReflectionClass(Comment::class);
|
||||
$property = $reflection->getProperty('tips');
|
||||
|
||||
return $property->getValue(new Comment(['consoleHostname' => 'localhost']));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user