bicho 0.0.8 → 0.0.9

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/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: