jiraMule 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +23 -0
- data/Gemfile +17 -0
- data/LICENSE +22 -0
- data/README.md +37 -0
- data/Rakefile +95 -0
- data/TODO.taskpaper +6 -0
- data/bin/jm +87 -0
- data/jiraMule.gemspec +43 -0
- data/lib/JiraMule/Tempo.rb +75 -0
- data/lib/JiraMule/commands/assign.rb +38 -0
- data/lib/JiraMule/commands/githubImport.rb +46 -0
- data/lib/JiraMule/commands/link.rb +41 -0
- data/lib/JiraMule/commands/timesheet.rb +113 -0
- data/lib/JiraMule/gb.rb +33 -0
- data/lib/JiraMule.rb +7 -0
- data/lib/jiraMule/Config.rb +224 -0
- data/lib/jiraMule/Passwords.rb +81 -0
- data/lib/jiraMule/commands/attach.rb +69 -0
- data/lib/jiraMule/commands/config.rb +68 -0
- data/lib/jiraMule/commands/goto.rb +166 -0
- data/lib/jiraMule/commands/kanban.rb +243 -0
- data/lib/jiraMule/commands/logWork.rb +39 -0
- data/lib/jiraMule/commands/next.rb +89 -0
- data/lib/jiraMule/commands/progress.rb +68 -0
- data/lib/jiraMule/commands/query.rb +80 -0
- data/lib/jiraMule/commands/release.rb +44 -0
- data/lib/jiraMule/commands/testReady.rb +68 -0
- data/lib/jiraMule/commands.rb +20 -0
- data/lib/jiraMule/gitUtils.rb +11 -0
- data/lib/jiraMule/http.rb +147 -0
- data/lib/jiraMule/jiraUtils.rb +288 -0
- data/lib/jiraMule/verbosing.rb +28 -0
- data/lib/jiraMule/version.rb +3 -0
- metadata +268 -0
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
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 :
|
data/lib/JiraMule/gb.rb
ADDED
@@ -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 :
|