rubocop-openproject 0.6.0 → 0.7.0

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: b6399b37d75f31159de26fc061439ab6107f3621da14770ab2e3f4a263e4748e
4
+ data.tar.gz: c0bc045863a214c19a10fe29e4b23edd6d60f3598158f665fdfb4fefba851946
5
5
  SHA512:
6
- metadata.gz: 20ea7aec95cb84472a6e145dfc71e31a542a3cda8e6a126ea5f6adf8832c6852aff30d506c624bb930fca6ef4a2fb324ecf777b88a2afb3d7d9e2e227c7a436e
7
- data.tar.gz: 240bcf2a89496e23e73ca909171b754eb92e417bb86d67c07cf3dc2415ca1404879d59fabff2c829bec58d40484b8c49e833a719749c95a2b1b1828b5b0de294
6
+ metadata.gz: 5089a09294d79954f16b4fe511fd6b3aabe57b9272ebf41fa4a376feb7a6fcf8c2872b072fd6e3c7eb8493484e0e5b3eb2dc88f2bbfb964fa5fb67f0cdd8e5d8
7
+ data.tar.gz: 46759bc28c398aeefb4fb18305dd9494056a5296a859bb7789d4c37548b785a935a254f0cfcc98442cccceeb70fc5a788113316b3c58707dc0172506ab6462e0
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 4.0.2
1
+ 4.0.6
data/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # rubocop-openproject
2
2
 
3
+ ## 0.7.0
4
+
5
+ ### Minor Changes
6
+
7
+ - ad3ff98: Add `OpenProject/UseEffectiveTypeForConfiguration` cop to catch reading a type's
8
+ configuration off `#type` instead of `#effective_type`. A work package stores the root of its
9
+ type family while its project may resolve that family to a variant configured differently, so
10
+ reading an aspect (form configuration, workflows, custom fields, defaults, export templates)
11
+ off the stored type silently answers with the root's configuration. The failure is quiet — a
12
+ project running the root behaves correctly, so a spec written without a variant passes while
13
+ the feature is broken wherever a variant is resolved. Inherited core settings (`name`,
14
+ `color`, `is_milestone`, `is_in_roadmap`) are read from the root by design and are not flagged.
15
+
3
16
  ## 0.6.0
4
17
 
5
18
  ### 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,84 @@
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
+ # # good
38
+ # work_package.effective_type.attribute_groups
39
+ #
40
+ # # good — when there is no work package to ask
41
+ # project.effective_type(type).attribute_groups
42
+ #
43
+ # # good — inherited from the root by design
44
+ # work_package.type.name
45
+ # work_package.type.is_milestone?
46
+ #
47
+ # # good — administration reads a specific member's own configuration
48
+ # @type.attribute_groups
49
+ class UseEffectiveTypeForConfiguration < Base
50
+ MSG = "Read configuration through `effective_type`, not `type` — the stored type is " \
51
+ "the family's root, so this ignores the variant the project resolves to."
52
+
53
+ # Configuration aspects, per Type::ConfigurationLink::ASPECTS and the readers
54
+ # Type::ConfigurationLinkable resolves through the link chain.
55
+ CONFIGURATION_METHODS = %i[
56
+ artefact_export_enabled?
57
+ artefact_export_mode
58
+ attribute_groups
59
+ custom_field_ids
60
+ custom_fields
61
+ description
62
+ export_templates_disabled
63
+ export_templates_order
64
+ patterns
65
+ project_custom_field_type_mappings
66
+ statuses
67
+ workflows
68
+ ].freeze
69
+
70
+ RESTRICT_ON_SEND = CONFIGURATION_METHODS
71
+
72
+ def_node_matcher :type_call?, <<~PATTERN
73
+ (send _ :type)
74
+ PATTERN
75
+
76
+ def on_send(node)
77
+ return unless type_call?(node.receiver)
78
+
79
+ add_offense(node)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ 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.0"
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.0
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: []