ghi 0.3.1 → 0.9.0.dev
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.
- data/bin/ghi +2 -4
- data/lib/ghi.rb +112 -42
- data/lib/ghi/authorization.rb +71 -0
- data/lib/ghi/client.rb +126 -0
- data/lib/ghi/commands.rb +20 -0
- data/lib/ghi/commands/assign.rb +53 -0
- data/lib/ghi/commands/close.rb +45 -0
- data/lib/ghi/commands/command.rb +114 -0
- data/lib/ghi/commands/comment.rb +104 -0
- data/lib/ghi/commands/config.rb +35 -0
- data/lib/ghi/commands/edit.rb +49 -0
- data/lib/ghi/commands/help.rb +62 -0
- data/lib/ghi/commands/label.rb +153 -0
- data/lib/ghi/commands/list.rb +133 -0
- data/lib/ghi/commands/milestone.rb +150 -0
- data/lib/ghi/commands/open.rb +69 -0
- data/lib/ghi/commands/show.rb +21 -0
- data/lib/ghi/commands/version.rb +16 -0
- data/lib/ghi/formatting.rb +301 -0
- data/lib/ghi/formatting/colors.rb +295 -0
- data/lib/ghi/json.rb +1304 -0
- metadata +71 -49
- data/README.rdoc +0 -126
- data/lib/ghi/api.rb +0 -145
- data/lib/ghi/cli.rb +0 -657
- data/lib/ghi/issue.rb +0 -30
- data/spec/ghi/api_spec.rb +0 -218
- data/spec/ghi/cli_spec.rb +0 -267
- data/spec/ghi/issue_spec.rb +0 -26
- data/spec/ghi_spec.rb +0 -62
    
        metadata
    CHANGED
    
    | @@ -1,70 +1,92 @@ | |
| 1 | 
            -
            --- !ruby/object:Gem::Specification
         | 
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: ghi
         | 
| 3 | 
            -
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
               | 
| 5 | 
            -
              prerelease: 
         | 
| 3 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            +
              hash: -1101288818
         | 
| 5 | 
            +
              prerelease: 6
         | 
| 6 | 
            +
              segments: 
         | 
| 7 | 
            +
              - 0
         | 
| 8 | 
            +
              - 9
         | 
| 9 | 
            +
              - 0
         | 
| 10 | 
            +
              - dev
         | 
| 11 | 
            +
              version: 0.9.0.dev
         | 
| 6 12 | 
             
            platform: ruby
         | 
| 7 | 
            -
            authors:
         | 
| 13 | 
            +
            authors: 
         | 
| 8 14 | 
             
            - Stephen Celis
         | 
| 9 15 | 
             
            autorequire: 
         | 
| 10 16 | 
             
            bindir: bin
         | 
| 11 17 | 
             
            cert_chain: []
         | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
                  - !ruby/object:Gem::Version
         | 
| 21 | 
            -
                    version: '2.0'
         | 
| 22 | 
            -
              type: :development
         | 
| 23 | 
            -
              prerelease: false
         | 
| 24 | 
            -
              version_requirements: *70100746900540
         | 
| 25 | 
            -
            description: GitHub Issues on the command line. Use your `$EDITOR`, not your browser.
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            date: 2012-04-04 00:00:00 -07:00
         | 
| 20 | 
            +
            default_executable: 
         | 
| 21 | 
            +
            dependencies: []
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            description: |
         | 
| 24 | 
            +
              GitHub Issues on the command line. Use your `$EDITOR`, not your browser.
         | 
| 25 | 
            +
             | 
| 26 26 | 
             
            email: stephen@stephencelis.com
         | 
| 27 | 
            -
            executables:
         | 
| 27 | 
            +
            executables: 
         | 
| 28 28 | 
             
            - ghi
         | 
| 29 29 | 
             
            extensions: []
         | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
            - lib/ghi/ | 
| 35 | 
            -
            - lib/ghi/ | 
| 36 | 
            -
            - lib/ghi/ | 
| 30 | 
            +
             | 
| 31 | 
            +
            extra_rdoc_files: []
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            files: 
         | 
| 34 | 
            +
            - lib/ghi/authorization.rb
         | 
| 35 | 
            +
            - lib/ghi/client.rb
         | 
| 36 | 
            +
            - lib/ghi/commands/assign.rb
         | 
| 37 | 
            +
            - lib/ghi/commands/close.rb
         | 
| 38 | 
            +
            - lib/ghi/commands/command.rb
         | 
| 39 | 
            +
            - lib/ghi/commands/comment.rb
         | 
| 40 | 
            +
            - lib/ghi/commands/config.rb
         | 
| 41 | 
            +
            - lib/ghi/commands/edit.rb
         | 
| 42 | 
            +
            - lib/ghi/commands/help.rb
         | 
| 43 | 
            +
            - lib/ghi/commands/label.rb
         | 
| 44 | 
            +
            - lib/ghi/commands/list.rb
         | 
| 45 | 
            +
            - lib/ghi/commands/milestone.rb
         | 
| 46 | 
            +
            - lib/ghi/commands/open.rb
         | 
| 47 | 
            +
            - lib/ghi/commands/show.rb
         | 
| 48 | 
            +
            - lib/ghi/commands/version.rb
         | 
| 49 | 
            +
            - lib/ghi/commands.rb
         | 
| 50 | 
            +
            - lib/ghi/formatting/colors.rb
         | 
| 51 | 
            +
            - lib/ghi/formatting.rb
         | 
| 52 | 
            +
            - lib/ghi/json.rb
         | 
| 37 53 | 
             
            - lib/ghi.rb
         | 
| 38 | 
            -
            -  | 
| 39 | 
            -
             | 
| 40 | 
            -
             | 
| 41 | 
            -
            - spec/ghi_spec.rb
         | 
| 42 | 
            -
            - README.rdoc
         | 
| 43 | 
            -
            homepage: http://github.com/stephencelis/ghi
         | 
| 54 | 
            +
            - bin/ghi
         | 
| 55 | 
            +
            has_rdoc: true
         | 
| 56 | 
            +
            homepage: https://github.com/stephencelis/ghi
         | 
| 44 57 | 
             
            licenses: []
         | 
| 58 | 
            +
             | 
| 45 59 | 
             
            post_install_message: 
         | 
| 46 | 
            -
            rdoc_options:
         | 
| 47 | 
            -
             | 
| 48 | 
            -
             | 
| 49 | 
            -
            require_paths:
         | 
| 60 | 
            +
            rdoc_options: []
         | 
| 61 | 
            +
             | 
| 62 | 
            +
            require_paths: 
         | 
| 50 63 | 
             
            - lib
         | 
| 51 | 
            -
            required_ruby_version: !ruby/object:Gem::Requirement
         | 
| 64 | 
            +
            required_ruby_version: !ruby/object:Gem::Requirement 
         | 
| 52 65 | 
             
              none: false
         | 
| 53 | 
            -
              requirements:
         | 
| 54 | 
            -
              - -  | 
| 55 | 
            -
                - !ruby/object:Gem::Version
         | 
| 56 | 
            -
                   | 
| 57 | 
            -
             | 
| 66 | 
            +
              requirements: 
         | 
| 67 | 
            +
              - - ">="
         | 
| 68 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 69 | 
            +
                  hash: 3
         | 
| 70 | 
            +
                  segments: 
         | 
| 71 | 
            +
                  - 0
         | 
| 72 | 
            +
                  version: "0"
         | 
| 73 | 
            +
            required_rubygems_version: !ruby/object:Gem::Requirement 
         | 
| 58 74 | 
             
              none: false
         | 
| 59 | 
            -
              requirements:
         | 
| 60 | 
            -
              - -  | 
| 61 | 
            -
                - !ruby/object:Gem::Version
         | 
| 62 | 
            -
                   | 
| 75 | 
            +
              requirements: 
         | 
| 76 | 
            +
              - - ">"
         | 
| 77 | 
            +
                - !ruby/object:Gem::Version 
         | 
| 78 | 
            +
                  hash: 25
         | 
| 79 | 
            +
                  segments: 
         | 
| 80 | 
            +
                  - 1
         | 
| 81 | 
            +
                  - 3
         | 
| 82 | 
            +
                  - 1
         | 
| 83 | 
            +
                  version: 1.3.1
         | 
| 63 84 | 
             
            requirements: []
         | 
| 85 | 
            +
             | 
| 64 86 | 
             
            rubyforge_project: 
         | 
| 65 | 
            -
            rubygems_version: 1. | 
| 87 | 
            +
            rubygems_version: 1.6.2
         | 
| 66 88 | 
             
            signing_key: 
         | 
| 67 89 | 
             
            specification_version: 3
         | 
| 68 90 | 
             
            summary: GitHub Issues command line interface
         | 
| 69 91 | 
             
            test_files: []
         | 
| 70 | 
            -
             | 
| 92 | 
            +
             | 
    
        data/README.rdoc
    DELETED
    
    | @@ -1,126 +0,0 @@ | |
| 1 | 
            -
            = ghi
         | 
| 2 | 
            -
             | 
| 3 | 
            -
            http://github.com/stephencelis/ghi
         | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
            GitHub Issues on the command line. Use your <tt>$EDITOR</tt>, not your
         | 
| 7 | 
            -
            browser.
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            == HOW?
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            Get:
         | 
| 12 | 
            -
             | 
| 13 | 
            -
              % gem install ghi
         | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
            Go:
         | 
| 17 | 
            -
             | 
| 18 | 
            -
              Usage: ghi [options]
         | 
| 19 | 
            -
                  -l, --list [state|term|number]
         | 
| 20 | 
            -
                      --search, --show
         | 
| 21 | 
            -
                  -v, --verbose
         | 
| 22 | 
            -
                      --ssl
         | 
| 23 | 
            -
                  -o, --open [title|number]
         | 
| 24 | 
            -
                      --reopen
         | 
| 25 | 
            -
                  -c, --closed, --close [number]
         | 
| 26 | 
            -
                  -e, --edit [number]
         | 
| 27 | 
            -
                  -r, --repo, --repository [name]
         | 
| 28 | 
            -
                  -m, --comment [number|comment]
         | 
| 29 | 
            -
                  -t, --label [number] [label]
         | 
| 30 | 
            -
                      --claim [number]
         | 
| 31 | 
            -
                  -d, --unlabel [number] [label]
         | 
| 32 | 
            -
                  -u, --url [state|number]
         | 
| 33 | 
            -
                      --[no-]color
         | 
| 34 | 
            -
                      --[no-]pager
         | 
| 35 | 
            -
                  -V, --version
         | 
| 36 | 
            -
                  -h, --help
         | 
| 37 | 
            -
             | 
| 38 | 
            -
             | 
| 39 | 
            -
            == EXAMPLE?
         | 
| 40 | 
            -
             | 
| 41 | 
            -
            ghi works simply from within a repository. Some short examples:
         | 
| 42 | 
            -
             | 
| 43 | 
            -
              ghi -l                    # Lists all open issues
         | 
| 44 | 
            -
              ghi                       # Shorter shorthand for "ghi -l"
         | 
| 45 | 
            -
              ghi -v                    # Lists all open issues, verbosely (includes body)
         | 
| 46 | 
            -
              ghi -lc                   # Lists all closed issues
         | 
| 47 | 
            -
              ghi -l "doesn't work"     # Searches for open issues matching "doesn't work"
         | 
| 48 | 
            -
              ghi -l invalid -c         # Searches for closed issues matching "invalid"
         | 
| 49 | 
            -
              ghi -l1                   # Shows issue 1
         | 
| 50 | 
            -
              ghi -1                    # Shorter shorthand for "ghi -l1"
         | 
| 51 | 
            -
              ghi 1                     # Shorter shorthand still
         | 
| 52 | 
            -
              ghi -o                    # Opens a new issue (in your $EDITOR)
         | 
| 53 | 
            -
              ghi -o "New issue"        # Opens a new issue with the title "New issue"
         | 
| 54 | 
            -
              ghi -o "Title" -m "Body"  # Opens a new issue with specified title and body
         | 
| 55 | 
            -
              ghi -e1                   # Edits issue number 1 (in your $EDITOR)
         | 
| 56 | 
            -
              ghi -e1 -m "New body"     # Edits issue number 1 with the specified body
         | 
| 57 | 
            -
              ghi -c1                   # Closes issue 1
         | 
| 58 | 
            -
              ghi -c1 -m                # Closes issue with comment (from your $EDITOR)
         | 
| 59 | 
            -
              ghi -c1 -m "Comment"      # Closes issue with specified comment
         | 
| 60 | 
            -
              ghi -o1                   # Reopens 1 (accepts comments, too)
         | 
| 61 | 
            -
              ghi -m1                   # Comments on issue 1 (in your $EDITOR)
         | 
| 62 | 
            -
              ghi -t1 "tag"             # Labels issue 1 with "tag"
         | 
| 63 | 
            -
              ghi -d1 "tag"             # Removes the label, "tag"
         | 
| 64 | 
            -
              ghi --claim 1             # Tags issue 1 with your GitHub username
         | 
| 65 | 
            -
              ghi -u                    # Loads issues in your browser.
         | 
| 66 | 
            -
              ghi -u1                   # Loads an issue in your browser.
         | 
| 67 | 
            -
             | 
| 68 | 
            -
             | 
| 69 | 
            -
            ghi also works anywhere:
         | 
| 70 | 
            -
             | 
| 71 | 
            -
              ghi -rghi                 # Your fork of "ghi"
         | 
| 72 | 
            -
              ghi -rstephencelis/ghi    # Mine: "stephencelis/ghi"
         | 
| 73 | 
            -
              ghi stephencelis/ghi      # Shorthand to merely list open.
         | 
| 74 | 
            -
             | 
| 75 | 
            -
             | 
| 76 | 
            -
            ghi uses ANSI colors if you use them in git.
         | 
| 77 | 
            -
             | 
| 78 | 
            -
            ghi looks for a <tt>$GHI_PAGER</tt> variable for paging.
         | 
| 79 | 
            -
             | 
| 80 | 
            -
            Always favor SSL by setting it:
         | 
| 81 | 
            -
             | 
| 82 | 
            -
              git config --global github.ssl true
         | 
| 83 | 
            -
             | 
| 84 | 
            -
             | 
| 85 | 
            -
            == CONTRIBUTORS
         | 
| 86 | 
            -
             | 
| 87 | 
            -
            * Jamie Macey (http://blog.tracefunc.com)
         | 
| 88 | 
            -
            * Hiroshi Nakamura (http://github.com/nahi)
         | 
| 89 | 
            -
            * David J. Hamilton
         | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
            === CONTRIBUTE?
         | 
| 93 | 
            -
             | 
| 94 | 
            -
            Running the tests should be as simple as a `bundle` and
         | 
| 95 | 
            -
            `bundle exec spec spec`.
         | 
| 96 | 
            -
             | 
| 97 | 
            -
            ghi is not under currently under the control of any gem packaging system. To
         | 
| 98 | 
            -
            build, use RubyGems:
         | 
| 99 | 
            -
             | 
| 100 | 
            -
              % gem build ghi.gemspec
         | 
| 101 | 
            -
              % sudo gem install ghi*.gem
         | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
            == LICENSE
         | 
| 105 | 
            -
             | 
| 106 | 
            -
            (The MIT License)
         | 
| 107 | 
            -
             | 
| 108 | 
            -
            (c) 2009-* Stephen Celis, stephen@stephencelis.com.
         | 
| 109 | 
            -
             | 
| 110 | 
            -
            Permission is hereby granted, free of charge, to any person obtaining a copy 
         | 
| 111 | 
            -
            of this software and associated documentation files (the "Software"), to deal 
         | 
| 112 | 
            -
            in the Software without restriction, including without limitation the rights 
         | 
| 113 | 
            -
            to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
         | 
| 114 | 
            -
            copies of the Software, and to permit persons to whom the Software is 
         | 
| 115 | 
            -
            furnished to do so, subject to the following conditions:
         | 
| 116 | 
            -
             | 
| 117 | 
            -
            The above copyright notice and this permission notice shall be included in all
         | 
| 118 | 
            -
            copies or substantial portions of the Software.
         | 
| 119 | 
            -
             | 
| 120 | 
            -
            THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
         | 
| 121 | 
            -
            IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
         | 
| 122 | 
            -
            FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
         | 
| 123 | 
            -
            AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
         | 
| 124 | 
            -
            LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
         | 
| 125 | 
            -
            OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
         | 
| 126 | 
            -
            SOFTWARE.
         | 
    
        data/lib/ghi/api.rb
    DELETED
    
    | @@ -1,145 +0,0 @@ | |
| 1 | 
            -
            require "net/https"
         | 
| 2 | 
            -
            require "yaml"
         | 
| 3 | 
            -
            require "cgi"
         | 
| 4 | 
            -
             | 
| 5 | 
            -
            class GHI::API
         | 
| 6 | 
            -
              class GHIError < StandardError
         | 
| 7 | 
            -
              end
         | 
| 8 | 
            -
             | 
| 9 | 
            -
              class InvalidRequest < GHIError
         | 
| 10 | 
            -
              end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
              class InvalidConnection < GHIError
         | 
| 13 | 
            -
              end
         | 
| 14 | 
            -
             | 
| 15 | 
            -
              class ResponseError < GHIError
         | 
| 16 | 
            -
              end
         | 
| 17 | 
            -
             | 
| 18 | 
            -
              API_HOST = "github.com"
         | 
| 19 | 
            -
              API_PATH = "/api/v2/yaml/issues/:action/:user/:repo"
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              attr_reader :user, :repo
         | 
| 22 | 
            -
             | 
| 23 | 
            -
              def initialize(user, repo, use_ssl = false)
         | 
| 24 | 
            -
                raise InvalidConnection if user.nil? || repo.nil?
         | 
| 25 | 
            -
                @user, @repo, @use_ssl = user, repo, use_ssl
         | 
| 26 | 
            -
              end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
              def search(term, state = :open)
         | 
| 29 | 
            -
                get(:search, state, term)["issues"].map { |attrs| GHI::Issue.new(attrs) }
         | 
| 30 | 
            -
              end
         | 
| 31 | 
            -
             | 
| 32 | 
            -
              def list(state = :open)
         | 
| 33 | 
            -
                get(:list, state)["issues"].map { |attrs| GHI::Issue.new(attrs) }
         | 
| 34 | 
            -
              end
         | 
| 35 | 
            -
             | 
| 36 | 
            -
              def show(number)
         | 
| 37 | 
            -
                GHI::Issue.new get(:show, number)["issue"]
         | 
| 38 | 
            -
              end
         | 
| 39 | 
            -
             | 
| 40 | 
            -
              def comments(number)
         | 
| 41 | 
            -
                get(:comments, number)["comments"]
         | 
| 42 | 
            -
              end
         | 
| 43 | 
            -
             | 
| 44 | 
            -
              def open(title, body)
         | 
| 45 | 
            -
                if title.empty? && body.empty?
         | 
| 46 | 
            -
                  raise GHIError, "Aborting request due to empty issue."
         | 
| 47 | 
            -
                end
         | 
| 48 | 
            -
                GHI::Issue.new post(:open, "title" => title, "body" => body)["issue"]
         | 
| 49 | 
            -
              end
         | 
| 50 | 
            -
             | 
| 51 | 
            -
              def edit(number, title, body)
         | 
| 52 | 
            -
                if title.empty? && body.empty?
         | 
| 53 | 
            -
                  raise GHIError, "Aborting request due to empty issue."
         | 
| 54 | 
            -
                end
         | 
| 55 | 
            -
                res = post :edit, number, "title" => title, "body" => body
         | 
| 56 | 
            -
                GHI::Issue.new res["issue"]
         | 
| 57 | 
            -
              end
         | 
| 58 | 
            -
             | 
| 59 | 
            -
              def close(number)
         | 
| 60 | 
            -
                GHI::Issue.new post(:close, number)["issue"]
         | 
| 61 | 
            -
              end
         | 
| 62 | 
            -
             | 
| 63 | 
            -
              def reopen(number)
         | 
| 64 | 
            -
                GHI::Issue.new post(:reopen, number)["issue"]
         | 
| 65 | 
            -
              end
         | 
| 66 | 
            -
             | 
| 67 | 
            -
              def add_label(label, number)
         | 
| 68 | 
            -
                post("label/add", label, number)["labels"]
         | 
| 69 | 
            -
              end
         | 
| 70 | 
            -
             | 
| 71 | 
            -
              def remove_label(label, number)
         | 
| 72 | 
            -
                post("label/remove", label, number)["labels"]
         | 
| 73 | 
            -
              end
         | 
| 74 | 
            -
             | 
| 75 | 
            -
              def comment(number, comment)
         | 
| 76 | 
            -
                if comment.empty?
         | 
| 77 | 
            -
                  raise GHIError, "Aborting request due to empty comment."
         | 
| 78 | 
            -
                end
         | 
| 79 | 
            -
                post(:comment, number, "comment" => comment)["comment"]
         | 
| 80 | 
            -
              end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
              private
         | 
| 83 | 
            -
             | 
| 84 | 
            -
              def get(*args)
         | 
| 85 | 
            -
                res = nil
         | 
| 86 | 
            -
                http = Net::HTTP.new(API_HOST, @use_ssl ? 443 : 80)
         | 
| 87 | 
            -
                http.use_ssl = true if @use_ssl
         | 
| 88 | 
            -
                http.start do
         | 
| 89 | 
            -
                  if @use_ssl
         | 
| 90 | 
            -
                    req = Net::HTTP::Post.new path(*args)
         | 
| 91 | 
            -
                    req.set_form_data auth
         | 
| 92 | 
            -
                  else
         | 
| 93 | 
            -
                    req = Net::HTTP::Get.new(path(*args) + auth(true))
         | 
| 94 | 
            -
                  end
         | 
| 95 | 
            -
                  res = YAML.load http.request(req).body
         | 
| 96 | 
            -
                end
         | 
| 97 | 
            -
             | 
| 98 | 
            -
                raise ResponseError, errors(res) if res["error"] || res[:error]
         | 
| 99 | 
            -
                res
         | 
| 100 | 
            -
              rescue ArgumentError, URI::InvalidURIError
         | 
| 101 | 
            -
                raise ResponseError, "GitHub hiccuped on your request"
         | 
| 102 | 
            -
              rescue SocketError
         | 
| 103 | 
            -
                raise ResponseError, "couldn't find the internet"
         | 
| 104 | 
            -
              end
         | 
| 105 | 
            -
             | 
| 106 | 
            -
              def post(*args)
         | 
| 107 | 
            -
                params = args.last.is_a?(Hash) ? args.pop : {}
         | 
| 108 | 
            -
             | 
| 109 | 
            -
                res = nil
         | 
| 110 | 
            -
                http = Net::HTTP.new(API_HOST, @use_ssl ? 443 : 80)
         | 
| 111 | 
            -
                http.use_ssl = true if @use_ssl
         | 
| 112 | 
            -
                http.start do
         | 
| 113 | 
            -
                  req = Net::HTTP::Post.new path(*args)
         | 
| 114 | 
            -
                  req.set_form_data params.merge(auth)
         | 
| 115 | 
            -
                  res = YAML.load http.request(req).body
         | 
| 116 | 
            -
                end
         | 
| 117 | 
            -
             | 
| 118 | 
            -
                raise ResponseError, errors(res) if res["error"] || res[:error]
         | 
| 119 | 
            -
                res
         | 
| 120 | 
            -
              rescue ArgumentError, URI::InvalidURIError
         | 
| 121 | 
            -
                raise ResponseError, "GitHub hiccuped on your request"
         | 
| 122 | 
            -
              rescue SocketError
         | 
| 123 | 
            -
                raise ResponseError, "couldn't find the internet"
         | 
| 124 | 
            -
              end
         | 
| 125 | 
            -
             | 
| 126 | 
            -
              def errors(response)
         | 
| 127 | 
            -
                return response[:error] if response.key? :error
         | 
| 128 | 
            -
                [*response["error"]].map { |e| e["error"] } * ", "
         | 
| 129 | 
            -
              end
         | 
| 130 | 
            -
             | 
| 131 | 
            -
              def auth(query = false)
         | 
| 132 | 
            -
                if query
         | 
| 133 | 
            -
                  "?login=#{GHI.login}&token=#{GHI.token}"
         | 
| 134 | 
            -
                else
         | 
| 135 | 
            -
                  { "login" => GHI.login, "token" => GHI.token }
         | 
| 136 | 
            -
                end
         | 
| 137 | 
            -
              end
         | 
| 138 | 
            -
             | 
| 139 | 
            -
              def path(action, *args)
         | 
| 140 | 
            -
                @path ||= API_PATH.sub(":user", user).sub(":repo", repo)
         | 
| 141 | 
            -
                path  = @path.sub ":action", action.to_s
         | 
| 142 | 
            -
                path << "/#{args.join("/")}" unless args.empty?
         | 
| 143 | 
            -
                path
         | 
| 144 | 
            -
              end
         | 
| 145 | 
            -
            end
         | 
    
        data/lib/ghi/cli.rb
    DELETED
    
    | @@ -1,657 +0,0 @@ | |
| 1 | 
            -
            require "optparse"
         | 
| 2 | 
            -
            require "tempfile"
         | 
| 3 | 
            -
            require "ghi"
         | 
| 4 | 
            -
            require "ghi/api"
         | 
| 5 | 
            -
            require "ghi/issue"
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            begin
         | 
| 8 | 
            -
              require "launchy"
         | 
| 9 | 
            -
            rescue LoadError
         | 
| 10 | 
            -
              # No launchy!
         | 
| 11 | 
            -
            end
         | 
| 12 | 
            -
             | 
| 13 | 
            -
            module GHI::CLI #:nodoc:
         | 
| 14 | 
            -
              module FileHelper
         | 
| 15 | 
            -
                def launch_editor(file)
         | 
| 16 | 
            -
                  system "#{editor} #{file.path}"
         | 
| 17 | 
            -
                end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                def gets_from_editor(issue)
         | 
| 20 | 
            -
                  if windows?
         | 
| 21 | 
            -
                    warn "Please supply the message with the -m option"
         | 
| 22 | 
            -
                    exit 1
         | 
| 23 | 
            -
                  end
         | 
| 24 | 
            -
             | 
| 25 | 
            -
                  if in_repo?
         | 
| 26 | 
            -
                    File.open message_path, "a+", &file_proc(issue)
         | 
| 27 | 
            -
                  else
         | 
| 28 | 
            -
                    Tempfile.open message_filename, &file_proc(issue)
         | 
| 29 | 
            -
                  end
         | 
| 30 | 
            -
             | 
| 31 | 
            -
                  return @message if comment?
         | 
| 32 | 
            -
                  return @message.shift.strip, @message.join.sub(/\b\n\b/, " ").strip
         | 
| 33 | 
            -
                end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                def delete_message
         | 
| 36 | 
            -
                  File.delete message_path
         | 
| 37 | 
            -
                rescue Errno::ENOENT, TypeError
         | 
| 38 | 
            -
                  nil
         | 
| 39 | 
            -
                end
         | 
| 40 | 
            -
             | 
| 41 | 
            -
                def message_path
         | 
| 42 | 
            -
                  File.join gitdir, message_filename
         | 
| 43 | 
            -
                end
         | 
| 44 | 
            -
             | 
| 45 | 
            -
                private
         | 
| 46 | 
            -
             | 
| 47 | 
            -
                def editor
         | 
| 48 | 
            -
                  ENV["GHI_EDITOR"] || ENV["GIT_EDITOR"] ||
         | 
| 49 | 
            -
                    `git config --get-all core.editor`.split.first || ENV["EDITOR"] || "vi"
         | 
| 50 | 
            -
                end
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def gitdir
         | 
| 53 | 
            -
                  @gitdir ||= `git rev-parse --git-dir 2>/dev/null`.chomp
         | 
| 54 | 
            -
                end
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                def message_filename
         | 
| 57 | 
            -
                  @message_filename ||= "GHI_#{action.to_s.upcase}#{number}_MESSAGE"
         | 
| 58 | 
            -
                end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                def file_proc(issue)
         | 
| 61 | 
            -
                  lambda do |file|
         | 
| 62 | 
            -
                    file << edit_format(issue).join("\n") if File.zero? file.path
         | 
| 63 | 
            -
                    file.rewind
         | 
| 64 | 
            -
                    launch_editor file
         | 
| 65 | 
            -
                    @message = File.readlines(file.path).find_all { |l| !l.match(/^#/) }
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                    if message.to_s =~ /\A\s*\Z/
         | 
| 68 | 
            -
                      raise GHI::API::InvalidRequest, "can't file empty message"
         | 
| 69 | 
            -
                    end
         | 
| 70 | 
            -
                    raise GHI::API::InvalidRequest, "no change" if issue == message
         | 
| 71 | 
            -
                  end
         | 
| 72 | 
            -
                end
         | 
| 73 | 
            -
             | 
| 74 | 
            -
                def in_repo?
         | 
| 75 | 
            -
                  !gitdir.empty? && user == local_user && repo == local_repo
         | 
| 76 | 
            -
                end
         | 
| 77 | 
            -
              end
         | 
| 78 | 
            -
             | 
| 79 | 
            -
              module FormattingHelper
         | 
| 80 | 
            -
                def list_header(term = nil)
         | 
| 81 | 
            -
                  if term
         | 
| 82 | 
            -
                    "# #{state.to_s.capitalize} #{term.inspect} issues on #{user}/#{repo}"
         | 
| 83 | 
            -
                  else
         | 
| 84 | 
            -
                    "# #{state.to_s.capitalize} issues on #{user}/#{repo}"
         | 
| 85 | 
            -
                  end
         | 
| 86 | 
            -
                end
         | 
| 87 | 
            -
             | 
| 88 | 
            -
                def list_format(issues, verbosity = nil)
         | 
| 89 | 
            -
                  unless issues.empty?
         | 
| 90 | 
            -
                    if verbosity
         | 
| 91 | 
            -
                      issues.map { |i| ["=" * 79] + show_format(i) }
         | 
| 92 | 
            -
                    else
         | 
| 93 | 
            -
                      issues.map { |i| "  #{i.number.to_s.rjust 3}: #{truncate(i.title, 72)} #{label_format(i.labels)}" }
         | 
| 94 | 
            -
                    end
         | 
| 95 | 
            -
                  else
         | 
| 96 | 
            -
                    "none"
         | 
| 97 | 
            -
                  end
         | 
| 98 | 
            -
                end
         | 
| 99 | 
            -
                
         | 
| 100 | 
            -
                def label_format(labels)
         | 
| 101 | 
            -
                  labels and labels.map {|l| "[#{l}]"}.join(' ')
         | 
| 102 | 
            -
                end
         | 
| 103 | 
            -
             | 
| 104 | 
            -
                def edit_format(issue)
         | 
| 105 | 
            -
                  l = []
         | 
| 106 | 
            -
                  l << issue.title if issue.title && !comment?
         | 
| 107 | 
            -
                  l << ""
         | 
| 108 | 
            -
                  l << issue.body  if issue.body  && !comment?
         | 
| 109 | 
            -
                  if comment?
         | 
| 110 | 
            -
                    l << "# Please enter your comment."
         | 
| 111 | 
            -
                  else
         | 
| 112 | 
            -
                    l << "# Please explain the issue. The first line will become the title."
         | 
| 113 | 
            -
                  end
         | 
| 114 | 
            -
                  l << "# Lines beginning '#' will be ignored; ghi aborts empty messages."
         | 
| 115 | 
            -
                  l << "# All line breaks will be honored in accordance with GFM:"
         | 
| 116 | 
            -
                  l << "#"
         | 
| 117 | 
            -
                  l << "#   http://github.github.com/github-flavored-markdown"
         | 
| 118 | 
            -
                  l << "#"
         | 
| 119 | 
            -
                  l << "# On #{user}/#{repo}:"
         | 
| 120 | 
            -
                  l << "#"
         | 
| 121 | 
            -
                  l += show_format(issue, false).map { |line| "# #{line}" }
         | 
| 122 | 
            -
                end
         | 
| 123 | 
            -
             | 
| 124 | 
            -
                def show_format(issue, verbose = true)
         | 
| 125 | 
            -
                  l = []
         | 
| 126 | 
            -
                  l << "      number:  #{issue.number}"                    if issue.number
         | 
| 127 | 
            -
                  l << "       state:  #{issue.state}"                     if issue.state
         | 
| 128 | 
            -
                  l << "       title:  #{indent(issue.title, 15, 0).join}" if issue.title
         | 
| 129 | 
            -
                  l << "      labels:  #{label_format(issue.labels)}"      unless issue.labels.nil? || issue.labels.empty?
         | 
| 130 | 
            -
                  l << "        user:  #{issue.user || GHI.login}"
         | 
| 131 | 
            -
                  l << "       votes:  #{issue.votes}"                     if issue.votes
         | 
| 132 | 
            -
                  l << "  created at:  #{issue.created_at}"                if issue.created_at
         | 
| 133 | 
            -
                  l << "  updated at:  #{issue.updated_at}"                if issue.updated_at
         | 
| 134 | 
            -
                  return l unless verbose
         | 
| 135 | 
            -
                  l << ""
         | 
| 136 | 
            -
                  l += indent(issue.body)[0..-2]
         | 
| 137 | 
            -
             | 
| 138 | 
            -
                  comments = api.comments(issue.number)
         | 
| 139 | 
            -
                  unless comments.empty?
         | 
| 140 | 
            -
                    l << "=" * 79
         | 
| 141 | 
            -
                    comments.each do |c|
         | 
| 142 | 
            -
                      l << "#{c["user"]} commented:"
         | 
| 143 | 
            -
                      l << ""
         | 
| 144 | 
            -
                      l += indent(c["body"])
         | 
| 145 | 
            -
                      l << "-" * 79
         | 
| 146 | 
            -
                    end
         | 
| 147 | 
            -
                  end
         | 
| 148 | 
            -
             | 
| 149 | 
            -
                  l
         | 
| 150 | 
            -
                end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                def action_format(value = nil)
         | 
| 153 | 
            -
                  key = "#{action.to_s.capitalize.sub(/e?$/, "ed")} issue #{number}"
         | 
| 154 | 
            -
                  "#{key}: #{truncate(value.to_s, 78 - key.length)}"
         | 
| 155 | 
            -
                end
         | 
| 156 | 
            -
             | 
| 157 | 
            -
                def truncate(string, length)
         | 
| 158 | 
            -
                  result = string.scan(/.{0,#{length - 3}}(?:\s|\Z)/).first.strip
         | 
| 159 | 
            -
                  result << "..." if result != string
         | 
| 160 | 
            -
                  result
         | 
| 161 | 
            -
                end
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                def indent(string, level = 4, first = level)
         | 
| 164 | 
            -
                  string = string.gsub(/\n{3,}/, "\n\n")
         | 
| 165 | 
            -
                  lines = string.scan(/.{0,#{79 - level}}(?:\s|\Z)/).map { |line|
         | 
| 166 | 
            -
                    " " * level + line
         | 
| 167 | 
            -
                  }
         | 
| 168 | 
            -
                  lines.first.sub!(/^\s+/) {} if first != level
         | 
| 169 | 
            -
                  lines
         | 
| 170 | 
            -
                end
         | 
| 171 | 
            -
             | 
| 172 | 
            -
                private
         | 
| 173 | 
            -
             | 
| 174 | 
            -
                def comment?
         | 
| 175 | 
            -
                  ![:open, :edit].include?(action)
         | 
| 176 | 
            -
                end
         | 
| 177 | 
            -
             | 
| 178 | 
            -
                def puts(*args)
         | 
| 179 | 
            -
                  args = args.flatten.each { |arg|
         | 
| 180 | 
            -
                    arg.gsub!(/\b\*(.+)\*\b/) { "\e[1m#$1\e[0m" } # Bold
         | 
| 181 | 
            -
                    arg.gsub!(/\b_(.+)_\b/) { "\e[4m#$1\e[0m" } # Underline
         | 
| 182 | 
            -
                    arg.gsub!(/(state:)?(# Open.*|  open)$/) { "#$1\e[32m#$2\e[0m" }
         | 
| 183 | 
            -
                    arg.gsub!(/(state:)?(# Closed.*|  closed)$/) { "#$1\e[31m#$2\e[0m" }
         | 
| 184 | 
            -
                    marked = [GHI.login, search_term, tag, "(?:#|gh)-\d+"].compact * "|"
         | 
| 185 | 
            -
                    unless arg.include? "\e"
         | 
| 186 | 
            -
                      arg.gsub!(/(#{marked})/i) { "\e[1;4;33m#{$&}\e[0m" }
         | 
| 187 | 
            -
                    end
         | 
| 188 | 
            -
                  } if colorize?
         | 
| 189 | 
            -
                rescue NoMethodError
         | 
| 190 | 
            -
                  # Do nothing.
         | 
| 191 | 
            -
                ensure
         | 
| 192 | 
            -
                  $stdout.puts(*args)
         | 
| 193 | 
            -
                end
         | 
| 194 | 
            -
             | 
| 195 | 
            -
                def colorize?
         | 
| 196 | 
            -
                  return @colorize if defined? @colorize
         | 
| 197 | 
            -
                  @colorize = if $stdout.isatty && !windows?
         | 
| 198 | 
            -
                    !`git config --get-regexp color`.chomp.empty?
         | 
| 199 | 
            -
                  else
         | 
| 200 | 
            -
                    false
         | 
| 201 | 
            -
                  end
         | 
| 202 | 
            -
                end
         | 
| 203 | 
            -
             | 
| 204 | 
            -
                def prepare_stdout
         | 
| 205 | 
            -
                  return if @prepared || @no_pager || !$stdout.isatty || pager.nil?
         | 
| 206 | 
            -
                  colorize? # Check for colorization.
         | 
| 207 | 
            -
                  $stdout = pager
         | 
| 208 | 
            -
                  @prepared = true
         | 
| 209 | 
            -
                end
         | 
| 210 | 
            -
             | 
| 211 | 
            -
                def pager
         | 
| 212 | 
            -
                  return @pager if defined? @pager
         | 
| 213 | 
            -
                  pager = ENV["GHI_PAGER"] || ENV["GIT_PAGER"] ||
         | 
| 214 | 
            -
                    `git config --get-all core.pager`.split.first || ENV["PAGER"] ||
         | 
| 215 | 
            -
                    "less -EMRX"
         | 
| 216 | 
            -
             | 
| 217 | 
            -
                  @pager = IO.popen(pager, "w")
         | 
| 218 | 
            -
                end
         | 
| 219 | 
            -
             | 
| 220 | 
            -
                def windows?
         | 
| 221 | 
            -
                  RUBY_PLATFORM.include? "mswin"
         | 
| 222 | 
            -
                end
         | 
| 223 | 
            -
              end
         | 
| 224 | 
            -
             | 
| 225 | 
            -
              class Executable
         | 
| 226 | 
            -
                include FileHelper, FormattingHelper
         | 
| 227 | 
            -
             | 
| 228 | 
            -
                attr_reader :message, :local_user, :local_repo, :user, :repo, :api,
         | 
| 229 | 
            -
                  :action, :search_term, :number, :title, :body, :tag, :args, :verbosity,
         | 
| 230 | 
            -
                  :use_ssl
         | 
| 231 | 
            -
             | 
| 232 | 
            -
                def parse!(*argv)
         | 
| 233 | 
            -
                  @args, @argv = argv, argv.dup
         | 
| 234 | 
            -
             | 
| 235 | 
            -
                  remotes = `git config --get-regexp remote\..+\.url`.split /\n/
         | 
| 236 | 
            -
                  repo_expression = %r{([^:/]+)/([^/\s]+?)(?:\.git)?$}
         | 
| 237 | 
            -
                  if remote = remotes.find { |r| r.include? "github.com" }
         | 
| 238 | 
            -
                    remote.match repo_expression
         | 
| 239 | 
            -
                    @user, @repo = $1, $2
         | 
| 240 | 
            -
                  end
         | 
| 241 | 
            -
             | 
| 242 | 
            -
                  option_parser.parse!(*args)
         | 
| 243 | 
            -
             | 
| 244 | 
            -
                  if action.nil? && fallback_parsing(*args).nil?
         | 
| 245 | 
            -
                    puts option_parser
         | 
| 246 | 
            -
                    exit
         | 
| 247 | 
            -
                  end
         | 
| 248 | 
            -
                rescue OptionParser::InvalidOption, OptionParser::InvalidArgument => e
         | 
| 249 | 
            -
                  if fallback_parsing(*e.args).nil?
         | 
| 250 | 
            -
                    warn "#{File.basename $0}: #{e.message}"
         | 
| 251 | 
            -
                    puts option_parser
         | 
| 252 | 
            -
                    exit 1
         | 
| 253 | 
            -
                  end
         | 
| 254 | 
            -
                rescue OptionParser::MissingArgument, OptionParser::AmbiguousOption => e
         | 
| 255 | 
            -
                  warn "#{File.basename $0}: #{e.message}"
         | 
| 256 | 
            -
                  puts option_parser
         | 
| 257 | 
            -
                  exit 1
         | 
| 258 | 
            -
                ensure
         | 
| 259 | 
            -
                  run!
         | 
| 260 | 
            -
                  $stdout.close_write
         | 
| 261 | 
            -
                end
         | 
| 262 | 
            -
             | 
| 263 | 
            -
                def run!
         | 
| 264 | 
            -
                  @api = GHI::API.new user, repo, use_ssl
         | 
| 265 | 
            -
             | 
| 266 | 
            -
                  case action
         | 
| 267 | 
            -
                    when :search        then search
         | 
| 268 | 
            -
                    when :list          then list
         | 
| 269 | 
            -
                    when :show          then show
         | 
| 270 | 
            -
                    when :open          then open
         | 
| 271 | 
            -
                    when :edit          then edit
         | 
| 272 | 
            -
                    when :close         then close
         | 
| 273 | 
            -
                    when :reopen        then reopen
         | 
| 274 | 
            -
                    when :comment       then prepare_comment && comment
         | 
| 275 | 
            -
                    when :label, :claim then prepare_label   && label
         | 
| 276 | 
            -
                    when :unlabel       then prepare_label   && unlabel
         | 
| 277 | 
            -
                    when :url           then url
         | 
| 278 | 
            -
                  end
         | 
| 279 | 
            -
                rescue GHI::API::InvalidConnection
         | 
| 280 | 
            -
                  if action
         | 
| 281 | 
            -
                    code = 1
         | 
| 282 | 
            -
                    warn "#{File.basename $0}: not a GitHub repo"
         | 
| 283 | 
            -
                    puts option_parser if args.flatten.empty?
         | 
| 284 | 
            -
                    exit 1
         | 
| 285 | 
            -
                  end
         | 
| 286 | 
            -
                rescue GHI::API::InvalidRequest => e
         | 
| 287 | 
            -
                  warn "#{File.basename $0}: #{e.message} (#{user}/#{repo})"
         | 
| 288 | 
            -
                  delete_message
         | 
| 289 | 
            -
                  exit 1
         | 
| 290 | 
            -
                rescue GHI::API::ResponseError => e
         | 
| 291 | 
            -
                  warn "#{File.basename $0}: #{e.message} (#{user}/#{repo})"
         | 
| 292 | 
            -
                  exit 1
         | 
| 293 | 
            -
                rescue GHI::API::GHIError => e
         | 
| 294 | 
            -
                  warn e.message
         | 
| 295 | 
            -
                  exit 1
         | 
| 296 | 
            -
                end
         | 
| 297 | 
            -
             | 
| 298 | 
            -
                def commenting?
         | 
| 299 | 
            -
                  @commenting
         | 
| 300 | 
            -
                end
         | 
| 301 | 
            -
             | 
| 302 | 
            -
                def state
         | 
| 303 | 
            -
                  @state || :open
         | 
| 304 | 
            -
                end
         | 
| 305 | 
            -
             | 
| 306 | 
            -
                private
         | 
| 307 | 
            -
             | 
| 308 | 
            -
                def option_parser
         | 
| 309 | 
            -
                  @option_parser ||= OptionParser.new { |opts|
         | 
| 310 | 
            -
                    opts.banner = "Usage: #{File.basename $0} [options]"
         | 
| 311 | 
            -
             | 
| 312 | 
            -
                    opts.on("-l", "--list", "--search", "--show [state|term|number]") do |v|
         | 
| 313 | 
            -
                      @action = :list
         | 
| 314 | 
            -
                      case v
         | 
| 315 | 
            -
                      when nil, /^o(?:pen)?$/
         | 
| 316 | 
            -
                        # Defaults.
         | 
| 317 | 
            -
                      when /^\d+$/
         | 
| 318 | 
            -
                        @action = :show
         | 
| 319 | 
            -
                        @number = v.to_i
         | 
| 320 | 
            -
                      when /^c(?:losed)?$/
         | 
| 321 | 
            -
                        @state = :closed
         | 
| 322 | 
            -
                      when /^[uw]$/
         | 
| 323 | 
            -
                        @action = :url
         | 
| 324 | 
            -
                      when /^v$/
         | 
| 325 | 
            -
                        @verbosity = true
         | 
| 326 | 
            -
                      else
         | 
| 327 | 
            -
                        @action = :search
         | 
| 328 | 
            -
                        @search_term = v
         | 
| 329 | 
            -
                      end
         | 
| 330 | 
            -
                    end
         | 
| 331 | 
            -
             | 
| 332 | 
            -
                    opts.on("-v", "--verbose") do |v|
         | 
| 333 | 
            -
                      if v
         | 
| 334 | 
            -
                        @action ||= :list
         | 
| 335 | 
            -
                        @verbosity = true
         | 
| 336 | 
            -
                      end
         | 
| 337 | 
            -
                    end
         | 
| 338 | 
            -
             | 
| 339 | 
            -
                    opts.on("--ssl") do |ssl|
         | 
| 340 | 
            -
                      @use_ssl = true
         | 
| 341 | 
            -
                    end
         | 
| 342 | 
            -
             | 
| 343 | 
            -
                    opts.on("-o", "--open", "--reopen [title|number]") do |v|
         | 
| 344 | 
            -
                      @action = :open
         | 
| 345 | 
            -
                      case v
         | 
| 346 | 
            -
                      when /^\d+$/
         | 
| 347 | 
            -
                        @action = :reopen
         | 
| 348 | 
            -
                        @number = v.to_i
         | 
| 349 | 
            -
                      when /^l$/
         | 
| 350 | 
            -
                        @action = :list
         | 
| 351 | 
            -
                      when /^m$/
         | 
| 352 | 
            -
                        @title = args * " "
         | 
| 353 | 
            -
                      when /^[uw]$/
         | 
| 354 | 
            -
                        @action = :url
         | 
| 355 | 
            -
                      else
         | 
| 356 | 
            -
                        @title = v
         | 
| 357 | 
            -
                      end
         | 
| 358 | 
            -
                    end
         | 
| 359 | 
            -
             | 
| 360 | 
            -
                    opts.on("-c", "--closed", "--close [number]") do |v|
         | 
| 361 | 
            -
                      case v
         | 
| 362 | 
            -
                      when /^\d+$/
         | 
| 363 | 
            -
                        @action = :close
         | 
| 364 | 
            -
                        @number = v.to_i unless v.nil?
         | 
| 365 | 
            -
                      when /^l$/
         | 
| 366 | 
            -
                        @action = :list
         | 
| 367 | 
            -
                        @state = :closed
         | 
| 368 | 
            -
                      when /^[uw]$/
         | 
| 369 | 
            -
                        @action = :url
         | 
| 370 | 
            -
                        @state = :closed
         | 
| 371 | 
            -
                      when nil
         | 
| 372 | 
            -
                        if @action.nil? || @number
         | 
| 373 | 
            -
                          @action = :close
         | 
| 374 | 
            -
                        else
         | 
| 375 | 
            -
                          @state = :closed
         | 
| 376 | 
            -
                        end
         | 
| 377 | 
            -
                      else
         | 
| 378 | 
            -
                        raise OptionParser::InvalidArgument
         | 
| 379 | 
            -
                      end
         | 
| 380 | 
            -
                    end
         | 
| 381 | 
            -
             | 
| 382 | 
            -
                    opts.on("-e", "--edit [number]") do |v|
         | 
| 383 | 
            -
                      case v
         | 
| 384 | 
            -
                      when /^\d+$/
         | 
| 385 | 
            -
                        @action = :edit
         | 
| 386 | 
            -
                        @number = v.to_i
         | 
| 387 | 
            -
                      when nil
         | 
| 388 | 
            -
                        raise OptionParser::MissingArgument
         | 
| 389 | 
            -
                      else
         | 
| 390 | 
            -
                        raise OptionParser::InvalidArgument
         | 
| 391 | 
            -
                      end
         | 
| 392 | 
            -
                    end
         | 
| 393 | 
            -
             | 
| 394 | 
            -
                    opts.on("-r", "--repo", "--repository [name]") do |v|
         | 
| 395 | 
            -
                      case v
         | 
| 396 | 
            -
                      when nil
         | 
| 397 | 
            -
                        raise OptionParser::MissingArgument
         | 
| 398 | 
            -
                      else
         | 
| 399 | 
            -
                        repo = v.split "/"
         | 
| 400 | 
            -
                        if repo.length == 1
         | 
| 401 | 
            -
                          if @repo && `git remote 2>/dev/null`[/^#{repo}$/]
         | 
| 402 | 
            -
                            repo << @repo
         | 
| 403 | 
            -
                          else
         | 
| 404 | 
            -
                            repo.unshift(GHI.login)
         | 
| 405 | 
            -
                          end
         | 
| 406 | 
            -
                        end
         | 
| 407 | 
            -
                        @user, @repo = repo
         | 
| 408 | 
            -
                      end
         | 
| 409 | 
            -
                    end
         | 
| 410 | 
            -
             | 
| 411 | 
            -
                    opts.on("-m", "--comment [number|comment]") do |v|
         | 
| 412 | 
            -
                      case v
         | 
| 413 | 
            -
                      when /^\d+$/, nil
         | 
| 414 | 
            -
                        @action ||= :comment
         | 
| 415 | 
            -
                        @number ||= v.to_i unless v.nil?
         | 
| 416 | 
            -
                        @commenting = true
         | 
| 417 | 
            -
                      else
         | 
| 418 | 
            -
                        @body = v
         | 
| 419 | 
            -
                      end
         | 
| 420 | 
            -
                    end
         | 
| 421 | 
            -
             | 
| 422 | 
            -
                    opts.on("-t", "--label [number] [label]") do |v|
         | 
| 423 | 
            -
                      raise OptionParser::MissingArgument if v.nil?
         | 
| 424 | 
            -
                      @action ||= :label
         | 
| 425 | 
            -
                      @number = v.to_i
         | 
| 426 | 
            -
                    end
         | 
| 427 | 
            -
             | 
| 428 | 
            -
                    opts.on("--claim [number]") do |v|
         | 
| 429 | 
            -
                      raise OptionParser::MissingArgument if v.nil?
         | 
| 430 | 
            -
                      @action = :claim
         | 
| 431 | 
            -
                      @number = v.to_i
         | 
| 432 | 
            -
                      @tag = GHI.login
         | 
| 433 | 
            -
                    end
         | 
| 434 | 
            -
             | 
| 435 | 
            -
                    opts.on("-d", "--unlabel [number] [label]") do |v|
         | 
| 436 | 
            -
                      @action = :unlabel
         | 
| 437 | 
            -
                      case v
         | 
| 438 | 
            -
                      when /^\d+$/
         | 
| 439 | 
            -
                        @number = v.to_i
         | 
| 440 | 
            -
                      when /^\w+$/
         | 
| 441 | 
            -
                        @tag = v
         | 
| 442 | 
            -
                      end
         | 
| 443 | 
            -
                    end
         | 
| 444 | 
            -
             | 
| 445 | 
            -
                    opts.on("-u", "-w", "--url", "--web [state|number]") do |v|
         | 
| 446 | 
            -
                      @action = :url
         | 
| 447 | 
            -
                      case v
         | 
| 448 | 
            -
                      when /^\d+$/
         | 
| 449 | 
            -
                        @number = v.to_i
         | 
| 450 | 
            -
                      when /^c(?:losed)?$/
         | 
| 451 | 
            -
                        @state = :closed
         | 
| 452 | 
            -
                      when /^u(?:nread)?$/
         | 
| 453 | 
            -
                        @state = :unread
         | 
| 454 | 
            -
                      end
         | 
| 455 | 
            -
                    end
         | 
| 456 | 
            -
             | 
| 457 | 
            -
                    opts.on("--[no-]color") do |v|
         | 
| 458 | 
            -
                      @colorize = v
         | 
| 459 | 
            -
                    end
         | 
| 460 | 
            -
             | 
| 461 | 
            -
                    opts.on("--[no-]pager") do |v|
         | 
| 462 | 
            -
                      @no_pager = (v == false)
         | 
| 463 | 
            -
                    end
         | 
| 464 | 
            -
             | 
| 465 | 
            -
                    opts.on_tail("-V", "--version") do
         | 
| 466 | 
            -
                      puts "#{File.basename($0)}: v#{GHI::VERSION}"
         | 
| 467 | 
            -
                      exit
         | 
| 468 | 
            -
                    end
         | 
| 469 | 
            -
             | 
| 470 | 
            -
                    opts.on_tail("-h", "--help") do
         | 
| 471 | 
            -
                      puts opts
         | 
| 472 | 
            -
                      exit
         | 
| 473 | 
            -
                    end
         | 
| 474 | 
            -
                  }
         | 
| 475 | 
            -
                end
         | 
| 476 | 
            -
             | 
| 477 | 
            -
                def search
         | 
| 478 | 
            -
                  prepare_stdout
         | 
| 479 | 
            -
                  puts list_header(search_term)
         | 
| 480 | 
            -
                  issues = api.search search_term, state
         | 
| 481 | 
            -
                  puts list_format(issues, verbosity)
         | 
| 482 | 
            -
                end
         | 
| 483 | 
            -
             | 
| 484 | 
            -
                def list
         | 
| 485 | 
            -
                  prepare_stdout
         | 
| 486 | 
            -
                  puts list_header
         | 
| 487 | 
            -
                  issues = api.list(state)
         | 
| 488 | 
            -
                  puts list_format(issues, verbosity)
         | 
| 489 | 
            -
                end
         | 
| 490 | 
            -
             | 
| 491 | 
            -
                def show
         | 
| 492 | 
            -
                  prepare_stdout
         | 
| 493 | 
            -
                  issue = api.show number
         | 
| 494 | 
            -
                  puts show_format(issue)
         | 
| 495 | 
            -
                end
         | 
| 496 | 
            -
             | 
| 497 | 
            -
                def open
         | 
| 498 | 
            -
                  if title.nil?
         | 
| 499 | 
            -
                    new_title, new_body = gets_from_editor GHI::Issue.new("title" => body)
         | 
| 500 | 
            -
                  elsif @commenting && body.nil?
         | 
| 501 | 
            -
                    new_title, new_body = gets_from_editor GHI::Issue.new("title" => title)
         | 
| 502 | 
            -
                  end
         | 
| 503 | 
            -
                  new_title ||= title
         | 
| 504 | 
            -
                  new_body  ||= body
         | 
| 505 | 
            -
                  issue = api.open new_title, new_body
         | 
| 506 | 
            -
                  delete_message
         | 
| 507 | 
            -
                  @number = issue.number
         | 
| 508 | 
            -
                  puts action_format(issue.title)
         | 
| 509 | 
            -
                end
         | 
| 510 | 
            -
             | 
| 511 | 
            -
                def edit
         | 
| 512 | 
            -
                  shown = api.show number
         | 
| 513 | 
            -
                  new_title, new_body = gets_from_editor(shown) if body.nil?
         | 
| 514 | 
            -
                  new_title ||= shown.title
         | 
| 515 | 
            -
                  new_body  ||= body
         | 
| 516 | 
            -
                  issue = api.edit number, new_title, new_body
         | 
| 517 | 
            -
                  delete_message
         | 
| 518 | 
            -
                  puts action_format(issue.title)
         | 
| 519 | 
            -
                end
         | 
| 520 | 
            -
             | 
| 521 | 
            -
                def close
         | 
| 522 | 
            -
                  raise GHI::API::InvalidRequest, "need a number" if number.nil?
         | 
| 523 | 
            -
                  issue = api.close number
         | 
| 524 | 
            -
                  if @commenting || new_body = body
         | 
| 525 | 
            -
                    new_body ||= gets_from_editor issue
         | 
| 526 | 
            -
                    comment = api.comment number, new_body
         | 
| 527 | 
            -
                  end
         | 
| 528 | 
            -
                  puts action_format(issue.title)
         | 
| 529 | 
            -
                  puts "(commented)" if comment
         | 
| 530 | 
            -
                end
         | 
| 531 | 
            -
             | 
| 532 | 
            -
                def reopen
         | 
| 533 | 
            -
                  issue = api.reopen number
         | 
| 534 | 
            -
                  if @commenting || new_body = body
         | 
| 535 | 
            -
                    new_body ||= gets_from_editor issue
         | 
| 536 | 
            -
                    comment = api.comment number, new_body
         | 
| 537 | 
            -
                  end
         | 
| 538 | 
            -
                  puts action_format(issue.title)
         | 
| 539 | 
            -
                  puts "(commented)" if comment
         | 
| 540 | 
            -
                end
         | 
| 541 | 
            -
             | 
| 542 | 
            -
                def prepare_label
         | 
| 543 | 
            -
                  @tag ||= (body || args * " ")
         | 
| 544 | 
            -
                  raise GHI::API::InvalidRequest, "need a label" if @tag.empty?
         | 
| 545 | 
            -
                  true
         | 
| 546 | 
            -
                end
         | 
| 547 | 
            -
             | 
| 548 | 
            -
                def label
         | 
| 549 | 
            -
                  labels = api.add_label tag, number
         | 
| 550 | 
            -
                  puts action_format
         | 
| 551 | 
            -
                  puts indent(labels.join(", "))
         | 
| 552 | 
            -
                end
         | 
| 553 | 
            -
             | 
| 554 | 
            -
                def unlabel
         | 
| 555 | 
            -
                  labels = api.remove_label tag, number
         | 
| 556 | 
            -
                  puts action_format
         | 
| 557 | 
            -
                  puts indent(labels.empty? ? "no labels" : labels.join(", "))
         | 
| 558 | 
            -
                end
         | 
| 559 | 
            -
             | 
| 560 | 
            -
                def prepare_comment
         | 
| 561 | 
            -
                  @body = args.flatten.first
         | 
| 562 | 
            -
                  @commenting = false unless body.nil?
         | 
| 563 | 
            -
                  true
         | 
| 564 | 
            -
                end
         | 
| 565 | 
            -
             | 
| 566 | 
            -
                def comment
         | 
| 567 | 
            -
                  @body ||= gets_from_editor api.show(number)
         | 
| 568 | 
            -
                  comment = api.comment(number, body)
         | 
| 569 | 
            -
                  delete_message
         | 
| 570 | 
            -
                  puts "(comment})"
         | 
| 571 | 
            -
                end
         | 
| 572 | 
            -
             | 
| 573 | 
            -
                def url
         | 
| 574 | 
            -
                  url = "https://github.com/#{user}/#{repo}/issues"
         | 
| 575 | 
            -
                  if number.nil?
         | 
| 576 | 
            -
                    url << "/#{state}" unless state == :open
         | 
| 577 | 
            -
                  else
         | 
| 578 | 
            -
                    url << "/#{number}"
         | 
| 579 | 
            -
                  end
         | 
| 580 | 
            -
                  defined?(Launchy) ? Launchy.open(url) : puts(url)
         | 
| 581 | 
            -
                end
         | 
| 582 | 
            -
             | 
| 583 | 
            -
                #-
         | 
| 584 | 
            -
                # Because these are mere fallbacks, any options used earlier will muddle
         | 
| 585 | 
            -
                # things: `ghi list` will work, `ghi list -c` will not.
         | 
| 586 | 
            -
                #
         | 
| 587 | 
            -
                # Argument parsing will have to better integrate with option parsing to
         | 
| 588 | 
            -
                # overcome this.
         | 
| 589 | 
            -
                #+
         | 
| 590 | 
            -
                def fallback_parsing(*arguments)
         | 
| 591 | 
            -
                  arguments = arguments.flatten
         | 
| 592 | 
            -
                  case command = arguments.shift
         | 
| 593 | 
            -
                  when nil, "list"
         | 
| 594 | 
            -
                    @action = :list
         | 
| 595 | 
            -
                    if arg = arguments.shift
         | 
| 596 | 
            -
                      @state ||= arg.to_sym if %w(open closed).include? arg
         | 
| 597 | 
            -
                      @user, @repo = arg.split "/" if arg.count("/") == 1
         | 
| 598 | 
            -
                    end
         | 
| 599 | 
            -
                  when "search"
         | 
| 600 | 
            -
                    @action = :search
         | 
| 601 | 
            -
                    @search_term ||= arguments.shift
         | 
| 602 | 
            -
                  when "show", /^-?(\d+)$/
         | 
| 603 | 
            -
                    @action = :show
         | 
| 604 | 
            -
                    @number ||= ($1 || arguments.shift[/\d+/]).to_i
         | 
| 605 | 
            -
                  when "open"
         | 
| 606 | 
            -
                    if arguments.first =~ /^\d+$/
         | 
| 607 | 
            -
                      @action = :reopen
         | 
| 608 | 
            -
                      @number ||= arguments.shift[/\d+/].to_i
         | 
| 609 | 
            -
                    else
         | 
| 610 | 
            -
                      @action = :open
         | 
| 611 | 
            -
                      @title = arguments.join(' ')
         | 
| 612 | 
            -
                    end
         | 
| 613 | 
            -
                  when "edit"
         | 
| 614 | 
            -
                    @action = :edit
         | 
| 615 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 616 | 
            -
                  when "close"
         | 
| 617 | 
            -
                    @action = :close
         | 
| 618 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 619 | 
            -
                  when "reopen"
         | 
| 620 | 
            -
                    @action = :reopen
         | 
| 621 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 622 | 
            -
                  when "label"
         | 
| 623 | 
            -
                    @action = :label
         | 
| 624 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 625 | 
            -
                    @label ||= arguments.shift
         | 
| 626 | 
            -
                  when "unlabel"
         | 
| 627 | 
            -
                    @action = :unlabel
         | 
| 628 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 629 | 
            -
                    @label ||= arguments.shift
         | 
| 630 | 
            -
                  when "comment"
         | 
| 631 | 
            -
                    @action = :comment
         | 
| 632 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 633 | 
            -
                  when "claim"
         | 
| 634 | 
            -
                    @action = :claim
         | 
| 635 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 636 | 
            -
                  when %r{^([^/]+)/([^/]+)$}
         | 
| 637 | 
            -
                    @action = :list
         | 
| 638 | 
            -
                    @user, @repo = $1, $2
         | 
| 639 | 
            -
                  when "url", "web"
         | 
| 640 | 
            -
                    @action = :url
         | 
| 641 | 
            -
                    @number ||= arguments.shift[/\d+/].to_i
         | 
| 642 | 
            -
                  end
         | 
| 643 | 
            -
             | 
| 644 | 
            -
                  @use_ssl ||= `git config github.ssl`.chomp == 'true'
         | 
| 645 | 
            -
             | 
| 646 | 
            -
                  if @action
         | 
| 647 | 
            -
                    @args = @argv.dup
         | 
| 648 | 
            -
                    args.delete_if { |arg| arg == command }
         | 
| 649 | 
            -
                    option_parser.parse!(*args)
         | 
| 650 | 
            -
                    return true
         | 
| 651 | 
            -
                  end
         | 
| 652 | 
            -
                  unless command.start_with? "-"
         | 
| 653 | 
            -
                    warn "#{File.basename $0}: what do you mean, '#{command}'?"
         | 
| 654 | 
            -
                  end
         | 
| 655 | 
            -
                end
         | 
| 656 | 
            -
              end
         | 
| 657 | 
            -
            end
         |