fogbugz 1.0.3 → 1.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/fogbugz +24 -76
- data/bin/fogbugz-areas +3 -49
- data/bin/fogbugz-assign +3 -54
- data/bin/fogbugz-categories +4 -50
- data/bin/fogbugz-close +1 -1
- data/bin/fogbugz-edit +46 -285
- data/bin/fogbugz-filter +2 -1
- data/bin/fogbugz-filters +6 -60
- data/bin/fogbugz-list +39 -42
- data/bin/fogbugz-login +3 -34
- data/bin/fogbugz-logoff +3 -47
- data/bin/fogbugz-milestones +6 -52
- data/bin/fogbugz-open +39 -0
- data/bin/fogbugz-people +5 -51
- data/bin/fogbugz-priorities +4 -51
- data/bin/fogbugz-projects +5 -51
- data/bin/fogbugz-reactivate +2 -1
- data/bin/fogbugz-reopen +2 -1
- data/bin/fogbugz-resolve +5 -72
- data/bin/fogbugz-show +22 -138
- data/bin/fogbugz-start +3 -52
- data/bin/fogbugz-statuses +5 -38
- data/bin/fogbugz-stop +3 -47
- data/lib/fogbugz/common.rb +370 -0
- metadata +19 -7
- data/bin/fogbugz-new +0 -175
- data/lib/dummy.rb +0 -1
data/bin/fogbugz
CHANGED
@@ -1,78 +1,26 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'fogbugz/common'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
reactivate Reactivate a resolved case.
|
27
|
-
reopen Reopen a closed case.
|
28
|
-
resolve Resolve a case.
|
29
|
-
show Show details on a case.
|
30
|
-
start Start working on a case.
|
31
|
-
statuses List available statuses.
|
32
|
-
stop Stop working on a case.
|
33
|
-
|
34
|
-
See '#{basename} help <commands>' for more information on a \
|
35
|
-
specific command.
|
36
|
-
HERE
|
37
|
-
|
38
|
-
if ARGV.length == 0
|
39
|
-
puts usage
|
40
|
-
exit 1
|
41
|
-
end
|
42
|
-
|
43
|
-
case ARGV[0]
|
44
|
-
when 'help'
|
45
|
-
if ARGV.length == 1
|
46
|
-
puts usage
|
47
|
-
exit 1
|
48
|
-
else
|
49
|
-
case ARGV[1]
|
50
|
-
when 'areas', 'assign', 'categories', 'close', 'edit', 'filter', 'filters',
|
51
|
-
'list', 'login', 'logoff', 'milestones', 'new', 'people', 'priorities',
|
52
|
-
'projects', 'reactivate', 'reopen', 'resolve', 'show', 'start',
|
53
|
-
'statuses', 'stop'
|
54
|
-
subcommand = ARGV[1]
|
55
|
-
ARGV.clear
|
56
|
-
ARGV.push '--help'
|
57
|
-
load "#{absolute}-#{subcommand}"
|
58
|
-
exit 0
|
59
|
-
else
|
60
|
-
puts usage
|
61
|
-
exit 1
|
62
|
-
end
|
63
|
-
end
|
64
|
-
when 'areas', 'assign', 'categories', 'close', 'edit', 'filter', 'filters',
|
65
|
-
'list', 'login', 'logoff', 'milestones', 'new', 'people', 'priorities',
|
66
|
-
'projects', 'reactivate', 'reopen', 'resolve', 'show', 'start',
|
67
|
-
'statuses', 'stop'
|
68
|
-
load "#{absolute}-#{ARGV.shift}"
|
69
|
-
exit 0
|
70
|
-
else
|
71
|
-
if ARGV[0].to_i.to_s == ARGV[0]
|
72
|
-
load "#{absolute}-show"
|
73
|
-
exit 0
|
74
|
-
else
|
75
|
-
puts usage
|
76
|
-
exit 1
|
77
|
-
end
|
78
|
-
end
|
4
|
+
dispatch_subcommand __FILE__,
|
5
|
+
:areas => 'List active areas.',
|
6
|
+
:assign => 'Assign a case.',
|
7
|
+
:categories => 'List available categories.',
|
8
|
+
:close => 'Close a resolved case.',
|
9
|
+
:edit => 'Edit an existing case.',
|
10
|
+
:filter => 'Set the current default filter.',
|
11
|
+
:filters => 'List available filters.',
|
12
|
+
:list => 'List cases by the current filter or a search query.',
|
13
|
+
:login => 'Create an API token.',
|
14
|
+
:logoff => 'Invalidate an API token.',
|
15
|
+
:milestones => 'List active milestones.',
|
16
|
+
:open => 'Open a new case.',
|
17
|
+
:people => 'List active users.',
|
18
|
+
:priorities => 'List available priorities.',
|
19
|
+
:projects => 'List active projects.',
|
20
|
+
:reactivate => 'Reactivate a resolved case.',
|
21
|
+
:reopen => 'Reopen a closed case.',
|
22
|
+
:resolve => 'Resolve a case.',
|
23
|
+
:show => 'Show details on a case.',
|
24
|
+
:start => 'Start working on a case.',
|
25
|
+
:statuses => 'List available statuses.',
|
26
|
+
:stop => 'Stop working on a case.'
|
data/bin/fogbugz-areas
CHANGED
@@ -1,54 +1,8 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'fogbugz/common'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
require 'uri'
|
6
|
-
require 'rexml/document'
|
7
|
-
require 'optparse'
|
8
|
-
|
9
|
-
api_url = ENV['FOGBUGZ_API_URL']
|
10
|
-
unless api_url
|
11
|
-
puts "Environment variable FOGBUGZ_API_URL must be set."
|
12
|
-
exit 1
|
13
|
-
end
|
14
|
-
|
15
|
-
api_token = ENV['FOGBUGZ_API_TOKEN']
|
16
|
-
unless api_token
|
17
|
-
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
18
|
-
exit 1
|
19
|
-
end
|
20
|
-
|
21
|
-
options = {}
|
22
|
-
optparse = OptionParser.new do |opts|
|
23
|
-
opts.banner = "usage: #{File::basename(__FILE__)} [options]"
|
24
|
-
|
25
|
-
opts.on_tail('-h', '--help') do
|
26
|
-
puts optparse.help
|
27
|
-
exit 1
|
28
|
-
end
|
29
|
-
end
|
30
|
-
optparse.parse!
|
31
|
-
|
32
|
-
uri = URI format("#{api_url}?cmd=listAreas&token=%s", URI.escape(api_token))
|
33
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
34
|
-
if uri.scheme == 'https'
|
35
|
-
http.use_ssl = true
|
36
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
37
|
-
end
|
38
|
-
response = http.start { |h| h.request Net::HTTP::Get.new(uri.request_uri) }
|
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 = REXML::Document.new(response.body)
|
45
|
-
error = result.elements['/response/error']
|
46
|
-
if error
|
47
|
-
puts "Failed with error: #{error.text}."
|
48
|
-
exit 1
|
49
|
-
end
|
50
|
-
|
51
|
-
result.elements.each('/response/areas/area') do |area|
|
4
|
+
parse_opts "usage: #{File::basename(__FILE__)} [options]", 0
|
5
|
+
do_api('listAreas').elements.each('/response/areas/area') do |area|
|
52
6
|
puts format("%-20.20s %-20.20s %s\n",
|
53
7
|
area.elements['sPersonOwner'].text,
|
54
8
|
area.elements['sProject'].text,
|
data/bin/fogbugz-assign
CHANGED
@@ -1,56 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'fogbugz/common'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
require 'uri'
|
6
|
-
require 'rexml/document'
|
7
|
-
require 'optparse'
|
8
|
-
|
9
|
-
api_url = ENV['FOGBUGZ_API_URL']
|
10
|
-
unless api_url
|
11
|
-
puts "Environment variable FOGBUGZ_API_URL must be set."
|
12
|
-
exit 1
|
13
|
-
end
|
14
|
-
|
15
|
-
api_token = ENV['FOGBUGZ_API_TOKEN']
|
16
|
-
unless api_token
|
17
|
-
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
18
|
-
exit 1
|
19
|
-
end
|
20
|
-
|
21
|
-
options = {}
|
22
|
-
optparse = OptionParser.new do |opts|
|
23
|
-
opts.banner = "usage: #{File::basename(__FILE__)} [options] <case> <assignee>"
|
24
|
-
|
25
|
-
opts.on_tail('-h', '--help') do
|
26
|
-
puts optparse.help
|
27
|
-
exit 1
|
28
|
-
end
|
29
|
-
end
|
30
|
-
optparse.parse!
|
31
|
-
|
32
|
-
unless ARGV.length == 2
|
33
|
-
puts optparse.help
|
34
|
-
exit 1
|
35
|
-
end
|
36
|
-
|
37
|
-
uri = URI format("#{api_url}?cmd=assign&token=%s&ixBug=%s&sPersonAssignedTo=%s",
|
38
|
-
URI.escape(api_token), URI.escape(ARGV[0]),
|
39
|
-
URI.escape(ARGV[1]))
|
40
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
41
|
-
if uri.scheme == 'https'
|
42
|
-
http.use_ssl = true
|
43
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
44
|
-
end
|
45
|
-
response = http.start { |h| h.request Net::HTTP::Get.new(uri.request_uri) }
|
46
|
-
if response.code != '200'
|
47
|
-
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
48
|
-
exit 1
|
49
|
-
end
|
50
|
-
|
51
|
-
result = REXML::Document.new(response.body)
|
52
|
-
error = result.elements['/response/error']
|
53
|
-
if error
|
54
|
-
puts "Failed with error: #{error.text}."
|
55
|
-
exit 1
|
56
|
-
end
|
4
|
+
parse_opts "usage: #{File::basename(__FILE__)} [options] <case> <assignee>", 2
|
5
|
+
do_api('assign', :ixBug => ARGV[0], :sPersonAssignedTo => ARGV[1])
|
data/bin/fogbugz-categories
CHANGED
@@ -1,53 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'fogbugz/common'
|
2
3
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
require 'rexml/document'
|
7
|
-
require 'optparse'
|
8
|
-
|
9
|
-
api_url = ENV['FOGBUGZ_API_URL']
|
10
|
-
unless api_url
|
11
|
-
puts "Environment variable FOGBUGZ_API_URL must be set."
|
12
|
-
exit 1
|
13
|
-
end
|
14
|
-
|
15
|
-
api_token = ENV['FOGBUGZ_API_TOKEN']
|
16
|
-
unless api_token
|
17
|
-
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
18
|
-
exit 1
|
19
|
-
end
|
20
|
-
|
21
|
-
options = {}
|
22
|
-
optparse = OptionParser.new do |opts|
|
23
|
-
opts.banner = "usage: #{File::basename(__FILE__)} [options]"
|
24
|
-
|
25
|
-
opts.on_tail('-h', '--help') do
|
26
|
-
puts optparse.help
|
27
|
-
exit 1
|
28
|
-
end
|
29
|
-
end
|
30
|
-
optparse.parse!
|
31
|
-
|
32
|
-
uri = URI format("#{api_url}?cmd=listCategories&token=%s", URI.escape(api_token))
|
33
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
34
|
-
if uri.scheme == 'https'
|
35
|
-
http.use_ssl = true
|
36
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
37
|
-
end
|
38
|
-
response = http.start { |h| h.request Net::HTTP::Get.new(uri.request_uri) }
|
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 = REXML::Document.new(response.body)
|
45
|
-
error = result.elements['/response/error']
|
46
|
-
if error
|
47
|
-
puts "Failed with error: #{error.text}."
|
48
|
-
exit 1
|
49
|
-
end
|
50
|
-
|
51
|
-
result.elements.each('/response/categories/category') do |category|
|
52
|
-
puts category.elements['sCategory'].text
|
4
|
+
parse_opts "usage: #{File::basename(__FILE__)} [options]", 0
|
5
|
+
do_api('listCategories').elements.each('/response/categories/category') do |c|
|
6
|
+
puts c.elements['sCategory'].text
|
53
7
|
end
|
data/bin/fogbugz-close
CHANGED
data/bin/fogbugz-edit
CHANGED
@@ -1,293 +1,54 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
+
require 'fogbugz/common'
|
2
3
|
|
3
|
-
|
4
|
-
require 'net/https'
|
5
|
-
require 'uri'
|
6
|
-
require 'rexml/document'
|
7
|
-
require 'tempfile'
|
8
|
-
require 'optparse'
|
9
|
-
require 'yaml'
|
10
|
-
require 'English'
|
11
|
-
require 'time'
|
4
|
+
options = parse_stdin_opts "usage: #{File::basename(__FILE__)} [options] <case> [-]", 1
|
12
5
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
exit 1
|
17
|
-
end
|
18
|
-
|
19
|
-
api_token = ENV['FOGBUGZ_API_TOKEN']
|
20
|
-
unless api_token
|
21
|
-
puts "Environment variable FOGBUGZ_API_TOKEN must be set."
|
22
|
-
exit 1
|
23
|
-
end
|
24
|
-
|
25
|
-
editor = ENV['EDITOR'] || 'vim'
|
26
|
-
|
27
|
-
options = {}
|
28
|
-
optparse = OptionParser.new do |opts|
|
29
|
-
opts.banner = "usage: #{File::basename(__FILE__)} [options] <case>"
|
30
|
-
|
31
|
-
opts.on_tail('-h', '--help') do
|
32
|
-
puts optparse.help
|
33
|
-
exit 1
|
34
|
-
end
|
35
|
-
|
36
|
-
options[:file] = nil
|
37
|
-
opts.on('-f', '--file=<file>',
|
38
|
-
'Take the case content from the given file. Use - to read from STDIN.') do |file|
|
39
|
-
options[:file] = file
|
40
|
-
end
|
41
|
-
|
42
|
-
options[:template] = nil
|
43
|
-
opts.on('-t', '--template=<template>',
|
44
|
-
'Use the file content or - for STDIN as the initial case content.') do |template|
|
45
|
-
options[:template] = template
|
46
|
-
end
|
47
|
-
end
|
48
|
-
optparse.parse!
|
49
|
-
|
50
|
-
unless ARGV.length == 1
|
51
|
-
puts optparse.help
|
52
|
-
exit 1
|
53
|
-
end
|
54
|
-
case_id = ARGV[0]
|
55
|
-
|
56
|
-
uri = URI format("#{api_url}?cmd=search&token=%s&cols=%s&q=%s&max=1",
|
57
|
-
URI.escape(api_token), URI.escape('ixBug,ixBugParent,tags,sTitle,sProject,sArea,sFixFor,sCategory,sPersonAssignedTo,sPriority,hrsCurrEst,events'),
|
58
|
-
URI.escape(case_id))
|
59
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
60
|
-
if uri.scheme == 'https'
|
61
|
-
http.use_ssl = true
|
62
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
63
|
-
end
|
64
|
-
response = http.start { |h| h.request Net::HTTP::Get.new(uri.request_uri) }
|
65
|
-
if response.code != '200'
|
66
|
-
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
67
|
-
exit 1
|
68
|
-
end
|
69
|
-
|
70
|
-
result = REXML::Document.new(response.body)
|
71
|
-
error = result.elements['/response/error']
|
72
|
-
if error
|
73
|
-
puts "Failed with error: #{error.text}."
|
74
|
-
exit 1
|
75
|
-
end
|
76
|
-
|
77
|
-
bug = result.elements["/response/cases/case[@ixBug='#{case_id}']"]
|
6
|
+
result = do_api('search', :max => 1, :q => ARGV[0],
|
7
|
+
:cols => 'ixBug,ixBugParent,tags,sTitle,sProject,sArea,sFixFor,sCategory,sPersonAssignedTo,sPriority,hrsCurrEst,dtDue,events')
|
8
|
+
bug = result.elements["/response/cases/case[@ixBug='#{ARGV[0]}']"]
|
78
9
|
unless bug
|
79
|
-
puts "Case #{
|
80
|
-
exit 1
|
81
|
-
end
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
template
|
99
|
-
|
100
|
-
template
|
101
|
-
template << <<HERE
|
102
|
-
# Fill in metadata for the case.
|
103
|
-
HERE
|
104
|
-
|
105
|
-
sTitle = bug.elements['sTitle']
|
106
|
-
if sTitle and sTitle.text and not sTitle.text.empty?
|
107
|
-
template << "# title: #{sTitle.text}\n"
|
108
|
-
else
|
109
|
-
template << "# title: <title>\n"
|
110
|
-
end
|
111
|
-
|
112
|
-
sPersonAssignedTo = bug.elements['sPersonAssignedTo']
|
113
|
-
if sPersonAssignedTo and sPersonAssignedTo.text and
|
114
|
-
not sPersonAssignedTo.text.empty?
|
115
|
-
template << "# assignee: #{sPersonAssignedTo.text}\n"
|
116
|
-
else
|
117
|
-
template << "# assignee: <person>\n"
|
118
|
-
end
|
119
|
-
|
120
|
-
ixBugParent = bug.elements['ixBugParent']
|
121
|
-
if ixBugParent and ixBugParent.text and not ixBugParent.text.empty? and
|
122
|
-
ixBugParent.text != '0'
|
123
|
-
template << "# parent: #{ixBugParent.text}\n"
|
124
|
-
else
|
125
|
-
template << "# parent: <case>\n"
|
126
|
-
end
|
127
|
-
|
128
|
-
tags = bug.elements.collect('tags/tag') { |tag| tag.text }
|
129
|
-
if tags and not tags.empty?
|
130
|
-
template << "# tags: [#{tags.join(', ')}]\n"
|
131
|
-
else
|
132
|
-
template << "# tags: [bug, enhancement]\n"
|
133
|
-
end
|
134
|
-
|
135
|
-
sProject = bug.elements['sProject']
|
136
|
-
if sProject and sProject.text and not sProject.text.empty?
|
137
|
-
template << "# project: #{sProject.text}\n"
|
138
|
-
else
|
139
|
-
template << "# project: <project>\n"
|
140
|
-
end
|
141
|
-
|
142
|
-
sArea = bug.elements['sArea']
|
143
|
-
if sArea and sArea.text and not sArea.text.empty?
|
144
|
-
template << "# area: #{sArea.text}\n"
|
145
|
-
else
|
146
|
-
template << "# area: <area>\n"
|
147
|
-
end
|
148
|
-
|
149
|
-
sFixFor = bug.elements['sFixFor']
|
150
|
-
if sFixFor and sFixFor.text and not sFixFor.text.empty?
|
151
|
-
template << "# milestone: #{sFixFor.text}\n"
|
152
|
-
else
|
153
|
-
template << "# milestone: <milestone>"
|
154
|
-
end
|
155
|
-
|
156
|
-
sCategory = bug.elements['sCategory']
|
157
|
-
if sCategory and sCategory.text and not sCategory.text.empty?
|
158
|
-
template << "# category: #{sCategory.text}\n"
|
159
|
-
else
|
160
|
-
template << "# category: <category>"
|
161
|
-
end
|
162
|
-
|
163
|
-
sPriority = bug.elements['sPriority']
|
164
|
-
if sPriority and sPriority.text and not sPriority.text.empty?
|
165
|
-
template << "# priority: #{sPriority.text}\n"
|
166
|
-
else
|
167
|
-
template << "# priority: <priority>"
|
168
|
-
end
|
169
|
-
|
170
|
-
hrsCurrEst = bug.elements['hrsCurrEst']
|
171
|
-
if hrsCurrEst and hrsCurrEst.text and not hrsCurrEst.text.empty? and
|
172
|
-
hrsCurrEst.text != '0'
|
173
|
-
template << "# estimate: #{hrsCurrEst.text}\n"
|
174
|
-
else
|
175
|
-
template << "# estimate: <estimate>\n"
|
176
|
-
end
|
177
|
-
|
10
|
+
puts "Case #{ARGV[0]} does not exist."
|
11
|
+
exit 1
|
12
|
+
end
|
13
|
+
|
14
|
+
template = "# Fill in metadata for the case.\n"
|
15
|
+
template << maybe_append('title', bug.elements['sTitle'])
|
16
|
+
template << maybe_append('assignee', bug.elements['sPersonAssignedTo'])
|
17
|
+
template << maybe_append('parent', bug.elements['ixBugParent'])
|
18
|
+
template << maybe_array('tags', bug.elements.collect('tags/tag') { |t| t.text })
|
19
|
+
template << maybe_append('project', bug.elements['sProject'])
|
20
|
+
template << maybe_append('area', bug.elements['sArea'])
|
21
|
+
template << maybe_append('milestone', bug.elements['sFixFor'])
|
22
|
+
template << maybe_append('category', bug.elements['sCategory'])
|
23
|
+
template << maybe_append('priority', bug.elements['sPriority'])
|
24
|
+
template << maybe_time('due', bug.elements['dtDue'])
|
25
|
+
template << maybe_append('estimate', bug.elements['hrsCurrEst'])
|
26
|
+
|
27
|
+
template << "\n"
|
28
|
+
bug.elements.each('events/event') do |event|
|
29
|
+
template << maybe_event(event.elements['evtDescription'], event.elements['dt'])
|
30
|
+
template << maybe_literal(event.elements['sChanges'])
|
31
|
+
template << maybe_literal(event.elements['s'])
|
178
32
|
template << "\n"
|
179
|
-
|
180
|
-
|
181
|
-
if evtDescription and evtDescription.text and
|
182
|
-
not evtDescription.text.empty?
|
183
|
-
time = Time.parse(event.elements['dt'].text).localtime
|
184
|
-
template << format("# %s at %s on %s.\n", evtDescription.text,
|
185
|
-
time.strftime('%-l:%M %p'),
|
186
|
-
time.strftime('%A, %B %e %Y'))
|
187
|
-
end
|
188
|
-
|
189
|
-
sChanges = event.elements['sChanges']
|
190
|
-
if sChanges and sChanges.text and not sChanges.text.empty?
|
191
|
-
commented = sChanges.text.gsub(/\n/, "\n# ")
|
192
|
-
template << "# #{commented}\n"
|
193
|
-
end
|
194
|
-
|
195
|
-
summary = event.elements['s']
|
196
|
-
if summary and summary.text and not summary.text.empty?
|
197
|
-
commented = summary.text.gsub(/\n/, "\n# ")
|
198
|
-
template << "# #{commented}\n"
|
199
|
-
end
|
200
|
-
template << "\n"
|
201
|
-
end
|
202
|
-
template << <<HERE
|
33
|
+
end
|
34
|
+
template << <<HERE
|
203
35
|
# Enter an additional note for the case after the dashes.
|
204
36
|
---
|
205
37
|
HERE
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
if
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
data = {}
|
225
|
-
if content =~ /(.*?\n?)^(---\s*$\n?)/m
|
226
|
-
# Combined YAML front matter with text content.
|
227
|
-
begin
|
228
|
-
data = YAML.load($1) || {}
|
229
|
-
data['body'] = $POSTMATCH if $POSTMATCH and not $POSTMATCH.empty?
|
230
|
-
rescue => e
|
231
|
-
puts "Exception reading YAML front matter. #{e.inspect}"
|
232
|
-
exit 1
|
233
|
-
end
|
234
|
-
else
|
235
|
-
begin
|
236
|
-
# YAML only content.
|
237
|
-
data = YAML.load(content)
|
238
|
-
was_yaml = true if data and not data.empty?
|
239
|
-
if data.instance_of? String
|
240
|
-
# Text only content.
|
241
|
-
data = { 'body' => data }
|
242
|
-
end
|
243
|
-
rescue => e
|
244
|
-
data = {}
|
245
|
-
end
|
246
|
-
end
|
247
|
-
|
248
|
-
if not data or data.empty?
|
249
|
-
puts "No changes to case. Aborting."
|
250
|
-
exit 1
|
251
|
-
end
|
252
|
-
|
253
|
-
sTitle = data['title'] ? "&sTitle=#{URI.escape(data['title'].to_s)}" : ''
|
254
|
-
ixBugParent = (data['parent'] ?
|
255
|
-
"&ixBugParent=#{URI.escape(data['parent'].to_s)}" : '')
|
256
|
-
sTags = data['tags'] ? "&sTags=#{URI.escape(data['tags'].join(','))}" : ''
|
257
|
-
sProject = (data['project'] ?
|
258
|
-
"&sProject=#{URI.escape(data['project'].to_s)}" : '')
|
259
|
-
sArea = data['area'] ? "&sArea=#{URI.escape(data['area'].to_s)}" : ''
|
260
|
-
sFixFor = (data['milestone'] ?
|
261
|
-
"&sFixFor=#{URI.escape(data['milestone'].to_s)}" : '')
|
262
|
-
sCategory = (data['category'] ?
|
263
|
-
"&sCategory=#{URI.escape(data['category'].to_s)}" : '')
|
264
|
-
sPersonAssignedTo = (data['assignee'] ?
|
265
|
-
"&sPersonAssignedTo=#{URI.escape(data['assignee'].to_s)}" :
|
266
|
-
'')
|
267
|
-
sPriority = (data['priority'] ?
|
268
|
-
"&sPriority=#{URI.escape(data['priority'].to_s)}" : '')
|
269
|
-
hrsCurrEst = (data['estimate'] ?
|
270
|
-
"&hrsCurrEst=#{URI.escape(data['estimate'].to_s)}" : '')
|
271
|
-
sEvent = data['body'] ? "&sEvent=#{URI.escape(data['body'].to_s)}" : ''
|
272
|
-
|
273
|
-
uri = URI format("#{api_url}?cmd=edit&token=%s&ixBug=%s%s%s%s%s%s%s%s%s%s%s%s",
|
274
|
-
URI.escape(api_token), URI.escape(case_id),
|
275
|
-
sTitle, ixBugParent, sTags, sProject, sArea, sFixFor, sCategory,
|
276
|
-
sPersonAssignedTo, sPriority, hrsCurrEst, sEvent)
|
277
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
278
|
-
if uri.scheme == 'https'
|
279
|
-
http.use_ssl = true
|
280
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
281
|
-
end
|
282
|
-
response = http.start { |h| h.request Net::HTTP::Get.new(uri.request_uri) }
|
283
|
-
if response.code != '200'
|
284
|
-
puts "HTTP request to #{api_url} failed with code #{response.code}."
|
285
|
-
exit 1
|
286
|
-
end
|
287
|
-
|
288
|
-
result = REXML::Document.new(response.body)
|
289
|
-
error = result.elements['/response/error']
|
290
|
-
if error
|
291
|
-
puts "Failed with error: #{error.text}."
|
292
|
-
exit 1
|
293
|
-
end
|
38
|
+
data = get_editor_content options, template
|
39
|
+
|
40
|
+
params = { :ixBug => ARGV[0] }
|
41
|
+
params[:sTitle] = data['title'] if data['title']
|
42
|
+
params[:ixBugParent] = data['parent'] if data['parent']
|
43
|
+
params[:sTags] = data['tags'].join(',') if data['tags']
|
44
|
+
params[:sProject] = data['project'] if data['project']
|
45
|
+
params[:sArea] = data['area'] if data['area']
|
46
|
+
params[:sFixFor] = data['milestone'] if data['milestone']
|
47
|
+
params[:sCategory] = data['category'] if data['category']
|
48
|
+
params[:sPersonAssignedTo] = data['assignee'] if data['assignee']
|
49
|
+
params[:sPriority] = data['priority'] if data['priority']
|
50
|
+
params[:dtDue] = parse_time(data['due']) if parse_time(data['due'])
|
51
|
+
params[:hrsCurrEst] = data['estimate'] if data['estimate']
|
52
|
+
params[:sEvent] = data['body'] if data['body']
|
53
|
+
|
54
|
+
do_api('edit', params)
|