tractive 1.0.10 → 1.0.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d048cfbc81f42620ae076e33691d303559fb14b097048e2d4dcfb9574ed5bae
4
- data.tar.gz: 3015ae96353d4e65c10569115d3c7b43d08474cfdf9223e82f8c2710e1663efc
3
+ metadata.gz: 0db013dccdcc48d417706b5f52036b4c5801b4d81d6a835c09ee4b1afc6480db
4
+ data.tar.gz: 4603e9e32107e75a4e2f495dc4a93cbc4e810a65c2bee576721e7d58d4be78cd
5
5
  SHA512:
6
- metadata.gz: f8ff314239f2b28ba8b2d87dadb07136c050d80a32a34e214e02d9826b375db886f09fe911cb8f42a63cbdf2a4ba244b8745d65bbf7be9177bc79c3bed20a835
7
- data.tar.gz: 474c1ecad5be50f06599fca50aeee7c33bdfeba778310c77f0830653235de30c34fed85f144a24044555cdce551ab28e645af268afbf1da55674e2e38c48f372
6
+ metadata.gz: 5cf948f6fd3aed7f3b67778e91e9d88e7e1f9586824e21c4a1a0a4a42b42a14eedac4df7d5bf7627e182741ccf35865e195c1990c18e008b352b43bee08d4f4a
7
+ data.tar.gz: f2b76c16fdf603a4d084df7a895f6ffdef16b4fc9297e6f039d9894e4b95a14a6d31ef090399983f46e68f4b904485df41102f3749926aef8adffee8e7d4011a
data/.rubocop.yml CHANGED
@@ -18,6 +18,7 @@ Metrics/ClassLength:
18
18
 
19
19
  Metrics/BlockLength:
20
20
  Max: 500
21
+ IgnoredMethods: ['describe']
21
22
 
22
23
  Style/Documentation:
23
24
  Enabled: false
@@ -37,6 +38,9 @@ Metrics/MethodLength:
37
38
  Metrics/ModuleLength:
38
39
  Max: 150
39
40
 
41
+ Metrics/ParameterLists:
42
+ Max: 6
43
+
40
44
  Security/Open:
41
45
  Enabled: false
42
46
 
data/README.adoc CHANGED
@@ -802,6 +802,14 @@ If attachment files are reachable via a URL we reference this here.
802
802
  | Path to config file.
803
803
  | String
804
804
 
805
+ | `-e`, `--wiki-extensions`
806
+ | Space separated list of extensions or filenames (if the file don't have an extension). This is required to convert file SVN source links to Github links. This is used to determine if a path belongs to a file or a directory.
807
+ | Array
808
+
809
+ | `-f`, `--source-folders`
810
+ | Space separated list of non standard folders in SVN that are used to find if a path is complete or partial.
811
+ | Array
812
+
805
813
  |===
806
814
 
807
815
 
data/exe/command_base.rb CHANGED
@@ -7,5 +7,7 @@ class CommandBase < Thor
7
7
  desc: "Name of the logfile to output logs to."
8
8
  class_option "config", type: :string, default: "tractive.config.yaml", banner: "<PATH>", aliases: "-c",
9
9
  desc: "Set the configuration file"
10
+ class_option "git-token", type: :string,
11
+ desc: "The access token for Github actions."
10
12
  class_option "verbose", type: :boolean, aliases: ["-v", "--verbose"], desc: "Verbose mode"
11
13
  end
data/exe/tractive CHANGED
@@ -58,6 +58,12 @@ class TractiveCommand < CommandBase
58
58
  desc: "Full path of the Trac sqlite3 database export file"
59
59
  method_option "repo-path", type: :string, aliases: ["-r"], banner: "/GIT/ROOT/DIR",
60
60
  desc: "Full path to the root of the git-repository that is our destination"
61
+ method_option "home-page-name", type: :string, aliases: ["-h"], default: "WikiStart",
62
+ desc: "Name of the SVN wiki to map to the home page in Github wiki"
63
+ method_option "wiki-extensions", type: :array, aliases: ["-e"], default: [".py", "changelog", "expire-ids"],
64
+ desc: "Array of strings to determinte whether a given path is a file path or a directory in wiki"
65
+ method_option "source-folders", type: :array, aliases: ["-f"], default: ["personal", "attic", "sprint", "branch/hawk"],
66
+ desc: "Array of strings to figure out if a path is complete or partial"
61
67
  def migrate_wikis
62
68
  Tractive::Main.new(options).migrate_wikis
63
69
  end
@@ -53,9 +53,10 @@ module Tractive
53
53
  $logger.info "Saving attachments of ticket #{attachment.id}... "
54
54
  FileUtils.mkdir_p "#{output_dir}/#{attachment.id}"
55
55
 
56
- File.open("#{output_dir}/#{attachment.id}/#{attachment.filename}", "wb") do |file|
57
- file.write URI.open(uri_parser.escape("#{trac_url}/#{attachment.id}/#{attachment.filename}")).read
58
- end
56
+ File.binwrite(
57
+ "#{output_dir}/#{attachment.id}/#{attachment.filename}",
58
+ URI.open(uri_parser.escape("#{trac_url}/#{attachment.id}/#{attachment.filename}")).read
59
+ )
59
60
  end
60
61
  end
61
62
  end
data/lib/tractive/main.rb CHANGED
@@ -8,6 +8,9 @@ module Tractive
8
8
  @opts = opts
9
9
  @cfg = YAML.load_file(@opts[:config])
10
10
 
11
+ @cfg["github"] ||= {}
12
+ @cfg["github"]["token"] = @opts["git-token"]
13
+
11
14
  Tractive::Utilities.setup_logger(output_stream: @opts[:logfile] || $stderr, verbose: @opts[:verbose])
12
15
  @db = Tractive::Utilities.setup_db!(@opts["trac-database-path"] || @cfg["trac"]["database"])
13
16
  rescue Sequel::DatabaseConnectionError, Sequel::AdapterNotFound, URI::InvalidURIError, Sequel::DatabaseError => e
@@ -33,7 +33,8 @@ module Migrator
33
33
  @attachment_options,
34
34
  @changeset_base_url,
35
35
  @wiki_attachments_url,
36
- @revmap_file_path
36
+ @revmap_file_path,
37
+ git_repo: @repo, home_page_name: args[:opts]["home-page-name"]
37
38
  )
38
39
  end
39
40
 
@@ -280,7 +281,7 @@ module Migrator
280
281
  # text += "created the issue\n\n"
281
282
  if body && !body.lstrip.empty?
282
283
  # text += "\n___\n" if not append
283
- text += @twf_to_markdown.convert(body)
284
+ text += @twf_to_markdown.convert(body, id: meta[:ticket])
284
285
  end
285
286
 
286
287
  when "comment"
@@ -294,7 +295,7 @@ module Migrator
294
295
  end
295
296
 
296
297
  text += "\n___\n" unless append
297
- text += @twf_to_markdown.convert(body) if body
298
+ text += @twf_to_markdown.convert(body, id: meta[:ticket]) if body
298
299
 
299
300
  when "attachment"
300
301
  text += "_uploaded file "
@@ -1,27 +1,41 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "cgi"
4
+
3
5
  module Migrator
4
6
  module Converter
5
7
  # twf => Trac wiki format
6
8
  class TwfToMarkdown
7
- def initialize(base_url, attachment_options, changeset_base_url, wiki_attachments_url, revmap_file_path)
9
+ def initialize(base_url, attachment_options, changeset_base_url, wiki_attachments_url, revmap_file_path, options = {})
8
10
  @base_url = base_url
9
11
  @attach_url = attachment_options[:url]
10
12
  @attach_hashed = attachment_options[:hashed]
11
13
  @changeset_base_url = changeset_base_url
12
14
  @wiki_attachments_url = wiki_attachments_url
13
15
  @revmap = load_revmap_file(revmap_file_path)
16
+
17
+ @git_repo = options[:git_repo]
18
+ @home_page_name = options[:home_page_name]
19
+ @wiki_extensions = options[:wiki_extensions]
20
+ @source_folders = options[:source_folders]
14
21
  end
15
22
 
16
- def convert(str)
23
+ def convert(str, image_options = {})
24
+ # Fix 'Windows EOL' to 'Linux EOL'
25
+ str.gsub!("\r\n", "\n")
26
+
27
+ convert_tables(str)
17
28
  convert_newlines(str)
29
+ convert_comments(str)
30
+ convert_html_snippets(str)
18
31
  convert_code_snippets(str)
19
32
  convert_headings(str)
20
- convert_links(str)
33
+ convert_links(str, @git_repo)
21
34
  convert_font_styles(str)
22
35
  convert_changeset(str, @changeset_base_url)
23
- convert_image(str, @base_url, @attach_url, @wiki_attachments_url)
36
+ convert_image(str, @base_url, @attach_url, @wiki_attachments_url, image_options)
24
37
  convert_ticket(str, @base_url)
38
+ revert_intermediate_references(str)
25
39
 
26
40
  str
27
41
  end
@@ -46,18 +60,12 @@ module Migrator
46
60
  revmap
47
61
  end
48
62
 
49
- # CommitTicketReference
50
- def convert_ticket_reference(str)
51
- str.gsub!(/\{\{\{\n(#!CommitTicketReference .+?)\}\}\}/m, '\1')
52
- str.gsub!(/#!CommitTicketReference .+\n/, "")
53
- end
54
-
55
63
  # Ticket
56
64
  def convert_ticket(str, base_url)
57
65
  # replace a full ticket id with the github short refrence
58
66
  if base_url
59
67
  baseurlpattern = base_url.gsub("/", "\\/")
60
- str.gsub!(%r{#{baseurlpattern}/(\d+)}) { "ticket:#{Regexp.last_match[1]}" }
68
+ str.gsub!(%r{#{baseurlpattern}/(\d+)}, '#\1')
61
69
  end
62
70
 
63
71
  # Ticket
@@ -80,16 +88,35 @@ module Migrator
80
88
  str.gsub!("\r\n", "\n")
81
89
  end
82
90
 
91
+ # Comments
92
+ def convert_comments(str)
93
+ str.gsub!(/\{\{\{(?>((?!(?:}}}|{{{)).+?|\g<0>))*\}\}\}/m) do |str_match|
94
+ str_match.gsub(/\{\{\{\s*#!comment(\s*)(.*)\}\}\}/m, '<!--\1\2\1-->')
95
+ end
96
+ end
97
+
98
+ # HTML Snippets
99
+ def convert_html_snippets(str)
100
+ str.gsub!(/\{\{\{#!html(.*?)\}\}\}/m, '\1')
101
+ end
102
+
103
+ # CommitTicketReference
104
+ def convert_ticket_reference(str)
105
+ str.gsub!(/\{\{\{\n(#!CommitTicketReference .+?)\}\}\}/m, '\1')
106
+ str.gsub!(/#!CommitTicketReference .+\n/, "")
107
+ end
108
+
83
109
  # Code
84
110
  def convert_code_snippets(str)
85
111
  str.gsub!(/\{\{\{([^\n]+?)\}\}\}/, '`\1`')
112
+ str.gsub!(/\{\{\{#!(.*?)\n(.+?)\}\}\}/m, "```\\1\n\\2\n```")
86
113
  str.gsub!(/\{\{\{(.+?)\}\}\}/m, '```\1```')
87
114
  str.gsub!(/(?<=```)#!/m, "")
88
115
  end
89
116
 
90
117
  # Changeset
91
118
  def convert_changeset(str, changeset_base_url)
92
- str.gsub!(%r{#{Regexp.quote(changeset_base_url)}/(\d+)/?}, '[changeset:\1]') if changeset_base_url
119
+ str.gsub!(%r{#{Regexp.quote(changeset_base_url)}/(\d+)/?}, '[changeset:\1]') if changeset_base_url && !changeset_base_url.empty?
93
120
  str.gsub!(/\[changeset:"r(\d+)".*\]/, '[changeset:\1]')
94
121
  str.gsub!(/\[changeset:r(\d+)\]/, '[changeset:\1]')
95
122
  str.gsub!(/\br(\d+)\b/) { Tractive::Utilities.map_changeset(Regexp.last_match[1], @revmap, changeset_base_url) }
@@ -103,44 +130,216 @@ module Migrator
103
130
  def convert_font_styles(str)
104
131
  str.gsub!(/'''(.+?)'''/, '**\1**')
105
132
  str.gsub!(/''(.+?)''/, '*\1*')
106
- str.gsub!(%r{[^:]//(.+?[^:])//}, '_\1_')
133
+ str.gsub!(%r{([^:])//(.+?[^:])//}, '\1_\2_')
134
+ end
135
+
136
+ # Tables
137
+ def convert_tables(str)
138
+ str.gsub!(/^( *\|\|[^\n]+\|\| *[^\n|]+$)+$/, '\1 ||')
139
+
140
+ str.gsub!(/(?:^( *\|\|[^\n]+\|\| *)\n?)+/) do |match_result|
141
+ rows = match_result.gsub("||", "|").split("\n")
142
+ rows.insert(1, "| #{"--- | " * (rows[0].split("|").size - 1)}".strip)
143
+
144
+ "#{rows.join("\n")}\n"
145
+ end
107
146
  end
108
147
 
109
148
  # Links
110
- def convert_links(str)
111
- str.gsub!(/\[(http[^\s\[\]]+)\s([^\[\]]+)\]/, '[\2](\1)')
149
+ def convert_links(str, git_repo)
150
+ convert_camel_case_links(str, git_repo)
151
+ convert_double_bracket_wiki_links(str, git_repo)
152
+ convert_single_bracket_wiki_links(str, git_repo)
153
+
154
+ str.gsub!(/(^!)\[(http[^\s\[\]]+)\s([^\[\]]+)\]/, '[\2](\1)')
112
155
  str.gsub!(/!(([A-Z][a-z0-9]+){2,})/, '\1')
113
156
  end
114
157
 
115
- def convert_image(str, base_url, attach_url, wiki_attachments_url)
158
+ def convert_single_bracket_wiki_links(str, git_repo)
159
+ str.gsub!(/(!?)\[((?:wiki|source):)?([^\s\]]*) ?(.*?)\]/) do |match_result|
160
+ source = Regexp.last_match[2]
161
+ path = Regexp.last_match[3]
162
+ name = Regexp.last_match[4]
163
+
164
+ formatted_link(
165
+ match_result,
166
+ git_repo,
167
+ { source: source, path: path, name: name }
168
+ )
169
+ end
170
+ end
171
+
172
+ def convert_double_bracket_wiki_links(str, git_repo)
173
+ str.gsub!(/(!?)\[\[((?:wiki|source):)?([^|\n]*)\|?(.*?)\]\]/) do |match_result|
174
+ source = Regexp.last_match[2]
175
+ path = Regexp.last_match[3]
176
+ name = Regexp.last_match[4]
177
+
178
+ formatted_link(
179
+ match_result,
180
+ git_repo,
181
+ { source: source, path: path, name: name }
182
+ )
183
+ end
184
+ end
185
+
186
+ def formatted_link(unformatted_text, git_repo, url_options = {})
187
+ return unformatted_text.gsub("!", "{~") if unformatted_text.start_with?("!")
188
+
189
+ if url_options[:source] == "wiki:"
190
+ link, internal_link = url_options[:path].split("#")
191
+ link = "Home" if link == @home_page_name
192
+ internal_link = Tractive::Utilities.dasharize(internal_link) if internal_link
193
+ url_options[:name] = link if url_options[:name].empty?
194
+ "{{#{url_options[:name]}}}(https://github.com/#{git_repo}/wiki/#{link}##{internal_link})"
195
+ elsif url_options[:source] == "source:"
196
+ url_options[:name] = url_options[:path] if url_options[:name].empty?
197
+ "{{#{url_options[:name]}}}(https://github.com/#{git_repo}/#{source_git_path(url_options[:path])})"
198
+ elsif url_options[:path].start_with?("http")
199
+ url_options[:name] = url_options[:path] if url_options[:name].empty?
200
+ "{{#{url_options[:name]}}}(#{url_options[:path]})"
201
+ else
202
+ unformatted_text
203
+ end
204
+ end
205
+
206
+ def source_git_path(trac_path)
207
+ trac_path = trac_path.gsub("trunk/", "main/")
208
+ trac_path = trac_path.delete_prefix("/").delete_suffix("/")
209
+
210
+ return "" if trac_path.empty?
211
+
212
+ uri = URI.parse(trac_path)
213
+
214
+ trac_path = uri.path
215
+ line_number = uri.fragment
216
+ trac_path, revision = trac_path.split("@")
217
+
218
+ if trac_path.split("/").count <= 1
219
+ wiki_path(trac_path)
220
+ else
221
+ unless trac_path.start_with?("tags")
222
+ params = CGI.parse(uri.query || "")
223
+ revision ||= params["rev"].first
224
+
225
+ # TODO: Currently @ does not work with file paths except for main branch
226
+ sha = @revmap[revision]&.strip
227
+
228
+ trac_path = if sha && file?(trac_path)
229
+ trac_path.gsub("main/", "#{sha}/")
230
+ else
231
+ sha || trac_path
232
+ end
233
+ end
234
+
235
+ wiki_path(trac_path.delete_prefix("tags/"), line_number)
236
+ end
237
+ end
238
+
239
+ def index_paths
240
+ @index_paths ||= {
241
+ "tags" => "tags",
242
+ "tags/" => "tags",
243
+ "branch" => "branches/all"
244
+ }
245
+ end
246
+
247
+ def file?(trac_path)
248
+ return false unless trac_path
249
+
250
+ @wiki_extensions&.any? { |extension| trac_path.end_with?(extension) }
251
+ end
252
+
253
+ def wiki_path(path, line_number = "")
254
+ # TODO: This will not work for folders given in the source_folder parameter and
255
+ # will not work for subfolders paths like `personal/rjs` unless given in the parameters.
256
+ return "branches/all?query=#{path}" if @source_folders&.any? { |folder| folder == path }
257
+ return index_paths[path] if index_paths[path]
258
+
259
+ prefix = if file?(path)
260
+ "blob"
261
+ else
262
+ "tree"
263
+ end
264
+
265
+ "#{prefix}/#{path}#{"#" unless line_number.to_s.empty?}#{line_number}"
266
+ end
267
+
268
+ # CamelCase page names follow these rules:
269
+ # 1. The name must consist of alphabetic characters only;
270
+ # no digits, spaces, punctuation or underscores are allowed.
271
+ # 2. A name must have at least two capital letters.
272
+ # 3. The first character must be capitalized.
273
+ # 4. Every capital letter must be followed by one or more lower-case letters.
274
+ # 5. The use of slash ( / ) is permitted in page names, where it typically represents a hierarchy.
275
+ def convert_camel_case_links(str, git_repo)
276
+ name_regex = %r{(^| )(!?)(/?[A-Z][a-z]+(/?[A-Z][a-z]+)+/?)}
277
+ wiki_pages_names = Tractive::Wiki.select(:name).distinct.map(:name)
278
+ str.gsub!(name_regex) do
279
+ start = Regexp.last_match[2]
280
+ name = Regexp.last_match[3]
281
+
282
+ wiki_link = if start != "!" && wiki_pages_names.include?(name)
283
+ make_wiki_link(name, git_repo)
284
+ else
285
+ name
286
+ end
287
+
288
+ "#{Regexp.last_match[1]}#{wiki_link}"
289
+ end
290
+ end
291
+
292
+ def make_wiki_link(wiki_name, git_repo)
293
+ wiki_name = "Home" if wiki_name == @home_page_name
294
+ "[#{wiki_name}](https://github.com/#{git_repo}/wiki/#{wiki_name})"
295
+ end
296
+
297
+ def convert_image(str, base_url, attach_url, wiki_attachments_url, options = {})
116
298
  # https://trac.edgewall.org/wiki/WikiFormatting#Images
117
299
  # [[Image(picture.gif)]] Current page (Ticket, Wiki, Comment)
118
300
  # [[Image(wiki:WikiFormatting:picture.gif)]] (referring to attachment on another page)
119
301
  # [[Image(ticket:1:picture.gif)]] (file attached to a ticket)
120
302
 
121
303
  image_regex = /\[\[Image\((?:(?<module>(?:source|wiki)):)?(?<path>[^)]+)\)\]\]/
122
- d = image_regex.match(str)
123
- return if d.nil?
124
-
125
- path = d[:path]
126
- mod = d[:module]
127
-
128
- image_path = if mod == "source"
129
- "![#{path.split("/").last}](#{base_url}#{path})"
130
- elsif mod == "wiki"
131
- id, file = path.split(":")
132
- upload_path = "#{wiki_attachments_url}/#{Tractive::Utilities.attachment_path(id, file, hashed: @attach_hashed)}"
133
- "![#{file}](#{upload_path})"
134
- elsif path.start_with?("http")
135
- # [[Image(http://example.org/s.jpg)]]
136
- "![#{d[:path]}](#{d[:path]})"
137
- else
138
- _, id, file = path.split(":")
139
- file_path = "#{attach_url}/#{Tractive::Utilities.attachment_path(id, file, hashed: @attach_hashed)}"
140
- "![#{d[:path]}](#{file_path})"
141
- end
142
-
143
- str.gsub!(image_regex, image_path)
304
+
305
+ str.gsub!(image_regex) do
306
+ path = Regexp.last_match[:path]
307
+ mod = Regexp.last_match[:module]
308
+
309
+ converted_image = if mod == "source"
310
+ "!{{#{path.split("/").last}}}(#{base_url}#{path})"
311
+ elsif mod == "wiki"
312
+ id, file = path.split(":")
313
+ upload_path = "#{wiki_attachments_url}/#{Tractive::Utilities.attachment_path(id, file, hashed: @attach_hashed)}"
314
+ "!{{#{file}}}(#{upload_path})"
315
+ elsif path.start_with?("http")
316
+ # [[Image(http://example.org/s.jpg)]]
317
+ "!{{#{path}}}(#{path})"
318
+ else
319
+ tmp = path.split(":")
320
+ id, file = case tmp.size
321
+ when 3
322
+ [tmp[1], tmp[2]]
323
+ when 2
324
+ tmp
325
+ else
326
+ [options[:id].to_s, tmp[0]]
327
+ end
328
+ file_path = "#{attach_url}/#{Tractive::Utilities.attachment_path(id, file, hashed: @attach_hashed)}"
329
+ "!{{#{path}}}(#{file_path})"
330
+ end
331
+
332
+ # There are also ticket references in the format of ticket:1 so
333
+ # changing this now and will revert it at the end again
334
+ converted_image.gsub(/ticket:(\d+)/, 'ImageTicket~\1')
335
+ end
336
+ end
337
+
338
+ def revert_intermediate_references(str)
339
+ str.gsub!(/ImageTicket~(\d)/, 'ticket:\1')
340
+ str.gsub!("{{", "[")
341
+ str.gsub!("}}", "]")
342
+ str.gsub!(/(\{~)*/, "")
144
343
  end
145
344
  end
146
345
  end
@@ -13,19 +13,35 @@ module Migrator
13
13
  @authors_map = @config["users"].to_h
14
14
 
15
15
  @tracticketbaseurl = @config["trac"]["ticketbaseurl"]
16
+ @git_repo = @config["github"]["repo"]
16
17
  @changeset_base_url = @config["trac"]["changeset_base_url"] || ""
18
+ @revmap_path = @config["revmap_path"]
19
+ @attachments_hashed = @config.dig("wiki", "attachments", "hashed")
20
+
17
21
  @wiki_attachments_url = @options["attachment-base-url"] || @config.dig("wiki", "attachments", "url") || ""
18
22
  @repo_path = @options["repo-path"] || ""
19
- @revmap_path = @config["revmap_path"]
23
+ @home_page_name = @options["home-page-name"]
24
+ @wiki_extensions = @options["wiki-extensions"]
25
+ @source_folders = @options["source-folders"]
20
26
 
21
27
  @attachment_options = {
22
- hashed: @config.dig("ticket", "attachments", "hashed")
28
+ hashed: @attachments_hashed
23
29
  }
24
30
 
25
31
  verify_options
26
32
  verify_locations
27
33
 
28
- @twf_to_markdown = Migrator::Converter::TwfToMarkdown.new(@tracticketbaseurl, @attachment_options, @changeset_base_url, @wiki_attachments_url, @revmap_path)
34
+ @twf_to_markdown = Migrator::Converter::TwfToMarkdown.new(
35
+ @tracticketbaseurl,
36
+ @attachment_options,
37
+ @changeset_base_url,
38
+ @wiki_attachments_url,
39
+ @revmap_path,
40
+ git_repo: @git_repo,
41
+ home_page_name: @home_page_name,
42
+ wiki_extensions: @wiki_extensions,
43
+ source_folders: @source_folders
44
+ )
29
45
  end
30
46
 
31
47
  def migrate_wikis
@@ -42,11 +58,13 @@ module Migrator
42
58
  wiki[:comment].gsub('"', '\"')
43
59
  end
44
60
 
45
- file_name = "#{cleanse_filename(wiki[:name])}.md"
61
+ file_name = filename_for_wiki(wiki)
62
+
46
63
  $logger.info("Working with file [#{file_name}]")
47
64
  $logger.debug("Object: #{wiki}")
48
65
 
49
- wiki_markdown_text = @twf_to_markdown.convert(wiki[:text])
66
+ wiki_markdown_text = @twf_to_markdown.convert(wiki[:text], id: wiki[:name])
67
+ wiki_markdown_text += wiki_attachments(wiki)
50
68
 
51
69
  # Create file with content
52
70
  File.open(file_name, "w") do |f|
@@ -73,6 +91,12 @@ module Migrator
73
91
 
74
92
  private
75
93
 
94
+ def filename_for_wiki(wiki)
95
+ return "Home.md" if @home_page_name == wiki[:name]
96
+
97
+ "#{cleanse_filename(wiki[:name])}.md"
98
+ end
99
+
76
100
  def verify_options
77
101
  $logger.info("Verifying options...")
78
102
 
@@ -118,6 +142,22 @@ module Migrator
118
142
  "#{author_name} <#{author_email}>"
119
143
  end
120
144
 
145
+ def wiki_attachments(wiki)
146
+ attachments = wiki.attachments
147
+ return "" if attachments.count.zero?
148
+
149
+ attachments_list = ["# Attachments\n"]
150
+
151
+ attachments.each do |attachment|
152
+ attachment_path = Tractive::Utilities.attachment_path(
153
+ wiki.name, attachment.filename, hashed: @attachments_hashed
154
+ )
155
+ attachments_list << "- [#{attachment.filename}](#{@wiki_attachments_url}/#{attachment_path})"
156
+ end
157
+
158
+ attachments_list.join("\n")
159
+ end
160
+
121
161
  def execute_command(command)
122
162
  `#{command}`
123
163
  $CHILD_STATUS
@@ -36,6 +36,10 @@ module Tractive
36
36
  db
37
37
  end
38
38
 
39
+ def dasharize(str)
40
+ str.gsub(/([a-z\d])([A-Z])/, '\1-\2').downcase
41
+ end
42
+
39
43
  def attachment_path(id, filename, options = {})
40
44
  return "#{id}/#{filename}" unless options[:hashed]
41
45
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tractive
4
- VERSION = "1.0.10"
4
+ VERSION = "1.0.14"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tractive
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.10
4
+ version: 1.0.14
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-12-15 00:00:00.000000000 Z
11
+ date: 2022-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: mysql2