watson-ruby 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b74f0d0a773b92e7c91c32aed52f93442ce369de
4
+ data.tar.gz: d00a06313e484236bdd166ea6fbf451fb63d3a91
5
+ SHA512:
6
+ metadata.gz: 0742222698737d023299258a6f8d44e5ac348ab2fe715f797bca1b5eb897a6312fc8c78e6a7a38cecc8a8ec7b1a4853cf2ca6d87d731b9be12c2e6874dcb4078
7
+ data.tar.gz: 9734ecb6497b219aa5d648096fefc370cf5f0641fd31b6f5a65140049e2845d717ec8b27ecde9f4a1be7d4f356ad782376881c6704a0d64a652be2b7fa9aa17a
data/.gitignore ADDED
@@ -0,0 +1,6 @@
1
+ doc/
2
+ dev/
3
+ pkg/
4
+ NOTES
5
+ *.swp
6
+ .watsonrc
data/Gemfile ADDED
@@ -0,0 +1,2 @@
1
+ source "http://rubygems.org"
2
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ watson (1.0.0)
5
+ json
6
+
7
+ GEM
8
+ remote: http://rubygems.org/
9
+ specs:
10
+ diff-lcs (1.2.5)
11
+ json (1.8.1)
12
+ rake (10.1.0)
13
+ rspec (2.14.1)
14
+ rspec-core (~> 2.14.0)
15
+ rspec-expectations (~> 2.14.0)
16
+ rspec-mocks (~> 2.14.0)
17
+ rspec-core (2.14.7)
18
+ rspec-expectations (2.14.4)
19
+ diff-lcs (>= 1.1.3, < 2.0)
20
+ rspec-mocks (2.14.4)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ rake
27
+ rspec
28
+ watson!
data/LICENSE ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2012-2013 goosecode labs
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in
11
+ all copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # watson-ruby
2
+ ### an inline issue manager
3
+ [watson](http://goosecode.com/watson) ([mirror](http://nhmood.github.io/watson-ruby)) is a tool for creating and tracking bug reports, issues, and internal notes in code.
4
+ It is avaliable in two flavors, [watson-ruby](http://github.com/nhmood/watson-ruby) and [watson-perl](http://github.com/watson-perl)
5
+
6
+ ### See watson in action [here](http://goosecode.com/watson) ([mirror](http://nhmood.github.io/watson-ruby))
7
+ ### See the RDoc documentation [here](http://goosecode.com/watson/ruby-documentation) ([mirror](http://nhmood.github.io/watson-ruby/documentation))
8
+
9
+ ## Installation
10
+ watson-ruby has been tested with **Ruby v2.0.0p247** and **RubyGems v2.0.3** (on **Arch Linux**)
11
+ watson-ruby requires the ```json``` gem
12
+
13
+ ### From Repo
14
+ watson-ruby is avaliable as a RubyGem.
15
+ You can either download it directory from ```gem``` using
16
+ ```
17
+ gem install watson
18
+ ```
19
+
20
+ Or you can clone this repo and install with Rake
21
+ ```
22
+ clone https://github.com/nhmood/watson-ruby.git .
23
+ cd watson-ruby
24
+ rake
25
+ ```
26
+
27
+ ## Usage
28
+ For a quick idea of how to use watson, check out the [app demo](http://goosecode.com/watson)! ([mirror](http://nhmood.github.io/watson-ruby))
29
+ See below for a description of what all the command line arguments do.
30
+
31
+ ## Command line arguments
32
+ ```
33
+ Usage: watson [OPTION]...
34
+ Running watson with no arguments will parse with settings in RC file
35
+ If no RC file exists, default RC file will be created
36
+
37
+ -c, --context-lines number of lines of context to provide with posted issue
38
+ -d, --dirs list of directories to search in
39
+ -f, --files list of files to search in
40
+ -h, --help print help
41
+ -i, --ignore list of files, directories, or types to ignore
42
+ -p, --parse-depth depth to recursively parse directories
43
+ -r, --remote list / create tokens for Bitbucket/Github
44
+ -t, --tags list of tags to search for
45
+ -u, --update update remote repos with current issues
46
+ -v, --version print watson version and info
47
+
48
+ Any number of files, tags, dirs, and ignores can be listed after flag
49
+ Ignored files should be space separated
50
+ To use *.filetype identifier, encapsulate in "" to avoid shell substitutions
51
+
52
+ Report bugs to: watson@goosecode.com
53
+ watson home page: <http://goosecode.com/projects/watson>
54
+ [goosecode] labs | 2012-2013
55
+
56
+ ```
57
+ ### All file/directory/tag related parameters support relative as well as absolute paths.
58
+
59
+ ### -c, --context-lines [LINES]
60
+ This parameter specifies how many lines of context watson should include when posting issues to remote repos.
61
+ When this parameter is set from the command line, the .watsonrc config file is written with the value; the command line option effectively sets the default value for this feature in the current directory.
62
+ The default value is set to 15 (and can be found in the lib/watson/command.rb file).
63
+
64
+ ### -d, --dirs [DIRS]
65
+ This parameter specifies which directories watson should parse through.
66
+ It should be followed by a space separated list of directories that should be parsed.
67
+ If watson is run without this parameter, the current directory is parsed.
68
+
69
+
70
+ ### -f, --files [FILES]
71
+ This parameter specifies which files watson should parse through.
72
+ It should be followed by a space separated list of files that should be parsed.
73
+
74
+
75
+ ### -h, --help
76
+ This parameter displays the list of avaliable options for watson.
77
+
78
+
79
+ ### -i, --ignore [IGNORES]
80
+ This parameter specifies which files and directories watson should ignore when parsing.
81
+ It should be followed by a space separated list of files and/or directories to be ignored.
82
+ This parameter should be used as an opposite to -d/-f, when there are more files that should be parsed in a directory than should be ignored.
83
+
84
+
85
+ ### -p, --parse-depth [PARSE_DEPTH]
86
+ This parameter specifies how deep watson should recursively parse directories.
87
+ The 'depth' is defined as how many levels deep from the top-most specified directory to parse.
88
+ If individual directories are passed with the -d (--dirs) flag, each will be parsed PARSE_DEPTH layers, regardless of their depth from the current directory.
89
+ If watson is run without this parameter, the parsing depth is unlimited and will search through all subdirectories found.
90
+
91
+
92
+ ### -r, --remote [GITHUB, BITBUCKET]
93
+ This parameter is used to both list currently established remotes as well as setup new ones.
94
+ If passed without any options, the currently established remotes will be listed.
95
+ If passed with a github or bitbucket argument, watson will proceed to ask some questions to set up the corresponding remote.
96
+
97
+
98
+ ### -t, --tags [TAGS]
99
+ This parameter is used to specify which tags watson should look for when parsing.
100
+ The tag currently supports any regular character and number combination, no special (!@#$...) characters.
101
+
102
+
103
+ ### -u, --update
104
+ This parameter is used to update remote repos with new issues.
105
+ watson **does not** post new issues by default therefore this parameter is required to push up to GitHub/Bitbucket.
106
+ watson **does** pull issue status by default, therefore you will always be notified of resolved issues on GitHub/Bitbucket.
107
+
108
+ ### -v, --version
109
+ This parameter displays the current version of watson you are running.
110
+
111
+
112
+ ## .watsonrc
113
+ watson supports an RC file that allows for reusing commong settings without repeating command line arguments every time.
114
+
115
+ The .watsonrc is placed in every directory that watson is run from as opposed to a unified file (in ~/.watsonrc for example). The thinking behind this is that each project may have a different set of folders to ignore, directories to search through, and tags to look for.
116
+ For example, a C/C++ project might want to look in src/ and ignore obj/ whereas a Ruby project might want to look in lib/ and ignore assets/.
117
+
118
+ The .watsonrc file is fairly straightforward...
119
+ **[dirs]** - This is a newline separated list of directories to ignore.
120
+
121
+ **[tags]** - This is a newline separated list of tags to look for while parsing.
122
+
123
+ **[ignore]** - This is a newline separated list of files / folders to ignore while parsing.
124
+ This supports wildcard type selecting by providing .filename (no * required)
125
+
126
+ **[context_depth]** - This value determines how many lines of context should be grabbed for each issue when posting to a remote.
127
+
128
+ **[(github/bitbucket)]** - If a remote is established, the API key for the corresponding remote is stored here.
129
+ Currently, OAuth has yet to be implemented for Bitbucket so the Bitbucket username is stored here.
130
+
131
+ **[(github/bitbucket)_repo]** - The repo name / path is stored here.
132
+
133
+ The remote related .watsonrc options shouldn't need to be edited manually, as they are automatically populated when the -r, --remote setup is called.
134
+
135
+ ## Special Thanks
136
+ Special thanks to [@samirahmed](http://github.com/samirahmed) for his super Ruby help and encouraging the Ruby port!
137
+ Special thanks to [@eugenekolo](http://twitter.com/eugenekolo) [[email](eugenek@bu.edu)] for his super Perl help!
138
+ Special thanks to [@crowell](http://twitter.com/crowell) for testing out watson-ruby!
139
+
140
+ ## FAQ
141
+ - **Why Ruby?**
142
+ I wanted to learn Ruby and this seemed like a pretty decent project.
143
+
144
+ - **Why is the Ruby version different from the Perl version?**
145
+ The Ruby version was developed after the Perl version was made. Because of this, it was a lot easier to add on features that were thought of while/after making the Perl version as the plumbing was still being setup.
146
+ With a combination of wanting to finish watson-ruby as well as laziness, some of the improvements that were added to watson-ruby *have yet* to be pulled back into watson-perl.
147
+ If you are interested in helping out or maintaining watson-perl let me know!
data/Rakefile ADDED
@@ -0,0 +1,21 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rdoc/task'
4
+
5
+ task :default => :run_all
6
+ task :test => :spec
7
+
8
+ task :run_all => [:spec, :rdoc, :install] do
9
+
10
+ end
11
+
12
+ desc 'Run RSpec tests'
13
+ RSpec::Core::RakeTask.new(:spec)
14
+
15
+ desc 'Generate RDoc documentation'
16
+ RDoc::Task.new(:rdoc) do | rdoc |
17
+ rdoc.rdoc_dir = 'doc'
18
+ rdoc.rdoc_files.include 'lib'
19
+ end
20
+
21
+
@@ -0,0 +1,21 @@
1
+ # watson rc
2
+ # watson - inline issue manager
3
+ # [goosecode] labs
4
+
5
+
6
+ # Directories
7
+ [dirs]
8
+ ./
9
+
10
+
11
+ # Tags
12
+ [tags]
13
+ fix
14
+ review
15
+ todo
16
+
17
+
18
+ # Ignores
19
+ [ignore]
20
+ .git
21
+ *.swp
data/assets/watson.svg ADDED
@@ -0,0 +1,25 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
+ <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4
+ <svg version="1.1" id="Layer_2" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
5
+ width="512px" height="512px" viewBox="0 0 512 512" enable-background="new 0 0 512 512" xml:space="preserve">
6
+ <rect fill="#F8DB94" width="512" height="512"/>
7
+ <g id="Layer_1">
8
+ <g>
9
+
10
+ <rect x="170.641" y="291.813" transform="matrix(0.8585 0.5128 -0.5128 0.8585 217.9851 -42.775)" fill="#6D6E71" width="31.729" height="163.625"/>
11
+ </g>
12
+
13
+ <rect x="107.541" y="332.827" transform="matrix(0.8585 0.5128 -0.5128 0.8585 238.3663 -15.0629)" display="none" fill="#BB9753" width="77.874" height="183.164"/>
14
+ <circle fill="#F5F6F7" cx="292.525" cy="186.898" r="139.89"/>
15
+ <circle fill="#00AEEF" cx="292.523" cy="186.898" r="123.796"/>
16
+ <circle fill="#FFFFFF" cx="317.697" cy="148.521" r="65.613"/>
17
+ <circle fill="#00AEEF" cx="306.143" cy="160.076" r="74.278"/>
18
+
19
+ <rect x="145.48" y="342.301" transform="matrix(0.8585 0.5128 -0.5128 0.8585 229.5986 -30.2952)" fill="#8B5E3C" stroke="#FFFFFF" stroke-width="4" stroke-linecap="round" stroke-linejoin="round" stroke-miterlimit="10" width="48.435" height="117.213"/>
20
+ <rect x="123.344" y="438.277" transform="matrix(0.8586 0.5127 -0.5127 0.8586 246.86 -12.2127)" width="44.441" height="6.057"/>
21
+
22
+ <rect x="131.203" y="425.132" transform="matrix(0.8586 0.5127 -0.5127 0.8586 241.2317 -18.1018)" width="44.441" height="6.057"/>
23
+ </g>
24
+ <rect x="138.849" y="412.382" transform="matrix(0.8586 0.5127 -0.5127 0.8586 235.7759 -23.8257)" width="44.441" height="6.057"/>
25
+ </svg>
data/bin/watson ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # coding: utf-8
3
+
4
+ # [review] - Using own funky path loading because traditional way seems wrong?
5
+ # Commented out version is traditional, seen in many apps. If you use that and
6
+ # look at load_path you get path/../lib (I'd expect those to be separate?)
7
+ # My funky version adds path/., path/bin, path/assets separately
8
+ # Maybe I don't get how the load path is supposed to look though...
9
+
10
+ #$:.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
11
+ $:.unshift *%w[. assets lib].map { |m| __dir__.gsub(/\/bin(.?)+/, '') + '/' + m }
12
+ #p($:)
13
+
14
+
15
+ require 'watson'
16
+
17
+
18
+ Watson::Command.execute(*ARGV)
data/lib/watson.rb ADDED
@@ -0,0 +1,69 @@
1
+ require_relative 'watson/command'
2
+ require_relative 'watson/config'
3
+ require_relative 'watson/fs'
4
+ require_relative 'watson/parser'
5
+ require_relative 'watson/printer'
6
+ require_relative 'watson/remote'
7
+ require_relative 'watson/github'
8
+ require_relative 'watson/bitbucket'
9
+
10
+ module Watson
11
+ # [todo] - Replace all regex parentheses() with brackets[] if not matching
12
+ # Was using () to group things together for syntax instead of []
13
+ # Replace so we can get cleaner matches and don't need to keep track of matches
14
+
15
+ # [todo] - Change debug_print to provide its own \n
16
+
17
+ # [todo] - Add ability to pass "IDENTIFY" to debug_print to auto print method entry info
18
+
19
+ # [todo] - Make sure all methods have proper return at end
20
+
21
+ # [review] - Method input arg always renamed from arg to _arg inside method, change this?
22
+ # Not sure if I should just make input arg _arg or if explicit _ is useful
23
+
24
+ # [todo] - Add option to save output to specified file
25
+ # [todo] - Replace Identify line in each method with method_added call
26
+ # http://ruby-doc.org/core-2.0.0/Module.html#method-i-method_added
27
+
28
+ # Separate ON and OFF so we can force state and still let
29
+ # individual classes have some control over their prints
30
+
31
+ # Global flag to turn ON debugging across all files
32
+ GLOBAL_DEBUG_ON = false
33
+ # Gllobal flag to turn OFF debugging across all files
34
+ GLOBAL_DEBUG_OFF = false
35
+
36
+ # [review] - Not sure if module_function is proper way to scope
37
+ # I want to be able to call debug_print without having to use the scope
38
+ # operator (Watson::Printer.debug_print) so it is defined here as a
39
+ # module_function instead of having it in the Printer class
40
+ # Gets included into every class individually
41
+ module_function
42
+
43
+ ###########################################################
44
+ # Global debug print that prints based on local file DEBUG flag as well as GLOBAL debug flag
45
+ def debug_print(msg)
46
+ # [todo] - If input msg is a Hash, use pp to dump it
47
+
48
+ # Print only if DEBUG flag of calling class is true OR
49
+ # GLOBAL_DEBUG_ON of Watson module (defined above) is true
50
+ # AND GLOBAL_DEBUG_OFF of Watson module (Defined above) is false
51
+
52
+ # Sometimes we call debug_print from a static method (class << self)
53
+ # and other times from a class method, and ::DEBUG is accessed differently
54
+ # from a class vs object, so lets take care of that
55
+ _DEBUG = (self.is_a? Class) ? self::DEBUG : self.class::DEBUG
56
+
57
+ print "=> #{msg}" if ( (_DEBUG == true || GLOBAL_DEBUG_ON == true) && (GLOBAL_DEBUG_OFF == false))
58
+ end
59
+
60
+
61
+ ###########################################################
62
+ # Perform system check to see if we are able to use unix less for printing
63
+ def check_less
64
+ # Check if system has less (so we can print out to it to allow scrolling)
65
+ # [todo] - Implement this scrolling thing inside watson with ncurses
66
+ return system("which less > /dev/null 2>&1")
67
+ end
68
+
69
+ end
@@ -0,0 +1,373 @@
1
+ module Watson
2
+ class Remote
3
+ # Bitbucket remote access class
4
+ # Contains all necessary methods to obtain access to, get issue list,
5
+ # and post issues to Bitbucket
6
+ class Bitbucket
7
+
8
+ # Debug printing for this class
9
+ DEBUG = false
10
+
11
+ class << self
12
+
13
+ # [todo] - Allow closing of issues from watson? Don't like that idea but maybe
14
+ # [todo] - Wrap Bitbucket password grabbing into separate method
15
+
16
+ # Include for debug_print
17
+ include Watson
18
+
19
+ #############################################################################
20
+ # Setup remote access to Bitbucket
21
+ # Get Username, Repo, and PW and perform necessary HTTP calls to check validity
22
+ def setup(config)
23
+
24
+ # Identify method entry
25
+ debug_print "#{ self.class } : #{ __method__ }\n"
26
+
27
+ Printer.print_status "+", GREEN
28
+ print BOLD + "Attempting to access Bitbucket...\n" + RESET
29
+
30
+ # Check config to make sure no previous repo info exists
31
+ unless config.bitbucket_api.empty? && config.bitbucket_repo.empty?
32
+ Printer.print_status "!", RED
33
+ print BOLD + "Previous Bitbucket API + Repo is in RC, are you sure you want to overwrite?\n" + RESET
34
+ print " (Y)es/(N)o: "
35
+
36
+ # Get user input
37
+ _overwrite = $stdin.gets.chomp
38
+ if ["no", "n"].include?(_overwrite.downcase)
39
+ print "\n"
40
+ Printer.print_status "x", RED
41
+ print BOLD + "Not overwriting current Bitbucket API + repo info\n" + RESET
42
+ return false
43
+ end
44
+ end
45
+
46
+
47
+ Printer.print_status "!", YELLOW
48
+ print BOLD + "Access to your Bitbucket account required to make/update issues\n" + RESET
49
+ print " See help or README for more details on GitHub/Bitbucket access\n\n"
50
+
51
+
52
+ # [todo] - Bitbucket OAuth not implemented yet so warn user about HTTP Auth
53
+ # Bitbucket doesn't have nonOAuth flow that GitHub does :(
54
+ # Even if I use OAuth lib, still need to validate from webview which is lame
55
+ Printer.print_status "!", RED
56
+ print BOLD + "Bitbucket OAuth not implemented yet.\n" + RESET;
57
+ print " Basic HTTP Auth in use, will request PW entry every time.\n\n"
58
+
59
+
60
+ # [todo] - Don't just check for blank password but invalid as well
61
+ # Poor mans username/password grabbing
62
+ print BOLD + "Username: " + RESET
63
+ _username = $stdin.gets.chomp
64
+ if _username.empty?
65
+ Printer.print_status "x", RED
66
+ print BOLD + "Input blank. Please enter your username!\n\n" + RESET
67
+ return false
68
+ end
69
+
70
+ print "\n"
71
+
72
+ # Get repo information, if blank give error
73
+ Printer.print_status "!", YELLOW
74
+ print BOLD + "Repo information required\n" + RESET
75
+ print " Please provide owner that repo is under followed by repo name\n"
76
+ print " e.g. owner: nhmood, repo: watson (case sensitive)\n"
77
+ print " See help or README for more details on GitHub access\n\n"
78
+
79
+ print BOLD + "Owner: " + RESET
80
+ _owner = $stdin.gets.chomp
81
+ if _owner.empty?
82
+ print "\n"
83
+ Printer.print_status "x", RED
84
+ print BOLD + "Input blank. Please enter the owner the repo is under!\n\n" + RESET
85
+ return false
86
+ end
87
+
88
+ print BOLD + "Repo: " + RESET
89
+ _repo = $stdin.gets.chomp
90
+ if _repo.empty?
91
+ print "\n"
92
+ Printer.print_status "x", RED
93
+ print BOLD + "Input blank. Please enter the repo name!\n\n" + RESET
94
+ return false
95
+ end
96
+
97
+ print "\n"
98
+
99
+ # [fix] - Crossplatform password block needed, not sure if current method is safe either
100
+ # Block output to tty to prevent PW showing, Linux/Unix only :(
101
+ print BOLD + "Password: " + RESET
102
+ system "stty -echo"
103
+ _password = $stdin.gets.chomp
104
+ system "stty echo"
105
+ print "\n"
106
+ if _password.empty?
107
+ Printer.print_status "x", RED
108
+ print BOLD + "Input is blank. Please enter your password!\n\n" + RESET
109
+ return false
110
+ end
111
+
112
+ # HTTP Request to check if Repo exists and user has access
113
+ # http://confluence.atlassian.com/display/BITBUCKET/Use+the+Bitbucket+REST+APIs
114
+
115
+ # Create options hash to pass to Remote::http_call
116
+ # Endpoint for accessing Repo as User with SSL
117
+ # Basic auth with user input
118
+ opts = {:url => "https://bitbucket.org/api/1.0/repositories/#{_owner}/#{_repo}",
119
+ :ssl => true,
120
+ :method => "GET",
121
+ :basic_auth => [_username, _password],
122
+ :verbose => false
123
+ }
124
+
125
+ _json, _resp = Watson::Remote.http_call(opts)
126
+
127
+ # Check response to validate authorization
128
+ if _resp.code == "200"
129
+ print "\n"
130
+ Printer.print_status "o", GREEN
131
+ print BOLD + "Successfully accessed remote repo with given credentials\n" + RESET
132
+ else
133
+ print "\n"
134
+ Printer.print_status "x", RED
135
+ print BOLD + "Unable to access /#{ _owner }/#{ _repo } with given credentials\n" + RESET
136
+ print " Check that credentials are correct and repository exists under user\n"
137
+ print " Status: #{ _resp.code } - #{ _resp.message }\n\n"
138
+ return false
139
+ end
140
+
141
+
142
+ # No OAuth for Bitbucket yet so just store username in api for config
143
+ # This will let us just prompt for PW
144
+ config.bitbucket_api = _owner
145
+ config.bitbucket_pw = _password # Never gets written to file
146
+ config.bitbucket_repo = _repo
147
+ debug_print " \n"
148
+
149
+ # All setup has been completed, need to update RC
150
+ # Call config updater/writer from @config to write config
151
+ debug_print "Updating config with new Bitbucket info\n"
152
+ config.update_conf("bitbucket_api", "bitbucket_repo")
153
+
154
+ print "\n"
155
+ Printer.print_status "o", GREEN
156
+ print BOLD + "Bitbucket successfully setup\n" + RESET
157
+ print " Issues will now automatically be retrieved from Bitbucket by default\n"
158
+ print " Use -p, --push to post issues to GitHub\n"
159
+ print " See help or README for more details on GitHub/Bitbucket access\n\n"
160
+
161
+ return true
162
+
163
+ end
164
+
165
+
166
+ ###########################################################
167
+ # Get all remote Bitbucket issues and store into Config container class
168
+ def get_issues(config)
169
+
170
+ # Identify method entry
171
+ debug_print "#{ self.class } : #{ __method__ }\n"
172
+
173
+ # Only attempt to get issues if API is specified
174
+ if config.bitbucket_api.empty?
175
+ debug_print "No API found, this shouldn't be called...\n"
176
+ return false
177
+ end
178
+
179
+
180
+ # If we haven't obtained the pw from user yet, do it
181
+ if config.bitbucket_pw.empty?
182
+ # No OAuth for Bitbucket yet, gotta get user password in order to make calls :(
183
+ Printer.print_status "!", YELLOW
184
+ print BOLD + "Bitbucket password required for remote checking/posting.\n" + RESET
185
+ print " Password: "
186
+
187
+ # Block output to tty to prevent PW showing, Linux/Unix only :(
188
+ system "stty -echo"
189
+ _password = $stdin.gets.chomp
190
+ system "stty echo"
191
+ if _password.empty?
192
+ print "Input is blank. Please enter your password!\n"
193
+ return false
194
+ else
195
+ print "\n"
196
+ end
197
+
198
+ config.bitbucket_pw = _password
199
+ end
200
+
201
+
202
+ # Get all open tickets (anything but resolved)
203
+ # Create options hash to pass to Remote::http_call
204
+ # Issues URL for Bitbucket + SSL
205
+ opts = {:url => "https://bitbucket.org/api/1.0/repositories/#{ config.bitbucket_api }/#{ config.bitbucket_repo }/issues?status=!resolved",
206
+ :ssl => true,
207
+ :method => "GET",
208
+ :basic_auth => [config.bitbucket_api, config.bitbucket_pw],
209
+ :verbose => false
210
+ }
211
+
212
+ _json, _resp = Watson::Remote.http_call(opts)
213
+
214
+
215
+ # Check response to validate repo access
216
+ if _resp.code != "200"
217
+ Printer.print_status "x", RED
218
+ print BOLD + "Unable to access remote #{ config.bitbucket_repo }, Bitbucket API may be invalid\n" + RESET
219
+ print " Make sure you have created an issue tracker for your repository on the Bitbucket website\n"
220
+ print " Consider running --remote (-r) option to regenerate/validate settings\n"
221
+ print " Status: #{ _resp.code } - #{ _resp.message }\n\n"
222
+
223
+ debug_print "Bitbucket invalid, setting config var\n"
224
+ config.bitbucket_valid = false
225
+ return false
226
+ end
227
+
228
+
229
+
230
+ config.bitbucket_issues[:open] = _json["issues"].empty? ? Hash.new : _json["issues"]
231
+ config.bitbucket_valid = true
232
+
233
+ # Get all closed tickets
234
+ # Create options hash to pass to Remote::http_call
235
+ # Issues URL for Bitbucket + SSL
236
+ opts = {:url => "https://bitbucket.org/api/1.0/repositories/#{ config.bitbucket_api }/#{ config.bitbucket_repo }/issues?status=resolved",
237
+ :ssl => true,
238
+ :method => "GET",
239
+ :basic_auth => [config.bitbucket_api, config.bitbucket_pw],
240
+ :verbose => false
241
+ }
242
+
243
+ _json, _resp = Watson::Remote.http_call(opts)
244
+
245
+ # Check response to validate repo access
246
+ # Shouldn't be necessary if we passed the last check but just to be safe
247
+ if _resp.code != "200"
248
+ Printer.print_status "x", RED
249
+ print BOLD + "Unable to get closed issues.\n" + RESET
250
+ print " Since the open issues were obtained, something is probably wrong and you should file a bug report or something...\n"
251
+ print " Status: #{ _resp.code } - #{ _resp.message }\n"
252
+
253
+ debug_print "Bitbucket invalid, setting config var\n"
254
+ config.bitbucket_valid = false
255
+ return false
256
+ end
257
+
258
+ config.bitbucket_issues[:closed] = _json["issues"].empty? ? Hash.new : _json["issues"]
259
+ config.bitbucket_valid = true
260
+ return true
261
+ end
262
+
263
+
264
+ ###########################################################
265
+ # Post given issue to remote Bitbucket repo
266
+ def post_issue(issue, config)
267
+ # [todo] - Better way to identify/compare remote->local issues than md5
268
+ # Current md5 based on some things that easily can change, need better ident
269
+
270
+ # Identify method entry
271
+ debug_print "#{self.class} : #{__method__}\n"
272
+
273
+
274
+ # Only attempt to get issues if API is specified
275
+ if config.bitbucket_api.empty?
276
+ debug_print "No API found, this shouldn't be called...\n"
277
+ return false
278
+ end
279
+
280
+ # Check that issue hasn't been posted already by comparing md5s
281
+ # Go through all open issues, if there is a match in md5, return out of method
282
+ # [todo] - Play with idea of making body of GitHub issue hash format to be exec'd
283
+ # Store pieces in text as :md5 => "whatever" so when we get issues we can
284
+ # call exec and turn it into a real hash for parsing in watson
285
+ # Makes watson code cleaner but not as readable comment on GitHub...?
286
+ debug_print "Checking open issues to see if already posted\n"
287
+ config.bitbucket_issues[:open].each do | _open |
288
+ if _open["content"].include?(issue[:md5])
289
+ debug_print "Found in #{ _open["title"] }, not posting\n"
290
+ return false
291
+ end
292
+ debug_print "Did not find in #{_open["title"]}\n"
293
+ end
294
+
295
+ debug_print "Checking closed issues to see if already posted\n"
296
+ config.bitbucket_issues[:closed].each do | _closed |
297
+ if _closed["content"].include?(issue[:md5])
298
+ debug_print "Found in #{ _closed["title"] }, not posting\n"
299
+ return false
300
+ end
301
+ debug_print "Did not find in #{ _closed["title"] }\n"
302
+ end
303
+
304
+
305
+ # If we haven't obtained the pw from user yet, do it
306
+ if config.bitbucket_pw.empty?
307
+ # No OAuth for Bitbucket yet, gotta get user password in order to make calls :(
308
+ Printer.print_status "!", YELLOW
309
+ print BOLD + "Bitbucket password required for remote checking/posting.\n" + RESET
310
+ print " Password: "
311
+
312
+ # Block output to tty to prevent PW showing, Linux/Unix only :(
313
+ print "Password: "
314
+ system "stty -echo"
315
+ _password = $stdin.gets.chomp
316
+ system "stty echo"
317
+ if _password.empty?
318
+ print "Input is blank. Please enter your password!\n"
319
+ return false
320
+ else
321
+ print "\n"
322
+ end
323
+
324
+ config.bitbucket_pw = _password
325
+ end
326
+
327
+
328
+
329
+
330
+ # We didn't find the md5 for this issue in the open or closed issues, so safe to post
331
+
332
+ # Create the body text for the issue here, too long to fit nicely into opts hash
333
+ # [review] - Only give relative path for privacy when posted
334
+ _body = "__filename__ : #{ issue[:path] } \n" +
335
+ "__line #__ : #{ issue[:line_number] } \n" +
336
+ "__tag__ : #{ issue[:tag] } \n" +
337
+ "__md5__ : #{ issue[:md5] } \n\n" +
338
+ "#{ issue[:context].join }"
339
+
340
+ # Create option hash to pass to Remote::http_call
341
+ # Issues URL for GitHub + SSL
342
+ # No tag or label concept in Bitbucket unfortunately :(
343
+ opts = {:url => "https://bitbucket.org/api/1.0/repositories/#{ config.bitbucket_api }/#{ config.bitbucket_repo }/issues",
344
+ :ssl => true,
345
+ :method => "POST",
346
+ :basic_auth => [config.bitbucket_api, config.bitbucket_pw],
347
+ :data => [{"title" => issue[:title] + " [#{ issue[:path] }]",
348
+ "content" => _body }],
349
+ :verbose => false
350
+ }
351
+
352
+ _json, _resp = Watson::Remote.http_call(opts)
353
+
354
+
355
+ # Check response to validate repo access
356
+ # Shouldn't be necessary if we passed the last check but just to be safe
357
+ if _resp.code != "200"
358
+ Printer.print_status "x", RED
359
+ print BOLD + "Post unsuccessful. \n" + RESET
360
+ print " Since the open issues were obtained earlier, something is probably wrong and you should let someone know...\n"
361
+ print " Status: #{ _resp.code } - #{ _resp.message }\n"
362
+ return false
363
+ end
364
+
365
+ return true
366
+ end
367
+
368
+ end
369
+
370
+
371
+ end
372
+ end
373
+ end