rubocop-openproject 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 821ee2f0425e32049c380dd582471e37feb47c8565b1a8b05e2746809e498993
4
- data.tar.gz: b8c1b464b25dbb3f0c07dcd5d7f20fd8bd331b91565f31782c7d27920a6148be
3
+ metadata.gz: ddc09cf55b857f7ce9d1f944be04ad89fca8733ed2ee571e7a21e61ee0b93531
4
+ data.tar.gz: 597940571a0def133a1e4c22ba02fc5f277b4e69b43e72be0ae8e63ad2b3959b
5
5
  SHA512:
6
- metadata.gz: 20ea7aec95cb84472a6e145dfc71e31a542a3cda8e6a126ea5f6adf8832c6852aff30d506c624bb930fca6ef4a2fb324ecf777b88a2afb3d7d9e2e227c7a436e
7
- data.tar.gz: 240bcf2a89496e23e73ca909171b754eb92e417bb86d67c07cf3dc2415ca1404879d59fabff2c829bec58d40484b8c49e833a719749c95a2b1b1828b5b0de294
6
+ metadata.gz: 7b4b3c182974ae3030781217c2a1c37abdff29b21398a1b9644806c36d55b81ec6ec1d22af6d7e44dead45a5ce3950d394a73ab361d15c15834562a67a443296
7
+ data.tar.gz: cefcaa216a26645a8ca75e6caedae544462cd411bd5b298d0d80b24e0502680075c5bf3ad4bf4b8e3e8d3054ab416c14408b87af9a841eb3950656e488ef3aef
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 4.0.2
1
+ 4.0.6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,33 @@
1
1
  # rubocop-openproject
2
2
 
3
+ ## 0.7.1
4
+
5
+ ### Patch Changes
6
+
7
+ - 2e41102: Widen `OpenProject/UseEffectiveTypeForConfiguration` to catch safe navigation and the derived
8
+ pattern readers. The cop only defined `on_send`, so `represented.type&.attribute_groups` parsed
9
+ as a `csend` and slipped through entirely — which is how the whole work package schema
10
+ representer read its form configuration off the root while the cop was enabled. Both sides of
11
+ the call are now matched as `send` or `csend`. `enabled_patterns` and
12
+ `replacement_pattern_defined_for?` join `CONFIGURATION_METHODS`: both resolve through
13
+ `patterns`, which a variant can own independently, so they are as variant-specific as the
14
+ aspect readers already listed.
15
+
16
+ Expect new offenses in consumers wherever a configuration aspect was read off `type` with `&.`.
17
+
18
+ ## 0.7.0
19
+
20
+ ### Minor Changes
21
+
22
+ - ad3ff98: Add `OpenProject/UseEffectiveTypeForConfiguration` cop to catch reading a type's
23
+ configuration off `#type` instead of `#effective_type`. A work package stores the root of its
24
+ type family while its project may resolve that family to a variant configured differently, so
25
+ reading an aspect (form configuration, workflows, custom fields, defaults, export templates)
26
+ off the stored type silently answers with the root's configuration. The failure is quiet — a
27
+ project running the root behaves correctly, so a spec written without a variant passes while
28
+ the feature is broken wherever a variant is resolved. Inherited core settings (`name`,
29
+ `color`, `is_milestone`, `is_in_roadmap`) are read from the root by design and are not flagged.
30
+
3
31
  ## 0.6.0
4
32
 
5
33
  ### Minor Changes
data/config/default.yml CHANGED
@@ -23,6 +23,11 @@ OpenProject/NoSleepInFeatureSpecs:
23
23
  Enabled: true
24
24
  VersionAdded: '0.1.0'
25
25
 
26
+ OpenProject/UseEffectiveTypeForConfiguration:
27
+ Description: 'Read a type''s configuration through `effective_type`, not `type`, so the project''s variant is honoured.'
28
+ Enabled: true
29
+ VersionAdded: '0.7.0'
30
+
26
31
  OpenProject/UseRenderModeInsteadOfPrimitives:
27
32
  Description: 'Use `render_mode:` instead of `static_html:`/`plain_text:`/`only_path:` on `format_text`.'
28
33
  Enabled: true
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module OpenProject
6
+ # Flags reading a type's configuration off `#type` rather than `#effective_type`.
7
+ #
8
+ # A work package stores the root of its type family, while the project it lives in may
9
+ # resolve that family to a variant configured differently — a different form
10
+ # configuration, workflow, set of custom fields, defaults or export templates. Reading a
11
+ # configuration aspect off the stored type therefore answers with the root's
12
+ # configuration and silently ignores the variant.
13
+ #
14
+ # The failure mode is quiet: a project running the root behaves correctly, so a spec
15
+ # written without a variant passes while the feature is broken for every project that
16
+ # resolves one. That is what this cop is here to catch.
17
+ #
18
+ # Only configuration aspects are flagged. `name`, `color`, `is_milestone` and
19
+ # `is_in_roadmap` are inherited from the root by design, so reading those off `#type` is
20
+ # correct and left alone.
21
+ #
22
+ # Deliberately narrow: it fires when the receiver is literally a `type` call, which is
23
+ # the shape the mistake takes in practice. Administration code holding an explicit type
24
+ # (`@type.attribute_groups`) is reading that member's own configuration on purpose and is
25
+ # not flagged, and neither is a type held in a local variable.
26
+ #
27
+ # @example
28
+ # # bad
29
+ # work_package.type.attribute_groups
30
+ #
31
+ # # bad
32
+ # work_package.type.custom_fields
33
+ #
34
+ # # bad — inside WorkPackage itself
35
+ # type.statuses(include_default: true)
36
+ #
37
+ # # bad — safe navigation on either side reads the root just the same
38
+ # represented.type&.attribute_groups
39
+ # model&.type.enabled_patterns
40
+ #
41
+ # # good
42
+ # work_package.effective_type.attribute_groups
43
+ #
44
+ # # good — when there is no work package to ask
45
+ # project.effective_type(type).attribute_groups
46
+ #
47
+ # # good — inherited from the root by design
48
+ # work_package.type.name
49
+ # work_package.type.is_milestone?
50
+ #
51
+ # # good — administration reads a specific member's own configuration
52
+ # @type.attribute_groups
53
+ class UseEffectiveTypeForConfiguration < Base
54
+ MSG = "Read configuration through `effective_type`, not `type` — the stored type is " \
55
+ "the family's root, so this ignores the variant the project resolves to."
56
+
57
+ # Configuration aspects, per Type::ConfigurationLink::ASPECTS and the readers
58
+ # Type::ConfigurationLinkable resolves through the link chain, plus the derived readers
59
+ # that sit on top of one — `enabled_patterns` and `replacement_pattern_defined_for?`
60
+ # both resolve through `patterns` and are just as variant-specific.
61
+ CONFIGURATION_METHODS = %i[
62
+ artefact_export_enabled?
63
+ artefact_export_mode
64
+ attribute_groups
65
+ custom_field_ids
66
+ custom_fields
67
+ description
68
+ enabled_patterns
69
+ export_templates_disabled
70
+ export_templates_order
71
+ patterns
72
+ project_custom_field_type_mappings
73
+ replacement_pattern_defined_for?
74
+ statuses
75
+ workflows
76
+ ].freeze
77
+
78
+ RESTRICT_ON_SEND = CONFIGURATION_METHODS
79
+
80
+ # Both node types on both sides: `type&.attribute_groups` reads the root exactly like
81
+ # `type.attribute_groups` does, and the mistake is written with `&.` at least as often.
82
+ def_node_matcher :type_call?, <<~PATTERN
83
+ ({send csend} _ :type)
84
+ PATTERN
85
+
86
+ def on_send(node)
87
+ return unless type_call?(node.receiver)
88
+
89
+ add_offense(node)
90
+ end
91
+ alias on_csend on_send
92
+ end
93
+ end
94
+ end
95
+ end
@@ -5,4 +5,5 @@ require_relative "open_project/no_not_implemented_error"
5
5
  require_relative "open_project/no_params_in_work_package_where_id"
6
6
  require_relative "open_project/use_service_result_factory_methods"
7
7
  require_relative "open_project/no_sleep_in_feature_specs"
8
+ require_relative "open_project/use_effective_type_for_configuration"
8
9
  require_relative "open_project/use_render_mode_instead_of_primitives"
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RuboCop
4
4
  module OpenProject
5
- VERSION = "0.6.0"
5
+ VERSION = "0.7.1"
6
6
  end
7
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop-openproject
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - OpenProject GmbH
@@ -43,6 +43,7 @@ files:
43
43
  - lib/rubocop/cop/open_project/no_not_implemented_error.rb
44
44
  - lib/rubocop/cop/open_project/no_params_in_work_package_where_id.rb
45
45
  - lib/rubocop/cop/open_project/no_sleep_in_feature_specs.rb
46
+ - lib/rubocop/cop/open_project/use_effective_type_for_configuration.rb
46
47
  - lib/rubocop/cop/open_project/use_render_mode_instead_of_primitives.rb
47
48
  - lib/rubocop/cop/open_project/use_service_result_factory_methods.rb
48
49
  - lib/rubocop/cop/open_project_cops.rb
@@ -71,7 +72,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
71
72
  - !ruby/object:Gem::Version
72
73
  version: '0'
73
74
  requirements: []
74
- rubygems_version: 4.0.6
75
+ rubygems_version: 4.0.16
75
76
  specification_version: 4
76
77
  summary: RuboCop cops for OpenProject
77
78
  test_files: []