minglemingle 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGES CHANGED
@@ -1,4 +1,12 @@
1
1
  = MingleMingle Changelog
2
+
3
+ * release 0.0.2:
4
+ * read options from local environment variables name of which are started with 'MM_', e.g. an environment variable 'MM_NUMBER=102', it would be a default card number instead of cached one and you can always overwrite it by specifying a card number in command line. Type 'mm help <subcommand>' to see environment options of each command.
5
+ * run a transition script template stored in an environment variable by template name
6
+ * transition script is able to parse variable which is specified by #{variable_name}. MingleMingle will try to find the variable from options.
7
+ * changed card option -a to access multi attributes, and always display card summarization even specified attributes
8
+ * removed noise part of transition script from svn commit message, e.g. "[fixed #1 with revision => #{revision}]blah..." => "fixed #1: blah..."
9
+
2
10
  * release 0.0.1: fit with Mingle 2.0 REST API
3
11
 
4
12
 
data/README CHANGED
@@ -2,15 +2,15 @@
2
2
 
3
3
  Supporting MingleMingle version: 0.0.x
4
4
 
5
- This package contains MingleMingle, a Mingle command line tool based on the Mingle REST api.
5
+ This package contains MingleMingle, a Mingle command line tool based on the Mingle REST API. (The name is came from a cartoon book named "Hunter Hunter":)
6
6
 
7
7
  MingleMingle has the following features integrating with Mingle:
8
8
 
9
- * run transition
10
- * show card
11
- * show card list view
12
- * show team member info
13
- * commit code with running transition
9
+ * run transition => mm run ...
10
+ * show card => mm card number
11
+ * show card list view => mm cards ... | mm view name
12
+ * show team member info => mm user id/login
13
+ * commit code with running transition => mm svnci ....
14
14
 
15
15
  == Download
16
16
 
data/TODO CHANGED
@@ -3,12 +3,4 @@
3
3
  Send suggestions for this list to swing1979@gmail.com
4
4
 
5
5
  === To Do
6
- ? get card transitions
7
6
  (moved DONE list to CHANGES file)
8
- ! add a revision option for auto adding revision number into trnasition when run svncommit command
9
- ! get cards specified by a card list view name
10
- ! don't show password when output init project url
11
- ! display card name and description as default when get a card, and add a display all option
12
- ! get card by number
13
- ! execute transition on one card by script
14
- ! integrate executing transition with svn commit command
data/lib/mm.rb CHANGED
@@ -28,7 +28,7 @@ require 'mm/cmds/view'
28
28
  require 'mm/cmds/help'
29
29
 
30
30
  module MM
31
- VERSION="0.0.1"
31
+ VERSION="0.0.2"
32
32
 
33
33
  module API
34
34
  def team_members
@@ -30,7 +30,10 @@ module MM
30
30
  end
31
31
 
32
32
  def options
33
- @options ||= Repository.new[self.class.name] || {}
33
+ return @options if @options
34
+ @options = Repository.new[self.class.name] || {}
35
+ ENV.keys.each { |key| @options[$1.downcase.to_sym] = ENV[key] if key =~ /^mm_(.+)/i }
36
+ @options
34
37
  end
35
38
 
36
39
  def parse(argv)
@@ -50,29 +53,45 @@ module MM
50
53
  return
51
54
  elsif message.is_a?(String)
52
55
  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
+ elsif options[:attrs]
57
+ attributes = if options[:attrs].is_a?(String)
58
+ options[:attrs].split(',')
56
59
  else
57
- message.send(options[:attr])
60
+ options[:attrs]
61
+ end
62
+ attributes.each do |attr_name|
63
+ attr_name = attr_name.strip
64
+ column_name = if pd = property_definitions.find{|pd| pd.name.downcase == attr_name.downcase}
65
+ pd.column_name
66
+ else
67
+ attr_name
68
+ end
69
+ output(" * #{attr_name}: #{display_value(column_name, message.send(column_name))}")
58
70
  end
59
- output(" * #{options[:attr]}: #{value}")
60
71
  else
61
72
  output(message.to_yaml)
62
73
  end
63
74
  end
64
75
 
65
- def property_value(pd, card)
66
- obj_value = card.send(pd.column_name)
76
+ def display_value(column_name, obj_value)
67
77
  case
68
- when pd.card_property?(obj_value)
78
+ when card_property?(column_name, obj_value)
69
79
  find_card(:id => obj_value).short_summarization
70
- when pd.user_property?(obj_value)
80
+ when user_property?(column_name, obj_value)
71
81
  team_members.find{|u|u.id==obj_value}.name
72
82
  else
73
83
  obj_value
74
84
  end
75
85
  end
86
+
87
+ def card_property?(column_name, obj_value)
88
+ obj_value.to_i > 0 && column_name =~ /card_id$/
89
+ end
90
+
91
+ def user_property?(column_name, obj_value)
92
+ obj_value.to_i > 0 && column_name =~ /user_id$/
93
+ end
94
+
76
95
  end
77
96
  end
78
97
  end
@@ -17,15 +17,15 @@ module MM
17
17
  module Command
18
18
  class Card < AbstractCommand
19
19
  def view(card)
20
- if options[:attr] || options[:show_all]
20
+ super(card.summarization) unless options[:show_all]
21
+ if options[:attrs] || options[:show_all]
21
22
  super(card)
22
- else
23
- super(card.summarization)
24
23
  end
25
24
  end
26
25
 
27
26
  def do_once
28
27
  output "card number => #{options[:number]}"
28
+ output "attributes => #{options[:attrs].inspect}" if options[:attrs]
29
29
  find_card_by_number(options[:number])
30
30
  end
31
31
 
@@ -37,14 +37,19 @@ module MM
37
37
  OptionParser.new do |opts|
38
38
  opts.banner = "usage: mm card <card_number>"
39
39
  opts.separator ""
40
+ opts.separator "Environment variable options:"
41
+ opts.separator " MM_NUMBER => card number used to find the card"
42
+ opts.separator " MM_ATTRS => card attributes need to show with card"
43
+ opts.separator " MM_SHOW_ALL => show all card attributes"
44
+ opts.separator ""
40
45
  opts.separator "Synopsis:"
41
46
  opts.separator "mm card 1 => find card by card number 1 and show all attributes"
42
47
  opts.separator "mm card 1 -a description => find card by card number 1 and show its description"
43
48
  opts.separator ""
44
49
  opts.separator "Options:"
45
50
 
46
- opts.on_tail("-a", "--attribute ATTR_NAME", "show specified attribute value") do |attr_name|
47
- options[:attr] = attr_name
51
+ opts.on("-a att_name1,attr_name2", Array, "show specified attribute value.") do |names|
52
+ options[:attrs] = names
48
53
  end
49
54
 
50
55
  opts.on_tail("-s", "--show_all", "show all card attributes") do
@@ -21,17 +21,15 @@ module MM
21
21
  output '----------'
22
22
  output card.short_summarization
23
23
  if options[:attrs]
24
- options[:attrs].each do |attr_name|
25
- options[:attr] = attr_name
26
- output card
27
- end
24
+ output(card)
28
25
  end
29
26
  end
30
27
  end
31
28
 
32
29
  def do_once
33
- output "card list params => #{options.inspect}"
34
- find_cards(options)
30
+ params = options.reject{|key, value| key.to_s=~/^transition_script_template/}
31
+ output "card list params => #{params.inspect}"
32
+ find_cards(params)
35
33
  end
36
34
 
37
35
  def parse(argv)
@@ -43,6 +41,10 @@ module MM
43
41
  OptionParser.new do |opts|
44
42
  opts.banner = "usage: mm cards [options]"
45
43
  opts.separator ""
44
+ opts.separator "Environment variable options:"
45
+ opts.separator " MM_ATTRS => attributes want to be displayed"
46
+ opts.separator " Could be any param's name with 'MM' started, e.g. MM_VIEW='favorite name', MM_PAGE=1"
47
+ opts.separator ""
46
48
  opts.separator "Synopsis:"
47
49
  opts.separator "mm cards \"{:view => 'favorite/tab name'}\" => find cards by favorite's/tab's name"
48
50
  opts.separator "mm cards \"{:view => 'favorite/tab name', :page => 2}\" => find cards in the page 2 by favorite's/tab's name"
@@ -36,7 +36,7 @@ module MM
36
36
  mingle mingle, version #{MM::VERSION}
37
37
  Type 'mm help <subcommand>' for help on a specific subcommand.
38
38
 
39
- Queck start:
39
+ Queck start part 1:
40
40
  * Suppose I am working on a project pet_store checked out at '~/pet_store'.
41
41
  * cd ~/pet_store
42
42
  * mm init http://my_login:password@mingle_server/projects/pet_store
@@ -44,10 +44,23 @@ Queck start:
44
44
  * mm view My Work -a owner,priority => list cards on card list view named 'My Work' including property owner and priority
45
45
  * mm card 102 => show name and description of the card
46
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 []
47
+ * mm svnci -m "[complete fix #1 with 'fixed revision' => \#{revision}, resolution => fixed (some comment)] blabla..." => commit code and run transition script inside of []
48
48
  * mm view => show view cached which is 'My Work' with property 'owner' and 'priority' by last time using view command
49
49
  * mm card => show card cached number of which is 102 by last time using card command
50
50
 
51
+ Queck start part 2:
52
+ * export MM_NUMBER=103 => setup my working card number
53
+ * export MM_ATTRS=priority,created_by_user_id
54
+ => setup attributes want to be displayed whenever showing a card. 'created_by_user_id' is not a custom property definition but you'll see the user name instead of id in this case, and it's same with 'Created by' column in the card list view.
55
+ * mm card
56
+ => show the working card summarization and attributes owner and priority which are just setup.
57
+ * export MM_TRANSITION_SCRIPT_TEMPLATE_COMPLETE_FIX="complete fix #\#{number} with 'fixed revision' => \#{revision}, resolution => fixed"
58
+ => setup a transition script template named 'complete fix'
59
+ * mm svnci -m "[complete fix] blabla..."
60
+ => commit code and run transition script template named 'complete fix', the number variable would be found in the environment which is MM_NUMBER=103
61
+ * mm svnci -m "[complete fix] blabla..." -n 105
62
+ => commit code and run transition script template named 'complete fix', card number is 105 instead of current working card number
63
+
51
64
  Available subcommands:
52
65
  help [subcommand] show help doc of subcommand
53
66
  init [url] init MingleMingle working directory with Mingle REST api project base url
@@ -33,6 +33,9 @@ module MM
33
33
  %{
34
34
  usage: mm init [site_url]
35
35
 
36
+ environment variable options:
37
+ MM_SITE => the Mingle REST API project base url
38
+
36
39
  Synopsis:
37
40
  mm init => show MingleMingle working directory settings.
38
41
  mm init http://name:pass@domain.com/projects/project_identifiler/ => setup MingleMingle working directory with Mingle REST api project base url.
@@ -17,9 +17,32 @@ require 'mm/cmds/abstract_command'
17
17
  module MM
18
18
  module Command
19
19
  class Run < AbstractCommand
20
+ def parse_template
21
+ if template = options["TRANSITION_SCRIPT_TEMPLATE_#{options[:script].gsub(/ /, '_')}".downcase.to_sym]
22
+ options[:script] = template
23
+ end
24
+ end
25
+
26
+ def parse_variables
27
+ options.keys.each do |key|
28
+ if options[:script] =~ /\{#{key}\}/
29
+ options[:script] = if key == :number
30
+ options[:script].gsub(/#?#\{#{key}\}/, "##{options[key]}")
31
+ else
32
+ options[:script].gsub(/#\{#{key}\}/, options[key])
33
+ end
34
+ end
35
+ end
36
+ end
37
+
38
+ def parse_script
39
+ parse_template
40
+ parse_variables
41
+ end
42
+
20
43
  def do_once
44
+ parse_script
21
45
  output "script => #{options[:script]}"
22
-
23
46
  attrs = ::TransitionExecutionLanguageParser.new.parse(options[:script])
24
47
  output "attrs => #{attrs.inspect}"
25
48
  attrs[:properties] = attrs[:properties].collect{|key, value| {:name => key, :value => value}} if attrs[:properties]
@@ -39,13 +62,20 @@ module MM
39
62
  usage: mm run <transition_script>
40
63
 
41
64
  transition script grammar:
42
- <transition name> #<card_number>[options]
65
+ <transition name> #<card_number> [options]
43
66
  options:
44
67
  1. with <properties>: properties: prop_name1 => prop_value1, prop_name2 => prop_value2
45
68
  2. (<comment>): comment: should be ok for any words except '(' and ')'
46
69
 
70
+ Environment variable options:
71
+ Any variable name start with 'MM_TRANSITION_SCRIPT_TEMPLATE_' would be handled as a transition script template. The string following the prefix would be template name, e.g. MM_TRANSITION_SCRIPT_TEMPLATE_FIX means a transition script template named 'fix'. You can specify a template name to run the transition, and MingleMingle also would help you to fill options into the template by same name, e.g. MM_TRANSITION_SCRIPT_TEMPLATE_FIX='Fix #\#{number} with resolution => fixed', MingleMingle would look for option named number in the options which is get from another environment variable MM_NUMBER=102. So type in 'mm run fix' would be translated to 'Fix #102 with fixed_revision => fixed'
72
+
47
73
  Synopsis:
48
- mm run 'complete development #1 with revision => 100, status => open (some comment)'
74
+ mm run 'complete fix #1 with revision => 100, status => open (some comment)'
75
+ mm run fix => run template named fix, you need setup environment variable
76
+
77
+ Notes:
78
+ * You can specify variable in the transition script by \#{variable name}, MingleMingle will look for variable in the environment variable. For example, set up environment variable: export MM_NUMBER=105, then transition script 'Start fix \#{number}' would be parsed as 'Start fix #105'.
49
79
  }
50
80
  end
51
81
 
@@ -16,25 +16,47 @@ require 'mm/cmds/run'
16
16
  module MM
17
17
  module Command
18
18
  class Svncommit < AbstractCommand
19
- TRANSITION_EXECUTION_SCRIPT_REGEX = /\[([^\]]+)\]/
19
+ TRANSITION_EXECUTION_SCRIPT_REGEX = /\[([^\]]+)\](.*)/
20
+
21
+ def self.parse_commit_message(msg)
22
+ if msg =~ /\[(.+) with .+\](.*)/
23
+ "#{$1}#{": #{$2.strip}" unless $2.blank?}"
24
+ elsif msg =~ /\[(.+)\](.*)/
25
+ "#{$1}#{": #{$2.strip}" unless $2.blank?}"
26
+ else
27
+ msg
28
+ end
29
+ end
20
30
 
21
31
  def do_once
22
- cmd = "svn ci #{svncmd_opts.join(' ')} -m #{options[:message].inspect}"
23
- output "svn command: #{cmd}"
24
- svnci = execute_cmd(cmd)
25
- output svnci
26
- if $?.exitstatus == 0
27
- revision = svnci.split("\n").last.gsub(/[^0-9]/, '')
28
- output "revision: #{revision}"
29
- options[:message].gsub!(/#\{revision\}/, revision)
30
- if options[:message] =~ TRANSITION_EXECUTION_SCRIPT_REGEX
31
- run = Run.new
32
- run.options[:script] = $1
32
+ if options[:message] =~ TRANSITION_EXECUTION_SCRIPT_REGEX
33
+ run = Run.new
34
+ run.options[:script] = $1
35
+ p "options[:number]: #{options[:number]}"
36
+ run.options[:number] = options[:number] if options[:number]
37
+ run.parse_script
38
+ options[:message] = "[#{run.options[:script]}] #{$2}"
39
+ svnci_output = svn_ci
40
+ if $?.exitstatus == 0
41
+ revision = svnci_output.split("\n").last.gsub(/[^0-9]/, '')
42
+ output "revision: #{revision}"
43
+ run.options[:revision] = revision
33
44
  run.do_once
34
45
  end
46
+ else
47
+ svn_ci
35
48
  end
36
49
  end
37
50
 
51
+ def svn_ci
52
+ commit_message = self.class.parse_commit_message(options[:message])
53
+ cmd = "svn ci #{svncmd_opts.join(' ')} -m #{commit_message.inspect}"
54
+ output "svn command: #{cmd}"
55
+ svnci_output = execute_cmd(cmd)
56
+ output svnci_output
57
+ svnci_output
58
+ end
59
+
38
60
  #don't want to cache options of this command
39
61
  def cache_options
40
62
  end
@@ -49,18 +71,27 @@ module MM
49
71
 
50
72
  def option_parser
51
73
  OptionParser.new do |opts|
52
- opts.banner = "usage: mm svnci -m '[<transition_script>] other commit messages' [other svn options] [args]"
74
+ opts.banner = "usage: mm svnci -m '[<transition_script>] commit message' [other svn options] [args]"
75
+ opts.separator ""
76
+ opts.separator "WARNING: '[' AND ']' SHOULD ONLY BE USED TO SPECIFY TRANSITION SCRIPT!"
77
+ opts.separator ""
53
78
  opts.separator "transition script: should be inside of '[' and ']'. Type 'mm help run' for help on transition script grammar. "
79
+ opts.separator ""
54
80
  opts.separator 'specify a #{revision} in the message to run the transition with revision commited number'
81
+ opts.separator 'noise part of transition script would be removed from commit message, e.g. "[fixed #1 with revision => #{revision}]blah..." => "fixed #1: blah..."'
55
82
  opts.separator ""
56
83
  opts.separator "Synopsis:"
57
- opts.separator 'mm svnci -m "[complete development #1 with fixed_revision => #{revision}, status => closed (some comment)]: details, blabla..."'
84
+ opts.separator 'mm svnci -m "[complete fix #1 with fixed_revision => #{revision}, status => closed (some comment)]: details, blabla..."'
58
85
  opts.separator ""
59
86
  opts.separator "Options:"
60
87
 
61
88
  opts.on_tail("-m", "--message MESSAGE", "specify log message ARG") do |message|
62
89
  options[:message] = message
63
90
  end
91
+
92
+ opts.on_tail("-n", "--number CARD_NUMBER", "specify card number") do |number|
93
+ options[:number] = number
94
+ end
64
95
  end
65
96
  end
66
97
  end
@@ -30,6 +30,9 @@ module MM
30
30
  %{
31
31
  usage: mm user [login/user id]
32
32
 
33
+ Environment variable options:
34
+ MM_USER => user id/login used to find the user info
35
+
33
36
  Synopsis:
34
37
  mm user 'login' => find team member info by login
35
38
  mm user id => find team member info by id
@@ -24,6 +24,9 @@ module MM
24
24
  %{
25
25
  usage: mm view <view_name>
26
26
 
27
+ Environment variable options:
28
+ MM_VIEW => view name used to show cards, setup it as your working queue.
29
+
27
30
  Synopsis:
28
31
  mm view My Work => show cards in the view
29
32
  mm view My Work -a priority,owner => show cards in the view with attributes specified
@@ -36,13 +36,6 @@ module MM
36
36
  end
37
37
 
38
38
  class PropertyDefinition < ActiveResource::Base
39
- def card_property?(obj_value)
40
- obj_value.to_i > 0 && column_name =~ /card_id$/
41
- end
42
-
43
- def user_property?(obj_value)
44
- obj_value.to_i > 0 && column_name =~ /user_id$/
45
- end
46
39
  end
47
40
 
48
41
  class Project < ActiveResource::Base
@@ -3,6 +3,7 @@ require File.dirname(__FILE__) + '/test_helper'
3
3
  class AbstractCommandTest < Test::Unit::TestCase
4
4
 
5
5
  def setup
6
+ ENV.delete_if{|k,v| k=~/^MM_/}
6
7
  MM::Repository.destroy rescue nil
7
8
  end
8
9
 
@@ -28,4 +29,9 @@ class AbstractCommandTest < Test::Unit::TestCase
28
29
  card_cmd.cache_options
29
30
  assert_equal({}, MM::Command::User.new.options)
30
31
  end
32
+
33
+ def test_load_mm_options_from_env
34
+ ENV['MM_NUMBER'] = '10'
35
+ assert_equal({:number => '10'}, MM::Command::Card.new.options)
36
+ end
31
37
  end
@@ -0,0 +1,32 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AbstractCommandTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ ENV.delete_if{|k,v| k=~/^MM_/}
7
+ MM::Repository.destroy rescue nil
8
+ end
9
+
10
+ def teardown
11
+ MM::Repository.destroy rescue nil
12
+ end
13
+
14
+ def test_run_with_script_template_stored_in_environment
15
+ ENV['MM_TRANSITION_SCRIPT_TEMPLATE_START_FIX'] = 'Start fix ##{number} with property => #{value}'
16
+ ENV['MM_NUMBER'] = '102'
17
+ ENV['MM_VALUE'] = 'mm_value'
18
+ run = MM::Command::Run.new
19
+ run.parse(['start', 'fix'])
20
+ run.do_once
21
+ assert_equal ["create_transition_execution", {:card=>"102", :comment=>nil, :transition=>"Start fix", :properties=>[{:value=>"mm_value", :name=>"property"}]}], run.run_apis.first
22
+ end
23
+
24
+ def test_script_template_doesnt_need_sharp_for_card_number
25
+ ENV['MM_TRANSITION_SCRIPT_TEMPLATE_START_FIX'] = 'Start fix #{number}'
26
+ ENV['MM_NUMBER'] = '102'
27
+ run = MM::Command::Run.new
28
+ run.parse(['start', 'fix'])
29
+ run.do_once
30
+ assert_equal ["create_transition_execution", {:card=>"102", :comment=>nil, :transition=>"Start fix", :properties => nil}], run.run_apis.first
31
+ end
32
+ end
@@ -0,0 +1,21 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AbstractCommandTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ ENV.delete_if{|k,v| k=~/^MM_/}
7
+ MM::Repository.destroy rescue nil
8
+ end
9
+
10
+ def teardown
11
+ MM::Repository.destroy rescue nil
12
+ end
13
+
14
+ def test_parse_commit_message
15
+ assert_equal "complete fix #1: blah", MM::Command::Svncommit.parse_commit_message('[complete fix #1 with revision => #{revision}]blah')
16
+ assert_equal "complete fix #1: blah", MM::Command::Svncommit.parse_commit_message('[complete fix #1]blah')
17
+ assert_equal "complete fix #1", MM::Command::Svncommit.parse_commit_message('[complete fix #1]')
18
+ assert_equal "complete fix #1: blah", MM::Command::Svncommit.parse_commit_message('[complete fix #1] blah')
19
+ assert_equal "blah", MM::Command::Svncommit.parse_commit_message('blah')
20
+ end
21
+ end
@@ -24,3 +24,55 @@ module Test
24
24
  end
25
25
  end
26
26
  end
27
+
28
+ module MM
29
+
30
+ module APIStub
31
+ def run_apis
32
+ @run_apis ||= []
33
+ end
34
+ def team_members
35
+ run_apis << 'team_members'
36
+ []
37
+ end
38
+
39
+ def property_definitions
40
+ run_apis << 'property_definitions'
41
+ []
42
+ end
43
+
44
+ def favorites
45
+ run_apis << 'favorites'
46
+ []
47
+ end
48
+
49
+ def create_transition_execution(attrs)
50
+ run_apis << ['create_transition_execution', attrs]
51
+ end
52
+
53
+ def find_card(options)
54
+ run_apis << ['find_card', options]
55
+ nil
56
+ end
57
+
58
+ def find_card_by_number(number)
59
+ run_apis << ['find_card_by_number', number]
60
+ nil
61
+ end
62
+
63
+ def find_cards(options)
64
+ run_apis << ['find_cards', options]
65
+ []
66
+ end
67
+
68
+ def init(klass=nil)
69
+ run_apis << ['init', klass]
70
+ end
71
+
72
+ def execute_cmd(cmd)
73
+ run_apis << ["execute_cmd", cmd]
74
+ end
75
+ end
76
+ end
77
+
78
+ MM::Command::AbstractCommand.send(:include, MM::APIStub)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minglemingle
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Li Xiao
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-04-18 00:00:00 +08:00
12
+ date: 2008-04-23 00:00:00 +08:00
13
13
  default_executable: mm
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -54,6 +54,8 @@ files:
54
54
  - lib/mm/utils.rb
55
55
  - lib/mm.rb
56
56
  - test/abstract_command_test.rb
57
+ - test/run_test.rb
58
+ - test/svncommit_test.rb
57
59
  - test/test_helper.rb
58
60
  - doc/jamis.rb
59
61
  has_rdoc: true