diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e0cab01e7..ed5ca7b0a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: timeout-minutes: 15 strategy: matrix: - php: [ '8.2', '8.1', '8.0' ] + php: [ '8.3', '8.2', '8.1', '8.0' ] dependency-version: [ '' ] platform-reqs: [ '' ] include: @@ -24,11 +24,14 @@ jobs: dependency-version: '--prefer-lowest' steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 # Node is required by some tests - - uses: actions/setup-node@v1 + - uses: actions/setup-node@v3 with: - node-version: 12 + node-version: 18 + # serverless is required by some tests + - name: Install serverless + run: npm i -g serverless - name: Setup PHP uses: shivammathur/setup-php@v2 with: @@ -46,15 +49,15 @@ jobs: name: PHPStan steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: '8.2' tools: composer:v2, cs2pr coverage: none - name: Cache Composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.composer/cache key: php-composer-locked-${{ hashFiles('composer.lock') }} @@ -69,15 +72,15 @@ jobs: name: PHP CodeSniffer steps: - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: '8.2' tools: composer:v2, cs2pr coverage: none - name: Cache Composer dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ~/.composer/cache key: php-composer-locked-${{ hashFiles('composer.lock') }} @@ -95,7 +98,7 @@ jobs: - uses: actions/setup-node@v3 with: node-version: 18 - - uses: actions/cache@v2 + - uses: actions/cache@v3 with: path: ~/.npm key: ${{ runner.os }}-node-${{ hashFiles('**/package.json') }} diff --git a/.github/workflows/update-layer-versions.yml b/.github/workflows/update-layer-versions.yml index ace094888..8dc3c4b48 100644 --- a/.github/workflows/update-layer-versions.yml +++ b/.github/workflows/update-layer-versions.yml @@ -5,13 +5,10 @@ on: workflow_dispatch: inputs: release_url: - required: true type: string release_html_url: - required: true type: string release_name: - required: true type: string # Necessary to connect to AWS using OIDC @@ -32,7 +29,7 @@ jobs: ref: master - name: Set AWS credentials - uses: aws-actions/configure-aws-credentials@v1 + uses: aws-actions/configure-aws-credentials@v2 with: role-to-assume: arn:aws:iam::534081306603:role/bref-github-actions role-session-name: bref-github-actions @@ -41,7 +38,7 @@ jobs: - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: 8.1 + php-version: '8.2' tools: composer - name: Install Composer dependencies @@ -50,7 +47,7 @@ jobs: - run: make layers.json - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v5 with: commit-message: Update layer versions title: Update Lambda layers [${{ inputs.release_name }}](${{ inputs.release_html_url }}) diff --git a/composer.json b/composer.json index c5b9cbd52..148a6061d 100644 --- a/composer.json +++ b/composer.json @@ -27,10 +27,10 @@ "hollodotme/fast-cgi-client": "^3.0.1", "nyholm/psr7": "^1.4.1", "psr/container": "^1.0|^2.0", - "psr/http-message": "^1.0", + "psr/http-message": "^1.0|^2.0", "psr/http-server-handler": "^1.0", "riverline/multipart-parser": "^2.0.6", - "symfony/process": "^4.4|^5.0|^6.0" + "symfony/process": "^4.4|^5.0|^6.0|^7.0" }, "require-dev": { "async-aws/core": "^1.0", @@ -40,9 +40,10 @@ "dms/phpunit-arraysubset-asserts": "^0.4", "doctrine/coding-standard": "^8.0", "guzzlehttp/guzzle": "^7.5", - "phpstan/phpstan": "^1.0", - "phpunit/phpunit": "^9.0", - "symfony/console": "^4.4|^5.0|^6.0" + "phpstan/phpstan": "^1.10.26", + "phpunit/phpunit": "^9.6.10", + "symfony/console": "^4.4|^5.0|^6.0|^7.0", + "symfony/yaml": "^4.4|^5.0|^6.0|^7.0" }, "scripts": { "test": [ diff --git a/index.js b/index.js index b60582236..c4ee46b8f 100644 --- a/index.js +++ b/index.js @@ -47,7 +47,7 @@ class ServerlessPlugin { .filter(name => !name.startsWith('arm-')); // Console runtimes must have a PHP version provided this.runtimes = this.runtimes.filter(name => name !== 'console'); - this.runtimes.push('php-80-console', 'php-81-console', 'php-82-console'); + this.runtimes.push('php-80-console', 'php-81-console', 'php-82-console', 'php-83-console'); this.checkCompatibleRuntime(); @@ -197,23 +197,27 @@ class ServerlessPlugin { const config = this.serverless.service; const isArmGlobally = config.provider.architecture === 'arm64'; - - // Check provider config - if (this.runtimes.includes(config.provider.runtime || '')) { - config.provider.layers = includeBrefLayers( - config.provider.runtime, - config.provider.layers || [], // make sure it's an array - isArmGlobally, - ); - config.provider.runtime = 'provided.al2'; - } + const isBrefRuntimeGlobally = this.runtimes.includes(config.provider.runtime || ''); // Check functions config for (const f of Object.values(config.functions || {})) { - if (f.runtime && this.runtimes.includes(f.runtime)) { + if ( + (f.runtime && this.runtimes.includes(f.runtime)) || + (!f.runtime && isBrefRuntimeGlobally) + ) { + // The logic here is a bit custom: + // If there are layers on the function, we preserve them + let existingLayers = f.layers || []; // make sure it's an array + // Else, we merge with the layers defined at the root. + // Indeed, SF overrides the layers defined at the root with the ones defined on the function. + if (existingLayers.length === 0) { + // for some reason it's not always an array + existingLayers = Array.from(config.provider.layers || []); + } + f.layers = includeBrefLayers( - f.runtime, - f.layers || [], // make sure it's an array + f.runtime || config.provider.runtime, + existingLayers, f.architecture === 'arm64' || (isArmGlobally && !f.architecture), ); f.runtime = 'provided.al2'; @@ -224,9 +228,9 @@ class ServerlessPlugin { for (const construct of Object.values(this.serverless.configurationInput.constructs || {})) { if (construct.type !== 'queue' && construct.type !== 'webhook') continue; const f = construct.type === 'queue' ? construct.worker : construct.authorizer; - if (f && f.runtime && this.runtimes.includes(f.runtime)) { + if (f && (f.runtime && this.runtimes.includes(f.runtime) || !f.runtime && isBrefRuntimeGlobally) ) { f.layers = includeBrefLayers( - f.runtime, + f.runtime || config.provider.runtime, f.layers || [], // make sure it's an array f.architecture === 'arm64' || (isArmGlobally && !f.architecture), ); diff --git a/layers.json b/layers.json index a8ffce5b9..54472726d 100644 --- a/layers.json +++ b/layers.json @@ -1,314 +1,410 @@ { + "php-83": { + "ca-central-1": "4", + "eu-central-1": "4", + "eu-north-1": "4", + "eu-west-1": "4", + "eu-west-2": "4", + "eu-west-3": "4", + "sa-east-1": "4", + "us-east-1": "4", + "us-east-2": "4", + "us-west-1": "4", + "us-west-2": "4", + "ap-east-1": "4", + "ap-south-1": "4", + "ap-northeast-1": "4", + "ap-northeast-2": "4", + "ap-northeast-3": "4", + "ap-southeast-1": "4", + "ap-southeast-2": "4", + "eu-south-1": "4", + "eu-south-2": "4", + "af-south-1": "4", + "me-south-1": "4" + }, + "php-83-fpm": { + "ca-central-1": "4", + "eu-central-1": "4", + "eu-north-1": "4", + "eu-west-1": "4", + "eu-west-2": "4", + "eu-west-3": "4", + "sa-east-1": "4", + "us-east-1": "4", + "us-east-2": "4", + "us-west-1": "4", + "us-west-2": "4", + "ap-east-1": "4", + "ap-south-1": "4", + "ap-northeast-1": "4", + "ap-northeast-2": "4", + "ap-northeast-3": "4", + "ap-southeast-1": "4", + "ap-southeast-2": "4", + "eu-south-1": "4", + "eu-south-2": "4", + "af-south-1": "4", + "me-south-1": "4" + }, "php-82": { - "ca-central-1": "42", - "eu-central-1": "42", - "eu-north-1": "42", - "eu-west-1": "42", - "eu-west-2": "42", - "eu-west-3": "42", - "sa-east-1": "42", - "us-east-1": "42", - "us-east-2": "42", - "us-west-1": "42", - "us-west-2": "42", - "ap-east-1": "42", - "ap-south-1": "42", - "ap-northeast-1": "42", - "ap-northeast-2": "42", - "ap-northeast-3": "42", - "ap-southeast-1": "42", - "ap-southeast-2": "42", - "eu-south-1": "42", - "eu-south-2": "41", - "af-south-1": "42", - "me-south-1": "42" + "ca-central-1": "48", + "eu-central-1": "48", + "eu-north-1": "48", + "eu-west-1": "48", + "eu-west-2": "48", + "eu-west-3": "48", + "sa-east-1": "48", + "us-east-1": "48", + "us-east-2": "48", + "us-west-1": "48", + "us-west-2": "48", + "ap-east-1": "48", + "ap-south-1": "48", + "ap-northeast-1": "48", + "ap-northeast-2": "48", + "ap-northeast-3": "48", + "ap-southeast-1": "48", + "ap-southeast-2": "48", + "eu-south-1": "48", + "eu-south-2": "47", + "af-south-1": "48", + "me-south-1": "48" }, "php-82-fpm": { - "ca-central-1": "42", - "eu-central-1": "42", - "eu-north-1": "42", - "eu-west-1": "42", - "eu-west-2": "42", - "eu-west-3": "42", - "sa-east-1": "42", - "us-east-1": "42", - "us-east-2": "42", - "us-west-1": "42", - "us-west-2": "42", - "ap-east-1": "42", - "ap-south-1": "42", - "ap-northeast-1": "42", - "ap-northeast-2": "42", - "ap-northeast-3": "42", - "ap-southeast-1": "42", - "ap-southeast-2": "42", - "eu-south-1": "42", - "eu-south-2": "41", - "af-south-1": "42", - "me-south-1": "42" + "ca-central-1": "48", + "eu-central-1": "48", + "eu-north-1": "48", + "eu-west-1": "48", + "eu-west-2": "48", + "eu-west-3": "48", + "sa-east-1": "48", + "us-east-1": "48", + "us-east-2": "48", + "us-west-1": "48", + "us-west-2": "48", + "ap-east-1": "48", + "ap-south-1": "48", + "ap-northeast-1": "48", + "ap-northeast-2": "48", + "ap-northeast-3": "48", + "ap-southeast-1": "48", + "ap-southeast-2": "48", + "eu-south-1": "48", + "eu-south-2": "47", + "af-south-1": "48", + "me-south-1": "48" }, "php-81": { - "ca-central-1": "53", - "eu-central-1": "53", - "eu-north-1": "53", - "eu-west-1": "53", - "eu-west-2": "53", - "eu-west-3": "53", - "sa-east-1": "53", - "us-east-1": "53", - "us-east-2": "53", - "us-west-1": "53", - "us-west-2": "53", - "ap-east-1": "45", - "ap-south-1": "52", - "ap-northeast-1": "52", - "ap-northeast-2": "52", - "ap-northeast-3": "52", - "ap-southeast-1": "52", - "ap-southeast-2": "52", - "eu-south-1": "45", - "eu-south-2": "42", - "af-south-1": "45", - "me-south-1": "45" + "ca-central-1": "59", + "eu-central-1": "59", + "eu-north-1": "59", + "eu-west-1": "59", + "eu-west-2": "59", + "eu-west-3": "59", + "sa-east-1": "59", + "us-east-1": "59", + "us-east-2": "59", + "us-west-1": "59", + "us-west-2": "59", + "ap-east-1": "51", + "ap-south-1": "58", + "ap-northeast-1": "58", + "ap-northeast-2": "58", + "ap-northeast-3": "58", + "ap-southeast-1": "58", + "ap-southeast-2": "58", + "eu-south-1": "51", + "eu-south-2": "48", + "af-south-1": "51", + "me-south-1": "51" }, "php-81-fpm": { - "ca-central-1": "52", - "eu-central-1": "52", - "eu-north-1": "53", - "eu-west-1": "53", - "eu-west-2": "52", - "eu-west-3": "52", - "sa-east-1": "52", - "us-east-1": "53", - "us-east-2": "52", - "us-west-1": "52", - "us-west-2": "53", - "ap-east-1": "45", - "ap-south-1": "51", - "ap-northeast-1": "52", - "ap-northeast-2": "51", - "ap-northeast-3": "51", - "ap-southeast-1": "51", - "ap-southeast-2": "51", - "eu-south-1": "44", - "eu-south-2": "41", - "af-south-1": "44", - "me-south-1": "44" + "ca-central-1": "58", + "eu-central-1": "58", + "eu-north-1": "59", + "eu-west-1": "59", + "eu-west-2": "58", + "eu-west-3": "58", + "sa-east-1": "58", + "us-east-1": "59", + "us-east-2": "58", + "us-west-1": "58", + "us-west-2": "59", + "ap-east-1": "51", + "ap-south-1": "57", + "ap-northeast-1": "58", + "ap-northeast-2": "57", + "ap-northeast-3": "57", + "ap-southeast-1": "57", + "ap-southeast-2": "57", + "eu-south-1": "50", + "eu-south-2": "47", + "af-south-1": "50", + "me-south-1": "50" }, "php-80": { - "ca-central-1": "56", - "eu-central-1": "55", - "eu-north-1": "56", - "eu-west-1": "56", - "eu-west-2": "56", - "eu-west-3": "56", - "sa-east-1": "56", - "us-east-1": "56", - "us-east-2": "56", - "us-west-1": "56", - "us-west-2": "56", - "ap-east-1": "46", - "ap-south-1": "55", - "ap-northeast-1": "53", - "ap-northeast-2": "52", - "ap-northeast-3": "53", - "ap-southeast-1": "52", - "ap-southeast-2": "54", - "eu-south-1": "46", - "eu-south-2": "42", - "af-south-1": "46", - "me-south-1": "46" + "ca-central-1": "62", + "eu-central-1": "61", + "eu-north-1": "62", + "eu-west-1": "62", + "eu-west-2": "62", + "eu-west-3": "62", + "sa-east-1": "62", + "us-east-1": "62", + "us-east-2": "62", + "us-west-1": "62", + "us-west-2": "62", + "ap-east-1": "52", + "ap-south-1": "61", + "ap-northeast-1": "59", + "ap-northeast-2": "58", + "ap-northeast-3": "59", + "ap-southeast-1": "58", + "ap-southeast-2": "60", + "eu-south-1": "52", + "eu-south-2": "48", + "af-south-1": "52", + "me-south-1": "52" }, "php-80-fpm": { - "ca-central-1": "53", - "eu-central-1": "53", - "eu-north-1": "53", - "eu-west-1": "53", - "eu-west-2": "53", - "eu-west-3": "53", - "sa-east-1": "53", - "us-east-1": "53", - "us-east-2": "53", - "us-west-1": "53", - "us-west-2": "53", - "ap-east-1": "45", - "ap-south-1": "52", - "ap-northeast-1": "52", - "ap-northeast-2": "52", - "ap-northeast-3": "52", - "ap-southeast-1": "52", - "ap-southeast-2": "52", - "eu-south-1": "45", - "eu-south-2": "42", - "af-south-1": "45", - "me-south-1": "45" + "ca-central-1": "59", + "eu-central-1": "59", + "eu-north-1": "59", + "eu-west-1": "59", + "eu-west-2": "59", + "eu-west-3": "59", + "sa-east-1": "59", + "us-east-1": "59", + "us-east-2": "59", + "us-west-1": "59", + "us-west-2": "59", + "ap-east-1": "51", + "ap-south-1": "58", + "ap-northeast-1": "58", + "ap-northeast-2": "58", + "ap-northeast-3": "58", + "ap-southeast-1": "58", + "ap-southeast-2": "58", + "eu-south-1": "51", + "eu-south-2": "48", + "af-south-1": "51", + "me-south-1": "51" + }, + "arm-php-83": { + "ca-central-1": "4", + "eu-central-1": "4", + "eu-north-1": "4", + "eu-west-1": "4", + "eu-west-2": "4", + "eu-west-3": "4", + "sa-east-1": "4", + "us-east-1": "4", + "us-east-2": "4", + "us-west-1": "4", + "us-west-2": "4", + "ap-east-1": "4", + "ap-south-1": "4", + "ap-northeast-1": "4", + "ap-northeast-2": "4", + "ap-northeast-3": "4", + "ap-southeast-1": "4", + "ap-southeast-2": "4", + "eu-south-1": "4", + "eu-south-2": "4", + "af-south-1": "4", + "me-south-1": "4" + }, + "arm-php-83-fpm": { + "ca-central-1": "4", + "eu-central-1": "4", + "eu-north-1": "4", + "eu-west-1": "4", + "eu-west-2": "4", + "eu-west-3": "4", + "sa-east-1": "4", + "us-east-1": "4", + "us-east-2": "4", + "us-west-1": "4", + "us-west-2": "4", + "ap-east-1": "4", + "ap-south-1": "4", + "ap-northeast-1": "4", + "ap-northeast-2": "4", + "ap-northeast-3": "4", + "ap-southeast-1": "4", + "ap-southeast-2": "4", + "eu-south-1": "4", + "eu-south-2": "4", + "af-south-1": "4", + "me-south-1": "4" }, "arm-php-82": { - "ca-central-1": "30", - "eu-central-1": "30", - "eu-north-1": "30", - "eu-west-1": "30", - "eu-west-2": "30", - "eu-west-3": "30", - "sa-east-1": "30", - "us-east-1": "30", - "us-east-2": "30", - "us-west-1": "30", - "us-west-2": "30", - "ap-east-1": "30", - "ap-south-1": "30", - "ap-northeast-1": "30", - "ap-northeast-2": "30", - "ap-northeast-3": "30", - "ap-southeast-1": "30", - "ap-southeast-2": "30", - "eu-south-1": "30", - "eu-south-2": "30", - "af-south-1": "30", - "me-south-1": "30" + "ca-central-1": "36", + "eu-central-1": "36", + "eu-north-1": "36", + "eu-west-1": "36", + "eu-west-2": "36", + "eu-west-3": "36", + "sa-east-1": "36", + "us-east-1": "36", + "us-east-2": "36", + "us-west-1": "36", + "us-west-2": "36", + "ap-east-1": "36", + "ap-south-1": "36", + "ap-northeast-1": "36", + "ap-northeast-2": "36", + "ap-northeast-3": "36", + "ap-southeast-1": "36", + "ap-southeast-2": "36", + "eu-south-1": "36", + "eu-south-2": "36", + "af-south-1": "36", + "me-south-1": "36" }, "arm-php-82-fpm": { - "ca-central-1": "30", - "eu-central-1": "30", - "eu-north-1": "30", - "eu-west-1": "30", - "eu-west-2": "30", - "eu-west-3": "30", - "sa-east-1": "30", - "us-east-1": "30", - "us-east-2": "30", - "us-west-1": "30", - "us-west-2": "30", - "ap-east-1": "30", - "ap-south-1": "30", - "ap-northeast-1": "30", - "ap-northeast-2": "30", - "ap-northeast-3": "30", - "ap-southeast-1": "30", - "ap-southeast-2": "30", - "eu-south-1": "30", - "eu-south-2": "30", - "af-south-1": "30", - "me-south-1": "30" + "ca-central-1": "36", + "eu-central-1": "36", + "eu-north-1": "36", + "eu-west-1": "36", + "eu-west-2": "36", + "eu-west-3": "36", + "sa-east-1": "36", + "us-east-1": "36", + "us-east-2": "36", + "us-west-1": "36", + "us-west-2": "36", + "ap-east-1": "36", + "ap-south-1": "36", + "ap-northeast-1": "36", + "ap-northeast-2": "36", + "ap-northeast-3": "36", + "ap-southeast-1": "36", + "ap-southeast-2": "36", + "eu-south-1": "36", + "eu-south-2": "36", + "af-south-1": "36", + "me-south-1": "36" }, "arm-php-81": { - "ca-central-1": "33", - "eu-central-1": "33", - "eu-north-1": "33", - "eu-west-1": "33", - "eu-west-2": "33", - "eu-west-3": "33", - "sa-east-1": "33", - "us-east-1": "33", - "us-east-2": "33", - "us-west-1": "33", - "us-west-2": "33", - "ap-east-1": "33", - "ap-south-1": "33", - "ap-northeast-1": "33", - "ap-northeast-2": "33", - "ap-northeast-3": "33", - "ap-southeast-1": "33", - "ap-southeast-2": "33", - "eu-south-1": "33", - "eu-south-2": "33", - "af-south-1": "33", - "me-south-1": "33" + "ca-central-1": "39", + "eu-central-1": "39", + "eu-north-1": "39", + "eu-west-1": "39", + "eu-west-2": "39", + "eu-west-3": "39", + "sa-east-1": "39", + "us-east-1": "39", + "us-east-2": "39", + "us-west-1": "39", + "us-west-2": "39", + "ap-east-1": "39", + "ap-south-1": "39", + "ap-northeast-1": "39", + "ap-northeast-2": "39", + "ap-northeast-3": "39", + "ap-southeast-1": "39", + "ap-southeast-2": "39", + "eu-south-1": "39", + "eu-south-2": "39", + "af-south-1": "39", + "me-south-1": "39" }, "arm-php-81-fpm": { - "ca-central-1": "33", - "eu-central-1": "33", - "eu-north-1": "33", - "eu-west-1": "33", - "eu-west-2": "33", - "eu-west-3": "33", - "sa-east-1": "33", - "us-east-1": "33", - "us-east-2": "33", - "us-west-1": "33", - "us-west-2": "33", - "ap-east-1": "33", - "ap-south-1": "33", - "ap-northeast-1": "33", - "ap-northeast-2": "33", - "ap-northeast-3": "33", - "ap-southeast-1": "33", - "ap-southeast-2": "33", - "eu-south-1": "33", - "eu-south-2": "33", - "af-south-1": "33", - "me-south-1": "33" + "ca-central-1": "39", + "eu-central-1": "39", + "eu-north-1": "39", + "eu-west-1": "39", + "eu-west-2": "39", + "eu-west-3": "39", + "sa-east-1": "39", + "us-east-1": "39", + "us-east-2": "39", + "us-west-1": "39", + "us-west-2": "39", + "ap-east-1": "39", + "ap-south-1": "39", + "ap-northeast-1": "39", + "ap-northeast-2": "39", + "ap-northeast-3": "39", + "ap-southeast-1": "39", + "ap-southeast-2": "39", + "eu-south-1": "39", + "eu-south-2": "39", + "af-south-1": "39", + "me-south-1": "39" }, "arm-php-80": { - "ca-central-1": "55", - "eu-central-1": "54", - "eu-north-1": "55", - "eu-west-1": "55", - "eu-west-2": "55", - "eu-west-3": "55", - "sa-east-1": "55", - "us-east-1": "55", - "us-east-2": "55", - "us-west-1": "55", - "us-west-2": "55", - "ap-east-1": "47", - "ap-south-1": "54", - "ap-northeast-1": "54", - "ap-northeast-2": "54", - "ap-northeast-3": "54", - "ap-southeast-1": "54", - "ap-southeast-2": "54", - "eu-south-1": "47", - "eu-south-2": "43", - "af-south-1": "47", - "me-south-1": "47" + "ca-central-1": "61", + "eu-central-1": "60", + "eu-north-1": "61", + "eu-west-1": "61", + "eu-west-2": "61", + "eu-west-3": "61", + "sa-east-1": "61", + "us-east-1": "61", + "us-east-2": "61", + "us-west-1": "61", + "us-west-2": "61", + "ap-east-1": "53", + "ap-south-1": "60", + "ap-northeast-1": "60", + "ap-northeast-2": "60", + "ap-northeast-3": "60", + "ap-southeast-1": "60", + "ap-southeast-2": "60", + "eu-south-1": "53", + "eu-south-2": "49", + "af-south-1": "53", + "me-south-1": "53" }, "arm-php-80-fpm": { - "ca-central-1": "54", - "eu-central-1": "53", - "eu-north-1": "54", - "eu-west-1": "54", - "eu-west-2": "53", - "eu-west-3": "53", - "sa-east-1": "53", - "us-east-1": "54", - "us-east-2": "54", - "us-west-1": "53", - "us-west-2": "54", - "ap-east-1": "46", - "ap-south-1": "52", - "ap-northeast-1": "53", - "ap-northeast-2": "52", - "ap-northeast-3": "52", - "ap-southeast-1": "52", - "ap-southeast-2": "52", - "eu-south-1": "45", - "eu-south-2": "42", - "af-south-1": "46", - "me-south-1": "45" + "ca-central-1": "60", + "eu-central-1": "59", + "eu-north-1": "60", + "eu-west-1": "60", + "eu-west-2": "59", + "eu-west-3": "59", + "sa-east-1": "59", + "us-east-1": "60", + "us-east-2": "60", + "us-west-1": "59", + "us-west-2": "60", + "ap-east-1": "52", + "ap-south-1": "58", + "ap-northeast-1": "59", + "ap-northeast-2": "58", + "ap-northeast-3": "58", + "ap-southeast-1": "58", + "ap-southeast-2": "58", + "eu-south-1": "51", + "eu-south-2": "48", + "af-south-1": "52", + "me-south-1": "51" }, "console": { - "ca-central-1": "52", - "eu-central-1": "52", - "eu-north-1": "52", - "eu-west-1": "52", - "eu-west-2": "52", - "eu-west-3": "52", - "sa-east-1": "52", - "us-east-1": "52", - "us-east-2": "52", - "us-west-1": "52", - "us-west-2": "52", - "ap-east-1": "44", - "ap-south-1": "51", - "ap-northeast-1": "51", - "ap-northeast-2": "51", - "ap-northeast-3": "51", - "ap-southeast-1": "51", - "ap-southeast-2": "51", - "eu-south-1": "44", - "eu-south-2": "41", - "af-south-1": "44", - "me-south-1": "44" + "ca-central-1": "58", + "eu-central-1": "58", + "eu-north-1": "58", + "eu-west-1": "58", + "eu-west-2": "58", + "eu-west-3": "58", + "sa-east-1": "58", + "us-east-1": "58", + "us-east-2": "58", + "us-west-1": "58", + "us-west-2": "58", + "ap-east-1": "50", + "ap-south-1": "57", + "ap-northeast-1": "57", + "ap-northeast-2": "57", + "ap-northeast-3": "57", + "ap-southeast-1": "57", + "ap-southeast-2": "57", + "eu-south-1": "50", + "eu-south-2": "47", + "af-south-1": "50", + "me-south-1": "50" } } \ No newline at end of file diff --git a/phpunit.xml b/phpunit.xml index 6fd8c028a..f8a3f2026 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -15,4 +15,7 @@ ./tests/Sam + + + diff --git a/serverless.yml b/serverless.yml index 32e235968..43244fa3d 100644 --- a/serverless.yml +++ b/serverless.yml @@ -25,14 +25,14 @@ package: functions: function: handler: demo/function.php - runtime: php-81 + runtime: php-83 description: 'Bref function demo' environment: BREF_LOOP_MAX: 100 http: handler: demo/http.php - runtime: php-81-fpm + runtime: php-83-fpm architecture: arm64 description: 'Bref HTTP demo' timeout: 5 # in seconds (API Gateway has a timeout of 29 seconds) @@ -41,7 +41,7 @@ functions: psr7: handler: demo/psr7.php - runtime: php-81 + runtime: php-83 description: 'Bref HTTP demo with a PSR-7 handler' timeout: 5 # in seconds (API Gateway has a timeout of 29 seconds) events: @@ -52,7 +52,7 @@ functions: http-api: handler: demo/http.php - runtime: php-81-fpm + runtime: php-83-fpm description: 'Bref HTTP demo' timeout: 5 # in seconds (API Gateway has a timeout of 29 seconds) events: @@ -60,6 +60,6 @@ functions: console: handler: demo/console.php - runtime: php-81-console + runtime: php-83-console description: 'Bref console command demo' timeout: 5 diff --git a/src/ConsoleRuntime/Main.php b/src/ConsoleRuntime/Main.php index d42435b55..b5c3bbeeb 100755 --- a/src/ConsoleRuntime/Main.php +++ b/src/ConsoleRuntime/Main.php @@ -25,7 +25,7 @@ public static function run(): void $appRoot = getenv('LAMBDA_TASK_ROOT'); $handlerFile = $appRoot . '/' . getenv('_HANDLER'); if (! is_file($handlerFile)) { - $lambdaRuntime->failInitialization("Handler `$handlerFile` doesn't exist"); + $lambdaRuntime->failInitialization("Handler `$handlerFile` doesn't exist", 'Runtime.NoSuchHandler'); } /** @phpstan-ignore-next-line */ diff --git a/src/Event/ApiGateway/WebsocketEvent.php b/src/Event/ApiGateway/WebsocketEvent.php index 55c62cea3..3e0c13b6b 100644 --- a/src/Event/ApiGateway/WebsocketEvent.php +++ b/src/Event/ApiGateway/WebsocketEvent.php @@ -105,7 +105,6 @@ public function getStage(): string public function getRegion(): string { - [, , $region] = explode('.', $this->getDomainName(), 4); - return $region; + return getenv('AWS_REGION'); } } diff --git a/src/FpmRuntime/Main.php b/src/FpmRuntime/Main.php index 6c8aa842b..d3241b5d1 100755 --- a/src/FpmRuntime/Main.php +++ b/src/FpmRuntime/Main.php @@ -5,6 +5,7 @@ use Bref\Bref; use Bref\LazySecretsLoader; use Bref\Runtime\LambdaRuntime; +use RuntimeException; use Throwable; /** @@ -27,14 +28,14 @@ public static function run(): void $appRoot = getenv('LAMBDA_TASK_ROOT'); $handlerFile = $appRoot . '/' . getenv('_HANDLER'); if (! is_file($handlerFile)) { - $lambdaRuntime->failInitialization("Handler `$handlerFile` doesn't exist"); + $lambdaRuntime->failInitialization("Handler `$handlerFile` doesn't exist", 'Runtime.NoSuchHandler'); } $phpFpm = new FpmHandler($handlerFile); try { $phpFpm->start(); } catch (Throwable $e) { - $lambdaRuntime->failInitialization('Error while starting PHP-FPM', $e); + $lambdaRuntime->failInitialization(new RuntimeException('Error while starting PHP-FPM: ' . $e->getMessage(), 0, $e)); } /** @phpstan-ignore-next-line */ diff --git a/src/FunctionRuntime/Main.php b/src/FunctionRuntime/Main.php index c4843eda4..f6925ca06 100644 --- a/src/FunctionRuntime/Main.php +++ b/src/FunctionRuntime/Main.php @@ -25,7 +25,7 @@ public static function run(): void try { $handler = $container->get(getenv('_HANDLER')); } catch (Throwable $e) { - $lambdaRuntime->failInitialization($e->getMessage()); + $lambdaRuntime->failInitialization($e, 'Runtime.NoSuchHandler'); } $loopMax = getenv('BREF_LOOP_MAX') ?: 1; diff --git a/src/Runtime/LambdaRuntime.php b/src/Runtime/LambdaRuntime.php index 6fbadb316..0b4014c4c 100755 --- a/src/Runtime/LambdaRuntime.php +++ b/src/Runtime/LambdaRuntime.php @@ -239,42 +239,57 @@ private function signalFailure(string $invocationId, Throwable $error): void * * @see https://docs.aws.amazon.com/lambda/latest/dg/runtimes-api.html#runtimes-api-initerror * + * @phpstan-param 'Runtime.NoSuchHandler'|'Runtime.UnknownReason' $lambdaInitializationReason * @phpstan-return never-returns */ - public function failInitialization(string $message, ?Throwable $error = null): void - { + public function failInitialization( + string|Throwable $error, + string $lambdaInitializationReason = 'Runtime.UnknownReason', + ): void { // Log the exception in CloudWatch - echo "$message\n"; - if ($error) { - if ($error instanceof Exception) { - $errorMessage = get_class($error) . ': ' . $error->getMessage(); - } else { - $errorMessage = $error->getMessage(); - } + if ($error instanceof Throwable) { + $traceAsArray = explode(PHP_EOL, $error->getTraceAsString()); + $data = [ + 'errorMessage' => $error->getMessage(), + 'errorType' => get_class($error), + 'stackTrace' => $traceAsArray, + ]; printf( - "Fatal error: %s in %s:%d\nStack trace:\n%s", - $errorMessage, + "Fatal error: %s in %s:%d\n %s\n", + get_class($error) . ': ' . $error->getMessage(), $error->getFile(), $error->getLine(), - $error->getTraceAsString() + json_encode([ + 'message' => $error->getMessage(), + 'type' => get_class($error), + 'stackTrace' => $traceAsArray, + ], JSON_THROW_ON_ERROR), ); + } else { + $data = [ + 'errorMessage' => $error, + 'errorType' => 'Internal', + 'stackTrace' => [], + ]; + echo "Fatal error: $error\n"; } + echo "The function failed to start. AWS Lambda will restart the process, do not be surprised if you see the error message twice.\n"; + $url = "http://$this->apiUrl/2018-06-01/runtime/init/error"; - $this->postJson($url, [ - 'errorMessage' => $message . ' ' . ($error ? $error->getMessage() : ''), - 'errorType' => $error ? get_class($error) : 'Internal', - 'stackTrace' => $error ? explode(PHP_EOL, $error->getTraceAsString()) : [], + $this->postJson($url, $data, [ + "Lambda-Runtime-Function-Error-Type: $lambdaInitializationReason", ]); exit(1); } /** - * @throws ResponseTooBig + * @param string[] $headers * @throws Exception + * @throws ResponseTooBig */ - private function postJson(string $url, mixed $data): void + private function postJson(string $url, mixed $data, array $headers = []): void { /** @noinspection JsonEncodingApiUsageInspection */ $jsonData = json_encode($data); @@ -296,6 +311,7 @@ private function postJson(string $url, mixed $data): void curl_setopt($this->curlHandleResult, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', 'Content-Length: ' . strlen($jsonData), + ...$headers, ]); $body = curl_exec($this->curlHandleResult); diff --git a/src/bref-local b/src/bref-local index d370bc924..63e77d5ac 100755 --- a/src/bref-local +++ b/src/bref-local @@ -18,6 +18,16 @@ if (file_exists(__DIR__ . '/../vendor/autoload.php')) { $handler = $argv[1] ?? ''; $data = $argv[2] ?? null; +$opts = getopt('', ['path:']); + +if (isset($opts['path'])) { + if (! file_exists($opts['path'])) { + throw new Exception('The file ' . $opts['path'] . ' could not be found.'); + } + + $handler = $argv[array_key_last($argv)]; + $data = file_get_contents($opts['path']); +} try { $handler = Bref::getContainer()->get($handler); diff --git a/tests/Plugin/serverless-runtime-root-with-layers.yml b/tests/Plugin/serverless-runtime-root-with-layers.yml new file mode 100644 index 000000000..074fe4bd5 --- /dev/null +++ b/tests/Plugin/serverless-runtime-root-with-layers.yml @@ -0,0 +1,27 @@ +service: bref +provider: + name: aws + runtime: php-83 + layers: + - arn:aws:lambda:us-east-1:1234567890:layer:foo:1 + +plugins: + - ../../index.js + +functions: + + function: + handler: function.php + function-arm: + handler: function.php + architecture: arm64 + + function-with-layers: + handler: function.php + layers: + - arn:aws:lambda:us-east-1:1234567890:layer:bar:1 + function-arm-with-layers: + handler: function.php + architecture: arm64 + layers: + - arn:aws:lambda:us-east-1:1234567890:layer:bar:1 diff --git a/tests/Plugin/serverless-runtime-root.yml b/tests/Plugin/serverless-runtime-root.yml new file mode 100644 index 000000000..206332e32 --- /dev/null +++ b/tests/Plugin/serverless-runtime-root.yml @@ -0,0 +1,14 @@ +service: bref +provider: + name: aws + runtime: php-83 + +plugins: + - ../../index.js + +functions: + function: + handler: function.php + function-arm: + handler: function.php + architecture: arm64 diff --git a/tests/Plugin/serverless-with-layers.yml b/tests/Plugin/serverless-with-layers.yml new file mode 100644 index 000000000..89cc2010f --- /dev/null +++ b/tests/Plugin/serverless-with-layers.yml @@ -0,0 +1,30 @@ +service: bref +provider: + name: aws + layers: + - arn:aws:lambda:us-east-1:1234567890:layer:foo:1 + +plugins: + - ../../index.js + +functions: + + function: + handler: function.php + runtime: php-83 + function-arm: + handler: function.php + runtime: php-83 + architecture: arm64 + + function-with-layers: + handler: function.php + runtime: php-83 + layers: + - arn:aws:lambda:us-east-1:1234567890:layer:bar:1 + function-arm-with-layers: + handler: function.php + runtime: php-83 + architecture: arm64 + layers: + - arn:aws:lambda:us-east-1:1234567890:layer:bar:1 diff --git a/tests/Plugin/serverless.yml b/tests/Plugin/serverless.yml new file mode 100644 index 000000000..867f2253a --- /dev/null +++ b/tests/Plugin/serverless.yml @@ -0,0 +1,30 @@ +service: bref +provider: + name: aws + +plugins: + - ../../index.js + +functions: + function: + handler: function.php + runtime: php-83 + fpm: + handler: fpm.php + runtime: php-83-fpm + console: + handler: console.php + runtime: php-83-console + + function-arm: + handler: function.php + architecture: arm64 + runtime: php-83 + fpm-arm: + handler: fpm.php + architecture: arm64 + runtime: php-83-fpm + console-arm: + handler: console.php + architecture: arm64 + runtime: php-83-console diff --git a/tests/PluginTest.php b/tests/PluginTest.php new file mode 100644 index 000000000..afc00d6d6 --- /dev/null +++ b/tests/PluginTest.php @@ -0,0 +1,122 @@ +slsPrint('serverless.yml'); + + self::assertFunction($output['functions']['function'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:', + ]); + self::assertFunction($output['functions']['fpm'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83-fpm:', + ]); + self::assertFunction($output['functions']['console'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:', + 'arn:aws:lambda:us-east-1:534081306603:layer:console:', + ]); + + self::assertFunction($output['functions']['function-arm'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:', + ]); + self::assertFunction($output['functions']['fpm-arm'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83-fpm:', + ]); + self::assertFunction($output['functions']['console-arm'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:', + 'arn:aws:lambda:us-east-1:534081306603:layer:console:', + ]); + } + + public function test the plugin adds the layers when the runtime is set in the provider(): void + { + $output = $this->slsPrint('serverless-runtime-root.yml'); + + self::assertFunction($output['functions']['function'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:', + ]); + self::assertFunction($output['functions']['function-arm'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:', + ]); + } + + public function test the plugin doesnt break layers added separately(): void + { + $output = $this->slsPrint('serverless-with-layers.yml'); + + self::assertFunction($output['functions']['function'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:', + 'arn:aws:lambda:us-east-1:1234567890:layer:foo:1', + ]); + self::assertFunction($output['functions']['function-arm'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:', + 'arn:aws:lambda:us-east-1:1234567890:layer:foo:1', + ]); + self::assertFunction($output['functions']['function-with-layers'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:', + // This function doesn't have the `foo` layer because that's how SF works: + // layers in the function completely override the layers in the root + 'arn:aws:lambda:us-east-1:1234567890:layer:bar:1', + ]); + self::assertFunction($output['functions']['function-arm-with-layers'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:', + // This function doesn't have the `foo` layer because that's how SF works: + // layers in the function completely override the layers in the root + 'arn:aws:lambda:us-east-1:1234567890:layer:bar:1', + ]); + } + + public function test the plugin doesnt break layers added separately with the runtime set at the root(): void + { + $output = $this->slsPrint('serverless-runtime-root-with-layers.yml'); + + self::assertFunction($output['functions']['function'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:', + 'arn:aws:lambda:us-east-1:1234567890:layer:foo:1', + ]); + self::assertFunction($output['functions']['function-arm'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:', + 'arn:aws:lambda:us-east-1:1234567890:layer:foo:1', + ]); + self::assertFunction($output['functions']['function-with-layers'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:php-83:', + // This function doesn't have the `foo` layer because that's how SF works: + // layers in the function completely override the layers in the root + 'arn:aws:lambda:us-east-1:1234567890:layer:bar:1', + ]); + self::assertFunction($output['functions']['function-arm-with-layers'], [ + 'arn:aws:lambda:us-east-1:534081306603:layer:arm-php-83:', + // This function doesn't have the `foo` layer because that's how SF works: + // layers in the function completely override the layers in the root + 'arn:aws:lambda:us-east-1:1234567890:layer:bar:1', + ]); + } + + private function slsPrint(string $configFile): array + { + $process = (new Process( + ['serverless', 'print', '-c', $configFile], + cwd: __DIR__ . '/Plugin', + env: [ + 'SLS_TELEMETRY_DISABLED' => '1', // else we sometimes get HTTP errors (and its faster) + ], + ))->mustRun(); + return Yaml::parse($process->getOutput()); + } + + private static function assertFunction(array $config, array $layers): void + { + self::assertEquals('provided.al2', $config['runtime']); + self::assertCount(count($layers), $config['layers'], sprintf('Expected %d layers, got %d: %s', count($layers), count($config['layers']), json_encode($config['layers'], JSON_THROW_ON_ERROR))); + foreach ($layers as $index => $layer) { + self::assertStringStartsWith($layer, $config['layers'][$index]); + } + } +} diff --git a/tests/Sam/PhpRuntimeTest.php b/tests/Sam/PhpRuntimeTest.php index bc30607e9..bbd379463 100644 --- a/tests/Sam/PhpRuntimeTest.php +++ b/tests/Sam/PhpRuntimeTest.php @@ -188,7 +188,7 @@ public function test php config() self::assertArraySubset([ // On the CLI we want errors to be sent to stdout -> those will end up in CloudWatch 'display_errors' => '1', - // This means `stderr` in php-cli (http://php.net/manual/errorfunc.configuration.php#ini.error-log) + // This means `stderr` in php-cli (https://www.php.net/manual/en/errorfunc.configuration.php#ini.error-log) 'error_log' => null, // This is the default production value 'error_reporting' => (string) (E_ALL & ~E_DEPRECATED & ~E_STRICT), diff --git a/tests/server.js b/tests/server.js index 1c7a49e81..5d416feca 100644 --- a/tests/server.js +++ b/tests/server.js @@ -56,7 +56,7 @@ * > DELETE /guzzle-server * > Host: 127.0.0.1:8126 * - * @package Guzzle PHP + * @package Guzzle PHP * @license See the LICENSE file that was distributed with this source code. */ diff --git a/utils/layers.json/update.php b/utils/layers.json/update.php index c20f67dd1..06c149eb7 100644 --- a/utils/layers.json/update.php +++ b/utils/layers.json/update.php @@ -13,12 +13,16 @@ require_once __DIR__ . '/../../vendor/autoload.php'; const LAYER_NAMES = [ + 'php-83', + 'php-83-fpm', 'php-82', 'php-82-fpm', 'php-81', 'php-81-fpm', 'php-80', 'php-80-fpm', + 'arm-php-83', + 'arm-php-83-fpm', 'arm-php-82', 'arm-php-82-fpm', 'arm-php-81', diff --git a/website/template/enterprise.twig b/website/template/enterprise.twig index 225c41e40..d1ad54b6c 100644 --- a/website/template/enterprise.twig +++ b/website/template/enterprise.twig @@ -119,14 +119,10 @@

Bref Enterprise

- Starting at - $1000 - /mo + Get in touch

-

- * cancel anytime, first month refund if not satisfied -

- Get In Touch +

+ Get In Touch