mingle-macro-development-toolkit 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (36) hide show
  1. data/LICENSE.txt +21 -0
  2. data/README.rdoc +66 -0
  3. data/Rakefile +36 -0
  4. data/bin/new_mingle_macro +107 -0
  5. data/example/Rakefile +3 -0
  6. data/example/deploy.rake +10 -0
  7. data/example/init.rb +10 -0
  8. data/example/integration_test.rb +13 -0
  9. data/example/integration_test_helper.rb +19 -0
  10. data/example/macro.rb +18 -0
  11. data/example/unit_test.rb +13 -0
  12. data/example/unit_test_helper.rb +12 -0
  13. data/getting_started.txt +253 -0
  14. data/lib/macro_development_toolkit.rb +22 -0
  15. data/lib/macro_development_toolkit/mingle/card_type.rb +41 -0
  16. data/lib/macro_development_toolkit/mingle/card_type_property_definition.rb +26 -0
  17. data/lib/macro_development_toolkit/mingle/project.rb +80 -0
  18. data/lib/macro_development_toolkit/mingle/project_variable.rb +23 -0
  19. data/lib/macro_development_toolkit/mingle/property_definition.rb +94 -0
  20. data/lib/macro_development_toolkit/mingle/property_value.rb +68 -0
  21. data/lib/macro_development_toolkit/mingle/user.rb +29 -0
  22. data/lib/macro_development_toolkit/mingle_model_loader.rb +169 -0
  23. data/tasks/test.rake +15 -0
  24. data/test/fixtures/sample/card_types.yml +29 -0
  25. data/test/fixtures/sample/card_types_property_definitions.yml +81 -0
  26. data/test/fixtures/sample/project_variables.yml +5 -0
  27. data/test/fixtures/sample/projects.yml +4 -0
  28. data/test/fixtures/sample/property_definitions.yml +41 -0
  29. data/test/fixtures/sample/users.yml +16 -0
  30. data/test/integration/integration_test_helper.rb +20 -0
  31. data/test/integration/rest_loader.rb +302 -0
  32. data/test/integration/rest_loader_test.rb +86 -0
  33. data/test/unit/fixture_loader.rb +180 -0
  34. data/test/unit/fixture_loader_test.rb +46 -0
  35. data/test/unit/unit_test_helper.rb +13 -0
  36. metadata +110 -0
@@ -0,0 +1,22 @@
1
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+
3
+ $:.unshift(File.dirname(__FILE__)) unless
4
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
5
+
6
+ module MacroDevelopmentToolkit
7
+ VERSION = '1.0'
8
+ end
9
+
10
+ require 'yaml'
11
+ require 'ostruct'
12
+ require 'net/http'
13
+ begin
14
+ require 'rubygems'
15
+ rescue Exception
16
+ #ignore
17
+ end
18
+ require 'active_support'
19
+
20
+ Dir.glob(File.join("#{File.dirname(__FILE__)}", 'macro_development_toolkit', '**', '*')).reverse.each do |f|
21
+ require f unless File.directory?(f)
22
+ end
@@ -0,0 +1,41 @@
1
+ module Mingle
2
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
3
+
4
+ #This is a lightweight representation of a card type in Mingle.
5
+ #From an instance of this class you can the name, color and position of the card type,
6
+ #in addition to Property Definitions that are associated with it.
7
+ class CardType
8
+
9
+ def initialize(full_card_type)
10
+ @full_card_type = full_card_type
11
+ end
12
+
13
+ # *returns*: The name of this CardType
14
+ def name
15
+ @full_card_type.name
16
+ end
17
+
18
+ # *returns*: The hex color code for this CardType
19
+ def color
20
+ @full_card_type.color.gsub('#', '')
21
+ end
22
+
23
+ # *returns*: The position of this CardType among all the CardTypes on the project.
24
+ # The first card type has position 1
25
+ def position
26
+ @full_card_type.position
27
+ end
28
+
29
+ # *returns*: The PropertyDefinitions associated with this CardType
30
+ def property_definitions
31
+ @card_types_property_definitions_loader.load.collect(&:property_definition)
32
+ end
33
+
34
+ def to_s
35
+ "CardType[name=#{name},color=#{color},position=#{position}]"
36
+ end
37
+
38
+ attr_writer :card_types_property_definitions_loader
39
+ end
40
+
41
+ end
@@ -0,0 +1,26 @@
1
+ module Mingle
2
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
3
+
4
+ #This is a lightweight representation of the relationship between a card_type
5
+ #and a property definition as configured in Mingle.
6
+ class CardTypePropertyDefinition
7
+ def initialize(card_type_property_definition)
8
+ @card_type_property_definition = card_type_property_definition
9
+ end
10
+
11
+ def position
12
+ @card_type_property_definition.position.to_i
13
+ end
14
+
15
+ def card_type
16
+ @card_type_loader.load
17
+ end
18
+
19
+ def property_definition
20
+ @property_definition_loader.load
21
+ end
22
+
23
+ attr_writer :card_type_loader, :property_definition_loader
24
+ end
25
+
26
+ end
@@ -0,0 +1,80 @@
1
+ module Mingle
2
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
3
+
4
+ #This is a lightweight representation of a project.
5
+ #From an instance of this class you can the name & identifier of the project.
6
+ #You can also get a list of property definitions and card types on the project,
7
+ #in addition to information about the team and project variables.
8
+ #This class also provides an interface to the MQL execution facilities provided by Mingle.
9
+ class Project
10
+
11
+ def initialize(project, card_query_options)
12
+ @full_project = project
13
+ @card_query_options = card_query_options
14
+ end
15
+
16
+ # *returns*: The identifier of this project
17
+ def identifier
18
+ @full_project.identifier
19
+ end
20
+
21
+ # *returns*: The name of this project
22
+ def name
23
+ @full_project.name
24
+ end
25
+
26
+ # *returns*: A list CardTypes as configured for this project.
27
+ # There will always be atleast one element in this array.
28
+ def card_types
29
+ @card_types_loader.load
30
+ end
31
+
32
+ # *returns*: An list of PropertyDefinitions as configured for this project.
33
+ # This array may be empty
34
+ def property_definitions
35
+ @property_definitions_loader.load
36
+ end
37
+
38
+ # *accepts*: The name of a project variable configured for this project
39
+ #
40
+ # *returns*: The display value of the PropertyValue(s) that project_variable_name represents
41
+ def value_of_project_variable(project_variable_name)
42
+ @project_variables_loader.load.detect { |pv| pv.name == project_variable_name }.value
43
+ end
44
+
45
+ # *accepts*: A valid MQL string. To see what constitutes valid MQL,
46
+ # look here[http://studios.thoughtworks.com/mingle-agile-project-management/2.2/help/index.html]
47
+ #
48
+ # *returns*: The display value of the PropertyValue(s) that project_variable_name represents
49
+ def execute_mql(mql)
50
+ CardQuery.parse(mql, @card_query_options).values
51
+ end
52
+
53
+ # *returns*: The full list of Users who are members of this project
54
+ def team
55
+ @team_loader.load
56
+ end
57
+
58
+ # *accepts*: Any Number
59
+ #
60
+ # *returns*: The number formatted to the precision configured for the project (default 2)
61
+ def format_number_with_project_precision(number)
62
+ @full_project.to_num(number)
63
+ end
64
+
65
+ # *accepts*: Any Number
66
+ #
67
+ # *returns*: The number formatted to the precision configured for the project (default 2)
68
+ def format_date_with_project_date_format(date)
69
+ @full_project.format_date(date)
70
+ end
71
+
72
+ attr_writer :card_types_loader, :property_definitions_loader, :team_loader, :project_variables_loader
73
+
74
+ private
75
+ def add_alert(message)
76
+ @card_query_options[:alert_receiver].alert(message) if @card_query_options[:alert_receiver]
77
+ end
78
+ end
79
+
80
+ end
@@ -0,0 +1,23 @@
1
+ module Mingle
2
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
3
+
4
+ #This is a lightweight representation of a ProjectVariable in Mingle
5
+ #which is a mnemonic that represents a particular value for multiple PropertyDefinitions
6
+ class ProjectVariable
7
+
8
+ def initialize(full_project_variable)
9
+ @full_project_variable = full_project_variable
10
+ end
11
+
12
+ # *returns*: The name of this variable
13
+ def name
14
+ @full_project_variable.name
15
+ end
16
+
17
+ # *returns*: The display value of the value configured for this project variable
18
+ def value
19
+ @full_project_variable.value
20
+ end
21
+ end
22
+
23
+ end
@@ -0,0 +1,94 @@
1
+ module Mingle
2
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
3
+
4
+ #This is a lightweight representation of a ProjectDefinition in Mingle
5
+ class PropertyDefinition
6
+
7
+ MANAGED_TEXT_TYPE = "Managed text list"
8
+ ANY_TEXT_TYPE = "Any text"
9
+ MANAGED_NUMBER_TYPE = "Managed number list"
10
+ ANY_NUMBER_TYPE = "Any number"
11
+ DATE_TYPE = "Date"
12
+ FORMULA_TYPE = "Formula"
13
+ USER_TYPE = "Automatically generated from the team list"
14
+ CARD_TYPE = "Card"
15
+ AGGREGATE_TYPE = "Aggregate"
16
+ TREE_RELATIONSHIP_TYPE = "Used in card tree"
17
+
18
+ def initialize(full_property_definition)
19
+ @full_property_definition = full_property_definition
20
+ end
21
+
22
+ # *returns*: The name of this PropertyDefinition
23
+ def name
24
+ @full_property_definition.name
25
+ end
26
+
27
+ # *returns*: The description of this PropertyDefinition
28
+ def description
29
+ @full_property_definition.description
30
+ end
31
+
32
+ # *returns*: A list of CardTypes that this PropertyDefinition is valid for
33
+ def card_types
34
+ @card_types_property_definitions_loader.load.collect(&:card_type).sort_by(&:position)
35
+ end
36
+
37
+ # *returns*: A
38
+ def type_description
39
+ @full_property_definition.type_description
40
+ end
41
+
42
+ # *returns*: A list of explicitly defined values that this PropertyDefinition has
43
+ # This method should ONLY be called for property definitions that are of the following types
44
+ # - MANAGED_TEXT_TYPE
45
+ # - MANAGED_NUMBER_TYPE
46
+ # - USER_TYPE
47
+ #
48
+ # Attempting to call this method for the following types will throw an Exception
49
+ # - ANY_TEXT_TYPE
50
+ # - ANY_NUMBER_TYPE
51
+ # - FORMULA_TYPE
52
+ # - AGGREGATE_TYPE
53
+ # - CARD_TYPE
54
+ # - TREE_RELATIONSHIP_TYPE
55
+ # - DATE_TYPE
56
+ #
57
+ # To get the values for the above types, you can use MQL, such as "SELECT property_name" to get
58
+ # a list of values
59
+ def values
60
+ valid_property_types_to_call_value_on = [MANAGED_TEXT_TYPE, MANAGED_NUMBER_TYPE, USER_TYPE]
61
+ unless valid_property_types_to_call_value_on.any? {|t| self.type_description == t}
62
+ raise "Do not call this method for property definitions of types other than MANAGED_TEXT_TYPE, MANAGED_NUMBER_TYPE, USER_TYPE."
63
+ end
64
+ @values_loader.load
65
+ end
66
+
67
+ # *returns*: True if a property definition has only textual values, such as ones of Un/managed text types
68
+ def textual?
69
+ type_description == MANAGED_TEXT_TYPE || type_description == ANY_TEXT_TYPE
70
+ end
71
+
72
+ # *returns*: True if a property definition has only numeric values, such as ones of Un/managed number types
73
+ def numeric?
74
+ type_description == MANAGED_NUMBER_TYPE || type_description == ANY_NUMBER_TYPE
75
+ end
76
+
77
+ # *returns*: True if a property definition has only calculated values, such as ones of Formula & Aggregate types
78
+ def calculated?
79
+ type_description == FORMULA_TYPE || type_description == AGGREGATE_TYPE
80
+ end
81
+
82
+ # *returns*: True if a property definition has only numeric values, such as the Date type
83
+ def date?
84
+ type_description == DATE_TYPE
85
+ end
86
+
87
+ def to_s
88
+ "PropertyDefinition[name=#{name},type=#{type}]"
89
+ end
90
+
91
+ attr_writer :card_types_property_definitions_loader, :values_loader
92
+ end
93
+
94
+ end
@@ -0,0 +1,68 @@
1
+ module Mingle
2
+
3
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
4
+
5
+ class PropertyValue
6
+
7
+ def initialize(property_value)
8
+ @property_value = property_value
9
+ end
10
+
11
+ # *returns*: The display value of this value
12
+ # Use the result of this method to display this value on the UI
13
+ # For the various property types, the following are the values you can expect to see
14
+ # * Managed/Unmanaged text : The string value of the value
15
+ # * Managed/Unmanaged numeric : The numeric string representation of the value
16
+ # * Date : The list of values this property has on all cards on the project, formatted using the project date format
17
+ # * User : The name of the user
18
+ # * Formula : Either the date or the numeric value, formatted as above
19
+ # * Card : The number of the card, followed by the name of the card
20
+ def display_value
21
+ @property_value.display_value
22
+ end
23
+
24
+ # *returns*: The identifier that is used to represent this value in the database
25
+ # You will most likely not have to use this value in your macros
26
+ # For the various property types, the following are the values you can expect to see
27
+ # * Managed/Unmanaged text : The string value of the value
28
+ # * Managed/Unmanaged numeric : The numeric string representation of the value
29
+ # * Date : The canonical date format, as stored in the database
30
+ # * User : The id of the user in the database
31
+ # * Formula : Either the date or the numeric value, formatted as above
32
+ # * Card : The id of the card in the database
33
+ def db_identifier
34
+ @property_value.db_identifier
35
+ end
36
+
37
+ # *returns*: A representation of this value that is unique and representable in a URL
38
+ # Use the result of this method if in any links that you want to build to point back into Mingle
39
+ # For the various property types, the following are the values you can expect to see
40
+ # * Managed/Unmanaged text : The string value of the value
41
+ # * Managed/Unmanaged numeric : The numeric string representation of the value
42
+ # * Date : The list of values this property has on all cards on the project, formatted using the project date format
43
+ # * User : The login of the user
44
+ # * Formula : Either the date or the numeric value, formatted as above
45
+ # * Card : The number of the card, followed by the name of the card
46
+ def url_identifier
47
+ @property_value.url_identifier
48
+ end
49
+
50
+ # *returns*: The hex color code for this PropertyValue
51
+ def color
52
+ @property_value.color.gsub('#', '')
53
+ end
54
+
55
+ # *returns*: The PropertyDefinition that this value belongs to
56
+ def property_definition
57
+ @property_definition_loader.load
58
+ end
59
+
60
+ def to_s
61
+ "PropertyValue[display_value=#{display_value},db_identifier=#{db_identifier},url_identifier=#{url_identifier}]"
62
+ end
63
+
64
+ attr_writer :property_definition_loader
65
+
66
+ end
67
+
68
+ end
@@ -0,0 +1,29 @@
1
+ module Mingle
2
+
3
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
4
+
5
+ class User
6
+
7
+ def initialize(full_user)
8
+ @full_user = full_user
9
+ end
10
+
11
+ def login
12
+ @full_user.login
13
+ end
14
+
15
+ def name
16
+ @full_user.name
17
+ end
18
+
19
+ def version_control_user_name
20
+ @full_user.version_control_user_name
21
+ end
22
+
23
+ def email
24
+ @full_user.email
25
+ end
26
+
27
+ end
28
+
29
+ end
@@ -0,0 +1,169 @@
1
+ #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+
3
+ #MingleModelLoaders understand how to load a graph of lightweight objects from
4
+ #the Mingle model objects at runtime, when the custom macro is deployed into production.
5
+ module MingleModelLoaders
6
+ class Base
7
+ def initialize(project, macro_context=nil, alert_receiver=nil)
8
+ @project = project
9
+ @macro_context = macro_context
10
+ @alert_receiver = alert_receiver
11
+ end
12
+
13
+ def card_types_property_definitions_by_card_type_id_loader(card_type_id)
14
+ LoadCardTypesPropertyDefinitionsByCardTypeId.new(card_type_id, @project)
15
+ end
16
+
17
+ def card_types_property_definitions_by_property_definition_id_loader(property_definition_id)
18
+ LoadCardTypesPropertyDefinitionsByPropertyDefinitionId.new(property_definition_id, @project)
19
+ end
20
+
21
+ def values_by_property_definition_id_loader(property_definition_id)
22
+ LoadValuesByPropertyDefinitionId.new(property_definition_id, @project)
23
+ end
24
+
25
+ def card_type_by_id_loader(card_type_id)
26
+ LoadCardTypeById.new(card_type_id, @project)
27
+ end
28
+
29
+ def property_definition_by_id_loader(property_definition_id)
30
+ LoadPropertyDefinitionById.new(property_definition_id, @project)
31
+ end
32
+
33
+ def card_types_by_project_id_loader
34
+ LoadCardTypesByProjectId.new(@project)
35
+ end
36
+
37
+ def property_definitions_by_project_id_loader
38
+ LoadPropertyDefinitionsByProjectId.new(@project)
39
+ end
40
+
41
+ def team_by_project_id_loader
42
+ LoadTeamByProjectId.new(@project)
43
+ end
44
+
45
+ def project_variables_by_project_id_loader
46
+ LoadProjectVariablesByProjectId.new(@project)
47
+ end
48
+ end
49
+
50
+ class ProjectLoader < Base
51
+ def project
52
+ project = Mingle::Project.new(@project, :content_provider => @macro_context[:content_provider], :alert_receiver => @alert_receiver)
53
+ project.card_types_loader = card_types_by_project_id_loader
54
+ project.property_definitions_loader = property_definitions_by_project_id_loader
55
+ project.team_loader = team_by_project_id_loader
56
+ project.project_variables_loader = project_variables_by_project_id_loader
57
+ project
58
+ end
59
+ end
60
+
61
+ class LoadCardTypesByProjectId < Base
62
+ def load
63
+ @project.card_types.collect do |ct|
64
+ card_type = Mingle::CardType.new(ct)
65
+ card_type.card_types_property_definitions_loader = card_types_property_definitions_by_card_type_id_loader(ct.id)
66
+ card_type
67
+ end.sort_by(&:position)
68
+ end
69
+ end
70
+
71
+ class LoadPropertyDefinitionsByProjectId < Base
72
+ def load
73
+ @project.all_property_definitions.collect do |pd|
74
+ property_definition = Mingle::PropertyDefinition.new(pd)
75
+ property_definition.card_types_property_definitions_loader = card_types_property_definitions_by_property_definition_id_loader(pd.id)
76
+ property_definition.values_loader = values_by_property_definition_id_loader(pd.id)
77
+ property_definition
78
+ end
79
+ end
80
+ end
81
+
82
+ class LoadCardTypesPropertyDefinitionsByCardTypeId < Base
83
+ def initialize(card_type_id, fixture_file_name)
84
+ super(fixture_file_name)
85
+ @card_type_id = card_type_id
86
+ end
87
+
88
+ def load
89
+ @project.card_types.find(@card_type_id).card_types_property_definitions.collect do |ctpd|
90
+ card_type_property_definition = Mingle::CardTypePropertyDefinition.new(ctpd)
91
+ card_type_property_definition.card_type_loader = card_type_by_id_loader(ctpd.card_type_id)
92
+ card_type_property_definition.property_definition_loader = property_definition_by_id_loader(ctpd.property_definition_id)
93
+ card_type_property_definition
94
+ end.sort_by(&:position).compact
95
+ end
96
+
97
+ end
98
+
99
+ class LoadCardTypesPropertyDefinitionsByPropertyDefinitionId < Base
100
+ def initialize(property_definition_id, fixture_file_name)
101
+ super(fixture_file_name)
102
+ @property_definition_id = property_definition_id
103
+ end
104
+
105
+ def load
106
+ @project.all_property_definitions.detect { |pd| pd.id == @property_definition_id }.card_types_property_definitions do |ctpd|
107
+ card_type_property_definition = Mingle::CardTypePropertyDefinition.new(ctpd)
108
+ card_type_property_definition.card_type_loader = card_type_by_id_loader(ctpd.card_type_id)
109
+ card_type_property_definition.property_definition_loader = property_definition_by_id_loader(ctpd.property_definition_id)
110
+ card_type_property_definition
111
+ end.compact.sort_by(&:position).compact
112
+ end
113
+
114
+ end
115
+
116
+ class LoadCardTypeById < Base
117
+ def initialize(card_type_id, fixture_file_name)
118
+ super(fixture_file_name)
119
+ @card_type_id = card_type_id
120
+ end
121
+
122
+ def load
123
+ ct = Mingle::CardType.new(@project.card_types.find(@card_type_id))
124
+ ct.card_types_property_definitions_loader = card_types_property_definitions_by_card_type_id_loader(@card_type_id)
125
+ ct
126
+ end
127
+ end
128
+
129
+ class LoadPropertyDefinitionById < Base
130
+ def initialize(property_definition_id, fixture_file_name)
131
+ super(fixture_file_name)
132
+ @property_definition_id = property_definition_id
133
+ end
134
+
135
+ def load
136
+ pd = Mingle::PropertyDefinition.new(@project.all_property_definitions.detect { |pd| pd.id == @property_definition_id })
137
+ pd.card_types_property_definitions_loader = card_types_property_definitions_by_property_definition_id_loader(@property_definition_id)
138
+ pd.values_loader = values_by_property_definition_id_loader(@property_definition_id)
139
+ pd
140
+ end
141
+ end
142
+
143
+ class LoadValuesByPropertyDefinitionId < Base
144
+ def initialize(property_definition_id, fixture_file_name)
145
+ super(fixture_file_name)
146
+ @property_definition_id = property_definition_id
147
+ end
148
+
149
+ def load
150
+ @project.all_property_definitions.detect { |pd| pd.id == @property_definition_id }.light_property_values.collect do |pv|
151
+ property_value = Mingle::PropertyValue.new(pv)
152
+ property_value.property_definition_loader = property_definition_by_id_loader(@property_definition_id)
153
+ property_value
154
+ end.compact
155
+ end
156
+ end
157
+
158
+ class LoadTeamByProjectId < Base
159
+ def load
160
+ @project.users.collect { |user| Mingle::User.new(user) }
161
+ end
162
+ end
163
+
164
+ class LoadProjectVariablesByProjectId < Base
165
+ def load
166
+ @project.project_variables.collect { |plv| Mingle::ProjectVariable.new(plv) }
167
+ end
168
+ end
169
+ end