fogbugz 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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."
|