Skip to content

Commit

Permalink
Draw deprecated references (#7)
Browse files Browse the repository at this point in the history
* Switch to using Packwerk’s root package constant

* Add method to list deprecated references for a package

* Move deprecated reference loading out into service

* Move specs across for DeprecatedReferencesLoader

* Add logic to draw deprecated references

* Update README with deprecated_references_color option
  • Loading branch information
samuelgiles authored Dec 10, 2020
1 parent 290c763 commit 1a72433
Show file tree
Hide file tree
Showing 10 changed files with 160 additions and 12 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
Unreleased

* Deprecated references are now drawn on the output graph.

1.1.0

* Default layout switched to Dot
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ graph = Graphwerk::Builders::Graph.new(
Packwerk::PackageSet.load_all_from("."),
options: {
layout: Graphwerk::Layout::Twopi,
deprecated_references_color: 'yellow',
graph: { overlap: true },
node: { fillcolor: '#000000' },
edges: { len: '3.0' }
Expand Down
1 change: 1 addition & 0 deletions lib/graphwerk.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require 'graphwerk/version'
require 'graphwerk/constants'
require 'graphwerk/layout'
require 'graphwerk/deprecated_references_loader'
require 'graphwerk/presenters/package'
require 'graphwerk/builders/graph'
require 'graphwerk/railtie' if defined?(Rails)
Expand Down
25 changes: 21 additions & 4 deletions lib/graphwerk/builders/graph.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ class Graph
OptionsShape = T.type_alias {
{
layout: Graphwerk::Layout,
deprecated_references_color: String,
application: T::Hash[Symbol, Object],
graph: T::Hash[Symbol, Object],
node: T::Hash[Symbol, Object],
Expand All @@ -18,6 +19,7 @@ class Graph

DEFAULT_OPTIONS = T.let({
layout: Graphwerk::Layout::Dot,
deprecated_references_color: 'red',
application: {
style: 'filled',
fillcolor: '#333333',
Expand All @@ -41,10 +43,11 @@ class Graph
}
}, OptionsShape)

sig { params(package_set: Packwerk::PackageSet, options: T::Hash[Symbol, Object]).void }
def initialize(package_set, options: {})
sig { params(package_set: Packwerk::PackageSet, options: T::Hash[Symbol, Object], root_path: Pathname).void }
def initialize(package_set, options: {}, root_path: Pathname.new(ENV['PWD']))
@package_set = package_set
@options = T.let(DEFAULT_OPTIONS.deep_merge(options), OptionsShape)
@root_path = root_path
@graph = T.let(build_empty_graph, GraphViz)
@nodes = T.let(build_empty_nodes, T::Hash[String, GraphViz::Node])
end
Expand Down Expand Up @@ -85,7 +88,10 @@ def setup_graph

sig { void }
def add_package_dependencies_to_graph
packages.each { |package| draw_dependencies(package) }
packages.each do |package|
draw_dependencies(package)
draw_deprecated_references(package)
end
end

sig { void }
Expand All @@ -102,10 +108,21 @@ def draw_dependencies(package)
end
end

sig { params(package: Presenters::Package).void }
def draw_deprecated_references(package)
package.deprecated_references.each do |reference|
@graph.add_edges(
@nodes[package.name],
@nodes[reference],
color: @options[:deprecated_references_color]
)
end
end

sig { returns(T::Array[Presenters::Package]) }
def packages
@packages = T.let(@packages, T.nilable(T::Array[Presenters::Package]))
@packages ||= @package_set.map { |package| Presenters::Package.new(package) }
@packages ||= @package_set.map { |package| Presenters::Package.new(package, @root_path) }
end
end
end
Expand Down
31 changes: 31 additions & 0 deletions lib/graphwerk/deprecated_references_loader.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# typed: strict
# frozen_string_literal: true

module Graphwerk
class DeprecatedReferencesLoader
extend T::Sig

sig { params(package: Packwerk::Package, root_path: Pathname).void }
def initialize(package, root_path)
@package = package
@root_path = root_path
end

sig { returns(T::Array[String]) }
def load
return [] if !deprecated_references_file.exist?

(YAML.load_file(deprecated_references_file) || {}).keys
end

private

DEPRECATED_REFERENCES_FILENAME = 'deprecated_references.yml'

sig { returns(Pathname) }
def deprecated_references_file
@deprecated_references_file = T.let(@deprecated_references_file, T.nilable(Pathname))
@deprecated_references_file ||= @root_path.join(@package.name, DEPRECATED_REFERENCES_FILENAME)
end
end
end
18 changes: 11 additions & 7 deletions lib/graphwerk/presenters/package.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,10 @@ module Presenters
class Package
extend T::Sig

sig { params(package: Packwerk::Package).void }
def initialize(package)
sig { params(package: Packwerk::Package, root_path: Pathname).void }
def initialize(package, root_path)
@package = package
@root_path = root_path
end

sig { returns(String) }
Expand All @@ -21,6 +22,13 @@ def dependencies
@package.dependencies.map { |dependency| Name.new(dependency).node_name }
end

sig { returns(T::Array[String]) }
def deprecated_references
DeprecatedReferencesLoader.new(@package, @root_path).load.map do |reference|
Name.new(reference).node_name
end
end

ROOT_COLOR = 'black'
COMPONENT_COLOR = 'azure4'

Expand Down Expand Up @@ -54,11 +62,9 @@ def node_name
Constants::ROOT_PACKAGE_NAME
end

ROOT_PACKAGE = '.'

sig { returns(T::Boolean) }
def root?
@package_name == ROOT_PACKAGE
@package_name == Packwerk::Package::ROOT_PACKAGE_NAME
end

private
Expand All @@ -67,8 +73,6 @@ def root?
def without_root_package
T.must(@package_name.split('/', 2).last)
end

private_constant :ROOT_PACKAGE
end

private_constant :ROOT_COLOR,
Expand Down
14 changes: 14 additions & 0 deletions spec/lib/graphwerk/builders/graph_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ module Builders
describe '#build' do
subject(:diagram) { builder.build.to_s }

let(:deprecated_references_loader_for_images) do
instance_double(DeprecatedReferencesLoader, load: ['.'])
end

before do
allow(DeprecatedReferencesLoader).to receive(:new).and_call_original
expect(DeprecatedReferencesLoader)
.to receive(:new)
.with(images_package, an_instance_of(Pathname))
.and_return(deprecated_references_loader_for_images)
end

specify do
expect(diagram).to eq <<~DOT
digraph "strict" {
Expand All @@ -64,6 +76,7 @@ module Builders
admin [color = "azure4", label = "admin"];
frontend -> images [color = "azure4"];
images -> "storage_providers/s3" [color = "azure4"];
images -> Application [color = "red"];
Application -> frontend [color = "black"];
Application -> admin [color = "black"];
}
Expand Down Expand Up @@ -96,6 +109,7 @@ module Builders
frontend -> images [color = "azure4"];
frontend -> Application [color = "azure4"];
images -> "storage_providers/s3" [color = "azure4"];
images -> Application [color = "red"];
Application -> frontend [color = "black"];
Application -> admin [color = "black"];
}
Expand Down
58 changes: 58 additions & 0 deletions spec/lib/graphwerk/deprecated_references_loader_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# typed: false
# frozen_string_literal: true

module Graphwerk
describe DeprecatedReferencesLoader do
let(:service) { described_class.new(package, root_path) }

let(:package) do
Packwerk::Package.new(
name: 'components/admin',
config: { 'dependencies' => ['components/security', 'components/orders'] }
)
end
let(:root_path) { Pathname.new('.') }

describe '#load' do
subject { service.load }

let(:deprecated_references_file) { instance_double(Pathname) }

before do
expect(root_path)
.to receive(:join)
.with('components/admin', 'deprecated_references.yml')
.and_return(deprecated_references_file)
expect(deprecated_references_file)
.to receive(:exist?)
.and_return(deprecated_dependency_file_is_present)
end

context 'when no deprecated dependency file is present' do
let(:deprecated_dependency_file_is_present) { false }

it { is_expected.to be_empty }
end

context 'when a deprecated dependency file is present' do
let(:deprecated_dependency_file_is_present) { true }

before do
expect(YAML)
.to receive(:load_file)
.with(deprecated_references_file)
.and_return(
'.' => {
"::Order" => {
"violations" => ["dependency"],
"files" => ["components/admin/interfaces/gateway.rb"]
}
}
)
end

it { is_expected.to contain_exactly('.') }
end
end
end
end
19 changes: 18 additions & 1 deletion spec/lib/graphwerk/presenters/package_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
module Graphwerk
module Presenters
describe Package do
let(:presenter) { described_class.new(package) }
let(:presenter) { described_class.new(package, root_path) }

let(:package) { child_package }
let(:root_path) { Pathname.new('.') }

let(:child_package) do
Packwerk::Package.new(
Expand Down Expand Up @@ -43,6 +44,22 @@ module Presenters
it { is_expected.to eq ['security', 'orders'] }
end

describe '#deprecated_references' do
subject { presenter.deprecated_references }

let(:deprecated_references_loader) { instance_double(DeprecatedReferencesLoader) }

before do
expect(DeprecatedReferencesLoader)
.to receive(:new)
.with(package, root_path)
.and_return(deprecated_references_loader)
expect(deprecated_references_loader).to receive(:load).and_return(['.'])
end

it { is_expected.to contain_exactly('Application') }
end

describe '#color' do
subject { presenter.color }

Expand Down
1 change: 1 addition & 0 deletions spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
config.example_status_persistence_file_path = '.rspec_status'

RSpec::Expectations.configuration.on_potential_false_positives = :nothing
RSpec::Sorbet.allow_doubles!
# Disable RSpec exposing methods globally on `Module` and `main`
# config.disable_monkey_patching!

Expand Down

0 comments on commit 1a72433

Please sign in to comment.