Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PVC Deprecations and configurable auto-correct #1635

Merged
merged 20 commits into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8af8a57
created yml file with schema and example, to represent PVC deprecations
mxriverlynn Nov 23, 2022
9a72228
updating the docs in the deprecations.yml file
mxriverlynn Nov 23, 2022
dc8d403
replacing example url with component name
mxriverlynn Nov 23, 2022
bc3f14c
corrected deprecations yml config for arrays
mxriverlynn Nov 23, 2022
a6349ba
first test to show deprecations working as expected
mxriverlynn Nov 23, 2022
c7bd5ca
finished first basic test of default deprecations, and updated deprec…
mxriverlynn Nov 23, 2022
15a2c7a
updated calls to deprecations
mxriverlynn Nov 23, 2022
0101aa6
rubocop
mxriverlynn Nov 25, 2022
445acd4
Merge remote-tracking branch 'origin/main' into mxriverlynn/autocorre…
mxriverlynn Nov 25, 2022
82d6730
added method to deprecations, to get list of deprecated components. c…
mxriverlynn Nov 25, 2022
922d6f6
added test to ensure all components with status :deprecated are liste…
mxriverlynn Nov 25, 2022
9fdcb3b
corrected rubocop tests
mxriverlynn Nov 25, 2022
98b251e
cleaning up lint
mxriverlynn Nov 25, 2022
5d0edf4
added changeset
mxriverlynn Nov 25, 2022
c65a2a0
remove guide related deprecation config for now
mxriverlynn Nov 25, 2022
a3c8a3d
workaround for css comments that contain and ampersand, due to a test…
mxriverlynn Nov 25, 2022
9182623
include build-assets in setup script
mxriverlynn Nov 25, 2022
039dec0
removed additional references to 'guide'
mxriverlynn Nov 25, 2022
e397d71
Merge remote-tracking branch 'origin/main' into mxriverlynn/autocorre…
mxriverlynn Nov 28, 2022
384d3dd
don't re-run build assets in setup
mxriverlynn Nov 28, 2022
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
5 changes: 5 additions & 0 deletions .changeset/neat-fireants-bake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@primer/view-components': patch
---

Converting deprecations list to a .yml file, and updating all code around deprecations to use this new structure
10 changes: 5 additions & 5 deletions app/components/primer/beta/popover.pcss
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@
}
}

/* Top & Bottom: Right-oriented carets */
/* Top and Bottom: Right-oriented carets */
.Popover-message--top-right,
.Popover-message--bottom-right {
right: -9px;
Expand All @@ -88,7 +88,7 @@
}
}

/* Top & Bottom: Left-oriented carets */
/* Top and Bottom: Left-oriented carets */
.Popover-message--top-left,
.Popover-message--bottom-left {
left: -9px;
Expand All @@ -105,7 +105,7 @@
}
}

/* Right- & Left-oriented carets */
/* Right- and Left-oriented carets */
.Popover-message--right,
.Popover-message--right-top,
.Popover-message--right-bottom,
Expand Down Expand Up @@ -159,7 +159,7 @@
}
}

/* Right & Left: Top-oriented carets */
/* Right and Left: Top-oriented carets */
.Popover-message--right-top,
.Popover-message--left-top {
&::before,
Expand All @@ -168,7 +168,7 @@
}
}

/* Right & Left: Bottom-oriented carets */
/* Right and Left: Bottom-oriented carets */
.Popover-message--right-bottom,
.Popover-message--left-bottom {
&::before,
Expand Down
4 changes: 4 additions & 0 deletions app/components/primer/component.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ class Component < ViewComponent::Base

INVALID_ARIA_LABEL_TAGS = [:div, :span, :p].freeze

def self.deprecated?
status == :deprecated
end

private

def raise_on_invalid_options?
Expand Down
70 changes: 44 additions & 26 deletions lib/primer/deprecations.rb
Original file line number Diff line number Diff line change
@@ -1,35 +1,53 @@
# frozen_string_literal: true

require "yaml"

module Primer
# :nodoc:
module Deprecations
# If there is no alternative to suggest, set the value to nil
DEPRECATED_COMPONENTS = {
"Primer::LabelComponent" => "Primer::Beta::Label",
"Primer::LinkComponent" => "Primer::Beta::Link",
"Primer::Alpha::AutoComplete" => "Primer::Beta::AutoComplete",
"Primer::Alpha::AutoComplete::Item" => "Primer::Beta::AutoComplete::Item",
"Primer::BlankslateComponent" => "Primer::Beta::Blankslate",
"Primer::BoxComponent" => "Primer::Box",
"Primer::DropdownMenuComponent" => nil,
"Primer::Dropdown" => "Primer::Alpha::Dropdown",
"Primer::Dropdown::Menu" => "Primer::Alpha::Dropdown::Menu",
"Primer::Dropdown::Menu::Item" => "Primer::Alpha::Dropdown::Menu::Item",
"Primer::IconButton" => "Primer::Beta::IconButton",
"Primer::Tooltip" => "Primer::Alpha::Tooltip",
"Primer::PopoverComponent" => "Primer::Beta::Popover"
}.freeze

def self.deprecated?(name)
DEPRECATED_COMPONENTS.key?(name)
end
class Deprecations
class << self
def register(file_path)
data = YAML.load_file(file_path)
data["deprecations"].each do |dep|
component = dep["component"]
deprecations[component] = {
autocorrect: dep["autocorrect"],
replacement: dep["replacement"]
}
end
end

def self.suggested_component(name)
DEPRECATED_COMPONENTS[name]
end
def deprecated_components
deprecations.keys.sort
end

def deprecated?(component_name)
# if the component is registered, it is deprecated
deprecations.key?(component_name)
end

def replacement(component_name)
dep = deprecations[component_name]
return nil if dep.nil?

def self.correctable?(name)
!suggested_component(name).nil?
dep[:replacement]
end

def correctable?(component_name)
dep = deprecations[component_name]
return false if dep.nil?

dep[:autocorrect]
end

private

def deprecations
@deprecations ||= {}
end
end

# auto-load PVC's deprecations
register(File.expand_path("deprecations.yml", __dir__))
end
end
84 changes: 84 additions & 0 deletions lib/primer/deprecations.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Primer ViewComponents Deprecation Configuration
#
# Schema
# ------
# - component: [string]
# autocorrect: [boolean]
# replacement: [string]
#
# Field Descriptions
# ------------------
# component:
# - Required
# - Type: string
# - The full ruby class of the deprecated component
#
# autocorrect:
# - Optional
# - Type: boolean
# - Default: false
# - Whether or not this deprecations can be autocorrected with `erblint -a`
#
# replacement:
# - Optional
# - Type: string
# - Default: nil
# - The full ruby class of the new component, if any, that replaces the now deprecated component
#
# Examples
# --------
# Please note that these examples are somewhat contrived, even if they match up to actual PVC components. They
# should be read as documentation only, and are not expected to be live. See the live configuration below the
# examples for the real list of deprecations.
#
# 1. An autocorrectable deprecation
#
# component: "Primer::LabelComponent"
# autocorrect: true
# replacement: "Primer::Beta::Label
#
# 2. A non-autocorrectable deprecation (no direct replacement component)
#
# component: "Primer::ButtonComponent"
# autocorrect: false

deprecations:
- component: "Primer::LabelComponent"
autocorrect: true
replacement: "Primer::Beta::Label"
- component: "Primer::LinkComponent"
autocorrect: true
replacement: "Primer::Beta::Link"
- component: "Primer::Alpha::AutoComplete"
autocorrect: true
replacement: "Primer::Beta::AutoComplete"
- component: "Primer::Alpha::AutoComplete::Item"
autocorrect: true
replacement: "Primer::Beta::AutoComplete::Item"
- component: "Primer::BlankslateComponent"
autocorrect: true
replacement: "Primer::Beta::Blankslate"
- component: "Primer::BoxComponent"
autocorrect: true
replacement: "Primer::Box"
- component: "Primer::DropdownMenuComponent"
autocorrect: false
replacement: "Primer::Beta::Dropdown"
- component: "Primer::Dropdown"
autocorrect: true
replacement: "Primer::Alpha::Dropdown"
- component: "Primer::Dropdown::Menu"
autocorrect: true
replacement: "Primer::Alpha::Dropdown::Menu"
- component: "Primer::Dropdown::Menu::Item"
autocorrect: true
replacement: "Primer::Alpha::Dropdown::Menu::Item"
- component: "Primer::IconButton"
autocorrect: true
replacement: "Primer::Beta::IconButton"
- component: "Primer::Tooltip"
autocorrect: true
replacement: "Primer::Alpha::Tooltip"
- component: "Primer::PopoverComponent"
autocorrect: true
replacement: "Primer::Beta::Popover"
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ def message(component)
message = "#{component} has been deprecated and should not be used."

if Primer::Deprecations.correctable?(component)
suggested_component = Primer::Deprecations.suggested_component(component)
message += " Try #{suggested_component} instead."
replacement = Primer::Deprecations.replacement(component)
message += " Try #{replacement} instead."
end

message
Expand Down
4 changes: 2 additions & 2 deletions lib/rubocop/cop/primer/component_name_migration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ def autocorrect(node)
component_name = node.const_name
return unless ::Primer::Deprecations.correctable?(component_name)

suggested_component = ::Primer::Deprecations.suggested_component(component_name)
corrector.replace(node, suggested_component) if suggested_component.present?
replacement = ::Primer::Deprecations.replacement(component_name)
corrector.replace(node, replacement) if replacement.present?
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion test/components/component_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def render_component(component, args, proc)

def test_deprecated_components_by_status_match_list
deprecated_by_status = Primer::ViewComponents::STATUSES.select { |_, value| value == "deprecated" }.keys.sort
deprecated_by_list = ::Primer::Deprecations::DEPRECATED_COMPONENTS.keys.sort
deprecated_by_list = ::Primer::Deprecations.deprecated_components

assert_empty(deprecated_by_status - deprecated_by_list, "Please make sure that components are officially deprecated by setting the `status :deprecated` within the component file.\nMake sure to provide an alternative component for each deprecated component in Primer::Deprecations::DEPRECATED_COMPONENTS (lib/primer/deprecations.rb). If there is no alternative to suggest, set the value to nil.")
end
Expand Down
36 changes: 36 additions & 0 deletions test/lib/deprecations_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# frozen_string_literal: true

require "lib/test_helper"
Dir["app/components/**/*.rb"].each { |file| require_relative "../../#{file}" }

class DeprecationsTest < Minitest::Test
def setup
@deprecated_components = Primer::Deprecations.deprecated_components
end

def test_default_deprecations_are_loaded
component = "Primer::BlankslateComponent"
replacement = "Primer::Beta::Blankslate"

assert Primer::Deprecations.deprecated?(component)
assert Primer::Deprecations.correctable?(component)
assert_equal Primer::Deprecations.replacement(component), replacement
end

# ensure all components that has `status: :deprecated` are listed in the
# component deprecations configuration file
Primer::Component.descendants.each do |component_class|
class_test_name = component_class.name.downcase.gsub("::", "_")
define_method("test_ensure_#{class_test_name}_is_properly_deprecated") do
if component_class.deprecated? # rubocop:disable Style/IfUnlessModifier
assert @deprecated_components.include?(component_class.name), missing_deprecation_message(component_class)
end
end
end

private

def missing_deprecation_message(component_class)
"PVC Component '#{component_class.name}' has a `status` of `:deprected`, but is not listed in the deprecations.yml file. Please update the deprecations configuration in `lib/primer/deprecations.yml`"
end
end
9 changes: 2 additions & 7 deletions test/lib/rubocop/component_name_migration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,11 @@ def test_no_deprecated_classes
end

def test_using_deprecated_class
original_list = Primer::Deprecations::DEPRECATED_COMPONENTS
Primer::Deprecations.const_set("DEPRECATED_COMPONENTS", { "Primer::TestComponent" => "Primer::Beta::Test" })

investigate(cop, <<-RUBY)
Primer::TestComponent.new
Primer::BlankslateComponent.new
RUBY

assert_equal 1, cop.offenses.count
assert_equal "Primer::Beta::Test.new", cop.offenses.first.corrector.rewrite.strip
ensure
Primer::Deprecations.const_set("DEPRECATED_COMPONENTS", original_list)
assert_equal "Primer::Beta::Blankslate.new", cop.offenses.first.corrector.rewrite.strip
end
end