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,335 @@
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 Articles within the module {Readiness::Repos}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.12
12
+ class Articles < Readiness::Client
13
+ def self.compare(zd_client, gl_client, instance, location = 'data', verbose = false)
14
+ diffs = {
15
+ updates: [],
16
+ creates: []
17
+ }
18
+ from_repo = gather(gl_client, instance, location)
19
+ from_zendesk = Zendesk::Articles.list(zd_client)
20
+ from_repo.each do |repo|
21
+ zd = from_zendesk.detect { |z| z.title == repo.title }
22
+ if zd.nil?
23
+ diffs[:creates].push(repo)
24
+ else
25
+ comparable = zd.dup
26
+ comparable.id = nil
27
+ diffs[:updates].push(update_object(repo, zd)) if to_clean_json(repo) != to_clean_json(comparable)
28
+ detailed_diff(repo, comparable) if verbose && to_clean_json(repo) != to_clean_json(comparable)
29
+ end
30
+ end
31
+ report_diffs(diffs) if verbose
32
+ diffs
33
+ end
34
+
35
+ ##
36
+ # Outputs a comparison report
37
+ #
38
+ # @author Jason Colyer
39
+ # @since 1.0.12
40
+ # @param diffs [Hash] The returned value of {compare}
41
+ def self.report_diffs(diffs)
42
+ puts 'Compare report:'
43
+ puts "- Creates: #{diffs[:creates].count}"
44
+ puts "- Updates: #{diffs[:updates].count}"
45
+ end
46
+
47
+ ##
48
+ # Outputs a comparison report
49
+ #
50
+ # @author Jason Colyer
51
+ # @since 1.0.12
52
+ # @param repo [Object] An instance of {Readiness::Zendesk::Automations}
53
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::Automations}
54
+ def self.detailed_diff(repo, zendesk)
55
+ puts "Detailed diff of #{repo.title}"
56
+ repo.instance_variables.each do |v|
57
+ next if v == :@id
58
+
59
+ if repo.instance_variable_get(v) != zendesk.instance_variable_get(v)
60
+ if v == :@body
61
+ puts "- #{v} Repo and #{v} Zendesk differ"
62
+ else
63
+ puts "- #{v} Repo:"
64
+ pp repo.instance_variable_get(v)
65
+ puts " #{v} Zendesk:"
66
+ pp zendesk.instance_variable_get(v)
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ ##
73
+ # Creates an instance of {Readiness::Zendesk::Automations} to use for updates
74
+ #
75
+ # @author Jason Colyer
76
+ # @since 1.0.12
77
+ # @param repo [Object] An instance of {Readiness::Zendesk::Automations}
78
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::Automations}
79
+ # @return [Object]
80
+ def self.update_object(repo, zendesk)
81
+ object = repo
82
+ object.id = zendesk.id
83
+ object
84
+ end
85
+
86
+ ##
87
+ # Parses repo article files
88
+ #
89
+ # @author Jason Colyer
90
+ # @since 1.0.12
91
+ # @param gl_client [Object] An instance of {Readiness::GitLab::Client}
92
+ # @param instance [String] The Zendesk instance being worked with. Accepted values are:
93
+ # - Global
94
+ # - Global Sandbox
95
+ # - US Government
96
+ # - US Government Sandbox
97
+ # @param location [String] The location (relative or absolute) of the repo's data folder
98
+ # @return [Array]
99
+ # @example
100
+ # require 'support_readiness'
101
+ # gl_config = Readiness::GitLab::Configuration.new
102
+ # gl_config.token = ENV.fetch('GL_TOKEN')
103
+ # gl_client = Readiness::GitLab::Client.new(gl_config)
104
+ # repo = Readiness::Repos::Articles.gather(gl_client, 'Global', 'automations/data')
105
+ # pp repo.count
106
+ # # => 15
107
+ def self.gather(gl_client, instance = 'Global', location = 'data')
108
+ @errors = []
109
+ @gl_client = gl_client
110
+ @instance = instance
111
+ @location = location
112
+ array = []
113
+ Dir["#{@location}/articles/**/*.yaml"].each do |f|
114
+ object = YAML.safe_load_file(f)
115
+ object['body'] = full_conversion(object)
116
+ validity_check(f, object)
117
+ object['id'] = nil
118
+ array.push(Zendesk::Articles.new(object))
119
+ end
120
+ repo_check(array)
121
+ report_errors unless @errors.count.zero?
122
+ array
123
+ end
124
+
125
+ ##
126
+ # Outputs an error report and exits with a status code of 1
127
+ #
128
+ # @author Jason Colyer
129
+ # @since 1.0.12
130
+ def self.report_errors
131
+ puts 'The following errors were found in the repo files:'
132
+ @errors.each do |e|
133
+ puts "- #{e}"
134
+ end
135
+ puts 'Rectify the errors and retry. We cannot proceed with those errors occurring.'
136
+ exit 1
137
+ end
138
+
139
+ ##
140
+ # Performs basic checks on the repo
141
+ #
142
+ # @author Jason Colyer
143
+ # @since 1.0.12
144
+ # @param objects [Array] The Array of Hashes derived from parsing the repo files
145
+ def self.repo_check(objects)
146
+ duplicate_names = objects.group_by { |o| o.title }.select { |k, v| v.size > 1 }.map(&:first)
147
+ unless duplicate_names.count.zero?
148
+ duplicate_names.each do |d|
149
+ @errors.push("The title '#{d}' is used in multiple files")
150
+ end
151
+ end
152
+ end
153
+
154
+ ##
155
+ # Performs a full conversion on the article's body
156
+ #
157
+ # @author Jason Colyer
158
+ # @since 1.0.12
159
+ # @param object [Hash]
160
+ # @return [String]
161
+ def self.full_conversion(object)
162
+ html = markdown_to_html(object)
163
+ @doc = Nokogiri::HTML.fragment(html)
164
+ rearrange_anchors
165
+ replace_modifiers
166
+ @doc.to_html
167
+ end
168
+
169
+ ##
170
+ # Converts the manasged content file's markdown to html
171
+ #
172
+ # @author Jason Colyer
173
+ # @since 1.0.12
174
+ # @param object [Hash]
175
+ # @return [String]
176
+ def self.markdown_to_html(object)
177
+ markdown = File.readlines("#{@location}/managed_content/pages/#{object['content_path']}")
178
+ body = replace_internal_links(markdown, object)
179
+ html = Readiness::GitLab::Markdown.convert(@gl_client, body, true, 'gitlab-com/support/support-pages' )
180
+ data_object_dom(object) + html
181
+ end
182
+
183
+ ##
184
+ # Returns the data_object_dom String
185
+ #
186
+ # @author Jason Colyer
187
+ # @since 1.0.12
188
+ # @param object [Hash]
189
+ # @return [String]
190
+ def self.data_object_dom(object)
191
+ <<~STRING
192
+ <p id="data_object_dom" style="display: none;" data-path="pages/#{object['content_path']}">&nbsp;</p>
193
+ STRING
194
+ end
195
+
196
+ ##
197
+ # Replaces internal links with their external values
198
+ #
199
+ # @author Jason Colyer
200
+ # @since 1.0.12
201
+ # @param object [Hash]
202
+ # @return [String]
203
+ def self.replace_internal_links(lines, object)
204
+ lines.each_with_index do |line, index|
205
+ line.scan(/{{LINK:\ ([^}]+)}}/).each do |matches|
206
+ matches.each do |m|
207
+ parts = m.split('#')
208
+ anchor = determine_anchor(parts)
209
+ lines[index] = line.gsub("{{LINK: #{m}}}", support_url("#{find_file(parts.first)['id']}#{anchor}", object))
210
+ end
211
+ end
212
+ end
213
+ lines.join
214
+ end
215
+
216
+ ##
217
+ # Locates the correct YAML content
218
+ #
219
+ # @author Jason Colyer
220
+ # @since 1.0.12
221
+ # @param path [String]
222
+ # @return [Hash]
223
+ def self.find_file(path)
224
+ raw_yaml.detect { |y| y['content_path'] =~ /#{path}/ }
225
+ end
226
+
227
+ ##
228
+ # Determiens the correct anchor for a String
229
+ #
230
+ # @author Jason Colyer
231
+ # @since 1.0.12
232
+ # @param parts [Array]
233
+ # @return [String]
234
+ def self.determine_anchor(parts)
235
+ return '' if parts.count == 1
236
+
237
+ "##{parts.last}"
238
+ end
239
+
240
+ ##
241
+ # Placeholder functiont to set the global variable @raw_yaml
242
+ #
243
+ # @author Jason Colyer
244
+ # @since 1.0.12
245
+ # @return [Array]
246
+ def self.raw_yaml
247
+ @raw_yaml ||= determine_raw_yaml
248
+ end
249
+
250
+ ##
251
+ # Function to set the default value for the @raw_yaml global variable
252
+ #
253
+ # @author Jason Colyer
254
+ # @since 1.0.12
255
+ # @return [Array]
256
+ def self.determine_raw_yaml
257
+ array = []
258
+ Dir["#{@location}/articles/**/*.yaml"].each do |f|
259
+ array.push(YAML.safe_load_file(f))
260
+ end
261
+ array
262
+ end
263
+
264
+ ##
265
+ # Returns the external URL for a link
266
+ #
267
+ # @author Jason Colyer
268
+ # @since 1.0.12
269
+ # @param endpoint [String]
270
+ # @param yaml [Hash]
271
+ # @return [String]
272
+ def self.support_url(endpoint, yaml)
273
+ return "##{endpoint.split('#').last}" if endpoint.split('#').first.to_i == yaml['id'].to_i
274
+ return "https://support.gitlab.com/hc/en-us/articles/#{endpoint}" if @instance == 'Global'
275
+ return "https://gitlab1707170878.zendesk.com/hc/en-us/articles/#{endpoint}" if @instance == 'Global Sandbox'
276
+ return "https://federal-support.gitlab.com/hc/en-us/articles/#{endpoint}" if @instance == 'US Government'
277
+ return "https://gitlabfederalsupport1585318082.zendesk.com/hc/en-us/articles/#{endpoint}" if @instance == 'US Government Sandbox'
278
+
279
+ handle_request_error(1, 'Zendesk', 404, { action: 'Find ZD instance', id: @instance })
280
+ end
281
+
282
+ ##
283
+ # Rearranges anchors into the correct format
284
+ #
285
+ # @author Jason Colyer
286
+ # @since 1.0.12
287
+ def self.rearrange_anchors
288
+ %w[h1 h2 h3 h4 h5 h6].each do |h|
289
+ headers = @doc.css(h)
290
+ next if headers.count.zero?
291
+
292
+ headers.each do |header|
293
+ anchor = header.children.at_css '.anchor'
294
+ anchor['name'] = anchor['href'].gsub('#', '')
295
+ text = header.children.last
296
+ text.add_next_sibling(anchor)
297
+ end
298
+ end
299
+ end
300
+
301
+ ##
302
+ # Replaces internal modifiers with their external values
303
+ #
304
+ # @author Jason Colyer
305
+ # @since 1.0.12
306
+ def self.replace_modifiers
307
+ @doc.children.each do |children|
308
+ next unless children.to_s =~ /{{([^}]+)}}/
309
+
310
+ children.each do |child|
311
+ current = child.parent.get_attribute('class').to_s.split
312
+ current.push(child.to_s[/{{([^}]+)}}/, 1])
313
+ child.parent.set_attribute('class', current.join(' '))
314
+ child.content = child.to_s.gsub(/{{([^}]+)}}/, '')
315
+ end
316
+ end
317
+ end
318
+
319
+ ##
320
+ # Performs basic checks on a repo file
321
+ #
322
+ # @author Jason Colyer
323
+ # @since 1.0.12
324
+ # @param file [String] The path to the repo file
325
+ # @param object [Hash] The Hash derived from parsing a YAML file
326
+ def self.validity_check(file, object)
327
+ folder = file.split("#{@location}/").last.split('/').first
328
+ @errors.push("Missing position: #{file}") if object['position'].nil?
329
+ @errors.push("Missing title: #{file}") if object['title'].nil?
330
+ @errors.push("Inactive article in active folder: #{file}") if folder == 'active' && object['draft']
331
+ @errors.push("Active article in inactive folder: #{file}") if folder == 'inactive' && !object['draft']
332
+ end
333
+ end
334
+ end
335
+ end
@@ -0,0 +1,247 @@
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 Automations within the module {Readiness::Repos}.
9
+ #
10
+ # @author Jason Colyer
11
+ # @since 1.0.12
12
+ class Automations < Readiness::Client
13
+ ##
14
+ # Compares the repo automation files to the Zendesk instance automations
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::Automations.compare(client, 'automations/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::Automations.compare(client, 'automations/data', true)
40
+ # # => Detailed diff of Status::Close::Close solved tickets after 7 days
41
+ # # => - @default Repo:
42
+ # # => false
43
+ # # => @default Zendesk:
44
+ # # => true
45
+ # # => Compare report:
46
+ # # => - Creates: 0
47
+ # # => - Updates: 1
48
+ # pp diffs[:updates.count]
49
+ # # => 1
50
+ def self.compare(zendesk_client, location = 'data', verbose = false)
51
+ diffs = {
52
+ updates: [],
53
+ creates: []
54
+ }
55
+ from_repo = gather(location)
56
+ from_zendesk = Zendesk::Automations.list(zendesk_client)
57
+ from_repo.each do |repo|
58
+ zd = from_zendesk.detect { |z| z.title == repo.title }
59
+ if zd.nil?
60
+ diffs[:creates].push(repo)
61
+ else
62
+ comparable = zd.dup
63
+ comparable.id = nil
64
+ diffs[:updates].push(update_object(repo, zd)) if to_clean_json(repo) != to_clean_json(comparable)
65
+ detailed_diff(repo, comparable) if verbose && to_clean_json(repo) != to_clean_json(comparable)
66
+ end
67
+ end
68
+ report_diffs(diffs) if verbose
69
+ diffs
70
+ end
71
+
72
+ ##
73
+ # Outputs a comparison report
74
+ #
75
+ # @author Jason Colyer
76
+ # @since 1.0.12
77
+ # @param diffs [Hash] The returned value of {compare}
78
+ def self.report_diffs(diffs)
79
+ puts 'Compare report:'
80
+ puts "- Creates: #{diffs[:creates].count}"
81
+ puts "- Updates: #{diffs[:updates].count}"
82
+ end
83
+
84
+ ##
85
+ # Outputs a comparison report
86
+ #
87
+ # @author Jason Colyer
88
+ # @since 1.0.12
89
+ # @param repo [Object] An instance of {Readiness::Zendesk::Automations}
90
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::Automations}
91
+ def self.detailed_diff(repo, zendesk)
92
+ puts "Detailed diff of #{repo.title}"
93
+ repo.instance_variables.each do |v|
94
+ next if v == :@id
95
+
96
+ if repo.instance_variable_get(v) != zendesk.instance_variable_get(v)
97
+ puts "- #{v} Repo:"
98
+ pp repo.instance_variable_get(v)
99
+ puts " #{v} Zendesk:"
100
+ pp zendesk.instance_variable_get(v)
101
+ end
102
+ end
103
+ end
104
+
105
+ ##
106
+ # Creates an instance of {Readiness::Zendesk::Automations} to use for updates
107
+ #
108
+ # @author Jason Colyer
109
+ # @since 1.0.12
110
+ # @param repo [Object] An instance of {Readiness::Zendesk::Automations}
111
+ # @param zendesk [Object] An instance of {Readiness::Zendesk::Automations}
112
+ # @return [Object]
113
+ def self.update_object(repo, zendesk)
114
+ object = repo
115
+ object.id = zendesk.id
116
+ object
117
+ end
118
+
119
+ ##
120
+ # Parses repo automation files
121
+ #
122
+ # @author Jason Colyer
123
+ # @since 1.0.12
124
+ # @param location [String] The location (relative or absolute) of the repo's data folder
125
+ # @return [Array]
126
+ # @example
127
+ # require 'support_readiness'
128
+ # repo = Readiness::Repos::Automations.gather('automations/data')
129
+ # pp repo.count
130
+ # # => 35
131
+ def self.gather(location = 'data')
132
+ @errors = []
133
+ @location = location
134
+ array = []
135
+ Dir["#{@location}/**/*.yaml"].each do |f|
136
+ object = YAML.safe_load_file(f)
137
+ object = convert_managed_content(object) if object['contains_managed_content']
138
+ object = convert_managed_webhook(object) if object['contains_managed_webhook']
139
+ validity_check(f, object)
140
+ object['id'] = nil
141
+ array.push(Zendesk::Automations.new(object))
142
+ end
143
+ repo_check(array)
144
+ report_errors unless @errors.count.zero?
145
+ array
146
+ end
147
+
148
+ ##
149
+ # Outputs an error report and exits with a status code of 1
150
+ #
151
+ # @author Jason Colyer
152
+ # @since 1.0.12
153
+ def self.report_errors
154
+ puts 'The following errors were found in the repo files:'
155
+ @errors.each do |e|
156
+ puts "- #{e}"
157
+ end
158
+ puts 'Rectify the errors and retry. We cannot proceed with those errors occurring.'
159
+ exit 1
160
+ end
161
+
162
+ ##
163
+ # Performs basic checks on a repo file
164
+ #
165
+ # @author Jason Colyer
166
+ # @since 1.0.12
167
+ # @param file [String] The path to the repo file
168
+ # @param object [Hash] The Hash derived from parsing a YAML file
169
+ def self.validity_check(file, object)
170
+ folder = file.split("#{@location}/").last.split('/').first
171
+ @errors.push("Missing position: #{file}") if object['position'].nil?
172
+ @errors.push("Missing title: #{file}") if object['title'].nil?
173
+ @errors.push("Inactive automation in active folder: #{file}") if folder == 'active' && !object['active']
174
+ @errors.push("Active automation in inactive folder: #{file}") if folder == 'inactive' && object['active']
175
+ end
176
+
177
+ ##
178
+ # Performs basic checks on the repo
179
+ #
180
+ # @author Jason Colyer
181
+ # @since 1.0.12
182
+ # @param objects [Array] The Array of Hashes derived from parsing the repo files
183
+ def self.repo_check(objects)
184
+ duplicate_names = objects.group_by { |o| o.title }.select { |k, v| v.size > 1 }.map(&:first)
185
+ unless duplicate_names.count.zero?
186
+ duplicate_names.each do |d|
187
+ @errors.push("The title '#{d}' is used in multiple files")
188
+ end
189
+ end
190
+ end
191
+
192
+ ##
193
+ # Performs conversions for a repo file if using managed content
194
+ #
195
+ # @author Jason Colyer
196
+ # @since 1.0.12
197
+ # @param object [Hash] The Hash derived from parsing a YAML file
198
+ def self.convert_managed_content(object)
199
+ path = "#{@location}/managed_content/#{object['title']}.md"
200
+ handle_request_error(1, 'Repos', 404, { action: 'Get managed content', id: object['title'] }) unless File.exist?(path)
201
+ object['actions'].each_with_index do |action, index|
202
+ if action['value'].is_a?(String)
203
+ if action['value'] =~ /MANAGED_CONTENT/
204
+ if action['value'] == 'MANAGED_CONTENT'
205
+ object['actions'][index]['value'] = action['value'].gsub('MANAGED_CONTENT', File.read(path).chomp)
206
+ else
207
+ object['actions'][index]['value'] = action['value'].gsub('MANAGED_CONTENT', File.read(path).chomp.gsub("\n", '\\n'))
208
+ end
209
+ end
210
+ elsif action['value'].is_a?(Array)
211
+ action['value'].each_with_index do |value, sub_index|
212
+ if value =~ /MANAGED_CONTENT/
213
+ if value == 'MANAGED_CONTENT'
214
+ object['actions'][index]['value'][sub_index] = value.gsub('MANAGED_CONTENT', File.read(path).chomp)
215
+ else
216
+ object['actions'][index]['value'][sub_index] = value.gsub('MANAGED_CONTENT', File.read(path).chomp.gsub("\n", '\\n'))
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+ object
223
+ end
224
+
225
+ ##
226
+ # Performs conversions for a repo file if using managed webhooks
227
+ #
228
+ # @author Jason Colyer
229
+ # @since 1.0.12
230
+ # @param object [Hash] The Hash derived from parsing a YAML file
231
+ def self.convert_managed_webhook(object)
232
+ path = "#{@location}/managed_content/#{object['title']}.webhook"
233
+ handle_request_error(1, 'Repos', 404, { action: 'Get managed webhook', id: object['title'] }) unless File.exist?(path)
234
+ object['actions'].each_with_index do |action, index|
235
+ next unless action['value'].is_a?(Array)
236
+
237
+ action['value'].each_with_index do |value, sub_index|
238
+ next unless value == 'MANAGED_WEBHOOK'
239
+
240
+ object['actions'][index]['value'][sub_index] = JSON.parse(File.read(path))
241
+ end
242
+ end
243
+ object
244
+ end
245
+ end
246
+ end
247
+ end