RFC: Hammer's help output improvement, Pt.I

Hello everyone,

I’m here to introduce quite a big change in Hammer’s help output I’m curently working on[1]. The task is splitted into 3 smaller parts, so this post is about the first one - squeezing options. The main purpose of this post is to introduce the change so more people are aware of it AND to get some feedback/comments/etc.

Problem:
As you may have noticed, Hammer’s help output contains quite a lot of duplicates regarding options that have the same meaning, but different names. For example:

$ hammer os create --help
Usage:
hammer os create [OPTIONS]

Options:
 --architecture-ids ARCHITECTURE_IDS                   IDs of associated architectures
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --architectures ARCHITECTURE_NAMES                    Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --description DESCRIPTION                              
 --family FAMILY                                        
 --location LOCATION_NAME                              Location Name, Set the current location context for the request
 --location-id LOCATION_ID                             Set the current location context for the request
 --location-title LOCATION_TITLE                       Location title, Set the current location context for the request
 --major MAJOR                                          
 --media MEDIUM_NAMES                                  Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --medium-ids MEDIUM_IDS                               IDs of associated media
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --minor MINOR                                          
 --name NAME                                            
 --organization ORGANIZATION_NAME                      Set the current organization context for the request
 --organization-id ORGANIZATION_ID                     Set the current organization context for the request
 --organization-title ORGANIZATION_TITLE               Set the current organization context for the request
 --os-parameters-attributes OS_PARAMETERS_ATTRIBUTES   Array of parameters
                                                       Comma separated list of values defined by a schema. See Option details section below.
                                                       JSON is acceptable and preferred way for complex parameters
 --partition-table-ids PARTITION_TABLE_IDS             IDs of associated partition tables
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --partition-tables PARTITION_TABLE_NAMES              Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --password-hash PASSWORD_HASH                         Root password hash function to use
                                                       Possible value(s): 'SHA256', 'SHA512', 'Base64', 'Base64-Windows', 'MD5'
 --provisioning-template-ids PROVISIONING_TEMPLATE_IDS IDs of associated provisioning templates
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --provisioning-templates PROVISIONING_TEMPLATE_NAMES  Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --release-name RELEASE_NAME                            
 -h, --help                                            Print help

Option details:
...

As you may see location options serves for setting the current location context for the request, but the user can use either location name, title or id. The same option (from the user’s perspective), but thrice. The same for organization, media, architectures, partition-tables and provisioning-templates. This is common issue for all hammer’s commands.

Solution:
We squeeze options that have the same meaning. For example:

Usage:
    hammer os create [OPTIONS]

Options:
 --architecture[s|-ids]                                IDs of associated architectures
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --description DESCRIPTION                              
 --family FAMILY                                        
 --location[-id|-title]                                Set the current location context for the request
 --major MAJOR                                          
 --medi[a|um-ids]                                      IDs of associated media
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --minor MINOR                                          
 --name NAME                                            
 --organization[-id|-title]                            Set the current organization context for the request
 --os-parameters-attributes OS_PARAMETERS_ATTRIBUTES   Array of parameters
                                                       Comma separated list of values defined by a schema. See Option details section below.
                                                       JSON is acceptable and preferred way for complex parameters
 --partition-table[s|-ids]                             IDs of associated partition tables
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --password-hash PASSWORD_HASH                         Root password hash function to use
                                                       Possible value(s): 'SHA256', 'SHA512', 'Base64', 'Base64-Windows', 'MD5'
 --provisioning-template[s|-ids]                       IDs of associated provisioning templates
                                                       Comma separated list of values. Values containing comma should be quoted or escaped with backslash.
                                                       JSON is acceptable and preferred way for complex parameters
 --release-name RELEASE_NAME                            
 -h, --help                                            Print help

Option details:
...

This will reduce the number of lines in help output by ~3k lines with all major plugins installed. The solution is in progress while I’m getting the feedback. I’d be happy if anyone could try to use the changes locally and give some feedback afterwards. The changes are available on GitHub[2] for hammer core and on GitHub[3] for hammer Foreman plugin[4].

Know issues:

  • Some squeezed options might lose their descriptions in regular help output. Since most of the descriptions repeat the option name (e.g. architecrure-ids option’s description is IDs of associated architectures). I’m not sure if we want such description at all, so here I’m asking your opinions. By default the descriptions (coming from API documentation) are kept with possibility to change them (see For developers section).
  • The options might be misleading. If I see --location[-id|-title] option I’d assume that I can pass anything in location option (e.g. --location 4), which is not currently supported. The user must use particular option for passing name, id or title.
  • The hammer full-help command is not affected by this change, so we keep somewhat of backward compatibility. The options are expanded in hammer full-help.
  • Some of options are not squeezed. By default Hammer generates options based on API documentation, but hammer’s plugins can extend/change/add options. They are not affected by automation, so it’s up to developers to change their code to be consistent with core.

For developers:
Hammer core introduces so-called option family which is mainly used for option grouping in help output. Some usage examples can be found in changes for the main Hammer plugin[3]. Documentation can be found here[4].

Here is the usage within a command extension (create a command extension to use option_family is not required, it can be used directly within the command definition) as an example:

module CommandExtensions
  class PuppetEnvironment < HammerCLI::CommandExtensions
    option_family(
      # Here you can pass options that are related to all the options in this family
      # as well as the family related options only .
      aliased_resource: 'environment',
      description: _('Puppet environment'),
      deprecation: _("Use %s instead") % '--puppet-environment[-id]',
      deprecated: { '--environment' => _("Use %s instead") % '--puppet-environment[-id]',
                    '--environment-id' => _("Use %s instead") % '--puppet-environment[-id]'}
    ) do
      parent '--environment-id', 'ENVIRONMENT_ID', _(''),
             format: HammerCLI::Options::Normalizers::Number.new,
             attribute_name: :option_environment_id
      child '--environment', 'ENVIRONMENT_NAME', _('Environment name'),
            attribute_name: :option_environment_name
    end
  end
end

Also here is an example how to use option_family for existing command to squeeze the help output:

option_family(
  format: HammerCLI::Options::Normalizers::List.new,
  aliased_resource: 'puppet-class'
) do
  parent '--puppet-class-ids', 'PUPPET_CLASS_IDS', '',
         attribute_name: :option_puppetclass_ids
  child '--puppet-classes', 'PUPPET_CLASS_NAMES', '',
        attribute_name: :option_puppetclass_names
end

P.S.
If something doesn’t work or something is missing, please feel free to reply here or on GitHub directly.

[1] - https://projects.theforeman.org/issues/27706.
[2] - https://github.com/theforeman/hammer-cli/pull/323
[3] - https://github.com/theforeman/hammer-cli-foreman/pull/489
[4] - https://github.com/theforeman/hammer-cli/blob/a7548e5e6cde4aaa1bab13beff552ed535d12acd/doc/creating_commands.md#option-family

3 Likes