module RedmineIssue
Constants
- CONFIG
- CONFIG_PATH
- STATUS_CLOSED
- STATUS_COMPLETED
- STATUS_FEEDBACK
- STATUS_INPROGRESS
Public Class Methods
_expand_issue_id(id)
click to toggle source
# File lib/redmine_issue.rb, line 102 def self._expand_issue_id(id) if id.nil?() return config('current')['id'] end if id.start_with?('#') return id[1..-1].to_i() end found = config('last_listed_issues', []).select() { |found_id| found_id.to_s().end_with?(id.to_s()) } if found.length > 1 raise "Issue #id is ambiguos; specify more digits" end if found.length == 0 return id end return found.first().to_i() end
_get_arguments_hash(args)
click to toggle source
# File lib/redmine_issue.rb, line 183 def self._get_arguments_hash(args) result = {} args.each_with_index() { |value, index| if value.start_with?('--no-') result[_get_arguments_key(value[5..-1])] = true next end if value.start_with?('--') if args[index + 1].nil?() || args[index + 1].start_with?('--') result[_get_arguments_key(value[2..-1])] = true next end result[_get_arguments_key(value[2..-1])] = args[index + 1] end } return result end
_get_arguments_key(key)
click to toggle source
# File lib/redmine_issue.rb, line 141 def self._get_arguments_key(key) key = key.gsub('_', '{{__DASH__}}') key = key.gsub('-', '_') key = key.gsub('{{__DASH__}}', '-') return key end
_get_console_option(args, option)
click to toggle source
# File lib/redmine_issue.rb, line 148 def self._get_console_option(args, option) if option.instance_of?(::Array) option.each() { |option_item| result = _get_console_option(args, option_item) if !result.nil?() return result end } return nil end if option.length == 1 index = args.index('-' + _get_arguments_key(option)) if !index.nil?() return args[index + 1] end end if args.index('--no-' + _get_arguments_key(option)) return false end index = args.index('--' + _get_arguments_key(option)) if index.nil?() return nil end if args[index + 1].nil?() return true end return args[index + 1] end
_get_current_elapsed_hours()
click to toggle source
# File lib/redmine_issue.rb, line 126 def self._get_current_elapsed_hours() current = config('current', nil) if current.nil?() || current['id'].nil?() raise 'No active issue in progress' end seconds = DateTime.now().to_time() - DateTime.parse(current['started']).to_time() hours = (seconds / 3600.0).round(2).to_s() return hours end
_get_responsible_user_id(issue)
click to toggle source
# File lib/redmine_issue.rb, line 215 def self._get_responsible_user_id(issue) if issue.instance_of?(::Fixnum) || issue.instance_of?(::String) issue = request("issues/#{issue}", {include: 'journals'})['issue'] end if !issue.has_key?('journals') raise "Issue should have journals to find out adminitrator id" end user_id = _get_user_id() issue['journals'].reverse().each() { |note| if note['user']['id'] != user_id return note['user']['id'] end } return issue['author']['id'] end
_get_user_id()
click to toggle source
# File lib/redmine_issue.rb, line 204 def self._get_user_id() user_id = config('user_id', nil) if !user_id.nil?() return user_id end user_id = request('users/current')['user']['id'] set_config('user_id', user_id) return user_id end
_pause_current(id)
click to toggle source
# File lib/redmine_issue.rb, line 234 def self._pause_current(id) current = config('current', nil) if !current.nil?() && current['id'].to_i() == id.to_i() pause() end end
_split_text(text, length = 60)
click to toggle source
# File lib/redmine_issue.rb, line 90 def self._split_text(text, length = 60) result = 0. upto((text.length / length.to_f()).floor()). collect() { |index| text[index * length, length] }. join("\n") return result end
cancel()
click to toggle source
# File lib/redmine_issue.rb, line 310 def self.cancel() current = config('current', nil) if current.nil?() raise "No active issue in progress" end set_config('current', nil) return current end
close(id = nil)
click to toggle source
# File lib/redmine_issue.rb, line 341 def self.close(id = nil) real_id = _expand_issue_id(id) _pause_current(real_id) issue = { 'status_id' => STATUS_CLOSED } return request("issues/#{real_id}", {}, {'issue' => issue}, {method: 'PUT'}) end
complete(id = nil)
click to toggle source
# File lib/redmine_issue.rb, line 329 def self.complete(id = nil) real_id = _expand_issue_id(id) _pause_current(real_id) issue = { 'assigned_to_id' => _get_responsible_user_id(real_id), 'status_id' => STATUS_COMPLETED, } return request("issues/#{real_id}", {}, {'issue' => issue}, {method: 'PUT'}) end
config(key, value = Undefined.new())
click to toggle source
# File lib/redmine_issue.rb, line 26 def self.config(key, value = Undefined.new()) if value.instance_of?(Undefined) && !CONFIG.has_key?(key) raise "#{key} should be set in config" end return CONFIG.fetch(key, value) end
description(id = nil)
click to toggle source
# File lib/redmine_issue.rb, line 352 def self.description(id = nil) real_id = _expand_issue_id(id) issue = request("issues/#{real_id}", {include: 'journals'})['issue'] journal = issue.delete('journals') info = issue. collect() { |key, value| if value.instance_of?(::Hash) if value.has_key?('name') value = value['name'] else value = value.to_s() end end [key.capitalize(), _split_text(value.to_s(), 100)] } comments = journal. select() { |element| !element['notes'].empty?() }. collect() { |element| [element['user']['name'], _split_text(element['notes'], 80)] } if comments.length > 0 info.push(['Comments', Terminal::Table.new(rows: comments)]) end return Terminal::Table.new(rows: info) end
help()
click to toggle source
# File lib/redmine_issue.rb, line 406 def self.help() return <<-TEXT USAGE: redmine-issue [command] [args] Manage redmine issues. Commands: list List issues; arguments is API get params: http://www.redmine.org/projects/redmine/wiki/Rest_Issues; Example: --project-id 10 --status-id closed; default arguments: --assigned-to-id me --status-id open --sort "priority:desc,project" description [id] Get issue description and comments reply [id] -m message Reply to issue; adds comment, sets status "Feedback" and returns issue to responsible user start id Starts issue specified by id; starts tracking current issue and spent time and set issue status "In progress" pause Pause current issue; save spent time to issue and untrack current issue. cancel Cancel current issue; untrack current issue without time saving. status Get current issue id and spent time. complete [id] Complete issue; set status "Completed" to issue and returns issue to responsible user; if completes current - save spent time. close [id] Same as complete but set status "Closed"; you have to have permission to close issues to tun this command. config key Displays config value. set-config key value Sets config value. TEXT end
list(*args)
click to toggle source
# File lib/redmine_issue.rb, line 241 def self.list(*args) params = _get_arguments_hash(args) params['assigned_to_id'] ||= 'me' params['status_id'] ||= 'open' params['sort'] ||= 'priority:desc,project' issues = request('issues', params).fetch('issues') ids = issues.collect() { |issue| issue['id'] } set_config('last_listed_issues', ids) info = [['id', 'priority', 'subject', 'info']] info.push(:separator) info += issues.collect() { |issue| next [ '#' + issue['id'].to_s(), [ issue.fetch('priority', {})['name'], issue.fetch('status', {})['name'], " ", ].join("\n"), _split_text(issue['subject']), [ issue.fetch('project', {})['name'], issue.fetch('author', {})['name'], ].join("\n") ] } info.pop() return Terminal::Table.new(rows: info) end
pause()
click to toggle source
# File lib/redmine_issue.rb, line 294 def self.pause() current = config('current', nil) if current.nil?() raise "No active issue in progress" end time_entry = { 'issue_id' => current['id'], 'hours' => _get_current_elapsed_hours() } result = request('time_entries', {}, {'time_entry' => time_entry}) set_config('current', nil) return result end
reply(*args)
click to toggle source
# File lib/redmine_issue.rb, line 387 def self.reply(*args) if args.length > 0 && args[0].match(/^\d+/) real_id = _expand_issue_id(args[0]) else id = _get_console_option(args, ['i', 'issue']) real_id = _expand_issue_id(id) end message = _get_console_option(args, ['m', 'message']) issue = { 'assigned_to_id' => _get_responsible_user_id(real_id), 'status' => STATUS_FEEDBACK, 'notes' => message, } return request("issues/#{real_id}", {}, {'issue' => issue}, {method: 'PUT'}) end
request(method, get = {}, data = nil, options = {method: 'POST'})
click to toggle source
# File lib/redmine_issue.rb, line 46 def self.request(method, get = {}, data = nil, options = {method: 'POST'}) query = get. collect() { |key, value | CGI.escape(key.to_s()) + '=' + CGI.escape(value.to_s()) }. join('&') uri = URI(config('address') + '/' + method + '.json?' + query) if data.nil?() request = Net::HTTP::Get.new(uri) else if options[:method] == 'POST' request = Net::HTTP::Post.new(uri) elsif options[:method] == 'PUT' request = Net::HTTP::Put.new(uri) else raise 'Wrong request method' end end request['X-Redmine-API-Key'] = config('secret') request['Content-Type'] = 'application/json' if !data.nil?() request.body = JSON.generate(data) end result = Net::HTTP.start(uri.hostname, uri.port) { |http| http.request(request) } if result.is_a?(Net::HTTPOK) && result.body == '' return true end begin return JSON.parse(result.body) rescue => error raise "Failed to parse json: #{result} (#{error})" end end
set_config(key, value)
click to toggle source
# File lib/redmine_issue.rb, line 34 def self.set_config(key, value) if value.nil?() CONFIG.delete(key) else CONFIG[key] = value end FileUtils.mkdir_p(File.dirname(CONFIG_PATH)) new_config = JSON.pretty_generate(CONFIG) File.write(File.expand_path(CONFIG_PATH), new_config) end
start(id)
click to toggle source
# File lib/redmine_issue.rb, line 276 def self.start(id) current = config('current', nil) if !current.nil?() raise "Can not start; issue #{current['id']} is already " + 'in progress' end real_id = _expand_issue_id(id) issue = { 'issue' => {'status_id' => STATUS_INPROGRESS} } result = request("issues/#{real_id}", {}, issue, {method: 'PUT'}) set_config('current', {'id' => real_id, 'started' => DateTime.now().to_s()}) return result end
status()
click to toggle source
# File lib/redmine_issue.rb, line 320 def self.status() current = config('current', nil) if current.nil?() raise "No active issue in progress" end return "Issue: ##{current['id']}\nTime: #{_get_current_elapsed_hours()}" end