bicho 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,4 +1,4 @@
1
- source "http://rubygems.org"
1
+ source 'http://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in bicho.gemspec
4
4
  gemspec
@@ -29,6 +29,8 @@ Plugins can be written to deal with specific bugzilla installations.
29
29
  server.get_bugs(127043).each do |bug|
30
30
  puts bug.summary
31
31
  puts bug.url
32
+
33
+ puts bug.history
32
34
  end
33
35
 
34
36
  You can give more than one bug or a named query, or both:
@@ -46,13 +48,13 @@ to set the Bicho common client:
46
48
 
47
49
  Bicho.client = Bicho::Client.new('https://bugzilla.gnome.org')
48
50
 
49
- Bicho::Bug.where(:product => "vala", :status => "resolved").each do |bug|
51
+ Bicho::Bug.where(product: 'vala', status: 'resolved').each do |bug|
50
52
  # .. do something with bug
51
53
  end
52
54
 
53
55
  Or alternatively:
54
56
 
55
- Bicho::Bug.where.product("vala").status("resolved").each do |bug|
57
+ Bicho::Bug.where.product('vala').status('resolved').each do |bug|
56
58
  # .. do something with bug
57
59
  end
58
60
 
@@ -60,6 +62,8 @@ to set the Bicho common client:
60
62
 
61
63
  bicho -b http://bugzilla.gnome.org show 127043
62
64
 
65
+ bicho -b http://bugzilla.gnome.org history 127043
66
+
63
67
  bicho -b https://bugzilla.gnome.org search --summary "crash"
64
68
 
65
69
  bicho -b https://bugzilla.gnome.org search --help
data/Rakefile CHANGED
@@ -1,11 +1,11 @@
1
- $:.push(File.join(File.dirname(__FILE__), 'lib'))
1
+ $LOAD_PATH.push(File.join(File.dirname(__FILE__), 'lib'))
2
2
  require 'bundler/gem_tasks'
3
3
  require 'bicho/version'
4
4
  require 'rake/testtask'
5
5
 
6
6
  extra_docs = ['README*', 'TODO*', 'CHANGELOG*']
7
7
 
8
- task :default => [:test]
8
+ task default: [:test]
9
9
 
10
10
  Rake::TestTask.new do |t|
11
11
  t.libs << File.expand_path('../test', __FILE__)
@@ -15,17 +15,17 @@ Rake::TestTask.new do |t|
15
15
  end
16
16
 
17
17
  begin
18
- require 'yard'
18
+ require 'yard'
19
19
  YARD::Rake::YardocTask.new(:doc) do |t|
20
20
  t.files = ['lib/**/*.rb', *extra_docs]
21
21
  t.options = ['--no-private']
22
22
  end
23
- rescue LoadError
24
- STDERR.puts "Install yard if you want prettier docs"
25
- require 'rdoc/task'
26
- Rake::RDocTask.new(:doc) do |rdoc|
27
- rdoc.rdoc_dir = "doc"
28
- rdoc.title = "bicho #{Bicho::VERSION}"
29
- extra_docs.each { |ex| rdoc.rdoc_files.include ex }
30
- end
23
+ rescue LoadError
24
+ STDERR.puts 'Install yard if you want prettier docs'
25
+ require 'rdoc/task'
26
+ Rake::RDocTask.new(:doc) do |rdoc|
27
+ rdoc.rdoc_dir = 'doc'
28
+ rdoc.title = "bicho #{Bicho::VERSION}"
29
+ extra_docs.each { |ex| rdoc.rdoc_files.include ex }
30
+ end
31
31
  end
@@ -1,26 +1,25 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path("../lib", __FILE__)
3
- require "bicho/version"
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'bicho/version'
4
4
 
5
5
  Gem::Specification.new do |s|
6
- s.name = "bicho"
6
+ s.name = 'bicho'
7
7
  s.version = Bicho::VERSION
8
- s.authors = ["Duncan Mac-Vicar P."]
9
- s.email = ["dmacvicar@suse.de"]
10
- s.homepage = "http://github.com/dmacvicar/bicho"
11
- s.summary = %q{Library to access bugzilla}
12
- s.description = %q{Library to access bugzilla}
8
+ s.authors = ['Duncan Mac-Vicar P.']
9
+ s.email = ['dmacvicar@suse.de']
10
+ s.homepage = 'http://github.com/dmacvicar/bicho'
11
+ s.summary = 'Library to access bugzilla'
12
+ s.description = 'Library to access bugzilla'
13
13
 
14
- s.add_dependency("inifile", ["~> 0.4.1"])
15
- s.add_dependency("trollop", [">= 1.16"])
16
- s.add_dependency("highline", ["~> 1.6.2"])
17
- s.add_dependency("nokogiri")
14
+ s.add_dependency('inifile', ['~> 0.4.1'])
15
+ s.add_dependency('trollop', ['>= 1.16'])
16
+ s.add_dependency('highline', ['~> 1.6.2'])
17
+ s.add_dependency('nokogiri')
18
18
 
19
-
20
- s.rubyforge_project = "bicho"
19
+ s.rubyforge_project = 'bicho'
21
20
 
22
21
  s.files = `git ls-files`.split("\n")
23
22
  s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
24
- s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
25
- s.require_paths = ["lib"]
23
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
24
+ s.require_paths = ['lib']
26
25
  end
data/bin/bicho CHANGED
@@ -23,17 +23,20 @@
23
23
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
24
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
25
  #++
26
- $:.push(File.join(File.dirname(__FILE__), '..', 'lib'))
26
+ $LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', 'lib'))
27
27
  require 'bicho'
28
28
  require 'highline/import'
29
29
 
30
30
  # Set the console color scheme
31
31
  ft = HighLine::ColorScheme.new do |cs|
32
- cs[:headline] = [ :bold ]
33
- cs[:horizontal_line] = [ :bold, :white ]
34
- cs[:even_row] = [ :green ]
35
- cs[:odd_row] = [ :magenta ]
36
- cs[:error] = [ :red ]
32
+ cs[:headline] = [:bold]
33
+ cs[:horizontal_line] = [:bold, :white]
34
+ cs[:even_row] = [:green]
35
+ cs[:odd_row] = [:magenta]
36
+ cs[:error] = [:red]
37
+ cs[:remove] = [ :red ]
38
+ cs[:add] = [ :green ]
39
+ cs[:changeset] = [ :blue ]
37
40
  end
38
41
 
39
42
  HighLine.color_scheme = ft
@@ -57,15 +60,15 @@ begin
57
60
  # symbols in BzConsole module
58
61
  SUB_COMMANDS = Bicho::CLI::Commands.constants.sort.map(&:to_s).map(&:downcase)
59
62
 
60
- global_opts = Trollop::options do
63
+ global_opts = Trollop.options do
61
64
  banner <<-EOS
62
65
  Usage: #{File.basename(__FILE__)} [global options] <command> ...
63
66
 
64
67
  Bugzilla url can be given as https://bugs.kde.org or bko
65
68
  EOS
66
- opt :config, "Read FILE as configuration file.", :type => :io
67
- opt :debug, "Show debug messages", :default => false
68
- opt :bugzilla, "Bugzilla URL or alias", :default => 'bnz'
69
+ opt :config, 'Read FILE as configuration file.', type: :io
70
+ opt :debug, 'Show debug messages', default: false
71
+ opt :bugzilla, 'Bugzilla URL or alias', default: 'bnz'
69
72
  stop_on SUB_COMMANDS
70
73
  end
71
74
 
@@ -74,8 +77,8 @@ EOS
74
77
  # get the subcommand
75
78
  cmd = ARGV.shift rescue nil
76
79
 
77
- if (!cmd || !SUB_COMMANDS.include?(cmd))
78
- Trollop.die "available subcommands: #{SUB_COMMANDS.join(" ")}"
80
+ if !cmd || !SUB_COMMANDS.include?(cmd)
81
+ Trollop.die "available subcommands: #{SUB_COMMANDS.join(' ')}"
79
82
  end
80
83
 
81
84
  # Create an instance for the command
@@ -30,32 +30,30 @@ require 'bicho/client'
30
30
  require 'bicho/bug'
31
31
 
32
32
  module Bicho
33
-
34
33
  SEARCH_FIELDS = [
35
34
  # name, type, description, multi
36
- [ :alias, :strings, "The unique alias for this bug", true],
37
- [ :assigned_to, :strings, "The login name of a user that a bug is assigned to.", true],
38
- [ :component, :strings, "The name of the Component", true],
39
- [ :creation_time, :string, "Searches for bugs that were created at this time or later.", false],
40
- [ :id, :ints, "The numeric id of the bug.", true],
41
- [ :last_change_time, :string, "Searches for bugs that were modified at this time or later.", false],
42
- [ :limit, :ints, "Limit the number of results returned to int records.", true],
43
- [ :offset, :ints, "Used in conjunction with the limit argument, offset defines the starting position for the search.", true],
44
- [ :op_sys, :strings, "The 'Operating System' field of a bug.", true],
45
- [ :platform, :strings, "The Platform field of a bug.", true],
46
- [ :priority, :strings, "The Priority field on a bug.", true],
47
- [ :product, :strings, "The name of the Product that the bug is in.", true],
48
- [ :reporter, :strings, "The login name of the user who reported the bug.", true],
49
- [ :resolution, :strings, "The current resolution--only set if a bug is closed.", true],
50
- [ :severity, :strings, "The Severity field on a bug.", true],
51
- [ :status, :strings, "The current status of a bug", true],
52
- [ :summary, :strings, "Searches for substrings in the single-line Summary field on bugs.", true],
53
- [ :target_milestone, :strings, "The Target Milestone field of a bug.", true],
54
- [ :qa_contact, :strings, "The login name of the bug's QA Contact.", true],
55
- [ :url, :strings, "The 'URL' field of a bug.", true],
56
- [ :version, :strings, "The Version field of a bug.", true],
57
- [ :votes, :ints, "Searches for bugs with this many votes or greater", false],
58
- [ :whiteboard, :strings, "Search the 'Status Whiteboard' field on bugs for a substring.", true]
35
+ [:alias, :strings, 'The unique alias for this bug', true],
36
+ [:assigned_to, :strings, 'The login name of a user that a bug is assigned to.', true],
37
+ [:component, :strings, 'The name of the Component', true],
38
+ [:creation_time, :string, 'Searches for bugs that were created at this time or later.', false],
39
+ [:id, :ints, 'The numeric id of the bug.', true],
40
+ [:last_change_time, :string, 'Searches for bugs that were modified at this time or later.', false],
41
+ [:limit, :ints, 'Limit the number of results returned to int records.', true],
42
+ [:offset, :ints, 'Used in conjunction with the limit argument, offset defines the starting position for the search.', true],
43
+ [:op_sys, :strings, "The 'Operating System' field of a bug.", true],
44
+ [:platform, :strings, 'The Platform field of a bug.', true],
45
+ [:priority, :strings, 'The Priority field on a bug.', true],
46
+ [:product, :strings, 'The name of the Product that the bug is in.', true],
47
+ [:reporter, :strings, 'The login name of the user who reported the bug.', true],
48
+ [:resolution, :strings, 'The current resolution--only set if a bug is closed.', true],
49
+ [:severity, :strings, 'The Severity field on a bug.', true],
50
+ [:status, :strings, 'The current status of a bug', true],
51
+ [:summary, :strings, 'Searches for substrings in the single-line Summary field on bugs.', true],
52
+ [:target_milestone, :strings, 'The Target Milestone field of a bug.', true],
53
+ [:qa_contact, :strings, "The login name of the bug's QA Contact.", true],
54
+ [:url, :strings, "The 'URL' field of a bug.", true],
55
+ [:version, :strings, 'The Version field of a bug.', true],
56
+ [:votes, :ints, 'Searches for bugs with this many votes or greater', false],
57
+ [:whiteboard, :strings, "Search the 'Status Whiteboard' field on bugs for a substring.", true]
59
58
  ]
60
-
61
59
  end
@@ -1,9 +1,7 @@
1
1
  require 'bicho/query'
2
2
 
3
3
  module Bicho
4
-
5
4
  class Bug
6
-
7
5
  # ActiveRecord like interface
8
6
  #
9
7
  # @example Searching for bugs
@@ -43,8 +41,8 @@ module Bicho
43
41
  #
44
42
  # @see http://www.bugzilla.org/docs/tip/en/html/api/Bugzilla/WebService/Bug.html#search bugzilla search API and allowed attributes
45
43
  #
46
- def self.where(conditions={})
47
- return Query.new(conditions)
44
+ def self.where(conditions = {})
45
+ Query.new(conditions)
48
46
  end
49
47
 
50
48
  # Normally you will not use this constructor as
@@ -57,7 +55,7 @@ module Bicho
57
55
  @data = data
58
56
  end
59
57
 
60
- def method_missing(name, *args)
58
+ def method_missing(name, *_args)
61
59
  @data[name.to_s]
62
60
  end
63
61
 
@@ -71,7 +69,7 @@ module Bicho
71
69
  "##{id} - #{summary} (#{url})"
72
70
  end
73
71
 
74
- def [] name, subname = nil
72
+ def [](name, subname = nil)
75
73
  v = @data[name.to_s]
76
74
  v = v[subname.to_s] if subname # for 'internals' properties
77
75
  v
@@ -83,6 +81,10 @@ module Bicho
83
81
  "#{@client.site_url}/#{id}"
84
82
  end
85
83
 
86
- end
84
+ # @return [History] history for this bug
85
+ def history
86
+ @client.get_history(id).first
87
+ end
87
88
 
89
+ end
88
90
  end
@@ -27,9 +27,7 @@ require 'trollop'
27
27
  require 'highline'
28
28
 
29
29
  module Bicho
30
-
31
30
  module CLI
32
-
33
31
  # Bicho allows to easily add commands to the
34
32
  # command line interface.
35
33
  #
@@ -55,7 +53,6 @@ module Bicho
55
53
  # </tt>
56
54
  #
57
55
  class Command
58
-
59
56
  include ::Bicho::Logging
60
57
 
61
58
  class << self; attr_accessor :parser end
@@ -68,8 +65,8 @@ module Bicho
68
65
 
69
66
  # Gateway to Trollop
70
67
  def self.opt(*args)
71
- self.parser = Trollop::Parser.new if not self.parser
72
- self.parser.opt(*args)
68
+ self.parser = Trollop::Parser.new unless parser
69
+ parser.opt(*args)
73
70
  end
74
71
 
75
72
  # DSL method to describe a command's option
@@ -80,8 +77,8 @@ module Bicho
80
77
  # Called by the cli to get the options
81
78
  # with current ARGV
82
79
  def parse_options
83
- self.class.parser = Trollop::Parser.new if not self.class.parser
84
- opts = Trollop::with_standard_exception_handling(self.class.parser) do
80
+ self.class.parser = Trollop::Parser.new unless self.class.parser
81
+ opts = Trollop.with_standard_exception_handling(self.class.parser) do
85
82
  o = self.class.parser.parse ARGV
86
83
  end
87
84
  end
@@ -90,10 +87,9 @@ module Bicho
90
87
  self.class.parser
91
88
  end
92
89
 
93
- def do(opts, args)
94
- raise RuntimeError, "No implementation for #{self.class}" if self.class =~ /CommandTemplate/
90
+ def do(_opts, _args)
91
+ fail RuntimeError, "No implementation for #{self.class}" if self.class =~ /CommandTemplate/
95
92
  end
96
-
97
93
  end
98
94
  end
99
95
  end
@@ -0,0 +1,53 @@
1
+ #--
2
+ # Copyright (c) 2011 SUSE LINUX Products GmbH
3
+ #
4
+ # Author: Duncan Mac-Vicar P. <dmacvicar@suse.de>
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+
26
+ require 'bicho/cli/command'
27
+ require 'bicho/client'
28
+ require 'pp'
29
+
30
+ module Bicho::CLI::Commands
31
+ # command that shows the history colored as a
32
+ # changelog
33
+ class History < ::Bicho::CLI::Command
34
+
35
+ def do(global_opts, _opts, args)
36
+ client = ::Bicho::Client.new(global_opts[:bugzilla])
37
+ client.get_history(*args).each do |history|
38
+ t.say("#{t.color(history.bug_id.to_s, :headline)} #{history.bug.summary}")
39
+ history.changesets.each do |cs|
40
+ text = " #{cs.date} - #{cs.who}"
41
+ t.say(t.color(text, :changeset))
42
+ cs.changes.each do |change|
43
+ text = " - #{change.field_name} = #{change.removed}"
44
+ t.say(t.color(text, :remove))
45
+ text = " + #{change.field_name} = #{change.added}"
46
+ t.say(t.color(text, :add))
47
+ end
48
+ end
49
+ end
50
+ 0
51
+ end
52
+ end
53
+ end
@@ -34,18 +34,18 @@ module Bicho::CLI::Commands
34
34
  options do
35
35
  # add all fields as command line options of this command
36
36
  Bicho::SEARCH_FIELDS.each do |field|
37
- opt field[0], field[2], :type => field[1], :multi => field[3]
37
+ opt field[0], field[2], type: field[1], multi: field[3]
38
38
  end
39
39
  end
40
40
 
41
- def do(global_opts, opts, args)
41
+ def do(global_opts, opts, _args)
42
42
  server = ::Bicho::Client.new(global_opts[:bugzilla])
43
43
  # for most parameter we accept arrays, and also multi mode
44
44
  # this means parameters come in arrays of arrays
45
45
  query = ::Bicho::Query.new
46
- opts.each do |n,v|
46
+ opts.each do |n, v|
47
47
  # skip any option that is not part of SEARCH_FIELDS
48
- next if not Bicho::SEARCH_FIELDS.map { |x| x[0] }.include?(n)
48
+ next unless Bicho::SEARCH_FIELDS.map { |x| x[0] }.include?(n)
49
49
  next if v.nil? || v.flatten.empty?
50
50
  v.flatten.each do |single_val|
51
51
  query.send(n.to_sym, single_val)
@@ -53,10 +53,9 @@ module Bicho::CLI::Commands
53
53
  end
54
54
 
55
55
  server.search_bugs(query).each do |bug|
56
- t.say("#{t.color(bug.id, :headline)} #{bug.summary}")
56
+ t.say("#{t.color(bug.id.to_s, :headline)} #{bug.summary}")
57
57
  end
58
- return 0
58
+ 0
59
59
  end
60
-
61
60
  end
62
61
  end
@@ -31,13 +31,12 @@ module Bicho::CLI::Commands
31
31
  options do
32
32
  end
33
33
 
34
- def do(global_opts, opts, args)
34
+ def do(global_opts, _opts, args)
35
35
  client = ::Bicho::Client.new(global_opts[:bugzilla])
36
36
  client.get_bugs(*args).each do |bug|
37
37
  t.say("#{t.color(bug.id.to_s, :headline)} #{bug.summary}")
38
38
  end
39
- return 0
39
+ 0
40
40
  end
41
-
42
41
  end
43
42
  end
@@ -30,6 +30,7 @@ require 'net/https'
30
30
  require 'cgi'
31
31
 
32
32
  require 'bicho/bug'
33
+ require 'bicho/history'
33
34
  require 'bicho/query'
34
35
  require 'bicho/logging'
35
36
 
@@ -48,18 +49,16 @@ end
48
49
  # @private
49
50
  class XMLRPC::Client
50
51
  def set_debug
51
- @http.set_debug_output(Bicho::LoggerIODevice.new);
52
+ @http.set_debug_output(Bicho::LoggerIODevice.new)
52
53
  end
53
54
  end
54
55
 
55
56
  module Bicho
56
-
57
57
  module Plugins
58
58
  end
59
59
 
60
60
  # Client to query bugzilla
61
61
  class Client
62
-
63
62
  include Bicho::Logging
64
63
 
65
64
  # @return [URI] XML-RPC API end-point
@@ -85,15 +84,15 @@ module Bicho
85
84
  # Implemented only to warn users about the replacement
86
85
  # APIs
87
86
  def url
88
- warn "url is deprecated. Use site_url or api_url"
89
- raise NoMethodError
87
+ warn 'url is deprecated. Use site_url or api_url'
88
+ fail NoMethodError
90
89
  end
91
90
 
92
91
  # @param [String] site_url Bugzilla installation site url
93
92
  def initialize(site_url)
94
93
  # Don't modify the original url
95
- @site_url = site_url.is_a?(URI) ? site_url.clone : URI.parse(site_url)
96
-
94
+ @site_url = site_url.is_a?(URI) ? site_url.clone : URI.parse(site_url)
95
+
97
96
  @api_url = @site_url.clone
98
97
  @api_url.path = '/xmlrpc.cgi'
99
98
 
@@ -104,7 +103,7 @@ module Bicho
104
103
  load plugin
105
104
  end
106
105
 
107
- #instantiate plugins
106
+ # instantiate plugins
108
107
  ::Bicho::Plugins.constants.each do |cnt|
109
108
  pl_class = ::Bicho::Plugins.const_get(cnt)
110
109
  pl_instance = pl_class.new
@@ -121,7 +120,7 @@ module Bicho
121
120
 
122
121
  # User.login sets the credentials cookie for subsequent calls
123
122
  if @client.user && @client.password
124
- ret = @client.call("User.login", { 'login' => @client.user, 'password' => @client.password, 'remember' => 0 } )
123
+ ret = @client.call('User.login', 'login' => @client.user, 'password' => @client.password, 'remember' => 0)
125
124
  handle_faults(ret)
126
125
  @userid = ret['id']
127
126
  end
@@ -132,7 +131,7 @@ module Bicho
132
131
  end
133
132
 
134
133
  def handle_faults(ret)
135
- if ret.has_key?('faults')
134
+ if ret.key?('faults')
136
135
  ret['faults'].each do |fault|
137
136
  logger.error fault
138
137
  end
@@ -149,7 +148,7 @@ module Bicho
149
148
  # allow plain strings to be passed, interpretting them
150
149
  query = Query.new.summary(query) if query.is_a?(String)
151
150
 
152
- ret = @client.call("Bug.search", query.query_map)
151
+ ret = @client.call('Bug.search', query.query_map)
153
152
  handle_faults(ret)
154
153
  bugs = []
155
154
  ret['bugs'].each do |bug_data|
@@ -173,14 +172,14 @@ module Bicho
173
172
  # @private
174
173
  # @returns [Array<String>] list of bugs
175
174
  def fetch_named_query_url(url, redirects_left)
176
- if not @userid
177
- raise "You need to be authenticated to use named queries"
175
+ unless @userid
176
+ fail 'You need to be authenticated to use named queries'
178
177
  end
179
178
  http = Net::HTTP.new(@api_url.host, @api_url.port)
180
179
  http.set_debug_output(Bicho::LoggerIODevice.new)
181
180
  http.verify_mode = OpenSSL::SSL::VERIFY_NONE
182
181
  http.use_ssl = (@api_url.scheme == 'https')
183
- #request = Net::HTTP::Get.new(url.request_uri, {'Cookie' => self.cookie})
182
+ # request = Net::HTTP::Get.new(url.request_uri, {'Cookie' => self.cookie})
184
183
  request = Net::HTTP::Get.new(url.request_uri)
185
184
  request.basic_auth @api_url.user, @api_url.password
186
185
  response = http.request(request)
@@ -189,9 +188,9 @@ module Bicho
189
188
  bugs = []
190
189
  begin
191
190
  xml = Nokogiri::XML.parse(response.body)
192
- xml.root.xpath("//xmlns:entry/xmlns:link/@href", xml.root.namespace).each do |attr|
191
+ xml.root.xpath('//xmlns:entry/xmlns:link/@href', xml.root.namespace).each do |attr|
193
192
  uri = URI.parse attr.value
194
- bugs << uri.query.split("=")[1]
193
+ bugs << uri.query.split('=')[1]
195
194
  end
196
195
  return bugs
197
196
  rescue Nokogiri::XML::XPath::SyntaxError
@@ -200,19 +199,26 @@ module Bicho
200
199
  when Net::HTTPRedirection
201
200
  location = response['location']
202
201
  if (redirects_left == 0)
203
- raise "Maximum redirects exceeded (redirected to #{location})"
202
+ fail "Maximum redirects exceeded (redirected to #{location})"
204
203
  end
205
204
  new_location_uri = URI.parse(location)
206
205
  logger.debug("Moved to #{new_location_uri}")
207
206
  fetch_named_query_url(new_location_uri, redirects_left - 1)
208
207
  else
209
- raise "Error when expanding named query '#{url.request_uri}': #{response}"
208
+ fail "Error when expanding named query '#{url.request_uri}': #{response}"
210
209
  end
211
210
  end
212
211
 
212
+ # Gets a single bug
213
+ # @return [Bug] a single bug by id
214
+ def get_bug(id)
215
+ get_bugs(id).first
216
+ end
217
+
213
218
  # Retrieves one or more bugs by id
219
+ # @return [Array<Bug>] a list of bugs
214
220
  def get_bugs(*ids)
215
- params = Hash.new
221
+ params = {}
216
222
  params[:ids] = ids.collect(&:to_s).map do |what|
217
223
  if what =~ /^[0-9]+$/
218
224
  next what.to_i
@@ -222,7 +228,7 @@ module Bicho
222
228
  end.flatten
223
229
 
224
230
  bugs = []
225
- ret = @client.call("Bug.get", params)
231
+ ret = @client.call('Bug.get', params)
226
232
  handle_faults(ret)
227
233
  ret['bugs'].each do |bug_data|
228
234
  bugs << Bug.new(self, bug_data)
@@ -230,5 +236,25 @@ module Bicho
230
236
  bugs
231
237
  end
232
238
 
239
+ # @return [Array<History>] the history of the given bugs
240
+ def get_history(*ids)
241
+ params = {}
242
+ params[:ids] = ids.collect(&:to_s).map do |what|
243
+ if what =~ /^[0-9]+$/
244
+ next what.to_i
245
+ else
246
+ next expand_named_query(what)
247
+ end
248
+ end.flatten
249
+
250
+ histories = []
251
+ ret = @client.call("Bug.history", params)
252
+ handle_faults(ret)
253
+ ret['bugs'].each do |history_data|
254
+ histories << History.new(self, history_data)
255
+ end
256
+ histories
257
+ end
258
+
233
259
  end
234
260
  end
@@ -30,12 +30,12 @@ module Bicho
30
30
  # API by allowing to set a default [Client]
31
31
  # to make operations.
32
32
  module CommonClient
33
- def self.common_client=(client)
34
- @common_client = client
33
+ class << self
34
+ attr_writer :common_client
35
35
  end
36
36
 
37
37
  def self.common_client
38
- @common_client || (raise "No common client set")
38
+ @common_client || (fail 'No common client set')
39
39
  end
40
40
 
41
41
  def common_client
@@ -53,5 +53,4 @@ module Bicho
53
53
  def self.client
54
54
  CommonClient.common_client
55
55
  end
56
-
57
56
  end
@@ -26,22 +26,22 @@ class Logger
26
26
  WHITE = '1;37'
27
27
 
28
28
  SCHEMA = {
29
- STDOUT => %w[nothing green brown red purple cyan],
30
- STDERR => %w[nothing green yellow light_red light_purple light_cyan],
29
+ STDOUT => %w(nothing green brown red purple cyan),
30
+ STDERR => %w(nothing green yellow light_red light_purple light_cyan)
31
31
  }
32
32
  end
33
33
  end
34
34
 
35
35
  class Logger
36
- alias format_message_colorless format_message
36
+ alias_method :format_message_colorless, :format_message
37
37
 
38
38
  def format_message(level, *args)
39
39
  if Logger::Colors::SCHEMA[@logdev.dev]
40
40
  color = begin
41
41
  Logger::Colors.const_get \
42
- Logger::Colors::SCHEMA[@logdev.dev][Logger.const_get(level.sub "ANY","UNKNOWN")].to_s.upcase
42
+ Logger::Colors::SCHEMA[@logdev.dev][Logger.const_get(level.sub 'ANY', 'UNKNOWN')].to_s.upcase
43
43
  rescue NameError
44
- "0;0"
44
+ '0;0'
45
45
  end
46
46
  "\e[#{ color }m#{ format_message_colorless(level, *args) }\e[0;0m"
47
47
  else
@@ -0,0 +1,139 @@
1
+ #--
2
+ # Copyright (c) 2011 SUSE LINUX Products GmbH
3
+ #
4
+ # Author: Duncan Mac-Vicar P. <dmacvicar@suse.de>
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #++
25
+ require 'stringio'
26
+
27
+ module Bicho
28
+ class Change
29
+ def field_name
30
+ @data['field_name']
31
+ end
32
+
33
+ def removed
34
+ @data['removed']
35
+ end
36
+
37
+ def added
38
+ @data['added']
39
+ end
40
+
41
+ def to_s
42
+ buffer = StringIO.new
43
+ buffer << "- #{field_name} = #{removed}\n"
44
+ buffer << "+ #{field_name} = #{added}"
45
+ buffer.string
46
+ end
47
+
48
+ def initialize(client, data)
49
+ @client = client
50
+ @data = data
51
+ end
52
+ end
53
+
54
+ class ChangeSet
55
+ # return [Date] The date the bug activity/change happened.
56
+ def date
57
+ @data['when'].to_date
58
+ end
59
+
60
+ # @return [String] The login name of the user who performed the bug change
61
+ def who
62
+ @data['who']
63
+ end
64
+
65
+ # @return [Array<Change>] list of changes, with details of what changed
66
+ def changes
67
+ @data['changes'].map do |change|
68
+ Change.new(@client, change)
69
+ end
70
+ end
71
+
72
+ def initialize(client, data)
73
+ @client = client
74
+ @data = data
75
+ end
76
+
77
+ def to_s
78
+ buffer = StringIO.new
79
+ buffer << "#{date}- #{who}\n"
80
+ changes.each do |diff|
81
+ buffer << "#{diff}\n"
82
+ end
83
+ buffer.string
84
+ end
85
+ end
86
+
87
+ # A collection of Changesets associated with a bug
88
+ class History
89
+ include Enumerable
90
+
91
+ # iterate over each changeset
92
+ def each
93
+ changesets.each
94
+ end
95
+
96
+ # @return [Fixnum] number of changesets
97
+ def size
98
+ changesets.size
99
+ end
100
+
101
+ # @return [Boolean] true when there are no changesets
102
+ def empty?
103
+ changesets.empty?
104
+ end
105
+
106
+ def initialize(client, data)
107
+ @client = client
108
+ @data = data
109
+ end
110
+
111
+ def bug_id
112
+ @data['id']
113
+ end
114
+
115
+ # @return [String] The numeric id of the bug
116
+ def bug
117
+ unless @bug
118
+ @bug = @client.get_bug(@data['id'])
119
+ end
120
+ @bug
121
+ end
122
+
123
+ # @return [Array<ChangeSet>] collection of changesets
124
+ def changesets
125
+ @data['history'].map do |changeset|
126
+ ChangeSet.new(@client, changeset)
127
+ end
128
+ end
129
+
130
+ def to_s
131
+ buffer = StringIO.new
132
+ buffer << "#{bug_id}\n"
133
+ change_sets.each do |cs|
134
+ buffer << "#{cs}\n"
135
+ end
136
+ buffer.string
137
+ end
138
+ end
139
+ end
@@ -27,9 +27,8 @@ require 'bicho/ext/logger_colors'
27
27
 
28
28
  module Bicho
29
29
  module Logging
30
-
31
- def self.logger=(logger)
32
- @logger = logger
30
+ class << self
31
+ attr_writer :logger
33
32
  end
34
33
 
35
34
  def self.logger
@@ -39,6 +38,5 @@ module Bicho
39
38
  def logger
40
39
  Logging.logger
41
40
  end
42
-
43
41
  end
44
42
  end
@@ -1,6 +1,6 @@
1
1
  #--
2
2
  # Copyright (c) 2011 SUSE LINUX Products GmbH
3
- # =>
3
+ # =>
4
4
  # Author: Duncan Mac-Vicar P. <dmacvicar@suse.de>
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
@@ -27,7 +27,6 @@ require 'uri'
27
27
 
28
28
  module Bicho
29
29
  module Plugins
30
-
31
30
  # Novell bugzilla is behind ichain
32
31
  #
33
32
  # Plugin that rewrites the bugzilla API url
@@ -38,12 +37,11 @@ module Bicho
38
37
  # your oscrc.
39
38
  #
40
39
  class Novell
41
-
42
- OSCRC_CREDENTIALS = "https://api.opensuse.org"
40
+ OSCRC_CREDENTIALS = 'https://api.opensuse.org'
43
41
  DEFAULT_OSCRC_PATH = File.join(ENV['HOME'], '.oscrc')
44
42
 
45
- def self.oscrc_path=(path)
46
- @oscrc_path = path
43
+ class << self
44
+ attr_writer :oscrc_path
47
45
  end
48
46
 
49
47
  def self.oscrc_path
@@ -57,21 +55,21 @@ module Bicho
57
55
  def self.oscrc_credentials
58
56
  oscrc = IniFile.load(oscrc_path)
59
57
  urls = [OSCRC_CREDENTIALS]
60
- urls << "#{OSCRC_CREDENTIALS}/" if not OSCRC_CREDENTIALS.end_with?('/')
58
+ urls << "#{OSCRC_CREDENTIALS}/" unless OSCRC_CREDENTIALS.end_with?('/')
61
59
  urls.each do |section|
62
- next if not oscrc.has_section?(section)
60
+ next unless oscrc.has_section?(section)
63
61
  user = oscrc[section]['user']
64
62
  pass = oscrc[section]['pass']
65
63
  if user && pass
66
- return {:user => user, :password => pass}
64
+ return { user: user, password: pass }
67
65
  end
68
66
  end
69
- raise "No valid .oscrc credentials for Novell/SUSE bugzilla (#{oscrc_path})"
67
+ fail "No valid .oscrc credentials for Novell/SUSE bugzilla (#{oscrc_path})"
70
68
  end
71
69
 
72
70
  def transform_api_url_hook(url, logger)
73
71
  domains = ['bugzilla.novell.com', 'bugzilla.suse.com']
74
- return url unless domains.map {|domain| url.host.include?(domain)}.any?
72
+ return url unless domains.map { |domain| url.host.include?(domain) }.any?
75
73
 
76
74
  auth = Novell.oscrc_credentials
77
75
 
@@ -82,10 +80,9 @@ module Bicho
82
80
  url.host = url.host.gsub(/bugzilla\.suse.com/, 'apibugzilla.novell.com')
83
81
  url.scheme = 'https'
84
82
 
85
- logger.debug("#{self} : Rewrote url to '#{url.to_s.gsub(/#{url.user}:#{url.password}/, "USER:PASS")}'")
86
- return url
83
+ logger.debug("#{self} : Rewrote url to '#{url.to_s.gsub(/#{url.user}:#{url.password}/, 'USER:PASS')}'")
84
+ url
87
85
  end
88
-
89
86
  end
90
87
  end
91
88
  end
@@ -25,13 +25,11 @@
25
25
  require 'bicho/common_client'
26
26
 
27
27
  module Bicho
28
-
29
28
  # Represents a bug search to the server and it can
30
29
  # be configured with all bug attributes.
31
30
  #
32
31
  #
33
32
  class Query
34
-
35
33
  include Enumerable
36
34
 
37
35
  # Iterates through the result of the current query.
@@ -41,7 +39,7 @@ module Bicho
41
39
  # @yield [Bicho::Bug]
42
40
  def each
43
41
  ret = Bicho.client.search_bugs(self)
44
- return ret.each if not block_given?
42
+ return ret.each unless block_given?
45
43
  ret.each { |bug| yield bug }
46
44
  end
47
45
 
@@ -57,7 +55,7 @@ module Bicho
57
55
  # @example using chainable methods:
58
56
  # q = Query.new.assigned_to("foo@bar.com@).summary("some text")
59
57
  #
60
- def initialize(conditions={})
58
+ def initialize(conditions = {})
61
59
  @query_map = conditions
62
60
  end
63
61
 
@@ -79,11 +77,12 @@ module Bicho
79
77
  # Shortcut, equivalent to
80
78
  # :summary => "L3"
81
79
  def L3
82
- append_query("summary", "L3")
80
+ append_query('summary', 'L3')
83
81
  self
84
82
  end
85
83
 
86
84
  private
85
+
87
86
  # Appends a parameter to the query map
88
87
  #
89
88
  # Only used internally.
@@ -93,12 +92,10 @@ module Bicho
93
92
  #
94
93
  # @private
95
94
  def append_query(param, value)
96
- if not @query_map.has_key?(param)
97
- @query_map[param] = Array.new
95
+ unless @query_map.key?(param)
96
+ @query_map[param] = []
98
97
  end
99
98
  @query_map[param] = [@query_map[param], value].flatten
100
99
  end
101
-
102
100
  end
103
-
104
101
  end
@@ -1,3 +1,3 @@
1
1
  module Bicho
2
- VERSION = '0.0.8'
2
+ VERSION = '0.0.9'
3
3
  end
@@ -1,9 +1,8 @@
1
- $: << File.join(File.dirname(__FILE__), "..", "lib")
1
+ $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
2
2
  require 'test/unit'
3
3
  require 'bicho'
4
4
 
5
- if ENV["DEBUG"]
5
+ if ENV['DEBUG']
6
6
  Bicho::Logging.logger = Logger.new(STDERR)
7
7
  Bicho::Logging.logger.level = Logger::DEBUG
8
8
  end
9
-
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__), 'helper')
2
+
3
+ class History_test < Test::Unit::TestCase
4
+
5
+ def test_basic_history
6
+ Bicho.client = Bicho::Client.new('https://bugzilla.gnome.org')
7
+
8
+ bug = Bicho.client.get_bug(645150)
9
+
10
+ assert bug.history.size > 0
11
+ end
12
+
13
+ end
@@ -3,16 +3,15 @@ require 'bicho/plugins/novell'
3
3
  require 'tmpdir'
4
4
 
5
5
  class NovellPlugin_test < Test::Unit::TestCase
6
-
7
6
  def test_urls_are_correct
8
- ['novell', 'suse'].each do |domain|
7
+ %w(novell suse).each do |domain|
9
8
  client = Bicho::Client.new("https://bugzilla.#{domain}.com")
10
9
  assert_raises NoMethodError do
11
10
  client.url
12
11
  end
13
12
 
14
- #assert_equal "https://apibugzilla.#{domain}.com/xmlrpc.cgi", "#{client.api_url.scheme}://#{client.api_url.host}#{client.api_url.path}"
15
- #assert_equal "https://bugzilla.#{domain}.com", "#{client.site_url.scheme}://#{client.site_url.host}#{client.site_url.path}"
13
+ # assert_equal "https://apibugzilla.#{domain}.com/xmlrpc.cgi", "#{client.api_url.scheme}://#{client.api_url.host}#{client.api_url.path}"
14
+ # assert_equal "https://bugzilla.#{domain}.com", "#{client.site_url.scheme}://#{client.site_url.host}#{client.site_url.path}"
16
15
  end
17
16
  end
18
17
 
@@ -35,10 +34,9 @@ EOS
35
34
  plugin = Bicho::Plugins::Novell.new
36
35
  credentials = Bicho::Plugins::Novell.oscrc_credentials
37
36
  assert_not_nil(credentials)
38
- assert(credentials.has_key?(:user))
39
- assert(credentials.has_key?(:password))
37
+ assert(credentials.key?(:user))
38
+ assert(credentials.key?(:password))
40
39
  Bicho::Plugins::Novell.oscrc_path = nil
41
40
  end
42
41
  end
43
-
44
42
  end
@@ -1,30 +1,27 @@
1
1
  require File.join(File.dirname(__FILE__), 'helper')
2
2
 
3
3
  class Query_test < Test::Unit::TestCase
4
-
5
4
  def test_active_record_style
6
5
  # No client set yet
7
6
  assert_raise RuntimeError do
8
- Bicho::Bug.where.assigned_to("foo@bar.com").each do |bug|
7
+ Bicho::Bug.where.assigned_to('foo@bar.com').each do |bug|
9
8
  puts bug
10
9
  end
11
10
  end
12
11
 
13
12
  Bicho.client = Bicho::Client.new('https://bugzilla.gnome.org')
14
13
 
15
- ret = Bicho::Bug.where.product("vala").status("resolved").component("Basic Types").each.to_a
16
- assert ret.collect(&:id).include?(645150)
17
-
14
+ ret = Bicho::Bug.where.product('vala').status('resolved').component('Basic Types').each.to_a
15
+ assert ret.collect(&:id).include?(645_150)
18
16
  end
19
-
17
+
20
18
  def test_query_addition_of_attributes
21
- ret = Bicho::Query.new.status("foo").status("bar")
22
- assert_equal({"status" => ["foo", "bar"]}, ret.query_map)
19
+ ret = Bicho::Query.new.status('foo').status('bar')
20
+ assert_equal({ 'status' => %w(foo bar) }, ret.query_map)
23
21
  end
24
22
 
25
23
  def test_query_shortcuts
26
24
  ret = Bicho::Query.new.open
27
- assert_equal({"status" => [:new, :assigned, :needinfo, :reopened]}, ret.query_map)
25
+ assert_equal({ 'status' => [:new, :assigned, :needinfo, :reopened] }, ret.query_map)
28
26
  end
29
-
30
27
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bicho
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.8
4
+ version: 0.0.9
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-26 00:00:00.000000000 Z
12
+ date: 2014-11-27 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: inifile
@@ -93,16 +93,19 @@ files:
93
93
  - lib/bicho.rb
94
94
  - lib/bicho/bug.rb
95
95
  - lib/bicho/cli/command.rb
96
+ - lib/bicho/cli/commands/history.rb
96
97
  - lib/bicho/cli/commands/search.rb
97
98
  - lib/bicho/cli/commands/show.rb
98
99
  - lib/bicho/client.rb
99
100
  - lib/bicho/common_client.rb
100
101
  - lib/bicho/ext/logger_colors.rb
102
+ - lib/bicho/history.rb
101
103
  - lib/bicho/logging.rb
102
104
  - lib/bicho/plugins/novell.rb
103
105
  - lib/bicho/query.rb
104
106
  - lib/bicho/version.rb
105
107
  - test/helper.rb
108
+ - test/test_history.rb
106
109
  - test/test_novell_plugin.rb
107
110
  - test/test_query.rb
108
111
  homepage: http://github.com/dmacvicar/bicho
@@ -131,6 +134,7 @@ specification_version: 3
131
134
  summary: Library to access bugzilla
132
135
  test_files:
133
136
  - test/helper.rb
137
+ - test/test_history.rb
134
138
  - test/test_novell_plugin.rb
135
139
  - test/test_query.rb
136
140
  has_rdoc: