tractive 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|