mingle-macro-development-toolkit 1.2 → 1.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ == 1.3 September, 2009
2
+
3
+ * Multiple project support
4
+ * The execute_mql call is now versioned to support both old and new formats for results
5
+
1
6
  == 1.2 April 16, 2009
2
7
 
3
8
  * Mingle 2.3 integration
data/LICENSE.txt CHANGED
@@ -1,6 +1,6 @@
1
1
  The MIT License
2
2
 
3
- Copyright (c) 2008 ThoughtWorks, Inc. All rights reserved.
3
+ Copyright (c) 2009 ThoughtWorks, Inc. All rights reserved.
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
data/README.rdoc CHANGED
@@ -45,7 +45,7 @@ team over email at support@thoughtworks.com
45
45
 
46
46
  The MIT License
47
47
 
48
- Copyright (c) 2008 ThoughtWorks, Inc. All rights reserved.
48
+ Copyright (c) 2009 ThoughtWorks, Inc. All rights reserved.
49
49
 
50
50
  Permission is hereby granted, free of charge, to any person obtaining a copy
51
51
  of this software and associated documentation files (the "Software"), to deal
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
1
+ #Copyright 2009 ThoughtWorks, Inc. All rights reserved.
2
2
 
3
3
  begin
4
4
  require 'rubygems'
@@ -13,19 +13,21 @@ rescue LoadError
13
13
  exit 1
14
14
  end
15
15
 
16
- %w[rake rake/clean fileutils newgem rubigen].each { |f| require f }
16
+ %w[rake rake/clean fileutils hoe newgem rubigen].each { |f| p "require #{f}"; require f }
17
17
  require File.dirname(__FILE__) + '/lib/macro_development_toolkit'
18
18
 
19
19
  # Generate all the Rake tasks
20
20
  # Run 'rake -T' to see list of generated tasks (from gem root directory)
21
- $hoe = Hoe.new('mingle-macro-development-toolkit', MacroDevelopmentToolkit::VERSION) do |p|
21
+ $hoe = Hoe.spec('mingle-macro-development-toolkit') do |p|
22
+ p.version = MacroDevelopmentToolkit::VERSION
22
23
  p.developer('ThoughtWorks Inc', 'support@thoughtworks.com')
23
24
  p.post_install_message = 'getting_started.txt'
24
25
  p.rubyforge_name = 'mingle-macros'
25
26
  p.extra_deps = [
26
27
  ['activesupport','>= 2.0.2'],
27
28
  ]
28
- p.rdoc_pattern = /README|(lib\/macro_development_toolkit\/mingle(?!_))/
29
+ p.summary = "This toolkit provides support for developing, testing and deploying custom Mingle macros."
30
+ p.extra_rdoc_files = ['README.rdoc']
29
31
  p.clean_globs |= %w[**/.DS_Store tmp *.log]
30
32
  path = (p.rubyforge_name == p.name) ? p.rubyforge_name : "\#{p.rubyforge_name}/\#{p.name}"
31
33
  p.remote_rdoc_dir = ''
data/bin/new_mingle_macro CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+ #Copyright 2009 ThoughtWorks, Inc. All rights reserved.
3
3
 
4
4
  require 'erb'
5
5
  begin
data/example/Rakefile CHANGED
@@ -1,3 +1,6 @@
1
1
  %w[rubygems rake rake/clean rake/testtask fileutils macro_development_toolkit].each { |f| require f }
2
2
 
3
3
  Dir['tasks/**/*.rake'].each { |t| load t }
4
+
5
+ desc "Runs all units and integration tests"
6
+ task :test => ['test:units', 'test:integration']
@@ -1,15 +1,27 @@
1
1
  require File.dirname(__FILE__) + '/integration_test_helper.rb'
2
2
 
3
- # The Mingle API supports basic authentication and must be used in order to run integration tests. However it is disabled in the default configuration. To enable basic authentication, you need set the basic_authentication_enabled configuration option to true in the Mingle data directory/config/auth_config.yml file where Mingle data directory is the path to the mingle data directory on your installation e.g.basic_authentication_enabled: true.
3
+ # The Mingle API supports basic authentication and must be used in order to run integration tests.
4
+ # However it is disabled in the default configuration. To enable basic authentication,
5
+ # you need set the basic_authentication_enabled configuration option to true in the
6
+ # <mingle_data_directory>/config/auth_config.yml file where <mingle_data_directory> is the path
7
+ # to the mingle data directory on your installation e.g.
8
+ # basic_authentication_enabled: true.
4
9
 
5
10
  class <%= macro_class_name %>IntegrationTest < Test::Unit::TestCase
6
11
 
7
12
  PROJECT_RESOURCE = 'http://username:password@your.mingle.server:port/lightweight_projects/your_project_identifier.xml'
8
-
13
+ ANOTHER_PROJECT_RESOURCE = 'http://username:password@your.mingle.server:port/lightweight_projects/another_project_identifier.xml'
14
+
9
15
  def test_macro_contents
10
16
  <%= macro_name %> = <%= macro_class_name %>.new(nil, project(PROJECT_RESOURCE), nil)
11
17
  result = <%= macro_name %>.execute
12
18
  assert result
13
19
  end
20
+
21
+ def test_macro_contents_with_a_project_group
22
+ <%= macro_name %> = <%= macro_class_name %>.new(nil, [project(PROJECT_RESOURCE), project(ANOTHER_PROJECT_RESOURCE)], nil)
23
+ result = <%= macro_name %>.execute
24
+ assert result
25
+ end
14
26
 
15
27
  end
@@ -1,19 +1,31 @@
1
+ require 'delegate'
1
2
  require 'test/unit'
2
3
  require File.join(File.dirname(__FILE__), '..', '..', 'init.rb')
3
4
  require File.join(File.dirname(__FILE__), '..', '..', 'lib', '<%= macro_name %>')
4
5
  require File.join(File.dirname(__FILE__), 'rest_loader')
5
6
 
6
7
  class Test::Unit::TestCase
7
-
8
+
8
9
  def project(name)
9
- @project ||= RESTfulLoaders::ProjectLoader.new(name, nil, self).project
10
- end
11
-
10
+ @project ||= load_project_resource(name)
11
+ end
12
+
13
+ def projects(*resources)
14
+ @projects ||= resources.map{ |resource| load_project_resource(resource) }
15
+ end
16
+
12
17
  def errors
13
18
  @errors ||= []
14
- end
19
+ end
15
20
 
16
21
  def alert(message)
17
22
  errors << message
18
23
  end
19
- end
24
+
25
+ private
26
+
27
+ def load_project_resource(resource)
28
+ RESTfulLoaders::ProjectLoader.new(resource, nil, self).project
29
+ end
30
+
31
+ end
data/example/unit_test.rb CHANGED
@@ -9,5 +9,11 @@ class <%= macro_class_name %>Test < Test::Unit::TestCase
9
9
  result = <%= macro_name %>.execute
10
10
  assert result
11
11
  end
12
+
13
+ def test_macro_contents_with_a_project_group
14
+ <%= macro_name %> = <%= macro_class_name %>.new(nil, [project(FIXTURE), project(FIXTURE)], nil)
15
+ result = <%= macro_name %>.execute
16
+ assert result
17
+ end
12
18
 
13
19
  end
@@ -6,7 +6,17 @@ require File.join(File.dirname(__FILE__), 'fixture_loader')
6
6
  class Test::Unit::TestCase
7
7
 
8
8
  def project(name)
9
- @project ||= FixtureLoaders::ProjectLoader.new(name).project
10
- end
9
+ @project ||= load_project_fixture(name)
10
+ end
11
+
12
+ def projects(*names)
13
+ @projects ||= names.map { |name| load_project_fixture(name) }
14
+ end
15
+
16
+ private
17
+
18
+ def load_project_fixture(name)
19
+ FixtureLoaders::ProjectLoader.new(name).project
20
+ end
11
21
 
12
22
  end
data/getting_started.txt CHANGED
@@ -49,11 +49,15 @@ class AverageMacro
49
49
  end
50
50
  end
51
51
 
52
- All data that is required to execute the macro is injected into the macro through the constructor. The parameters that are interpreted from the markup are passed in as a hash. The project that is passed in is a lightweight representation of the project in the Mingle model, and is documented at http://mingle-macros.rubyforge.org/rdoc
52
+ All data that is required to execute the macro is injected into the macro through the constructor. The parameters that are interpreted from the markup are passed in as a hash.
53
+
54
+ The second parameter is special and could be either a single project or multiple projects, based on the parameter name used in the macro. In versions 1.3 and above of the gem, a comma separated list of project identifiers when supplied as the value of a macro parameter called project-group will be interpretted as multiple projects. This functionality can be used to build macros that report across multiple projects. The project or projects that are passed in are a lightweight representation of the project in the Mingle model which is documented at http://mingle-macros.rubyforge.org/rdoc
53
55
 
54
56
  The execute method uses the MQL execution facility that the project class provides, to execute the MQL string that is passed into through the parameters hash. It then formats the results to be a number, and provides that result of the execute command.
55
57
 
56
- For more help on what constitutes valid MQL, you can refer to our help documentation at http://studios.thoughtworks.com/mingle-agile-project-management/2.3/help/mql_reference.html
58
+ For more help on what constitutes valid MQL, you can refer to our help documentation at http://studios.thoughtworks.com/mingle-agile-project-management/3.0/help/mql_reference.html
59
+
60
+ To see an example of how to use the gem to report across multiple projects, refer to the cross_project_rollup macro which ships with versions of Mingle 3.0 and higher.
57
61
 
58
62
  Writing your own macro
59
63
  ----------------------
@@ -103,9 +107,13 @@ will be parsed as YAML and handling will be delegated to an instance of your mac
103
107
 
104
108
  {'parameter1' => 'value1', 'parameter2' => '<some_mql_snippet>'}
105
109
 
106
- and will be passed into the constructor of the class, along with an instance of a Mingle::Project, that represents the project that this macro is being rendered on.
110
+ and will be passed into the constructor of the class. Additionally, by default, an instance of Mingle::Project that represents the project that this macro is being rendered on will also be provided. You can specify a different project to be passed in by setting a project parameter in your macro. Also you can specify a group of projects to be provided to your macro by setting a project-group parameter. In this case the projects will be an array of Mingle::Project. You will also need to implement a class method called supports_project_group? which returns true if you want your macro to be used with project-group, for example:
111
+
112
+ def self.supports_project_group?
113
+ true
114
+ end
107
115
 
108
- As an example of what you can do with this information is the following macro, which uses the Google Charting API to render a Google-o-meter style chart to represent work completed in a fuel gauge style meter.
116
+ As an example of what you can do with this toolkit is the following macro, which uses the Google Charting API to render a Google-o-meter style chart to represent work completed in a fuel gauge style meter.
109
117
 
110
118
  class WorkGauge
111
119
 
@@ -168,6 +176,9 @@ of macros use Javascript (or JSONP) to offload work to the browser.
168
176
 
169
177
  You can find both simpler and more complex examples in the vendor/plugins/sample_macros directory.
170
178
 
179
+ Tip: If you wish to use JQuery, you will have to add a call to JQuery.noConflict() to prevent conflicts with the Prototype library that ships with Mingle. You can refer to the JQuery documentation here (http://docs.jquery.com/Core/jQuery.noConflict) to see the correct order in which to load the libraries and other conditions to be followed in order to make this work properly. If you do not do this, you can still use JQuery without using the $ shorthand for the jQuery function.
180
+
181
+
171
182
  Unit testing your macro
172
183
  ------------------------
173
184
 
@@ -204,7 +215,7 @@ Integration testing your macro
204
215
 
205
216
  ########################################################NOTE###############################################################
206
217
  # #
207
- # IN ORDER TO RUN THE INTEGRATION TESTS, YOU WILL NEED TO TURN ON BASIC AUTHENTICATION FOR THE MINGLE 2.3 SERVER THAT YOU #
218
+ # IN ORDER TO RUN THE INTEGRATION TESTS, YOU WILL NEED TO TURN ON BASIC AUTHENTICATION FOR THE MINGLE 3.0 SERVER THAT YOU #
208
219
  # ARE GOING TO BE TESTING AGAINST. #
209
220
  # #
210
221
  #########################################################NOTE##############################################################
@@ -235,7 +246,7 @@ end
235
246
 
236
247
  The skeleton project also has a sample integration test set up for you, which points to a bogus Mingle server, and uses bad credentials. Replace this resource URL with the URL for a deployed instance within your organization. The helper method project(...) which takes the resource URL, loads the data from the XML data obtained from the live instance of Mingle.
237
248
 
238
- You can see examples of integration tests in the average macro that is packaged with Mingle in the vendor/plugins/average_macro directory. These tests run against a standard template that ships with Mingle2.3, and so you should be able to run them within your organization too, without a problem.
249
+ You can see examples of integration tests in the average macro that is packaged with Mingle in the vendor/plugins/average_macro directory. These tests run against a standard template that ships with Mingle 3.0, and so you should be able to run them within your organization too, without a problem.
239
250
 
240
251
  To run your integration tests, run
241
252
 
@@ -267,7 +278,7 @@ To deploy your macro to a locally deployed instance of Mingle, which is running
267
278
 
268
279
  % rake macro:deploy MINGLE_LOCATION=/path/to/mingle_root
269
280
 
270
- where /path/to/mingle_root is the location where Mingle2.3 is installed.
281
+ where /path/to/mingle_root is the location where Mingle 3.0 is installed.
271
282
 
272
283
  * On Windows, this is the location that the installer installed Mingle at
273
284
  * On OSX, this will be within the app bundle, at <mingle_application_bundle>/Contents/Resources/app
@@ -1,10 +1,10 @@
1
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
1
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
2
2
 
3
3
  $:.unshift(File.dirname(__FILE__)) unless
4
4
  $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
5
5
 
6
6
  module MacroDevelopmentToolkit
7
- VERSION = '1.2'
7
+ VERSION = '1.3'
8
8
  end
9
9
 
10
10
  require 'yaml'
@@ -1,9 +1,9 @@
1
1
  module Mingle
2
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
3
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.
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
7
  class CardType
8
8
 
9
9
  def initialize(full_card_type)
@@ -1,12 +1,12 @@
1
1
  module Mingle
2
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
3
3
 
4
- #This is a lightweight representation of the relationship between a card_type
5
- #and a property definition as configured in Mingle.
4
+ # This is a lightweight representation of the relationship between a card_type
5
+ # and a property definition as configured in Mingle.
6
6
  class CardTypePropertyDefinition
7
7
  def initialize(card_type_property_definition)
8
8
  @card_type_property_definition = card_type_property_definition
9
- end
9
+ end
10
10
 
11
11
  def position
12
12
  @card_type_property_definition.position.to_i
@@ -1,13 +1,16 @@
1
1
  module Mingle
2
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
3
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.
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
9
  class Project
10
10
 
11
+ VERSION_ONE = 'v1'
12
+ VERSION_TWO = 'v2'
13
+
11
14
  def initialize(project, card_query_options)
12
15
  @full_project = project
13
16
  @card_query_options = card_query_options
@@ -24,13 +27,12 @@ module Mingle
24
27
  end
25
28
 
26
29
  # *returns*: A list CardTypes as configured for this project.
27
- # There will always be atleast one element in this array.
30
+ # There will always be atleast one element in this list.
28
31
  def card_types
29
32
  @card_types_loader.load
30
33
  end
31
34
 
32
- # *returns*: An list of PropertyDefinitions as configured for this project.
33
- # This array may be empty
35
+ # *returns*: An list of PropertyDefinitions as configured for this project, which may be empty
34
36
  def property_definitions
35
37
  @property_definitions_loader.load
36
38
  end
@@ -43,13 +45,81 @@ module Mingle
43
45
  end
44
46
 
45
47
  # *accepts*: A valid MQL string. To see what constitutes valid MQL,
46
- # look here[http://studios.thoughtworks.com/mingle-agile-project-management/2.3/help/index.html]
48
+ # look here[http://studios.thoughtworks.com/mingle-agile-project-management/3.0/help/index.html]
47
49
  #
48
50
  # *returns*: An Array of Hashes, in which each Hash represents one row of results from the MQL execution
49
- # The keys in the Hash are the names of the properties selected, with spaces and special characters replaced
50
- # with underscores(_).
51
- def execute_mql(mql)
52
- CardQuery.parse(mql, @card_query_options).values
51
+ # The keys in the Hash are the names of the properties selected, with all the alphanumeric characters
52
+ # downcased and all the spaces and special characters replaced with underscores(_).
53
+ #
54
+ # Executing a mql statement with explictly supplied property names will return results as follows
55
+ # mql = select number,"defect status" where type=defect
56
+ #
57
+ # [
58
+ # {"number"=>"106", "defect_status"=>"Fixed"},
59
+ # {"number"=>"70", "defect_status"=>"Fixed"},
60
+ # {"number"=>"69", "defect_status"=>"New"},
61
+ # {"number"=>"68", "defect_status"=>"In Progress"},
62
+ # ...
63
+ # ...
64
+ # ]
65
+ #
66
+ # If aggregate functions are selected, the values look as below
67
+ # mql = select "defect status", count(*) where type=defect group by "defect status"
68
+ #
69
+ # [
70
+ # {"count"=>"14", "defect_status"=>"New"},
71
+ # {"count"=>"3", "defect_status"=>"Open"},
72
+ # {"count"=>"1", "defect_status"=>"In Progress"},
73
+ # {"count"=>"2", "defect_status"=>"Fixed"},
74
+ # {"count"=>"1", "defect_status"=>"Closed"}
75
+ # ]
76
+ #
77
+ # If no columns are explicitly provided, the results contain the raw column names specific
78
+ # properties. It is not possible to interpret these results in the general case with the current
79
+ # version of the macro development toolkit, so this is not a particularly useful form of
80
+ # MQL to execute. The documentation here is provided here just for completeness and should
81
+ # not be used as a recommended way of using this call. The structure of this response is
82
+ # subject to change in future versions of the toolkit.
83
+ #
84
+ # mql = type=defect
85
+ #
86
+ # {
87
+ # "cp_testing_status"=>"Ready to Be Tested",
88
+ # "cp_actual_effort"=>nil,
89
+ # "created_at"=>"2009-09-09 21:45:34",
90
+ # "cp_story_count"=>nil,
91
+ # "caching_stamp"=>"2",
92
+ # "cp_release_card_id"=>"2",
93
+ # "cp_risk_liklihood"=>nil,
94
+ # "cp_build_completed"=>"452",
95
+ # "cp_closed"=>nil,
96
+ # "has_macros"=>"f",
97
+ # "description"=>"",
98
+ # "cp_release_start_date"=>nil,
99
+ # "cp_risk_status"=>nil,
100
+ # "cp_story_time_to_life"=>nil,
101
+ # "cp_total_open_iterations"=>nil,
102
+ # "cp_defect_time_to_life"=>"50.00",
103
+ # "cp_development_started_on"=>nil,
104
+ # "card_type_name"=>"Defect",
105
+ # "cp_added_to_scope_on"=>nil,
106
+ # "cp_owner_user_id"=>nil,
107
+ # "cp_added_to_scope_card_id"=>nil,
108
+ # "cp_type_of_test"=>nil,
109
+ # "cp_velocity"=>nil,
110
+ # "cp_feature_card_id"=>"60"
111
+ # }
112
+ #
113
+ # Note: In versions of the toolkit beyond 1.3, the keys for the aggregate function
114
+ # (such as COUNT, SUM etc.) have been normalized to follow the same conventions as a
115
+ # property name, i.e. lowecase and stripped of all spaces.
116
+ # If you wish to get the results in the old form, set the optional second parameter
117
+ # of this call to be Project::VERSION_ONE, while you transition your macros to use the new form.
118
+ # The old version of response will be deprecated in a future version of Mingle and the toolkit.
119
+ def execute_mql(mql, version = VERSION_TWO)
120
+ @full_project.with_active_project do
121
+ CardQuery.parse(mql, @card_query_options).values_for_macro(:api_version => version)
122
+ end
53
123
  end
54
124
 
55
125
  # The macros on a page determine whether the page content is cached. Macros that use certain MQL concepts
@@ -59,11 +129,13 @@ module Mingle
59
129
  # cached.
60
130
  #
61
131
  # *accepts*: A valid MQL string. To see what constitutes valid MQL,
62
- # look here[http://studios.thoughtworks.com/mingle-agile-project-management/2.3/help/index.html]
132
+ # look here[http://studios.thoughtworks.com/mingle-agile-project-management/3.0/help/index.html]
63
133
  #
64
134
  # *returns*: A boolean indicating whether the data pertaining to the MQL can be cached
65
135
  def can_be_cached?(mql)
66
- CardQuery.parse(mql, @card_query_options).can_be_cached?
136
+ @full_project.with_active_project do
137
+ CardQuery.parse(mql, @card_query_options).can_be_cached?
138
+ end
67
139
  end
68
140
 
69
141
  # *returns*: The full list of Users who are members of this project
@@ -73,14 +145,14 @@ module Mingle
73
145
 
74
146
  # *accepts*: Any Number
75
147
  #
76
- # *returns*: The number formatted to the precision configured for the project (default 2)
148
+ # *returns*: The argument number formatted to the precision configured for the project (default 2)
77
149
  def format_number_with_project_precision(number)
78
150
  @full_project.to_num(number)
79
151
  end
80
152
 
81
153
  # *accepts*: Any Number
82
154
  #
83
- # *returns*: The number formatted to the precision configured for the project (default 2)
155
+ # *returns*: The argument date formatted using the date format configured for the project
84
156
  def format_date_with_project_date_format(date)
85
157
  @full_project.format_date(date)
86
158
  end
@@ -1,8 +1,9 @@
1
1
  module Mingle
2
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
3
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
4
+ # This is a lightweight representation of a ProjectVariable in Mingle
5
+ # A property defintion is a mnemonic name that represents a particular
6
+ # value for one or more PropertyDefinitions
6
7
  class ProjectVariable
7
8
 
8
9
  def initialize(full_project_variable)
@@ -1,7 +1,7 @@
1
1
  module Mingle
2
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
3
3
 
4
- #This is a lightweight representation of a ProjectDefinition in Mingle
4
+ # This is a lightweight representation of a ProjectDefinition in Mingle
5
5
  class PropertyDefinition
6
6
 
7
7
  MANAGED_TEXT_TYPE = "Managed text list"
@@ -13,7 +13,7 @@ module Mingle
13
13
  USER_TYPE = "Automatically generated from the team list"
14
14
  CARD_TYPE = "Card"
15
15
  AGGREGATE_TYPE = "Aggregate"
16
- TREE_RELATIONSHIP_TYPE = "Used in card tree"
16
+ TREE_RELATIONSHIP_TYPE = "Any card used in tree"
17
17
 
18
18
  def initialize(full_property_definition)
19
19
  @full_property_definition = full_property_definition
@@ -34,7 +34,18 @@ module Mingle
34
34
  @card_types_property_definitions_loader.load.collect(&:card_type).sort_by(&:position)
35
35
  end
36
36
 
37
- # *returns*: A
37
+ # *returns*: A short description of the property definition.
38
+ # This will be one of the above values
39
+ # - MANAGED_TEXT_TYPE
40
+ # - ANY_TEXT_TYPE
41
+ # - MANAGED_NUMBER_TYPE
42
+ # - ANY_NUMBER_TYPE
43
+ # - DATE_TYPE
44
+ # - FORMULA_TYPE
45
+ # - USER_TYPE
46
+ # - CARD_TYPE
47
+ # - AGGREGATE_TYPE
48
+ # - TREE_RELATIONSHIP_TYPE
38
49
  def type_description
39
50
  @full_property_definition.type_description
40
51
  end
@@ -1,7 +1,6 @@
1
1
  module Mingle
2
2
 
3
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
4
-
3
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
5
4
  class PropertyValue
6
5
 
7
6
  def initialize(property_value)
@@ -1,25 +1,29 @@
1
1
  module Mingle
2
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
2
3
 
3
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
4
-
4
+ # A lightweight model of a user in Mingle.
5
5
  class User
6
6
 
7
7
  def initialize(full_user)
8
8
  @full_user = full_user
9
9
  end
10
10
 
11
+ # *returns*: The login of the user as configured in Mingle
11
12
  def login
12
13
  @full_user.login
13
14
  end
14
15
 
16
+ # *returns*: The full name of the user as configured in Mingle
15
17
  def name
16
18
  @full_user.name
17
19
  end
18
20
 
21
+ # *returns*: The version control user name of the user as configured in Mingle
19
22
  def version_control_user_name
20
23
  @full_user.version_control_user_name
21
24
  end
22
25
 
26
+ # *returns*: The email address of the user as configured in Mingle
23
27
  def email
24
28
  @full_user.email
25
29
  end
@@ -1,7 +1,7 @@
1
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
1
+ # Copyright 2009 ThoughtWorks, Inc. All rights reserved.
2
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.
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
5
  module MingleModelLoaders
6
6
  class Base
7
7
  def initialize(project, macro_context=nil, alert_receiver=nil)
@@ -60,21 +60,25 @@ module MingleModelLoaders
60
60
 
61
61
  class LoadCardTypesByProjectId < Base
62
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)
63
+ @project.with_active_project do
64
+ @project.card_types.collect do |ct|
65
+ card_type = Mingle::CardType.new(ct)
66
+ card_type.card_types_property_definitions_loader = card_types_property_definitions_by_card_type_id_loader(ct.id)
67
+ card_type
68
+ end.sort_by(&:position)
69
+ end
68
70
  end
69
71
  end
70
72
 
71
73
  class LoadPropertyDefinitionsByProjectId < Base
72
74
  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
75
+ @project.with_active_project do
76
+ @project.all_property_definitions.collect do |pd|
77
+ property_definition = Mingle::PropertyDefinition.new(pd)
78
+ property_definition.card_types_property_definitions_loader = card_types_property_definitions_by_property_definition_id_loader(pd.id)
79
+ property_definition.values_loader = values_by_property_definition_id_loader(pd.id)
80
+ property_definition
81
+ end
78
82
  end
79
83
  end
80
84
  end
@@ -86,12 +90,14 @@ module MingleModelLoaders
86
90
  end
87
91
 
88
92
  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
93
+ @project.with_active_project do
94
+ @project.card_types.find(@card_type_id).card_types_property_definitions.collect do |ctpd|
95
+ card_type_property_definition = Mingle::CardTypePropertyDefinition.new(ctpd)
96
+ card_type_property_definition.card_type_loader = card_type_by_id_loader(ctpd.card_type_id)
97
+ card_type_property_definition.property_definition_loader = property_definition_by_id_loader(ctpd.property_definition_id)
98
+ card_type_property_definition
99
+ end.sort_by(&:position).compact
100
+ end
95
101
  end
96
102
 
97
103
  end
@@ -103,12 +109,14 @@ module MingleModelLoaders
103
109
  end
104
110
 
105
111
  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
+ @project.with_active_project do
113
+ @project.all_property_definitions.detect { |pd| pd.id == @property_definition_id }.card_types_property_definitions do |ctpd|
114
+ card_type_property_definition = Mingle::CardTypePropertyDefinition.new(ctpd)
115
+ card_type_property_definition.card_type_loader = card_type_by_id_loader(ctpd.card_type_id)
116
+ card_type_property_definition.property_definition_loader = property_definition_by_id_loader(ctpd.property_definition_id)
117
+ card_type_property_definition
118
+ end.compact.sort_by(&:position).compact
119
+ end
112
120
  end
113
121
 
114
122
  end
@@ -120,9 +128,11 @@ module MingleModelLoaders
120
128
  end
121
129
 
122
130
  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
131
+ @project.with_active_project do
132
+ ct = Mingle::CardType.new(@project.card_types.find(@card_type_id))
133
+ ct.card_types_property_definitions_loader = card_types_property_definitions_by_card_type_id_loader(@card_type_id)
134
+ ct
135
+ end
126
136
  end
127
137
  end
128
138
 
@@ -133,10 +143,12 @@ module MingleModelLoaders
133
143
  end
134
144
 
135
145
  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
146
+ @project.with_active_project do
147
+ pd = Mingle::PropertyDefinition.new(@project.all_property_definitions.detect { |pd| pd.id == @property_definition_id })
148
+ pd.card_types_property_definitions_loader = card_types_property_definitions_by_property_definition_id_loader(@property_definition_id)
149
+ pd.values_loader = values_by_property_definition_id_loader(@property_definition_id)
150
+ pd
151
+ end
140
152
  end
141
153
  end
142
154
 
@@ -147,23 +159,29 @@ module MingleModelLoaders
147
159
  end
148
160
 
149
161
  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
162
+ @project.with_active_project do
163
+ @project.all_property_definitions.detect { |pd| pd.id == @property_definition_id }.light_property_values.collect do |pv|
164
+ property_value = Mingle::PropertyValue.new(pv)
165
+ property_value.property_definition_loader = property_definition_by_id_loader(@property_definition_id)
166
+ property_value
167
+ end.compact
168
+ end
155
169
  end
156
170
  end
157
171
 
158
172
  class LoadTeamByProjectId < Base
159
173
  def load
160
- @project.users.collect { |user| Mingle::User.new(user) }
174
+ @project.with_active_project do
175
+ @project.users.collect { |user| Mingle::User.new(user) }
176
+ end
161
177
  end
162
178
  end
163
179
 
164
180
  class LoadProjectVariablesByProjectId < Base
165
181
  def load
166
- @project.project_variables.collect { |plv| Mingle::ProjectVariable.new(plv) }
182
+ @project.with_active_project do
183
+ @project.project_variables.collect { |plv| Mingle::ProjectVariable.new(plv) }
184
+ end
167
185
  end
168
186
  end
169
187
  end
@@ -1,6 +1,5 @@
1
1
  ---
2
2
  - name: Current Release
3
3
  display_value: 'Release 3'
4
-
5
4
  - name: Current Sprint
6
5
  display_value: 'Iteration 7'
@@ -1,5 +1,6 @@
1
1
  #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
2
 
3
+ require 'delegate'
3
4
  require 'test/unit'
4
5
  require 'macro_development_toolkit'
5
6
  require File.dirname(__FILE__) + '/rest_loader'
@@ -1,4 +1,4 @@
1
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
1
+ #Copyright 2009 ThoughtWorks, Inc. All rights reserved.
2
2
 
3
3
  module RESTfulLoaders
4
4
  class RemoteError < StandardError
@@ -41,7 +41,7 @@ module RESTfulLoaders
41
41
  load_all_card_types_from_xml.collect do |card_type_xml|
42
42
  card_types_property_definitions = OpenStruct.new(card_type_xml).card_types_property_definitions
43
43
  [card_types_property_definitions['card_type_property_definition']].flatten if card_types_property_definitions
44
- end.compact.flatten
44
+ end.compact.flatten.compact
45
45
  end
46
46
 
47
47
  def card_types_property_definitions_by_card_type_id_loader(card_type_id)
@@ -123,6 +123,8 @@ module RESTfulLoaders
123
123
 
124
124
  def initialize(project_name, macro_context=nil, alert_receiver=nil)
125
125
  super(project_name)
126
+ project_name =~ /(\/api\/([^\/]*))\//
127
+ @api_version_name = $1
126
128
  @macro_context = macro_context
127
129
  @alert_receiver = alert_receiver
128
130
  end
@@ -144,28 +146,32 @@ module RESTfulLoaders
144
146
  from_xml_data(
145
147
  Hash.from_xml(
146
148
  get(
147
- build_request_url(:path => "/projects/#{project.identifier}/cards/execute_mql.xml", :query => "mql=#{mql}"))))
149
+ build_request_url(:path => url_for("execute_mql"), :query => "mql=#{mql}"))))
148
150
  end
149
151
 
150
152
  def can_be_cached?(mql, project)
151
153
  from_xml_data(
152
154
  Hash.from_xml(
153
155
  get(
154
- build_request_url(:path => "/projects/#{project.identifier}/cards/can_be_cached.xml", :query => "mql=#{mql}"))))
156
+ build_request_url(:path => url_for("can_be_cached"), :query => "mql=#{mql}"))))
155
157
  end
156
158
 
157
159
  def format_number_with_project_precision(number, project)
158
160
  from_xml_data(
159
161
  Hash.from_xml(
160
162
  get(
161
- build_request_url(:path => "/projects/#{project.identifier}/cards/format_number_to_project_precision.xml", :query => "number=#{number}"))))
163
+ build_request_url(:path => url_for("format_number_to_project_precision"), :query => "number=#{number}"))))
162
164
  end
163
165
 
164
166
  def format_date_with_project_date_format(date, project)
165
167
  from_xml_data(
166
168
  Hash.from_xml(
167
169
  get(
168
- build_request_url(:path => "/projects/#{project.identifier}/cards/format_string_to_date_format.xml", :query => "date=#{date}"))))
170
+ build_request_url(:path => url_for("format_string_to_date_format"), :query => "date=#{date}"))))
171
+ end
172
+
173
+ def url_for(action)
174
+ "#{@api_version_name}/projects/#{project.identifier}/cards/#{action}.xml"
169
175
  end
170
176
 
171
177
  def build_request_url(params)
@@ -188,7 +194,6 @@ module RESTfulLoaders
188
194
  data
189
195
  end
190
196
  end
191
-
192
197
  end
193
198
 
194
199
  class LoadCardTypesByProjectId < Base
@@ -1,10 +1,11 @@
1
- #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
1
+ #Copyright 2009 ThoughtWorks, Inc. All rights reserved.
2
2
 
3
3
  require File.dirname(__FILE__) + '/integration_test_helper.rb'
4
4
 
5
5
  class RestLoaderTest < Test::Unit::TestCase
6
6
 
7
- TEST_PROJECT = 'http://bjanakir:p@localhost:8080/lightweight_projects/scrum_template_2_3.xml'
7
+ TEST_PROJECT = 'http://bjanakir:p@localhost:8080/api/v2/lightweight_projects/scrum_template_2_3.xml'
8
+ TEST_PROJECT_V1 = "http://bjanakir:p@localhost:8080/api/v1/lightweight_projects/scrum_template_2_3.xml"
8
9
 
9
10
  def test_should_load_direct_project_attributes_from_correct_fixture
10
11
  assert_not_nil project(TEST_PROJECT)
@@ -43,32 +44,42 @@ class RestLoaderTest < Test::Unit::TestCase
43
44
  assert_equal '#21 Release 1', project(TEST_PROJECT).value_of_project_variable('Current Release')
44
45
  end
45
46
 
46
- def test_should_execute_mql_to_return_an_array_of_hash_results_for_each_result_row
47
+ def test_should_execute_mql_to_return_an_array_of_hash_results_for_each_result_row_for_v2
47
48
  mql_results = project(TEST_PROJECT).execute_mql("SELECT SUM('Estimate - planning') WHERE 'Planning - Release' = (Current Release) AND 'Added On' IS NOT NULL")
49
+ assert_equal 1, mql_results.size
50
+ assert_equal Hash, mql_results.first.class
51
+ assert_equal 86, mql_results.first['sum_estimate___planning'].to_i
52
+ end
48
53
 
54
+ def test_should_execute_mql_to_return_an_array_of_hash_results_for_each_result_row_for_v1
55
+ mql_results = project(TEST_PROJECT_V1).execute_mql("SELECT SUM('Estimate - planning') WHERE 'Planning - Release' = (Current Release) AND 'Added On' IS NOT NULL")
49
56
  assert_equal 1, mql_results.size
50
57
  assert_equal Hash, mql_results.first.class
51
58
  assert_equal 86, mql_results.first['Sum_Estimate___Planning'].to_i
52
59
  end
53
60
 
54
- def test_should_execute_number_format_remotely
61
+ def test_should_execute_number_format_remotely_for_v2
55
62
  proj = project(TEST_PROJECT)
56
63
  assert_equal "3.67", proj.format_number_with_project_precision("3.6711").to_s
57
64
  assert_equal "20.14", proj.format_number_with_project_precision("20.1398").to_s
58
65
  end
59
66
 
60
- def test_should_execute_date_format_remotely
67
+ def test_should_execute_number_format_remotely_for_v1
68
+ proj = project(TEST_PROJECT_V1)
69
+ assert_equal "3.67", proj.format_number_with_project_precision("3.6711").to_s
70
+ assert_equal "20.14", proj.format_number_with_project_precision("20.1398").to_s
71
+ end
72
+
73
+ def test_should_execute_date_format_remotely_for_v2
61
74
  proj = project(TEST_PROJECT)
62
75
  assert_equal "22 May 2005", proj.format_date_with_project_date_format(Date.new(2005, 5, 22))
63
76
  assert_equal "06 Oct 2008", proj.format_date_with_project_date_format(Date.new(2008, 10, 6))
64
77
  end
65
78
 
66
- def test_should_execute_mql_to_return_an_array_of_hash_results_for_each_result_row
67
- mql_results = project(TEST_PROJECT).execute_mql("SELECT SUM('Estimate - planning') WHERE 'Planning - Release' = (Current Release) AND 'Added On' IS NOT NULL")
68
-
69
- assert_equal 1, mql_results.size
70
- assert_equal Hash, mql_results.first.class
71
- assert_equal 86, mql_results.first['Sum_Estimate___Planning'].to_i
79
+ def test_should_execute_date_format_remotely_for_v1
80
+ proj = project(TEST_PROJECT_V1)
81
+ assert_equal "22 May 2005", proj.format_date_with_project_date_format(Date.new(2005, 5, 22))
82
+ assert_equal "06 Oct 2008", proj.format_date_with_project_date_format(Date.new(2008, 10, 6))
72
83
  end
73
84
 
74
85
  def test_should_errors_in_executing_mql_should_be_available_in_the_test
@@ -1,4 +1,5 @@
1
1
  #Copyright 2008 ThoughtWorks, Inc. All rights reserved.
2
+ require 'erb'
2
3
 
3
4
  module FixtureLoaders
4
5
  class Base
@@ -9,7 +10,7 @@ module FixtureLoaders
9
10
  end
10
11
 
11
12
  def load_fixtures_for(name)
12
- YAML::load(File.open("#{@expanded_fixture}/#{name}.yml"))
13
+ YAML::load(ERB.new(File.read("#{@expanded_fixture}/#{name}.yml")).result(binding))
13
14
  end
14
15
 
15
16
  def card_types_property_definitions_by_card_type_id_loader(card_type_id)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mingle-macro-development-toolkit
3
3
  version: !ruby/object:Gem::Version
4
- version: "1.2"
4
+ version: "1.3"
5
5
  platform: ruby
6
6
  authors:
7
7
  - ThoughtWorks Inc
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-04-16 00:00:00 -07:00
12
+ date: 2009-12-04 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -30,7 +30,7 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 1.8.0
33
+ version: 2.3.3
34
34
  version:
35
35
  description: ""
36
36
  email:
@@ -41,9 +41,9 @@ extensions: []
41
41
 
42
42
  extra_rdoc_files:
43
43
  - getting_started.txt
44
- - README.rdoc
45
44
  - LICENSE.txt
46
45
  - History.txt
46
+ - README.rdoc
47
47
  files:
48
48
  - getting_started.txt
49
49
  - README.rdoc
@@ -82,11 +82,13 @@ files:
82
82
  - example/integration_test.rb
83
83
  - example/integration_test_helper.rb
84
84
  has_rdoc: true
85
- homepage: "This toolkit provides support for developing, testing and deploying custom Mingle macros. "
85
+ homepage:
86
+ licenses: []
87
+
86
88
  post_install_message: getting_started.txt
87
89
  rdoc_options:
88
90
  - --main
89
- - README.rdoc
91
+ - README.txt
90
92
  require_paths:
91
93
  - lib
92
94
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -104,9 +106,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
106
  requirements: []
105
107
 
106
108
  rubyforge_project: mingle-macros
107
- rubygems_version: 1.3.0
109
+ rubygems_version: 1.3.5
108
110
  signing_key:
109
- specification_version: 2
110
- summary: ""
111
+ specification_version: 3
112
+ summary: This toolkit provides support for developing, testing and deploying custom Mingle macros.
111
113
  test_files: []
112
114