Roots Discourse

Invalid working directory specified with ansible composer module

I’m using Ansible v2.10.6, as installed by Trellis-cli.

The command I’m having trouble with, in build-before.yml is:

- name: Install Composer dependencies
  composer:
    command: install
    arguments: --no_dev --optimize_autoloader --no_scripts --classmap_authoritative
    working_dir: "{{ project_local_path }}/web/app/plugins/my-plugin"

Where ansible is reporting:

[RuntimeException]                                                                                ",
Invalid working directory specified, ../site/web/app/plugins/my-plugin does not exist.

This happens even if I hard code the path to the plugin.

Additionally, in troubleshooting, I can see that the directory does exist:

- name: Listing
  command: ls -l
  register: ls_result
  connection: local
  args:
    chdir: "{{ project_local_path }}/web/app/plugins/my-plugin"

- debug:
    msg: "Plugin Listing: {{ ls_result }}"

It prints out the plugin directory contents.

In case my overall approach is misguided, what I’m aiming to do is:

  • remove the local vendor directory
  • rebuild without the dev dependencies
  • install npm dependencies
  • compile assets
  • copy the vendor and dist directories to the server
- name: Clean out Composer vendor directory
  file:
    state: absent
    path: "{{ project_local_path }}/web/app/plugins/my-plugin/vendor"
  delegate_to: localhost

- name: Install Composer dependencies
  composer:
    command: install
    arguments: --no_dev --optimize_autoloader --no_scripts --classmap_authoritative
    working_dir: "{{ project_local_path }}/web/app/plugins/my-plugin"

- name: Install Plugin npm requirements
  command: yarn install
  connection: local
  args:
    chdir: "{{ project_local_path }}/web/app/plugins/my-plugin"

- name: Build Plugin dist from assets
  command: grunt
  connection: local
  args:
    chdir: "{{ project_local_path }}/web/app/plugins/my-plugin"

- name: Copy Plugin dist files
  synchronize:
    src: "{{ project_local_path }}/web/app/plugins/my-plugin/dist"
    dest: "{{ deploy_helper.new_release_path }}/web/app/plugins/my-plugin"
    group: no
    owner: no
    rsync_opts: --chmod=Du=rwx,--chmod=Dg=rx,--chmod=Do=rx,--chmod=Fu=rw,--chmod=Fg=r,--chmod=Fo=r

- name: Copy Plugin vendor directory
  synchronize:
    src: "{{ project_local_path }}/web/app/plugins/my-plugin/dist"
    dest: "{{ deploy_helper.new_release_path }}/web/app/plugins/my-plugin"
    group: no
    owner: no
    rsync_opts: --chmod=Du=rwx,--chmod=Dg=rx,--chmod=Do=rx,--chmod=Fu=rw,--chmod=Fg=r,--chmod=Fo=r

Thanks much, as always for your time, sage insights and wisdom.

The path of composer install is wrong because it is executing at {{ project_local_path }} on remote servers.

ls -l able to show the files because of connection: local, i.e: ls on your local machine.

Try this:

  - name: Install Composer dependencies
    composer:
      command: install
      arguments: --no_dev --optimize_autoloader --no_scripts --classmap_authoritative
-     working_dir: "{{ project_local_path }}/web/app/plugins/my-plugin"
+     working_dir: "{{ deploy_helper.new_release_path }}/web/app/plugins/my-plugin"

see: https://github.com/roots/trellis/blob/f89ae25b32d037bc14168da2ec47b7f874f0f018/deploy-hooks/build-before.yml#L19


I could understand the need of yarn install, grunt and rsync the dist folder
However, running composer install at plugin level and rsync plugin’s vendor folder usually wrong. Isn’t it already handled at bedrock level?

Well, that’s what I’m a little undecided on. The plugin was independent at first, then I integrated it into Bedrock (adding the composer deps at site/composer.json and pointing to the site directory from within the plugin), but then another developer got involved who we didn’t want to (at first) onboard into the Trellis/Bedrock workflow. I’m considering reintegrating it into the overall app again, though, which I think will simplify things.

All of the composer dependencies, in this case, would normally be generated in and pulled from the same location in site/vendor, correct? What I had been doing previously, when the plugin was part of the app, was requiring the Composer dependencies like this:

require '/srv/www/example.com/current/vendor/autoload.php';

As opposed to:

require 'vendor/autoload.php';

On the Ansible command, {{ deploy_helper.new_release_path }} references the remote server, right? So it would be installing the composer deps remotely, in which case there would be no need to rsync vendor anyway, right?

Thank you much, as always, @TangRufus.

Yes, if your plugin’s composer.json define the dependencies correctly.

Your plugin can require the autoloader like this:

if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    require_once __DIR__ . '/vendor/autoload.php';
}

This is to handle both cases:

  1. you composer install --no-dev and then zip it as a normal wp plugin
  2. you use bedrock’s vendor folder

Yes to both.

Right. That’s how it had been, but now I’ve returned the plugin to the main Bedrock codebase, since it’s not being used as part of anything else anyway.

I think the way to do that is by including “its” Composer deps in the main site/composer.json file. Isn’t that correct.

I played around a little bit with using:

$composer_deps_path = substr($_SERVER['DOCUMENT_ROOT'], 0, -3);
require $composer_deps_path . 'vendor/autoload.php';

But I believe the result was inconsistent between the local dev and remote environments so went back, for now, to hardcoding it (/srv/www/example.com...)

Am I thinking along the right direction here?