fogbugz 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/bin/fogbugz +78 -0
- data/bin/fogbugz-areas +64 -0
- data/bin/fogbugz-assign +58 -0
- data/bin/fogbugz-categories +55 -0
- data/bin/fogbugz-close +57 -0
- data/bin/fogbugz-edit +281 -0
- data/bin/fogbugz-filter +78 -0
- data/bin/fogbugz-filters +53 -0
- data/bin/fogbugz-list +69 -0
- data/bin/fogbugz-login +60 -0
- data/bin/fogbugz-logoff +49 -0
- data/bin/fogbugz-milestones +57 -0
- data/bin/fogbugz-new +165 -0
- data/bin/fogbugz-people +57 -0
- data/bin/fogbugz-priorities +55 -0
- data/bin/fogbugz-projects +57 -0
- data/bin/fogbugz-reactivate +56 -0
- data/bin/fogbugz-reopen +56 -0
- data/bin/fogbugz-resolve +82 -0
- data/bin/fogbugz-show +147 -0
- data/bin/fogbugz-start +55 -0
- data/bin/fogbugz-statuses +62 -0
- data/bin/fogbugz-stop +50 -0
- data/lib/dummy.rb +1 -0
- metadata +119 -0
data/bin/fogbugz-filter
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'xml'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
9
|
+
unless api_url
|
10
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
api_token = ENV['FOGBUGZ_API_TOKEN']
|
15
|
+
unless api_url
|
16
|
+
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
options = {}
|
21
|
+
optparse = OptionParser.new do |opts|
|
22
|
+
opts.banner = "usage: #{File::basename(__FILE__)} [options] <filter>"
|
23
|
+
|
24
|
+
options[:verbose] = false
|
25
|
+
opts.on('-v', '--verbose', 'Output verbose debugging information.') do
|
26
|
+
options[:verbose] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on_tail('-h', '--help') do
|
30
|
+
puts optparse.help
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
optparse.parse!
|
35
|
+
unless ARGV[0]
|
36
|
+
puts optparse.help
|
37
|
+
exit 1
|
38
|
+
end
|
39
|
+
|
40
|
+
response = Typhoeus::Request.get(api_url,
|
41
|
+
:verbose => options[:verbose],
|
42
|
+
:params => { :cmd => 'listFilters', :token => api_token })
|
43
|
+
if response.code != 200
|
44
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
45
|
+
exit 1
|
46
|
+
end
|
47
|
+
|
48
|
+
result = XML::Parser.string(response.body).parse
|
49
|
+
error = result.find_first('/response/error')
|
50
|
+
if error
|
51
|
+
puts "Failed with error: #{error.content}."
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
|
55
|
+
params = { :cmd => 'setCurrentFilter', :token => api_token }
|
56
|
+
filter = result.find_first "/response/filters/filter[.='#{ARGV[0]}']"
|
57
|
+
if filter
|
58
|
+
params[:sFilter] = filter['sFilter']
|
59
|
+
else
|
60
|
+
puts "#{ARGV[0]} is not a valid filter."
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
|
64
|
+
response = Typhoeus::Request.get(api_url,
|
65
|
+
:verbose => options[:verbose],
|
66
|
+
:params => params)
|
67
|
+
|
68
|
+
if response.code != 200
|
69
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
70
|
+
exit 1
|
71
|
+
end
|
72
|
+
|
73
|
+
result = XML::Parser.string(response.body).parse
|
74
|
+
error = result.find_first('/response/error')
|
75
|
+
if error
|
76
|
+
puts "Failed with error: #{error.content}."
|
77
|
+
exit 1
|
78
|
+
end
|
data/bin/fogbugz-filters
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'xml'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
9
|
+
unless api_url
|
10
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
api_token = ENV['FOGBUGZ_API_TOKEN']
|
15
|
+
unless api_url
|
16
|
+
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
options = {}
|
21
|
+
optparse = OptionParser.new do |opts|
|
22
|
+
opts.banner = "usage: #{File::basename(__FILE__)} [options]"
|
23
|
+
|
24
|
+
options[:verbose] = false
|
25
|
+
opts.on('-v', '--verbose', 'Output verbose debugging information') do
|
26
|
+
options[:verbose] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on_tail('-h', '--help') do
|
30
|
+
puts optparse.help
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
optparse.parse!
|
35
|
+
|
36
|
+
response = Typhoeus::Request.get(api_url,
|
37
|
+
:verbose => options[:verbose],
|
38
|
+
:params => { :cmd => 'listFilters', :token => api_token })
|
39
|
+
if response.code != 200
|
40
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
|
44
|
+
result = XML::Parser.string(response.body).parse
|
45
|
+
error = result.find_first('/response/error')
|
46
|
+
if error
|
47
|
+
puts "Failed with error: #{error.content}."
|
48
|
+
exit 1
|
49
|
+
end
|
50
|
+
|
51
|
+
result.find('/response/filters/filter').each do |filter|
|
52
|
+
puts filter.content
|
53
|
+
end
|
data/bin/fogbugz-list
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'xml'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
9
|
+
unless api_url
|
10
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
api_token = ENV['FOGBUGZ_API_TOKEN']
|
15
|
+
unless api_url
|
16
|
+
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
options = {}
|
21
|
+
optparse = OptionParser.new do |opts|
|
22
|
+
opts.banner = "usage: #{File::basename(__FILE__)} [options] [query]"
|
23
|
+
|
24
|
+
options[:verbose] = false
|
25
|
+
opts.on('-v', '--verbose', 'Output verbose debugging information') do
|
26
|
+
options[:verbose] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on_tail('-h', '--help') do
|
30
|
+
puts optparse.help
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
|
34
|
+
options[:max] = nil
|
35
|
+
opts.on('--max=<max>', 'Maximum number of results.') do |max|
|
36
|
+
options[:max] = max
|
37
|
+
end
|
38
|
+
end
|
39
|
+
optparse.parse!
|
40
|
+
|
41
|
+
response = Typhoeus::Request.get(api_url,
|
42
|
+
:verbose => options[:verbose],
|
43
|
+
:params => {
|
44
|
+
:cmd => 'search',
|
45
|
+
:token => api_token,
|
46
|
+
:cols => 'ixBug,sPersonAssignedTo,sFixFor,sPriority,sTitle',
|
47
|
+
:q => ARGV[0],
|
48
|
+
:max => options[:max] })
|
49
|
+
|
50
|
+
if response.code != 200
|
51
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
52
|
+
exit 1
|
53
|
+
end
|
54
|
+
|
55
|
+
result = XML::Parser.string(response.body).parse
|
56
|
+
error = result.find_first('/response/error')
|
57
|
+
if error
|
58
|
+
puts "Failed with error: #{error.content}."
|
59
|
+
exit 1
|
60
|
+
end
|
61
|
+
|
62
|
+
result.find('/response/cases/case').each do |bug|
|
63
|
+
puts format("%-6.6s %-20.20s %-16.16s %-16.16s %s\n",
|
64
|
+
bug.find_first('ixBug').content,
|
65
|
+
bug.find_first('sPersonAssignedTo').content,
|
66
|
+
bug.find_first('sFixFor').content,
|
67
|
+
bug.find_first('sPriority').content,
|
68
|
+
bug.find_first('sTitle').content).strip!
|
69
|
+
end
|
data/bin/fogbugz-login
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'xml'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'pp'
|
8
|
+
require 'optparse'
|
9
|
+
require 'yaml'
|
10
|
+
require 'English'
|
11
|
+
require 'term/ansicolor'
|
12
|
+
|
13
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
14
|
+
unless api_url
|
15
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
16
|
+
exit 1
|
17
|
+
end
|
18
|
+
|
19
|
+
options = {}
|
20
|
+
optparse = OptionParser.new do |opts|
|
21
|
+
opts.banner = "usage: #{File::basename(__FILE__)} [options] <email> <password>"
|
22
|
+
|
23
|
+
options[:verbose] = false
|
24
|
+
opts.on('-v', '--verbose', 'Output verbose debugging information') do
|
25
|
+
options[:verbose] = true
|
26
|
+
end
|
27
|
+
|
28
|
+
opts.on_tail('-h', '--help') do
|
29
|
+
puts optparse.help
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
optparse.parse!
|
34
|
+
unless ARGV.length == 2
|
35
|
+
puts optparse.help
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
response = Typhoeus::Request.get(api_url,
|
40
|
+
:verbose => options[:verbose],
|
41
|
+
:params => {
|
42
|
+
:cmd => 'logon',
|
43
|
+
:email => ARGV[0],
|
44
|
+
:password => ARGV[1] })
|
45
|
+
if response.code != 200
|
46
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
47
|
+
exit 1
|
48
|
+
end
|
49
|
+
|
50
|
+
result = XML::Parser.string(response.body).parse
|
51
|
+
error = result.find_first('/response/error')
|
52
|
+
if error
|
53
|
+
puts "Failed with error: #{error.content}."
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
|
57
|
+
puts <<HERE
|
58
|
+
Login successful. Set the following environment variable:
|
59
|
+
export FOGBUGZ_API_TOKEN=#{result.find_first('/response/token').content}
|
60
|
+
HERE
|
data/bin/fogbugz-logoff
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'xml'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
9
|
+
unless api_url
|
10
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
api_token = ENV['FOGBUGZ_API_TOKEN']
|
15
|
+
unless api_url
|
16
|
+
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
options = {}
|
21
|
+
optparse = OptionParser.new do |opts|
|
22
|
+
opts.banner = "usage: #{File::basename(__FILE__)} [options]"
|
23
|
+
|
24
|
+
options[:verbose] = false
|
25
|
+
opts.on('-v', '--verbose', 'Output verbose debugging information') do
|
26
|
+
options[:verbose] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on_tail('-h', '--help') do
|
30
|
+
puts optparse.help
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
optparse.parse!
|
35
|
+
|
36
|
+
response = Typhoeus::Request.get(api_url,
|
37
|
+
:params => { :cmd => 'logoff', :token => api_token },
|
38
|
+
:verbose => options[:verbose]);
|
39
|
+
if response.code != 200
|
40
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
41
|
+
exit 1
|
42
|
+
end
|
43
|
+
|
44
|
+
result = XML::Parser.string(response.body).parse
|
45
|
+
error = result.find_first('/response/error')
|
46
|
+
if error
|
47
|
+
puts "Failed with error: #{error.content}."
|
48
|
+
exit 1
|
49
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'xml'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
9
|
+
unless api_url
|
10
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
api_token = ENV['FOGBUGZ_API_TOKEN']
|
15
|
+
unless api_url
|
16
|
+
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
17
|
+
exit 1
|
18
|
+
end
|
19
|
+
|
20
|
+
options = {}
|
21
|
+
optparse = OptionParser.new do |opts|
|
22
|
+
opts.banner = "usage: #{File::basename(__FILE__)} [options]"
|
23
|
+
|
24
|
+
options[:verbose] = false
|
25
|
+
opts.on('-v', '--verbose', 'Output verbose debugging information') do
|
26
|
+
options[:verbose] = true
|
27
|
+
end
|
28
|
+
|
29
|
+
opts.on_tail('-h', '--help') do
|
30
|
+
puts optparse.help
|
31
|
+
exit 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
optparse.parse!
|
35
|
+
response = Typhoeus::Request.get(api_url,
|
36
|
+
:verbose => options[:verbose],
|
37
|
+
:params => {
|
38
|
+
:cmd => 'listFixFors',
|
39
|
+
:token => api_token })
|
40
|
+
if response.code != 200
|
41
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
|
45
|
+
result = XML::Parser.string(response.body).parse
|
46
|
+
error = result.find_first('/response/error')
|
47
|
+
if error
|
48
|
+
puts "Failed with error: #{error.content}."
|
49
|
+
exit 1
|
50
|
+
end
|
51
|
+
|
52
|
+
result.find('/response/fixfors/fixfor').each do |status|
|
53
|
+
puts format("%-30.30s %-16.16s %s\n",
|
54
|
+
status.find_first('sFixFor').content,
|
55
|
+
status.find_first('dt').content,
|
56
|
+
status.find_first('sProject').content).strip!
|
57
|
+
end
|
data/bin/fogbugz-new
ADDED
@@ -0,0 +1,165 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'typhoeus'
|
5
|
+
require 'xml'
|
6
|
+
require 'tempfile'
|
7
|
+
require 'optparse'
|
8
|
+
require 'yaml'
|
9
|
+
require 'English'
|
10
|
+
|
11
|
+
api_url = ENV['FOGBUGZ_API_URL']
|
12
|
+
unless api_url
|
13
|
+
puts "Environment variable FOGBUGZ_API_URL must be set."
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
api_token = ENV['FOGBUGZ_API_TOKEN']
|
18
|
+
unless api_url
|
19
|
+
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
editor = ENV['EDITOR'] || 'vim'
|
24
|
+
|
25
|
+
options = {}
|
26
|
+
optparse = OptionParser.new do |opts|
|
27
|
+
opts.banner = "usage: #{File::basename(__FILE__)} [options] [-|files]"
|
28
|
+
|
29
|
+
options[:verbose] = false
|
30
|
+
opts.on('-v', '--verbose', 'Output verbose debugging information.') do
|
31
|
+
options[:verbose] = true
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on_tail('-h', '--help') do
|
35
|
+
puts optparse.help
|
36
|
+
exit 1
|
37
|
+
end
|
38
|
+
|
39
|
+
options[:file] = nil
|
40
|
+
opts.on('-f', '--file=<file>',
|
41
|
+
'Take the case content from the given file. Use - to read from STDIN.') do |file|
|
42
|
+
options[:file] = file
|
43
|
+
end
|
44
|
+
|
45
|
+
options[:template] = nil
|
46
|
+
opts.on('-t', '--template=<template>',
|
47
|
+
'Use the file content or - for STDIN as the initial case content.') do |template|
|
48
|
+
options[:template] = template
|
49
|
+
end
|
50
|
+
end
|
51
|
+
optparse.parse!
|
52
|
+
|
53
|
+
unless ARGV.empty?
|
54
|
+
puts optparse.help
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
|
58
|
+
invoke_editor = true
|
59
|
+
if options[:file]
|
60
|
+
if options[:file] == '-'
|
61
|
+
ARGV.replace []
|
62
|
+
else
|
63
|
+
ARGV.replace [options[:file]]
|
64
|
+
end
|
65
|
+
template = ARGF.read
|
66
|
+
invoke_editor = false
|
67
|
+
elsif options[:template]
|
68
|
+
if options[:template] == '-'
|
69
|
+
ARGV.replace []
|
70
|
+
else
|
71
|
+
ARGV.replace [options[:template]]
|
72
|
+
end
|
73
|
+
template = ARGF.read
|
74
|
+
else
|
75
|
+
template = <<HERE
|
76
|
+
# Fill in metadata for the case.
|
77
|
+
# title: <title>
|
78
|
+
# assignee: <person>
|
79
|
+
# parent: <case>
|
80
|
+
# tags: [bug, enhancement]
|
81
|
+
# project: <project>
|
82
|
+
# area: <area>
|
83
|
+
# milestone: <milestone>
|
84
|
+
# category: <category>
|
85
|
+
# priority: <priority>
|
86
|
+
# estimate: <hours>
|
87
|
+
|
88
|
+
# Enter an optional description of the case after the dashes.
|
89
|
+
---
|
90
|
+
HERE
|
91
|
+
end
|
92
|
+
|
93
|
+
content = template
|
94
|
+
if invoke_editor
|
95
|
+
tempfile = Tempfile.new ['case', '.md']
|
96
|
+
tempfile.write template
|
97
|
+
tempfile.close
|
98
|
+
rc = system "#{editor} #{tempfile.path}"
|
99
|
+
unless rc
|
100
|
+
puts "Editor exited with non-zero status. Aborting."
|
101
|
+
exit 1
|
102
|
+
end
|
103
|
+
tempfile.open
|
104
|
+
content = tempfile.read
|
105
|
+
tempfile.close
|
106
|
+
tempfile.delete
|
107
|
+
end
|
108
|
+
|
109
|
+
data = {}
|
110
|
+
if content =~ /(.*?\n?)^(---\s*$\n?)/m
|
111
|
+
# Combined YAML front matter with text content.
|
112
|
+
begin
|
113
|
+
data = YAML.load($1) || {}
|
114
|
+
data['body'] = $POSTMATCH if $POSTMATCH and not $POSTMATCH.empty?
|
115
|
+
rescue => e
|
116
|
+
puts "Exception reading YAML front matter. #{e.inspect}"
|
117
|
+
exit 1
|
118
|
+
end
|
119
|
+
else
|
120
|
+
begin
|
121
|
+
# YAML only content.
|
122
|
+
data = YAML.load(content)
|
123
|
+
if data.instance_of? String
|
124
|
+
# Text only content.
|
125
|
+
data = { 'body' => data }
|
126
|
+
end
|
127
|
+
rescue => e
|
128
|
+
data = {}
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
if not data or data.empty?
|
133
|
+
puts "No content for case. Aborting."
|
134
|
+
exit 1
|
135
|
+
end
|
136
|
+
|
137
|
+
response = Typhoeus::Request.get(api_url,
|
138
|
+
:verbose => options[:verbose],
|
139
|
+
:params => {
|
140
|
+
:cmd => 'new',
|
141
|
+
:token => api_token,
|
142
|
+
:sTitle => data['title'],
|
143
|
+
:ixBugParent => data['parent'],
|
144
|
+
:sTags => data['tags'] ? data['tags'].join(',') : nil,
|
145
|
+
:sProject => data['project'],
|
146
|
+
:sArea => data['area'],
|
147
|
+
:sFixFor => data['milestone'],
|
148
|
+
:sCategory => data['category'],
|
149
|
+
:sPersonAssignedTo => data['assignee'],
|
150
|
+
:sPriority => data['priority'],
|
151
|
+
:hrsCurrEst => data['estimate'],
|
152
|
+
:sEvent => data['body'] })
|
153
|
+
if response.code != 200
|
154
|
+
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
155
|
+
exit 1
|
156
|
+
end
|
157
|
+
|
158
|
+
result = XML::Parser.string(response.body).parse
|
159
|
+
error = result.find_first('/response/error')
|
160
|
+
if error
|
161
|
+
puts "Failed with error: #{error.content}."
|
162
|
+
exit 1
|
163
|
+
end
|
164
|
+
|
165
|
+
puts "Case #{result.find_first('/response/case')['ixBug']} created."
|