minglemingle 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES +4 -0
- data/LICENSE.TXT +203 -0
- data/README +79 -0
- data/Rakefile +349 -0
- data/TODO +14 -0
- data/bin/mm +17 -0
- data/doc/jamis.rb +591 -0
- data/install.rb +88 -0
- data/lib/mm.rb +81 -0
- data/lib/mm/cmds/abstract_command.rb +78 -0
- data/lib/mm/cmds/card.rb +57 -0
- data/lib/mm/cmds/cards.rb +58 -0
- data/lib/mm/cmds/favorites.rb +29 -0
- data/lib/mm/cmds/help.rb +70 -0
- data/lib/mm/cmds/init.rb +43 -0
- data/lib/mm/cmds/run.rb +54 -0
- data/lib/mm/cmds/svncommit.rb +68 -0
- data/lib/mm/cmds/tabs.rb +28 -0
- data/lib/mm/cmds/user.rb +40 -0
- data/lib/mm/cmds/view.rb +37 -0
- data/lib/mm/repository.rb +40 -0
- data/lib/mm/rest_api.rb +63 -0
- data/lib/mm/transition_execution.tab.rb +279 -0
- data/lib/mm/utils.rb +41 -0
- data/test/abstract_command_test.rb +31 -0
- data/test/test_helper.rb +26 -0
- metadata +86 -0
data/install.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'rbconfig'
|
2
|
+
require 'find'
|
3
|
+
require 'ftools'
|
4
|
+
|
5
|
+
include Config
|
6
|
+
|
7
|
+
$ruby = CONFIG['ruby_install_name']
|
8
|
+
|
9
|
+
##
|
10
|
+
# Install a binary file. We patch in on the way through to
|
11
|
+
# insert a #! line. If this is a Unix install, we name
|
12
|
+
# the command (for example) 'mm' and let the shebang line
|
13
|
+
# handle running it. Under windows, we add a '.rb' extension
|
14
|
+
# and let file associations to their stuff
|
15
|
+
#
|
16
|
+
|
17
|
+
def installBIN(from, opfile)
|
18
|
+
|
19
|
+
tmp_dir = nil
|
20
|
+
for t in [".", "/tmp", "c:/temp", $bindir]
|
21
|
+
stat = File.stat(t) rescue next
|
22
|
+
if stat.directory? and stat.writable?
|
23
|
+
tmp_dir = t
|
24
|
+
break
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
fail "Cannot find a temporary directory" unless tmp_dir
|
29
|
+
tmp_file = File.join(tmp_dir, "_tmp")
|
30
|
+
|
31
|
+
File.open(from) do |ip|
|
32
|
+
File.open(tmp_file, "w") do |op|
|
33
|
+
ruby = File.join($realbindir, $ruby)
|
34
|
+
op.puts "#!#{ruby}"
|
35
|
+
op.write ip.read
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
opfile += ".rb" if CONFIG["target_os"] =~ /mswin/i
|
40
|
+
File::install(tmp_file, File.join($bindir, opfile), 0755, true)
|
41
|
+
File::unlink(tmp_file)
|
42
|
+
end
|
43
|
+
|
44
|
+
$sitedir = CONFIG["sitelibdir"]
|
45
|
+
unless $sitedir
|
46
|
+
version = CONFIG["MAJOR"]+"."+CONFIG["MINOR"]
|
47
|
+
$libdir = File.join(CONFIG["libdir"], "ruby", version)
|
48
|
+
$sitedir = $:.find {|x| x =~ /site_ruby/}
|
49
|
+
if !$sitedir
|
50
|
+
$sitedir = File.join($libdir, "site_ruby")
|
51
|
+
elsif $sitedir !~ Regexp.quote(version)
|
52
|
+
$sitedir = File.join($sitedir, version)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
$bindir = CONFIG["bindir"]
|
57
|
+
|
58
|
+
$realbindir = $bindir
|
59
|
+
|
60
|
+
bindir = CONFIG["bindir"]
|
61
|
+
if (destdir = ENV['DESTDIR'])
|
62
|
+
$bindir = destdir + $bindir
|
63
|
+
$sitedir = destdir + $sitedir
|
64
|
+
|
65
|
+
File::makedirs($bindir)
|
66
|
+
File::makedirs($sitedir)
|
67
|
+
end
|
68
|
+
|
69
|
+
mm_dest = File.join($sitedir, "mm")
|
70
|
+
File::makedirs(mm_dest, true)
|
71
|
+
File::chmod(0755, mm_dest)
|
72
|
+
|
73
|
+
# The library files
|
74
|
+
|
75
|
+
files = Dir.chdir('lib') { Dir['**/*.rb', '**/*.rake'] }
|
76
|
+
|
77
|
+
for fn in files
|
78
|
+
fn_dir = File.dirname(fn)
|
79
|
+
target_dir = File.join($sitedir, fn_dir)
|
80
|
+
if ! File.exist?(target_dir)
|
81
|
+
File.makedirs(target_dir)
|
82
|
+
end
|
83
|
+
File::install(File.join('lib', fn), File.join($sitedir, fn), 0644, true)
|
84
|
+
end
|
85
|
+
|
86
|
+
# and the executable
|
87
|
+
|
88
|
+
installBIN("bin/mm", "mm")
|
data/lib/mm.rb
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# Copyright (c) 2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'mm/utils'
|
16
|
+
require 'mm/rest_api'
|
17
|
+
|
18
|
+
require 'mm/cmds/abstract_command'
|
19
|
+
require 'mm/cmds/init'
|
20
|
+
require 'mm/cmds/run'
|
21
|
+
require 'mm/cmds/svncommit'
|
22
|
+
require 'mm/cmds/user'
|
23
|
+
require 'mm/cmds/card'
|
24
|
+
require 'mm/cmds/cards'
|
25
|
+
require 'mm/cmds/favorites'
|
26
|
+
require 'mm/cmds/tabs'
|
27
|
+
require 'mm/cmds/view'
|
28
|
+
require 'mm/cmds/help'
|
29
|
+
|
30
|
+
module MM
|
31
|
+
VERSION="0.0.1"
|
32
|
+
|
33
|
+
module API
|
34
|
+
def team_members
|
35
|
+
return @team_members if defined?(@team_members)
|
36
|
+
init(Resource::User)
|
37
|
+
@team_members = Resource::User.find(:all)
|
38
|
+
end
|
39
|
+
|
40
|
+
def property_definitions
|
41
|
+
return @property_definitions if defined?(@property_definitions)
|
42
|
+
init(Resource::PropertyDefinition)
|
43
|
+
@property_definitions = Resource::PropertyDefinition.find(:all)
|
44
|
+
end
|
45
|
+
|
46
|
+
def favorites
|
47
|
+
init(Resource::Favorite)
|
48
|
+
Resource::Favorite.find(:all)
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_transition_execution(attrs)
|
52
|
+
init(Resource::TransitionExecution)
|
53
|
+
Resource::TransitionExecution.create(attrs)
|
54
|
+
end
|
55
|
+
|
56
|
+
def find_card(options)
|
57
|
+
init(Resource::Card)
|
58
|
+
Resource::Card.find(:first, options)
|
59
|
+
end
|
60
|
+
|
61
|
+
def find_card_by_number(number)
|
62
|
+
init(Resource::Card)
|
63
|
+
Resource::Card.find(number)
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_cards(options)
|
67
|
+
init(Resource::Card)
|
68
|
+
Resource::Card.find(:all, :params => options)
|
69
|
+
end
|
70
|
+
|
71
|
+
def init(klass)
|
72
|
+
Command::Init.new.do_once(klass)
|
73
|
+
end
|
74
|
+
|
75
|
+
def execute_cmd(cmd)
|
76
|
+
%x[#{cmd}]
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
MM::Command::AbstractCommand.send(:include, MM::API)
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# Copyright (c) 2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'mm/repository'
|
15
|
+
|
16
|
+
module MM
|
17
|
+
module Command
|
18
|
+
class AbstractCommand
|
19
|
+
def run(argv)
|
20
|
+
if respond_to?(:option_parser)
|
21
|
+
option_parser.parse!(argv)
|
22
|
+
end
|
23
|
+
parse(argv) unless argv.empty?
|
24
|
+
cache_options
|
25
|
+
view do_once
|
26
|
+
end
|
27
|
+
|
28
|
+
def view(result)
|
29
|
+
output result
|
30
|
+
end
|
31
|
+
|
32
|
+
def options
|
33
|
+
@options ||= Repository.new[self.class.name] || {}
|
34
|
+
end
|
35
|
+
|
36
|
+
def parse(argv)
|
37
|
+
end
|
38
|
+
|
39
|
+
def doc
|
40
|
+
puts(respond_to?(:option_parser) ? option_parser : "No document.")
|
41
|
+
end
|
42
|
+
|
43
|
+
def cache_options
|
44
|
+
Repository.new[self.class.name] = options
|
45
|
+
end
|
46
|
+
|
47
|
+
def output(message=nil)
|
48
|
+
if block_given?
|
49
|
+
output yield
|
50
|
+
return
|
51
|
+
elsif message.is_a?(String)
|
52
|
+
puts message
|
53
|
+
elsif options[:attr]
|
54
|
+
value = if pd = property_definitions.find{|pd| pd.name.downcase == options[:attr].downcase}
|
55
|
+
property_value(pd, message)
|
56
|
+
else
|
57
|
+
message.send(options[:attr])
|
58
|
+
end
|
59
|
+
output(" * #{options[:attr]}: #{value}")
|
60
|
+
else
|
61
|
+
output(message.to_yaml)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def property_value(pd, card)
|
66
|
+
obj_value = card.send(pd.column_name)
|
67
|
+
case
|
68
|
+
when pd.card_property?(obj_value)
|
69
|
+
find_card(:id => obj_value).short_summarization
|
70
|
+
when pd.user_property?(obj_value)
|
71
|
+
team_members.find{|u|u.id==obj_value}.name
|
72
|
+
else
|
73
|
+
obj_value
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
data/lib/mm/cmds/card.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Copyright (c) 2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'mm/cmds/abstract_command'
|
15
|
+
|
16
|
+
module MM
|
17
|
+
module Command
|
18
|
+
class Card < AbstractCommand
|
19
|
+
def view(card)
|
20
|
+
if options[:attr] || options[:show_all]
|
21
|
+
super(card)
|
22
|
+
else
|
23
|
+
super(card.summarization)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def do_once
|
28
|
+
output "card number => #{options[:number]}"
|
29
|
+
find_card_by_number(options[:number])
|
30
|
+
end
|
31
|
+
|
32
|
+
def parse(argv)
|
33
|
+
options[:number] = argv[0].gsub(/[^\d]/, '').strip
|
34
|
+
end
|
35
|
+
|
36
|
+
def option_parser
|
37
|
+
OptionParser.new do |opts|
|
38
|
+
opts.banner = "usage: mm card <card_number>"
|
39
|
+
opts.separator ""
|
40
|
+
opts.separator "Synopsis:"
|
41
|
+
opts.separator "mm card 1 => find card by card number 1 and show all attributes"
|
42
|
+
opts.separator "mm card 1 -a description => find card by card number 1 and show its description"
|
43
|
+
opts.separator ""
|
44
|
+
opts.separator "Options:"
|
45
|
+
|
46
|
+
opts.on_tail("-a", "--attribute ATTR_NAME", "show specified attribute value") do |attr_name|
|
47
|
+
options[:attr] = attr_name
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on_tail("-s", "--show_all", "show all card attributes") do
|
51
|
+
options[:show_all] = true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright (c) 2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'mm/cmds/abstract_command'
|
15
|
+
|
16
|
+
module MM
|
17
|
+
module Command
|
18
|
+
class Cards < AbstractCommand
|
19
|
+
def view(cards)
|
20
|
+
cards.each do |card|
|
21
|
+
output '----------'
|
22
|
+
output card.short_summarization
|
23
|
+
if options[:attrs]
|
24
|
+
options[:attrs].each do |attr_name|
|
25
|
+
options[:attr] = attr_name
|
26
|
+
output card
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def do_once
|
33
|
+
output "card list params => #{options.inspect}"
|
34
|
+
find_cards(options)
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse(argv)
|
38
|
+
view_options = argv.join(' ').strip
|
39
|
+
options.merge!(eval(view_options =~ /^\{.*\}$/ ? view_options : "{#{view_options}}"))
|
40
|
+
end
|
41
|
+
|
42
|
+
def option_parser
|
43
|
+
OptionParser.new do |opts|
|
44
|
+
opts.banner = "usage: mm cards [options]"
|
45
|
+
opts.separator ""
|
46
|
+
opts.separator "Synopsis:"
|
47
|
+
opts.separator "mm cards \"{:view => 'favorite/tab name'}\" => find cards by favorite's/tab's name"
|
48
|
+
opts.separator "mm cards \"{:view => 'favorite/tab name', :page => 2}\" => find cards in the page 2 by favorite's/tab's name"
|
49
|
+
opts.separator ""
|
50
|
+
opts.separator "Options:"
|
51
|
+
opts.on("-a att_name1,attr_name2", Array, "show specified attribute value.") do |names|
|
52
|
+
options[:attrs] = names
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# Copyright (c) 2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'mm/cmds/abstract_command'
|
15
|
+
|
16
|
+
#not finished yet
|
17
|
+
module MM
|
18
|
+
module Command
|
19
|
+
class Favorites < AbstractCommand
|
20
|
+
def view(favorites)
|
21
|
+
output "All favorites: \n#{favorites.collect{|f| " * #{f.name}"}.join("\n")}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def do_once
|
25
|
+
favorites
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/lib/mm/cmds/help.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# Copyright (c) 2008 Li Xiao
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
require 'mm/cmds/abstract_command'
|
15
|
+
|
16
|
+
module MM
|
17
|
+
module Command
|
18
|
+
class Help < AbstractCommand
|
19
|
+
def do_once
|
20
|
+
return doc if options[:cmd].blank?
|
21
|
+
"#{MM.cmd_instance(options[:cmd]).doc}\n"
|
22
|
+
rescue Exception => e
|
23
|
+
"Unknow subcommand: #{options[:cmd]}\n#{doc}\n"
|
24
|
+
end
|
25
|
+
|
26
|
+
def parse(argv)
|
27
|
+
options[:cmd] = argv.first
|
28
|
+
end
|
29
|
+
|
30
|
+
#don't want to cache options of this command
|
31
|
+
def cache_options
|
32
|
+
end
|
33
|
+
|
34
|
+
def doc
|
35
|
+
%{
|
36
|
+
mingle mingle, version #{MM::VERSION}
|
37
|
+
Type 'mm help <subcommand>' for help on a specific subcommand.
|
38
|
+
|
39
|
+
Queck start:
|
40
|
+
* Suppose I am working on a project pet_store checked out at '~/pet_store'.
|
41
|
+
* cd ~/pet_store
|
42
|
+
* mm init http://my_login:password@mingle_server/projects/pet_store
|
43
|
+
* mm cards => list first page cards on All tab
|
44
|
+
* mm view My Work -a owner,priority => list cards on card list view named 'My Work' including property owner and priority
|
45
|
+
* mm card 102 => show name and description of the card
|
46
|
+
* mm run 'Start fix #102' => run transition 'Start fix' on card 102
|
47
|
+
* mm svnci -m "[complete development #1 with 'fixed revision' => \#{revision}, resolution => fixed (some comment)] blabla..." => commit code and run transition script inside of []
|
48
|
+
* mm view => show view cached which is 'My Work' with property 'owner' and 'priority' by last time using view command
|
49
|
+
* mm card => show card cached number of which is 102 by last time using card command
|
50
|
+
|
51
|
+
Available subcommands:
|
52
|
+
help [subcommand] show help doc of subcommand
|
53
|
+
init [url] init MingleMingle working directory with Mingle REST api project base url
|
54
|
+
card [number] show card content by card number
|
55
|
+
cards [params] show cards by params, it will do nothing without params.
|
56
|
+
user [id/login] show user info by id/login
|
57
|
+
view name show cards find by view/tab name
|
58
|
+
run script run transition
|
59
|
+
svncommit(svnci) run transition execution script inside the commit message after committed code(subversion)
|
60
|
+
|
61
|
+
MingleMingle is a tool for integrating Mingle(http://studios.thoughtworks.com/) with command-line
|
62
|
+
For additional information, see http://minglemingle.rubyforge.org
|
63
|
+
Notes:
|
64
|
+
* In the command line, should use \\! instead of !.
|
65
|
+
* There would be a '.mm_pstore' file created for cache in the MingleMingle working directory.
|
66
|
+
}
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|