mingle-macro-development-toolkit 1.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.
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