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 +5 -0
- data/LICENSE.txt +1 -1
- data/README.rdoc +1 -1
- data/Rakefile +6 -4
- data/bin/new_mingle_macro +1 -1
- data/example/Rakefile +3 -0
- data/example/integration_test.rb +14 -2
- data/example/integration_test_helper.rb +18 -6
- data/example/unit_test.rb +6 -0
- data/example/unit_test_helper.rb +12 -2
- data/getting_started.txt +18 -7
- data/lib/macro_development_toolkit.rb +2 -2
- data/lib/macro_development_toolkit/mingle/card_type.rb +4 -4
- data/lib/macro_development_toolkit/mingle/card_type_property_definition.rb +4 -4
- data/lib/macro_development_toolkit/mingle/project.rb +90 -18
- data/lib/macro_development_toolkit/mingle/project_variable.rb +4 -3
- data/lib/macro_development_toolkit/mingle/property_definition.rb +15 -4
- data/lib/macro_development_toolkit/mingle/property_value.rb +1 -2
- data/lib/macro_development_toolkit/mingle/user.rb +6 -2
- data/lib/macro_development_toolkit/mingle_model_loader.rb +57 -39
- data/test/fixtures/sample/project_variables.yml +0 -1
- data/test/integration/integration_test_helper.rb +1 -0
- data/test/integration/rest_loader.rb +12 -7
- data/test/integration/rest_loader_test.rb +22 -11
- data/test/unit/fixture_loader.rb +2 -1
- metadata +11 -9
data/History.txt
CHANGED
data/LICENSE.txt
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
The MIT License
|
2
2
|
|
3
|
-
Copyright (c)
|
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)
|
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
|
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.
|
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.
|
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
data/example/Rakefile
CHANGED
data/example/integration_test.rb
CHANGED
@@ -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.
|
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 ||=
|
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
|
-
|
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
|
data/example/unit_test_helper.rb
CHANGED
@@ -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 ||=
|
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.
|
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/
|
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,
|
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
|
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
|
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
|
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
|
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
|
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.
|
7
|
+
VERSION = '1.3'
|
8
8
|
end
|
9
9
|
|
10
10
|
require 'yaml'
|
@@ -1,9 +1,9 @@
|
|
1
1
|
module Mingle
|
2
|
-
#Copyright
|
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
|
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
|
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
|
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/
|
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
|
50
|
-
# with underscores(_).
|
51
|
-
|
52
|
-
|
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/
|
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
|
-
|
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
|
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
|
2
|
+
# Copyright 2009 ThoughtWorks, Inc. All rights reserved.
|
3
3
|
|
4
|
-
#This is a lightweight representation of a ProjectVariable in Mingle
|
5
|
-
#
|
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
|
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 = "
|
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,25 +1,29 @@
|
|
1
1
|
module Mingle
|
2
|
+
# Copyright 2009 ThoughtWorks, Inc. All rights reserved.
|
2
3
|
|
3
|
-
|
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
|
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.
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
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.
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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.
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
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.
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
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
|
-
|
124
|
-
|
125
|
-
|
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
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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.
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
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.
|
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.
|
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,4 +1,4 @@
|
|
1
|
-
#Copyright
|
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 => "
|
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
|
-
|
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 => "
|
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 => "
|
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
|
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
|
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
|
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
|
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
|
67
|
-
|
68
|
-
|
69
|
-
assert_equal
|
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
|
data/test/unit/fixture_loader.rb
CHANGED
@@ -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.
|
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.
|
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
|
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:
|
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:
|
85
|
+
homepage:
|
86
|
+
licenses: []
|
87
|
+
|
86
88
|
post_install_message: getting_started.txt
|
87
89
|
rdoc_options:
|
88
90
|
- --main
|
89
|
-
- README.
|
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.
|
109
|
+
rubygems_version: 1.3.5
|
108
110
|
signing_key:
|
109
|
-
specification_version:
|
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
|
|