Skip to content

Commit

Permalink
📝 Expanded and updated Command Hooks docs
Browse files Browse the repository at this point in the history
  • Loading branch information
mkarlesky committed Jun 25, 2024
1 parent 101f20b commit 2f246f1
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 55 deletions.
8 changes: 5 additions & 3 deletions docs/BreakingChanges.md
Original file line number Diff line number Diff line change
Expand Up @@ -160,11 +160,13 @@ In addition, a previously undocumented feature for merging a second configuratio

Thorough documentation on Mixins and the new options for loading a project configuration can be found in _[CeedlingPacket](CeedlingPacket.md))_.

## `command_hooks` plugin tools configuration
## Command Hooks plugin configuration change

Previously, Command Hooks tools were defined under `:tools` section, now they must be defined under top-level `:command_hooks` section in project configuration.
In previous versions of Ceedling, the Command Hooks plugin associated tools and hooks by a naming convention within the top-level `:tools` section of your project configuration. This required some semi-ugly tool names and could lead to a rather unwieldy `:tools` list. Further, this convention also limited a hook to an association with only a single tool.

# Subprojects Plugin Replaced
Hooks are now enabled within a top-level `:command_hooks` section in your project configuration. Each hook key in this configuration block can now support one or more tools organized beneath it. As such, each hook can execute one or more tools.

## Subprojects plugin replaced

The `subprojects` plugin has been completely replaced by the more-powerful `dependencies` plugin. To retain your previous functionality, you need to do a little reorganizing in your `project.yml` file. Obviously the `:subprojects` section is now called `:dependencies`. The collection of `:paths` is now `:deps`. We'll have a little more organizing to do once we're inside that section as well. Your `:source` is now organized in `:paths` ↳ `:source` and, since you're not fetching it form another project, the `:fetch` ↳ `:method` should be set to `:none`. The `:build_root` now becomes `:paths` ↳ `:build`. You'll also need to specify the name of the library produced under `:artifacts` ↳ `:static_libraries`.

Expand Down
10 changes: 8 additions & 2 deletions docs/Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,7 @@ The report format of the previously independent `xml_tests_report` plugin has be

In some circumstances, JUnit report generation would yield an exception in its routines for reorganizing test results (Issues [#829](https://github.com/ThrowTheSwitch/Ceedling/issues/829) & [#833](https://github.com/ThrowTheSwitch/Ceedling/issues/833)). The true source of the nil test results entries has likely been fixed but protections have also been added in JUnit report generation as well.

### Improvements and changes for `gcov` plugin
### Improvements and changes for Gcov plugin

1. Documentation has been significantly updated including a _Troubleshooting_ for common issues.
1. Compilation with coverage now only occurs for the source files under test and no longer for all C files (i.e. coverage for unity.c, mocks, and test files that is meaningless noise has been eliminated).
Expand All @@ -256,12 +256,18 @@ See the [gcov plugin’s documentation](plugins/gcov/README.md).
1. The plugin creates a compilation database that distinguishes the same code file compiled multiple times with different configurations as part of the new test suite build structure. It has been updated to work with other Ceedling changes.
1. Documentation has been greatly revised.

### Improvements for `beep` plugin
### Improvements for Beep plugin

1. Additional sound tools — `:tput`, `:beep`, and `:say` — have been added for more platform sound output options and fun.
1. Documentation has been greatly revised.
1. The plugin more properly uses looging and system shell calls.

## Improvements for Command Hooks plugin

In previous versions of Ceedling, the Command Hooks plugin associated tools and hooks by a naming convention within the top-level `:tools` section of your project configuration. This required some semi-ugly tool names and could lead to a rather unwieldy `:tools` list. Further, this convention also limited a hook to an association with only a single tool.

Hooks are now enabled within a top-level `:command_hooks` section in your project configuration. Each hook key in this configuration block can now support one or more tools organized beneath it. As such, each hook can execute one or more tools.

## 👋 Removed

### `verbosity` and `log` command line tasks
Expand Down
1 change: 0 additions & 1 deletion docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,6 @@ There’s more to be done, but Ceedling’s documentation is more complete and a
- The historically unwieldy `verbosity` command line task now comes in two flavors. The original recipe numeric parameterized version (e.g. `[4]`) exist as is. The new extra crispy recipe includes — funny enough — verbose task names `verbosity:silent`, `verbosity:errors`, `verbosity:complain`, `verbosity:normal`, `verbosity:obnoxious`, `verbosity:debug`.
- This release marks the beginning of the end for Rake as a backbone of Ceedling. Over many years it has become clear that Rake’s design assumptions hamper building the sorts of features Ceedling’s users want, Rake’s command line structure creates a messy user experience for a full application built around it, and Rake’s quirks cause maintenance challenges. Particularly for test suites, much of Ceedling’s (invisible) dependence on Rake has been removed in this release. Much more remains to be done, including replicating some of the abilities Rake offers.
- This is the first ever release of Ceedling with proper release notes. Hello, there! Release notes will be a regular part of future Ceedling updates. If you haven't noticed already, this edition of the notes are detailed and quite lengthy. This is entirely due to how extensive the changes are in the 1.0.0 release. Future releases will have far shorter notes.
- The `fake_function_framework` plugin has been renamed simply `fff`.
- Optional Unicode and emoji decorators have been added for your output stream enjoyment. See the documentation for logging decorators in _[CeedlingPacket](CeedlingPacket.md)_.

## 🚨 Important Changes in Behavior to Be Aware Of
Expand Down
41 changes: 30 additions & 11 deletions plugins/command_hooks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,51 @@ To use this plugin, it must be enabled:
# Configuration
To connect a utilties or scripts to build step hooks, Ceedling tools must be defined.
## Overview
To connect utilties or scripts to build step hooks, Ceedling tools must be defined.
A Ceedling tool is just a YAML blob that gathers together a handful of settings and values that tell Ceedling how to build and execute a command line. Your tool can be a command line utility, a script, etc.
Example Ceedling tools follow. Their tool entry names correspond to the build step hooks listed later in this document. That's how this plugin works. When enabled, it ensures any tools you define are executed by the corresponding build step hook that shares their name. The build step hook tool entry can be either a Ceedling tool or a list of them.
Example Ceedling tools follow. When enabled, this plugin ensures any tools you define are executed by the corresponding build step hook they are organized beneath. The configurtion of enabled hooks and tools happens in a top-level `:command_hooks:` block within your project configuration. One or more tools can be attached to a build step hook.

## Tool lists

A command hook can execute one or more tools.

If only a single tool is needed, its hash keys and value can be organized as a YAML sub-hash beneath the hook key. Alternatively, a single tool can exist as the only entry in a YAML list.

If multiple tools are needed, they must be organized as entries in a YAML list.

See the commented examples below.

## Tool definitions

Each Ceedling tool requires an `:executable` string and an optional `:arguments` list. See _[CeedlingPacket][ceedling-packet]_ documentation for project configuration [`:tools`][tools-doc] entries to understand how to craft your argument list and other tool options.

At present, this plugin passes at most one runtime parameter for use in a hook's tool argument list. If available, this parameter can be referenced with a Ceedling tool argument expansion identifier `${1}`. That is, wherever you place `${1}` in your tool argument list, `${1}` will expand in the command line Ceedling constructs with the parameter this plugin provides for that build step hook. The list of build steps hooks below document any single parameters they provide at execution.

Each Ceedling tool requires an `:executable` string and an optional `:arguments` list. See _[CeedlingPacket][ceedling-packet]_ documentation for [`:tools`](https://github.com/ThrowTheSwitch/Ceedling/blob/test/ceedling_0_32_rc/docs/CeedlingPacket.md#tools-configuring-command-line-tools-used-for-build-steps) entries to understand how to craft your argument list and other tool options.
[tools-doc]: https://github.com/ThrowTheSwitch/Ceedling/blob/test/ceedling_0_32_rc/docs/CeedlingPacket.md#tools-configuring-command-line-tools-used-for-build-steps

At present, this plugin only passes at most one runtime parameter for a given build step hook for use in a tool's argument list (from among the many processed by Ceedling's plugin framework). If available, this parameter can be referenced with a Ceedling tool argument expansion identifier `${1}`. That is, wherever you place `${1}` in your tool argument list, `${1}` will expand in the command line Ceedling constructs with the parameter this plugin provides for that build step hook. The list of build steps hooks below document any single parameters they provide at execution.
## Command Hooks example configuration YAML

```yaml
:command_hooks:
# Called every time a mock is generated
# Hook called every time a mock is generated
# Who knows what my_script.py does -- sky is the limit
:pre_mock_generate:
# This tool is organized as a sub-hash beneath the command hook key
:executable: python
:arguments:
- my_script.py
- --some-arg
- ${1} # Replaced with the filepath of the header file that will be mocked
# Called after each linking operation
# Here, we are performing two task on the same build step hook, converting a
# binary executable to S-record format and then, zipping it along with some
# other files like linker's memory allocation/usage report and so on.
# Hook called for each linking operation
# Here, we are performing two tasks for the same build step hook, converting a
# binary executable to S-record format and, then, archiving with other artifacts.
:post_link_execute:
# These tools are organized in a YAML list beneath the command hook key
- :executable: objcopy.exe
:arguments:
- ${1} # Replaced with the filepath to the linker's binary artifact output
Expand All @@ -59,9 +78,9 @@ At present, this plugin only passes at most one runtime parameter for a given bu

# Available Build Step Hooks

Define any of the following entries within the `:command_hooks:` section of your Ceedling project file to automagically connect utilities or scripts to build process steps.
Define any of the following entries within a top-level `:command_hooks:` section of your Ceedling project file to automagically connect utilities or scripts to build process steps.

Some hooks are called for every file-related operation for which the hook is named. Other hooks are triggered by single build step for which the hook is named.
Some hooks are called for every file-related operation for which the hook is named. Other hooks are triggered by the single build step for which the hook is named.

As an example, consider a Ceedling project with ten test files and seventeen mocks. The command line `ceedling test:all` would trigger:

Expand Down
86 changes: 48 additions & 38 deletions plugins/command_hooks/lib/command_hooks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,28 +39,33 @@
class CommandHooks < Plugin

def setup
# Get a copy of the project configuration
project_config = @ceedling[:setupinator].config_hash

# Look up if the accompanying `:command_hooks` configuration block exists
config_exists = @ceedling[:configurator_validator].exists?(
project_config,
COMMAND_HOOKS_SYM
)

# Go boom if the required configuration block does not exist
unless config_exists
name = @ceedling[:reportinator].generate_config_walk([COMMAND_HOOKS_SYM])
error = "Missing configuration #{name}"
error = "Command Hooks plugin is enabled but is missing a required configuration block `#{name}`"
raise CeedlingException.new(error)
end

@config = project_config[COMMAND_HOOKS_SYM]

validate_config(@config)
# Validate the command hook keys (look out for typos)
validate_config( @config )

# Validate the tools beneath the keys
@config.each do |hook, tool|
if tool.is_a?(Array)
tool.each_index {|index| validate_hook_tool(project_config, hook, index)}
tool.each_index {|index| validate_hook_tool( project_config, hook, index )}
else
validate_hook_tool(project_config, hook)
validate_hook_tool( project_config, hook )
end
end
end
Expand All @@ -87,6 +92,8 @@ def pre_build; run_hook( :pre_build
def post_build; run_hook( :post_build ); end
def post_error; run_hook( :post_error ); end

### Private

private

##
Expand All @@ -102,16 +109,16 @@ def validate_config(config)
raise CeedlingException.new(error)
end

unknown_hooks = config.keys - COMMAND_HOOKS_LIST
unrecognized_hooks = config.keys - COMMAND_HOOKS_LIST

unknown_hooks.each do |not_a_hook|
name = @ceedling[:reportinator].generate_config_walk([COMMAND_HOOKS_SYM, not_a_hook])
error = "Unrecognized option: #{name}"
@ceedling[:loginator].log(error, Verbosity::ERRORS)
unrecognized_hooks.each do |not_a_hook|
name = @ceedling[:reportinator].generate_config_walk( [COMMAND_HOOKS_SYM, not_a_hook] )
error = "Unrecognized command hook: #{name}"
@ceedling[:loginator].log( error, Verbosity::ERRORS )
end

unless unknown_hooks.empty?
error = "Unrecognized hooks have been found in project configuration"
unless unrecognized_hooks.empty?
error = "Unrecognized hooks found in Command Hooks plugin configuration"
raise CeedlingException.new(error)
end
end
Expand All @@ -125,43 +132,25 @@ def validate_config(config)
#
def validate_hook_tool(config, *keys)
walk = [COMMAND_HOOKS_SYM, *keys]
name = @ceedling[:reportinator].generate_config_walk(walk)
hash = @ceedling[:config_walkinator].fetch_value(config, *walk)
name = @ceedling[:reportinator].generate_config_walk( walk )
hash = @ceedling[:config_walkinator].fetch_value( config, *walk )

tool_exists = @ceedling[:configurator_validator].exists?(config, *walk)
tool_exists = @ceedling[:configurator_validator].exists?( config, *walk )

unless tool_exists
raise CeedlingException.new("Missing configuration #{name}")
raise CeedlingException.new( "Missing Command Hook plugin tool configuration #{name}" )
end

tool = hash[:value]

unless tool.is_a?(Hash)
error = "Expected configuration #{name} to be a Hash but found #{tool.class}"
raise CeedlingException.new(error)
raise CeedlingException.new( error )
end

@ceedling[:tool_validator].validate(tool: tool, name: name, boom: true)
@ceedling[:tool_validator].validate( tool: tool, name: name, boom: true )
end

##
# Run a hook if its available.
#
# :args:
# - hook: Name of the hook to run
# - name: Name of file (default: "")
#
# :return:
# shell_result.
#
def run_hook_step(hook, name="")
if (hook[:executable])
# Handle argument replacemant ({$1}), and get commandline
cmd = @ceedling[:tool_executor].build_command_line( hook, [], name )
shell_result = @ceedling[:tool_executor].exec(cmd)
end
end

##
# Run a hook if its available.
#
Expand All @@ -173,23 +162,44 @@ def run_hook_step(hook, name="")
#
def run_hook(which_hook, name="")
if (@config[which_hook])
@ceedling[:loginator].log("Running command hook #{which_hook}...")
msg = "Running command hook #{which_hook}"
msg = @ceedling[:reportinator].generate_progress( msg )
@ceedling[:loginator].log( msg )

# Single tool config
if (@config[which_hook].is_a? Hash)
run_hook_step( @config[which_hook], name )

# Multiple took configs
# Multiple tool configs
elsif (@config[which_hook].is_a? Array)
@config[which_hook].each do |hook|
run_hook_step(hook, name)
end

# Tool config is bad
else
msg = "Tool config for command hook #{which_hook} was poorly formed and not run"
msg = "The tool config for Command Hook #{which_hook} was poorly formed and not run"
@ceedling[:loginator].log( msg, Verbosity::COMPLAIN )
end
end
end

##
# Run a hook if its available.
#
# :args:
# - hook: Name of the hook to run
# - name: Name of file (default: "")
#
# :return:
# shell_result.
#
def run_hook_step(hook, name="")
if (hook[:executable])
# Handle argument replacemant ({$1}), and get commandline
cmd = @ceedling[:tool_executor].build_command_line( hook, [], name )
shell_result = @ceedling[:tool_executor].exec( cmd )
end
end

end

0 comments on commit 2f246f1

Please sign in to comment.