Skip to content

Commit

Permalink
Add ability to load extensions to packwerk
Browse files Browse the repository at this point in the history
  • Loading branch information
Alex Evanczuk committed Oct 31, 2022
1 parent 589fe52 commit bd1c27b
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 12 deletions.
15 changes: 15 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
* [Understanding how to respond to new violations](#understanding-how-to-respond-to-new-violations)
* [Recording existing violations](#recording-existing-violations)
* [Understanding the package todo file](#understanding-the-package-todo-file)
* [Understanding the list of deprecated references](#understanding-the-list-of-deprecated-references)
* [Loading extensions](#loading-extensions)

## What problem does Packwerk solve?

Expand Down Expand Up @@ -275,3 +277,16 @@ Above is an example of a constant violation entry in `package_todo.yml`.
* `components/merchant/app/public/merchant/generate_order.rb` - path to the file containing the violated constant

Violations exist within the package that makes a violating reference. This means privacy violations of your package can be found listed in `package_todo.yml` files in the packages with the reference to a private constant.

# Loading Extensions

You can optionally specify ruby files that you'd like to be loaded with `packwerk` by specifying a `require` directive in `packwerk.yml`:
```yml
require:
- ./path/to/file.rb
- my_gem
```

`packwerk` will directly call `require` with these paths.
You can prefix local files with a dot to define them relative to `packwerk.yml`, or you can use absolute paths.
You can also reference the name of a gem.
1 change: 1 addition & 0 deletions lib/packwerk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ module Packwerk
autoload :ConstantNameInspector
autoload :ConstNodeInspector
autoload :PackageTodo
autoload :ExtensionLoader
autoload :FileProcessor
autoload :FilesForProcessing
autoload :Graph
Expand Down
6 changes: 6 additions & 0 deletions lib/packwerk/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ def initialize(configs = {}, config_path: nil)
@cache_directory = Pathname.new(configs["cache_directory"] || "tmp/cache/packwerk")
@config_path = config_path

if configs.key?("require")
configs["require"].each do |require_directive|
ExtensionLoader.load(require_directive, @root_path)
end
end

if configs["load_paths"]
warning = <<~WARNING
DEPRECATION WARNING: The 'load_paths' key in `packwerk.yml` is deprecated.
Expand Down
24 changes: 24 additions & 0 deletions lib/packwerk/extension_loader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# typed: strict
# frozen_string_literal: true

module Packwerk
# This class handles loading extensions to packwerk using the `require` directive
# in the `packwerk.yml` configuration.
module ExtensionLoader
class << self
extend T::Sig
sig { params(require_directive: String, config_dir_path: String).void }
def load(require_directive, config_dir_path)
# We want to transform the require directive to behave differently
# if it's a specific local file being required versus a gem
if require_directive.start_with?(".")
require File.join(config_dir_path, require_directive)
else
require require_directive
end
end
end
end

private_constant :ExtensionLoader
end
Empty file.
1 change: 1 addition & 0 deletions test/fixtures/extended/config/environment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
# this file intentionally left blank
2 changes: 2 additions & 0 deletions test/fixtures/extended/config/my_local_extension.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module MyLocalExtension
end
Empty file.
4 changes: 4 additions & 0 deletions test/fixtures/extended/packwerk.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
parallel: false
require:
- ./config/my_local_extension
- my_gem_extension
Empty file.
Empty file.
29 changes: 29 additions & 0 deletions test/unit/configuration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ class ConfigurationTest < Minitest::Test

teardown do
teardown_application_fixture
Object.send(:remove_const, :MyLocalExtension) if defined?(MyLocalExtension)
end

test ".from_path raises ArgumentError if path does not exist" do
Expand Down Expand Up @@ -63,5 +64,33 @@ class ConfigurationTest < Minitest::Test
Configuration.expects(:new).with({}, config_path: to_app_path("packwerk.yml"))
Configuration.from_path
end

test "require works when referencing a local file" do
refute defined?(MyLocalExtension)
use_template(:extended)
mock_require_method = ->(required_thing) do
next unless required_thing.include?("my_local_extension")

require required_thing
end
ExtensionLoader.stub(:require, mock_require_method) do
Configuration.from_path
end
assert defined?(MyLocalExtension)
end

test "require works when referencing a gem" do
use_template(:extended)

required_things = []
mock_require_method = ->(required_thing) do
required_things << required_thing
end
ExtensionLoader.stub(:require, mock_require_method) do
Configuration.from_path
end

assert_includes(required_things, "my_gem_extension")
end
end
end
28 changes: 16 additions & 12 deletions test/unit/files_for_processing_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@

module Packwerk
class FilesForProcessingTest < Minitest::Test
def setup
include ApplicationFixtureHelper

setup do
setup_application_fixture
use_template(:skeleton)
@package_path = "components/sales"
@configuration = ::Packwerk::Configuration.from_path("test/fixtures/skeleton")
@configuration = ::Packwerk::Configuration.from_path
end

teardown do
teardown_application_fixture
end

test "fetch with custom paths includes only include glob in custom paths" do
files = Dir.chdir("test/fixtures/skeleton") do
::Packwerk::FilesForProcessing.fetch(relative_file_paths: [@package_path], configuration: @configuration)
end
files = ::Packwerk::FilesForProcessing.fetch(relative_file_paths: [@package_path], configuration: @configuration)
included_file_pattern = File.join(@package_path, "**/*.rb")
assert_all_match(files, [included_file_pattern])
end
Expand Down Expand Up @@ -54,13 +60,11 @@ def setup
end

test "fetch with no custom paths ignoring nested packages includes only include glob across codebase" do
files = Dir.chdir("test/fixtures/skeleton") do
::Packwerk::FilesForProcessing.fetch(
relative_file_paths: [],
configuration: @configuration,
ignore_nested_packages: true
)
end
files = ::Packwerk::FilesForProcessing.fetch(
relative_file_paths: [],
configuration: @configuration,
ignore_nested_packages: true
)

assert_all_match(files, @configuration.include)
end
Expand Down

0 comments on commit bd1c27b

Please sign in to comment.