gitlab_support_readiness 1.0.11 → 1.0.13

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/lib/support_readiness/calendly/client.rb +64 -0
  3. data/lib/support_readiness/calendly/configuration.rb +45 -0
  4. data/lib/support_readiness/calendly/organization_memberships.rb +67 -0
  5. data/lib/support_readiness/calendly/organizations.rb +123 -0
  6. data/lib/support_readiness/calendly/users.rb +105 -0
  7. data/lib/support_readiness/calendly.rb +16 -0
  8. data/lib/support_readiness/client.rb +88 -1
  9. data/lib/support_readiness/dates.rb +90 -0
  10. data/lib/support_readiness/gitlab/configuration.rb +0 -1
  11. data/lib/support_readiness/gitlab/groups.rb +35 -0
  12. data/lib/support_readiness/gitlab/jobs.rb +189 -0
  13. data/lib/support_readiness/gitlab/markdown.rb +37 -0
  14. data/lib/support_readiness/gitlab/merge_requests.rb +127 -0
  15. data/lib/support_readiness/gitlab/namespaces.rb +22 -0
  16. data/lib/support_readiness/gitlab/pipelines.rb +191 -0
  17. data/lib/support_readiness/gitlab/projects.rb +85 -1
  18. data/lib/support_readiness/gitlab/repositories.rb +174 -0
  19. data/lib/support_readiness/gitlab/users.rb +24 -0
  20. data/lib/support_readiness/gitlab.rb +4 -0
  21. data/lib/support_readiness/google_calendar/client.rb +59 -0
  22. data/lib/support_readiness/google_calendar/configuration.rb +39 -0
  23. data/lib/support_readiness/google_calendar/events.rb +169 -0
  24. data/lib/support_readiness/google_calendar.rb +14 -0
  25. data/lib/support_readiness/mailgun/bounces.rb +103 -0
  26. data/lib/support_readiness/mailgun/client.rb +65 -0
  27. data/lib/support_readiness/mailgun/configuration.rb +46 -0
  28. data/lib/support_readiness/mailgun/emails.rb +95 -0
  29. data/lib/support_readiness/mailgun.rb +15 -0
  30. data/lib/support_readiness/pagerduty/escalation_policies.rb +1 -1
  31. data/lib/support_readiness/pagerduty/schedules.rb +27 -3
  32. data/lib/support_readiness/pagerduty/services.rb +1 -1
  33. data/lib/support_readiness/pagerduty/users.rb +197 -0
  34. data/lib/support_readiness/pagerduty.rb +1 -0
  35. data/lib/support_readiness/repos/articles.rb +335 -0
  36. data/lib/support_readiness/repos/automations.rb +247 -0
  37. data/lib/support_readiness/repos/groups.rb +188 -0
  38. data/lib/support_readiness/repos/macros.rb +224 -0
  39. data/lib/support_readiness/repos/organization_fields.rb +193 -0
  40. data/lib/support_readiness/repos/sla_policies.rb +192 -0
  41. data/lib/support_readiness/repos/ticket_fields.rb +200 -0
  42. data/lib/support_readiness/repos/ticket_forms.rb +200 -0
  43. data/lib/support_readiness/repos/triggers.rb +255 -0
  44. data/lib/support_readiness/repos/user_fields.rb +201 -0
  45. data/lib/support_readiness/repos/views.rb +362 -0
  46. data/lib/support_readiness/repos.rb +22 -0
  47. data/lib/support_readiness/salesforce/accounts.rb +109 -0
  48. data/lib/support_readiness/salesforce/cases.rb +109 -0
  49. data/lib/support_readiness/salesforce/client.rb +64 -0
  50. data/lib/support_readiness/salesforce/configuration.rb +49 -0
  51. data/lib/support_readiness/salesforce/queries.rb +62 -0
  52. data/lib/support_readiness/salesforce.rb +16 -0
  53. data/lib/support_readiness/slack/client.rb +63 -0
  54. data/lib/support_readiness/slack/configuration.rb +43 -0
  55. data/lib/support_readiness/slack/messages.rb +37 -0
  56. data/lib/support_readiness/slack.rb +14 -0
  57. data/lib/support_readiness/zendesk/app_job_statuses.rb +140 -0
  58. data/lib/support_readiness/zendesk/apps.rb +209 -0
  59. data/lib/support_readiness/zendesk/automations.rb +1 -2
  60. data/lib/support_readiness/zendesk/macros.rb +1 -3
  61. data/lib/support_readiness/zendesk/organization_fields.rb +1 -1
  62. data/lib/support_readiness/zendesk/theme_job_statuses.rb +136 -0
  63. data/lib/support_readiness/zendesk/themes.rb +303 -0
  64. data/lib/support_readiness/zendesk/ticket_field_options.rb +110 -0
  65. data/lib/support_readiness/zendesk/ticket_fields.rb +85 -16
  66. data/lib/support_readiness/zendesk/ticket_forms.rb +65 -2
  67. data/lib/support_readiness/zendesk/tickets.rb +77 -0
  68. data/lib/support_readiness/zendesk/triggers.rb +1 -2
  69. data/lib/support_readiness/zendesk/user_field_options.rb +110 -0
  70. data/lib/support_readiness/zendesk/user_fields.rb +257 -0
  71. data/lib/support_readiness/zendesk/views.rb +49 -2
  72. data/lib/support_readiness/zendesk.rb +7 -0
  73. data/lib/support_readiness.rb +16 -0
  74. metadata +122 -2
@@ -0,0 +1,255 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module Readiness.
4
+ module Readiness
5
+ # Defines the module Repos
6
+ module Repos
7
+ ##
8
+ # Defines the class Triggers within the module {Readiness::Repos}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.12
12
+ class Triggers < Readiness::Client
13
+ ##
14
+ # Compares the repo trigger files to the Zendesk instance triggers
15
+ #
16
+ # @author Jason Colyer
17
+ # @since 1.0.12
18
+ # @param zendesk_client [Object] An instance of {Readiness::Zendesk::Client}
19
+ # @param location [String] The location (relative or absolute) of the repo's data folder
20
+ # @param verbose [Boolean] Whether you want a detailed report or not
21
+ # @return [Hash]
22
+ # @example
23
+ # require 'support_readiness'
24
+ # config = Readiness::Zendesk::Configuration.new
25
+ # config.username = 'alice@example.com'
26
+ # config.token = 'test123abc'
27
+ # config.url = 'https://example.zendesk.com/api/v2'
28
+ # client = Readiness::Zendesk::Client.new(config)
29
+ # diffs = Readiness::Repos::Triggers.compare(client, 'triggers/data', false)
30
+ # pp diffs[:updates.count]
31
+ # # => 5
32
+ # @example
33
+ # require 'support_readiness'
34
+ # config = Readiness::Zendesk::Configuration.new
35
+ # config.username = 'alice@example.com'
36
+ # config.token = 'test123abc'
37
+ # config.url = 'https://example.zendesk.com/api/v2'
38
+ # client = Readiness::Zendesk::Client.new(config)
39
+ # diffs = Readiness::Repos::Triggers.compare(client, 'triggers/data', true)
40
+ # # => Detailed diff of Cleanup followup tickets
41
+ # # => - @position Repo:
42
+ # # => 13
43
+ # # => @position Zendesk:
44
+ # # => 12
45
+ # # => Detailed diff of New Billing ticket created via Webform
46
+ # # => - @position Repo:
47
+ # # => 11
48
+ # # => @position Zendesk:
49
+ # # => 10
50
+ # # => Compare report:
51
+ # # => - Creates: 0
52
+ # # => - Updates: 2
53
+ # pp diffs[:updates.count]
54
+ # # => 2
55
+ def self.compare(zendesk_client, location = 'data', verbose = false)
56
+ diffs = {
57
+ updates: [],
58
+ creates: []
59
+ }
60
+ from_repo = gather(location)
61
+ from_zendesk = Zendesk::Triggers.list(zendesk_client)
62
+ from_repo.each do |repo|
63
+ zd = from_zendesk.detect { |z| z.title == repo.title }
64
+ if zd.nil?
65
+ diffs[:creates].push(repo)
66
+ else
67
+ comparable = zd.dup
68
+ comparable.id = nil
69
+ diffs[:updates].push(update_object(repo, zd)) if to_clean_json(repo) != to_clean_json(comparable)
70
+ detailed_diff(repo, comparable) if verbose && to_clean_json(repo) != to_clean_json(comparable)
71
+ end
72
+ end
73
+ report_diffs(diffs) if verbose
74
+ diffs
75
+ end
76
+
77
+ ##
78
+ # Outputs a comparison report
79
+ #
80
+ # @author Jason Colyer
81
+ # @since 1.0.12
82
+ # @param diffs [Hash] The returned value of {compare}
83
+ def self.report_diffs(diffs)
84
+ puts 'Compare report:'
85
+ puts "- Creates: #{diffs[:creates].count}"
86
+ puts "- Updates: #{diffs[:updates].count}"
87
+ end
88
+
89
+ ##
90
+ # Outputs a comparison report
91
+ #
92
+ # @author Jason Colyer
93
+ # @since 1.0.12
94
+ # @param repo [Object] An instance of {Readiness::Zendesk::Triggers}
95
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::Triggers}
96
+ def self.detailed_diff(repo, zendesk)
97
+ puts "Detailed diff of #{repo.title}"
98
+ repo.instance_variables.each do |v|
99
+ next if v == :@id
100
+
101
+ if repo.instance_variable_get(v) != zendesk.instance_variable_get(v)
102
+ puts "- #{v} Repo:"
103
+ pp repo.instance_variable_get(v)
104
+ puts " #{v} Zendesk:"
105
+ pp zendesk.instance_variable_get(v)
106
+ end
107
+ end
108
+ end
109
+
110
+ ##
111
+ # Creates an instance of {Readiness::Zendesk::Triggers} to use for updates
112
+ #
113
+ # @author Jason Colyer
114
+ # @since 1.0.12
115
+ # @param repo [Object] An instance of {Readiness::Zendesk::Triggers}
116
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::Triggers}
117
+ # @return [Object]
118
+ def self.update_object(repo, zendesk)
119
+ object = repo
120
+ object.id = zendesk.id
121
+ object
122
+ end
123
+
124
+ ##
125
+ # Parses repo trigger files
126
+ #
127
+ # @author Jason Colyer
128
+ # @since 1.0.12
129
+ # @param location [String] The location (relative or absolute) of the repo's data folder
130
+ # @return [Array]
131
+ # @example
132
+ # require 'support_readiness'
133
+ # repo = Readiness::Repos::Triggers.gather('triggers/data')
134
+ # pp repo.count
135
+ # # => 35
136
+ def self.gather(location = 'data')
137
+ @errors = []
138
+ @location = location
139
+ array = []
140
+ Dir["#{@location}/**/*.yaml"].each do |f|
141
+ object = YAML.safe_load_file(f)
142
+ object = convert_managed_content(object, f) if object['contains_managed_content']
143
+ object['default'] = false
144
+ #object = convert_managed_webhook(object, f) if object['contains_managed_webhook']
145
+ validity_check(f, object)
146
+ object['id'] = nil
147
+ array.push(Zendesk::Triggers.new(object))
148
+ end
149
+ repo_check(array)
150
+ report_errors unless @errors.count.zero?
151
+ array
152
+ end
153
+
154
+ ##
155
+ # Outputs an error report and exits with a status code of 1
156
+ #
157
+ # @author Jason Colyer
158
+ # @since 1.0.12
159
+ def self.report_errors
160
+ puts 'The following errors were found in the repo files:'
161
+ @errors.each do |e|
162
+ puts "- #{e}"
163
+ end
164
+ puts 'Rectify the errors and retry. We cannot proceed with those errors occurring.'
165
+ exit 1
166
+ end
167
+
168
+ ##
169
+ # Performs basic checks on a repo file
170
+ #
171
+ # @author Jason Colyer
172
+ # @since 1.0.12
173
+ # @param file [String] The path to the repo file
174
+ # @param object [Hash] The Hash derived from parsing a YAML file
175
+ def self.validity_check(file, object)
176
+ folder = file.split("#{@location}/").last.split('/').first
177
+ @errors.push("Missing position: #{file}") if object['position'].nil?
178
+ @errors.push("Missing title: #{file}") if object['title'].nil?
179
+ @errors.push("Inactive trigger in active folder: #{file}") if folder == 'active' && !object['active']
180
+ @errors.push("Active trigger in inactive folder: #{file}") if folder == 'inactive' && object['active']
181
+ end
182
+
183
+ ##
184
+ # Performs basic checks on the repo
185
+ #
186
+ # @author Jason Colyer
187
+ # @since 1.0.12
188
+ # @param objects [Array] The Array of Hashes derived from parsing the repo files
189
+ def self.repo_check(objects)
190
+ duplicate_names = objects.group_by { |o| o.title }.select { |k, v| v.size > 1 }.map(&:first)
191
+ unless duplicate_names.count.zero?
192
+ duplicate_names.each do |d|
193
+ @errors.push("The title '#{d}' is used in multiple files")
194
+ end
195
+ end
196
+ end
197
+
198
+ ##
199
+ # Performs conversions for a repo file if using managed content
200
+ #
201
+ # @author Jason Colyer
202
+ # @since 1.0.12
203
+ # @param object [Hash] The Hash derived from parsing a YAML file
204
+ def self.convert_managed_content(object, file)
205
+ category = file.split("#{@location}/#{object['active'] ? '' : 'in' }active/").last.split('/').first
206
+ path = "#{@location}/managed_content/#{category}/#{object['title']}.md"
207
+ handle_request_error(1, 'Repos', 404, { action: 'Get managed content', id: object['title'] }) unless File.exist?(path)
208
+ object['actions'].each_with_index do |action, index|
209
+ if action['value'].is_a?(String)
210
+ if action['value'] =~ /MANAGED_CONTENT/
211
+ if action['value'] == 'MANAGED_CONTENT'
212
+ object['actions'][index]['value'] = action['value'].gsub('MANAGED_CONTENT', File.read(path).chomp)
213
+ else
214
+ object['actions'][index]['value'] = action['value'].gsub('MANAGED_CONTENT', File.read(path).chomp.gsub("\n", '\\n'))
215
+ end
216
+ end
217
+ elsif action['value'].is_a?(Array)
218
+ action['value'].each_with_index do |value, sub_index|
219
+ if value =~ /MANAGED_CONTENT/
220
+ if value == 'MANAGED_CONTENT'
221
+ object['actions'][index]['value'][sub_index] = value.gsub('MANAGED_CONTENT', File.read(path).chomp)
222
+ else
223
+ object['actions'][index]['value'][sub_index] = value.gsub('MANAGED_CONTENT', File.read(path).chomp.gsub("\n", '\\n'))
224
+ end
225
+ end
226
+ end
227
+ end
228
+ end
229
+ object
230
+ end
231
+
232
+ ##
233
+ # Performs conversions for a repo file if using managed webhooks
234
+ #
235
+ # @author Jason Colyer
236
+ # @since 1.0.12
237
+ # @param object [Hash] The Hash derived from parsing a YAML file
238
+ def self.convert_managed_webhook(object, file)
239
+ category = file.split("#{@location}/#{object['active'] ? '' : 'in' }active/").last.split('/').first
240
+ path = "#{@location}/managed_content/#{category}/#{object['title']}.webhook"
241
+ handle_request_error(1, 'Repos', 404, { action: 'Get managed webhook', id: object['title'] }) unless File.exist?(path)
242
+ object['actions'].each_with_index do |action, index|
243
+ next unless action['value'].is_a?(Array)
244
+
245
+ action['value'].each_with_index do |value, sub_index|
246
+ next unless value == 'MANAGED_WEBHOOK'
247
+
248
+ object['actions'][index]['value'][sub_index] = JSON.parse(File.read(path))
249
+ end
250
+ end
251
+ object
252
+ end
253
+ end
254
+ end
255
+ end
@@ -0,0 +1,201 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Defines the module Readiness.
4
+ module Readiness
5
+ # Defines the module Repos
6
+ module Repos
7
+ ##
8
+ # Defines the class UserFields within the module {Readiness::Repos}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.12
12
+ class UserFields < Readiness::Client
13
+ ##
14
+ # Compares the repo user fields files to the Zendesk instance user fields
15
+ #
16
+ # @author Jason Colyer
17
+ # @since 1.0.12
18
+ # @param zendesk_client [Object] An instance of {Readiness::Zendesk::Client}
19
+ # @param location [String] The location (relative or absolute) of the repo's data folder
20
+ # @param verbose [Boolean] Whether you want a detailed report or not
21
+ # @return [Hash]
22
+ def self.compare(zendesk_client, location = 'data', verbose = false)
23
+ @from_repo = gather(zendesk_client, location)
24
+ @from_zendesk = Zendesk::UserFields.list(zendesk_client)
25
+ @diffs = {
26
+ field_updates: [],
27
+ field_creates: [],
28
+ option_updates: [],
29
+ option_deletes: []
30
+ }
31
+ @from_repo.each do |repo|
32
+ zd = @from_zendesk.detect { |z| z.title == repo.title }
33
+ if zd.nil?
34
+ pp @from_zendesk
35
+ pp repo
36
+ @diffs[:field_creates].push(repo)
37
+ unless repo.custom_field_options.nil?
38
+ repo.custom_field_options.each do |o|
39
+ @diffs[:option_updates].push({ "#{repo.title}" => o })
40
+ end
41
+ end
42
+ else
43
+ comparable_zd = zd.dup
44
+ comparable_repo = repo.dup
45
+ comparable_zd.id = nil
46
+ comparable_zd.custom_field_options = nil
47
+ comparable_repo.custom_field_options = nil
48
+ @diffs[:field_updates].push(update_object(repo, zd)) if to_clean_json(comparable_zd) != to_clean_json(comparable_repo)
49
+ detailed_diff(comparable_repo, comparable_zd) if verbose && to_clean_json(comparable_repo) != to_clean_json(comparable_zd)
50
+ next if repo.custom_field_options.nil?
51
+
52
+ zd_options = @from_zendesk.detect { |z| z.title == repo.title }.custom_field_options
53
+ repo.custom_field_options.map! { |o| Zendesk::UserFieldOptions.new(o) } unless repo.custom_field_options.first.is_a? Object
54
+ repo.custom_field_options.each do |repo_option|
55
+ repo_option.position = repo.custom_field_options.index(repo_option) if repo_option.position.nil?
56
+ zd_option = zd_options.detect { |zd_o| zd_o.name == repo_option.name }
57
+ if zd_option.nil? || to_clean_json(zd_option) != to_clean_json(repo_option)
58
+ @diffs[:option_updates].push({ "#{repo.title}" => repo_option })
59
+ end
60
+ end
61
+ zd_options.each do |zd_option|
62
+ repo_option = repo.custom_field_options.detect { |rp_o| rp_o.name == zd_option.name }
63
+ if repo_option.nil?
64
+ @diffs[:option_deletes].push({ "#{repo.title}" => zd_option })
65
+ end
66
+ end
67
+ end
68
+ end
69
+ report_diffs if verbose
70
+ @diffs
71
+ end
72
+
73
+ ##
74
+ # Outputs a comparison report
75
+ #
76
+ # @author Jason Colyer
77
+ # @since 1.0.12
78
+ def self.report_diffs
79
+ puts 'Compare report:'
80
+ puts "- Field Creates: #{@diffs[:field_creates].count}"
81
+ puts "- Field Updates: #{@diffs[:field_updates].count}"
82
+ puts "- Option Updates: #{@diffs[:option_updates].count}"
83
+ puts "- Option Deletes: #{@diffs[:option_deletes].count}"
84
+ end
85
+
86
+ ##
87
+ # Outputs a comparison report
88
+ #
89
+ # @author Jason Colyer
90
+ # @since 1.0.12
91
+ # @param repo [Object] An instance of {Readiness::Zendesk::UserFields}
92
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::UserFields}
93
+ def self.detailed_diff(repo, zendesk)
94
+ puts "Detailed diff of #{repo.title}"
95
+ repo.instance_variables.each do |v|
96
+ next if v == :@id
97
+
98
+ if repo.instance_variable_get(v) != zendesk.instance_variable_get(v)
99
+ puts "- #{v} Repo:"
100
+ pp repo.instance_variable_get(v)
101
+ puts " #{v} Zendesk:"
102
+ pp zendesk.instance_variable_get(v)
103
+ end
104
+ end
105
+ end
106
+
107
+ ##
108
+ # Creates an instance of {Readiness::Zendesk::UserFields} to use for updates
109
+ #
110
+ # @author Jason Colyer
111
+ # @since 1.0.12
112
+ # @param repo [Object] An instance of {Readiness::Zendesk::UserFields}
113
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::UserFields}
114
+ # @return [Object]
115
+ def self.update_object(repo, zendesk)
116
+ object = repo
117
+ object.id = zendesk.id
118
+ object
119
+ end
120
+
121
+ ##
122
+ # Parses repo user field files
123
+ #
124
+ # @author Jason Colyer
125
+ # @since 1.0.12
126
+ # @param client [Object] An instance of {Readiness::Zendesk::Client}
127
+ # @param location [String] The location (relative or absolute) of the repo's data folder
128
+ # @return [Array]
129
+ # @example
130
+ # require 'support_readiness'
131
+ # config = Readiness::Zendesk::Configuration.new
132
+ # config.username = 'alice@example.com'
133
+ # config.token = 'test123abc'
134
+ # config.url = 'https://example.zendesk.com/api/v2'
135
+ # client = Readiness::Zendesk::Client.new(config)
136
+ # repo = Readiness::Repos::UserFields.gather(client, 'users/fields/data')
137
+ # pp repo.count
138
+ # # => 170
139
+ def self.gather(client, location = 'data')
140
+ @errors = []
141
+ @location = location
142
+ array = []
143
+ Dir["#{@location}/**/*.yaml"].each do |f|
144
+ object = YAML.safe_load_file(f)
145
+ validity_check(f, object)
146
+ object['id'] = nil
147
+ object['title_in_portal'] = (object['visible_in_portal'] ? object['title_in_portal'] : object['title'])
148
+ array.push(Zendesk::UserFields.new(client, object))
149
+ end
150
+ repo_check(array)
151
+ report_errors unless @errors.count.zero?
152
+ array
153
+ end
154
+
155
+ ##
156
+ # Outputs an error report and exits with a status code of 1
157
+ #
158
+ # @author Jason Colyer
159
+ # @since 1.0.12
160
+ def self.report_errors
161
+ puts 'The following errors were found in the repo files:'
162
+ @errors.each do |e|
163
+ puts "- #{e}"
164
+ end
165
+ puts 'Rectify the errors and retry. We cannot proceed with those errors occurring.'
166
+ exit 1
167
+ end
168
+
169
+ ##
170
+ # Performs basic checks on a repo file
171
+ #
172
+ # @author Jason Colyer
173
+ # @since 1.0.12
174
+ # @param file [String] The path to the repo file
175
+ # @param object [Hash] The Hash derived from parsing a YAML file
176
+ def self.validity_check(file, object)
177
+ folder = file.split("#{@location}/").last.split('/').first
178
+ @errors.push("Missing type: #{file}") if object['type'].nil?
179
+ @errors.push("Missing title: #{file}") if object['title'].nil?
180
+ @errors.push("Missing position: #{file}") if object['position'].nil?
181
+ @errors.push("Inactive user field in active folder: #{file}") if folder == 'active' && !object['active']
182
+ @errors.push("Active user field in inactive folder: #{file}") if folder == 'inactive' && object['active']
183
+ end
184
+
185
+ ##
186
+ # Performs basic checks on the repo
187
+ #
188
+ # @author Jason Colyer
189
+ # @since 1.0.12
190
+ # @param objects [Array] The Array of Hashes derived from parsing the repo files
191
+ def self.repo_check(objects)
192
+ duplicate_names = objects.group_by { |o| o.title }.select { |k, v| v.size > 1 }.map(&:first)
193
+ unless duplicate_names.count.zero?
194
+ duplicate_names.each do |d|
195
+ @errors.push("The title '#{d}' is used in multiple files")
196
+ end
197
+ end
198
+ end
199
+ end
200
+ end
201
+ end