Skip to content

Make packwerk work with in-repo engines using load_path aliases #206

@AndrewSwerlick

Description

@AndrewSwerlick

Description
This is similar to #47 , but there are some distinctions because we're discussing engines, which are autoloaded, vs gems that are not.

The context is that we have a mono-repo setup like this

root_dir
|- engine_1
|- engine_2
|- app_1
|- app_2

where multiple apps will use the same engines. Each engine is symlinked under an apps vendor directory like
root_dir/app_1/vendor/gems/engine_1 -> root_dir/engine_1`

We attempted to setup packwerk for a given app with a root_dir/app_1/packwerk.yml, with a root package at root_dir/app_1/package.yml and a package inside an engine like root_dir/engine_1/app/models/users/package.yml.

We found that we could properly setup the packwerk.yml include and package_paths to follow the symlinks inside of vendor and scan all the files both in the app folder, and in the engine folders, but it would never flag any violations.

In digging in, we found the problem was with the constant resolution workflow. Although the autoload paths for the engines were available in Rails.autoloaders, the path found there was root_dir/engine_1/** instead of root_dir/app_1/vendor/gems/engine_1. As a result it was being filtered out of the paths provided to the ConstantResolver by ApplicationLoadPaths.filter_relevant_paths

We experimented with monkey patching filter_relevant_paths to transform the path names for all these in-repo engines to use the full symlink path. When we did that, everything worked as expected.

I wanted to propose the idea that we upstream our patch by adding a new key to the packwerk.yml configuration file named something like load_path_aliases. This would take a hash where the keys would be the load_path as discovered in Rails.autoloaders and the value would be an alias that the path should be transformed to. Then we'd modify ApplicationLoadPaths to go through these aliases, and transform all the paths before passing them into ConstantResolver

Does this seem like a reasonable approach? If folks are open to it, I can put together a PR

To Reproduce

Setup a mono repo as described above. If folks would like a clearer example, I can setup a sample application.

Expected Behaviour

Under this proposal, a developer could a define a packwerk.yml with this new load_path_aliases something like this

load_path_aliases:
  '../engine_1/': 'vendor/gems/engine_1/'
  '../engine_2/': 'vendor/gems/engine_2'/

Then any paths that started with ../engine_1/ would be replaced with an equivalent starting with vendor/gems/engine_1

Version Information

  • Packwerk: 2.2.0
  • Ruby 2.75

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions