Search code examples
phplaravelgoogle-app-enginecomposer-phpgoogle-cloud-build

Why is Composer not detected by Google's Cloud Build?


I'm trying to deploy a new app to the App Engine (standard env). It is a Laravel 11, PHP 8.3 application that I'm deploying using GitHub actions.

The problem is, that it is successfully uploaded to Google Cloud, but the Cloud Build doesn't detect that it should run composer install. I've checked the build logs and saw this:

During the build step, my previous app (Laravel 9, PHP 8.2) always runs the detector, which discovers that it needs to run composer:

===> DETECTING
Timer: Detector started at 2024-05-27T00:01:25Z
5 of 6 buildpacks participating
google.php.runtime          0.0.2
google.php.composer-install 0.0.1
google.php.composer         0.9.1
google.php.appengine        0.9.0
google.utils.label-image    0.0.2
Timer: Detector ran for 179.182403ms and ended at 2024-05-27T00:01:25Z

Now my Laravel 11, PHP 8.3 has only this in the build step:

===> DETECTING
Timer: Detector started at 2024-05-26T21:41:32Z
3 of 6 buildpacks participating
google.php.runtime       0.0.2
google.php.appengine     0.9.0
google.utils.label-image 0.0.2
Timer: Detector ran for 175.726391ms and ended at 2024-05-26T21:41:32Z

Now, according to Cloud Docs, Composer runs automatically if you require autoload.php (which is true for Laravel apps in public/index.php).

For the context, this is my .github/workflows/v2.yml:

name: V2 Deployment

on:
  push:
    branches:
      - v2

jobs:
  build:
    name: 📦 Build the App
    runs-on: ubuntu-latest
    steps:
      - name: 💾 Get the latest code
        uses: actions/checkout@v4

      - name: 🧩 Build the frontend
        run: |
          npm install
          npm run build

      - name: 📤 Upload frontend
        uses: actions/upload-artifact@v4
        with:
          name: frontend
          path: public/build

  deploy_staging:
    name: 🦺 Deploy to staging (v2)
    runs-on: ubuntu-latest
    environment: staging
    needs: build
    permissions:
      id-token: write
      contents: read
    steps:
      - name: 💾 Get the latest code
        uses: actions/checkout@v4

      - name: 📥 Download frontend
        uses: actions/download-artifact@v4
        with:
          name: frontend
          path: public/build

      - name: 🔑 Authenticate to Google Cloud
        uses: google-github-actions/auth@v2
        with:
          workload_identity_provider: ${{ vars.GCLOUD_WORKLOAD_IDENTITY_PROVIDER }}
          service_account: ${{ vars.GCLOUD_SERVICE_ACCOUNT }}

      - name: 🚀 Deploy to App Engine
        uses: google-github-actions/deploy-appengine@v2
        with:
          project_id: ${{ vars.GCLOUD_PROJECT }}
          version: v2
          deliverables: .github/workflows/appengine/staging.yaml 
          gcloud_component: beta
          flags: --no-cache

And this is my .github/workflows/appengine/staging.yaml:

runtime: php83
env: standard
service: staging
handlers:
  - url: /(.*\.(bmp|gif|png|jpg|jpeg|png|ico))$
    static_files: public/\1
    upload: public/.*\.(bmp|gif|png|jpg|jpeg|png|ico)$
  - url: /(.*\.ico)$
    static_files: public/\1
    upload: public/.*\.icon$
  - url: /(.*\.mp4)$
    mime_type: video/mp4
    static_files: public/\1
    upload: public/.*\.mp4$
  - url: /(.*\.css)$
    mime_type: text/css
    static_files: public/\1
    upload: public/.*\.css$
  - url: /(.*\.js)$
    mime_type: application/javascript
    static_files: public/\1
    upload: public/.*\.js$
  - url: /(.*\.json)$
    mime_type: application/json
    static_files: public/\1
    upload: public/.*\.json$
  - url: /(.*\.(svg|svgz))$
    mime_type: image/svg+xml
    static_files: public/\1
    upload: public/.*\.(svg|svgz)$
  - url: /(.*\.txt)$
    mime_type: text/plain
    static_files: public/\1
    upload: public/.*\.txt$
  - url: /(.*\.ttf)$
    mime_type: font/ttf
    static_files: public/\1
    upload: public/.*\.ttf$
  - url: /(.*\.woff2)$
    mime_type: font/woff2
    static_files: public/\1
    upload: public/.*\.woff2$
  - url: /(.*\.map)$
    mime_type: application/json
    static_files: public/\1
    upload: public/.*\.map$
env_variables:
  VIEW_COMPILED_PATH: /tmp
  CACHE_STORAGE_PATH: /tmp/framework/cache/data

(note: the service: staging in staging.yaml is valid, since I have deployed a V1 with a valid dispatch.yaml).


Solution

  • Well, the Occam's Razor never stops to impress me. The problem is that my v2.yml is not in the app's root directory. I thought that wouldn't be a problem because I tried to set working_directory: ./ (see action's inputs). But it is...

    So for the developers, who are obsessively trying to tidy up their codebase, here is the missing step that I added before the 🚀 Deploy to App Engine:

          - name: 📑 Move the GAE deliverables
            run: |
              mv .github/workflows/appengine/staging.yaml app.yaml
              mv .github/workflows/appengine/dispatch.yaml dispatch.yaml
    

    and then adjust the deliverables' path in:

          - name: 🚀 Deploy to App Engine
            uses: google-github-actions/deploy-appengine@v2
            with:
              project_id: ${{ vars.GCLOUD_PROJECT }}
              version: v2
              deliverables: app.yaml dispatch.yaml
    

    PS: It created another problem with Cloud Composer:

    Problem 1
    Step #2 - "build":     - laravel/framework is locked to version v11.0.5 and an update of this package was not requested.
    Step #2 - "build":     - laravel/framework v11.0.5 requires composer-runtime-api ^2.2 -> found composer-runtime-api[2.1.0] but it does not match the constraint.
    

    ...so I also had to add this to the deployment step:

              build_env_vars:
                GOOGLE_COMPOSER_VERSION=2.2.1