bozo 0.3.3 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,408 +1,420 @@
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
- ### env
124
-
125
- Returns the hash of environment variables. Initially populated by calling
126
- `ENV.to_hash` this may be added to by runners and hooks to enable lightweight
127
- communication and to cache the result of expensive calls.
128
-
129
- ### environment
130
-
131
- Returns the name of the environment that the build is running in, eg.
132
- `'development'`.
133
-
134
- This is a shortcut for `global_params[:environment]`.
135
-
136
- ### execute_command(tool, args)
137
-
138
- Executes a command line tool.
139
-
140
- Raises a `Bozo::ExecutionError` if the command responds with a non-zero exit
141
- code.
142
-
143
- #### Parameters
144
-
145
- * __tool [Symbol]__ A friendly identifier for the tool
146
- * __args [Array]__ An array of arguments making up the command to execute
147
-
148
- ### global_params
149
-
150
- Returns the hash of global parameters passed to bozo. All key symbols are
151
- converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
152
- idiomatic for Ruby.
153
-
154
- ### log_debug(msg)
155
-
156
- Records an `debug` log message.
157
-
158
- #### Parameters
159
-
160
- * __msg [String]__ The message to log
161
-
162
- ### log_fatal(msg)
163
-
164
- Records an `fatal` log message.
165
-
166
- #### Parameters
167
-
168
- * __msg [String]__ The message to log
169
-
170
- ### log_info(msg)
171
-
172
- Records an `info` log message.
173
-
174
- #### Parameters
175
-
176
- * __msg [String]__ The message to log
177
-
178
- ### log_warn(msg)
179
-
180
- Records an `warn` log message.
181
-
182
- #### Parameters
183
-
184
- * __msg [String]__ The message to log
185
-
186
- ### params
187
-
188
- Returns the hash of command parameters passed to bozo. All key symbols are
189
- converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
190
- idiomatic for Ruby.
191
-
192
- ### version
193
-
194
- Returns the version of the build.
195
-
196
- This is a shortcut for `build_configuration.version`.
197
-
198
- ## Creating step runners
199
-
200
- The structure of all runners is the same. They must be defined within the
201
- appropriate module, dependency resolvers in the `Bozo::DependencyResolvers`
202
- module, project preparers must be defined within the `Bozo::Preparers`
203
- module, compilers in the`Bozo::Compilers` module, test runners in the
204
- `Bozo::TestRunners` module, packagers in the `Bozo::Packagers` module and
205
- publishers in the `Bozo::Publishers` module. They must have a parameterless
206
- constructor and they must expose an `#execute` method which will be invoked
207
- when they should execute whatever task they are meant to perform. They can
208
- optionally define a `#required_tools` method which returns the name of any
209
- build tools it requires that cannot be retrieved through dependency
210
- resolvers, for example a dependency resolving executable such as `nuget.exe`.
211
-
212
- When executing a command line executable they should use the
213
- `execute_command(tool, args)` method so that the command will be logged in if
214
- the correct format and if executable completes with an error exit code the
215
- build will be aborted. They should also use the `log_info(msg)` and
216
- `log_debug(msg)` methods to ensure their output is formatted correctly and
217
- the verbosity of the messages can be controlled centrally.
218
-
219
- The runner will be passed back to the configuration code via an optional
220
- block so if further configuration of the runner is possible, or required,
221
- this should be exposed through public methods on the runner. If required
222
- configuration is omitted then a `Bozo::ConfigurationError` with a message
223
- explaining the problem and how to rectify it should be raised when the
224
- `#execute` method of the runner is called.
225
-
226
- ### Registration
227
-
228
- Runners are registered through step-specific methods:
229
-
230
- * `dependency_resolver(identifier, &block)` registers dependency resolvers
231
- * `prepare(identifier, &block)` registers project preparers
232
- * `compile_with(identifier, &block)` registers compilers
233
- * `test_with(identifier, &block)` registers test runners
234
- * `package_with(identifier, &block)` registers packagers
235
- * `publish_with(identifier, &block)` registers publishers
236
-
237
- ### Example
238
-
239
- Here is an example of a 'compiler' that logs `"Hello, <name>!"` where name is
240
- configured from the optional block and a `Bozo::ConfigurationError` is raised
241
- if no name has been configured:
242
-
243
- ```ruby
244
- module Bozo::Compilers
245
-
246
- class HelloWorld
247
-
248
- def name(name)
249
- @name = name
250
- end
251
-
252
- def execute
253
- raise Bozo::ConfigurationError.new('You must specify a name to say "Hello" to') if @name.nil?
254
- log_info "Hello, #{@name}!"
255
- end
256
-
257
- end
258
-
259
- end
260
- ```
261
-
262
- This compiler would be added to your build via the configuration:
263
-
264
- ```ruby
265
- compile_with :hello_world do |hw|
266
- hw.name 'Bozo'
267
- end
268
- ```
269
-
270
- ## Creating hooks
271
-
272
- The structure of all hooks is the same. The must be defined within the
273
- `Bozo::Hooks` module and they must have a parameterless constructor. They can
274
- optionally define a `#required_tools` method which returns the name of any
275
- build tools it requires that cannot be retrieved through dependency resolvers,
276
- for example a dependency resolving executable such as `nuget.exe`.
277
-
278
- When executing a command line executable they should use the
279
- `execute_command(tool, args)` method so that the command will be logged in if
280
- the correct format and if executable completes with an error exit code the
281
- build will be aborted. They should also use the `log_info(msg)` and
282
- `log_debug(msg)` methods to ensure their output is formatted correctly and the
283
- verbosity of the messages can be controlled centrally.
284
-
285
- The hook will be passed back to the configuration code via an optional block
286
- so if further configuration of the hook is possible, or required, this should
287
- be exposed through public methods on the hook. If required configuration is
288
- omitted then a `Bozo::ConfigurationError` with a message explaining the
289
- problem and how to rectify it should be raised when a hook method is called.
290
-
291
- A hook can be called several times. In order to hook around a step all that is
292
- required is that an appropriately named method is defined within the class.
293
- For example, this hook logs a message both before and after the compile step
294
- is run:
295
-
296
- ```ruby
297
- module Bozo::Hooks
298
-
299
- class CompilingMessages
300
-
301
- def pre_compile
302
- log_info 'About to compile'
303
- end
304
-
305
- def post_compile
306
- log_info 'Finished compiling'
307
- end
308
-
309
- end
310
-
311
- end
312
- ```
313
-
314
- Which steps the hook wants to execute on is determined by checking the
315
- response to the `#respond_to?` method so if you wish to use `#method_missing`
316
- to add functionality you need to ensure that the response to `#respond_to?`
317
- reflects that.
318
-
319
- ### Registration
320
-
321
- As hook instances can listen to one or more pre- or post-stage hooks there are
322
- multiple ways to register a hook. However, they are all functionally identical
323
- and are just aliases to the same method so that your configuration can read
324
- more clearly.
325
-
326
- The registration methods are:
327
-
328
- * `with_hook(identifier, &block)` (recommended when hooking several stages)
329
- * `pre_build(identifier, &block)`
330
- * `post_build(identifier, &block)`
331
- * `pre_clean(identifier, &block)`
332
- * `post_clean(identifier, &block)`
333
- * `pre_dependencies(identifier, &block)`
334
- * `post_dependencies(identifier, &block)`
335
- * `pre_prepare(identifier, &block)`
336
- * `post_prepare(identifier, &block)`
337
- * `pre_compile(identifier, &block)`
338
- * `post_compile(identifier, &block)`
339
- * `pre_test(identifier, &block)`
340
- * `post_test(identifier, &block)`
341
- * `pre_package(identifier, &block)`
342
- * `post_package(identifier, &block)`
343
- * `pre_publish(identifier, &block)`
344
- * `post_publish(identifier, &block)`
345
-
346
- ## Build tools
347
-
348
- Build tools are usually executables that you need to perform a task that are
349
- not available via some other means.
350
-
351
- For example, at Zopa we use in Nuget to resolve our .NET dependencies. This is
352
- a chicken and egg situation in that you can't use a dependency management
353
- system like Nuget until you've got a copy of the Nuget executable you can
354
- call. The build tools function aims to resolve this loop of cyclical dependency.
355
-
356
- Your build tools are resolve as the first part of the "resolve dependencies"
357
- step. When possible you should use real package management systems to retrieve
358
- dependencies rather than using the build tools function.
359
-
360
- ### Specifying required build tools
361
-
362
- All the runners and hooks you create can optionally specify a `required_tools`
363
- method which returns the name of one or more required build tools:
364
-
365
- ```ruby
366
- module Bozo::DependencyResolvers
367
-
368
- class Nuget
369
-
370
- def required_tools
371
- :nuget # or for many [:nuget, :open_wrap]
372
- end
373
-
374
- end
375
-
376
- end
377
- ```
378
-
379
- ### How it works
380
-
381
- Within the example configuration there is a single line:
382
-
383
- ```ruby
384
- build_tools_location '//SERVER/network/path' # Defines the location build tools can be copied from
385
- ```
386
-
387
- This specifies the location that build tools should be retrieved from. This
388
- location is then joined with the name of the build tool to find the directory
389
- that must be copied into the `./build/tools` directory. For example with a
390
- `build_tools_location` of `//SERVER/network/path` along with a required
391
- build tool called `:nuget` will result in the directory
392
- `//SERVER/network/path/nuget` being copied to `./build/tools/nuget` directory.
393
- By knowing the contents of this directory you can then invoke the executables
394
- contained within it:
395
-
396
- ```ruby
397
- module Bozo::DependencyResolvers
398
-
399
- class Nuget
400
-
401
- def execute
402
- execute_command :nuget, File.join('build', 'tools', 'nuget', 'NuGet.exe')
403
- end
404
-
405
- end
406
-
407
- 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
+ ### env
124
+
125
+ Returns the hash of environment variables. Initially populated by calling
126
+ `ENV.to_hash` this may be added to by runners and hooks to enable lightweight
127
+ communication and to cache the result of expensive calls.
128
+
129
+ ### environment
130
+
131
+ Returns the name of the environment that the build is running in, eg.
132
+ `'development'`.
133
+
134
+ This is a shortcut for `global_params[:environment]`.
135
+
136
+ ### execute_command(tool, args)
137
+
138
+ Executes a command line tool.
139
+
140
+ Raises a `Bozo::ExecutionError` if the command responds with a non-zero exit
141
+ code.
142
+
143
+ #### Parameters
144
+
145
+ * __tool [Symbol]__ A friendly identifier for the tool
146
+ * __args [Array]__ An array of arguments making up the command to execute
147
+
148
+ ### global_params
149
+
150
+ Returns the hash of global parameters passed to bozo. All key symbols are
151
+ converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
152
+ idiomatic for Ruby.
153
+
154
+ ### log_debug(msg)
155
+
156
+ Records an `debug` log message.
157
+
158
+ #### Parameters
159
+
160
+ * __msg [String]__ The message to log
161
+
162
+ ### log_fatal(msg)
163
+
164
+ Records an `fatal` log message.
165
+
166
+ #### Parameters
167
+
168
+ * __msg [String]__ The message to log
169
+
170
+ ### log_info(msg)
171
+
172
+ Records an `info` log message.
173
+
174
+ #### Parameters
175
+
176
+ * __msg [String]__ The message to log
177
+
178
+ ### log_warn(msg)
179
+
180
+ Records an `warn` log message.
181
+
182
+ #### Parameters
183
+
184
+ * __msg [String]__ The message to log
185
+
186
+ ### params
187
+
188
+ Returns the hash of command parameters passed to bozo. All key symbols are
189
+ converted from the CLI style of `:'multi-word'` to `:multi_word` to be more
190
+ idiomatic for Ruby.
191
+
192
+ ### version
193
+
194
+ Returns the version of the build.
195
+
196
+ This is a shortcut for `build_configuration.version`.
197
+
198
+ ## Creating step runners
199
+
200
+ The structure of all runners is the same. They must be defined within the
201
+ appropriate module, dependency resolvers in the `Bozo::DependencyResolvers`
202
+ module, project preparers must be defined within the `Bozo::Preparers`
203
+ module, compilers in the`Bozo::Compilers` module, test runners in the
204
+ `Bozo::TestRunners` module, packagers in the `Bozo::Packagers` module and
205
+ publishers in the `Bozo::Publishers` module. They must have a parameterless
206
+ constructor and they must expose an `#execute` method which will be invoked
207
+ when they should execute whatever task they are meant to perform. They can
208
+ optionally define a `#required_tools` method which returns the name of any
209
+ build tools it requires that cannot be retrieved through dependency
210
+ resolvers, for example a dependency resolving executable such as `nuget.exe`.
211
+
212
+ When executing a command line executable they should use the
213
+ `execute_command(tool, args)` method so that the command will be logged in if
214
+ the correct format and if executable completes with an error exit code the
215
+ build will be aborted. They should also use the `log_info(msg)` and
216
+ `log_debug(msg)` methods to ensure their output is formatted correctly and
217
+ the verbosity of the messages can be controlled centrally.
218
+
219
+ The runner will be passed back to the configuration code via an optional
220
+ block so if further configuration of the runner is possible, or required,
221
+ this should be exposed through public methods on the runner. If required
222
+ configuration is omitted then a `Bozo::ConfigurationError` with a message
223
+ explaining the problem and how to rectify it should be raised when the
224
+ `#execute` method of the runner is called.
225
+
226
+ ### Registration
227
+
228
+ Runners are registered through step-specific methods:
229
+
230
+ * `dependency_resolver(identifier, &block)` registers dependency resolvers
231
+ * `prepare(identifier, &block)` registers project preparers
232
+ * `compile_with(identifier, &block)` registers compilers
233
+ * `test_with(identifier, &block)` registers test runners
234
+ * `package_with(identifier, &block)` registers packagers
235
+ * `publish_with(identifier, &block)` registers publishers
236
+
237
+ ### Example
238
+
239
+ Here is an example of a 'compiler' that logs `"Hello, <name>!"` where name is
240
+ configured from the optional block and a `Bozo::ConfigurationError` is raised
241
+ if no name has been configured:
242
+
243
+ ```ruby
244
+ module Bozo::Compilers
245
+
246
+ class HelloWorld
247
+
248
+ def name(name)
249
+ @name = name
250
+ end
251
+
252
+ def execute
253
+ raise Bozo::ConfigurationError.new('You must specify a name to say "Hello" to') if @name.nil?
254
+ log_info "Hello, #{@name}!"
255
+ end
256
+
257
+ end
258
+
259
+ end
260
+ ```
261
+
262
+ This compiler would be added to your build via the configuration:
263
+
264
+ ```ruby
265
+ compile_with :hello_world do |hw|
266
+ hw.name 'Bozo'
267
+ end
268
+ ```
269
+
270
+ ## Creating hooks
271
+
272
+ The structure of all hooks is the same. The must be defined within the
273
+ `Bozo::Hooks` module and they must have a parameterless constructor. They can
274
+ optionally define a `#required_tools` method which returns the name of any
275
+ build tools it requires that cannot be retrieved through dependency resolvers,
276
+ for example a dependency resolving executable such as `nuget.exe`.
277
+
278
+ When executing a command line executable they should use the
279
+ `execute_command(tool, args)` method so that the command will be logged in if
280
+ the correct format and if executable completes with an error exit code the
281
+ build will be aborted. They should also use the `log_info(msg)` and
282
+ `log_debug(msg)` methods to ensure their output is formatted correctly and the
283
+ verbosity of the messages can be controlled centrally.
284
+
285
+ The hook will be passed back to the configuration code via an optional block
286
+ so if further configuration of the hook is possible, or required, this should
287
+ be exposed through public methods on the hook. If required configuration is
288
+ omitted then a `Bozo::ConfigurationError` with a message explaining the
289
+ problem and how to rectify it should be raised when a hook method is called.
290
+
291
+ A hook can be called several times. In order to hook around a step all that is
292
+ required is that an appropriately named method is defined within the class.
293
+ For example, this hook logs a message both before and after the compile step
294
+ is run:
295
+
296
+ ```ruby
297
+ module Bozo::Hooks
298
+
299
+ class CompilingMessages
300
+
301
+ def pre_compile
302
+ log_info 'About to compile'
303
+ end
304
+
305
+ def post_compile
306
+ log_info 'Finished compiling'
307
+ end
308
+
309
+ end
310
+
311
+ end
312
+ ```
313
+
314
+ Which steps the hook wants to execute on is determined by checking the
315
+ response to the `#respond_to?` method so if you wish to use `#method_missing`
316
+ to add functionality you need to ensure that the response to `#respond_to?`
317
+ reflects that.
318
+
319
+ ### Registration
320
+
321
+ As hook instances can listen to one or more pre- or post-stage hooks there are
322
+ multiple ways to register a hook. However, they are all functionally identical
323
+ and are just aliases to the same method so that your configuration can read
324
+ more clearly.
325
+
326
+ The registration methods are:
327
+
328
+ * `with_hook(identifier, &block)` (recommended when hooking several stages)
329
+ * `pre_build(identifier, &block)`
330
+ * `post_build(identifier, &block)`
331
+ * `pre_clean(identifier, &block)`
332
+ * `post_clean(identifier, &block)`
333
+ * `pre_dependencies(identifier, &block)`
334
+ * `post_dependencies(identifier, &block)`
335
+ * `pre_prepare(identifier, &block)`
336
+ * `post_prepare(identifier, &block)`
337
+ * `pre_compile(identifier, &block)`
338
+ * `post_compile(identifier, &block)`
339
+ * `pre_test(identifier, &block)`
340
+ * `post_test(identifier, &block)`
341
+ * `pre_package(identifier, &block)`
342
+ * `post_package(identifier, &block)`
343
+ * `pre_publish(identifier, &block)`
344
+ * `post_publish(identifier, &block)`
345
+
346
+ Failed hooks exist that are called when a stage fails, in these cases the
347
+ relevant `post` hook is not called.
348
+
349
+ * `failed_build(identifier, &block)`
350
+ * `failed_clean(identifier, &block)`
351
+ * `failed_dependencies(identifier, &block)`
352
+ * `failed_prepare(identifier, &block)`
353
+ * `failed_compile(identifier, &block)`
354
+ * `failed_test(identifier, &block)`
355
+ * `failed_package(identifier, &block)`
356
+ * `failed_publish(identifier, &block)`
357
+
358
+ ## Build tools
359
+
360
+ Build tools are usually executables that you need to perform a task that are
361
+ not available via some other means.
362
+
363
+ For example, at Zopa we use in Nuget to resolve our .NET dependencies. This is
364
+ a chicken and egg situation in that you can't use a dependency management
365
+ system like Nuget until you've got a copy of the Nuget executable you can
366
+ call. The build tools function aims to resolve this loop of cyclical dependency.
367
+
368
+ Your build tools are resolve as the first part of the "resolve dependencies"
369
+ step. When possible you should use real package management systems to retrieve
370
+ dependencies rather than using the build tools function.
371
+
372
+ ### Specifying required build tools
373
+
374
+ All the runners and hooks you create can optionally specify a `required_tools`
375
+ method which returns the name of one or more required build tools:
376
+
377
+ ```ruby
378
+ module Bozo::DependencyResolvers
379
+
380
+ class Nuget
381
+
382
+ def required_tools
383
+ :nuget # or for many [:nuget, :open_wrap]
384
+ end
385
+
386
+ end
387
+
388
+ end
389
+ ```
390
+
391
+ ### How it works
392
+
393
+ Within the example configuration there is a single line:
394
+
395
+ ```ruby
396
+ build_tools_location '//SERVER/network/path' # Defines the location build tools can be copied from
397
+ ```
398
+
399
+ This specifies the location that build tools should be retrieved from. This
400
+ location is then joined with the name of the build tool to find the directory
401
+ that must be copied into the `./build/tools` directory. For example with a
402
+ `build_tools_location` of `//SERVER/network/path` along with a required
403
+ build tool called `:nuget` will result in the directory
404
+ `//SERVER/network/path/nuget` being copied to `./build/tools/nuget` directory.
405
+ By knowing the contents of this directory you can then invoke the executables
406
+ contained within it:
407
+
408
+ ```ruby
409
+ module Bozo::DependencyResolvers
410
+
411
+ class Nuget
412
+
413
+ def execute
414
+ execute_command :nuget, File.join('build', 'tools', 'nuget', 'NuGet.exe')
415
+ end
416
+
417
+ end
418
+
419
+ end
408
420
  ```