From 2f246f1b9aa8eb5ad94f5f7337fb96a57dbefa8a Mon Sep 17 00:00:00 2001 From: Michael Karlesky Date: Mon, 24 Jun 2024 22:43:53 -0400 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Expanded=20and=20updated=20Comma?= =?UTF-8?q?nd=20Hooks=20docs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/BreakingChanges.md | 8 +- docs/Changelog.md | 10 ++- docs/ReleaseNotes.md | 1 - plugins/command_hooks/README.md | 41 ++++++++--- plugins/command_hooks/lib/command_hooks.rb | 86 ++++++++++++---------- 5 files changed, 91 insertions(+), 55 deletions(-) diff --git a/docs/BreakingChanges.md b/docs/BreakingChanges.md index ab479cb5..2b475b57 100644 --- a/docs/BreakingChanges.md +++ b/docs/BreakingChanges.md @@ -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`. diff --git a/docs/Changelog.md b/docs/Changelog.md index c1fcf3bb..5f067464 100644 --- a/docs/Changelog.md +++ b/docs/Changelog.md @@ -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). @@ -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 diff --git a/docs/ReleaseNotes.md b/docs/ReleaseNotes.md index e6cc686a..739539b0 100644 --- a/docs/ReleaseNotes.md +++ b/docs/ReleaseNotes.md @@ -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 diff --git a/plugins/command_hooks/README.md b/plugins/command_hooks/README.md index 9227e2d2..eefef9a7 100644 --- a/plugins/command_hooks/README.md +++ b/plugins/command_hooks/README.md @@ -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 @@ -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: diff --git a/plugins/command_hooks/lib/command_hooks.rb b/plugins/command_hooks/lib/command_hooks.rb index d940a811..ff2f513d 100755 --- a/plugins/command_hooks/lib/command_hooks.rb +++ b/plugins/command_hooks/lib/command_hooks.rb @@ -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 @@ -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 ## @@ -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 @@ -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. # @@ -173,13 +162,15 @@ 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) @@ -187,9 +178,28 @@ def run_hook(which_hook, name="") # 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