bozo 0.3.8 → 0.4.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.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- ZGUwMTRlYmExMGUzY2FhMGMxMGI1YWRhOTE1Njg4ZTQ2NDk2MzM4NA==
4
+ MTZhNmM4OTA4NjQwZDI3NTUxN2I0MDE4NmYyNTJmOTg0OGViOGZmMA==
5
5
  data.tar.gz: !binary |-
6
- OGY3NmY1ZmI2MmVlMjg4NjhlY2NiYjU0ZjZkYjJjNTM2YjYwZWVhYw==
6
+ N2EwMGFlOTJhZTFmMjI5MzQ2MjQzMzQ4OTAxZGQ2NTU1OGQwMTQxYg==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- NTU5Y2UxZjRiOGY0ZjNmMGRjMjlmYjI2NmEwYWVmYWYxY2YwNTFjOWY3NTNj
10
- Mjc4NGM1OWRkNWJmYmQ3MDgxMjJlNmU0NGYwYjcxMjRiZDE0Y2Y1NjRlZjVl
11
- MmJhYTZhOTJhNzkyODkyMDVkZDQ0MjJmYjg3NjY3OWI3NjUzMDk=
9
+ ZmM1YzhiZmEwYjE3YWJiMGE1MTMzNTU3NWUyNjdiZjU0NGRiZTk5MGRmNjI1
10
+ MThiZWY5ODI2ZDZjZjQwNjg3NGY1ZGNjZWY3ZGRjMjdiNGVjZWQ3NDRjNmRl
11
+ YjY3Nzk4ODYxYTFmMzBkMGU3MTFkYTRhMGU5NTFkMmMzMjMxNTk=
12
12
  data.tar.gz: !binary |-
13
- YjIwODU3NjQ4YmU5OTc2ZTJhMzZhYTc2ZDExNWE0OWFlY2M1MGE4ZmMzMjM1
14
- ZWE1MDUwYmI0YTJiNGVmODY3YWE4NmZlNDBiYjYwOTQ4MDMyZWE4NjY4MDg1
15
- NDk0NTg4YWE2ZTRjMTFjMDVjMDUyNmRhYjBlODI1MGVlZGI0YWE=
13
+ OTJmNmFmYWJkY2M0Y2I4MWY3ODU2MjY0ZWQ3Mjg5YmQyM2MxYTYwNmY2Y2Rj
14
+ MDc0YTY2NzQ1YTM1NWRkMDgwOGI5YTkwMmRmNDY1MjU2ZTZlNTU0YjcyMDli
15
+ YTg5MWJjZTNkMWMwOTdlZmFhZTUxNGI0ZDdhNWQwZWU2MzMxYzk=
data/README.md CHANGED
@@ -1,427 +1,444 @@
1
- # Bozo
2
-
3
- Bozo is a build system written in Ruby. It is designed to be rigid yet
4
- extensible.
5
-
6
- ## Steps
7
-
8
- There is a fixed set of steps, they are currently:
9
-
10
- 1. Clean
11
- 2. Resolve dependencies
12
- 3. Prepare
13
- 4. Compile
14
- 5. Test
15
- 6. Package
16
- 7. Publish
17
-
18
- The steps are sequential but you can run up to any of them. For example `bozo
19
- compile` executes the `clean`, `dependencies`, `prepare` and `compile` steps
20
- whereas `bozo dependencies` only executes the `clean` and `dependencies`
21
- steps.
22
-
23
- Bozo is a framework that provides a skeleton which can be populated by custom
24
- runners and hooks. Bozo itself provides no runners or hooks a reference
25
- project for runners and hooks can be found in the [bozo-scripts
26
- project](https://github.com/zopaUK/bozo-scripts/).
27
-
28
- Each step allows several runners to execute, for example you may run RSpec
29
- unit tests followed by Cucumber integration tests within the scope of the
30
- `test` step. Each step, along with the entire build, also expose pre- and
31
- post-step hooks.
32
-
33
- ## Configuration
34
-
35
- A bozo build is configured through a single Ruby file, by convention this
36
- should be `bozorc.rb` located at the root of your project.
37
-
38
- Bozo makes use of a VERSION file in the root directory of the project. Versions can be specified in whatever format
39
- is required but a string in the format [major].[minor].[point] is generally expected.
40
-
41
- ### Conventions
42
-
43
- Dependency resolvers must be defined within the `Bozo::DependencyResolvers`
44
- module, project preparers must be defined within the `Bozo::Preparers`
45
- module, compilers must be defined within the `Bozo::Compilers` module, test
46
- runners must be defined within the `Bozo::TestRunners` module, packagers must
47
- be defined within the `Bozo::Packagers`, publishers must be defined within
48
- the `Bozo::Publishers` module and hooks, regardless of the steps they relate
49
- to, must be defined within the `Bozo::Hooks` module.
50
-
51
- Runners are specified by convention with the relevant module being inspected
52
- for a matching class definition. For example, the configuration `compile_with
53
- :msbuild` will resolve to the class definition `Bozo::Compilers::Msbuild`.
54
- The symbol provided will be converted to Pascal Case prior to resolution. For
55
- example, the configuration `pre_compile :common_assembly_info` will resolve
56
- to the class definition `Bozo::Hooks::CommonAssemblyInfo`.
57
-
58
- Each runner and hook must provide a parameterless constructor and Bozo will
59
- invoke that constructor before registering and passing the instance to any
60
- block provided as part of the configuration. A runner or hook should be able
61
- to run with the default configuration whenever possible with customizations
62
- being provided through the block:
63
-
64
- ```ruby
65
- test_with :nunit do |n| # Creates and registers a new Bozo::TestRunners::Nunit instance
66
- n.project 'Project.Tests' # Adds additonal configuration to the instance
67
- end
68
- ```
69
-
70
- If there are several runners for the same step then they will be executed in
71
- the order the are specified within the configuration.
72
-
73
- As soon as one runner or hook raises an error through either failing to
74
- execute a command successfully or some custom condition then the build is
75
- aborted.
76
-
77
- ### Configuration example
78
-
79
- The exact syntax is still a work in progress though the concepts will remain
80
- the same.
81
-
82
- ```ruby
83
- require 'bozo_scripts' # Makes custom runners and hooks available
84
-
85
- prepare :common_assembly_info # Defines that the common assembly info should be prepared for the project
86
-
87
- compile_with :msbuild # Defines that the project should be compiled with the `msbuild` compiler
88
-
89
- test_with :nunit do |n| # Defines that the project should be tested with the `nunit` test runner
90
- n.project 'Project.Tests' # Runner specific configuration - in this case defining the assemblies to run
91
- end
92
-
93
- package_with :nuget do |p| # Defines that the project should be packaged with `nuget`
94
- p.project 'Project' # Runner specific configuration - in this case the projects to package
95
- p.project 'Project.Testing'
96
- end
97
-
98
- resolve_dependencies_with :nuget # Defines that project dependencies should be resolved with `nuget`
99
-
100
- with_hook :git_commit_hashes # Defines that the `git_commit_hashes` hook should be executed with the build
101
- with_hook :timing # Defines that the `timing` hook should be executed with the build
102
-
103
- build_tools_location '//SERVER/network/path' # Defines the location build tools can be copied from
104
- ```
105
-
106
- ## Creating step runners and hooks
107
-
108
- Both step runners and hooks have their nuances which are covered in their
109
- dedicated sections. However, both are extended by the `Bozo::Runner` module
110
- that makes a collection of methods available to them.
111
-
112
- ### build_configuration
113
-
114
- Returns the `Bozo::Configuration` of the build.
115
-
116
- ### build_server?
117
-
118
- Returns `true` when the build is being run with the `--build-server` switch,
119
- otherwise `false`.
120
-
121
- This is a shortcut for `global_params[:build_server]`.
122
-
123
- ### pre_release?
124
-
125
- Returns `true` when the build is being run with the `--pre-release` switch,
126
- otherwise `false`.
127
-
128
- This is a shortcut for `params[:pre_release]`.
129
-
130
- ### env
131
-
132
- Returns the hash of environment variables. Initially populated by calling
133
- `ENV.to_hash` this may be added to by runners and hooks to enable lightweight
134
- communication and to cache the result of expensive calls.
135
-
136
- ### environment
137
-
138
- Returns the name of the environment that the build is running in, eg.
139
- `'development'`.
140
-
141
- This is a shortcut for `global_params[:environment]`.
142
-
143
- ### execute_command(tool, args)
144
-
145
- Executes a command line tool.
146
-
147
- Raises a `Bozo::ExecutionError` if the command responds with a non-zero exit
148
- code.
149
-
150
- #### Parameters
151
-
152
- * __tool [Symbol]__ A friendly identifier for the tool
153
- * __args [Array]__ An array of arguments making up the command to execute
154
-
155
- ### global_params
156
-
157
- Returns the hash of global parameters passed to bozo. All key symbols are
158
- converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
159
- idiomatic for Ruby.
160
-
161
- ### log_debug(msg)
162
-
163
- Records an `debug` log message.
164
-
165
- #### Parameters
166
-
167
- * __msg [String]__ The message to log
168
-
169
- ### log_fatal(msg)
170
-
171
- Records an `fatal` log message.
172
-
173
- #### Parameters
174
-
175
- * __msg [String]__ The message to log
176
-
177
- ### log_info(msg)
178
-
179
- Records an `info` log message.
180
-
181
- #### Parameters
182
-
183
- * __msg [String]__ The message to log
184
-
185
- ### log_warn(msg)
186
-
187
- Records an `warn` log message.
188
-
189
- #### Parameters
190
-
191
- * __msg [String]__ The message to log
192
-
193
- ### params
194
-
195
- Returns the hash of command parameters passed to bozo. All key symbols are
196
- converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
197
- idiomatic for Ruby.
198
-
199
- ### version
200
-
201
- Returns the version of the build.
202
-
203
- This is a shortcut for `build_configuration.version`.
204
-
205
- ## Creating step runners
206
-
207
- The structure of all runners is the same. They must be defined within the
208
- appropriate module, dependency resolvers in the `Bozo::DependencyResolvers`
209
- module, project preparers must be defined within the `Bozo::Preparers`
210
- module, compilers in the`Bozo::Compilers` module, test runners in the
211
- `Bozo::TestRunners` module, packagers in the `Bozo::Packagers` module and
212
- publishers in the `Bozo::Publishers` module. They must have a parameterless
213
- constructor and they must expose an `#execute` method which will be invoked
214
- when they should execute whatever task they are meant to perform. They can
215
- optionally define a `#required_tools` method which returns the name of any
216
- build tools it requires that cannot be retrieved through dependency
217
- resolvers, for example a dependency resolving executable such as `nuget.exe`.
218
-
219
- When executing a command line executable they should use the
220
- `execute_command(tool, args)` method so that the command will be logged in if
221
- the correct format and if executable completes with an error exit code the
222
- build will be aborted. They should also use the `log_info(msg)` and
223
- `log_debug(msg)` methods to ensure their output is formatted correctly and
224
- the verbosity of the messages can be controlled centrally.
225
-
226
- The runner will be passed back to the configuration code via an optional
227
- block so if further configuration of the runner is possible, or required,
228
- this should be exposed through public methods on the runner. If required
229
- configuration is omitted then a `Bozo::ConfigurationError` with a message
230
- explaining the problem and how to rectify it should be raised when the
231
- `#execute` method of the runner is called.
232
-
233
- ### Registration
234
-
235
- Runners are registered through step-specific methods:
236
-
237
- * `dependency_resolver(identifier, &block)` registers dependency resolvers
238
- * `prepare(identifier, &block)` registers project preparers
239
- * `compile_with(identifier, &block)` registers compilers
240
- * `test_with(identifier, &block)` registers test runners
241
- * `package_with(identifier, &block)` registers packagers
242
- * `publish_with(identifier, &block)` registers publishers
243
-
244
- ### Example
245
-
246
- Here is an example of a 'compiler' that logs `"Hello, <name>!"` where name is
247
- configured from the optional block and a `Bozo::ConfigurationError` is raised
248
- if no name has been configured:
249
-
250
- ```ruby
251
- module Bozo::Compilers
252
-
253
- class HelloWorld
254
-
255
- def name(name)
256
- @name = name
257
- end
258
-
259
- def execute
260
- raise Bozo::ConfigurationError.new('You must specify a name to say "Hello" to') if @name.nil?
261
- log_info "Hello, #{@name}!"
262
- end
263
-
264
- end
265
-
266
- end
267
- ```
268
-
269
- This compiler would be added to your build via the configuration:
270
-
271
- ```ruby
272
- compile_with :hello_world do |hw|
273
- hw.name 'Bozo'
274
- end
275
- ```
276
-
277
- ## Creating hooks
278
-
279
- The structure of all hooks is the same. The must be defined within the
280
- `Bozo::Hooks` module and they must have a parameterless constructor. They can
281
- optionally define a `#required_tools` method which returns the name of any
282
- build tools it requires that cannot be retrieved through dependency resolvers,
283
- for example a dependency resolving executable such as `nuget.exe`.
284
-
285
- When executing a command line executable they should use the
286
- `execute_command(tool, args)` method so that the command will be logged in if
287
- the correct format and if executable completes with an error exit code the
288
- build will be aborted. They should also use the `log_info(msg)` and
289
- `log_debug(msg)` methods to ensure their output is formatted correctly and the
290
- verbosity of the messages can be controlled centrally.
291
-
292
- The hook will be passed back to the configuration code via an optional block
293
- so if further configuration of the hook is possible, or required, this should
294
- be exposed through public methods on the hook. If required configuration is
295
- omitted then a `Bozo::ConfigurationError` with a message explaining the
296
- problem and how to rectify it should be raised when a hook method is called.
297
-
298
- A hook can be called several times. In order to hook around a step all that is
299
- required is that an appropriately named method is defined within the class.
300
- For example, this hook logs a message both before and after the compile step
301
- is run:
302
-
303
- ```ruby
304
- module Bozo::Hooks
305
-
306
- class CompilingMessages
307
-
308
- def pre_compile
309
- log_info 'About to compile'
310
- end
311
-
312
- def post_compile
313
- log_info 'Finished compiling'
314
- end
315
-
316
- end
317
-
318
- end
319
- ```
320
-
321
- Which steps the hook wants to execute on is determined by checking the
322
- response to the `#respond_to?` method so if you wish to use `#method_missing`
323
- to add functionality you need to ensure that the response to `#respond_to?`
324
- reflects that.
325
-
326
- ### Registration
327
-
328
- As hook instances can listen to one or more pre- or post-stage hooks there are
329
- multiple ways to register a hook. However, they are all functionally identical
330
- and are just aliases to the same method so that your configuration can read
331
- more clearly.
332
-
333
- The registration methods are:
334
-
335
- * `with_hook(identifier, &block)` (recommended when hooking several stages)
336
- * `pre_build(identifier, &block)`
337
- * `post_build(identifier, &block)`
338
- * `pre_clean(identifier, &block)`
339
- * `post_clean(identifier, &block)`
340
- * `pre_dependencies(identifier, &block)`
341
- * `post_dependencies(identifier, &block)`
342
- * `pre_prepare(identifier, &block)`
343
- * `post_prepare(identifier, &block)`
344
- * `pre_compile(identifier, &block)`
345
- * `post_compile(identifier, &block)`
346
- * `pre_test(identifier, &block)`
347
- * `post_test(identifier, &block)`
348
- * `pre_package(identifier, &block)`
349
- * `post_package(identifier, &block)`
350
- * `pre_publish(identifier, &block)`
351
- * `post_publish(identifier, &block)`
352
-
353
- Failed hooks exist that are called when a stage fails, in these cases the
354
- relevant `post` hook is not called.
355
-
356
- * `failed_build(identifier, &block)`
357
- * `failed_clean(identifier, &block)`
358
- * `failed_dependencies(identifier, &block)`
359
- * `failed_prepare(identifier, &block)`
360
- * `failed_compile(identifier, &block)`
361
- * `failed_test(identifier, &block)`
362
- * `failed_package(identifier, &block)`
363
- * `failed_publish(identifier, &block)`
364
-
365
- ## Build tools
366
-
367
- Build tools are usually executables that you need to perform a task that are
368
- not available via some other means.
369
-
370
- For example, at Zopa we use in Nuget to resolve our .NET dependencies. This is
371
- a chicken and egg situation in that you can't use a dependency management
372
- system like Nuget until you've got a copy of the Nuget executable you can
373
- call. The build tools function aims to resolve this loop of cyclical dependency.
374
-
375
- Your build tools are resolve as the first part of the "resolve dependencies"
376
- step. When possible you should use real package management systems to retrieve
377
- dependencies rather than using the build tools function.
378
-
379
- ### Specifying required build tools
380
-
381
- All the runners and hooks you create can optionally specify a `required_tools`
382
- method which returns the name of one or more required build tools:
383
-
384
- ```ruby
385
- module Bozo::DependencyResolvers
386
-
387
- class Nuget
388
-
389
- def required_tools
390
- :nuget # or for many [:nuget, :open_wrap]
391
- end
392
-
393
- end
394
-
395
- end
396
- ```
397
-
398
- ### How it works
399
-
400
- Within the example configuration there is a single line:
401
-
402
- ```ruby
403
- build_tools_location '//SERVER/network/path' # Defines the location build tools can be copied from
404
- ```
405
-
406
- This specifies the location that build tools should be retrieved from. This
407
- location is then joined with the name of the build tool to find the directory
408
- that must be copied into the `./build/tools` directory. For example with a
409
- `build_tools_location` of `//SERVER/network/path` along with a required
410
- build tool called `:nuget` will result in the directory
411
- `//SERVER/network/path/nuget` being copied to `./build/tools/nuget` directory.
412
- By knowing the contents of this directory you can then invoke the executables
413
- contained within it:
414
-
415
- ```ruby
416
- module Bozo::DependencyResolvers
417
-
418
- class Nuget
419
-
420
- def execute
421
- execute_command :nuget, File.join('build', 'tools', 'nuget', 'NuGet.exe')
422
- end
423
-
424
- end
425
-
426
- end
1
+ # Bozo
2
+
3
+ Bozo is a build system written in Ruby. It is designed to be rigid yet
4
+ extensible.
5
+
6
+ ## Steps
7
+
8
+ There is a fixed set of steps, they are currently:
9
+
10
+ 1. Clean
11
+ 2. Resolve dependencies
12
+ 3. Prepare
13
+ 4. Compile
14
+ 5. Test
15
+ 6. Package
16
+ 7. Publish
17
+
18
+ The steps are sequential but you can run up to any of them. For example `bozo
19
+ compile` executes the `clean`, `dependencies`, `prepare` and `compile` steps
20
+ whereas `bozo dependencies` only executes the `clean` and `dependencies`
21
+ steps.
22
+
23
+ Bozo is a framework that provides a skeleton which can be populated by custom
24
+ runners and hooks. Bozo itself provides no runners or hooks a reference
25
+ project for runners and hooks can be found in the [bozo-scripts
26
+ project](https://github.com/zopaUK/bozo-scripts/).
27
+
28
+ Each step allows several runners to execute, for example you may run RSpec
29
+ unit tests followed by Cucumber integration tests within the scope of the
30
+ `test` step. Each step, along with the entire build, also expose pre- and
31
+ post-step hooks.
32
+
33
+ ## Configuration
34
+
35
+ A bozo build is configured through a single Ruby file, by convention this
36
+ should be `bozorc.rb` located at the root of your project.
37
+
38
+ Bozo makes use of a VERSION file in the root directory of the project. Versions can be specified in whatever format
39
+ is required but a string in the format [major].[minor].[point] is generally expected.
40
+
41
+ ### Conventions
42
+
43
+ Dependency resolvers must be defined within the `Bozo::DependencyResolvers`
44
+ module, project preparers must be defined within the `Bozo::Preparers`
45
+ module, compilers must be defined within the `Bozo::Compilers` module, test
46
+ runners must be defined within the `Bozo::TestRunners` module, packagers must
47
+ be defined within the `Bozo::Packagers`, publishers must be defined within
48
+ the `Bozo::Publishers` module and hooks, regardless of the steps they relate
49
+ to, must be defined within the `Bozo::Hooks` module.
50
+
51
+ Runners are specified by convention with the relevant module being inspected
52
+ for a matching class definition. For example, the configuration `compile_with
53
+ :msbuild` will resolve to the class definition `Bozo::Compilers::Msbuild`.
54
+ The symbol provided will be converted to Pascal Case prior to resolution. For
55
+ example, the configuration `pre_compile :common_assembly_info` will resolve
56
+ to the class definition `Bozo::Hooks::CommonAssemblyInfo`.
57
+
58
+ Each runner and hook must provide a parameterless constructor and Bozo will
59
+ invoke that constructor before registering and passing the instance to any
60
+ block provided as part of the configuration. A runner or hook should be able
61
+ to run with the default configuration whenever possible with customizations
62
+ being provided through the block:
63
+
64
+ ```ruby
65
+ test_with :nunit do |n| # Creates and registers a new Bozo::TestRunners::Nunit instance
66
+ n.project 'Project.Tests' # Adds additonal configuration to the instance
67
+ end
68
+ ```
69
+
70
+ If there are several runners for the same step then they will be executed in
71
+ the order the are specified within the configuration.
72
+
73
+ As soon as one runner or hook raises an error through either failing to
74
+ execute a command successfully or some custom condition then the build is
75
+ aborted.
76
+
77
+ ### Configuration example
78
+
79
+ The exact syntax is still a work in progress though the concepts will remain
80
+ the same.
81
+
82
+ ```ruby
83
+ require 'bozo_scripts' # Makes custom runners and hooks available
84
+
85
+ prepare :common_assembly_info # Defines that the common assembly info should be prepared for the project
86
+
87
+ compile_with :msbuild # Defines that the project should be compiled with the `msbuild` compiler
88
+
89
+ test_with :nunit do |n| # Defines that the project should be tested with the `nunit` test runner
90
+ n.project 'Project.Tests' # Runner specific configuration - in this case defining the assemblies to run
91
+ end
92
+
93
+ package_with :nuget do |p| # Defines that the project should be packaged with `nuget`
94
+ p.project 'Project' # Runner specific configuration - in this case the projects to package
95
+ p.project 'Project.Testing'
96
+ end
97
+
98
+ resolve_dependencies_with :nuget # Defines that project dependencies should be resolved with `nuget`
99
+
100
+ with_hook :git_commit_hashes # Defines that the `git_commit_hashes` hook should be executed with the build
101
+ with_hook :timing # Defines that the `timing` hook should be executed with the build
102
+
103
+ build_tools_location '//SERVER/network/path' # Defines the location build tools can be copied from
104
+ ```
105
+
106
+ ## Creating step runners and hooks
107
+
108
+ Both step runners and hooks have their nuances which are covered in their
109
+ dedicated sections. However, both are extended by the `Bozo::Runner` module
110
+ that makes a collection of methods available to them.
111
+
112
+ ### build_configuration
113
+
114
+ Returns the `Bozo::Configuration` of the build.
115
+
116
+ ### build_server?
117
+
118
+ Returns `true` when the build is being run with the `--build-server` switch,
119
+ otherwise `false`.
120
+
121
+ This is a shortcut for `global_params[:build_server]`.
122
+
123
+ ### pre_release?
124
+
125
+ Returns `true` when the build is being run with the `--pre-release` switch,
126
+ otherwise `false`.
127
+
128
+ This is a shortcut for `params[:pre_release]`.
129
+
130
+ ### env
131
+
132
+ Returns the hash of environment variables. Initially populated by calling
133
+ `ENV.to_hash` this may be added to by runners and hooks to enable lightweight
134
+ communication and to cache the result of expensive calls.
135
+
136
+ ### environment
137
+
138
+ Returns the name of the environment that the build is running in, eg.
139
+ `'development'`.
140
+
141
+ This is a shortcut for `global_params[:environment]`.
142
+
143
+ ### execute_command(tool, args)
144
+
145
+ Executes a command line tool.
146
+
147
+ Raises a `Bozo::ExecutionError` if the command responds with a non-zero exit
148
+ code.
149
+
150
+ #### Parameters
151
+
152
+ * __tool [Symbol]__ A friendly identifier for the tool
153
+ * __args [Array]__ An array of arguments making up the command to execute
154
+
155
+ ### global_params
156
+
157
+ Returns the hash of global parameters passed to bozo. All key symbols are
158
+ converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
159
+ idiomatic for Ruby.
160
+
161
+ ### log_debug(msg)
162
+
163
+ Records an `debug` log message.
164
+
165
+ #### Parameters
166
+
167
+ * __msg [String]__ The message to log
168
+
169
+ ### log_fatal(msg)
170
+
171
+ Records an `fatal` log message.
172
+
173
+ #### Parameters
174
+
175
+ * __msg [String]__ The message to log
176
+
177
+ ### log_info(msg)
178
+
179
+ Records an `info` log message.
180
+
181
+ #### Parameters
182
+
183
+ * __msg [String]__ The message to log
184
+
185
+ ### log_warn(msg)
186
+
187
+ Records an `warn` log message.
188
+
189
+ #### Parameters
190
+
191
+ * __msg [String]__ The message to log
192
+
193
+ ### params
194
+
195
+ Returns the hash of command parameters passed to bozo. All key symbols are
196
+ converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
197
+ idiomatic for Ruby.
198
+
199
+ ### version
200
+
201
+ Returns the version of the build.
202
+
203
+ This is a shortcut for `build_configuration.version`.
204
+
205
+ ## Creating step runners
206
+
207
+ The structure of all runners is the same. They must be defined within the
208
+ appropriate module, dependency resolvers in the `Bozo::DependencyResolvers`
209
+ module, project preparers must be defined within the `Bozo::Preparers`
210
+ module, compilers in the`Bozo::Compilers` module, test runners in the
211
+ `Bozo::TestRunners` module, packagers in the `Bozo::Packagers` module and
212
+ publishers in the `Bozo::Publishers` module. They must have a parameterless
213
+ constructor and they must expose an `#execute` method which will be invoked
214
+ when they should execute whatever task they are meant to perform. They can
215
+ optionally define a `#required_tools` method which returns the name of any
216
+ build tools it requires that cannot be retrieved through dependency
217
+ resolvers, for example a dependency resolving executable such as `nuget.exe`.
218
+
219
+ When executing a command line executable they should use the
220
+ `execute_command(tool, args)` method so that the command will be logged in if
221
+ the correct format and if executable completes with an error exit code the
222
+ build will be aborted. They should also use the `log_info(msg)` and
223
+ `log_debug(msg)` methods to ensure their output is formatted correctly and
224
+ the verbosity of the messages can be controlled centrally.
225
+
226
+ The runner will be passed back to the configuration code via an optional
227
+ block so if further configuration of the runner is possible, or required,
228
+ this should be exposed through public methods on the runner. If required
229
+ configuration is omitted then a `Bozo::ConfigurationError` with a message
230
+ explaining the problem and how to rectify it should be raised when the
231
+ `#execute` method of the runner is called.
232
+
233
+ ### Registration
234
+
235
+ Runners are registered through step-specific methods:
236
+
237
+ * `dependency_resolver(identifier, &block)` registers dependency resolvers
238
+ * `prepare(identifier, &block)` registers project preparers
239
+ * `compile_with(identifier, &block)` registers compilers
240
+ * `test_with(identifier, &block)` registers test runners
241
+ * `package_with(identifier, &block)` registers packagers
242
+ * `publish_with(identifier, &block)` registers publishers
243
+
244
+ ### Example
245
+
246
+ Here is an example of a 'compiler' that logs `"Hello, <name>!"` where name is
247
+ configured from the optional block and a `Bozo::ConfigurationError` is raised
248
+ if no name has been configured:
249
+
250
+ ```ruby
251
+ module Bozo::Compilers
252
+
253
+ class HelloWorld
254
+
255
+ def name(name)
256
+ @name = name
257
+ end
258
+
259
+ def execute
260
+ raise Bozo::ConfigurationError.new('You must specify a name to say "Hello" to') if @name.nil?
261
+ log_info "Hello, #{@name}!"
262
+ end
263
+
264
+ end
265
+
266
+ end
267
+ ```
268
+
269
+ This compiler would be added to your build via the configuration:
270
+
271
+ ```ruby
272
+ compile_with :hello_world do |hw|
273
+ hw.name 'Bozo'
274
+ end
275
+ ```
276
+
277
+ ## Creating hooks
278
+
279
+ The structure of all hooks is the same. The must be defined within the
280
+ `Bozo::Hooks` module and they must have a parameterless constructor. They can
281
+ optionally define a `#required_tools` method which returns the name of any
282
+ build tools it requires that cannot be retrieved through dependency resolvers,
283
+ for example a dependency resolving executable such as `nuget.exe`.
284
+
285
+ When executing a command line executable they should use the
286
+ `execute_command(tool, args)` method so that the command will be logged in if
287
+ the correct format and if executable completes with an error exit code the
288
+ build will be aborted. They should also use the `log_info(msg)` and
289
+ `log_debug(msg)` methods to ensure their output is formatted correctly and the
290
+ verbosity of the messages can be controlled centrally.
291
+
292
+ The hook will be passed back to the configuration code via an optional block
293
+ so if further configuration of the hook is possible, or required, this should
294
+ be exposed through public methods on the hook. If required configuration is
295
+ omitted then a `Bozo::ConfigurationError` with a message explaining the
296
+ problem and how to rectify it should be raised when a hook method is called.
297
+
298
+ A hook can be called several times. In order to hook around a step all that is
299
+ required is that an appropriately named method is defined within the class.
300
+ For example, this hook logs a message both before and after the compile step
301
+ is run:
302
+
303
+ ```ruby
304
+ module Bozo::Hooks
305
+
306
+ class CompilingMessages
307
+
308
+ def pre_compile
309
+ log_info 'About to compile'
310
+ end
311
+
312
+ def post_compile
313
+ log_info 'Finished compiling'
314
+ end
315
+
316
+ end
317
+
318
+ end
319
+ ```
320
+
321
+ Which steps the hook wants to execute on is determined by checking the
322
+ response to the `#respond_to?` method so if you wish to use `#method_missing`
323
+ to add functionality you need to ensure that the response to `#respond_to?`
324
+ reflects that.
325
+
326
+ ### Registration
327
+
328
+ As hook instances can listen to one or more pre- or post-stage hooks there are
329
+ multiple ways to register a hook. However, they are all functionally identical
330
+ and are just aliases to the same method so that your configuration can read
331
+ more clearly.
332
+
333
+ The registration methods are:
334
+
335
+ * `with_hook(identifier, &block)` (recommended when hooking several stages)
336
+ * `pre_build(identifier, &block)`
337
+ * `post_build(identifier, &block)`
338
+ * `pre_clean(identifier, &block)`
339
+ * `post_clean(identifier, &block)`
340
+ * `pre_dependencies(identifier, &block)`
341
+ * `post_dependencies(identifier, &block)`
342
+ * `pre_prepare(identifier, &block)`
343
+ * `post_prepare(identifier, &block)`
344
+ * `pre_compile(identifier, &block)`
345
+ * `post_compile(identifier, &block)`
346
+ * `pre_test(identifier, &block)`
347
+ * `post_test(identifier, &block)`
348
+ * `pre_package(identifier, &block)`
349
+ * `post_package(identifier, &block)`
350
+ * `pre_publish(identifier, &block)`
351
+ * `post_publish(identifier, &block)`
352
+
353
+ Failed hooks exist that are called when a stage fails, in these cases the
354
+ relevant `post` hook is not called.
355
+
356
+ * `failed_build(identifier, &block)`
357
+ * `failed_clean(identifier, &block)`
358
+ * `failed_dependencies(identifier, &block)`
359
+ * `failed_prepare(identifier, &block)`
360
+ * `failed_compile(identifier, &block)`
361
+ * `failed_test(identifier, &block)`
362
+ * `failed_package(identifier, &block)`
363
+ * `failed_publish(identifier, &block)`
364
+
365
+ ## Build tools
366
+
367
+ Build tools are usually executables that you need to perform a task that are
368
+ not available via some other means.
369
+
370
+ For example, at Zopa we use in Nuget to resolve our .NET dependencies. This is
371
+ a chicken and egg situation in that you can't use a dependency management
372
+ system like Nuget until you've got a copy of the Nuget executable you can
373
+ call. The build tools function aims to resolve this loop of cyclical dependency.
374
+
375
+ Your build tools are resolved as the first part of the "resolve dependencies"
376
+ step. When possible you should use real package management systems to retrieve
377
+ dependencies rather than using the build tools function.
378
+
379
+ ### Specifying required build tools
380
+
381
+ All the runners and hooks you create can optionally specify a `required_tools`
382
+ method which returns the name of one or more required build tools:
383
+
384
+ ```ruby
385
+ module Bozo::DependencyResolvers
386
+
387
+ class Nuget
388
+
389
+ def required_tools
390
+ :nuget # or for many [:nuget, :open_wrap]
391
+ end
392
+
393
+ end
394
+
395
+ end
396
+ ```
397
+
398
+ Tools that aren't `required_tools` of another runner can be specified using the following:
399
+
400
+ ```ruby
401
+ required_tool :nuget
402
+
403
+ required_tool :tool_with_configuration do |n|
404
+ n.tool_version '1.0'
405
+ end
406
+ ```
407
+
408
+ In the case of the configuration `required_tool` method only the `Bozo::Tools` module is used.
409
+
410
+ ### How it works
411
+
412
+ There are two ways which tools may be resolved when required by another module, either
413
+ from the `build_tools_location` or via a `Bozo::Tool` module class. A class in the `Bozo::Tool` module
414
+ takes priority over the `build_tools_location`, if Bozo fails to find a class with the same name then
415
+ the `build_tools_location` is used.
416
+
417
+ Within the example configuration there is a single line:
418
+
419
+ ```ruby
420
+ build_tools_location '//SERVER/network/path' # Defines the location build tools can be copied from
421
+ ```
422
+
423
+ This specifies the location that build tools should be retrieved from. This
424
+ location is then joined with the name of the build tool to find the directory
425
+ that must be copied into the `./build/tools` directory. For example with a
426
+ `build_tools_location` of `//SERVER/network/path` along with a required
427
+ build tool called `:nuget` will result in the directory
428
+ `//SERVER/network/path/nuget` being copied to `./build/tools/nuget` directory.
429
+ By knowing the contents of this directory you can then invoke the executables
430
+ contained within it:
431
+
432
+ ```ruby
433
+ module Bozo::DependencyResolvers
434
+
435
+ class Nuget
436
+
437
+ def execute
438
+ execute_command :nuget, File.join('build', 'tools', 'nuget', 'NuGet.exe')
439
+ end
440
+
441
+ end
442
+
443
+ end
427
444
  ```