danger-packwerk 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (98) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +2 -2
  3. data/lib/danger-packwerk/check/default_formatter.rb +110 -0
  4. data/lib/danger-packwerk/check/offenses_formatter.rb +23 -0
  5. data/lib/danger-packwerk/danger_deprecated_references_yml_changes.rb +7 -5
  6. data/lib/danger-packwerk/danger_packwerk.rb +7 -5
  7. data/lib/danger-packwerk/packwerk_wrapper.rb +2 -2
  8. data/lib/danger-packwerk/private/ownership_information.rb +60 -0
  9. data/lib/danger-packwerk/private.rb +1 -1
  10. data/lib/danger-packwerk/update/default_formatter.rb +67 -0
  11. data/lib/danger-packwerk/update/offenses_formatter.rb +23 -0
  12. data/lib/danger-packwerk/version.rb +1 -1
  13. data/lib/danger-packwerk.rb +4 -0
  14. data/sorbet/config +1 -0
  15. data/sorbet/rbi/gems/actionview@7.0.4.rbi +11543 -0
  16. data/sorbet/rbi/gems/activesupport@7.0.4.rbi +12959 -0
  17. data/sorbet/rbi/gems/addressable@2.8.1.rbi +1505 -0
  18. data/sorbet/rbi/gems/ast@2.4.2.rbi +522 -0
  19. data/sorbet/rbi/gems/better_html@2.0.1.rbi +286 -0
  20. data/sorbet/rbi/gems/builder@3.2.4.rbi +8 -0
  21. data/sorbet/rbi/gems/claide-plugins@0.9.2.rbi +791 -0
  22. data/sorbet/rbi/gems/claide@1.1.0.rbi +1132 -0
  23. data/sorbet/rbi/gems/code_ownership@1.29.1.rbi +336 -0
  24. data/sorbet/rbi/gems/code_teams@1.0.0.rbi +120 -0
  25. data/sorbet/rbi/gems/coderay@1.1.3.rbi +2256 -0
  26. data/sorbet/rbi/gems/colored2@3.1.2.rbi +130 -0
  27. data/sorbet/rbi/gems/concurrent-ruby@1.1.10.rbi +8695 -0
  28. data/sorbet/rbi/gems/cork@0.3.0.rbi +248 -0
  29. data/sorbet/rbi/gems/crass@1.0.6.rbi +436 -0
  30. data/sorbet/rbi/gems/danger-plugin-api@1.0.0.rbi +8 -0
  31. data/sorbet/rbi/gems/danger@9.0.0.rbi +4722 -0
  32. data/sorbet/rbi/gems/diff-lcs@1.5.0.rbi +862 -0
  33. data/sorbet/rbi/gems/erubi@1.11.0.rbi +102 -0
  34. data/sorbet/rbi/gems/faraday-em_http@1.0.0.rbi +266 -0
  35. data/sorbet/rbi/gems/faraday-em_synchrony@1.0.0.rbi +209 -0
  36. data/sorbet/rbi/gems/faraday-excon@1.1.0.rbi +212 -0
  37. data/sorbet/rbi/gems/faraday-http-cache@2.4.1.rbi +805 -0
  38. data/sorbet/rbi/gems/faraday-httpclient@1.0.1.rbi +221 -0
  39. data/sorbet/rbi/gems/faraday-multipart@1.0.4.rbi +266 -0
  40. data/sorbet/rbi/gems/faraday-net_http@1.0.1.rbi +216 -0
  41. data/sorbet/rbi/gems/faraday-net_http_persistent@1.2.0.rbi +206 -0
  42. data/sorbet/rbi/gems/faraday-patron@1.0.0.rbi +212 -0
  43. data/sorbet/rbi/gems/faraday-rack@1.0.0.rbi +225 -0
  44. data/sorbet/rbi/gems/faraday-retry@1.0.3.rbi +222 -0
  45. data/sorbet/rbi/gems/faraday@1.10.2.rbi +1862 -0
  46. data/sorbet/rbi/gems/git@1.12.0.rbi +1936 -0
  47. data/sorbet/rbi/gems/i18n@1.12.0.rbi +1643 -0
  48. data/sorbet/rbi/gems/kramdown-parser-gfm@1.1.0.rbi +8 -0
  49. data/sorbet/rbi/gems/kramdown@2.4.0.rbi +2168 -0
  50. data/sorbet/rbi/gems/loofah@2.19.0.rbi +646 -0
  51. data/sorbet/rbi/gems/method_source@1.0.0.rbi +199 -0
  52. data/sorbet/rbi/gems/minitest@5.16.3.rbi +997 -0
  53. data/sorbet/rbi/gems/multipart-post@2.2.3.rbi +165 -0
  54. data/sorbet/rbi/gems/nap@1.1.0.rbi +351 -0
  55. data/sorbet/rbi/gems/no_proxy_fix@0.1.2.rbi +8 -0
  56. data/sorbet/rbi/gems/nokogiri@1.13.8.rbi +4916 -0
  57. data/sorbet/rbi/gems/octokit@5.6.1.rbi +8939 -0
  58. data/sorbet/rbi/gems/open4@1.3.4.rbi +8 -0
  59. data/sorbet/rbi/gems/{packwerk@2.1.1.rbi → packwerk@2.2.1.rbi} +602 -51
  60. data/sorbet/rbi/gems/parallel@1.22.1.rbi +163 -0
  61. data/sorbet/rbi/gems/parser@3.1.2.1.rbi +5988 -0
  62. data/sorbet/rbi/gems/pry@0.14.1.rbi +6969 -0
  63. data/sorbet/rbi/gems/public_suffix@5.0.0.rbi +779 -0
  64. data/sorbet/rbi/gems/racc@1.6.0.rbi +92 -0
  65. data/sorbet/rbi/gems/rails-dom-testing@2.0.3.rbi +8 -0
  66. data/sorbet/rbi/gems/rails-html-sanitizer@1.4.3.rbi +493 -0
  67. data/sorbet/rbi/gems/rainbow@3.1.1.rbi +227 -0
  68. data/sorbet/rbi/gems/rake@13.0.6.rbi +1865 -0
  69. data/sorbet/rbi/gems/rbi@0.0.14.rbi +2337 -0
  70. data/sorbet/rbi/gems/rchardet@1.8.0.rbi +587 -0
  71. data/sorbet/rbi/gems/regexp_parser@2.5.0.rbi +1851 -0
  72. data/sorbet/rbi/gems/rexml@3.2.5.rbi +3852 -0
  73. data/sorbet/rbi/gems/rspec-core@3.11.0.rbi +7725 -0
  74. data/sorbet/rbi/gems/rspec-expectations@3.11.0.rbi +6201 -0
  75. data/sorbet/rbi/gems/rspec-mocks@3.11.1.rbi +3625 -0
  76. data/sorbet/rbi/gems/rspec-support@3.11.0.rbi +1176 -0
  77. data/sorbet/rbi/gems/rspec@3.11.0.rbi +40 -0
  78. data/sorbet/rbi/gems/rubocop-ast@1.21.0.rbi +4193 -0
  79. data/sorbet/rbi/gems/rubocop-sorbet@0.6.8.rbi +677 -0
  80. data/sorbet/rbi/gems/rubocop@1.36.0.rbi +37914 -0
  81. data/sorbet/rbi/gems/ruby-progressbar@1.11.0.rbi +732 -0
  82. data/sorbet/rbi/gems/ruby2_keywords@0.0.5.rbi +8 -0
  83. data/sorbet/rbi/gems/sawyer@0.9.2.rbi +513 -0
  84. data/sorbet/rbi/gems/smart_properties@1.17.0.rbi +326 -0
  85. data/sorbet/rbi/gems/spoom@1.1.11.rbi +1600 -0
  86. data/sorbet/rbi/gems/tapioca@0.8.0.rbi +1959 -0
  87. data/sorbet/rbi/gems/terminal-table@3.0.2.rbi +438 -0
  88. data/sorbet/rbi/gems/thor@1.2.1.rbi +2921 -0
  89. data/sorbet/rbi/gems/tzinfo@2.0.5.rbi +4879 -0
  90. data/sorbet/rbi/gems/unicode-display_width@2.3.0.rbi +27 -0
  91. data/sorbet/rbi/gems/unparser@0.6.5.rbi +2789 -0
  92. data/sorbet/rbi/gems/webrick@1.7.0.rbi +1802 -0
  93. data/sorbet/rbi/gems/yard-sorbet@0.6.1.rbi +288 -0
  94. data/sorbet/rbi/gems/yard@0.9.27.rbi +12668 -0
  95. data/sorbet/rbi/todo.rbi +122 -0
  96. metadata +104 -8
  97. data/lib/danger-packwerk/private/default_offenses_formatter.rb +0 -37
  98. data/sorbet/rbi/gems/danger@8.5.0.rbi +0 -122
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '0118c3bc15c4a681dc290f557549e24451cd5c3fda714c8a29637ad791f77cfb'
4
- data.tar.gz: 716b2b0a13d4392cf8263abadca2620e241527c4874e25c93e9ad2b7baec57ee
3
+ metadata.gz: 0ad3f46c259911564eb4b955fb62e8152962db5c5682a6ba6000054dde9d8128
4
+ data.tar.gz: ef61b403058b20869cda462629724943317e55f5f4b1bfe125f9be7323a634c4
5
5
  SHA512:
6
- metadata.gz: ac00cad5d9241aec516693df310a0b97afd8da2bc59f0234d005ab9bc9ae1d3d781fa6c591f9267f03919327ef6f57dc16e2ef6d494d98d8e43acd205c9ef530
7
- data.tar.gz: 7043ca6402ac04d799dabe1ed8ddce3d4d239ebc6f818236e47b494faa9a5b3b52df1b6148e9a2d35e50788264c6735e70548a814ff12219cb080f2efbf953be
6
+ metadata.gz: cfc452185f83aef5f9ff5e53c475ac7472d7cfcda477a0a1f1fcc863704df6e93358a6e6096f5d4f1afb68176c687c8748a8c2c2562458c03bac47d120de91b4
7
+ data.tar.gz: '08df3f5e1d6e6d7367c3dc85f464346cf479dd13b5d831b26847b194f90190cb33e429c92095517124ae78eb0d23479c2a3b1146ab5a1ef529bfe967b9cf9192'
data/README.md CHANGED
@@ -83,11 +83,11 @@ Without any configuration, `deprecated_references_yml_changes.check` should just
83
83
  `deprecated_references_yml_changes.check` can be configured to in the following ways:
84
84
 
85
85
  ### Change the message that displays in the markdown
86
- The default message displayed is from `lib/danger-packwerk/private/default_offenses_formatter.rb`. To customize this this, pass in `added_offenses_formatter` to `deprecated_references_yml_changes.check` in your `Dangerfile`. Here's a simple example:
86
+ The default message displayed is from `lib/danger-packwerk/private/default_offenses_formatter.rb`. To customize this this, pass in `offenses_formatter` to `deprecated_references_yml_changes.check` in your `Dangerfile`. Here's a simple example:
87
87
  ```ruby
88
88
  deprecated_references_yml_changes.check(
89
89
  # Offenses are a T::Array[DangerPackwerk::BasicReferenceOffense]
90
- added_offenses_formatter: -> (added_offenses) do
90
+ offenses_formatter: -> (added_offenses) do
91
91
  "There are #{added_offenses.count} new violations this line!"
92
92
  end
93
93
  )
@@ -0,0 +1,110 @@
1
+ # typed: strict
2
+
3
+ require 'code_ownership'
4
+
5
+ module DangerPackwerk
6
+ module Check
7
+ class DefaultFormatter
8
+ include OffensesFormatter
9
+ extend T::Sig
10
+
11
+ sig do
12
+ params(
13
+ custom_help_message: T.nilable(String)
14
+ ).void
15
+ end
16
+ def initialize(custom_help_message: nil)
17
+ @custom_help_message = custom_help_message
18
+ end
19
+
20
+ sig do
21
+ override.params(
22
+ offenses: T::Array[Packwerk::ReferenceOffense],
23
+ repo_link: String,
24
+ org_name: String
25
+ ).returns(String)
26
+ end
27
+ def format_offenses(offenses, repo_link, org_name)
28
+ reference_offense = T.must(offenses.first)
29
+ violation_types = offenses.map(&:violation_type)
30
+ referencing_file = reference_offense.reference.relative_path
31
+ referencing_file_pack = ParsePackwerk.package_from_path(referencing_file).name
32
+ # We remove leading double colons as they feel like an implementation detail of packwerk.
33
+ constant_name = reference_offense.reference.constant.name.delete_prefix('::')
34
+
35
+ constant_source_package_name = reference_offense.reference.constant.package.name
36
+
37
+ constant_location = reference_offense.reference.constant.location
38
+ constant_source_package = T.must(ParsePackwerk.all.find { |p| p.name == constant_source_package_name })
39
+ constant_source_package_ownership_info = Private::OwnershipInformation.for_package(constant_source_package, org_name)
40
+
41
+ disclaimer = 'Before you run `bin/packwerk update-deprecations`, check out these quick suggestions:'
42
+ referencing_code_in_right_pack = "- Does the code you are writing live in the right pack?\n - If not, try `bin/packs move packs/destination_pack #{referencing_file}`"
43
+ referenced_code_in_right_pack = "- Does #{constant_name} live in the right pack?\n - If not, try `bin/packs move packs/destination_pack #{constant_location}`"
44
+ dependency_violation_message = "- Do we actually want to depend on #{constant_source_package_name}?\n - If so, try `bin/packs add_dependency #{referencing_file_pack} #{constant_source_package_name}`\n - If not, what can we change about the design so we do not have to depend on #{constant_source_package_name}?"
45
+ team_to_work_with = constant_source_package_ownership_info.owning_team ? constant_source_package_ownership_info.markdown_link_to_github_members_no_tag : 'the pack owner'
46
+ privacy_violation_message = "- Does API in #{constant_source_package.name}/public support this use case?\n - If not, can we work with #{team_to_work_with} to create and use a public API?\n - If `#{constant_name}` should already be public, try `bin/packs make_public #{constant_location}`."
47
+
48
+ if violation_types.include?(Packwerk::ViolationType::Dependency) && violation_types.include?(Packwerk::ViolationType::Privacy)
49
+ <<~MESSAGE
50
+ **Packwerk Violation**
51
+ - Type: Privacy :lock: + Dependency :knot:
52
+ - Constant: [<ins>`#{constant_name}`</ins>](#{repo_link}/blob/main/#{constant_location})
53
+ - Owning pack: #{constant_source_package_name}
54
+ #{constant_source_package_ownership_info.ownership_copy}
55
+
56
+ <details><summary>Quick suggestions :bulb:</summary>
57
+
58
+ #{disclaimer}
59
+ #{referencing_code_in_right_pack}
60
+ #{referenced_code_in_right_pack}
61
+ #{dependency_violation_message}
62
+ #{privacy_violation_message}
63
+
64
+ </details>
65
+
66
+ _#{@custom_help_message}_
67
+ MESSAGE
68
+ elsif violation_types.include?(Packwerk::ViolationType::Dependency)
69
+ <<~MESSAGE
70
+ **Packwerk Violation**
71
+ - Type: Dependency :knot:
72
+ - Constant: [<ins>`#{constant_name}`</ins>](#{repo_link}/blob/main/#{constant_location})
73
+ - Owning pack: #{constant_source_package_name}
74
+ #{constant_source_package_ownership_info.ownership_copy}
75
+
76
+ <details><summary>Quick suggestions :bulb:</summary>
77
+
78
+ #{disclaimer}
79
+ #{referencing_code_in_right_pack}
80
+ #{referenced_code_in_right_pack}
81
+ #{dependency_violation_message}
82
+
83
+ </details>
84
+
85
+ _#{@custom_help_message}_
86
+ MESSAGE
87
+ else # violation_types.include?(Packwerk::ViolationType::Privacy)
88
+ <<~MESSAGE
89
+ **Packwerk Violation**
90
+ - Type: Privacy :lock:
91
+ - Constant: [<ins>`#{constant_name}`</ins>](#{repo_link}/blob/main/#{constant_location})
92
+ - Owning pack: #{constant_source_package_name}
93
+ #{constant_source_package_ownership_info.ownership_copy}
94
+
95
+ <details><summary>Quick suggestions :bulb:</summary>
96
+
97
+ #{disclaimer}
98
+ #{referencing_code_in_right_pack}
99
+ #{referenced_code_in_right_pack}
100
+ #{privacy_violation_message}
101
+
102
+ </details>
103
+
104
+ _#{@custom_help_message}_
105
+ MESSAGE
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+
3
+ require 'code_ownership'
4
+
5
+ module DangerPackwerk
6
+ module Check
7
+ module OffensesFormatter
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ interface!
12
+
13
+ sig do
14
+ abstract.params(
15
+ offenses: T::Array[Packwerk::ReferenceOffense],
16
+ repo_link: String,
17
+ org_name: String
18
+ ).returns(String)
19
+ end
20
+ def format_offenses(offenses, repo_link, org_name); end
21
+ end
22
+ end
23
+ end
@@ -17,23 +17,25 @@ module DangerPackwerk
17
17
  # Therefore we hope to capture the majority case of people making changes to code while not spamming PRs that do a big rename.
18
18
  # We set a max (rather than unlimited) to avoid GitHub rate limiting and general spam if a PR does some sort of mass rename.
19
19
  DEFAULT_MAX_COMMENTS = 5
20
- AddedOffensesFormatter = T.type_alias { T.proc.params(added_violations: T::Array[BasicReferenceOffense]).returns(String) }
21
- DEFAULT_ADDED_OFFENSES_FORMATTER = T.let(->(added_violations) { Private::DefaultAddedOffensesFormatter.format(added_violations) }, AddedOffensesFormatter)
22
20
  BeforeComment = T.type_alias { T.proc.params(violation_diff: ViolationDiff, changed_deprecated_references_ymls: T::Array[String]).void }
23
21
  DEFAULT_BEFORE_COMMENT = T.let(->(violation_diff, changed_deprecated_references_ymls) {}, BeforeComment)
24
22
 
25
23
  sig do
26
24
  params(
27
- added_offenses_formatter: AddedOffensesFormatter,
25
+ offenses_formatter: T.nilable(Update::OffensesFormatter),
28
26
  before_comment: BeforeComment,
29
27
  max_comments: Integer
30
28
  ).void
31
29
  end
32
30
  def check(
33
- added_offenses_formatter: DEFAULT_ADDED_OFFENSES_FORMATTER,
31
+ offenses_formatter: nil,
34
32
  before_comment: DEFAULT_BEFORE_COMMENT,
35
33
  max_comments: DEFAULT_MAX_COMMENTS
36
34
  )
35
+ offenses_formatter ||= Update::DefaultFormatter.new
36
+ repo_link = github.pr_json[:base][:repo][:html_url]
37
+ org_name = github.pr_json[:base][:repo][:owner][:login]
38
+
37
39
  changed_deprecated_references_ymls = (git.modified_files + git.added_files + git.deleted_files).grep(DEPRECATED_REFERENCES_PATTERN)
38
40
 
39
41
  violation_diff = get_violation_diff
@@ -51,7 +53,7 @@ module DangerPackwerk
51
53
  location = T.must(violations.first).file_location
52
54
 
53
55
  markdown(
54
- added_offenses_formatter.call(violations),
56
+ offenses_formatter.format_offenses(violations, repo_link, org_name),
55
57
  line: location.line_number,
56
58
  file: location.file
57
59
  )
@@ -19,8 +19,6 @@ module DangerPackwerk
19
19
  DEFAULT_MAX_COMMENTS = 15
20
20
  OnFailure = T.type_alias { T.proc.params(offenses: T::Array[Packwerk::ReferenceOffense]).void }
21
21
  DEFAULT_ON_FAILURE = T.let(->(offenses) {}, OnFailure)
22
- OffensesFormatter = T.type_alias { T.proc.params(offenses: T::Array[Packwerk::ReferenceOffense]).returns(String) }
23
- DEFAULT_OFFENSES_FORMATTER = T.let(->(offenses) { offenses.map(&:message).join("\n\n") }, OffensesFormatter)
24
22
  DEFAULT_FAIL = false
25
23
  DEFAULT_FAILURE_MESSAGE = 'Packwerk violations were detected! Please resolve them to unblock the build.'
26
24
 
@@ -35,8 +33,8 @@ module DangerPackwerk
35
33
 
36
34
  sig do
37
35
  params(
36
+ offenses_formatter: T.nilable(Check::OffensesFormatter),
38
37
  max_comments: Integer,
39
- offenses_formatter: OffensesFormatter,
40
38
  fail_build: T::Boolean,
41
39
  failure_message: String,
42
40
  on_failure: OnFailure,
@@ -44,13 +42,17 @@ module DangerPackwerk
44
42
  ).void
45
43
  end
46
44
  def check(
45
+ offenses_formatter: nil,
47
46
  max_comments: DEFAULT_MAX_COMMENTS,
48
- offenses_formatter: DEFAULT_OFFENSES_FORMATTER,
49
47
  fail_build: DEFAULT_FAIL,
50
48
  failure_message: DEFAULT_FAILURE_MESSAGE,
51
49
  on_failure: DEFAULT_ON_FAILURE,
52
50
  grouping_strategy: CommentGroupingStrategy::PerConstantPerLocation
53
51
  )
52
+ offenses_formatter ||= Check::DefaultFormatter.new
53
+ repo_link = github.pr_json[:base][:repo][:html_url]
54
+ org_name = github.pr_json[:base][:repo][:owner][:login]
55
+
54
56
  # This is important because by default, Danger will leave a concantenated list of all its messages if it can't find a commentable place in the
55
57
  # diff to leave its message. This is an especially bad UX because it will be a huge wall of text not connected to the source of the issue.
56
58
  # Furthermore, dismissing these ensures that something like moving a file from pack to pack does not trigger the danger message. That is,
@@ -120,7 +122,7 @@ module DangerPackwerk
120
122
  line_number = reference_offense.location&.line
121
123
  referencing_file = reference_offense.reference.relative_path
122
124
 
123
- message = offenses_formatter.call(unique_packwerk_reference_offenses)
125
+ message = offenses_formatter.format_offenses(unique_packwerk_reference_offenses, repo_link, org_name)
124
126
 
125
127
  markdown(message, file: referencing_file, line: line_number)
126
128
  end
@@ -56,8 +56,8 @@ module DangerPackwerk
56
56
  ''
57
57
  end
58
58
 
59
- sig { override.params(offense_collection: Packwerk::OffenseCollection).returns(String) }
60
- def show_stale_violations(offense_collection)
59
+ sig { override.params(offense_collection: Packwerk::OffenseCollection, for_files: T::Set[String]).returns(String) }
60
+ def show_stale_violations(offense_collection, for_files)
61
61
  ''
62
62
  end
63
63
  end
@@ -0,0 +1,60 @@
1
+ # typed: strict
2
+
3
+ require 'code_ownership'
4
+
5
+ module DangerPackwerk
6
+ module Private
7
+ class OwnershipInformation < T::Struct
8
+ extend T::Sig
9
+
10
+ const :owning_team, T.nilable(CodeTeams::Team)
11
+ const :github_team, T.nilable(String)
12
+ const :slack_channel, T.nilable(String)
13
+ const :org_name, T.nilable(String)
14
+
15
+ sig { params(package: ParsePackwerk::Package, org_name: String).returns(OwnershipInformation) }
16
+ def self.for_package(package, org_name)
17
+ team = CodeOwnership.for_package(package)
18
+
19
+ if team.nil?
20
+ OwnershipInformation.new
21
+ else
22
+ OwnershipInformation.new(
23
+ owning_team: team,
24
+ github_team: team.raw_hash.fetch('github', {}).fetch('team', nil),
25
+ slack_channel: team.raw_hash.fetch('slack', {}).fetch('room_for_humans', nil),
26
+ org_name: org_name
27
+ )
28
+ end
29
+ end
30
+
31
+ sig { returns(String) }
32
+ def ownership_copy
33
+ github_team_flow_sensitive = github_team
34
+ slack_channel_flow_sensitive = slack_channel
35
+
36
+ if owning_team && github_team_flow_sensitive && slack_channel_flow_sensitive
37
+ team_slack_link = markdown_link_to_slack_room
38
+ "- Owned by #{markdown_link_to_github_members_no_tag} (Slack: #{team_slack_link})"
39
+ else
40
+ '- This pack is unowned.'
41
+ end
42
+ end
43
+
44
+ sig { returns(String) }
45
+ def markdown_link_to_slack_room
46
+ "[<ins>#{slack_channel}</ins>](https://slack.com/app_redirect?channel=#{T.must(slack_channel).delete('#')})"
47
+ end
48
+
49
+ #
50
+ # Note this will NOT tag the team on Github, but it will link
51
+ # to the mentioned team's members page. If you want to tag and
52
+ # link the team, simply use the string and Github will handle it.
53
+ #
54
+ sig { returns(String) }
55
+ def markdown_link_to_github_members_no_tag
56
+ "[<ins>#{github_team}</ins>](https://github.com/orgs/#{org_name}/teams/#{T.must(github_team).gsub("@#{org_name}/", '')}/members)"
57
+ end
58
+ end
59
+ end
60
+ end
@@ -1,7 +1,7 @@
1
1
  # typed: strict
2
2
 
3
3
  require 'danger-packwerk/private/deprecated_references'
4
- require 'danger-packwerk/private/default_offenses_formatter'
4
+ require 'danger-packwerk/private/ownership_information'
5
5
  require 'constant_resolver'
6
6
 
7
7
  module DangerPackwerk
@@ -0,0 +1,67 @@
1
+ # typed: strict
2
+
3
+ module DangerPackwerk
4
+ module Update
5
+ class DefaultFormatter
6
+ extend T::Sig
7
+ include OffensesFormatter
8
+
9
+ sig do
10
+ params(
11
+ custom_help_message: T.nilable(String)
12
+ ).void
13
+ end
14
+ def initialize(custom_help_message: nil)
15
+ @custom_help_message = custom_help_message
16
+ end
17
+
18
+ sig { override.params(offenses: T::Array[BasicReferenceOffense], repo_link: String, org_name: String).returns(String) }
19
+ def format_offenses(offenses, repo_link, org_name)
20
+ violation = T.must(offenses.first)
21
+ referencing_file_pack = ParsePackwerk.package_from_path(violation.file)
22
+ # We remove leading double colons as they feel like an implementation detail of packwerk.
23
+ constant_name = violation.class_name.delete_prefix('::')
24
+ constant_source_package_name = violation.to_package_name
25
+
26
+ constant_source_package = T.must(ParsePackwerk.find(constant_source_package_name))
27
+ constant_source_package_owner = Private::OwnershipInformation.for_package(constant_source_package, org_name)
28
+
29
+ package_referring_to_constant_owner = Private::OwnershipInformation.for_package(referencing_file_pack, org_name)
30
+
31
+ disclaimer = 'We noticed you ran `bin/packwerk update-deprecations`. Check out [the docs](https://github.com/Shopify/packwerk/blob/main/RESOLVING_VIOLATIONS.md) to see other ways to resolve violations.'
32
+ pluralized_violation = offenses.count > 1 ? 'these violations' : 'this violation'
33
+ request_to_add_context = "- Could you add some context as a reply here about why we needed to add #{pluralized_violation}?\n"
34
+
35
+ dependency_violation_message = "- cc #{package_referring_to_constant_owner.github_team} (#{package_referring_to_constant_owner.markdown_link_to_slack_room}) for the dependency violation.\n" if package_referring_to_constant_owner.owning_team
36
+
37
+ privacy_violation_message = "- cc #{constant_source_package_owner.github_team} (#{constant_source_package_owner.markdown_link_to_slack_room}) for the privacy violation.\n" if constant_source_package_owner.owning_team
38
+
39
+ if offenses.any?(&:dependency?) && offenses.any?(&:privacy?)
40
+ <<~MESSAGE.chomp
41
+ Hi again! It looks like `#{constant_name}` is private API of `#{constant_source_package_name}`, which is also not in `#{referencing_file_pack.name}`'s list of dependencies.
42
+ #{disclaimer}
43
+
44
+ #{request_to_add_context}#{dependency_violation_message}#{privacy_violation_message}
45
+ #{@custom_help_message}
46
+ MESSAGE
47
+ elsif offenses.any?(&:dependency?)
48
+ <<~MESSAGE.chomp
49
+ Hi again! It looks like `#{constant_name}` belongs to `#{constant_source_package_name}`, which is not in `#{referencing_file_pack.name}`'s list of dependencies.
50
+ #{disclaimer}
51
+
52
+ #{request_to_add_context}#{dependency_violation_message}
53
+ #{@custom_help_message}
54
+ MESSAGE
55
+ else # violations.any?(&:privacy?)
56
+ <<~MESSAGE.chomp
57
+ Hi again! It looks like `#{constant_name}` is private API of `#{constant_source_package_name}`.
58
+ #{disclaimer}
59
+
60
+ #{request_to_add_context}#{privacy_violation_message}
61
+ #{@custom_help_message}
62
+ MESSAGE
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,23 @@
1
+ # typed: strict
2
+
3
+ require 'code_ownership'
4
+
5
+ module DangerPackwerk
6
+ module Update
7
+ module OffensesFormatter
8
+ extend T::Sig
9
+ extend T::Helpers
10
+
11
+ interface!
12
+
13
+ sig do
14
+ abstract.params(
15
+ offenses: T::Array[BasicReferenceOffense],
16
+ repo_link: String,
17
+ org_name: String
18
+ ).returns(String)
19
+ end
20
+ def format_offenses(offenses, repo_link, org_name); end
21
+ end
22
+ end
23
+ end
@@ -2,5 +2,5 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  module DangerPackwerk
5
- VERSION = '0.7.0'
5
+ VERSION = '0.8.0'
6
6
  end
@@ -9,4 +9,8 @@ module DangerPackwerk
9
9
 
10
10
  require 'danger-packwerk/danger_packwerk'
11
11
  require 'danger-packwerk/danger_deprecated_references_yml_changes'
12
+ require 'danger-packwerk/check/offenses_formatter'
13
+ require 'danger-packwerk/check/default_formatter'
14
+ require 'danger-packwerk/update/offenses_formatter'
15
+ require 'danger-packwerk/update/default_formatter'
12
16
  end
data/sorbet/config CHANGED
@@ -1,3 +1,4 @@
1
1
  --dir
2
2
  .
3
3
  --enable-experimental-requires-ancestor
4
+ --ignore=/vendor/bundle