tractive 1.0.1 → 1.0.5
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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.adoc +69 -20
- data/config.example.yaml +41 -10
- data/exe/tractive +3 -2
- data/lib/tractive/github_api/client/labels.rb +33 -0
- data/lib/tractive/github_api/client.rb +2 -0
- data/lib/tractive/info.rb +4 -4
- data/lib/tractive/migrator/converter/trac_to_github.rb +25 -6
- data/lib/tractive/migrator/engine.rb +1 -1
- data/lib/tractive/models/ticket.rb +4 -1
- data/lib/tractive/revmap_generator.rb +22 -9
- data/lib/tractive/utilities.rb +7 -0
- data/lib/tractive/version.rb +1 -1
- metadata +3 -2
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: db1fec86bca93ac81ac4ce8c4f1e6fb99f0983743c55fc3275a95188c8178e0e
         | 
| 4 | 
            +
              data.tar.gz: f2907430c9a64b4cd5e0004050c1d7eddf11a18f94a4a007bf5315706a73e23b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1828a51469e9418188cd72195b51b245bb47921b7fbc883287bd089f9b2da58d18fbf08411c9f5cc33ed4a4a92259e365931afe281e1cf810a16c97a0632fa1a
         | 
| 7 | 
            +
              data.tar.gz: f898f265b58c41ca3ae59ee20cf52ec50ced92045a1595f23ea50e66bb4b0bd911a8695cfdc34b3a41a248a8b11bcb3a20be70eb8193aba8a7867c3f9ba4cc1e
         | 
    
        data/Gemfile.lock
    CHANGED
    
    
    
        data/README.adoc
    CHANGED
    
    | @@ -1,5 +1,4 @@ | |
| 1 1 | 
             
            = Tractive: migrating from Trac to GitHub
         | 
| 2 | 
            -
             | 
| 3 2 | 
             
            == Purpose
         | 
| 4 3 |  | 
| 5 4 | 
             
            Tractive is a tool that helps you migrate Trac instances to GitHub.
         | 
| @@ -194,15 +193,17 @@ user interface. | |
| 194 193 |  | 
| 195 194 | 
             
            | `--svn-url`
         | 
| 196 195 | 
             
            |
         | 
| 197 | 
            -
            (required | 
| 198 | 
            -
             | 
| 199 | 
            -
            prefix).
         | 
| 196 | 
            +
            (required unless `--svn-local-path` set)
         | 
| 197 | 
            +
            SVN repository URL that should be used in RevMap generation. The URL must start
         | 
| 198 | 
            +
            with the `http://` or `https://` prefix (not the `svn://` prefix).
         | 
| 200 199 | 
             
            | String
         | 
| 201 200 |  | 
| 202 201 | 
             
            | `--svn-local-path`
         | 
| 203 | 
            -
            | | 
| 204 | 
            -
             | 
| 205 | 
            -
             | 
| 202 | 
            +
            |
         | 
| 203 | 
            +
            (required unless `-svn-url` set)
         | 
| 204 | 
            +
            SVN local repository path that should be used in RevMap generation. You can
         | 
| 205 | 
            +
            clone the svn repo locally and provide its local path if the svn repository is
         | 
| 206 | 
            +
            offline.
         | 
| 206 207 | 
             
            | String
         | 
| 207 208 |  | 
| 208 209 | 
             
            | `--rev-timestamp-file`
         | 
| @@ -384,25 +385,55 @@ The pattern of a mapping is like: | |
| 384 385 | 
             
            +
         | 
| 385 386 | 
             
            [source,yaml]
         | 
| 386 387 | 
             
            ----
         | 
| 387 | 
            -
               | 
| 388 | 
            -
             | 
| 389 | 
            -
             | 
| 390 | 
            -
               | 
| 391 | 
            -
             | 
| 392 | 
            -
             | 
| 393 | 
            -
               | 
| 394 | 
            -
             | 
| 388 | 
            +
              trivial:
         | 
| 389 | 
            +
                name: trivial
         | 
| 390 | 
            +
                color: ff0000
         | 
| 391 | 
            +
              major:
         | 
| 392 | 
            +
                name: major
         | 
| 393 | 
            +
                color: b44647
         | 
| 394 | 
            +
              minor:
         | 
| 395 | 
            +
                name: minor
         | 
| 396 | 
            +
                color: f7347a
         | 
| 397 | 
            +
              medium:
         | 
| 398 | 
            +
                name: medium
         | 
| 399 | 
            +
                color: f3c77c
         | 
| 395 400 | 
             
            ----
         | 
| 396 401 |  | 
| 397 402 | 
             
            `priority:`::: Priority of the Trac ticket.
         | 
| 398 403 | 
             
            +
         | 
| 399 404 | 
             
            [source,yaml]
         | 
| 400 405 | 
             
            ----
         | 
| 401 | 
            -
              Low: | 
| 402 | 
            -
             | 
| 406 | 
            +
              Low:
         | 
| 407 | 
            +
                name: low
         | 
| 408 | 
            +
                color: 22dd00
         | 
| 409 | 
            +
              High:
         | 
| 410 | 
            +
                name: high
         | 
| 411 | 
            +
                color: ff0000
         | 
| 412 | 
            +
            ----
         | 
| 413 | 
            +
             | 
| 414 | 
            +
             | 
| 415 | 
            +
            `tracstate:`::: Status of the Trac ticket.
         | 
| 416 | 
            +
            +
         | 
| 417 | 
            +
            [source,yaml]
         | 
| 418 | 
            +
            ----
         | 
| 419 | 
            +
              accepted:
         | 
| 420 | 
            +
                name: accepted
         | 
| 421 | 
            +
                color: 22dd00
         | 
| 422 | 
            +
              assigned:
         | 
| 423 | 
            +
                name: assigned
         | 
| 424 | 
            +
                color: aadd88
         | 
| 425 | 
            +
              closed:
         | 
| 426 | 
            +
                name: closed
         | 
| 427 | 
            +
                color: ee00aa
         | 
| 428 | 
            +
              new:
         | 
| 429 | 
            +
                name: new
         | 
| 430 | 
            +
                color:
         | 
| 403 431 | 
             
            ----
         | 
| 404 432 |  | 
| 405 433 |  | 
| 434 | 
            +
            NOTE: As `severity`, `priority` and `tracstate` are converted into `labels` on github so there is an option to specify the `color` for those labels.
         | 
| 435 | 
            +
             | 
| 436 | 
            +
             | 
| 406 437 | 
             
            ==== User mapping
         | 
| 407 438 |  | 
| 408 439 | 
             
            `users:`:: a one-to-one mapping between Trac usernames or email addresses to
         | 
| @@ -411,7 +442,10 @@ GitHub usernames for users, in the following pattern: | |
| 411 442 | 
             
            [source,yaml]
         | 
| 412 443 | 
             
            ----
         | 
| 413 444 | 
             
            users:
         | 
| 414 | 
            -
              {Trac email or username}: | 
| 445 | 
            +
              {Trac email or username}:
         | 
| 446 | 
            +
                email: {Github email}
         | 
| 447 | 
            +
                name: {name of the person}
         | 
| 448 | 
            +
                username: {username on GitHub}
         | 
| 415 449 | 
             
              ...
         | 
| 416 450 | 
             
            ----
         | 
| 417 451 |  | 
| @@ -420,8 +454,23 @@ EXAMPLE: | |
| 420 454 | 
             
            [source,yaml]
         | 
| 421 455 | 
             
            ----
         | 
| 422 456 | 
             
            users:
         | 
| 423 | 
            -
              matthew@ | 
| 424 | 
            -
             | 
| 457 | 
            +
              matthew@gmail.org:
         | 
| 458 | 
            +
                email: matthew@example.org
         | 
| 459 | 
            +
                name: Matthew
         | 
| 460 | 
            +
                username: example-matt
         | 
| 461 | 
            +
              valencia:
         | 
| 462 | 
            +
                email: valencia
         | 
| 463 | 
            +
                name: Valencia
         | 
| 464 | 
            +
                username: example-vale
         | 
| 465 | 
            +
            ----
         | 
| 466 | 
            +
             | 
| 467 | 
            +
            If you don't want to map a user, you can just leave the `username` empty like below:
         | 
| 468 | 
            +
            ----
         | 
| 469 | 
            +
            users:
         | 
| 470 | 
            +
              matthew@gmail.org:
         | 
| 471 | 
            +
                email: matthew@example.org
         | 
| 472 | 
            +
                name: Matthew
         | 
| 473 | 
            +
                username:
         | 
| 425 474 | 
             
            ----
         | 
| 426 475 |  | 
| 427 476 | 
             
            ==== Milestone mapping
         | 
    
        data/config.example.yaml
    CHANGED
    
    | @@ -24,9 +24,16 @@ revmap_path: ./example-revmap.txt | |
| 24 24 | 
             
            #   the issue migration process will fail if the GitHub user specified as owner
         | 
| 25 25 | 
             
            #   (assignee) does not exist.
         | 
| 26 26 | 
             
            users:
         | 
| 27 | 
            -
              # <Trac email or username | 
| 28 | 
            -
               | 
| 29 | 
            -
               | 
| 27 | 
            +
              # email: <Trac email or username>
         | 
| 28 | 
            +
              # name: <Name of the person (optional)>
         | 
| 29 | 
            +
              # username: <username on GitHub>
         | 
| 30 | 
            +
              - email: matthew@example.org
         | 
| 31 | 
            +
                name: Matthew
         | 
| 32 | 
            +
                username: example-matt
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              - email: valencia
         | 
| 35 | 
            +
                name: Valencia
         | 
| 36 | 
            +
                username: example-vale
         | 
| 30 37 |  | 
| 31 38 | 
             
            # Label mapping from Trac ticket to GitHub label
         | 
| 32 39 | 
             
            labels:
         | 
| @@ -47,14 +54,38 @@ labels: | |
| 47 54 |  | 
| 48 55 | 
             
              # less useful, but also possible:
         | 
| 49 56 | 
             
              priority:
         | 
| 50 | 
            -
                Low: | 
| 51 | 
            -
             | 
| 57 | 
            +
                Low:
         | 
| 58 | 
            +
                  name:             low
         | 
| 59 | 
            +
                  color:            22dd00
         | 
| 60 | 
            +
                High:
         | 
| 61 | 
            +
                  name:             high
         | 
| 62 | 
            +
                  color:            ff0000
         | 
| 52 63 | 
             
              severity:
         | 
| 53 | 
            -
                 | 
| 54 | 
            -
             | 
| 55 | 
            -
             | 
| 56 | 
            -
                 | 
| 57 | 
            -
             | 
| 64 | 
            +
                trivial:
         | 
| 65 | 
            +
                  name:             trivial
         | 
| 66 | 
            +
                  color:            ff0000
         | 
| 67 | 
            +
                major:
         | 
| 68 | 
            +
                  name:             major
         | 
| 69 | 
            +
                  color:            b44647
         | 
| 70 | 
            +
                minor:
         | 
| 71 | 
            +
                  name:             minor
         | 
| 72 | 
            +
                  color:            f7347a
         | 
| 73 | 
            +
                medium:
         | 
| 74 | 
            +
                  name:             medium
         | 
| 75 | 
            +
                  color:            f3c77c
         | 
| 76 | 
            +
              tracstate:
         | 
| 77 | 
            +
                accepted:
         | 
| 78 | 
            +
                  name:             accepted
         | 
| 79 | 
            +
                  color:            22dd00
         | 
| 80 | 
            +
                assigned:
         | 
| 81 | 
            +
                  name:             assigned
         | 
| 82 | 
            +
                  color:            aadd88
         | 
| 83 | 
            +
                closed:
         | 
| 84 | 
            +
                  name:             closed
         | 
| 85 | 
            +
                  color:            ee00aa
         | 
| 86 | 
            +
                new:
         | 
| 87 | 
            +
                  name:             new
         | 
| 88 | 
            +
                  color:
         | 
| 58 89 | 
             
              version:
         | 
| 59 90 | 
             
                '1.3':              v1.3
         | 
| 60 91 | 
             
                '1.4':              v1.4
         | 
    
        data/exe/tractive
    CHANGED
    
    | @@ -5,6 +5,8 @@ require_relative "../lib/tractive" | |
| 5 5 |  | 
| 6 6 | 
             
            class TractiveCommand < Thor
         | 
| 7 7 | 
             
              default_command :migrate
         | 
| 8 | 
            +
              class_option "logfile", type: :string, aliases: ["-L", "--log-file"],
         | 
| 9 | 
            +
                                      desc: "Name of the logfile to output logs to."
         | 
| 8 10 |  | 
| 9 11 | 
             
              desc "<OPTIONS>", "Migrate Trac instances to modern Git management platforms like GitHub and GitLab"
         | 
| 10 12 | 
             
              method_option "attachmentexporter", type: :string, aliases: ["-A", "--attachment-exporter"],
         | 
| @@ -33,8 +35,6 @@ class TractiveCommand < Thor | |
| 33 35 | 
             
                                              desc: "Import issues from a json file"
         | 
| 34 36 | 
             
              method_option "info", type: :boolean, aliases: ["-i", "--info"],
         | 
| 35 37 | 
             
                                    desc: "Reports existing labels and users in the database"
         | 
| 36 | 
            -
              method_option "logfile", type: :string, aliases: ["-L", "--log-file"],
         | 
| 37 | 
            -
                                       desc: "Name of the logfile to output logs to."
         | 
| 38 38 | 
             
              method_option "mockdeleted", type: :boolean, aliases: ["-M", "--mockup"],
         | 
| 39 39 | 
             
                                           desc: "Import from 0 and mocking tickets deleted on trac"
         | 
| 40 40 | 
             
              method_option "openedonly", type: :boolean, aliases: ["-o", "--opened-only"],
         | 
| @@ -64,6 +64,7 @@ class TractiveCommand < Thor | |
| 64 64 | 
             
              def generate_revmap
         | 
| 65 65 | 
             
                verify_revmap_generator_options!(options)
         | 
| 66 66 |  | 
| 67 | 
            +
                Tractive::Utilities.setup_logger(output_stream: options[:log_file] || $stderr, verbose: options[:verbose])
         | 
| 67 68 | 
             
                Tractive::RevmapGenerator.new(
         | 
| 68 69 | 
             
                  options["revtimestampfile"],
         | 
| 69 70 | 
             
                  options["svnurl"],
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module GithubApi
         | 
| 4 | 
            +
              class Client
         | 
| 5 | 
            +
                module Labels
         | 
| 6 | 
            +
                  def list_labels(repo, params = {})
         | 
| 7 | 
            +
                    JSON.parse(
         | 
| 8 | 
            +
                      RestClient.get(
         | 
| 9 | 
            +
                        "https://api.github.com/repos/#{repo}/labels",
         | 
| 10 | 
            +
                        {
         | 
| 11 | 
            +
                          "Authorization" => "token #{@token}",
         | 
| 12 | 
            +
                          params: params
         | 
| 13 | 
            +
                        }
         | 
| 14 | 
            +
                      )
         | 
| 15 | 
            +
                    )
         | 
| 16 | 
            +
                  end
         | 
| 17 | 
            +
                  alias labels list_labels
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def create_label(repo, params)
         | 
| 20 | 
            +
                    JSON.parse(
         | 
| 21 | 
            +
                      RestClient.post(
         | 
| 22 | 
            +
                        "https://api.github.com/repos/#{repo}/labels",
         | 
| 23 | 
            +
                        params.to_json,
         | 
| 24 | 
            +
                        {
         | 
| 25 | 
            +
                          "Authorization" => "token #{@token}",
         | 
| 26 | 
            +
                          "Accept" => "application/vnd.github.v3+json"
         | 
| 27 | 
            +
                        }
         | 
| 28 | 
            +
                      )
         | 
| 29 | 
            +
                    )
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -1,12 +1,14 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 3 | 
             
            require_relative "client/issues"
         | 
| 4 | 
            +
            require_relative "client/labels"
         | 
| 4 5 | 
             
            require_relative "client/milestones"
         | 
| 5 6 |  | 
| 6 7 | 
             
            # Service to perform github actions
         | 
| 7 8 | 
             
            module GithubApi
         | 
| 8 9 | 
             
              class Client
         | 
| 9 10 | 
             
                include GithubApi::Client::Issues
         | 
| 11 | 
            +
                include GithubApi::Client::Labels
         | 
| 10 12 | 
             
                include GithubApi::Client::Milestones
         | 
| 11 13 |  | 
| 12 14 | 
             
                def initialize(options = {})
         | 
    
        data/lib/tractive/info.rb
    CHANGED
    
    | @@ -30,15 +30,15 @@ module Tractive | |
| 30 30 | 
             
                  tracstates  = Ticket.distinct.select(:status).select_map(:status).compact
         | 
| 31 31 |  | 
| 32 32 | 
             
                  {
         | 
| 33 | 
            -
                    "users" => Utilities. | 
| 33 | 
            +
                    "users" => Utilities.make_each_hash(users, %w[email name username]),
         | 
| 34 34 | 
             
                    "milestones" => milestones,
         | 
| 35 35 | 
             
                    "labels" => {
         | 
| 36 36 | 
             
                      "type" => Utilities.make_hash("type_", types),
         | 
| 37 37 | 
             
                      "component" => Utilities.make_hash("component_", components),
         | 
| 38 38 | 
             
                      "resolution" => Utilities.make_hash("resolution_", resolutions),
         | 
| 39 | 
            -
                      "severity" => Utilities. | 
| 40 | 
            -
                      "priority" => Utilities. | 
| 41 | 
            -
                      "tracstate" => Utilities. | 
| 39 | 
            +
                      "severity" => Utilities.make_each_hash(severity, %w[name color]),
         | 
| 40 | 
            +
                      "priority" => Utilities.make_each_hash(priorities, %w[name color]),
         | 
| 41 | 
            +
                      "tracstate" => Utilities.make_each_hash(tracstates, %w[name color])
         | 
| 42 42 | 
             
                    }
         | 
| 43 43 | 
             
                  }
         | 
| 44 44 | 
             
                end
         | 
| @@ -17,6 +17,9 @@ module Migrator | |
| 17 17 | 
             
                    @wiki_attachments_url = args[:cfg]["trac"]["wiki_attachments_url"]
         | 
| 18 18 |  | 
| 19 19 | 
             
                    load_milestone_map
         | 
| 20 | 
            +
                    create_labels_on_github(@labels_cfg["severity"].values)
         | 
| 21 | 
            +
                    create_labels_on_github(@labels_cfg["priority"].values)
         | 
| 22 | 
            +
                    create_labels_on_github(@labels_cfg["tracstate"].values)
         | 
| 20 23 |  | 
| 21 24 | 
             
                    @uri_parser = URI::Parser.new
         | 
| 22 25 | 
             
                    @twf_to_markdown = Migrator::Converter::TwfToMarkdown.new(@tracticketbaseurl, @attachurl, @changeset_base_url, @wiki_attachments_url)
         | 
| @@ -116,7 +119,8 @@ module Migrator | |
| 116 119 | 
             
                    # compose body
         | 
| 117 120 | 
             
                    body = [badgetable, body, footer].join("\n\n___\n")
         | 
| 118 121 |  | 
| 119 | 
            -
                    labels.add("owner:#{github_assignee}")
         | 
| 122 | 
            +
                    labels.add("name" => "owner:#{github_assignee}") unless github_assignee.nil? || github_assignee.empty?
         | 
| 123 | 
            +
                    labels = labels.map { |label| label["name"] }
         | 
| 120 124 |  | 
| 121 125 | 
             
                    issue = {
         | 
| 122 126 | 
             
                      "title" => ticket[:summary],
         | 
| @@ -129,7 +133,7 @@ module Migrator | |
| 129 133 |  | 
| 130 134 | 
             
                    if @users.key?(ticket[:owner])
         | 
| 131 135 | 
             
                      owner = trac_mail(ticket[:owner])
         | 
| 132 | 
            -
                      github_owner = @users[owner]
         | 
| 136 | 
            +
                      github_owner = @users[owner]["username"]
         | 
| 133 137 | 
             
                      $logger.debug("..owner in trac: #{owner}")
         | 
| 134 138 | 
             
                      $logger.debug("..assignee in GitHub: #{github_owner}")
         | 
| 135 139 | 
             
                      issue["assignee"] = github_owner
         | 
| @@ -155,11 +159,11 @@ module Migrator | |
| 155 159 | 
             
                  private
         | 
| 156 160 |  | 
| 157 161 | 
             
                  def map_user(user)
         | 
| 158 | 
            -
                    @users[ | 
| 162 | 
            +
                    @users.fetch(user, {})["email"] || user
         | 
| 159 163 | 
             
                  end
         | 
| 160 164 |  | 
| 161 165 | 
             
                  def map_assignee(user)
         | 
| 162 | 
            -
                    @users[ | 
| 166 | 
            +
                    @users.fetch(user, {})["email"]
         | 
| 163 167 | 
             
                  end
         | 
| 164 168 |  | 
| 165 169 | 
             
                  def load_milestone_map
         | 
| @@ -168,9 +172,9 @@ module Migrator | |
| 168 172 | 
             
                    newmilestonekeys = @milestonesfromtrac.keys - @milestonemap.keys
         | 
| 169 173 |  | 
| 170 174 | 
             
                    newmilestonekeys.each do |milestonelabel|
         | 
| 171 | 
            -
                      milestone | 
| 175 | 
            +
                      milestone = {
         | 
| 172 176 | 
             
                        "title" => milestonelabel.to_s,
         | 
| 173 | 
            -
                        "state" => @milestonesfromtrac[milestonelabel][:completed]. | 
| 177 | 
            +
                        "state" => @milestonesfromtrac[milestonelabel][:completed].to_i.zero? ? "open" : "closed",
         | 
| 174 178 | 
             
                        "description" => @milestonesfromtrac[milestonelabel][:description] || "no description in trac",
         | 
| 175 179 | 
             
                        "due_on" => "2012-10-09T23:39:01Z"
         | 
| 176 180 | 
             
                      }
         | 
| @@ -194,6 +198,21 @@ module Migrator | |
| 194 198 | 
             
                    nil
         | 
| 195 199 | 
             
                  end
         | 
| 196 200 |  | 
| 201 | 
            +
                  def create_labels_on_github(labels)
         | 
| 202 | 
            +
                    return if labels.nil? || labels.empty?
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    existing_labels = @client.labels(@repo, per_page: 100).map { |label| label["name"] }
         | 
| 205 | 
            +
                    new_labels = labels.reject { |label| existing_labels.include?(label["name"]) }
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                    new_labels.each do |label|
         | 
| 208 | 
            +
                      params = { name: label["name"] }
         | 
| 209 | 
            +
                      params["color"] = label["color"] unless label["color"].nil?
         | 
| 210 | 
            +
             | 
| 211 | 
            +
                      @client.create_label(@repo, params)
         | 
| 212 | 
            +
                      $logger.info("Created label: #{label["name"]}")
         | 
| 213 | 
            +
                    end
         | 
| 214 | 
            +
                  end
         | 
| 215 | 
            +
             | 
| 197 216 | 
             
                  def ticket_change(append, meta)
         | 
| 198 217 | 
             
                    # kind
         | 
| 199 218 | 
             
                    kind = if meta[:ticket]
         | 
| @@ -58,7 +58,7 @@ module Migrator | |
| 58 58 | 
             
                  @dry_run          = args[:opts][:dryrun]
         | 
| 59 59 | 
             
                  @output_file      = File.new(dry_run_output_file, "w+")
         | 
| 60 60 | 
             
                  @delimiter        = "{"
         | 
| 61 | 
            -
                  @revmap           = load_revmap_file(args[:opts][:revmapfile] || args[:cfg][" | 
| 61 | 
            +
                  @revmap           = load_revmap_file(args[:opts][:revmapfile] || args[:cfg]["revmap_path"])
         | 
| 62 62 | 
             
                  @safetychecks     = safetychecks
         | 
| 63 63 | 
             
                  @start_ticket     = (start_ticket || (@last_created_issue + 1)).to_i
         | 
| 64 64 | 
             
                  @filter_closed    = filter_closed
         | 
| @@ -19,8 +19,11 @@ module Tractive | |
| 19 19 | 
             
                  def filter_column(options)
         | 
| 20 20 | 
             
                    return self if options.nil? || options.values.compact.empty?
         | 
| 21 21 |  | 
| 22 | 
            -
                     | 
| 22 | 
            +
                    case options[:operator].downcase
         | 
| 23 | 
            +
                    when "like"
         | 
| 23 24 | 
             
                      where { Sequel.like(options[:column_name].to_sym, options[:column_value]) }
         | 
| 25 | 
            +
                    when "not like"
         | 
| 26 | 
            +
                      where { ~Sequel.like(options[:column_name].to_sym, options[:column_value]) }
         | 
| 24 27 | 
             
                    else
         | 
| 25 28 | 
             
                      where { Sequel.lit("#{options[:column_name]} #{options[:operator]} '#{options[:column_value]}'") }
         | 
| 26 29 | 
             
                    end
         | 
| @@ -11,6 +11,7 @@ module Tractive | |
| 11 11 | 
             
                  @duplicate_message_commits = {}
         | 
| 12 12 | 
             
                  @last_revision = nil
         | 
| 13 13 | 
             
                  @pinwheel = %w[| / - \\]
         | 
| 14 | 
            +
                  @skipped = []
         | 
| 14 15 | 
             
                  @output_file = output_file
         | 
| 15 16 | 
             
                end
         | 
| 16 17 |  | 
| @@ -20,6 +21,7 @@ module Tractive | |
| 20 21 |  | 
| 21 22 | 
             
                  File.open(@output_file, "w+") do |file|
         | 
| 22 23 | 
             
                    File.foreach(@input_file) do |line|
         | 
| 24 | 
            +
                      i += 1
         | 
| 23 25 | 
             
                      info = extract_info_from_line(line)
         | 
| 24 26 | 
             
                      next if @last_revision == info[:revision]
         | 
| 25 27 |  | 
| @@ -29,9 +31,10 @@ module Tractive | |
| 29 31 | 
             
                      percent = ((i.to_f / line_count) * 100).round(2)
         | 
| 30 32 | 
             
                      progress = "=" * (percent.to_i / 2) unless i < 2
         | 
| 31 33 | 
             
                      printf("\rProgress: [%<progress>-50s] %<percent>.2f%% %<spinner>s", progress: progress, percent: percent, spinner: @pinwheel.rotate!.first)
         | 
| 32 | 
            -
                      i += 1
         | 
| 33 34 | 
             
                    end
         | 
| 34 35 | 
             
                  end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                  $logger.info "\n\nFollowing revisions are skipped because they don't have a corresponding git commit. #{@skipped}"
         | 
| 35 38 | 
             
                end
         | 
| 36 39 |  | 
| 37 40 | 
             
                private
         | 
| @@ -52,11 +55,13 @@ module Tractive | |
| 52 55 | 
             
                  # get sha from git api
         | 
| 53 56 | 
             
                  commits = git_commits(info)
         | 
| 54 57 |  | 
| 55 | 
            -
                  if commits. | 
| 56 | 
            -
                     | 
| 58 | 
            +
                  if commits.empty?
         | 
| 59 | 
            +
                    @skipped << info[:revision]
         | 
| 60 | 
            +
                  elsif commits.count == 1
         | 
| 61 | 
            +
                    file.puts "#{info[:revision]} | #{commits.values[0]&.join(",")}"
         | 
| 57 62 | 
             
                  else
         | 
| 58 63 | 
             
                    message = commit_message_from_svn(info[:revision])
         | 
| 59 | 
            -
                    file.puts "#{info[:revision]} | #{@duplicate_commits[info[:timestamp]][message] | 
| 64 | 
            +
                    file.puts "#{info[:revision]} | #{@duplicate_commits[info[:timestamp]][message]&.join(",")}"
         | 
| 60 65 | 
             
                  end
         | 
| 61 66 | 
             
                end
         | 
| 62 67 |  | 
| @@ -91,16 +96,24 @@ module Tractive | |
| 91 96 | 
             
                end
         | 
| 92 97 |  | 
| 93 98 | 
             
                def commits_from_git_repo(info)
         | 
| 94 | 
            -
                   | 
| 99 | 
            +
                  shas_command = "git rev-list --after=#{info[:timestamp]} --until=#{info[:timestamp]} --committer=#{info[:author]} --all"
         | 
| 100 | 
            +
                  shas = Dir.chdir(@git_local_repo_path) do
         | 
| 101 | 
            +
                    `#{shas_command}`
         | 
| 102 | 
            +
                  end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                  commits_command = "git rev-list --after=#{info[:timestamp]} --until=#{info[:timestamp]} --committer=#{info[:author]} --all --format='medium'"
         | 
| 95 105 | 
             
                  commits = Dir.chdir(@git_local_repo_path) do
         | 
| 96 | 
            -
                    `#{ | 
| 106 | 
            +
                    `#{commits_command}`
         | 
| 97 107 | 
             
                  end
         | 
| 98 108 |  | 
| 109 | 
            +
                  regex = /#{shas.split("\n").map { |sha| "(?=commit #{sha})" }.join "|"}/
         | 
| 110 | 
            +
             | 
| 99 111 | 
             
                  commits_arr = []
         | 
| 100 | 
            -
                  commits.split( | 
| 112 | 
            +
                  commits.split(regex).each do |commit_info|
         | 
| 101 113 | 
             
                    commit_hash = {}
         | 
| 102 | 
            -
                     | 
| 103 | 
            -
                    commit_hash[: | 
| 114 | 
            +
                    info = commit_info.split("\n", 4)
         | 
| 115 | 
            +
                    commit_hash[:sha] = info[0].split.last
         | 
| 116 | 
            +
                    commit_hash[:message] = info.last.strip.gsub("\n", "").gsub(/\s+/, " ")
         | 
| 104 117 |  | 
| 105 118 | 
             
                    commits_arr << commit_hash
         | 
| 106 119 | 
             
                  end
         | 
    
        data/lib/tractive/utilities.rb
    CHANGED
    
    | @@ -7,6 +7,13 @@ module Tractive | |
| 7 7 | 
             
                    array.map { |i| [i, "#{prefix}#{i}"] }.to_h
         | 
| 8 8 | 
             
                  end
         | 
| 9 9 |  | 
| 10 | 
            +
                  def make_each_hash(values, keys)
         | 
| 11 | 
            +
                    values.map do |value|
         | 
| 12 | 
            +
                      value = [value] unless value.is_a?(Array)
         | 
| 13 | 
            +
                      [value[0], keys.zip(value).to_h]
         | 
| 14 | 
            +
                    end.to_h
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
             | 
| 10 17 | 
             
                  def setup_db!(db_url)
         | 
| 11 18 | 
             
                    files_to_load = [
         | 
| 12 19 | 
             
                      "lib/tractive/models/attachment.rb",
         | 
    
        data/lib/tractive/version.rb
    CHANGED
    
    
    
        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. | 
| 4 | 
            +
              version: 1.0.5
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Ribose
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2021-10- | 
| 11 | 
            +
            date: 2021-10-21 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: mysql2
         | 
| @@ -140,6 +140,7 @@ files: | |
| 140 140 | 
             
            - lib/tractive/github_api.rb
         | 
| 141 141 | 
             
            - lib/tractive/github_api/client.rb
         | 
| 142 142 | 
             
            - lib/tractive/github_api/client/issues.rb
         | 
| 143 | 
            +
            - lib/tractive/github_api/client/labels.rb
         | 
| 143 144 | 
             
            - lib/tractive/github_api/client/milestones.rb
         | 
| 144 145 | 
             
            - lib/tractive/graceful_quit.rb
         | 
| 145 146 | 
             
            - lib/tractive/info.rb
         |