jiraMule 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,243 @@
1
+ require 'terminal-table'
2
+ require 'mustache'
3
+ require 'yaml'
4
+ require 'JiraMule/jiraUtils'
5
+
6
+ command :kanban do |c|
7
+ extra_columns = []
8
+ c.syntax = 'jm query [options] kanban'
9
+ c.summary = 'Show a kanban table'
10
+ c.description = %{
11
+ Display issues grouped by a query. Each group is a column in a table or a section in a list.
12
+
13
+ Original intent was to build kanban tables, hence the name. However, the output is quite
14
+ configurable can can be used for many other styles.
15
+
16
+ Use the --dump option to see how things have been styled.
17
+
18
+ Formatting is done with Mustash.
19
+ }
20
+ c.example 'Show a kanban table', 'jm kanban'
21
+ c.example 'Show a status list', 'jm status'
22
+ c.example 'Another way to show a status list', 'jm --style status'
23
+ c.example 'Show a list to use with Taskpaper', 'jm --style taskpaper'
24
+ c.example 'Show status list, with differnt styling', %{jm --style status --header '# {{column}}' --item '** {{key}} {{summary}}'}
25
+ c.example 'Showoff', %{jm kanban --style empty --heading '<h1>{{column}}</h1>' \\
26
+ --column 'Working=status="In Progress"' \\
27
+ --column 'Done=status="Pending Release"' \\
28
+ --fields key,summary,assignee \\
29
+ --item '<h2>{{key}}</h2><b>Who:{{assignee.name}}</b><p>{{summary}}</p>'}
30
+
31
+ c.option '--[no-]raw', 'Do not prefix queries with project and assignee'
32
+ c.option '-w', '--width WIDTH', Integer, 'Width of the terminal'
33
+ c.option '-s', '--style STYLE', String, 'Which style to use'
34
+ c.option '--heading STYLE', String, 'Format for heading'
35
+ c.option '--item STYLE', String, 'Format for items'
36
+ c.option('-c', '--column NAME=QUERY', '') {|ec| extra_columns << ec}
37
+ c.option '-f', '--fields FIELDS', Array, 'Which fields to return'
38
+ c.option '-d', '--dump', 'Dump the style to STDOUT as yaml'
39
+ c.option '--file FILE', String, %{Style definition file to load}
40
+
41
+ c.action do |args, options|
42
+ options.default :width=>HighLine::SystemExtensions.terminal_size[0],
43
+ :style => 'kanban'
44
+
45
+ # Table of Styles. Appendable via config file. ??and command line??
46
+ allOfThem = {
47
+ :empty => {
48
+ :fields => [:key, :summary],
49
+ :format => {
50
+ :heading => "{{column}}",
51
+ :item => "{{key}} {{summary}}",
52
+ },
53
+ :columns => {}
54
+ },
55
+ :status => {
56
+ :fields => [:key, :summary],
57
+ :format => {
58
+ :heading => "#### {{column}}",
59
+ :item => "- {{key}} {{summary}}",
60
+ :order => [:Done, :Testing, :InProgress, :Todo],
61
+ },
62
+ :columns => {
63
+ :Done => [%{status = 'Pending Release'}],
64
+ :Testing => [%{status = Testing}],
65
+ :InProgress => [%{status = "In Progress"}],
66
+ :Todo => [%{(status = Open OR},
67
+ %{status = Reopened OR},
68
+ %{status = "On Deck" OR},
69
+ %{status = "Waiting Estimation Approval" OR},
70
+ %{status = "Reopened" OR},
71
+ %{status = "Testing (Signoff)" OR},
72
+ %{status = "Testing (Review)" OR},
73
+ %{status = "Testing - Bug Found")}],
74
+ },
75
+
76
+ },
77
+ :kanban => {
78
+ :fields => [:key, :summary],
79
+ :format => {
80
+ :heading => "{{column}}",
81
+ :item => "{{key}}\n {{summary}}",
82
+ :order => [:Todo, :InProgress, :Done],
83
+ :usetable => true
84
+ },
85
+ :columns => {
86
+ :Done => [%{(status = Released OR status = "Not Needed - Closed")}],
87
+ :InProgress => [%{(status = "In Progress" OR},
88
+ %{status = "In Dev" OR},
89
+ %{status = "Pending Release" OR},
90
+ %{status = "In QA" OR},
91
+ %{status = "Integration QA" OR},
92
+ %{status = "In Design")},
93
+ ],
94
+ :Todo => [%{(status = Open OR},
95
+ %{status = Reopened OR},
96
+ %{status = "On Deck" OR},
97
+ %{status = "Waiting Estimation Approval" OR},
98
+ %{status = "Reopened" OR},
99
+ %{status = "Testing (Signoff)" OR},
100
+ %{status = "Testing (Review)" OR},
101
+ %{status = "Testing - Bug Found" OR},
102
+ %{status = "Backlog" OR},
103
+ %{status = "Ready For Dev" OR},
104
+ %{status = "Ready For QA" OR},
105
+ %{status = "To Do" OR},
106
+ %{status = "Release Package")},
107
+ ],
108
+ },
109
+ },
110
+ :taskpaper => {
111
+ :fields => [:key, :summary, :duedate],
112
+ :format => {
113
+ :heading => "{{column}}:",
114
+ :item => "- {{summary}} @jira({{key}}) {{#duedate}}@due({{duedate}}){{/duedate}}",
115
+ },
116
+ :columns => {
117
+ :InProgress => %{status = "In Progress"},
118
+ :Todo => [%{(status = Open OR},
119
+ %{status = "Testing - Bug Found")}],
120
+ }
121
+ },
122
+ }
123
+ # TODO: Load styles from project dir
124
+
125
+ if options.file.nil? then
126
+ theStyle = allOfThem[options.style.to_sym]
127
+ else
128
+ theStyle = allOfThem[:empty]
129
+ File.open(options.file) {|io|
130
+ theStyle = YAML.load(io)
131
+ # make sure the required keys are symbols.
132
+ %w{fields format columns}.each do |key|
133
+ if theStyle.has_key? key then
134
+ theStyle[key.to_sym] = theStyle[key]
135
+ theStyle.delete(key)
136
+ end
137
+ end
138
+ %w{heading item}.each do |key|
139
+ if theStyle[:format].has_key? key then
140
+ theStyle[:format][key.to_sym] = theStyle[:format][key]
141
+ theStyle[:format].delete(key)
142
+ end
143
+ end
144
+ }
145
+ end
146
+
147
+ #### look for command line overrides
148
+ extra_columns.each do |cm|
149
+ name, query = cm.split(/=/, 2)
150
+ theStyle[:columns][name.to_sym] = [query]
151
+ end
152
+
153
+ theStyle[:fields] = options.fields if options.fields
154
+ theStyle[:format][:heading] = options.heading if options.heading
155
+ theStyle[:format][:item] = options.item if options.item
156
+
157
+
158
+ # All loading and computing of the style is complete, now fetch and print
159
+
160
+ if options.dump then
161
+ puts theStyle.to_yaml
162
+ else
163
+
164
+ ### Fetch the issues for each column
165
+ columns = theStyle[:columns]
166
+
167
+ jira = JiraMule::JiraUtils.new(args, options)
168
+
169
+ #### Fetch these fields
170
+ fields = theStyle[:fields]
171
+
172
+ #### Now fetch
173
+ qBase = []
174
+ qBase.unshift("assignee = #{jira.username} AND") unless options.raw
175
+ qBase.unshift("project = #{jira.project} AND") unless options.raw
176
+ qBase.unshift('(' + args.join(' ') + ') AND') unless args.empty?
177
+
178
+ results = {}
179
+ columns.each_pair do |name, query|
180
+ query = [query] unless query.is_a? Array
181
+ q = qBase + query + [%{ORDER BY Rank}]
182
+ issues = jira.getIssues(q.join(' '), fields)
183
+ results[name] = issues
184
+ end
185
+
186
+ ### Now format the output
187
+ format = theStyle[:format]
188
+
189
+ #### Setup ordering
190
+ format[:order] = columns.keys.sort unless format.has_key? :order
191
+
192
+ #### setup column widths
193
+ cW = options.width.to_i
194
+ cW = -1 if cW == 0
195
+ cWR = cW
196
+ if format[:usetable] and cW > 0 then
197
+ borders = 4 + (columns.count * 3); # 2 on left, 2 on right, 3 for each internal
198
+ cW = (cW - borders) / columns.count
199
+ cWR = cW + ((cW - borders) % columns.count)
200
+ end
201
+
202
+ #### Format Items
203
+ formatted={}
204
+ results.each_pair do |name, issues|
205
+ formatted[name] = issues.map do |issue|
206
+ line = Mustache.render(format[:item], issue.merge(issue[:fields]))
207
+ #### Trim length?
208
+ if format[:order].last == name
209
+ line[0..cWR]
210
+ else
211
+ line[0..cW]
212
+ end
213
+ end
214
+ end
215
+
216
+ #### Print
217
+ if format.has_key?(:usetable) and format[:usetable] then
218
+ # Table type
219
+ #### Pad
220
+ longest = formatted.values.map{|l| l.length}.max
221
+ formatted.each_pair do |name, issues|
222
+ if issues.length <= longest then
223
+ issues.fill(' ', issues.length .. longest)
224
+ end
225
+ end
226
+
227
+ #### Transpose
228
+ rows = format[:order].map{|n| formatted[n]}.transpose
229
+ puts Terminal::Table.new :headings => format[:order], :rows=>rows
230
+
231
+ else
232
+ # List type
233
+ format[:order].each do |columnName|
234
+ puts Mustache.render(format[:heading], :column => columnName.to_s)
235
+ formatted[columnName].each {|issue| puts issue}
236
+ end
237
+ end
238
+ end
239
+ end
240
+ end
241
+ alias_command :status, :kanban, '--style', 'status'
242
+
243
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,39 @@
1
+ require 'chronic_duration'
2
+ require 'date'
3
+ require 'JiraMule/jiraUtils'
4
+
5
+ command :logwork do |c|
6
+ c.syntax = 'jm logwork [options] <key> <time spent...>'
7
+ c.summary = 'Log work spent'
8
+ c.description = %{Log time spent on a issue}
9
+ c.option '-m', '--message MSG', String, 'Message to add to work log'
10
+ c.option '--date DATE', String, 'When this work was done'
11
+ c.example 'Log some work done on an issue', %{jm logwork BUG-42 1h 12m}
12
+
13
+ c.action do |args, options|
14
+ options.default :message => ''
15
+ jira = JiraMule::JiraUtils.new(args, options)
16
+
17
+ key = jira.expandKeys(args).shift
18
+ ts = ChronicDuration.parse(args.join(' '))
19
+
20
+ unless options.date.nil? then
21
+ options.date = DateTime.parse(options.date)
22
+ if options.date.day_fraction.numerator == 0 then
23
+ # No time component. Need to add timezone...
24
+ offset = -(Time.now.gmt_offset/3600)
25
+ options.date += Rational(offset,24)
26
+ end
27
+ end
28
+
29
+ begin
30
+ jira.logWork(key, ts, options.message, options.date)
31
+ rescue JiraUtilsException => e
32
+ pp e.response.body
33
+ end
34
+
35
+ end
36
+ end
37
+ alias_command :lw, :logwork
38
+
39
+ # vim: set et sw=2 ts=2 :
@@ -0,0 +1,89 @@
1
+ require 'vine'
2
+ require 'pp'
3
+ require 'JiraMule/jiraUtils'
4
+
5
+ command :next do |c|
6
+ c.syntax = 'jm next [options] [keys]'
7
+ c.summary = 'Move issue to the next state'
8
+ c.description = %{
9
+ Move to the next state. For states with multiple exits, use the 'preferred' one.
10
+ }
11
+ c.example 'Move BUG-4 into the next state.', %{jm next BUG-4}
12
+ c.option '--[no-]save-next', %{Save transition as preferred}
13
+ c.option '--force-choice', %{Always show menu of transitions (if more than one)}
14
+
15
+ c.action do |args, options|
16
+ jira = JiraMule::JiraUtils.new(args, options)
17
+
18
+ # keys can be with or without the project prefix.
19
+ keys = jira.expandKeys(args)
20
+ jira.printVars(:keys=>keys)
21
+ return if keys.empty?
22
+
23
+ keys.each do |key|
24
+ # First see if there is a single exit. If so, just do that.
25
+ trans = jira.transitionsFor(key)
26
+ if trans.length == 1 then
27
+ id = trans.first[:id]
28
+ jira.verbose "Taking single exit: '#{trans.first[:name]}'"
29
+ jira.transition(key, id)
30
+
31
+ else
32
+ # If more than one:
33
+
34
+ # Need to know the name of the state we are currently in
35
+ #query = "assignee = #{jira.username} AND project = #{jira.project} AND "
36
+ query = "key = #{key}"
37
+ issues = jira.getIssues(query, ["status"])
38
+ raise "Cannot find #{key}" if issues.empty?
39
+ at = issues.first.access('fields.status.name')
40
+
41
+ unless options.force_choice then
42
+ # If a preferred transition is set, use that
43
+ nxt = $cfg["next-preferred.#{at}"]
44
+ unless nxt.nil? then
45
+ direct = trans.select {|item| jira.fuzzyMatchStatus(item, nxt) }
46
+ unless direct.empty? then
47
+ id = direct.first[:id]
48
+ jira.verbose "Taking preferred exit #{key} to #{direct.first['name']} (#{id})"
49
+ jira.transition(key, id)
50
+ exit
51
+ end
52
+ end
53
+
54
+ # Filter ignored transitions; If only one left, goto it.
55
+ skiplist = $cfg['next.ignore'] || []
56
+ check = trans.reject{|t| skiplist.include? t[:name] }
57
+ if check.length == 1 then
58
+ id = check.first[:id]
59
+ jira.verbose "Taking filtered single exit: '#{check.first[:name]}'"
60
+ jira.transition(key, id)
61
+ exit
62
+ end
63
+ end
64
+
65
+ # Otherwise, ask which transition to use.
66
+ # - save that as preferred
67
+ # - goto it.
68
+ choose do |menu|
69
+ menu.prompt = "Follow which transition?"
70
+ trans.each do |tr|
71
+ menu.choice(tr[:name]) do
72
+ if options.save_next then
73
+ $cfg.set("next-preferred.#{at}", tr[:name], :project)
74
+ end
75
+ jira.verbose "Transitioning #{key} to #{tr[:name]} (#{tr[:id]})"
76
+ jira.transition(key, tr[:id])
77
+ end
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+ end #keys.each
84
+ end
85
+ end
86
+
87
+
88
+ # vim: set sw=2 ts=2 :
89
+
@@ -0,0 +1,68 @@
1
+ require 'date'
2
+ require 'terminal-table'
3
+ require 'vine'
4
+ require 'JiraMule/jiraUtils'
5
+
6
+ command :progress do |c|
7
+ c.syntax = 'jm progress [options] [<key>]'
8
+ c.summary = 'Show progress on issues'
9
+ c.description = %{}
10
+ # Show only overdue (today > duedate)
11
+ # Show only unstarted (timespent == 0)
12
+ # Show only Started (timespent > 0)
13
+ c.option '-s', '--status STATUSES', Array, %{Which status to limit to. (default is "In Progress")}
14
+
15
+ c.example 'Show how current project is going', %{jm progress}
16
+ c.example 'Show how work on task 5 is going', %{jm progress 5}
17
+
18
+ c.action do |args, options|
19
+ options.default :status=>[]
20
+
21
+ jira = JiraMule::JiraUtils.new(args, options)
22
+ keys = jira.expandKeys(args)
23
+ if keys.empty? and options.status.empty? then
24
+ options.status << 'In Progress'
25
+ end
26
+
27
+ query = []
28
+ query << %{assignee = #{jira.username}}
29
+ query << %{project = #{jira.project}} if keys.empty?
30
+ unless keys.empty? then
31
+ query << '(' + keys.map{|k| "key=#{k}"}.join(' OR ') + ')'
32
+ end
33
+ unless options.status.empty? then
34
+ query << '(' + options.status.map{|s| %{status="#{s}"}}.join(' OR ') + ')'
35
+ end
36
+ query = query.join(' AND ')
37
+
38
+ #jira.printVars(:q=>query)
39
+ progresses = jira.getIssues(query, ['key', 'workratio', 'aggregatetimespent',
40
+ 'duedate', 'aggregatetimeoriginalestimate'])
41
+
42
+ rows = progresses.map do |issue|
43
+ estimate = (issue.access('fields.aggregatetimeoriginalestimate') or 0)/3600.0
44
+ progress = (issue.access('fields.aggregatetimespent') or 0)/3600.0
45
+ due = issue.access('fields.duedate')
46
+ percent = issue.access('fields.workratio')
47
+ if percent < 0 then
48
+ estimate = progress if estimate == 0
49
+ percent = (progress / estimate * 100).floor
50
+ end
51
+ ret = [ issue[:key], "%.2f"%[estimate], "%.2f"%[progress],
52
+ %{#{"%.1f"%[percent]}%}, due ]
53
+ if progress > estimate or (not due.nil? and Date.new >= Date.parse(due)) then
54
+ ret.map!{|v| HighLine.color((v or ''), :bold)}
55
+ end
56
+ ret
57
+ end.sort{|a,b| a[0].sub(/^\D+(\d+)$/,'\1').to_i <=> b[0].sub(/^\D+(\d+)$/,'\1').to_i }
58
+
59
+ tbl = Terminal::Table.new :headings=>[:key, :estimated, :progress, :percent, :due], :rows=>rows
60
+ tbl.align_column(1, :right)
61
+ tbl.align_column(2, :right)
62
+ tbl.align_column(3, :right)
63
+ puts tbl
64
+
65
+ end
66
+ end
67
+
68
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,80 @@
1
+ require 'terminal-table'
2
+ require 'mustache'
3
+
4
+ command :query do |c|
5
+ c.syntax = 'jm query [options] query'
6
+ c.summary = 'Get the keys from a jira query'
7
+ c.description = 'Run a query. '
8
+ c.example 'Get Open issues and dump everything', %{jm query status=Open --fields "" --json}
9
+ c.option '--[no-]raw', 'Do not prefix query with project and assignee'
10
+ c.option '--[no-]json', 'Output json reply instead of summary'
11
+ c.option '--fields FIELDS', Array, 'Which fields to return.'
12
+ c.option '--all_fields', 'Return all fields'
13
+ c.option '--format STYLE', String, 'Format for keys'
14
+ c.option '--style STYLE', String, 'Which style to use'
15
+
16
+ c.action do |args, options|
17
+ options.default :json => false, :all_fields => false, :style => 'basic'
18
+
19
+ allOfThem = {
20
+ :basic => {
21
+ :fields => [:key, :summary],
22
+ :format => %{{{key}} {{summary}}},
23
+ },
24
+ :info => {
25
+ :fields => [:key, :description, :assignee, :reporter, :priority, :issuetype,
26
+ :status, :resolution, :votes, :watches],
27
+ :format => %{{{key}}
28
+ Reporter: {{reporter.displayName}}
29
+ Assignee: {{assignee.displayName}}
30
+ Type: {{issuetype.name}} ({{priority.name}})
31
+ Status: {{status.name}} (Resolution: {{resolution.name}})
32
+ Watches: {{watches.watchCount}} Votes: {{votes.votes}}
33
+ Description: {{description}}
34
+ }
35
+ },
36
+ }
37
+
38
+ theStyle = allOfThem[options.style.to_sym]
39
+ theStyle[:fields] = options.fields if options.fields
40
+
41
+ jira = JiraMule::JiraUtils.new(args, options)
42
+ args.unshift("assignee = #{jira.username} AND") unless options.raw
43
+ args.unshift("project = #{jira.project} AND") unless options.raw
44
+ q = args.join(' ')
45
+ if options.all_fields then
46
+ issues = jira.getIssues(q, [])
47
+ else
48
+ issues = jira.getIssues(q, theStyle[:fields])
49
+ end
50
+ if options.json then
51
+ puts JSON.dump(issues)
52
+ else
53
+
54
+ format = theStyle[:format]
55
+ keys = issues.map do |issue|
56
+ Mustache.render(format, issue.merge(issue[:fields]))
57
+ end
58
+ keys.each {|k| puts k}
59
+
60
+
61
+
62
+
63
+ # headers = [:key]
64
+ # rows = issues.map do |item|
65
+ # rw = [item[:key]]
66
+ # item[:fields].each_pair do |fname, fvalue|
67
+ # headers << fname unless headers.include? fname
68
+ # rw << fvalue
69
+ # end
70
+ # rw
71
+ # end
72
+ #
73
+ # puts Terminal::Table.new :headings => headers, :rows=>rows
74
+
75
+ end
76
+ end
77
+ end
78
+ alias_command :q, :query
79
+
80
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,44 @@
1
+
2
+ command :release do |c|
3
+ c.syntax = 'jm release [options]'
4
+ c.summary = 'Little tool for releasing a version in Jira'
5
+ c.description = ''
6
+ c.example 'description', 'command example'
7
+ c.option '--some-switch', 'Some switch that does something'
8
+ c.action do |args, options|
9
+ # Do something or c.when_called Jira::Commands::Release
10
+
11
+ version = GitUtils.getVersion
12
+ newver = ask("\033[1m=?\033[0m Enter the version you want to release (#{version}) ")
13
+ version = newver unless newver == ''
14
+
15
+ project = $cfg['jira.project']
16
+ jira = JiraUtils.new(args, options)
17
+
18
+ jira.createVersion(project, version)
19
+
20
+ ### Find all unreleased issues
21
+ query ="assignee = #{jira.username} AND project = #{project} AND (status = Resolved OR status = Closed) AND fixVersion = EMPTY"
22
+ keys = jira.getIssues(query).map {|item| item['key'] }
23
+ printVars({:keys=>keys})
24
+
25
+ ### Mark issues as fixed by version
26
+ updt = { 'fixVersions'=>[{'add'=>{'name'=>version}}] }
27
+ jira.updateKeys(keys, updt)
28
+
29
+ ### This is old process residue. So should consider removing
30
+ if $cfg['jira.alsoClose'] == true
31
+ puts "Also closing." if options.verbose
32
+ query = "assignee = #{jira.username} AND project = #{project} AND status = Resolved AND fixVersion != EMPTY"
33
+ keys = jira.getIssues(query).map {|item| item['key'] }
34
+ printVars({:Rkeys=>keys})
35
+
36
+ if !keys.empty?
37
+ jira.transition(keys, 'Closed')
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+
44
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,68 @@
1
+
2
+ def printErr(msg)
3
+ $stdout.print("\033[1m=!\033[0m ")
4
+ $stdout.print(msg)
5
+ $stdout.print("\n")
6
+ end
7
+
8
+ command :testReady do |c|
9
+ c.syntax = 'jm testReady [options] [version]'
10
+ c.summary = 'Little tool for setting the fix version on testable issues'
11
+ c.description = %{On all issues in the Testing state, set the fix version and optionally reassign.
12
+ }
13
+ c.example 'Set the release version to the latest git tag', %{jm testReady}
14
+ c.example 'Set the release version to "v2.0"', %{jm testReady v2.0}
15
+ c.example 'Also reassign to the default', %{jm testReady -r v2.0}
16
+ c.example 'Also reassign to BOB', %{jm testReady v2.0 --assign BOB}
17
+ c.option '-r', '--[no-]reassign', 'Also reassign to Default'
18
+ c.option '-a', '--assign USER', 'Assign to USER'
19
+ c.action do |args, options|
20
+ options.default :reassign => false
21
+
22
+ if args[0].nil? then
23
+ version = GitUtils.getVersion
24
+ newver = ask("\033[1m=?\033[0m Enter the version you want to release (#{version}) ")
25
+ version = newver unless newver == ''
26
+ else
27
+ version = args[0]
28
+ end
29
+
30
+ jira = JiraUtils.new(args, options)
31
+ project = jira.project
32
+
33
+ if !options.assign.nil? then
34
+ users = jira.checkUser(options.assign)
35
+ if users.length > 1 then
36
+ printErr "User name '#{options.assign}' is ambigious."
37
+ printVars('Could be'=>users)
38
+ exit 4
39
+ end
40
+ if users.length <= 0 then
41
+ printErr "No users match #{options.assign}"
42
+ exit 4
43
+ end
44
+ options.assign = users[0]
45
+ printVars(:assign=>options.assign)
46
+ end
47
+
48
+ jira.createVersion(project, version)
49
+
50
+ ### Find all unreleased issues
51
+ query ="assignee = #{jira.username} AND project = #{project} AND status = Testing"
52
+ keys = jira.getIssues(query).map {|item| item['key'] }
53
+ printVars({:keys=>keys})
54
+
55
+ ### Mark issues as fixed by version
56
+ updt = { 'fixVersions'=>[{'add'=>{'name'=>version}}] }
57
+ ## assign to '-1' to have Jira automatically assign it
58
+ updt['assignee'] = [{'set'=>{'name'=>'-1'}}] if options.reassign
59
+ updt['assignee'] = [{'set'=>{'name'=>options.assign}}] if options.assign
60
+
61
+ printVars(:update=>updt) if options.verbose
62
+
63
+ jira.updateKeys(keys, updt)
64
+
65
+ end
66
+ end
67
+
68
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,20 @@
1
+ require 'JiraMule/commands/assign'
2
+ require 'JiraMule/commands/attach'
3
+ require 'JiraMule/commands/config'
4
+ require 'JiraMule/commands/githubImport'
5
+ require 'JiraMule/commands/goto'
6
+ require 'JiraMule/commands/kanban'
7
+ require 'JiraMule/commands/link'
8
+ require 'JiraMule/commands/logWork'
9
+ require 'JiraMule/commands/next'
10
+ require 'JiraMule/commands/progress'
11
+ require 'JiraMule/commands/query'
12
+ require 'JiraMule/commands/timesheet'
13
+
14
+ #require 'JiraMule/commands/release'
15
+ #require 'JiraMule/commands/testReady'
16
+ # difference between testReady and release is two things:
17
+ # 1. testReady also assigns
18
+ # 2. release also transitions
19
+ #
20
+ # So, merge all that into one command and have the parts be --options; maybe
@@ -0,0 +1,11 @@
1
+
2
+
3
+ class GitUtils
4
+
5
+ def self.getVersion
6
+ tag = `git for-each-ref --sort=taggerdate --format '%(refname)' refs/tags | head -1`.chomp
7
+ return tag.split('/').last
8
+ end
9
+ end
10
+
11
+ # vim: set sw=4 ts=4 :