Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file added empty_commit
Empty file.
59 changes: 39 additions & 20 deletions lib/packwerk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,58 @@
module Packwerk
extend ActiveSupport::Autoload

# Public APIs
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I chose these APIs with these rationales:

Checker

API for extending checkers

Cli

Main API for calling packwerk right now. Eventually we might want API like Packwerk.check instead of using the CLI, but this is the de-facto API.

Offense

Part of the interface for OffensesFormatter

OffensesFormatter

API for extending offenses formatter

OutputStyle

Implementation of this needs to be passed into CLI

Package, PackageSet, PackageTodo

API for getting information about YML files

Parsers

Contains documented API for Packwerk::Parsers::Factory.erb_parser_class=(...), which is the current API for substituting the ERB parser.
The hope is that #243 will allow us to mark this API as private.

This module also contains ParserInterface as well. With the above PR, we'd allow the interface to be public but the rest to be private.

Reference, ReferenceOffense

Part of the API to Checker

Result

Return value of CLI

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Result is overloaded, I vote to nest the toplevel result in CLI. We should also nest the app validator result in Validator instead, especially if we use it in the interface.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah makes sense, changed!

autoload :Checker
autoload :Cli
autoload :Offense
autoload :OffensesFormatter
autoload :OutputStyle
autoload :Package
autoload :PackageSet
autoload :PackageTodo
autoload :Parsers
autoload :Reference
autoload :ReferenceOffense
autoload :Validator
autoload :Version

# Private APIs
# Please submit an issue if you have a use-case for these
autoload :ApplicationLoadPaths
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is more easily read commit by commit. A previous commit sorts these then another separates them.

autoload :ApplicationValidator
autoload :AssociationInspector
autoload :OffenseCollection
autoload :Cache
autoload :Checker
autoload :Cli
autoload :Configuration
autoload :ConstantDiscovery
autoload :ConstantNameInspector
autoload :ConstNodeInspector
autoload :PackageTodo
autoload :ExtensionLoader
autoload :FileProcessor
autoload :FilesForProcessing
autoload :Graph
autoload :Loader
autoload :Node
autoload :NodeHelpers
autoload :NodeProcessor
autoload :NodeProcessorFactory
autoload :NodeVisitor
autoload :Offense
autoload :OffensesFormatter
autoload :OutputStyle
autoload :Package
autoload :PackageSet
autoload :OffenseCollection
autoload :ParsedConstantDefinitions
autoload :Parsers
autoload :ParseRun
autoload :UnresolvedReference
autoload :Reference
autoload :ReferenceExtractor
autoload :ReferenceOffense
autoload :Result
autoload :RunContext
autoload :Validator
autoload :Version
autoload :UnresolvedReference

module Validator
extend ActiveSupport::Autoload

autoload :Result
end

class Cli
extend ActiveSupport::Autoload

autoload :Result
end

module OutputStyles
extend ActiveSupport::Autoload
Expand All @@ -69,13 +83,17 @@ module Formatters
autoload :ProgressFormatter
end

private_constant :Formatters

module Generators
extend ActiveSupport::Autoload

autoload :ConfigurationFile
autoload :RootPackage
end

private_constant :Generators

module ReferenceChecking
extend ActiveSupport::Autoload

Expand All @@ -89,17 +107,18 @@ module Checkers
end
end

private_constant :ReferenceChecking

class ApplicationValidator
extend ActiveSupport::Autoload

autoload :Result
autoload :Helpers
end
end

# Required to register the default OffensesFormatter
# Required to register the DefaultOffensesFormatter
# We put this at the *end* of the file to specify all autoloads first
require "packwerk/formatters/offenses_formatter"
require "packwerk/formatters/default_offenses_formatter"

# Required to register the default DependencyChecker
require "packwerk/reference_checking/checkers/dependency_checker"
Expand Down
2 changes: 2 additions & 0 deletions lib/packwerk/application_load_paths.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,6 @@ def assert_load_paths_present(paths)
end
end
end

private_constant :ApplicationLoadPaths
end
30 changes: 16 additions & 14 deletions lib/packwerk/application_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,13 @@ class ApplicationValidator
include Validator
extend T::Sig

sig { params(package_set: PackageSet, configuration: Configuration).returns(ApplicationValidator::Result) }
sig { params(package_set: PackageSet, configuration: Configuration).returns(Validator::Result) }
def check_all(package_set, configuration)
results = Validator.all.flat_map { |validator| validator.call(package_set, configuration) }
merge_results(results)
end

sig { override.params(package_set: PackageSet, configuration: Configuration).returns(ApplicationValidator::Result) }
sig { override.params(package_set: PackageSet, configuration: Configuration).returns(Validator::Result) }
def call(package_set, configuration)
results = [
check_package_manifest_syntax(configuration),
Expand All @@ -37,7 +37,7 @@ def permitted_keys
]
end

sig { params(configuration: Configuration).returns(Result) }
sig { params(configuration: Configuration).returns(Validator::Result) }
def check_package_manifest_syntax(configuration)
errors = []

Expand All @@ -54,18 +54,18 @@ def check_package_manifest_syntax(configuration)
end

if errors.empty?
Result.new(ok: true)
Validator::Result.new(ok: true)
else
merge_results(
errors.map { |error| Result.new(ok: false, error_value: error) },
errors.map { |error| Validator::Result.new(ok: false, error_value: error) },
separator: "\n",
before_errors: "Malformed syntax in the following manifests:\n\n",
after_errors: "\n",
)
end
end

sig { params(configuration: Configuration).returns(Result) }
sig { params(configuration: Configuration).returns(Validator::Result) }
def check_application_structure(configuration)
resolver = ConstantResolver.new(
root_path: configuration.root_path.to_s,
Expand All @@ -74,23 +74,23 @@ def check_application_structure(configuration)

begin
resolver.file_map
Result.new(ok: true)
Validator::Result.new(ok: true)
rescue => e
Result.new(ok: false, error_value: e.message)
Validator::Result.new(ok: false, error_value: e.message)
end
end

sig { params(configuration: Configuration).returns(Result) }
sig { params(configuration: Configuration).returns(Validator::Result) }
def check_package_manifest_paths(configuration)
all_package_manifests = package_manifests(configuration, "**/")
package_paths_package_manifests = package_manifests(configuration, package_glob(configuration))

difference = all_package_manifests - package_paths_package_manifests

if difference.empty?
Result.new(ok: true)
Validator::Result.new(ok: true)
else
Result.new(
Validator::Result.new(
ok: false,
error_value: <<~EOS
Expected package paths for all package.ymls to be specified, but paths were missing for the following manifests:
Expand All @@ -101,15 +101,15 @@ def check_package_manifest_paths(configuration)
end
end

sig { params(configuration: Configuration).returns(Result) }
sig { params(configuration: Configuration).returns(Validator::Result) }
def check_root_package_exists(configuration)
root_package_path = File.join(configuration.root_path, "package.yml")
all_packages_manifests = package_manifests(configuration, package_glob(configuration))

if all_packages_manifests.include?(root_package_path)
Result.new(ok: true)
Validator::Result.new(ok: true)
else
Result.new(
Validator::Result.new(
ok: false,
error_value: <<~EOS
A root package does not exist. Create an empty `package.yml` at the root directory.
Expand All @@ -130,4 +130,6 @@ def relative_paths(configuration, paths)
paths.map { |path| relative_path(configuration, path) }
end
end

private_constant :ApplicationValidator
end
2 changes: 2 additions & 0 deletions lib/packwerk/association_inspector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,6 @@ def association_name(arguments)
NodeHelpers.literal_value(association_name_node)
end
end

private_constant :AssociationInspector
end
3 changes: 2 additions & 1 deletion lib/packwerk/cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -169,8 +169,9 @@ def out(out)
puts(out)
end
end
end
end
end

private_constant :Cache
private_constant :Debug
end
12 changes: 6 additions & 6 deletions lib/packwerk/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ class Cli
out: T.any(StringIO, IO),
err_out: T.any(StringIO, IO),
environment: String,
style: Packwerk::OutputStyle,
offenses_formatter: T.nilable(Packwerk::OffensesFormatter)
style: OutputStyle,
offenses_formatter: T.nilable(OffensesFormatter)
).void
end
def initialize(
Expand Down Expand Up @@ -77,12 +77,12 @@ def init

sig { returns(T::Boolean) }
def generate_configs
configuration_file = Packwerk::Generators::ConfigurationFile.generate(
configuration_file = Generators::ConfigurationFile.generate(
root: @configuration.root_path,
out: @out
)

root_package = Packwerk::Generators::RootPackage.generate(root: @configuration.root_path, out: @out)
root_package = Generators::RootPackage.generate(root: @configuration.root_path, out: @out)

success = configuration_file && root_package

Expand Down Expand Up @@ -159,7 +159,7 @@ def validate(_paths)

sig { returns(ApplicationValidator) }
def validator
Packwerk::ApplicationValidator.new
ApplicationValidator.new
end

sig { returns(PackageSet) }
Expand All @@ -170,7 +170,7 @@ def package_set
)
end

sig { params(result: ApplicationValidator::Result).void }
sig { params(result: Validator::Result).void }
def list_validation_errors(result)
@out.puts
if result.ok?
Expand Down
11 changes: 11 additions & 0 deletions lib/packwerk/cli/result.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# typed: strict
# frozen_string_literal: true

module Packwerk
class Cli
class Result < T::Struct
const :message, String
const :status, T::Boolean
end
end
end
4 changes: 3 additions & 1 deletion lib/packwerk/configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def initialize(configs = {}, config_path: nil)
@cache_directory = Pathname.new(configs["cache_directory"] || "tmp/cache/packwerk")
@config_path = config_path

@offenses_formatter_identifier = configs["offenses_formatter"] || Formatters::OffensesFormatter::IDENTIFIER
@offenses_formatter_identifier = configs["offenses_formatter"] || Formatters::DefaultOffensesFormatter::IDENTIFIER

if configs.key?("require")
configs["require"].each do |require_directive|
Expand All @@ -77,4 +77,6 @@ def cache_enabled?
@cache_enabled
end
end

private_constant :Configuration
end
2 changes: 2 additions & 0 deletions lib/packwerk/const_node_inspector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,6 @@ def fully_qualify_constant(ancestors)
"::" + NodeHelpers.parent_module_name(ancestors: ancestors)
end
end

private_constant :ConstNodeInspector
end
4 changes: 3 additions & 1 deletion lib/packwerk/constant_discovery.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def package_from_path(path)
# @param const_name [String] The unresolved constant's name.
# @param current_namespace_path [Array<String>] (optional) The namespace of the context in which the constant is
# used, e.g. ["Apps", "Models"] for `Apps::Models`. Defaults to [] which means top level.
# @return [Packwerk::ConstantDiscovery::ConstantContext]
# @return [ConstantDiscovery::ConstantContext]
sig do
params(
const_name: String,
Expand All @@ -74,4 +74,6 @@ def context_for(const_name, current_namespace_path: [])
)
end
end

private_constant :ConstantDiscovery
end
2 changes: 2 additions & 0 deletions lib/packwerk/constant_name_inspector.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ module ConstantNameInspector
end
def constant_name_from_node(node, ancestors:); end
end

private_constant :ConstantNameInspector
end
4 changes: 3 additions & 1 deletion lib/packwerk/file_processor.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ def references_from_ast(node, relative_file)
references = []

node_processor = @node_processor_factory.for(relative_file: relative_file, node: node)
node_visitor = Packwerk::NodeVisitor.new(node_processor: node_processor)
node_visitor = NodeVisitor.new(node_processor: node_processor)
node_visitor.visit(node, ancestors: [], result: references)

references
Expand All @@ -82,4 +82,6 @@ def parser_for(file_path)
@parser_factory.for_path(file_path)
end
end

private_constant :FileProcessor
end
2 changes: 2 additions & 0 deletions lib/packwerk/files_for_processing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -111,4 +111,6 @@ def relative_files_for_globs(relative_globs)
Set.new(relative_globs.flat_map { |glob| Dir[glob] })
end
end

private_constant :FilesForProcessing
end
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@

module Packwerk
module Formatters
class OffensesFormatter
include Packwerk::OffensesFormatter
class DefaultOffensesFormatter
include OffensesFormatter

IDENTIFIER = T.let("default", String)

Expand All @@ -20,7 +20,7 @@ def show_offenses(offenses)
EOS
end

sig { override.params(offense_collection: Packwerk::OffenseCollection, fileset: T::Set[String]).returns(String) }
sig { override.params(offense_collection: OffenseCollection, fileset: T::Set[String]).returns(String) }
def show_stale_violations(offense_collection, fileset)
if offense_collection.stale_violations?(fileset)
"There were stale violations found, please run `packwerk update-todo`"
Expand Down
2 changes: 1 addition & 1 deletion lib/packwerk/generators/configuration_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def initialize(root:, out: $stdout)
sig { returns(T::Boolean) }
def generate
@out.puts("📦 Generating Packwerk configuration file...")
default_config_path = File.join(@root, ::Packwerk::Configuration::DEFAULT_CONFIG_PATH)
default_config_path = File.join(@root, Configuration::DEFAULT_CONFIG_PATH)

if File.exist?(default_config_path)
@out.puts("⚠️ Packwerk configuration file already exists.")
Expand Down
Loading