tractive 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/main.yml +24 -0
- data/.gitignore +11 -0
- data/.rspec +3 -0
- data/.rubocop.yml +47 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +14 -0
- data/LICENSE.md +69 -0
- data/README.adoc +742 -0
- data/Rakefile +12 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/config.example.yaml +73 -0
- data/db/trac-test.db +0 -0
- data/docker/Dockerfile +19 -0
- data/docker/docker-compose.yml +68 -0
- data/exe/tractive +111 -0
- data/lib/tractive/attachment_exporter.rb +62 -0
- data/lib/tractive/github_api/client/issues.rb +78 -0
- data/lib/tractive/github_api/client/milestones.rb +35 -0
- data/lib/tractive/github_api/client.rb +16 -0
- data/lib/tractive/github_api.rb +3 -0
- data/lib/tractive/graceful_quit.rb +30 -0
- data/lib/tractive/info.rb +46 -0
- data/lib/tractive/main.rb +81 -0
- data/lib/tractive/migrator/converter/trac_to_github.rb +307 -0
- data/lib/tractive/migrator/converter/twf_to_markdown.rb +125 -0
- data/lib/tractive/migrator/converter.rb +3 -0
- data/lib/tractive/migrator/engine/migrate_from_db.rb +95 -0
- data/lib/tractive/migrator/engine/migrate_from_file.rb +100 -0
- data/lib/tractive/migrator/engine/migrate_to_file.rb +68 -0
- data/lib/tractive/migrator/engine.rb +131 -0
- data/lib/tractive/migrator.rb +3 -0
- data/lib/tractive/models/attachment.rb +10 -0
- data/lib/tractive/models/milestone.rb +6 -0
- data/lib/tractive/models/report.rb +6 -0
- data/lib/tractive/models/revision.rb +6 -0
- data/lib/tractive/models/session.rb +6 -0
- data/lib/tractive/models/ticket.rb +36 -0
- data/lib/tractive/models/ticket_change.rb +7 -0
- data/lib/tractive/revmap_generator.rb +111 -0
- data/lib/tractive/trac.rb +16 -0
- data/lib/tractive/utilities.rb +68 -0
- data/lib/tractive/version.rb +5 -0
- data/lib/tractive.rb +29 -0
- data/tractive.gemspec +37 -0
- metadata +189 -0
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Migrator
|
4
|
+
class Engine
|
5
|
+
module MigrateToFile
|
6
|
+
def migrate_to_file
|
7
|
+
Tractive::GracefulQuit.enable
|
8
|
+
migrate_tickets_to_file(@start_ticket, @filter_closed)
|
9
|
+
rescue RuntimeError => e
|
10
|
+
$logger.error e.message
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# Creates github issues for trac tickets.
|
16
|
+
def migrate_tickets_to_file(start_ticket, filterout_closed)
|
17
|
+
$logger.info("migrating issues")
|
18
|
+
# We match the issue title to determine whether an issue exists already.
|
19
|
+
tractickets = @trac.tickets
|
20
|
+
.for_migration(start_ticket, filterout_closed, @filter_options)
|
21
|
+
.all
|
22
|
+
begin
|
23
|
+
lasttracid = tractickets.last[:id]
|
24
|
+
rescue StandardError
|
25
|
+
raise("trac has no ticket #{start_ticket}")
|
26
|
+
end
|
27
|
+
|
28
|
+
(start_ticket.to_i..lasttracid).each do |ticket_id|
|
29
|
+
ticket = tractickets.select { |i| i[:id] == ticket_id }.first
|
30
|
+
|
31
|
+
@current_ticket_id = ticket_id # used to build filename for attachments
|
32
|
+
|
33
|
+
if ticket.nil?
|
34
|
+
next unless @mockdeleted
|
35
|
+
|
36
|
+
ticket = mock_ticket_details(ticket_id)
|
37
|
+
end
|
38
|
+
|
39
|
+
raise("tickets out of sync #{ticket_id} - #{ticket[:id]}") if ticket[:id] != ticket_id
|
40
|
+
|
41
|
+
next if filterout_closed && (ticket[:status] == "closed")
|
42
|
+
|
43
|
+
Tractive::GracefulQuit.check("quitting after processing ticket ##{@last_created_issue}") do
|
44
|
+
@output_file.puts "}"
|
45
|
+
end
|
46
|
+
|
47
|
+
$logger.info(%{creating issue for trac #{ticket[:id]} "#{ticket[:summary]}" (#{ticket[:reporter]})})
|
48
|
+
# API details: https://gist.github.com/jonmagic/5282384165e0f86ef105
|
49
|
+
request = Migrator::Converter::TracToGithub.new(@config).compose(ticket)
|
50
|
+
|
51
|
+
@output_file.puts @delimiter
|
52
|
+
@output_file.puts({ @current_ticket_id => request }.to_json[1...-1])
|
53
|
+
@delimiter = "," if @delimiter != ","
|
54
|
+
response = { "status" => "added to file", "issue_url" => "/#{ticket[:id]}" }
|
55
|
+
|
56
|
+
$logger.info("Status: #{response["status"]}")
|
57
|
+
|
58
|
+
issue_id = response["issue_url"].match(/\d+$/).to_s.to_i
|
59
|
+
$logger.info("created issue ##{issue_id} for trac ticket #{ticket[:id]}")
|
60
|
+
|
61
|
+
@last_created_issue = ticket[:id]
|
62
|
+
end
|
63
|
+
|
64
|
+
@output_file.puts "}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "engine/migrate_from_db"
|
4
|
+
require_relative "engine/migrate_from_file"
|
5
|
+
require_relative "engine/migrate_to_file"
|
6
|
+
|
7
|
+
require_relative "converter/trac_to_github"
|
8
|
+
require_relative "converter/twf_to_markdown"
|
9
|
+
|
10
|
+
# Service to perform migrations
|
11
|
+
module Migrator
|
12
|
+
class Engine
|
13
|
+
include Migrator::Engine::MigrateFromDb
|
14
|
+
include Migrator::Engine::MigrateToFile
|
15
|
+
include Migrator::Engine::MigrateFromFile
|
16
|
+
|
17
|
+
def initialize(args)
|
18
|
+
# def initialize(trac, github, users, labels, revmap, attachurl, singlepost, safetychecks, mockdeleted = false)
|
19
|
+
@config = args
|
20
|
+
|
21
|
+
db = args[:db]
|
22
|
+
github = args[:cfg]["github"]
|
23
|
+
safetychecks = !(args[:opts][:fast])
|
24
|
+
mockdeleted = args[:opts][:mockdeleted]
|
25
|
+
start_ticket = args[:opts][:start]
|
26
|
+
filter_closed = args[:opts][:openedonly]
|
27
|
+
input_file_name = args[:opts][:importfromfile]
|
28
|
+
|
29
|
+
@filter_applied = args[:opts][:filter]
|
30
|
+
@filter_options = { column_name: args[:opts][:columnname], operator: args[:opts][:operator], column_value: args[:opts][:columnvalue] }
|
31
|
+
|
32
|
+
@trac = Tractive::Trac.new(db)
|
33
|
+
@repo = github["repo"]
|
34
|
+
@client = GithubApi::Client.new(access_token: github["token"])
|
35
|
+
|
36
|
+
if input_file_name
|
37
|
+
@from_file = input_file_name
|
38
|
+
file = File.open(@from_file, "r")
|
39
|
+
@input_file = JSON.parse(file.read)
|
40
|
+
file.close
|
41
|
+
end
|
42
|
+
|
43
|
+
@ticket_to_issue = {}
|
44
|
+
@mockdeleted = mockdeleted || @filter_applied
|
45
|
+
|
46
|
+
$logger.debug("Get highest in #{@repo}")
|
47
|
+
issues = @client.issues(@repo, { filter: "all",
|
48
|
+
state: "all",
|
49
|
+
sort: "created",
|
50
|
+
direction: "desc" })
|
51
|
+
|
52
|
+
@last_created_issue = issues.empty? ? 0 : issues[0]["number"].to_i
|
53
|
+
|
54
|
+
$logger.info("created issue on GitHub is '#{@last_created_issue}' #{issues.count}")
|
55
|
+
|
56
|
+
dry_run_output_file = args[:cfg][:dry_run_output_file] || "#{Dir.pwd}/dryrun_out.json"
|
57
|
+
|
58
|
+
@dry_run = args[:opts][:dryrun]
|
59
|
+
@output_file = File.new(dry_run_output_file, "w+")
|
60
|
+
@delimiter = "{"
|
61
|
+
@revmap = load_revmap_file(args[:opts][:revmapfile] || args[:cfg]["revmapfile"])
|
62
|
+
@safetychecks = safetychecks
|
63
|
+
@start_ticket = (start_ticket || (@last_created_issue + 1)).to_i
|
64
|
+
@filter_closed = filter_closed
|
65
|
+
end
|
66
|
+
|
67
|
+
def migrate
|
68
|
+
if @dry_run
|
69
|
+
migrate_to_file
|
70
|
+
elsif @from_file
|
71
|
+
migrate_from_file
|
72
|
+
else
|
73
|
+
migrate_from_db
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def load_revmap_file(revmapfile)
|
80
|
+
# load revision mapping file and convert it to a hash.
|
81
|
+
# This revmap file allows to map between SVN revisions (rXXXX)
|
82
|
+
# and git commit sha1 hashes.
|
83
|
+
revmap = nil
|
84
|
+
if revmapfile
|
85
|
+
File.open(revmapfile, "r:UTF-8") do |f|
|
86
|
+
$logger.info("loading revision map #{revmapfile}")
|
87
|
+
|
88
|
+
revmap = f.each_line
|
89
|
+
.map { |line| line.split(/\s+\|\s+/) }
|
90
|
+
.map { |rev, sha, _| [rev.gsub(/^r/, ""), sha] }.to_h # remove leading "r" if present
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
revmap
|
95
|
+
end
|
96
|
+
|
97
|
+
def mock_ticket_details(ticket_id)
|
98
|
+
summary = if @filter_applied
|
99
|
+
"Not available in trac #{ticket_id}"
|
100
|
+
else
|
101
|
+
"DELETED in trac #{ticket_id}"
|
102
|
+
end
|
103
|
+
{
|
104
|
+
id: ticket_id,
|
105
|
+
summary: summary,
|
106
|
+
time: Time.now.to_i,
|
107
|
+
status: "closed",
|
108
|
+
reporter: "tractive"
|
109
|
+
}
|
110
|
+
end
|
111
|
+
|
112
|
+
def update_comment_ref(issue_id)
|
113
|
+
comments = @client.issue_comments(@repo, issue_id)
|
114
|
+
comments.each do |comment|
|
115
|
+
next unless comment["body"].include?("Replying to [comment:")
|
116
|
+
|
117
|
+
updated_comment_body = create_update_comment_params(comment, comments, issue_id)
|
118
|
+
@client.update_issue_comment(@repo, comment["id"], updated_comment_body)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def create_update_comment_params(comment, comments, issue_id)
|
123
|
+
body = comment["body"]
|
124
|
+
matcher = body.match(/Replying to \[comment:(?<comment_number>\d+).*\]/)
|
125
|
+
matched_comment = comments[matcher[:comment_number].to_i - 1]
|
126
|
+
body.gsub!(/Replying to \[comment:(\d+).*\]/, "Replying to [#{@repo}##{issue_id} (comment:\\1)](#{matched_comment["html_url"]})")
|
127
|
+
|
128
|
+
body
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tractive
|
4
|
+
class Ticket < Sequel::Model(:ticket)
|
5
|
+
one_to_many :changes, class: Tractive::TicketChange, key: :ticket
|
6
|
+
one_to_many :attachments, class: Attachment, key: :id, conditions: { type: "ticket" }
|
7
|
+
|
8
|
+
dataset_module do
|
9
|
+
def for_migration(start_ticket, filterout_closed, filter_options)
|
10
|
+
tickets = order(:id)
|
11
|
+
.where { id >= start_ticket }
|
12
|
+
.filter_column(filter_options)
|
13
|
+
|
14
|
+
tickets = tickets.exclude(status: "closed") if filterout_closed
|
15
|
+
|
16
|
+
tickets
|
17
|
+
end
|
18
|
+
|
19
|
+
def filter_column(options)
|
20
|
+
return self if options.nil? || options.values.compact.empty?
|
21
|
+
|
22
|
+
if options[:operator].downcase == "like"
|
23
|
+
where { Sequel.like(options[:column_name].to_sym, options[:column_value]) }
|
24
|
+
else
|
25
|
+
where { Sequel.lit("#{options[:column_name]} #{options[:operator]} '#{options[:column_value]}'") }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def all_changes
|
31
|
+
# combine the changes and attachment table results and sort them by date
|
32
|
+
change_arr = changes + attachments
|
33
|
+
change_arr.sort_by { |change| change[:time] }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tractive
|
4
|
+
class RevmapGenerator
|
5
|
+
def initialize(input_file, svn_url, svn_local_path, git_local_repo_path, output_file = "revmap.txt")
|
6
|
+
@input_file = input_file
|
7
|
+
@git_local_repo_path = git_local_repo_path
|
8
|
+
@svn_url = svn_url
|
9
|
+
@svn_local_path = svn_local_path
|
10
|
+
@duplicate_commits = {}
|
11
|
+
@duplicate_message_commits = {}
|
12
|
+
@last_revision = nil
|
13
|
+
@pinwheel = %w[| / - \\]
|
14
|
+
@output_file = output_file
|
15
|
+
end
|
16
|
+
|
17
|
+
def generate
|
18
|
+
line_count = File.read(@input_file).scan(/\n/).count
|
19
|
+
i = 0
|
20
|
+
|
21
|
+
File.open(@output_file, "w+") do |file|
|
22
|
+
File.foreach(@input_file) do |line|
|
23
|
+
info = extract_info_from_line(line)
|
24
|
+
next if @last_revision == info[:revision]
|
25
|
+
|
26
|
+
@last_revision = info[:revision]
|
27
|
+
print_revmap_info(info, file)
|
28
|
+
|
29
|
+
percent = ((i.to_f / line_count) * 100).round(2)
|
30
|
+
progress = "=" * (percent.to_i / 2) unless i < 2
|
31
|
+
printf("\rProgress: [%<progress>-50s] %<percent>.2f%% %<spinner>s", progress: progress, percent: percent, spinner: @pinwheel.rotate!.first)
|
32
|
+
i += 1
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def extract_info_from_line(line)
|
40
|
+
info = {}
|
41
|
+
|
42
|
+
info[:revision], timestamp_author = line.split
|
43
|
+
info[:revision], info[:revision_count] = info[:revision].split(".")
|
44
|
+
info[:revision].gsub!("SVN:", "r")
|
45
|
+
info[:timestamp], author_count = timestamp_author.split("!")
|
46
|
+
info[:author], info[:count] = author_count.split(":")
|
47
|
+
|
48
|
+
info
|
49
|
+
end
|
50
|
+
|
51
|
+
def print_revmap_info(info, file)
|
52
|
+
# get sha from git api
|
53
|
+
commits = git_commits(info)
|
54
|
+
|
55
|
+
if commits.count == 1
|
56
|
+
file.puts "#{info[:revision]} | #{commits.values[0].join(",")}"
|
57
|
+
else
|
58
|
+
message = commit_message_from_svn(info[:revision])
|
59
|
+
file.puts "#{info[:revision]} | #{@duplicate_commits[info[:timestamp]][message].join(",")}"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def git_commits(info)
|
64
|
+
return @duplicate_commits[info[:timestamp]] if @duplicate_commits[info[:timestamp]]
|
65
|
+
|
66
|
+
# get commits from git dir
|
67
|
+
commits = commits_from_git_repo(info)
|
68
|
+
|
69
|
+
commits_hash = {}
|
70
|
+
commits.each do |commit|
|
71
|
+
message = commit[:message]
|
72
|
+
sha = commit[:sha]
|
73
|
+
|
74
|
+
if commits_hash[message]
|
75
|
+
commits_hash[message] << sha
|
76
|
+
else
|
77
|
+
$logger.warn("'#{sha}' has same timestamp, commiter and commit messgae as '#{commits_hash[message]}'") unless commits_hash[message].nil?
|
78
|
+
commits_hash[message] = [sha]
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
@duplicate_commits[info[:timestamp]] = commits_hash if commits.count > 1
|
83
|
+
|
84
|
+
commits_hash
|
85
|
+
end
|
86
|
+
|
87
|
+
def commit_message_from_svn(revision)
|
88
|
+
svn_logs = Tractive::Utilities.svn_log(@svn_url, @svn_local_path, "-r": revision, "--xml": "")
|
89
|
+
h = Ox.load(svn_logs, mode: :hash)
|
90
|
+
h[:log][:logentry][3][:msg]
|
91
|
+
end
|
92
|
+
|
93
|
+
def commits_from_git_repo(info)
|
94
|
+
command = "git rev-list --after=#{info[:timestamp]} --until=#{info[:timestamp]} --committer=#{info[:author]} --all --format='%cd|%h~|~%s' --date=format:'%Y-%m-%dT%H:%M:%SZ'"
|
95
|
+
commits = Dir.chdir(@git_local_repo_path) do
|
96
|
+
`#{command}`
|
97
|
+
end
|
98
|
+
|
99
|
+
commits_arr = []
|
100
|
+
commits.split("\n").each_slice(2) do |sha_hash, commit_info|
|
101
|
+
commit_hash = {}
|
102
|
+
commit_hash[:sha] = sha_hash.split.last
|
103
|
+
commit_hash[:short_sha], commit_hash[:message] = commit_info.split("~|~")
|
104
|
+
|
105
|
+
commits_arr << commit_hash
|
106
|
+
end
|
107
|
+
|
108
|
+
commits_arr
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tractive
|
4
|
+
class Trac
|
5
|
+
attr_reader :tickets, :changes, :sessions, :attachments
|
6
|
+
|
7
|
+
def initialize(db)
|
8
|
+
$logger.info("loading tickets")
|
9
|
+
@db = db
|
10
|
+
@tickets = Ticket
|
11
|
+
@changes = TicketChange
|
12
|
+
@sessions = Session
|
13
|
+
@attachments = Attachment
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Tractive
|
4
|
+
class Utilities
|
5
|
+
class << self
|
6
|
+
def make_hash(prefix, array)
|
7
|
+
array.map { |i| [i, "#{prefix}#{i}"] }.to_h
|
8
|
+
end
|
9
|
+
|
10
|
+
def setup_db!(db_url)
|
11
|
+
files_to_load = [
|
12
|
+
"lib/tractive/models/attachment.rb",
|
13
|
+
"lib/tractive/models/milestone.rb",
|
14
|
+
"lib/tractive/models/report.rb",
|
15
|
+
"lib/tractive/models/revision.rb",
|
16
|
+
"lib/tractive/models/session.rb",
|
17
|
+
"lib/tractive/models/ticket_change.rb",
|
18
|
+
"lib/tractive/models/ticket.rb"
|
19
|
+
]
|
20
|
+
db = Sequel.connect(db_url) if db_url
|
21
|
+
|
22
|
+
raise("could not connect to tractive database") unless db
|
23
|
+
|
24
|
+
files_to_load.each do |file|
|
25
|
+
require_relative "../../#{file}"
|
26
|
+
end
|
27
|
+
|
28
|
+
db
|
29
|
+
end
|
30
|
+
|
31
|
+
def setup_logger(options = {})
|
32
|
+
$logger = Logger.new(options[:output_stream])
|
33
|
+
$logger.level = options[:verbose] ? Logger::DEBUG : Logger::INFO
|
34
|
+
$logger.formatter = proc do |severity, datetime, _progname, msg|
|
35
|
+
time = datetime.strftime("%Y-%m-%d %H:%M:%S")
|
36
|
+
"[#{time}] #{severity}#{" " * (5 - severity.size + 1)}| #{msg}\n"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# returns the git commit hash for a specified revision (using revmap hash)
|
41
|
+
def map_changeset(str)
|
42
|
+
if @revmap&.key?(str)
|
43
|
+
"[r#{str}](../commit/#{@revmap[str]}) #{@revmap[str]}"
|
44
|
+
else
|
45
|
+
str
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def svn_log(url, local_path, flags = {})
|
50
|
+
command = "svn log"
|
51
|
+
command += " #{url}" if url
|
52
|
+
|
53
|
+
flags.each do |key, value|
|
54
|
+
command += " #{key}"
|
55
|
+
command += " #{value}" if value
|
56
|
+
end
|
57
|
+
|
58
|
+
if local_path
|
59
|
+
Dir.chdir(local_path) do
|
60
|
+
`#{command}`
|
61
|
+
end
|
62
|
+
else
|
63
|
+
`#{command}`
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
data/lib/tractive.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "tractive/graceful_quit"
|
4
|
+
require_relative "tractive/attachment_exporter"
|
5
|
+
require_relative "tractive/migrator"
|
6
|
+
require_relative "tractive/trac"
|
7
|
+
require_relative "tractive/info"
|
8
|
+
require_relative "tractive/version"
|
9
|
+
require_relative "tractive/main"
|
10
|
+
require_relative "tractive/utilities"
|
11
|
+
require_relative "tractive/github_api"
|
12
|
+
require_relative "tractive/revmap_generator"
|
13
|
+
require "json"
|
14
|
+
require "logger"
|
15
|
+
require "yaml"
|
16
|
+
require "rest-client"
|
17
|
+
require "optparse"
|
18
|
+
require "sequel"
|
19
|
+
require "set"
|
20
|
+
require "singleton"
|
21
|
+
require "uri"
|
22
|
+
require "pry"
|
23
|
+
require "thor"
|
24
|
+
require "ox"
|
25
|
+
|
26
|
+
module Tractive
|
27
|
+
class Error < StandardError; end
|
28
|
+
# Your code goes here...
|
29
|
+
end
|
data/tractive.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/tractive/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "tractive"
|
7
|
+
spec.version = Tractive::VERSION
|
8
|
+
spec.authors = ["Ribose"]
|
9
|
+
spec.email = ["open.source@ribose.com"]
|
10
|
+
|
11
|
+
spec.summary = "Exporting tool for Trac"
|
12
|
+
# spec.description = "TODO: Write a longer description or delete this line."
|
13
|
+
spec.homepage = "https://github.com/ietf-ribose/tractive"
|
14
|
+
spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
|
15
|
+
|
16
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
17
|
+
spec.metadata["source_code_uri"] = "https://github.com/ietf-ribose/tractive"
|
18
|
+
spec.metadata["changelog_uri"] = "https://github.com/ietf-ribose/tractive"
|
19
|
+
|
20
|
+
# Specify which files should be added to the gem when it is released.
|
21
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
22
|
+
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
23
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
|
24
|
+
end
|
25
|
+
spec.bindir = "exe"
|
26
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
27
|
+
spec.require_paths = ["lib"]
|
28
|
+
|
29
|
+
spec.add_dependency "mysql2"
|
30
|
+
spec.add_dependency "ox"
|
31
|
+
spec.add_dependency "rest-client"
|
32
|
+
spec.add_dependency "sequel"
|
33
|
+
spec.add_dependency "sqlite3"
|
34
|
+
spec.add_dependency "thor"
|
35
|
+
|
36
|
+
spec.add_development_dependency "pry"
|
37
|
+
end
|