tractive 1.0.14 → 1.0.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -1
- data/exe/tractive +2 -0
- data/lib/tractive/github_api/graph_ql_client/issues.rb +29 -0
- data/lib/tractive/github_api/graph_ql_client.rb +31 -0
- data/lib/tractive/github_api.rb +1 -0
- data/lib/tractive/info.rb +13 -0
- data/lib/tractive/main.rb +3 -1
- data/lib/tractive/migrator/converter/trac_to_github.rb +15 -11
- data/lib/tractive/migrator/engine/migrate_from_db.rb +41 -0
- data/lib/tractive/migrator/engine.rb +2 -0
- data/lib/tractive/version.rb +1 -1
- data/tractive.gemspec +1 -0
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8cde84b7e5731a9be33bbbdecc11abacca397665fa29e4734c01bc50c1823c46
|
4
|
+
data.tar.gz: e38bd03de9ed35f8bde8c371c30789815f9fbecbe9b5cb8535c1585ad9f2e4e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8e5fd7afc6dfab34b8514a3fa0d12eec6d98d697938a500f7142891c33fc5a4d5f32442da7503be59b112c361d7010e617fb6dab9f9f90b65d0917a98bded050
|
7
|
+
data.tar.gz: 2c0247ec8af3ac372f4244d9c8ac0c2b2dc0a1358f5be3d7619507640404b8db088b03e9c884fa3c4612ae160bfa97828fa41992c2d31e7470a45cdb736342dd
|
data/.rubocop.yml
CHANGED
data/exe/tractive
CHANGED
@@ -47,6 +47,8 @@ class TractiveCommand < CommandBase
|
|
47
47
|
desc: "Put all issue comments in the first message."
|
48
48
|
method_option "start", type: :numeric, aliases: ["-s", "--start-at"], banner: "<ID>",
|
49
49
|
desc: "Start migration from ticket with number <ID>"
|
50
|
+
method_option "make-owners-labels", type: :boolean,
|
51
|
+
desc: "If true, this will make a tag like `owner:<owner name>` and add it to the issue."
|
50
52
|
def migrate_tickets
|
51
53
|
Tractive::Main.new(options).run
|
52
54
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module GithubApi
|
4
|
+
class GraphQlClient
|
5
|
+
# Methods for the Issues API
|
6
|
+
module Issues
|
7
|
+
DELETE_ISSUE_QUERY = <<~QUERY
|
8
|
+
mutation ($input: DeleteIssueInput!) {
|
9
|
+
deleteIssue(input: $input) {
|
10
|
+
repository {
|
11
|
+
name
|
12
|
+
url
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
QUERY
|
17
|
+
|
18
|
+
def delete_issue(issue_id)
|
19
|
+
variables = {
|
20
|
+
"input" => {
|
21
|
+
"issueId" => issue_id
|
22
|
+
}
|
23
|
+
}
|
24
|
+
|
25
|
+
Client.query(DeleteIssueQuery, variables: variables)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "graph_ql_client/issues"
|
4
|
+
|
5
|
+
require "graphql/client"
|
6
|
+
require "graphql/client/http"
|
7
|
+
|
8
|
+
# Service to perform github actions
|
9
|
+
module GithubApi
|
10
|
+
class GraphQlClient
|
11
|
+
include GithubApi::GraphQlClient::Issues
|
12
|
+
|
13
|
+
HttpAdapter = GraphQL::Client::HTTP.new("https://api.github.com/graphql") do
|
14
|
+
attr_writer :token
|
15
|
+
|
16
|
+
def headers(_context)
|
17
|
+
{
|
18
|
+
"Authorization" => "bearer #{@token}"
|
19
|
+
}
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.add_constants(token)
|
24
|
+
HttpAdapter.token = token
|
25
|
+
|
26
|
+
GithubApi::GraphQlClient.const_set("Schema", GraphQL::Client.load_schema(HttpAdapter))
|
27
|
+
GithubApi::GraphQlClient.const_set("Client", GraphQL::Client.new(schema: Schema, execute: HttpAdapter))
|
28
|
+
GithubApi::GraphQlClient.const_set("DeleteIssueQuery", Client.parse(DELETE_ISSUE_QUERY))
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/tractive/github_api.rb
CHANGED
data/lib/tractive/info.rb
CHANGED
@@ -29,12 +29,25 @@ module Tractive
|
|
29
29
|
priorities = Ticket.distinct.select(:priority).select_map(:priority).compact
|
30
30
|
tracstates = Ticket.distinct.select(:status).select_map(:status).compact
|
31
31
|
|
32
|
+
keywords = Ticket.distinct
|
33
|
+
.select(:keywords)
|
34
|
+
.select_map(:keywords)
|
35
|
+
.map do |keyword|
|
36
|
+
keyword&.split(",")&.map do |k|
|
37
|
+
k.strip.gsub(" ", "_")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
.flatten
|
41
|
+
.uniq
|
42
|
+
.compact
|
43
|
+
|
32
44
|
{
|
33
45
|
"users" => Utilities.make_each_hash(users, %w[email name username]),
|
34
46
|
"milestones" => milestones,
|
35
47
|
"labels" => {
|
36
48
|
"type" => Utilities.make_hash("type_", types),
|
37
49
|
"resolution" => Utilities.make_hash("resolution_", resolutions),
|
50
|
+
"keywords" => Utilities.make_hash("keyword_", keywords),
|
38
51
|
"component" => Utilities.make_each_hash(components, %w[name color], "component: "),
|
39
52
|
"severity" => Utilities.make_each_hash(severity, %w[name color]),
|
40
53
|
"priority" => Utilities.make_each_hash(priorities, %w[name color]),
|
data/lib/tractive/main.rb
CHANGED
@@ -9,7 +9,9 @@ module Tractive
|
|
9
9
|
@cfg = YAML.load_file(@opts[:config])
|
10
10
|
|
11
11
|
@cfg["github"] ||= {}
|
12
|
-
@cfg["github"]["token"] = @opts["git-token"]
|
12
|
+
@cfg["github"]["token"] = @opts["git-token"] if @opts["git-token"]
|
13
|
+
|
14
|
+
GithubApi::GraphQlClient.add_constants(@cfg["github"]["token"]) unless @opts[:info]
|
13
15
|
|
14
16
|
Tractive::Utilities.setup_logger(output_stream: @opts[:logfile] || $stderr, verbose: @opts[:verbose])
|
15
17
|
@db = Tractive::Utilities.setup_db!(@opts["trac-database-path"] || @cfg["trac"]["database"])
|
@@ -16,6 +16,7 @@ module Migrator
|
|
16
16
|
@client = GithubApi::Client.new(access_token: args[:cfg]["github"]["token"])
|
17
17
|
@wiki_attachments_url = args[:cfg].dig("wiki", "attachments", "url")
|
18
18
|
@revmap_file_path = args[:opts][:revmapfile] || args[:cfg]["revmap_path"]
|
19
|
+
@make_owners_label = args[:opts]["make-owners-labels"] || args[:cfg]["make_owners_labels"]
|
19
20
|
@attachment_options = {
|
20
21
|
url: @attachurl,
|
21
22
|
hashed: args[:cfg].dig("ticket", "attachments", "hashed")
|
@@ -101,14 +102,11 @@ module Migrator
|
|
101
102
|
|
102
103
|
labels.delete(nil)
|
103
104
|
|
104
|
-
keywords = ticket[:keywords]
|
105
|
-
|
106
|
-
|
107
|
-
labels.add(@labels_cfg.fetch("keywords", {})[ticket[:keywords].downcase])
|
108
|
-
else
|
109
|
-
badges.add(@labels_cfg.fetch("keywords", {})[ticket[:keywords]])
|
110
|
-
end
|
105
|
+
keywords = ticket[:keywords]&.split(",") || []
|
106
|
+
keywords.each do |keyword|
|
107
|
+
badges.add(@labels_cfg.fetch("keywords", {})[keyword.strip])
|
111
108
|
end
|
109
|
+
|
112
110
|
# If the field is not set, it will be nil and generate an unprocessable json
|
113
111
|
|
114
112
|
milestone = @milestonemap[ticket[:milestone]]
|
@@ -121,6 +119,14 @@ module Migrator
|
|
121
119
|
|
122
120
|
github_assignee = map_assignee(ticket[:owner])
|
123
121
|
|
122
|
+
unless github_assignee.nil? || github_assignee.empty?
|
123
|
+
if @make_owners_label
|
124
|
+
labels.add("name" => "owner:#{github_assignee}")
|
125
|
+
else
|
126
|
+
badges.add("owner:#{github_assignee}")
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
124
130
|
badges = badges.to_a.compact.sort
|
125
131
|
badgetable = badges.map { |i| %(`#{i}`) }.join(" ")
|
126
132
|
badgetable += begin
|
@@ -132,8 +138,6 @@ module Migrator
|
|
132
138
|
|
133
139
|
# compose body
|
134
140
|
body = [badgetable, body, footer].join("\n\n___\n")
|
135
|
-
|
136
|
-
labels.add("name" => "owner:#{github_assignee}") unless github_assignee.nil? || github_assignee.empty?
|
137
141
|
labels = labels.map { |label| label["name"] }
|
138
142
|
|
139
143
|
issue = {
|
@@ -265,7 +269,7 @@ module Migrator
|
|
265
269
|
end
|
266
270
|
|
267
271
|
case kind
|
268
|
-
when "owner", "status", "title", "resolution", "priority", "component", "type", "severity", "platform", "milestone"
|
272
|
+
when "owner", "status", "title", "resolution", "priority", "component", "type", "severity", "platform", "milestone", "keywords"
|
269
273
|
old = meta[:oldvalue]
|
270
274
|
new = meta[:newvalue]
|
271
275
|
if old && new
|
@@ -345,7 +349,7 @@ module Migrator
|
|
345
349
|
end
|
346
350
|
|
347
351
|
def interested_in_change?(kind, newvalue)
|
348
|
-
!(%w[
|
352
|
+
!(%w[cc reporter version].include?(kind) ||
|
349
353
|
(kind == "comment" && (newvalue.nil? || newvalue.lstrip.empty?)))
|
350
354
|
end
|
351
355
|
|
@@ -23,6 +23,7 @@ module Migrator
|
|
23
23
|
begin
|
24
24
|
lasttracid = tractickets.last[:id]
|
25
25
|
rescue StandardError
|
26
|
+
delete_mocked_tickets if can_delete_mocked_tickets?
|
26
27
|
raise("trac has no ticket #{start_ticket}")
|
27
28
|
end
|
28
29
|
|
@@ -89,6 +90,46 @@ module Migrator
|
|
89
90
|
|
90
91
|
@last_created_issue = ticket[:id]
|
91
92
|
end
|
93
|
+
|
94
|
+
delete_mocked_tickets if can_delete_mocked_tickets?
|
95
|
+
end
|
96
|
+
|
97
|
+
def can_delete_mocked_tickets?
|
98
|
+
@delete_mocked_tickets
|
99
|
+
end
|
100
|
+
|
101
|
+
def delete_mocked_tickets
|
102
|
+
page = 1
|
103
|
+
issues = @client.issues(@repo, { filter: "all",
|
104
|
+
state: "closed",
|
105
|
+
page: page })
|
106
|
+
|
107
|
+
until issues.empty?
|
108
|
+
deleted = false
|
109
|
+
|
110
|
+
issues.each do |issue|
|
111
|
+
next if issue["title"] != "Placeholder issue #{issue["number"]} created to align Github issue and trac ticket numbers during migration."
|
112
|
+
|
113
|
+
response = @graph_ql_client.delete_issue(issue["node_id"])
|
114
|
+
|
115
|
+
if response.data.errors.any?
|
116
|
+
error_message = response.data
|
117
|
+
.errors
|
118
|
+
.messages
|
119
|
+
.map { |k, v| "#{k}: #{v}" }
|
120
|
+
.join(", ")
|
121
|
+
raise StandardError, error_message
|
122
|
+
end
|
123
|
+
|
124
|
+
deleted = true
|
125
|
+
puts "Successfully deleted issue ##{issue["number"]}, Title: #{issue["title"]}"
|
126
|
+
end
|
127
|
+
|
128
|
+
page += 1 unless deleted
|
129
|
+
issues = @client.issues(@repo, { filter: "all",
|
130
|
+
state: "closed",
|
131
|
+
page: page })
|
132
|
+
end
|
92
133
|
end
|
93
134
|
end
|
94
135
|
end
|
@@ -32,6 +32,7 @@ module Migrator
|
|
32
32
|
@trac = Tractive::Trac.new(db)
|
33
33
|
@repo = github["repo"]
|
34
34
|
@client = GithubApi::Client.new(access_token: github["token"])
|
35
|
+
@graph_ql_client = GithubApi::GraphQlClient.new
|
35
36
|
|
36
37
|
if input_file_name
|
37
38
|
@from_file = input_file_name
|
@@ -62,6 +63,7 @@ module Migrator
|
|
62
63
|
@safetychecks = safetychecks
|
63
64
|
@start_ticket = (start_ticket || (@last_created_issue + 1)).to_i
|
64
65
|
@filter_closed = filter_closed
|
66
|
+
@delete_mocked_tickets = args[:cfg]["ticket"]["delete_mocked"]
|
65
67
|
end
|
66
68
|
|
67
69
|
def migrate
|
data/lib/tractive/version.rb
CHANGED
data/tractive.gemspec
CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
28
28
|
spec.require_paths = ["lib"]
|
29
29
|
|
30
|
+
spec.add_dependency "graphql-client"
|
30
31
|
spec.add_dependency "mysql2"
|
31
32
|
spec.add_dependency "ox"
|
32
33
|
spec.add_dependency "rest-client"
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tractive
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.15
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ribose
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-01-
|
11
|
+
date: 2022-01-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: graphql-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: mysql2
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -145,6 +159,8 @@ files:
|
|
145
159
|
- lib/tractive/github_api/client/issues.rb
|
146
160
|
- lib/tractive/github_api/client/labels.rb
|
147
161
|
- lib/tractive/github_api/client/milestones.rb
|
162
|
+
- lib/tractive/github_api/graph_ql_client.rb
|
163
|
+
- lib/tractive/github_api/graph_ql_client/issues.rb
|
148
164
|
- lib/tractive/graceful_quit.rb
|
149
165
|
- lib/tractive/http/client.rb
|
150
166
|
- lib/tractive/http/client/request.rb
|