jiraMule 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d008f2c8e0cba19fd13ccd63a83a5a7b7781fb0c
4
+ data.tar.gz: 3c9b22e555541db99d55a69d053248119ef90a28
5
+ SHA512:
6
+ metadata.gz: 031b45942d961a29fe74eb7df4ca9bd0b11a5c6c094208ee849b71267ec5146d209ee82575a224fda9ca7e8021409541326a3f8e7db8171f80f0e9768d8be602
7
+ data.tar.gz: 76e18cfc740fae51ec9554cbe4d603a230fd93dc0a86ef9f0ee43467ec8b8bb3cab3bc09c7d0fea61f6a4f8ac70df6943e6c1621ee0c6be542ddc3c4ca05948b
data/.gitignore ADDED
@@ -0,0 +1,23 @@
1
+ .DS_Store
2
+ .AppleDouble
3
+ .LSOverride
4
+ Icon
5
+ *.sw[a-z]
6
+ cookies
7
+ .jiraProject
8
+ .rpjProject
9
+ .jiramulerc
10
+ jiraMule-*.gem
11
+ tags
12
+
13
+ xcuserdata
14
+ Pods/
15
+
16
+ # Thumbnails
17
+ ._*
18
+
19
+ # Files that might appear on external disk
20
+ .Spotlight-V100
21
+ .Trashes
22
+
23
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,17 @@
1
+ source 'http://rubygems.org'
2
+
3
+ gemspec
4
+
5
+ gem 'chronic_duration'
6
+ gem 'commander'
7
+ gem 'inifile', '~> 3.0'
8
+ gem 'mime-types', '~> 1.25.1'
9
+ gem 'mime-types-data', '~> 3.2016'
10
+ gem 'multipart-post'
11
+ gem 'mustache'
12
+ gem "octokit", "~> 4.0"
13
+ gem 'terminal-table'
14
+ gem 'vine'
15
+ gem 'zip'
16
+
17
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 michael conrad tadpol tilstra
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
data/README.md ADDED
@@ -0,0 +1,37 @@
1
+ # jiraMule
2
+
3
+ ## Install
4
+
5
+ ### From source
6
+ ```
7
+ > bundler install
8
+ > rake install
9
+ ```
10
+
11
+ ### By Gem
12
+ ```
13
+ > gem install JiraMule
14
+ ```
15
+
16
+ ## Setup
17
+
18
+ You need to set a few config keys before anyhting really works.
19
+
20
+ Globally:
21
+ ```
22
+ jm config net.url <URL to your Jira> --user
23
+ jm config user.name <Your account name in Jira> --user
24
+ ```
25
+
26
+ Then in each project directory:
27
+ ```
28
+ jm config jira.project <Project ID>
29
+ ```
30
+
31
+ (you could add that to your user config too if you wanted.)
32
+
33
+
34
+ #### Jira API Docs
35
+
36
+ [https://docs.atlassian.com/jira/REST/6.4.7/][]
37
+
data/Rakefile ADDED
@@ -0,0 +1,95 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ #task :default => []
4
+
5
+ tagName = "v#{Bundler::GemHelper.gemspec.version}"
6
+ gemName = "jiraMule-#{Bundler::GemHelper.gemspec.version}.gem"
7
+ builtGem = "pkg/#{gemName}"
8
+
9
+ desc "Install gem in user dir"
10
+ task :bob do
11
+ sh %{gem install --user-install #{builtGem}}
12
+ end
13
+
14
+ desc "Uninstall from user dir"
15
+ task :unbob do
16
+ sh %{gem uninstall --user-install #{builtGem}}
17
+ end
18
+
19
+ task :echo do
20
+ puts tagName
21
+ puts gemName
22
+ puts builtGem
23
+ end
24
+
25
+ namespace :git do
26
+ desc "Push only develop, master, and tags to origin"
27
+ task :origin do
28
+ sh %{git push origin develop}
29
+ sh %{git push origin master}
30
+ sh %{git push origin --tags}
31
+ end
32
+
33
+ # desc "Push only develop, master, and tags to upstream"
34
+ # task :upstream do
35
+ # sh %{git push upstream develop}
36
+ # sh %{git push upstream master}
37
+ # sh %{git push upstream --tags}
38
+ # end
39
+
40
+ desc "Push to origin and upstream"
41
+ task :all => [:origin]
42
+ end
43
+
44
+ task :gemit do
45
+ mrt=Bundler::GemHelper.gemspec.version
46
+ sh %{git checkout v#{mrt}}
47
+ Rake::Task[:build].invoke
48
+ Rake::Task[:bob].invoke
49
+ Rake::Task['push:gem'].invoke
50
+ sh %{git checkout develop}
51
+ end
52
+
53
+ namespace :push do
54
+ desc 'Push gem up to RubyGems'
55
+ task :gem do
56
+ sh %{gem push #{builtGem}}
57
+ end
58
+
59
+ namespace :github do
60
+ desc "Make a release in Github"
61
+ task :makeRelease do
62
+ # ENV['GITHUB_TOKEN'] set by CI.
63
+ # ENV['GITHUB_USER'] set by CI.
64
+ # ENV['GITHUB_REPO'] set by CI
65
+ # Create Release
66
+ sh %{github-release info --tag #{tagName}} do |ok, res|
67
+ if not ok then
68
+ sh %{github-release release --tag #{tagName}}
69
+ end
70
+ end
71
+ end
72
+
73
+ desc 'Push gem up to Github Releases'
74
+ task :gem => [:makeRelease, :build] do
75
+ # ENV['GITHUB_TOKEN'] set by CI.
76
+ # ENV['GITHUB_USER'] set by CI.
77
+ # ENV['GITHUB_REPO'] set by CI
78
+ # upload gem
79
+ sh %{github-release upload --tag #{tagName} --name #{gemName} --file #{builtGem}}
80
+ end
81
+ end
82
+ end
83
+
84
+ task :run do
85
+ sh %{ruby -Ilib bin/jm }
86
+ end
87
+
88
+ desc "Prints a cmd to test this in another directory"
89
+ task :testwith do
90
+ pwd=Dir.pwd.sub(Dir.home, '~')
91
+ puts "ruby -I#{pwd}/lib #{pwd}/bin/jm "
92
+ end
93
+
94
+
95
+ # vim: set sw=4 ts=4 :
data/TODO.taskpaper ADDED
@@ -0,0 +1,6 @@
1
+
2
+ New commands:
3
+ - 'comment' for adding a comment. If no '-m' then open $EDITOR
4
+ - 'assign' Assign to another user.
5
+
6
+
data/bin/jm ADDED
@@ -0,0 +1,87 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'commander/import'
5
+ require 'JiraMule'
6
+ require 'pp'
7
+ require 'json'
8
+
9
+ Signal.trap('INT', 'EXIT') # Don't drop traces on ^C
10
+
11
+ program :version, JiraMule::VERSION
12
+ program :description, %{A collection of things that I do with jira.
13
+
14
+ Many of which are either big batch operations, or need bits of info from
15
+ the command line. All of which turn out to be better handled as a command
16
+ line app.
17
+
18
+ This very specifically does not try to be a generic jira tool; those exist
19
+ already. Rather this is specific to things I need.
20
+ }
21
+ global_option('-V', '--verbose', 'Be chatty') {
22
+ $cfg['tool.verbose'] = true
23
+ }
24
+ global_option('-n', '--dry', "Don't run actions that make changes") {
25
+ $cfg['tool.dry'] = true
26
+ $cfg['tool.verbose'] = true # dry implies verbose
27
+ }
28
+ #global_option('--username USERNAME') {|un|
29
+ # $cfg['jira.userpass'] = un
30
+ #}
31
+ #global_option('--project PROJECT', "Which project to use") {|project|
32
+ # $cfg['jira.project'] = project
33
+ #}
34
+ #global_option('--url URL', "Set jira base url") {|url|
35
+ # $cfg['jira.url'] = url
36
+ #}
37
+ global_option('-L', '--curl', 'Print out a curl command for each network call') {
38
+ $cfg['tool.curldebug'] = true
39
+ }
40
+ global_option '--skip-plugins', %{Don't load plugins. Good for when one goes bad.}
41
+
42
+ global_option('-C', '--configfile FILE', %{Load additional configuration file}) {|file|
43
+ # this is called after all of the top level code in this file.
44
+ $cfg.load_specific(file)
45
+ }
46
+ global_option('-c', '--config KEY=VALUE', %{Set a single config key}) {|param|
47
+ key, value = param.split('=', 2)
48
+ # a=b :> ["a","b"]
49
+ # a= :> ["a",""]
50
+ # a :> ["a"]
51
+ raise "Bad config '#{param}'" if key.nil?
52
+ if value.nil? then
53
+ $cfg[key] = 'true'
54
+ else
55
+ $cfg[key] = value
56
+ end
57
+ }
58
+
59
+ default_command :help
60
+
61
+ $cfg = JiraMule::Config.new
62
+ $cfg.load
63
+
64
+ # Look for plug-ins
65
+ pgds = [
66
+ Pathname.new(Dir.home) + '.jiramule' + 'plugins'
67
+ ]
68
+ # Add plugin dirs from configs
69
+ # This is run before the command line options are parsed, so need to check old way.
70
+ if not ARGV.include? '--skip-plugins' then
71
+ pgds << Pathname.new(ENV['JIRAMULE_PLUGIN_DIR']) if ENV.has_key? 'JIRAMULE_PLUGIN_DIR'
72
+ pgds.each do |path|
73
+ next unless path.exist?
74
+ path.each_child do |plugin|
75
+ next if plugin.directory?
76
+ next unless plugin.readable?
77
+ next if plugin.basename.fnmatch('.*') # don't read anything starting with .
78
+ begin
79
+ require plugin.to_s
80
+ rescue Exception => e
81
+ $stderr.puts "Failed to load plugin at #{plugin} because #{e}"
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ # vim: set sw=2 ts=2 :
data/jiraMule.gemspec ADDED
@@ -0,0 +1,43 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
+ require 'jiraMule/version'
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'jiraMule'
7
+ s.version = JiraMule::VERSION
8
+ s.authors = ['Michael Conrad Tadpol Tilstra']
9
+ s.email = ['tadpol@tadpol.org']
10
+ s.license = 'MIT'
11
+ s.homepage = ''
12
+ s.summary = 'A collection of things that I do with jira'
13
+ s.description = %{A collection of things that I do with jira.
14
+
15
+ Many of which are either big batch operations, or need bits of info from
16
+ the command line. All of which turn out to be better handled as a command
17
+ line app.
18
+
19
+ This very specifically does not try to be a generic jira tool; those exist
20
+ already. Rather this is specific to things I need.
21
+ }
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
26
+ s.require_paths = ['lib']
27
+
28
+ s.add_runtime_dependency('chronic_duration', '~> 0.10.6')
29
+ s.add_runtime_dependency('commander', '~> 4.4.0')
30
+ s.add_runtime_dependency('inifile', '~> 3.0')
31
+ s.add_runtime_dependency('mime-types', '~> 1.25.1')
32
+ s.add_runtime_dependency('mime-types-data', '~> 3.2016')
33
+ s.add_runtime_dependency('multipart-post', '~> 2.0.0')
34
+ s.add_runtime_dependency('mustache', '~> 1.0')
35
+ s.add_runtime_dependency('terminal-table', '~> 1.4.5')
36
+ s.add_runtime_dependency('vine', '~> 0.2')
37
+ s.add_runtime_dependency('zip', '~> 2.0.0')
38
+
39
+ s.add_development_dependency('bundler', '~> 1.12.0')
40
+ s.add_development_dependency('rspec', '~> 3.2')
41
+ s.add_development_dependency('rake')
42
+ end
43
+
@@ -0,0 +1,75 @@
1
+ require 'date'
2
+ require 'json'
3
+ require 'pp'
4
+ require 'vine'
5
+ require 'JiraMule/Config'
6
+ require 'JiraMule/Passwords'
7
+ require 'JiraMule/http'
8
+ require 'JiraMule/verbosing'
9
+
10
+ module JiraMule
11
+ class Tempo
12
+ include Verbose
13
+ include Http
14
+
15
+ def initialize()
16
+ acc = Account.new
17
+ up = acc.loginInfo
18
+ @username = up[:email]
19
+ @password = up[:password]
20
+ end
21
+ attr_reader :username, :password
22
+
23
+ def endPoint(path='')
24
+ URI($cfg['net.url'] + '/rest/tempo-timesheets/3/' + path.to_s)
25
+ end
26
+
27
+ # Get worklogs from Tempo plugin
28
+ def workLogs(username=@username, dateFrom=nil, dateTo=nil, project=nil)
29
+ q = {:username => username}
30
+ q[:dateFrom] = DateTime.parse(dateFrom).to_date.iso8601 unless dateFrom.nil?
31
+ q[:dateTo] = DateTime.parse(dateTo).to_date.iso8601 unless dateTo.nil?
32
+ q[:projectKey] = project unless project.nil?
33
+ #q[:accountKey]
34
+ #q[:teamId]
35
+
36
+ verbose "Fetching worklogs for #{q}"
37
+ get('worklogs', q)
38
+ end
39
+
40
+ ## Submit a timesheet for approval.
41
+ def submitForApproval(period=nil, name=@username, comment='')
42
+ if period.nil? then
43
+ # First day of work week
44
+ cur = currentApprovalStatus(nil, name)
45
+ period = cur.access 'period.dateFrom'
46
+ end
47
+ verbose "Submitting timesheet for #{period}"
48
+ post('timesheet-approval/', {
49
+ :user=>{
50
+ :name=>name,
51
+ },
52
+ :period=>{
53
+ :dateFrom=>period,
54
+ },
55
+ :action=>{
56
+ :name=>:submit,
57
+ :comment=>comment,
58
+ }
59
+ }) unless $cfg['tool.dry']
60
+ end
61
+
62
+ def currentApprovalStatus(period=nil, name=@username)
63
+ verbose "Getting current approval status; #{period} #{name}"
64
+ q = {
65
+ :username => name,
66
+ }
67
+ q[:periodStartDate] = period unless period.nil?
68
+
69
+ get('timesheet-approval/current/', q)
70
+ end
71
+ end
72
+
73
+ end
74
+
75
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,38 @@
1
+ require 'JiraMule/jiraUtils'
2
+
3
+ command :assign do |c|
4
+ c.syntax = 'jm assign [options] <to user> <keys...> '
5
+ c.summary = 'Assign keys to another user'
6
+
7
+ c.action do |args, options|
8
+
9
+ jira = JiraMule::JiraUtils.new(args, options)
10
+
11
+ muser = args.shift
12
+ if muser == '-1' or muser =~ /^:de/ then
13
+ # assign to default
14
+ to = '-1'
15
+ else
16
+ to = jira.checkUser(muser)
17
+ if to.count > 1 then
18
+ say "Username '#{muser}' is ambigious."
19
+ say "Could be: #{to.join(' ')}"
20
+ exit 4
21
+ elsif to.empty? then
22
+ say "No such user: '#{muser}'"
23
+ exit 4
24
+ end
25
+ to = to.first
26
+ end
27
+
28
+ # keys can be with or without the project prefix.
29
+ keys = jira.expandKeys(args)
30
+
31
+ jira.printVars(:key=>keys, :to=>to)
32
+
33
+ jira.assignTo(keys, to)
34
+
35
+ end
36
+ end
37
+
38
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,46 @@
1
+ require 'octokit'
2
+
3
+ command 'github import' do |c|
4
+ c.syntax = %{jm github import <issue id>}
5
+ c.summary = %{Import a Github issue into Jira}
6
+
7
+ c.action do |args, options|
8
+
9
+ iid = args.shift
10
+
11
+ okey = $cfg['github.token']
12
+ if okey.nil? then
13
+ say_error "Missing github token!"
14
+ exit 2
15
+ end
16
+
17
+ oc = Octokit::Client.new(:access_token => okey)
18
+ if oc.nil? then
19
+ exit 3
20
+ end
21
+ oc.login
22
+
23
+ repo = oc.repo $cfg['github.project']
24
+ rel = repo.rels[:issues]
25
+ gissue = rel.get(:uri=>{:number=>iid})
26
+ if gissue.status != 200 then
27
+ say_error "Failed to get issue: #{gissue}"
28
+ exit 2
29
+ end
30
+ gissue = gissue.data
31
+
32
+ jira = JiraMule::JiraUtils.new(args, options)
33
+ # Create Issue
34
+ it = jira.checkIssueType
35
+
36
+ jissue = jira.createIssue(it.first[:name], gissue[:title], gissue[:body])
37
+ jira.verbose "Created #{jissue[:key]}"
38
+
39
+ # Link
40
+ jira.linkTo(jissue[:key], gissue[:html_url], gissue[:title])
41
+
42
+ end
43
+ end
44
+ alias_command :ghi, 'github import'
45
+
46
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,41 @@
1
+ require 'JiraMule/jiraUtils'
2
+
3
+ command :links do |c|
4
+ c.syntax = %{jm links <keys>}
5
+ c.summary = %{Show all remote links}
6
+
7
+ c.action do |args, options|
8
+ jira = JiraMule::JiraUtils.new(args, options)
9
+ keys = jira.expandKeys(args)
10
+ keys.each do |key|
11
+ jira.remote_links(key).each do |link|
12
+ obj = link[:object]
13
+ unless obj.nil? then
14
+ say "- #{obj[:title]}"
15
+ say " #{obj[:url]}"
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+
22
+ command :addLink do |c|
23
+ c.syntax = %{jm addLink <key> <url> <title>}
24
+ c.summary = %{Add a remote link to an issue}
25
+ c.action do |args, options|
26
+ jira = JiraMule::JiraUtils.new(args, options)
27
+ key = jira.expandKeys([args[0]]).first
28
+ url = args[1]
29
+ title = args[2]
30
+ if url.nil? then
31
+ say_error "Missing URL"
32
+ elsif title.nil? then
33
+ say_error "Missing Title"
34
+ else
35
+ jira.linkTo(key, url, title)
36
+ end
37
+ end
38
+ end
39
+ alias_command :link, :addLink
40
+
41
+ # vim: set ai et sw=2 ts=2 :
@@ -0,0 +1,113 @@
1
+ require 'chronic_duration'
2
+ require 'date'
3
+ require 'terminal-table'
4
+ require 'vine'
5
+ require 'JiraMule/jiraUtils'
6
+ require 'JiraMule/Tempo'
7
+
8
+ command :timesheet do |c|
9
+ c.syntax = 'jm timesheet [options]'
10
+ c.summary = 'Show work done this week'
11
+ c.description = %{Show the work done this week
12
+ }
13
+ c.example 'Show work done this week', 'jm timesheet'
14
+ c.example 'Show work done for project', 'jm timesheet --project DEV'
15
+ c.example 'Show work done for projects', 'jm timesheet --project DEV,PROD'
16
+ c.example 'Show work done for keys', 'jm timesheet 12 PROD-15 99 STG-6'
17
+
18
+ c.option '--project PROJECTS', Array, 'Limit results to specific projects'
19
+
20
+ #c.option '--prev COUNT', Integer, 'Look at previous weeks'
21
+ c.option '--starts_on DAY', String, 'Which day does the week start on'
22
+
23
+ c.action do |args, options|
24
+ options.default :starts_on => 'Mon'
25
+
26
+ jira = JiraMule::JiraUtils.new
27
+ tempo = JiraMule::Tempo.new
28
+
29
+ #Days Of Week
30
+ dows = [:Sun,:Mon,:Tue,:Wed,:Thu,:Fri,:Sat]
31
+ dayShift = dows.index{|i| options.starts_on.downcase.start_with? i.to_s.downcase}
32
+ workweek = dows.rotate dayShift
33
+
34
+ dayTo = Date.today
35
+ dayFrom = dayTo
36
+ while not dayFrom.wday == dayShift do
37
+ dayFrom = dayFrom.prev_day
38
+ end
39
+
40
+ # Get keys to get worklogs from
41
+ keys = jira.expandKeys(args)
42
+ if keys.empty? then
43
+ query = %{worklogAuthor = #{jira.username}}
44
+ query << %{ AND worklogDate >= #{dayFrom.iso8601}}
45
+
46
+ if options.project and not options.project.empty? then
47
+ query << ' AND ('
48
+ query << options.project.map{|p| %{project="#{p}"}}.join(' OR ')
49
+ query << ')'
50
+ end
51
+
52
+ keys = jira.getIssues(query, ['key']).map{|k| k[:key]}
53
+ end
54
+ jira.printVars(:keys=>keys) if $cfg['tool.verbose']
55
+
56
+ wls = tempo.workLogs(jira.username, dayFrom.iso8601, dayTo.iso8601)
57
+
58
+ # filter out entries not in keys.
59
+ selected = wls.select{|i| keys.include? i.access('issue.key')}
60
+
61
+ # build table; each row is a key. each column is hours worked in SSMTWTF
62
+ # multiple passes.
63
+ # 1: build hash by issue, each value is a hash by week day.
64
+ hrows = {}
65
+ selected.each do |isu|
66
+ k = isu.access('issue.key')
67
+ hrows[k] = {} unless hrows.has_key? k
68
+ ds = DateTime.parse(isu[:dateStarted]).to_date
69
+ dow = dows[ds.wday]
70
+ hrows[k][dow] = 0 unless hrows[k].has_key?(dow)
71
+ hrows[k][dow] += isu[:timeSpentSeconds]
72
+ end
73
+
74
+ totals = Hash[ *(workweek.map{|i| [i,0]}.flatten) ]
75
+ # 2: reshape into Array or Arrays.
76
+ rows = hrows.to_a.map do |row|
77
+ # row[0] is key, want to keep that.
78
+ # row[1] is a hash we want to sort and flatten.
79
+ row[1] = workweek.map do |d|
80
+ s = row[1][d]
81
+ if s.nil? then
82
+ nil
83
+ else
84
+ totals[d] += s
85
+ ChronicDuration.output(s, :format=>:short)
86
+ end
87
+ end
88
+ row.flatten
89
+ end
90
+
91
+ trow = workweek.map do |d|
92
+ s = totals[d]
93
+ if s.nil? then
94
+ nil
95
+ else
96
+ ChronicDuration.output(s, :format=>:short)
97
+ end
98
+ end
99
+ trow.insert(0, 'TOTALS:')
100
+
101
+ hdr = workweek.insert(0, :Key)
102
+ table = Terminal::Table.new do |t|
103
+ t.headings = hdr
104
+ t.rows = rows
105
+ t.add_separator
106
+ t.add_row trow
107
+ end
108
+ puts table
109
+ end
110
+ end
111
+ alias_command :ts, :timesheet
112
+
113
+ # vim: set sw=2 ts=2 :
@@ -0,0 +1,33 @@
1
+ require 'pp'
2
+
3
+ # You don't need this.
4
+ # To use this:
5
+ # - mkdir -p ~/.jiramule/plugins
6
+ # - ln gb.rb ~/.jiramule/plugins
7
+
8
+ command :_gb do |c|
9
+ c.syntax = %{jm _gb <class> <method> (<args>)}
10
+ c.summary = %{Call internal class methods directly.}
11
+ c.description = %{Call internal class methods directly.}
12
+
13
+ c.action do |args, options|
14
+ cls = args[0]
15
+ meth = args[1].to_sym
16
+ args.shift(2)
17
+
18
+ begin
19
+ gb = Object::const_get("JiraMule::#{cls}").new
20
+ if gb.respond_to? meth then
21
+ pp gb.__send__(meth, *args)
22
+ else
23
+ say_error "'#{cls}' doesn't '#{meth}'"
24
+ end
25
+ rescue Exception => e
26
+ say_error e.message
27
+ pp e
28
+ end
29
+ end
30
+ end
31
+
32
+
33
+ # vim: set ai et sw=2 ts=2 :