minglr 1.3.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. data/.document +5 -0
  2. data/.gitignore +3 -0
  3. data/LICENSE +20 -0
  4. data/PostInstall.txt +1 -0
  5. data/README.rdoc +87 -0
  6. data/Rakefile +90 -0
  7. data/VERSION.yml +4 -0
  8. data/bin/minglr +29 -0
  9. data/bin/mtx +14 -0
  10. data/cucumber.yml +2 -0
  11. data/features/cards.feature +27 -0
  12. data/features/step_definitions/minglr_steps.rb +34 -0
  13. data/features/step_definitions/shared_steps.rb +69 -0
  14. data/features/users.feature +6 -0
  15. data/lib/minglr.rb +34 -0
  16. data/lib/minglr/action.rb +85 -0
  17. data/lib/minglr/config_parser.rb +51 -0
  18. data/lib/minglr/extensions/array.rb +23 -0
  19. data/lib/minglr/mtx/input_cache.rb +24 -0
  20. data/lib/minglr/mtx/options_parser.rb +58 -0
  21. data/lib/minglr/options_parser.rb +82 -0
  22. data/lib/minglr/resources/attachment.rb +51 -0
  23. data/lib/minglr/resources/base.rb +42 -0
  24. data/lib/minglr/resources/card.rb +117 -0
  25. data/lib/minglr/resources/project.rb +25 -0
  26. data/lib/minglr/resources/property_definition.rb +12 -0
  27. data/lib/minglr/resources/transition_execution.rb +6 -0
  28. data/lib/minglr/resources/user.rb +19 -0
  29. data/minglr.gemspec +120 -0
  30. data/minglrconfig.sample +37 -0
  31. data/tasks/commit.sample.rake +86 -0
  32. data/tasks/svn.sample.rake +27 -0
  33. data/test/action_test.rb +75 -0
  34. data/test/commands_test.rb +111 -0
  35. data/test/config_parser_test.rb +116 -0
  36. data/test/extensions/array_test.rb +41 -0
  37. data/test/options_parser_test.rb +74 -0
  38. data/test/resources/attachment_test.rb +90 -0
  39. data/test/resources/base_test.rb +58 -0
  40. data/test/resources/card_test.rb +199 -0
  41. data/test/resources/project_test.rb +44 -0
  42. data/test/resources/property_definition_test.rb +25 -0
  43. data/test/resources/user_test.rb +32 -0
  44. data/test/test_helper.rb +31 -0
  45. metadata +219 -0
@@ -0,0 +1,25 @@
1
+ module Resources
2
+
3
+ class Project < Base
4
+
5
+ def self.configure
6
+ self.prefix = self.prefix.split("/")[0...-1].join("/")
7
+ self.site = self.prefix
8
+ end
9
+
10
+ def self.print_all(options = [], status_property = nil)
11
+ attributes = [:name, :description]
12
+ projects = find(:all)
13
+ projects.send(:extend, Minglr::Extensions::Array)
14
+ projects = projects.filter(attributes, options)
15
+
16
+ if projects.any?
17
+ print_collection projects, attributes
18
+ else
19
+ warn "No projects found"
20
+ end
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,12 @@
1
+ module Resources
2
+
3
+ class PropertyDefinition < Base
4
+
5
+ def self.project_options
6
+ properties = find(:all)
7
+ properties.collect { |property| [property.column_name.to_sym, property.name] }
8
+ end
9
+
10
+ end
11
+
12
+ end
@@ -0,0 +1,6 @@
1
+ module Resources
2
+
3
+ class TransitionExecution < Base
4
+ end
5
+
6
+ end
@@ -0,0 +1,19 @@
1
+ module Resources
2
+
3
+ class User < Base
4
+
5
+ def self.print_all(options = [])
6
+ attributes = [:login, :name, :email]
7
+ users = find(:all).collect! { |user| user.user }
8
+ users.send(:extend, Minglr::Extensions::Array)
9
+ users = users.filter(attributes, options)
10
+ if users.any?
11
+ print_collection users, attributes, :right
12
+ else
13
+ warn "No users in project"
14
+ end
15
+ end
16
+
17
+ end
18
+
19
+ end
@@ -0,0 +1,120 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{minglr}
8
+ s.version = "1.3.11"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Michael Schubert", "Stephen Chu", "Chris O'Meara"]
12
+ s.date = %q{2009-09-17}
13
+ s.description = %q{* This gem provides two executable binaries to interact with Mingle (http://mingle.thoughtworks.com/mingle-agile-project-management) through its API. It also has sample interactive Rake task on how to facilitate easy card movements when a card enters/exits the development queue. * mtx is a binary that facilities transition changes for use on rake tasks * minglr is a more interactive tool that provides a quick interface for many common uses}
14
+ s.email = %q{michael@schubert.cx}
15
+ s.executables = ["mtx", "minglr"]
16
+ s.extra_rdoc_files = [
17
+ "LICENSE",
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".gitignore",
23
+ "LICENSE",
24
+ "PostInstall.txt",
25
+ "README.rdoc",
26
+ "Rakefile",
27
+ "VERSION.yml",
28
+ "bin/minglr",
29
+ "bin/mtx",
30
+ "cucumber.yml",
31
+ "features/cards.feature",
32
+ "features/step_definitions/minglr_steps.rb",
33
+ "features/step_definitions/shared_steps.rb",
34
+ "features/users.feature",
35
+ "lib/minglr.rb",
36
+ "lib/minglr/action.rb",
37
+ "lib/minglr/config_parser.rb",
38
+ "lib/minglr/extensions/array.rb",
39
+ "lib/minglr/mtx/input_cache.rb",
40
+ "lib/minglr/mtx/options_parser.rb",
41
+ "lib/minglr/options_parser.rb",
42
+ "lib/minglr/resources/attachment.rb",
43
+ "lib/minglr/resources/base.rb",
44
+ "lib/minglr/resources/card.rb",
45
+ "lib/minglr/resources/project.rb",
46
+ "lib/minglr/resources/property_definition.rb",
47
+ "lib/minglr/resources/transition_execution.rb",
48
+ "lib/minglr/resources/user.rb",
49
+ "minglr.gemspec",
50
+ "minglrconfig.sample",
51
+ "tasks/commit.sample.rake",
52
+ "tasks/svn.sample.rake",
53
+ "test/action_test.rb",
54
+ "test/commands_test.rb",
55
+ "test/config_parser_test.rb",
56
+ "test/extensions/array_test.rb",
57
+ "test/options_parser_test.rb",
58
+ "test/resources/attachment_test.rb",
59
+ "test/resources/base_test.rb",
60
+ "test/resources/card_test.rb",
61
+ "test/resources/project_test.rb",
62
+ "test/resources/property_definition_test.rb",
63
+ "test/resources/user_test.rb",
64
+ "test/test_helper.rb"
65
+ ]
66
+ s.homepage = %q{http://github.com/schubert/minglr}
67
+ s.post_install_message = %q{PostInstall.txt}
68
+ s.rdoc_options = ["--charset=UTF-8"]
69
+ s.require_paths = ["lib"]
70
+ s.rubygems_version = %q{1.3.5}
71
+ s.summary = %q{command line user tool for Mingle (http://mingle.thoughtworks.com/mingle-agile-project-management)}
72
+ s.test_files = [
73
+ "test/action_test.rb",
74
+ "test/commands_test.rb",
75
+ "test/config_parser_test.rb",
76
+ "test/extensions/array_test.rb",
77
+ "test/options_parser_test.rb",
78
+ "test/resources/attachment_test.rb",
79
+ "test/resources/base_test.rb",
80
+ "test/resources/card_test.rb",
81
+ "test/resources/project_test.rb",
82
+ "test/resources/property_definition_test.rb",
83
+ "test/resources/user_test.rb",
84
+ "test/test_helper.rb"
85
+ ]
86
+
87
+ if s.respond_to? :specification_version then
88
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
89
+ s.specification_version = 3
90
+
91
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
92
+ s.add_runtime_dependency(%q<httpclient>, [">= 0"])
93
+ s.add_runtime_dependency(%q<activeresource>, [">= 2.3.0"])
94
+ s.add_runtime_dependency(%q<activesupport>, [">= 2.3.0"])
95
+ s.add_development_dependency(%q<thoughtbot-shoulda>, [">= 0"])
96
+ s.add_development_dependency(%q<mocha>, [">= 0"])
97
+ s.add_development_dependency(%q<relevance-rcov>, [">= 0"])
98
+ s.add_development_dependency(%q<cucumber>, [">= 0"])
99
+ s.add_development_dependency(%q<redgreen>, [">= 0"])
100
+ else
101
+ s.add_dependency(%q<httpclient>, [">= 0"])
102
+ s.add_dependency(%q<activeresource>, [">= 2.3.0"])
103
+ s.add_dependency(%q<activesupport>, [">= 2.3.0"])
104
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
105
+ s.add_dependency(%q<mocha>, [">= 0"])
106
+ s.add_dependency(%q<relevance-rcov>, [">= 0"])
107
+ s.add_dependency(%q<cucumber>, [">= 0"])
108
+ s.add_dependency(%q<redgreen>, [">= 0"])
109
+ end
110
+ else
111
+ s.add_dependency(%q<httpclient>, [">= 0"])
112
+ s.add_dependency(%q<activeresource>, [">= 2.3.0"])
113
+ s.add_dependency(%q<activesupport>, [">= 2.3.0"])
114
+ s.add_dependency(%q<thoughtbot-shoulda>, [">= 0"])
115
+ s.add_dependency(%q<mocha>, [">= 0"])
116
+ s.add_dependency(%q<relevance-rcov>, [">= 0"])
117
+ s.add_dependency(%q<cucumber>, [">= 0"])
118
+ s.add_dependency(%q<redgreen>, [">= 0"])
119
+ end
120
+ end
@@ -0,0 +1,37 @@
1
+ [global]
2
+ default = someproject
3
+ username = yourusername
4
+
5
+ [someproject]
6
+ url = http://your.mingle.host.com/mingle/projects/someproject
7
+ username = yourusername
8
+ password = YOURMINGLEPASSWORD
9
+ delete_property = cp_story_status
10
+ delete_state = Deleted
11
+ status_property = cp_story_status
12
+ story_state_1 = Ready For Development > Sign Up for Story
13
+ story_state_2 = Dev In Progress > Dev Complete
14
+ task_state_1 = New > New to ready for Dev for Task
15
+ task_state_2 = Ready for Development > Dev in Progress
16
+ task_state_3 = Dev In Progress > Story from Dev in Progress to Dev Complete
17
+ story_checkout = story_state_1
18
+ task_checkout = story_state_2
19
+
20
+ # Mingle Project Templates
21
+ # [blank]
22
+ # url = http://localhost:9090/projects/blank
23
+ #
24
+ # [agilehybrid]
25
+ # url = http://localhost:9090/projects/agilehybrid
26
+ # status_property = cp_status
27
+ #
28
+ # [scrum]
29
+ # url = http://localhost:9090/projects/scrum
30
+ # status_property = cp_status
31
+ #
32
+ # [storytracker]
33
+ # url = http://localhost:9090/projects/storytracker
34
+ # status_property = cp_status
35
+ #
36
+ # [xp]
37
+ # url = http://localhost:9090/projects/xp
@@ -0,0 +1,86 @@
1
+ require 'minglr'
2
+
3
+ desc "Run this if you have new code to check in"
4
+ task :check_in => %w( minglr:dev_complete:prepare
5
+ svn:add
6
+ svn:rm
7
+ svn:up
8
+ svn:conflict_check
9
+ db:migrate
10
+ test
11
+ svn:ci
12
+ minglr:dev_complete:transition )
13
+
14
+ namespace :minglr do
15
+ task :prepare do
16
+ @host_port = 'mingle-host:8080' # REPLACE WITH YOUR MINGLE HOST AND PORT
17
+ @project = 'project_4808' # REPLACE WITH YOUR MINGLE PROJECT IDENTIFIER
18
+ end
19
+
20
+ namespace :dev_complete do
21
+ desc "Gather inputs to execute a 'Development Complete' card transition."
22
+ task :prepare => 'minglr:prepare' do
23
+ @transition = 'Transition Uno' # REPLACE WITH THE TRANSITION YOU WANT TO EXECUTE
24
+ @username = prompt 'Please enter your Mingle username', :cache_key => 'username'
25
+ @password = prompt 'Please enter your Mingle password', :secure => true
26
+ @card = prompt 'Please enter a Mingle card number', :cache_key => 'card'
27
+ @commit_message = prompt 'Please enter a commit message', :cache_key => 'commit_message'
28
+ @comment = prompt 'Please enter a comment for the transition', :cache_key => 'transition_comment'
29
+ @properties = ['Actual Effort', 'Property Dos'].inject([]) do |memo, property_name|
30
+ memo << [ %Q|"#{escape(property_name)}"|,
31
+ %Q|"#{prompt(%Q{Please enter the value for the property "#{property_name}"}, :cache_key => property_name)}"|]
32
+ memo
33
+ end.flatten.join(',')
34
+ @story_complete = prompt('Is the story complete? (y/N)', :cache_key => 'story_complete').to_s.downcase == 'y'
35
+ end
36
+
37
+ desc "Executes a 'Development Complete' card transition."
38
+ task :transition => 'minglr:dev_complete:prepare' do
39
+ if @story_complete
40
+ cmd = %Q|#{Minglr::ROOT}/bin/mtx --username "#{@username}" --password "#{@password}" --card "#{@card}" --comment "#{@comment}" --transition "#{@transition}" --properties #{@properties} --host_port "#{@host_port}" --project "#{@project}"|
41
+ `#{cmd}`
42
+ raise "Minglr transition failed with exit status #{$?}." unless $?.success?
43
+ end
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def prompt(message, options = { :secure => false })
50
+ require 'rubygems'
51
+ begin
52
+ require 'password' rescue Exception
53
+ rescue Exception
54
+ @clear_text_password = true
55
+ end
56
+
57
+ user_input = if options[:secure]
58
+ if @clear_text_password
59
+ puts "NOTE: You do not have the 'rb-password' port installed. Perform 'sudo port install rb-password' to avoid your password shown in clear text as you type below."
60
+ print "#{message}: "
61
+ $stdin.gets.chop
62
+ else
63
+ Password.get "#{message}: "
64
+ end
65
+ else
66
+ print "#{message}"
67
+ if cache = MTX::InputCache.get(options[:cache_key])
68
+ print " [#{cache}]"
69
+ end
70
+ print ": "
71
+ $stdin.gets.chop
72
+ end
73
+
74
+ if !options[:secure] && cache_key = options.delete(:cache_key)
75
+ user_input = MTX::InputCache.get(cache_key) if user_input.blank?
76
+ MTX::InputCache.put(cache_key, user_input)
77
+ end
78
+
79
+ user_input = escape(user_input)
80
+ end
81
+
82
+ def escape(user_input)
83
+ user_input.gsub(/["]/, %q{\"}) if user_input
84
+ end
85
+
86
+ end
@@ -0,0 +1,27 @@
1
+ namespace :svn do
2
+ desc "Updates your local WC"
3
+ task :up do
4
+ `svn up`
5
+ end
6
+
7
+ desc "Adds new local WC files"
8
+ task :add do
9
+ `svn st | grep '^?' | xargs svn add`
10
+ end
11
+
12
+ desc "Removes deleted local WC files"
13
+ task :rm do
14
+ `svn st | grep '^!' | xargs svn rm`
15
+ end
16
+
17
+ desc "Check-in your local WC changes"
18
+ task :ci do
19
+ `svn ci -m "#{@commit_message || ENV['commit_message']}"`
20
+ end
21
+
22
+ desc "Checks if your WC has merge conflicts."
23
+ task :conflict_check do
24
+ `svn st | awk '{ if( $1 == "C" ) exit 1}'`
25
+ raise 'You have conflicts!' unless $?.success?
26
+ end
27
+ end
@@ -0,0 +1,75 @@
1
+ require 'test_helper'
2
+
3
+ module Minglr
4
+
5
+ class ActionTest < Test::Unit::TestCase
6
+
7
+ context Action do
8
+
9
+ context "valid_actions" do
10
+
11
+ should "return an array of valid actions" do
12
+ valid_actions = ["users", "cards", "card", "move", "update", "attach", "projects", "create", "fetch"].sort
13
+ assert_equal [], (valid_actions - Action.valid_actions)
14
+ end
15
+
16
+ end
17
+
18
+ context "valid_action?" do
19
+
20
+ should "return true if action is a valid action" do
21
+ assert_equal true, Action.valid_action?("move")
22
+ end
23
+
24
+ should "return false if action is not a valid action" do
25
+ assert_equal false, Action.valid_action?("frobble")
26
+ end
27
+
28
+ end
29
+
30
+ context "execute" do
31
+
32
+ should "ignore the first option if no project is specified" do
33
+ action = :someaction
34
+ options = ["someaction", "option2"]
35
+ flag_options = { :foo => "bar" }
36
+ config = { :foo => "bar" }
37
+
38
+ Minglr::Action::Commands.expects(:send).with(action, ["option2"], flag_options, config)
39
+ Action.execute(action, options, flag_options, config)
40
+ end
41
+
42
+ should "ignore the first two options if project is specified" do
43
+ action = :someaction
44
+ options = ["someproject", "someaction", "option2"]
45
+ flag_options = { :foo => "bar" }
46
+ config = { :foo => "bar" }
47
+
48
+ Minglr::Action::Commands.expects(:send).with(action, ["option2"], flag_options, config)
49
+ Action.execute(action, options, flag_options, config)
50
+ end
51
+
52
+ should "send the action to commands" do
53
+ action = "someaction"
54
+ options = ["option1", "option2"]
55
+ flag_options = { :foo => "bar" }
56
+ config = { :foo => "bar" }
57
+
58
+ Minglr::Action::Commands.expects(:send).with(action, options, flag_options, config)
59
+ Action.execute(action, options, flag_options, config)
60
+ end
61
+
62
+ should "rescue and print an error if the resource can't be found" do
63
+ Action.expects(:puts).with("Failed with MyError for URL '#{Resources::Base.site}' ...")
64
+ Minglr::Action::Commands.expects(:send).raises(ActiveResource::ResourceNotFound, stub("Response", :code => "MyError"))
65
+
66
+ Action.execute("someaction", ["someaction"])
67
+ end
68
+
69
+ end
70
+
71
+ end
72
+
73
+ end
74
+
75
+ end
@@ -0,0 +1,111 @@
1
+ require 'test_helper'
2
+
3
+ module Minglr
4
+
5
+ class CommandsTest < Test::Unit::TestCase
6
+
7
+ context Action::Commands do
8
+
9
+ setup do
10
+ @options = []
11
+ @flag_options = {}
12
+ @config = { :status_property => "cp_status", :username => "user", :password => "password" }
13
+ end
14
+
15
+ context "attach" do
16
+
17
+ should "parse card number and file number as options and call resource" do
18
+ @options << "1"
19
+ @flag_options[:file_attachment] = "file"
20
+
21
+ Resources::Attachment.expects(:attach).with("1", "file", "user", "password")
22
+ Action::Commands.attach(@options, @flag_options, @config)
23
+ end
24
+
25
+ end
26
+
27
+ context "card" do
28
+
29
+ should "parse card number and call resource" do
30
+ @options << "1"
31
+
32
+ Resources::Card.expects(:print_card).with("1", "cp_status")
33
+ Action::Commands.card(@options, @flag_options, @config)
34
+ end
35
+
36
+ end
37
+
38
+ context "cards" do
39
+
40
+ should "call resource" do
41
+ Resources::Card.expects(:print_all).with(@options, "cp_status")
42
+ Action::Commands.cards(@options, @flag_options, @config)
43
+ end
44
+
45
+ end
46
+
47
+ context "create" do
48
+
49
+ should "call resource" do
50
+ Resources::Card.expects(:create).with(@flag_options, "cp_status")
51
+ Action::Commands.create(@options, @flag_options, @config)
52
+ end
53
+
54
+ end
55
+
56
+ context "fetch" do
57
+
58
+ should "parse card number and call resource" do
59
+ @options << "1"
60
+
61
+ Resources::Attachment.expects(:fetch).with("1", "user", "password")
62
+ Action::Commands.fetch(@options, @flag_options, @config)
63
+ end
64
+
65
+ end
66
+
67
+ context "move" do
68
+
69
+ should "parse card number and call resource" do
70
+ @options << "1"
71
+
72
+ Resources::Card.expects(:move).with("1", @flag_options, @config)
73
+ Action::Commands.move(@options, @flag_options, @config)
74
+ end
75
+
76
+ end
77
+
78
+ context "projects" do
79
+
80
+ should "call resource" do
81
+ Resources::Project.expects(:print_all).with(@options, "cp_status")
82
+ Action::Commands.projects(@options, @flag_options, @config)
83
+ end
84
+
85
+ end
86
+
87
+ context "update" do
88
+
89
+ should "parse card number and call resource" do
90
+ @options << "1"
91
+
92
+ Resources::Card.expects(:update).with("1", @flag_options)
93
+ Action::Commands.update(@options, @flag_options, @config)
94
+ end
95
+
96
+ end
97
+
98
+ context "users" do
99
+
100
+ should "call resource" do
101
+ Resources::User.expects(:print_all).with(@options)
102
+ Action::Commands.users(@options, @flag_options, @config)
103
+ end
104
+
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+
111
+ end