schubert-minglr 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +2 -0
- data/VERSION.yml +2 -2
- data/bin/minglr +11 -11
- data/bin/mtx +1 -1
- data/lib/minglr.rb +18 -10
- data/lib/minglr/action.rb +75 -0
- data/lib/minglr/config_parser.rb +49 -0
- data/lib/minglr/extensions/array.rb +23 -0
- data/lib/minglr/input_cache.rb +3 -3
- data/lib/minglr/options_parser.rb +79 -0
- data/lib/minglr/resources/attachment.rb +46 -0
- data/lib/minglr/resources/base.rb +42 -0
- data/lib/minglr/resources/card.rb +107 -0
- data/lib/minglr/resources/project.rb +25 -0
- data/lib/minglr/resources/property_definition.rb +12 -0
- data/lib/minglr/resources/transition_execution.rb +6 -0
- data/lib/minglr/resources/user.rb +25 -0
- data/minglr.gemspec +30 -28
- data/minglrconfig.sample +19 -0
- data/test/extensions/array_test.rb +41 -0
- data/test/resources/attachment_test.rb +40 -0
- data/test/resources/base_test.rb +45 -0
- data/test/resources/card_test.rb +89 -0
- data/test/resources/project_test.rb +26 -0
- data/test/resources/property_definition_test.rb +25 -0
- data/test/resources/user_test.rb +39 -0
- data/test/test_helper.rb +15 -5
- metadata +27 -15
- data/lib/minglr/attachment.rb +0 -7
- data/lib/minglr/card.rb +0 -2
- data/lib/minglr/mingle_resource.rb +0 -5
- data/lib/minglr/minglr_action.rb +0 -200
- data/lib/minglr/minglr_config_parser.rb +0 -44
- data/lib/minglr/minglr_options_parser.rb +0 -70
- data/lib/minglr/property_definition.rb +0 -2
- data/lib/minglr/transition_execution.rb +0 -2
- data/lib/minglr/user.rb +0 -2
- data/test/attachment_test.rb +0 -24
- data/test/minglr_resource_test.rb +0 -24
@@ -0,0 +1,107 @@
|
|
1
|
+
module Resources
|
2
|
+
|
3
|
+
class Card < Base
|
4
|
+
|
5
|
+
def self.create(options = {}, status_property = nil)
|
6
|
+
options.merge!({status_property.to_sym => "New"}) if status_property
|
7
|
+
card = self.new(options)
|
8
|
+
if card.save
|
9
|
+
card.reload
|
10
|
+
puts "Card #{card.number} created"
|
11
|
+
else
|
12
|
+
warn "Unable to create card"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.move(card_number, options = {}, config = {})
|
17
|
+
if card_to_move = find(card_number)
|
18
|
+
transition_options = { :card => card_number }
|
19
|
+
transition_options.merge!({ :comment => options[:comment]}) if options[:comment]
|
20
|
+
current_status = card_to_move.send(config[:status_property]) if config[:status_property]
|
21
|
+
next_transition = nil
|
22
|
+
|
23
|
+
card_type = card_to_move.card_type_name.downcase
|
24
|
+
case card_type
|
25
|
+
when /defect/
|
26
|
+
status_states = config.select do |key, value|
|
27
|
+
key.to_s =~ /^defect/
|
28
|
+
end
|
29
|
+
when /task/
|
30
|
+
status_states = config.select do |key, value|
|
31
|
+
key.to_s =~ /^task_state_/
|
32
|
+
end
|
33
|
+
when /story/
|
34
|
+
status_states = config.select do |key, value|
|
35
|
+
key.to_s =~ /^story_state/
|
36
|
+
end
|
37
|
+
else
|
38
|
+
puts "No transitions defined for card of type #{card_to_move.card_type_name}"
|
39
|
+
end
|
40
|
+
status_states = status_states.collect {|state| state.last }.collect {|state| state.split(">").collect { |value| value.strip } }
|
41
|
+
next_transition = status_states.select {|state| state.first.downcase == current_status.downcase }.first.last
|
42
|
+
transition_options.merge!({ :transition => next_transition })
|
43
|
+
|
44
|
+
if response = TransitionExecution.create(transition_options)
|
45
|
+
if response.attributes["status"] == "completed"
|
46
|
+
puts "Moved card from #{current_status} to #{next_transition}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
else
|
50
|
+
warn "No card #{card_number} found to move"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.print_all(options = [], status_property = nil)
|
55
|
+
attributes = [:number, :card_type_name, status_property, :name].compact
|
56
|
+
cards = Resources::Card.find(:all)
|
57
|
+
cards.send(:extend, Minglr::Extensions::Array)
|
58
|
+
cards = cards.filter(attributes, options)
|
59
|
+
if cards.any?
|
60
|
+
print_collection(cards, attributes)
|
61
|
+
else
|
62
|
+
warn "No cards found"
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.print_card(card_number, status_property = nil)
|
67
|
+
attributes = [:number, :card_type_name, status_property, :name, :description].compact
|
68
|
+
if card = find(card_number)
|
69
|
+
puts card.to_s(status_property)
|
70
|
+
else
|
71
|
+
warn "No card ##{card_number} found"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.update(card_number, options = {})
|
76
|
+
if card_to_update = find(card_number)
|
77
|
+
options.each do |attribute, value|
|
78
|
+
card_to_update.send("#{attribute.to_s}=".to_sym, value)
|
79
|
+
end
|
80
|
+
card_to_update.save
|
81
|
+
puts "Card #{card_to_update.number} updated\n\n"
|
82
|
+
puts card.to_s
|
83
|
+
else
|
84
|
+
warn "Unable to update card #{card_number}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def to_s(status_property = nil)
|
89
|
+
attachments = Resources::Attachment.find(:all, :params => { :card_number => number })
|
90
|
+
attachments = attachments.collect do |attachment|
|
91
|
+
"* #{attachment.file_name}: #{Resources::Base.site + attachment.url}"
|
92
|
+
end
|
93
|
+
output = <<-EOS
|
94
|
+
Number: #{number}
|
95
|
+
Name: #{name}
|
96
|
+
Type: #{card_type_name}
|
97
|
+
Status: #{send(status_property) if status_property}
|
98
|
+
Description: #{description}
|
99
|
+
|
100
|
+
Attachments:
|
101
|
+
#{attachments.join("\n")}
|
102
|
+
EOS
|
103
|
+
output
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
@@ -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,25 @@
|
|
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
|
+
def self.find_user_id_for_user(user)
|
18
|
+
if user = Resources::User.find(:all).select { |user| user.user.login == user }.first
|
19
|
+
user.user_id
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/minglr.gemspec
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
1
|
Gem::Specification.new do |s|
|
4
2
|
s.name = %q{minglr}
|
5
|
-
s.version = "1.
|
3
|
+
s.version = "1.2.0"
|
4
|
+
|
5
|
+
s.specification_version = 2 if s.respond_to? :specification_version=
|
6
6
|
|
7
7
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
8
|
s.authors = ["Michael Schubert", "Stephen Chu", "Chris O'Meara"]
|
9
|
-
s.date = %q{2009-07-
|
9
|
+
s.date = %q{2009-07-26}
|
10
10
|
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}
|
11
11
|
s.email = %q{michael@schubert.cx}
|
12
12
|
s.executables = ["mtx", "minglr"]
|
@@ -25,23 +25,30 @@ Gem::Specification.new do |s|
|
|
25
25
|
"bin/minglr",
|
26
26
|
"bin/mtx",
|
27
27
|
"lib/minglr.rb",
|
28
|
-
"lib/minglr/
|
29
|
-
"lib/minglr/
|
28
|
+
"lib/minglr/action.rb",
|
29
|
+
"lib/minglr/config_parser.rb",
|
30
|
+
"lib/minglr/extensions/array.rb",
|
30
31
|
"lib/minglr/input_cache.rb",
|
31
|
-
"lib/minglr/mingle_resource.rb",
|
32
|
-
"lib/minglr/minglr_action.rb",
|
33
|
-
"lib/minglr/minglr_config_parser.rb",
|
34
|
-
"lib/minglr/minglr_options_parser.rb",
|
35
32
|
"lib/minglr/mtx_options_parser.rb",
|
36
|
-
"lib/minglr/
|
37
|
-
"lib/minglr/
|
38
|
-
"lib/minglr/
|
33
|
+
"lib/minglr/options_parser.rb",
|
34
|
+
"lib/minglr/resources/attachment.rb",
|
35
|
+
"lib/minglr/resources/base.rb",
|
36
|
+
"lib/minglr/resources/card.rb",
|
37
|
+
"lib/minglr/resources/project.rb",
|
38
|
+
"lib/minglr/resources/property_definition.rb",
|
39
|
+
"lib/minglr/resources/transition_execution.rb",
|
40
|
+
"lib/minglr/resources/user.rb",
|
39
41
|
"minglr.gemspec",
|
40
42
|
"minglrconfig.sample",
|
41
43
|
"tasks/commit.sample.rake",
|
42
44
|
"tasks/svn.sample.rake",
|
43
|
-
"test/
|
44
|
-
"test/
|
45
|
+
"test/extensions/array_test.rb",
|
46
|
+
"test/resources/attachment_test.rb",
|
47
|
+
"test/resources/base_test.rb",
|
48
|
+
"test/resources/card_test.rb",
|
49
|
+
"test/resources/project_test.rb",
|
50
|
+
"test/resources/property_definition_test.rb",
|
51
|
+
"test/resources/user_test.rb",
|
45
52
|
"test/test_helper.rb"
|
46
53
|
]
|
47
54
|
s.has_rdoc = true
|
@@ -49,21 +56,16 @@ Gem::Specification.new do |s|
|
|
49
56
|
s.post_install_message = %q{PostInstall.txt}
|
50
57
|
s.rdoc_options = ["--charset=UTF-8"]
|
51
58
|
s.require_paths = ["lib"]
|
52
|
-
s.rubygems_version = %q{1.
|
59
|
+
s.rubygems_version = %q{1.0.1}
|
53
60
|
s.summary = %q{command line user tool for Mingle (http://mingle.thoughtworks.com/mingle-agile-project-management)}
|
54
61
|
s.test_files = [
|
55
|
-
"test/
|
56
|
-
"test/
|
62
|
+
"test/extensions/array_test.rb",
|
63
|
+
"test/resources/attachment_test.rb",
|
64
|
+
"test/resources/base_test.rb",
|
65
|
+
"test/resources/card_test.rb",
|
66
|
+
"test/resources/project_test.rb",
|
67
|
+
"test/resources/property_definition_test.rb",
|
68
|
+
"test/resources/user_test.rb",
|
57
69
|
"test/test_helper.rb"
|
58
70
|
]
|
59
|
-
|
60
|
-
if s.respond_to? :specification_version then
|
61
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
62
|
-
s.specification_version = 2
|
63
|
-
|
64
|
-
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
65
|
-
else
|
66
|
-
end
|
67
|
-
else
|
68
|
-
end
|
69
71
|
end
|
data/minglrconfig.sample
CHANGED
@@ -16,3 +16,22 @@
|
|
16
16
|
task_state_3 = Dev In Progress > Story from Dev in Progress to Dev Complete
|
17
17
|
story_checkout = story_state_1
|
18
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,41 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Minglr
|
4
|
+
module Extensions
|
5
|
+
|
6
|
+
class ArrayTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
context Array do
|
9
|
+
|
10
|
+
context "filter" do
|
11
|
+
|
12
|
+
setup do
|
13
|
+
class TestObject
|
14
|
+
attr_accessor :name
|
15
|
+
end
|
16
|
+
@test1 = TestObject.new
|
17
|
+
@test2 = TestObject.new
|
18
|
+
@test1.name = "test1"
|
19
|
+
@test2.name = "test2"
|
20
|
+
@collection = [@test1, @test2]
|
21
|
+
@collection.send(:extend, Minglr::Extensions::Array)
|
22
|
+
end
|
23
|
+
|
24
|
+
should "include elements matching words in attributes" do
|
25
|
+
assert_equal [@test1], @collection.filter([:name], ["1"])
|
26
|
+
assert_equal [@test1, @test2], @collection.filter([:name], ["test"])
|
27
|
+
end
|
28
|
+
|
29
|
+
should "deal with empty words and attributes" do
|
30
|
+
assert_equal [@test1, @test2], @collection.filter([], [])
|
31
|
+
assert_equal [@test1, @test2], @collection.filter([:name], [])
|
32
|
+
assert_equal [], @collection.filter([], ["1"])
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Resources
|
4
|
+
|
5
|
+
class AttachmentTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context Attachment do
|
8
|
+
|
9
|
+
context "configure" do
|
10
|
+
|
11
|
+
should "append to the site url" do
|
12
|
+
options = { :username => "user",
|
13
|
+
:password => "pass",
|
14
|
+
:url => "proto://somehost.com:1234/projects/my_project" }
|
15
|
+
Base.configure(options)
|
16
|
+
Attachment.configure
|
17
|
+
assert_equal "/projects/my_project/cards/1/", Attachment.prefix(:card_number => 1)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context "fetch" do
|
23
|
+
|
24
|
+
should_eventually "download all found attachments for a given card number" do
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
context "attach" do
|
30
|
+
|
31
|
+
should_eventually "upload file for a given card number" do
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Resources
|
4
|
+
|
5
|
+
class BaseTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context Base do
|
8
|
+
|
9
|
+
context "configure" do
|
10
|
+
|
11
|
+
should "combine options to build url" do
|
12
|
+
options = { :username => "user",
|
13
|
+
:password => "pass",
|
14
|
+
:url => "proto://somehost.com:1234/projects/my_project" }
|
15
|
+
Base.configure(options)
|
16
|
+
assert_equal "proto://user:pass@somehost.com:1234/projects/my_project",
|
17
|
+
Base.site.to_s
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context "warn" do
|
23
|
+
|
24
|
+
should "prepend message with warning" do
|
25
|
+
Base.expects(:puts).with("Warning: test")
|
26
|
+
Base.warn("test")
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
context "print_collection" do
|
32
|
+
|
33
|
+
should_eventually "print values of attributes of objects separated by dashes and aligning columns of values" do
|
34
|
+
end
|
35
|
+
|
36
|
+
should_eventually "allow for right adjusted values" do
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Resources
|
4
|
+
|
5
|
+
class CardTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
context Card do
|
8
|
+
|
9
|
+
context "create" do
|
10
|
+
|
11
|
+
should_eventually "create a card with options passed in" do
|
12
|
+
end
|
13
|
+
|
14
|
+
should_eventually "create a card with the status of new if status property is available" do
|
15
|
+
end
|
16
|
+
|
17
|
+
should_eventually "warn if it is unable to create the card" do
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
context "move" do
|
23
|
+
|
24
|
+
should "move card from one state to the next as defined" do
|
25
|
+
end
|
26
|
+
|
27
|
+
should "warn if card cannot be found" do
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
context "print_all" do
|
33
|
+
|
34
|
+
should "warn if there are no cards" do
|
35
|
+
Card.expects(:find).with(:all).returns([])
|
36
|
+
Card.expects(:warn).with("No cards found")
|
37
|
+
Card.print_all
|
38
|
+
end
|
39
|
+
|
40
|
+
should "print the cards found with format" do
|
41
|
+
card1 = stub("Card", :number => 1, :card_type_name => "Story", :name => "Some Story")
|
42
|
+
card2 = stub("Card", :number => 2, :card_type_name => "Task", :name => "Some Task")
|
43
|
+
Card.expects(:find).with(:all).returns([card1, card2])
|
44
|
+
Card.expects(:puts).with("1 - Story - Some Story")
|
45
|
+
Card.expects(:puts).with("2 - Task - Some Task ")
|
46
|
+
Card.print_all
|
47
|
+
end
|
48
|
+
|
49
|
+
should "print cards with status property if available" do
|
50
|
+
card1 = stub("Card", :number => 1, :card_type_name => "Story", :name => "Some Story", :cp_status => "Ready")
|
51
|
+
Card.expects(:find).with(:all).returns([card1])
|
52
|
+
Card.expects(:puts).with("1 - Story - Ready - Some Story")
|
53
|
+
Card.print_all([], "cp_status")
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
context "print_card" do
|
59
|
+
|
60
|
+
should_eventually "print the details for a given card" do
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
context "update" do
|
66
|
+
|
67
|
+
should_eventually "update a card with the options passed in" do
|
68
|
+
end
|
69
|
+
|
70
|
+
should_eventually "print out the details of the card after updating" do
|
71
|
+
end
|
72
|
+
|
73
|
+
should_eventually "warn if it is not able to find the card" do
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
context "to_s" do
|
79
|
+
|
80
|
+
should_eventually "format the details of a given card including attachments" do
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|