tractive 1.0.14 → 1.0.18

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: 0db013dccdcc48d417706b5f52036b4c5801b4d81d6a835c09ee4b1afc6480db
4
- data.tar.gz: 4603e9e32107e75a4e2f495dc4a93cbc4e810a65c2bee576721e7d58d4be78cd
3
+ metadata.gz: e08becfcae314c82bdc793b7eb6bc2f7b52f9a7be040b7141da825753a9f1af2
4
+ data.tar.gz: 51385bdf7fcf7b12b110c852b9d0b9dc277240abf0b8c2f94b68b77db2839c32
5
5
  SHA512:
6
- metadata.gz: 5cf948f6fd3aed7f3b67778e91e9d88e7e1f9586824e21c4a1a0a4a42b42a14eedac4df7d5bf7627e182741ccf35865e195c1990c18e008b352b43bee08d4f4a
7
- data.tar.gz: f2b76c16fdf603a4d084df7a895f6ffdef16b4fc9297e6f039d9894e4b95a14a6d31ef090399983f46e68f4b904485df41102f3749926aef8adffee8e7d4011a
6
+ metadata.gz: ad89e67997dd07cb3b6d65c5baca788033991122d8a10a73a64b09df79695ed8e2488b033dfaaa5fdd07d4a65c4ee5b4230121f3f7f094c8286bce352bcd6118
7
+ data.tar.gz: 04f60f8190dbc644367c3095f28e4f7fddba04dfa5140a820dfbced58430fb3b1df1bb9c72dd10dadba6e4f66e1cfe9a2ea57f647bbf982452643824e87622f8
data/.rubocop.yml CHANGED
@@ -36,7 +36,7 @@ Metrics/MethodLength:
36
36
  Enabled: false
37
37
 
38
38
  Metrics/ModuleLength:
39
- Max: 150
39
+ Max: 250
40
40
 
41
41
  Metrics/ParameterLists:
42
42
  Max: 6
data/README.adoc CHANGED
@@ -506,6 +506,8 @@ milestones:
506
506
  ==== Attachments migration configuration
507
507
  `ticket | wiki:`:: specifies the options for the tickets or wikis
508
508
 
509
+ `delete_mocked:`::: Whether to delete mocked tickets after migration or not
510
+
509
511
  `attachments:`::: specifies method of obtaining attachments from Trac.
510
512
 
511
513
  `url:`:::: URL to obtain Trac attachments from
@@ -517,9 +519,12 @@ milestones:
517
519
  `export_script:`:::: output of a script that utilizes `trac-admin` to download
518
520
  all attachments from Trac.
519
521
 
522
+ NOTE: To delete the issues, an organization owner must enable deleting an issue for the organization's repositories, and you must have admin or owner permissions in the repository. For more information, see "https://docs.github.com/en/issues/tracking-your-work-with-issues/deleting-an-issue[deleting an issue]".
523
+
520
524
  [source,yaml]
521
525
  ----
522
526
  ticket:
527
+ delete_mocked: true
523
528
  attachments:
524
529
  url: https://abc.com/raw-attachment/ticket
525
530
  hashed: true
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
@@ -1,3 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "github_api/client"
4
+ require_relative "github_api/graph_ql_client"
@@ -22,7 +22,7 @@ module Http
22
22
  minutes = retry_after / 60
23
23
  seconds = retry_after % 60
24
24
 
25
- print "\rRate Limit Exceeded, Will retry in #{minutes} min #{seconds} sec"
25
+ $logger.info "Rate Limit Exceeded, Will retry in #{minutes} min #{seconds} sec"
26
26
  sleep(1)
27
27
 
28
28
  retry_after = e.http_headers[:x_ratelimit_reset].to_i - Time.now.to_i
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
- if keywords
106
- if ticket[:keywords].downcase == "discuss"
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.gsub(" ", "_")])
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[keywords cc reporter version].include?(kind) ||
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tractive
4
- VERSION = "1.0.14"
4
+ VERSION = "1.0.18"
5
5
  end
data/tractive.gemspec CHANGED
@@ -27,6 +27,8 @@ 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", "1.13.3"
31
+ spec.add_dependency "graphql-client"
30
32
  spec.add_dependency "mysql2"
31
33
  spec.add_dependency "ox"
32
34
  spec.add_dependency "rest-client"
metadata CHANGED
@@ -1,15 +1,43 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tractive
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.14
4
+ version: 1.0.18
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 00:00:00.000000000 Z
11
+ date: 2022-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: graphql
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '='
18
+ - !ruby/object:Gem::Version
19
+ version: 1.13.3
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '='
25
+ - !ruby/object:Gem::Version
26
+ version: 1.13.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: graphql-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
13
41
  - !ruby/object:Gem::Dependency
14
42
  name: mysql2
15
43
  requirement: !ruby/object:Gem::Requirement
@@ -145,6 +173,8 @@ files:
145
173
  - lib/tractive/github_api/client/issues.rb
146
174
  - lib/tractive/github_api/client/labels.rb
147
175
  - lib/tractive/github_api/client/milestones.rb
176
+ - lib/tractive/github_api/graph_ql_client.rb
177
+ - lib/tractive/github_api/graph_ql_client/issues.rb
148
178
  - lib/tractive/graceful_quit.rb
149
179
  - lib/tractive/http/client.rb
150
180
  - lib/tractive/http/client/request.rb