schubert-minglr 1.1.0 → 1.2.0
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.
- 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
|