diff --git a/README.md b/README.md index 9c23ddd3..4afb8050 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,7 @@ The example above reflects the changes in the Puppet catalog from switching an u - [Requirements](/doc/requirements.md) - [Limitations](/doc/limitations.md) - [List of all command line options](/doc/optionsref.md) +- [API](/doc/dev/api.md) ### Project diff --git a/bin/octocatalog-diff b/bin/octocatalog-diff index 24d03bb1..5dd89984 100755 --- a/bin/octocatalog-diff +++ b/bin/octocatalog-diff @@ -20,56 +20,15 @@ end config_test = ARGV.include?('--config-test') -paths = [ - ENV['OCTOCATALOG_DIFF_CONFIG_FILE'], - File.join(Dir.pwd, '.octocatalog-diff.cfg.rb'), - File.join(ENV['HOME'], '.octocatalog-diff.cfg.rb'), - '/opt/puppetlabs/octocatalog-diff/octocatalog-diff.cfg.rb', - '/usr/local/etc/octocatalog-diff.cfg.rb', - '/etc/octocatalog-diff.cfg.rb' -] +logger = Logger.new(STDERR) +logger.level = Logger::DEBUG if config_test -cfgfile = nil - -paths.each do |path| - next if path.nil? - puts "Looking for config in: #{path}" if config_test - next unless File.file?(path) - begin - cfgfile = path - puts "Loading config: #{path}" if config_test - require path - rescue => exc - STDERR.puts "#{exc.class} error with #{path}: #{exc.message}\n#{exc.backtrace}" - exit 1 - end - break -end - -options = {} - -if cfgfile - begin - options = OctocatalogDiff::Config.config - rescue => exc - STDERR.puts "#{exc.class} error with #{cfgfile}: #{exc.message}\n#{exc.backtrace}" - exit 1 - end - unless options.is_a?(Hash) - STDERR.puts "Configuration must be Hash not #{options.class}!" - exit 1 - end - if config_test - options.each do |key, val| - puts ":#{key} => (#{val.class}) #{val.inspect}" - end - exit 0 - end -elsif config_test - STDERR.puts 'No configuration files found' - exit 1 +options = OctocatalogDiff::API::V1.config(logger: logger, test: config_test) +if config_test + logger.info 'Exiting now because --config-test was specified' + exit(0) end argv = ARGV.dup -exit_code = OctocatalogDiff::CatalogDiff::Cli.cli(argv, Logger.new(STDERR), options) +exit_code = OctocatalogDiff::Cli.cli(argv, Logger.new(STDERR), options) exit(exit_code) diff --git a/doc/advanced-filter.md b/doc/advanced-filter.md index 7938a609..56dc3a3a 100644 --- a/doc/advanced-filter.md +++ b/doc/advanced-filter.md @@ -9,7 +9,7 @@ Please note that there are other options to ignore specified diffs, including: Here is the list of available filters and an explanation of each: -- [YAML](#YAML) - Ignore whitespace/comment differences if YAML parses to the same object +- [YAML](/doc/advanced-filter.md#yaml) - Ignore whitespace/comment differences if YAML parses to the same object ## YAML diff --git a/doc/advanced-pe-enc.md b/doc/advanced-pe-enc.md index 02c209bb..8f98243f 100644 --- a/doc/advanced-pe-enc.md +++ b/doc/advanced-pe-enc.md @@ -39,7 +39,7 @@ Please see [Authentication token](https://docs.puppet.com/pe/latest/nc_forming_r The referenced document contains links to generate a token with the `puppet-access` command. -Note that if you wish to hard-code an authentication token in your [configuration file](/doc/configuration.md), the internal variable key is `:pe_enc_token` and the content is a string containing the entire token. (The `--pe-enc-token-file` option simply reads the provided file and stores the content in the `:pe_enc_token` key. See [source](/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token_file.rb).) +Note that if you wish to hard-code an authentication token in your [configuration file](/doc/configuration.md), the internal variable key is `:pe_enc_token` and the content is a string containing the entire token. (The `--pe-enc-token-file` option simply reads the provided file and stores the content in the `:pe_enc_token` key. See [source](/lib/octocatalog-diff/cli/options/pe_enc_token_file.rb).) ### SSL client keypair diff --git a/doc/dev/api.md b/doc/dev/api.md new file mode 100644 index 00000000..9d360e32 --- /dev/null +++ b/doc/dev/api.md @@ -0,0 +1,5 @@ +# octocatalog-diff API documentation + +The octocatalog-diff API allows developers to construct and work with certain octocatalog-diff internals in their own projects. + +The current API version is [API v1](/doc/dev/api/v1.md), which is available as of octocatalog-diff version 0.7. diff --git a/doc/dev/api/v1.md b/doc/dev/api/v1.md new file mode 100644 index 00000000..a8f792fc --- /dev/null +++ b/doc/dev/api/v1.md @@ -0,0 +1,35 @@ +# octocatalog-diff v1 API documentation + +## API calls + +#### catalog + +`catalog` allows you to build a catalog using the octocatalog-diff compiler or to obtain a catalog from a Puppet server. + +[Read more about the `catalog` call](/doc/dev/api/v1/calls/catalog.md) + +#### catalog-diff + +`catalog-diff` allows you compare two catalogs and obtain the differences between them. Catalogs can be built if necessary. + +[Read more about the `catalog-diff` call](/doc/dev/api/v1/calls/catalog-diff.md) + +#### config + +`config` allows you read and parse an [octocatalog-diff configuration file](/doc/configuration.md). + +[Read more about the `config` call](/doc/dev/api/v1/calls/config.md) + +## Objects + +#### OctocatalogDiff::API::V1::Catalog + +The `OctocatalogDiff::API::V1::Catalog` object represents a compiled catalog and supports several methods to get information about the catalog. + +[Read more about the `OctocatalogDiff::API::V1::Catalog` object](/doc/dev/api/v1/objects/catalog.md) + +#### OctocatalogDiff::API::V1::Diff + +The `OctocatalogDiff::API::V1::Diff` object represents a difference between two catalogs and supports several methods to get information about the difference. + +[Read more about the `OctocatalogDiff::API::V1::Diff` object](/doc/dev/api/v1/objects/diff.md) diff --git a/doc/dev/api/v1/calls/catalog-diff.md b/doc/dev/api/v1/calls/catalog-diff.md new file mode 100644 index 00000000..a5fbc6a9 --- /dev/null +++ b/doc/dev/api/v1/calls/catalog-diff.md @@ -0,0 +1,37 @@ +# octocatalog-diff v1 API documentation: catalog-diff + +## Overview + +`catalog-diff` allows you compare two catalogs and obtain the differences between them. Catalogs can be built if necessary. + +This is analogous to using the default arguments with the octocatalog-diff command-line script. + +``` +catalog_diff_result = OctocatalogDiff::API::V1.catalog_diff( + +) +``` + +## Options + +**NOTE**: Additional options as described in the [options reference](/doc/optionsref.md) may also have an effect on catalog difference generation. + +## Return value + +The return value is a structure in the following format: + +``` +{ + diffs: Array, + from: OctocatalogDiff::API::V1::Catalog, + to: OctocatalogDiff::API::V1::Catalog +} +``` + +It is possible to query this object as a hash (e.g. `result[:diffs]`) or using methods (e.g. `result.diffs`). + +[Read more about the `OctocatalogDiff::API::V1::Catalog` object](/doc/dev/api/v1/objects/catalog.md) + +[Read more about the `OctocatalogDiff::API::V1::Diff` object](/doc/dev/api/v1/objects/diff.md) + +## Exceptions diff --git a/doc/dev/api/v1/calls/catalog.md b/doc/dev/api/v1/calls/catalog.md new file mode 100644 index 00000000..4aad9215 --- /dev/null +++ b/doc/dev/api/v1/calls/catalog.md @@ -0,0 +1,115 @@ +# octocatalog-diff v1 API documentation: catalog + +## Overview + +`catalog` returns an `OctocatalogDiff::Catalog` object built with the octocatalog-diff compiler, obtained from a Puppet server, or read in from a file. This is analogous to using the `--catalog-only` option with the octocatalog-diff command-line script. + +``` +catalog_obj = OctocatalogDiff::API::V1.catalog() +#=> OctocatalogDiff::API::V1::Catalog +``` + +The return value is an [`OctocatalogDiff::API::V1::Catalog`](/doc/dev/api/v1/objects/catalog.md) object. + +For an example, see [catalog-builder-local-files.rb](/examples/api/v1/catalog-builder-local-files.rb). + +## Parameters + +The `catalog` method takes one argument, which is a Hash containing parameters. + +The list of parameters here is not exhaustive. The `.catalog` method accepts most parameters described in [Configuration](/doc/configuration.md), [Building catalogs instead of diffing catalogs](/doc/advanced-catalog-only.md), and [Command line options reference](/doc/optionsref.md). + +It is also possible to use the parameters from [OctocatalogDiff::API::V1.config](/doc/dev/api/v1/calls/config.md) for the catalog compilation. Simply combine the hash returned by `.config` with any additional keys, and pass the merged hash to the `.catalog` method. + +### Global parameters + +#### `:logger` (Logger, Optional) + +Debugging and informational messages will be logged to this object as the catalog is built. + +If no Logger object is passed, these messages will be silently discarded. + +#### `:node` (String, Required) + +The node name whose catalog is to be compiled or obtained. This should be the fully qualified domain name that matches the node's name as seen in Puppet. + +### Computed catalog parameters + +#### `:basedir` (String, Optional) + +Directory that contains a git repository with the Puppet code. Use in conjunction with `:to_branch` to specify the branch name that should be checked out. + +If your Puppet code is not in a git repository, or you already have the branch checked out via some other process, use `:bootstrapped_to_dir` instead. + +#### `:bootstrap_script` (String, Optional) + +Path to a script to run after checking out the selected branch of Puppet code from the git repository. See [Bootstrapping your Puppet checkout](/doc/advanced-bootstrap.md) for details. + +#### `:bootstrapped_to_dir` (String, Optional) + +Directory that is already prepared ("bootstrapped") and can have Puppet run against its contents to compile the catalog. + +Often this means that you have done the following to this directory: + +- Checked out the necessary branch of Puppet code from your version control system +- Installed any third party modules (e.g. with librarian-puppet or r10k) + +#### `:enc` (String, Optional) + +File path to your External Node Classifier. + +See [Configuring octocatalog-diff to use ENC](/doc/configuration-enc.md) for details on using octocatalog-diff with an External Node Classifier. + +#### `:fact_file` (String, Optional) + +Path to the file that contains the facts for the node whose catalog you are going to compile. + +Generally, must either specify the fact file, or [configure octocatalog-diff to use PuppetDB](/doc/configuration-puppetdb.md) to retrieve node facts. + +#### `:hiera_config` (String, Optional) + +Path to the Hiera configuration file (generally named `hiera.yaml`) for your Puppet installation. Please see [Configuring octocatalog-diff to use Hiera](/doc/configuration-hiera.md) for details on Hiera configuration. + +#### `:hiera_path` (String, Optional) + +Directory within your Puppet installation where Hiera data is stored. Please see [Configuring octocatalog-diff to use Hiera](/doc/configuration-hiera.md) for details on Hiera configuration. + +If your Puppet setup is modeled after the [Puppet control repository template](https://github.com/puppetlabs/control-repo), the correct setting for `:hiera_path` is `'hieradata'`. + +#### `:puppet_binary` (String, Required) + +Path to the Puppet binary on your system. + +Please refer to [Configuring octocatalog-diff to use Puppet](/doc/configuration-puppet.md) for details of connecting octocatalog-diff to your Puppet installation. + +#### `:puppetdb_url` (String, Optional) + +URL to PuppetDB. See [Configuring octocatalog-diff to use PuppetDB](/doc/configuration-puppetdb.md) for instructions on this setting, and other settings that may be needed in your environment. + +#### `:to_branch` (String, Optional) + +Branch name in git repository to use for Puppet code. This option must be used in conjunction with `:basedir` so that code can be located. + +## Exceptions + +The following exceptions may occur during the compilation of a catalog: + +- `OctocatalogDiff::Errors::BootstrapError` + + Bootstrapping failed. + +- `OctocatalogDiff::Errors::CatalogError` + + Catalog failed to compile. Please note that whenever possible, a `OctocatalogDiff::API::V1::Catalog` object is still constructed for a failed catalog, with `#valid?` returning false. + +- `OctocatalogDiff::Errors::GitCheckoutError` + + Git checkout failed. + +- `OctocatalogDiff::Errors::PuppetVersionError` + + The version of Puppet could not be determined, generally because the Puppet binary was not found, or does not respond as expected to `puppet version`. + +- `OctocatalogDiff::Errors::ReferenceValidationError` + + See [Catalog validation](/doc/advanced-catalog-validation.md). diff --git a/doc/dev/api/v1/calls/config.md b/doc/dev/api/v1/calls/config.md new file mode 100644 index 00000000..b7d275b4 --- /dev/null +++ b/doc/dev/api/v1/calls/config.md @@ -0,0 +1,37 @@ +# octocatalog-diff v1 API documentation: config + +## Overview + +`config` reads and parses an [octocatalog-diff configuration file](/doc/configuration.md). + +``` +options = OctocatalogDiff::API::V1.config( + filename: "String", + logger: Logger, + test: +) +``` + +## Options + +- **`:filename`** (String, optional): Full path to configuration file to read. If not provided, the configuration file will be searched as described in [Configuration](/doc/configuration.md). + +- **`:logger`** (Logger, optional): Logger object. If provided, debug messages and fatal errors will be logged to this object. + +- **`:test`** (Boolean, optional): Test mode, defaults to false. If true, the value of the configuration settings will be logged to the logger (with priority DEBUG) and an exception will be raised if the configuration file cannot be located. + +## Return value + +If the configuration file is located and valid, the return value is a Hash consisting of the options defined in the configuration file. + +If the configuration file cannot be found, the return value is an empty Hash (`{}`). Except, with `:test => true`, an exception will be raised. + +## Exceptions + +- `OctocatalogDiff::Errors::ConfigurationFileContentError` + + Raised if the configuration file could not be evaluated. A more specific error message will help identify the cause. Possible causes include the file not being valid ruby, the file not containing the expected structure or methods, or the method returning something other than a Hash. + +- `OctocatalogDiff::Errors::ConfigurationFileNotFoundError` + + Raised if the configuration file could not be found, *and* `:test => true` was supplied. (Note, if no configuration file is found, but `:test => false`, no error is raised, and `{}` is returned.) diff --git a/doc/dev/api/v1/objects/catalog.md b/doc/dev/api/v1/objects/catalog.md new file mode 100644 index 00000000..3571818a --- /dev/null +++ b/doc/dev/api/v1/objects/catalog.md @@ -0,0 +1,127 @@ +# octocatalog-diff v1 API documentation: OctocatalogDiff::API::V1::Catalog + +## Overview + +`OctocatalogDiff::API::V1::Catalog` is an object that represents a compiled catalog. + +It wraps the [`OctocatalogDiff::Catalog`](/lib/octocatalog-diff/catalog.rb) object. + +This object is the return value from the [`catalog`](/doc/dev/api/v1/calls/catalog.md) API call, and the `to` and `from` catalogs computed by the [`catalog-diff`](/doc/dev/api/v1/calls/catalog-diff.md) API call. + +## Methods + +#### `#builder` (String) + +Returns the name of the class the built the catalog. + +``` +catalog.builder #=> 'OctocatalogDiff::Catalog::JSON' +``` + +#### `#compilation_dir` (String) + +Returns the temporary directory in which the catalog was compiled. + +``` +catalog.compilation_dir #=> '/var/folders/dw/5ftmkqk972j_kw2fdjyzdqdw0000gn/T/d20170108-95774-1r4ohjd' +``` + +This is only applicable for catalogs compiled by `OctocatalogDiff::Catalog::Computed`. This method will return `nil` for catalogs generated by other backends. + +#### `#error_message` (String) + +Returns the error message for a failed catalog. (If the catalog is valid, this returns `nil`.) + +``` +good_catalog.valid? #=> true +good_catalog.error_message #=> nil + +bad_catalog.valid? #=> false +bad_catalog.error_message #=> 'Failed to compile catalog for node ...' +``` + +#### `#puppet_version` (String) + +Returns the Puppet version used to compile the catalog. + +``` +catalog.puppet_version #=> '3.8.7' +``` + +This is only applicable for catalogs compiled by `OctocatalogDiff::Catalog::Computed`. This method will return `nil` for catalogs generated by other backends. + +#### `#resource()` (Hash) + +Returns the hash representation of the object identified by the type and title supplied. + +This method requires 1 argument, which is a hash containing `:type` and `:title` keys. + +``` +catalog.resource(type: 'File', title: '/etc/foo') +#=> {"title"=>"/etc/foo", "type"=>"File", + "parameters"=>{"content"=>"This is the file", "owner"=>"root"}, + "file"=>"/etc/puppetlabs/code/environments/production/manifests/site.pp", "line"=>25} +``` + +Returns `nil` if the type+title resource was not present in the catalog. + +##### Notes + +1. The first call to this method will build a hash table (`O(N)` operation) from the resource array. Thereafter, each call to this method will look up the value in that hash table (`O(1)` operation). To perform lookups of known types and titles, it is faster to use this method than to use `#resources` with array operations when performing multiple lookups. + +2. The structure of the returned hash is dependent on the representation of the resource in the Puppet catalog. It is therefore possible that different versions of Puppet could cause different data structures. It is the author's experience that Puppet 3.8.7 and Puppet 4.x produce similar (if not indistinguishable) resource representations. + +3. This method will also locate a resource that was named using an alias. + + ``` + # Puppet code + file { '/etc/foo': + alias => 'foo file for the win', + ... + } + + # octocatalog-diff API + catalog.resource(type: 'File', title: 'foo file for the win') + #=> {"title"=>"/etc/foo", "type"=>"File", ...} + ``` + +#### `#resources` (Array<Hash>) + +Returns an array of catalog resources in a successful catalog. (If the catalog is not valid, this returns `nil`.) + +``` +bad_catalog.valid? #=> false +bad_catalog.resources #=> nil + +good_catalog.valid? #=> true +good_catalog.resources +#=> [ + { "title"=>"/etc/foo", "type"=>"File", ... }, + { "title"=>"/bin/true", "type"=>"Exec", ... } +] +``` + +The structure of the returned hash is dependent on the representation of the resource in the Puppet catalog. It is therefore possible that different versions of Puppet could cause different data structures. It is the author's experience that Puppet 3.8.7 and Puppet 4.x produce similar (if not indistinguishable) resource representations. + +#### `#to_json` (String) + +Returns the JSON representation of a successful catalog. (If the catalog is not valid, this returns `nil`.) + +``` +bad_catalog.valid? #=> false +bad_catalog.to_json #=> nil + +good_catalog.valid? #=> true +good_catalog.to_json #=> '{ "document_type": "Catalog", ... }' +``` + +#### `#valid?` (Boolean) + +Returns `true` if the catalog is valid, and `false` if the catalog is not valid. + +## Other methods + +These methods are available for debugging or development purposes but are not guaranteed to remain consistent between versions: + +- `#to_h` (Hash): Returns hash representation of parsed JSON catalog +- `#raw` (OctocatalogDiff::Catalog): Returns underlying internal catalog object diff --git a/doc/dev/api/v1/objects/diff.md b/doc/dev/api/v1/objects/diff.md new file mode 100644 index 00000000..4555c36b --- /dev/null +++ b/doc/dev/api/v1/objects/diff.md @@ -0,0 +1,252 @@ +# octocatalog-diff v1 API documentation: OctocatalogDiff::API::V1::Diff + +## Overview + +`OctocatalogDiff::API::V1::Diff` is an object that represents a single difference between two catalogs. + +The return value from the `diffs` computed by the [`catalog-diff`](/doc/dev/api/v1/calls/catalog-diff.md) API call is an Array of these `OctocatalogDiff::API::V1::Diff` objects. + +## Methods + +#### `#addition?` (Boolean) + +Returns true if this diff is an addition (resource exists in new catalog but not old catalog). + +#### `#change?` (Boolean) + +Returns true if this diff is a change (resource exists in both catalogs but is different between them). + +#### `#diff_type` (String) + +Returns the type of difference, which is one of the following characters: + +- `+` for addition (resource exists in new catalog but not old catalog) +- `-` for removal (resource exists in old catalog but not new catalog) +- `~` or `!` for change (resource exists in both catalogs but is different between them) + +See also: `#addition?`, `#change?`, `#removal?` + +Note: Internally `~` and `!` represent different types of changes, but when presenting the output, these can generally be considered equivalent. + +#### `#new_file` (String) + +Returns the filename of the Puppet manifest giving rise to the resource as it exists in the new catalog. + +Note that this is a pass-through of information provided in the Puppet catalog, and is not calculated by octocatalog-diff. If the Puppet catalog does not contain this information, this method will return `nil`. + +Note also that if the diff represents removal of a resource, this will return `nil`, because the resource does not exist in the new catalog. + +#### `#new_line` (String) + +Returns the line number within the Puppet manifest giving rise to the resource as it exists in the new catalog. (See `#new_file` for the filename of the Puppet manifest.) + +Note that this is a pass-through of information provided in the Puppet catalog, and is not calculated by octocatalog-diff. If the Puppet catalog does not contain this information, this method will return `nil`. + +Note also that if the diff represents removal of a resource, this will return `nil`, because the resource does not exist in the new catalog. + +#### `#new_value` (Object) + +Returns the value of the resource from the new catalog. + +- If a resource was added, this returns the data structure associated with the resource in the Puppet catalog. For example, if the resource was created as follows in the Puppet catalog, the `new_value` is as indicated. + + ``` + # Resource in New Catalog + { + "type": "File", + "title": "/etc/foo", + "parameters": { + "owner": "root", + "content": "hello new world" + } + } + + # Demonstrates new_value + diff.new_value #=> { 'parameters' => { 'owner' => 'root', 'content' => 'hello new world' } } + ``` + +- If a resource was removed, this returns `nil` because there was no value of this resource in the new catalog. + +- If a resource was changed, this returns the portion of the data structure that is indicated by the `.structure` method. For example, if the resource existed as follows in both the old and new Puppet catalogs, the `new_value` is as indicated. + + ``` + # Resource in Old Catalog + { + "type": "File", + "title": "/etc/foo", + "parameters": { + "owner": "root", + "content": "This is the old file" + } + } + + # Resource in New Catalog + { + "type": "File", + "title": "/etc/foo", + "parameters": { + "owner": "root", + "content": "This is the NEW FILE!!!!!" + } + } + + # Demonstrates structure and old_value + diff.structure #=> ['parameters', 'content'] + diff.old_value #=> 'This is the NEW FILE!!!!!' + ``` + +#### `#old_file` (String) + +Returns the filename of the Puppet manifest giving rise to the resource as it exists in the old catalog. + +Note that this is a pass-through of information provided in the Puppet catalog, and is not calculated by octocatalog-diff. If the Puppet catalog does not contain this information, this method will return `nil`. + +Note also that if the diff represents addition of a resource, this will return `nil`, because the resource does not exist in the old catalog. + +#### `#old_file` (String) + +Returns the line number within the Puppet manifest giving rise to the resource as it exists in the old catalog. (See `#old_file` for the filename of the Puppet manifest.) + +Note that this is a pass-through of information provided in the Puppet catalog, and is not calculated by octocatalog-diff. If the Puppet catalog does not contain this information, this method will return `nil`. + +Note also that if the diff represents addition of a resource, this will return `nil`, because the resource does not exist in the old catalog. + +#### `#old_value` (Object) + +Returns the value of the resource from the old catalog. + +- If a resource was added, this returns `nil` because there was no value of this resource in the old catalog. + +- If a resource was removed, this returns the data structure associated with the resource in the Puppet catalog. For example, if the resource existed as follows in the Puppet catalog, the `old_value` is as indicated. + + ``` + # Resource in Old Catalog + { + "type": "File", + "title": "/etc/foo", + "parameters": { + "owner": "root", + "content": "hello old world" + } + } + + # Demonstrates old_value + diff.old_value #=> { 'parameters' => { 'owner' => 'root', 'content' => 'hello old world' } } + ``` + +- If a resource was changed, this returns the portion of the data structure that is indicated by the `.structure` method. For example, if the resource existed as follows in both the old and new Puppet catalogs, the `old_value` is as indicated. + + ``` + # Resource in Old Catalog + { + "type": "File", + "title": "/etc/foo", + "parameters": { + "owner": "root", + "content": "This is the old file" + } + } + + # Resource in New Catalog + { + "type": "File", + "title": "/etc/foo", + "parameters": { + "owner": "root", + "content": "This is the NEW FILE!!!!!" + } + } + + # Demonstrates structure and old_value + diff.structure #=> ['parameters', 'content'] + diff.old_value #=> 'This is the old file' + ``` + +#### `#removal?` (Boolean) + +Returns true if this diff is a removal (resource exists in old catalog but not new catalog). + +#### `#structure` (Array) + +Returns the structure that has been changed, as an array. + +When a resource was added or removed, the result is an empty array. That's because all of the parameters and other metadata from the resource exist entirely in one catalog but not the other. + +When a resource has changed, one diff is created for each parameter that changed. For example, both the old and new catalogs contain the file resource `/etc/foo` but just the content has changed: + +``` +# Old +file { '/etc/foo': + owner => 'root', + content => 'This is the old file', +} + +# New +file { '/etc/foo': + owner => 'root', + content => 'This is the NEW FILE!!!!!', +} +``` + +Internally, the Puppet catalog for this resource will look like this in the catalogs (this has been abbreviated a bit for clarity): + +``` +# Old +{ + "type": "File", + "title": "/etc/foo", + "exported": false, + "parameters": { + "owner": "root", + "content": "This is the old file" + } +} + +# New +{ + "type": "File", + "title": "/etc/foo", + "exported": false, + "parameters": { + "owner": "root", + "content": "This is the NEW FILE!!!!!" + } +} +``` + +One diff will be generated to represent the change to the content of the file (which in the catalog is nested in the 'parameters' hash). The diff will be structured as follows: + +``` +diff.type #=> 'File' +diff.title #=> '/etc/foo' +diff.structure #=> ['parameters', 'content'] +``` + +#### `#title` (String) + +Returns the title of the resource from the Puppet catalog. + +For example, a diff involving `File['/etc/passwd']` would have: + +- `diff.title #=> '/etc/passwd'` +- `diff.type #=> 'File'` + +#### `#type` (String) + +Returns the type of the resource from the Puppet catalog. + +For example, a diff involving `File['/etc/passwd']` would have: + +- `diff.title #=> '/etc/passwd'` +- `diff.type #=> 'File'` + +Note that the type will be capitalized because Puppet capitalizes this in catalogs. + +## Other methods + +These methods are available for debugging or development purposes but are not guaranteed to remain consistent between versions: + +- `#inspect` (String): Returns inspection of object +- `#raw` (Array): Returns internal array data structure of the "diff" +- `#to_h` (Hash): Returns object as a hash, where keys are above described methods +- `#[]` (Object): Retrieve indexed array elements from raw internal array object diff --git a/doc/dev/how-to-add-options.md b/doc/dev/how-to-add-options.md index a65075d9..a95b4882 100644 --- a/doc/dev/how-to-add-options.md +++ b/doc/dev/how-to-add-options.md @@ -7,9 +7,9 @@ This document contains a checklist and guidance to adding new command line optio Please copy and paste this text into your Pull Request. This will create boxes for each step along the way, which you can then check off when complete. ``` -- [ ] REQUIRED: Add new file in `lib/octocatalog-diff/catalog-diff/cli/options` -- [ ] REQUIRED: Add corresponding test in `spec/octocatalog-diff/tests/catalog-diff/cli/options` -- [ ] OPTIONAL: Add default value in `lib/octocatalog-diff/catalog-diff/cli.rb` +- [ ] REQUIRED: Add new file in `lib/octocatalog-diff/cli/options` +- [ ] REQUIRED: Add corresponding test in `spec/octocatalog-diff/tests/cli/options` +- [ ] OPTIONAL: Add default value in `lib/octocatalog-diff/cli.rb` - [ ] OPTIONAL: Add configuration example in `examples/octocatalog-diff.cfg.rb` - [ ] REQUIRED: Add code to implement your option in `lib` - [ ] REQUIRED: Add corresponding tests for code to implement your option in `spec/octocatalog-diff/tests` @@ -20,7 +20,7 @@ Please copy and paste this text into your Pull Request. This will create boxes f ### Create option parser -Option parsers are created in [`lib/octocatalog-diff/catalog-diff/cli/options`](/lib/octocatalog-diff/catalog-diff/cli/options). +Option parsers are created in [`lib/octocatalog-diff/cli/options`](/lib/octocatalog-diff/cli/options). Your option should have a "long form" that contains dashes and not underscores. For example, you should prefer `--your-new-option` and NOT use `--your_new_option`. @@ -32,23 +32,23 @@ If you are creating a binary (yes-no) option, please recognize both `--your-new- We recommend copying prior art as a template: -- For a binary (yes-no) option, look at [`quiet.rb`](/lib/octocatalog-diff/catalog-diff/cli/options/quiet.rb). +- For a binary (yes-no) option, look at [`quiet.rb`](/lib/octocatalog-diff/cli/options/quiet.rb). -- For an option that takes an integer parameter, look at [`retry_failed_catalog.rb`](/lib/octocatalog-diff/catalog-diff/cli/options/retry_failed_catalog.rb). +- For an option that takes an integer parameter, look at [`retry_failed_catalog.rb`](/lib/octocatalog-diff/cli/options/retry_failed_catalog.rb). -- For an option that takes an string parameter, look at [`bootstrap_script.rb`](/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_script.rb). +- For an option that takes an string parameter, look at [`bootstrap_script.rb`](/lib/octocatalog-diff/cli/options/bootstrap_script.rb). -- For an option that takes an array or can be specified more than once, look at [`bootstrap_environment.rb`](/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_environment.rb). +- For an option that takes an array or can be specified more than once, look at [`bootstrap_environment.rb`](/lib/octocatalog-diff/cli/options/bootstrap_environment.rb). -If you can do simple validation of the argument, such as making sure the argument (if specified) matches a particular regular expression or is one of a particular set of values, please do that within the option file. For example, look at [`facts_terminus.rb`](/lib/octocatalog-diff/catalog-diff/cli/options/facts_terminus.rb). +If you can do simple validation of the argument, such as making sure the argument (if specified) matches a particular regular expression or is one of a particular set of values, please do that within the option file. For example, look at [`facts_terminus.rb`](/lib/octocatalog-diff/cli/options/facts_terminus.rb). ### Create test for option parser -Option parser tests are created in [`spec/octocatalog-diff/tests/catalog-diff/cli/options`](/spec/octocatalog-diff/tests/catalog-diff/cli/options). +Option parser tests are created in [`spec/octocatalog-diff/tests/cli/options`](/spec/octocatalog-diff/tests/cli/options). If you used an existing option as a reference for your new code, consider using that option's test as a reference for your test. We have some methods, e.g. `test_with_true_false_option`, to avoid repetitive code for common patterns. -If you have handled any edge cases, e.g. input validation, please add a test that expects an error when input is provided that does not match your validation. For example, look at [`parser_spec.rb`](/spec/octocatalog-diff/tests/catalog-diff/cli/options/parser_spec.rb). +If you have handled any edge cases, e.g. input validation, please add a test that expects an error when input is provided that does not match your validation. For example, look at [`parser_spec.rb`](/spec/octocatalog-diff/tests/cli/options/parser_spec.rb). ### Add default value (OPTIONAL) @@ -56,7 +56,7 @@ Unless specifically cleared with the project maintainers, adding a new option sh In other words, if someone invokes the program *without* specifying your option, it should behave in the same way as it did before your option was ever added. -If you need to set a default value for your option, do so in [`lib/octocatalog-diff/catalog-diff/cli.rb`](/lib/octocatalog-diff/catalog-diff/cli.rb). Items should be added to DEFAULT_OPTIONS *only if* a value is required even if your option is not provided, or if you are defaulting something to *true* but providing an option to make it false. +If you need to set a default value for your option, do so in [`lib/octocatalog-diff/cli.rb`](/lib/octocatalog-diff/cli.rb). Items should be added to DEFAULT_OPTIONS *only if* a value is required even if your option is not provided, or if you are defaulting something to *true* but providing an option to make it false. ### Add configuration example (OPTIONAL) diff --git a/doc/optionsref.md b/doc/optionsref.md index 4e72b19d..7ec49e97 100644 --- a/doc/optionsref.md +++ b/doc/optionsref.md @@ -169,7 +169,7 @@ Usage: octocatalog-diff [command line options] Use an alternate base directory (git checkout of puppet repository) - Option to set the base checkout directory of puppet repository (basedir.rb) + Option to set the base checkout directory of puppet repository (basedir.rb) @@ -182,7 +182,7 @@ Usage: octocatalog-diff [command line options] Option to bootstrap the current directory (by default, the bootstrap script is NOT -run when the catalog builds in the current directory). (bootstrap_current.rb) +run when the catalog builds in the current directory). (bootstrap_current.rb) @@ -194,7 +194,7 @@ run when the catalog builds in the current directory). (bootstrap_environment.rb) + Allow the bootstrap environment to be set up via the command line. (bootstrap_environment.rb) @@ -208,7 +208,7 @@ run when the catalog builds in the current directory). (bootstrap_script.rb) +to be done. (bootstrap_script.rb) @@ -220,7 +220,7 @@ to be done. (bootstrap_then_exit.rb) + Option to bootstrap directories and then exit (bootstrap_then_exit.rb) @@ -233,7 +233,7 @@ to be done. (bootstrapped_dirs.rb) +to save time when diffing multiple catalogs on this system. (bootstrapped_dirs.rb) @@ -246,7 +246,7 @@ to save time when diffing multiple catalogs on this system. (bootstrapped_dirs.rb) +to save time when diffing multiple catalogs on this system. (bootstrapped_dirs.rb) @@ -259,7 +259,7 @@ to save time when diffing multiple catalogs on this system. (cached_master_dir.rb) +has not changed. (cached_master_dir.rb) @@ -273,7 +273,7 @@ has not changed. (catalog_only.rb) +diffing activity. The catalog will be printed to STDOUT or written to the output file. (catalog_only.rb) @@ -286,7 +286,7 @@ diffing activity. The catalog will be printed to STDOUT or written to the output Enable/disable colors in output - Color printing option (color.rb) + Color printing option (color.rb) @@ -302,7 +302,7 @@ diffing activity. The catalog will be printed to STDOUT or written to the output When a file is specified with `source => 'puppet:///modules/something/foo.txt'`, remove the 'source' attribute and populate the 'content' attribute with the text of the file. This allows for a diff of the content, rather than a diff of the location, which is -what is most often desired. (compare_file_text.rb) +what is most often desired. (compare_file_text.rb) @@ -316,7 +316,7 @@ what is most often desired. (debug.rb) + Debugging option (debug.rb) @@ -330,7 +330,7 @@ what is most often desired. (debug_bootstrap.rb) +any effect. (debug_bootstrap.rb) @@ -342,7 +342,7 @@ any effect. (header.rb) + Provide ability to set custom header or to display no header at all (header.rb) @@ -358,7 +358,7 @@ any effect. (display_datatype_changes.rb) +difference. (display_datatype_changes.rb) @@ -371,7 +371,7 @@ difference. (display_detail_add.rb) + Provide ability to display details of 'added' resources in the output. (display_detail_add.rb) @@ -384,7 +384,7 @@ difference. (display_source_file_line.rb) + Display source filename and line number for diffs (display_source_file_line.rb) @@ -396,7 +396,7 @@ difference. (enc.rb) + Path to external node classifier, relative to the base directory of the checkout. (enc.rb) @@ -408,7 +408,7 @@ difference. (fact_file.rb) + Allow an existing fact file to be provided, to avoid pulling facts from PuppetDB. (fact_file.rb) @@ -422,7 +422,7 @@ difference. (facts_terminus.rb) +on which this is running. (facts_terminus.rb) @@ -436,7 +436,7 @@ on which this is running. (filters.rb) +Filtering results. (filters.rb) @@ -450,7 +450,7 @@ For a list of available filters and further explanation, please refer to Set the 'from' and 'to' branches, which is used to compile catalogs. A branch of '.' means to use -the current contents of the base code directory without any git checkouts. (to_from_branch.rb) +the current contents of the base code directory without any git checkouts. (to_from_branch.rb) @@ -463,7 +463,7 @@ the current contents of the base code directory without any git checkouts. ( If pre-compiled catalogs are available, these can be used to short-circuit the build process. -These files must exist and be in Puppet catalog format. (existing_catalogs.rb) +These files must exist and be in Puppet catalog format. (existing_catalogs.rb) @@ -475,7 +475,7 @@ These files must exist and be in Puppet catalog format. (enc.rb) + Path to external node classifier, relative to the base directory of the checkout. (enc.rb) @@ -488,7 +488,7 @@ These files must exist and be in Puppet catalog format. ( - Set --from-puppetdb to pull most recent catalog from PuppetDB instead of compiling (from_puppetdb.rb) + Set --from-puppetdb to pull most recent catalog from PuppetDB instead of compiling (from_puppetdb.rb) @@ -500,7 +500,7 @@ These files must exist and be in Puppet catalog format. (header.rb) + Provide ability to set custom header or to display no header at all (header.rb) @@ -512,7 +512,7 @@ These files must exist and be in Puppet catalog format. (hiera_config.rb) + Specify a relative path to the Hiera yaml file (hiera_config.rb) @@ -525,7 +525,7 @@ These files must exist and be in Puppet catalog format. (hiera_path.rb) +Puppet control repo template, the value of this should be 'hieradata', which is the default. (hiera_path.rb) @@ -537,7 +537,7 @@ Puppet control repo template, the value of this should be 'hieradata', which is Path prefix to strip when munging hiera.yaml - Specify the path to strip off the datadir to munge hiera.yaml file (hiera_path_strip.rb) + Specify the path to strip off the datadir to munge hiera.yaml file (hiera_path_strip.rb) @@ -550,7 +550,7 @@ Puppet control repo template, the value of this should be 'hieradata', which is Use PuppetDB facts from last run of hostname - Set hostname, which is used to look up facts in PuppetDB, and in the header of diff display. (hostname.rb) + Set hostname, which is used to look up facts in PuppetDB, and in the header of diff display. (hostname.rb) @@ -562,7 +562,7 @@ Puppet control repo template, the value of this should be 'hieradata', which is More resources to ignore in format type[title] - Options used when comparing catalogs - set ignored changes. (ignore.rb) + Options used when comparing catalogs - set ignored changes. (ignore.rb) @@ -574,7 +574,7 @@ Puppet control repo template, the value of this should be 'hieradata', which is Attributes to ignore - Specify attributes to ignore (ignore_attr.rb) + Specify attributes to ignore (ignore_attr.rb) @@ -587,7 +587,7 @@ Puppet control repo template, the value of this should be 'hieradata', which is Provide ability to set one or more tags, which will cause catalog-diff -to ignore any changes for any defined type where this tag is set. (ignore_tags.rb) +to ignore any changes for any defined type where this tag is set. (ignore_tags.rb) @@ -600,7 +600,7 @@ to ignore any changes for any defined type where this tag is set. (include_tags.rb) + Options used when comparing catalogs - tags are generally ignored; you can un-ignore them. (include_tags.rb) @@ -612,7 +612,7 @@ to ignore any changes for any defined type where this tag is set. (master_cache_branch.rb) + Allow override of the branch that is cached. This defaults to 'origin/master'. (master_cache_branch.rb) @@ -624,7 +624,7 @@ to ignore any changes for any defined type where this tag is set. (enc.rb) + Path to external node classifier, relative to the base directory of the checkout. (enc.rb) @@ -636,7 +636,7 @@ to ignore any changes for any defined type where this tag is set. (header.rb) + Provide ability to set custom header or to display no header at all (header.rb) @@ -648,7 +648,7 @@ to ignore any changes for any defined type where this tag is set. (hiera_config.rb) + Specify a relative path to the Hiera yaml file (hiera_config.rb) @@ -661,7 +661,7 @@ to ignore any changes for any defined type where this tag is set. (hiera_path.rb) +Puppet control repo template, the value of this should be 'hieradata', which is the default. (hiera_path.rb) @@ -673,7 +673,7 @@ Puppet control repo template, the value of this should be 'hieradata', which is Do not use any default hiera path strip settings - Specify the path to strip off the datadir to munge hiera.yaml file (hiera_path_strip.rb) + Specify the path to strip off the datadir to munge hiera.yaml file (hiera_path_strip.rb) @@ -686,7 +686,7 @@ Puppet control repo template, the value of this should be 'hieradata', which is Provide ability to set one or more tags, which will cause catalog-diff -to ignore any changes for any defined type where this tag is set. (ignore_tags.rb) +to ignore any changes for any defined type where this tag is set. (ignore_tags.rb) @@ -699,7 +699,7 @@ to ignore any changes for any defined type where this tag is set. (output_file.rb) + Output file option (output_file.rb) @@ -711,7 +711,7 @@ to ignore any changes for any defined type where this tag is set. (output_format.rb) + Output format option (output_format.rb) @@ -724,7 +724,7 @@ to ignore any changes for any defined type where this tag is set. (parallel.rb) + Disable or enable parallel processing of catalogs. (parallel.rb) @@ -736,7 +736,7 @@ to ignore any changes for any defined type where this tag is set. (parser.rb) + Enable future parser for both branches or for just one (parser.rb) @@ -748,7 +748,7 @@ to ignore any changes for any defined type where this tag is set. (parser.rb) + Enable future parser for both branches or for just one (parser.rb) @@ -760,7 +760,7 @@ to ignore any changes for any defined type where this tag is set. (parser.rb) + Enable future parser for both branches or for just one (parser.rb) @@ -774,7 +774,7 @@ to ignore any changes for any defined type where this tag is set. (pass_env_vars.rb) +available. Setting these variables is your responsibility outside of octocatalog-diff. (pass_env_vars.rb) @@ -788,7 +788,7 @@ available. Setting these variables is your responsibility outside of octocatalog Specify the CA certificate for the Puppet Enterprise ENC. If specified, this will enable SSL verification that the certificate being presented has been signed by this CA, and that the common name -matches the name you are using to connecting. (pe_enc_ssl_ca.rb) +matches the name you are using to connecting. (pe_enc_ssl_ca.rb) @@ -801,7 +801,7 @@ matches the name you are using to connecting. (pe_enc_ssl_client_cert.rb) +--pe-enc-ssl-client-key in order to work. (pe_enc_ssl_client_cert.rb) @@ -814,7 +814,7 @@ matches the name you are using to connecting. (pe_enc_ssl_client_key.rb) +--pe-enc-ssl-client-cert in order to work. (pe_enc_ssl_client_key.rb) @@ -829,7 +829,7 @@ matches the name you are using to connecting. (pe_enc_token.rb) +of the token. (Use --pe-enc-token-file to read the content of the token from a file.) (pe_enc_token.rb) @@ -844,7 +844,7 @@ of the token. (Use --pe-enc-token-file to read the content of the token from a f Specify the access token to access the Puppet Enterprise ENC. Refer to https://docs.puppet.com/pe/latest/nc_forming_requests.html#authentication for details on generating and obtaining a token. Use this option if the token is stored -in a file, to read the content of the token from the file. (pe_enc_token_file.rb) +in a file, to read the content of the token from the file. (pe_enc_token_file.rb) @@ -859,7 +859,7 @@ in a file, to read the content of the token from the file. (pe_enc_url.rb) +https://your-pe-console-server:4433/classifier-api (pe_enc_url.rb) @@ -874,7 +874,7 @@ https://your-pe-console-server:4433/classifier-api (preserve_environments.rb) +to work correctly. (preserve_environments.rb) @@ -887,7 +887,7 @@ to work correctly. (puppetdb_api_version.rb) +the default. (puppetdb_api_version.rb) @@ -901,7 +901,7 @@ the default. (puppetdb_ssl_ca.rb) +matches the name you are using to connecting. (puppetdb_ssl_ca.rb) @@ -914,7 +914,7 @@ matches the name you are using to connecting. (puppetdb_ssl_client_cert.rb) +--puppetdb-ssl-client-key in order to work. (puppetdb_ssl_client_cert.rb) @@ -927,7 +927,7 @@ matches the name you are using to connecting. (puppetdb_ssl_client_key.rb) +--puppetdb-ssl-client-cert in order to work. (puppetdb_ssl_client_key.rb) @@ -941,7 +941,7 @@ matches the name you are using to connecting. (puppetdb_ssl_client_password.rb) +the text of the password won't appear in the process list. (puppetdb_ssl_client_password.rb) @@ -953,7 +953,7 @@ the text of the password won't appear in the process list. (puppetdb_ssl_client_password_file.rb) + Specify the password for a PEM or PKCS12 private key, by reading it from a file. (puppetdb_ssl_client_password_file.rb) @@ -965,7 +965,7 @@ the text of the password won't appear in the process list. (puppetdb_url.rb) + Specify the base URL for PuppetDB. This will generally look like https://puppetdb.yourdomain.com:8081 (puppetdb_url.rb) @@ -979,7 +979,7 @@ the text of the password won't appear in the process list. (quiet.rb) + Quiet option (quiet.rb) @@ -992,7 +992,7 @@ the text of the password won't appear in the process list. (retry_failed_catalog.rb) +a failed catalog multiple times before kicking out an error message. (retry_failed_catalog.rb) @@ -1006,7 +1006,7 @@ a failed catalog multiple times before kicking out an error message. (safe_to_delete_cached_master_dir.rb) +cached directory). (safe_to_delete_cached_master_dir.rb) @@ -1019,7 +1019,7 @@ cached directory). (storeconfigs.rb) + Set storeconfigs (integration with PuppetDB for collected resources) (storeconfigs.rb) @@ -1034,7 +1034,7 @@ cached directory). (suppress_absent_file_details.rb) +include user, group, mode, and content, because a removed file has none of those. (suppress_absent_file_details.rb) @@ -1048,7 +1048,7 @@ include user, group, mode, and content, because a removed file has none of those Set the 'from' and 'to' branches, which is used to compile catalogs. A branch of '.' means to use -the current contents of the base code directory without any git checkouts. (to_from_branch.rb) +the current contents of the base code directory without any git checkouts. (to_from_branch.rb) @@ -1061,7 +1061,7 @@ the current contents of the base code directory without any git checkouts. ( If pre-compiled catalogs are available, these can be used to short-circuit the build process. -These files must exist and be in Puppet catalog format. (existing_catalogs.rb) +These files must exist and be in Puppet catalog format. (existing_catalogs.rb) @@ -1073,7 +1073,7 @@ These files must exist and be in Puppet catalog format. (enc.rb) + Path to external node classifier, relative to the base directory of the checkout. (enc.rb) @@ -1088,8 +1088,16 @@ These files must exist and be in Puppet catalog format. (validate_references.rb) +parameters are to be checked. (validate_references.rb) - \ No newline at end of file + + +## Using these options in API calls + +Most of these options can also be used when making calls to the [API](/doc/dev/api.md). + +Generally, parameters for the API are named corresponding to the names of the command line parameters, with dashes (`-`) converted to underscores (`_`). For example, the command line option `--hiera-config` is passed to the API as the symbol `:hiera_config`. + +Each of the options above has a link to the source file where it is declared, should you wish to review the specific parameter names and data structures that are being set. \ No newline at end of file diff --git a/examples/api/v1/catalog-builder-local-files.rb b/examples/api/v1/catalog-builder-local-files.rb new file mode 100755 index 00000000..809543a2 --- /dev/null +++ b/examples/api/v1/catalog-builder-local-files.rb @@ -0,0 +1,93 @@ +#!/usr/bin/env ruby + +# ------------------------------------------------------------------------------------ +# This is a script that demonstrates the use of the OctocatalogDiff::API::V1.catalog +# method to build a catalog. +# +# Run this with: +# bundle exec examples/api/v1/catalog-builder-local-files.rb +# ------------------------------------------------------------------------------------ + +# Once you have installed the gem, you want this: +# +# require 'octocatalog-diff' +# +# To make the script run correctly from within the `examples` directory, this locates +# the `octocatalog-diff` gem directly from this checkout. +require_relative '../../../lib/octocatalog-diff' + +# Here are a few variables we'll use to compile this catalog. To ensure that this is a +# working script, it will use resources from the test fixtures. You will need adjust these +# to the actual values in your application. + +FACT_FILE = File.expand_path('../../../spec/octocatalog-diff/fixtures/facts/facts.yaml', File.dirname(__FILE__)) +HIERA_CONFIG = File.expand_path('../../../spec/octocatalog-diff/fixtures/repos/default/config/hiera.yaml', File.dirname(__FILE__)) +NODE = 'rspec-node.github.net'.freeze +PUPPET_REPO = File.expand_path('../../../spec/octocatalog-diff/fixtures/repos/default', File.dirname(__FILE__)) +PUPPET_BINARY = File.expand_path('../../../script/puppet', File.dirname(__FILE__)) + +# To compile this catalog, call the octocatalog-diff API. +catalog = OctocatalogDiff::API::V1.catalog( + bootstrapped_to_dir: PUPPET_REPO, + fact_file: FACT_FILE, + hiera_config: HIERA_CONFIG, + hiera_path: 'hieradata', + node: NODE, + puppet_binary: PUPPET_BINARY +) + +# Let's see what kind of an object we got... +# #=> OctocatalogDiff::API::V1::Catalog +puts "Object returned from OctocatalogDiff::API::V1.catalog is: #{catalog.class}" + +# If it's not valid, the error message will be available. +unless catalog.valid? + puts 'The catalog is not valid.' + puts catalog.error_message + exit 1 +end + +# If it is valid, many other methods may be of interest. +puts 'The catalog is valid.' + +# We can determine which backend was used to build it. With the arguments in this example, +# the catalog was computed. +# #=> OctocatalogDiff::Catalog::Computed +puts "The catalog was built using #{catalog.builder}" + +# We can determine which directory was used as the temporary compilation directory. +# This is only defined for the Computed backend. +puts "Puppet was run in #{catalog.compilation_dir}" + +# We can report on which version of Puppet was run. This is only defined for the +# Computed backend. +puts "The version of Puppet used was #{catalog.puppet_version}" + +# We can get all resources in the catalog via the .resources method, which returns +# an Array. The Hash comes directly from the catalog structure. +puts "There is/are #{catalog.resources.count} resource(s) in this catalog" +catalog.resources.each do |resource| + puts "- #{resource['type']} - #{resource['title']}" +end + +# You can also locate a resource by its type and title. We'll choose an element at +# random from the array. We will then locate it via the `.resource` method. +selected_resource = catalog.resources.sample +puts "Randomly selected type=#{selected_resource['type']} title=#{selected_resource['title']}" + +param = { type: selected_resource['type'], title: selected_resource['title'] } +looked_up_resource = catalog.resource(param) +puts "Looked up using catalog.resource: type=#{looked_up_resource['type']}, title=#{looked_up_resource['title']}" + +if selected_resource == looked_up_resource + puts 'The resources are equal!' +else + # If this happens, it's a bug - please report it to us! + puts 'The resources do not match!' +end + +# If we want the JSON representation of the catalog, we can get that too. You'd +# normally want to write this out to a file. We'll just print the first 80 characters. +json_text = catalog.to_json +puts "The JSON representation of the catalog is #{json_text.length} characters long" +puts json_text[0..80] diff --git a/lib/octocatalog-diff.rb b/lib/octocatalog-diff.rb index 986ed011..dbf98ded 100644 --- a/lib/octocatalog-diff.rb +++ b/lib/octocatalog-diff.rb @@ -1,12 +1,5 @@ # These are all the classes we believe people might want to call directly, so load # them in response to a 'require octocatalog-diff'. -loads = [ - 'bootstrap', - 'catalog', - 'facts', - 'puppetdb', - 'version', - 'catalog-diff/cli' -] +loads = %w(api/v1 bootstrap catalog cli errors facts puppetdb version) loads.each { |f| require_relative "octocatalog-diff/#{f}" } diff --git a/lib/octocatalog-diff/api/v1.rb b/lib/octocatalog-diff/api/v1.rb new file mode 100644 index 00000000..5c29aba7 --- /dev/null +++ b/lib/octocatalog-diff/api/v1.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +require_relative 'v1/catalog' +require_relative 'v1/catalog-compile' +require_relative 'v1/catalog-diff' +require_relative 'v1/config' +require_relative 'v1/diff' + +module OctocatalogDiff + module API + # Call available methods for this version of the API + module V1 + def self.catalog(options = nil) + OctocatalogDiff::API::V1::CatalogCompile.catalog(options) + end + + def self.catalog_diff(options = nil) + OctocatalogDiff::API::V1::CatalogDiff.catalog_diff(options) + end + + def self.config(options = nil) + OctocatalogDiff::API::V1::Config.config(options) + end + end + end +end diff --git a/lib/octocatalog-diff/api/v1/catalog-compile.rb b/lib/octocatalog-diff/api/v1/catalog-compile.rb new file mode 100644 index 00000000..dd57162d --- /dev/null +++ b/lib/octocatalog-diff/api/v1/catalog-compile.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require_relative 'catalog' +require_relative 'common' +require_relative '../../util/catalogs' + +module OctocatalogDiff + module API + module V1 + # This class allows octocatalog-diff to be used to compile catalogs. + class CatalogCompile + # Public: Compile a catalog given the options provided. + # + # Parameters are to be passed in a hash. + # @param :logger [Logger] Logger object (be sure to configure log level) + # @param :node [String] Node name (FQDN) + # Other catalog building parameters are also accepted + # @return [OctocatalogDiff::Catalog] Compiled catalogs + + def self.catalog(options = nil) + # Validate the required options. + unless options.is_a?(Hash) + raise ArgumentError, 'Usage: #catalog(options_hash)' + end + + pass_opts, logger = OctocatalogDiff::API::V1::Common.logger_from_options(options) + logger.debug "Compiling catalog for #{options[:node]}" + + # Compile catalog + catalog_opts = pass_opts.merge( + from_catalog: '-', # Prevents a compile + to_catalog: nil, # Forces a compile + ) + cat_obj = OctocatalogDiff::Util::Catalogs.new(catalog_opts, logger) + OctocatalogDiff::API::V1::Catalog.new(cat_obj.catalogs[:to]) + end + end + end + end +end diff --git a/lib/octocatalog-diff/api/v1/catalog-diff.rb b/lib/octocatalog-diff/api/v1/catalog-diff.rb new file mode 100644 index 00000000..2b6bd6df --- /dev/null +++ b/lib/octocatalog-diff/api/v1/catalog-diff.rb @@ -0,0 +1,68 @@ +# frozen_string_literal: true + +require_relative 'catalog' +require_relative 'common' +require_relative 'diff' +require_relative '../../util/catalogs' +require_relative '../../catalog-util/cached_master_directory' + +require 'ostruct' + +module OctocatalogDiff + module API + module V1 + # This class allows octocatalog-diff to be used to compile catalogs (if needed) + # and then compute the differences between them. + class CatalogDiff + # Public: Run catalog-diff + # + # Parameters are to be passed in a hash. + # @param :logger [Logger] Logger object (be sure to configure log level) + # Other catalog-diff parameters are required + # @return [OpenStruct] { :diffs (Array); :from (OctocatalogDiff::Catalog), :to (OctocatalogDiff::Catalog) } + def self.catalog_diff(options = nil) + # Validate the required options. + unless options.is_a?(Hash) + raise ArgumentError, 'Usage: #catalog_diff(options_hash)' + end + + pass_opts, logger = OctocatalogDiff::API::V1::Common.logger_from_options(options) + + # Compile catalogs + logger.debug "Compiling catalogs for #{options[:node]}" + catalogs_obj = OctocatalogDiff::Util::Catalogs.new(pass_opts, logger) + catalogs = catalogs_obj.catalogs + logger.info "Catalogs compiled for #{options[:node]}" + + # Cache catalogs if master caching is enabled. If a catalog is being read from the cached master + # directory, set the compilation directory attribute, so that the "compilation directory dependent" + # suppressor will still work. + %w(from to).each do |x| + next unless options["#{x}_env".to_sym] == options.fetch(:master_cache_branch, 'origin/master') + next if options[:cached_master_dir].nil? + catalogs[x.to_sym].compilation_dir = options["#{x}_catalog_compilation_dir".to_sym] || options[:cached_master_dir] + rc = OctocatalogDiff::CatalogUtil::CachedMasterDirectory.save_catalog_in_cache_dir( + options[:node], + options[:cached_master_dir], + catalogs[x.to_sym] + ) + logger.debug "Cached master catalog for #{options[:node]}" if rc + end + + # Compute diffs + diffs_obj = OctocatalogDiff::Cli::Diffs.new(options, logger) + diffs = diffs_obj.diffs(catalogs) + logger.info "Diffs computed for #{options[:node]}" + logger.info 'No differences' if diffs.empty? + + # Return diffs and catalogs in expected format + OpenStruct.new( + diffs: diffs.map { |x| OctocatalogDiff::API::V1::Diff.new(x) }, + from: OctocatalogDiff::API::V1::Catalog.new(catalogs[:from]), + to: OctocatalogDiff::API::V1::Catalog.new(catalogs[:to]) + ) + end + end + end + end +end diff --git a/lib/octocatalog-diff/api/v1/catalog.rb b/lib/octocatalog-diff/api/v1/catalog.rb new file mode 100644 index 00000000..8caba0dd --- /dev/null +++ b/lib/octocatalog-diff/api/v1/catalog.rb @@ -0,0 +1,84 @@ +# frozen_string_literal: true + +require_relative 'common' +require_relative '../../catalog' + +module OctocatalogDiff + module API + module V1 + # This is a wrapper class around OctocatalogDiff::Catalog. This contains the methods we + # are choosing to expose, and will be a compatibility layer should underlying methods + # change in the future. The raw object will be available as `#raw` but this is not + # guaranteed to be stable. + class Catalog + attr_reader :raw + + # Constructor: Accepts a raw OctocatalogDiff::Catalog object and stores it. + # @param raw [OctocatalogDiff::Catalog] Catalog object + def initialize(raw) + unless raw.is_a?(OctocatalogDiff::Catalog) + raise ArgumentError, 'OctocatalogDiff::API::V1::Catalog#initialize expects OctocatalogDiff::Catalog argument' + end + @raw = raw + end + + # Public: Get the builder for the catalog + # @return [String] Class of backend used + def builder + @raw.builder + end + + # Public: Get the JSON for the catalog + # @return [String] Catalog JSON + def to_json + @raw.catalog_json + end + + # Public: Get the compilation directory + # @return [String] Compilation directory + def compilation_dir + @raw.compilation_dir + end + + # Public: Get the error message + # @return [String] Error message, or nil if no error + def error_message + @raw.error_message + end + + # Public: Get the Puppet version used to compile the catalog + # @return [String] Puppet version + def puppet_version + @raw.puppet_version + end + + # Public: Get a specific resource identified by type and title. + # This is intended for use when a O(1) lookup is required. + # @param :type [String] Type of resource + # @param :title [String] Title of resource + # @return [Hash] Resource item + def resource(opts = {}) + @raw.resource(opts) + end + + # Public: Get the resources in the catalog + # @return [Array] Resource array + def resources + @raw.resources + end + + # Public: Determine if the catalog build was successful. + # @return [Boolean] Whether the catalog is valid + def valid? + @raw.valid? + end + + # Public: Return catalog as hash. + # @return [Hash] Catalog as hash + def to_h + @raw.catalog + end + end + end + end +end diff --git a/lib/octocatalog-diff/api/v1/common.rb b/lib/octocatalog-diff/api/v1/common.rb new file mode 100644 index 00000000..ad4a081b --- /dev/null +++ b/lib/octocatalog-diff/api/v1/common.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +module OctocatalogDiff + module API + module V1 + # Common functions for API v1 + class Common + def self.logger_from_options(options) + # If logger is not provided, create an object that can have messages written to it. + # There won't be a way to access these messages, so if you want to log messages, then + # provide that logger! + logger = options[:logger] || Logger.new(StringIO.new) + + # We can't keep :logger in the options due to marshal/unmarshal as part of parallelization. + pass_opts = options.merge(logger: nil) + + # Return cleaned options and logger + [pass_opts, logger] + end + end + end + end +end diff --git a/lib/octocatalog-diff/api/v1/config.rb b/lib/octocatalog-diff/api/v1/config.rb new file mode 100644 index 00000000..fe2e7843 --- /dev/null +++ b/lib/octocatalog-diff/api/v1/config.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true + +require_relative 'common' +require_relative '../../errors' + +module OctocatalogDiff + module API + module V1 + # This class interacts with the configuration file typically named `.octocatalog-diff.cfg.rb`. + class Config + # Default directory paths: These are the documented default locations that will be checked + # for the configuration file. + DEFAULT_PATHS = [ + ENV['OCTOCATALOG_DIFF_CONFIG_FILE'], + File.join(Dir.pwd, '.octocatalog-diff.cfg.rb'), + File.join(ENV['HOME'], '.octocatalog-diff.cfg.rb'), + '/opt/puppetlabs/octocatalog-diff/octocatalog-diff.cfg.rb', + '/usr/local/etc/octocatalog-diff.cfg.rb', + '/etc/octocatalog-diff.cfg.rb' + ].compact.freeze + + # Public: Find the configuration file in the specified path or one of the default paths + # as appropriate. Parses the configuration file and returns the hash object with its settings. + # Returns empty hash if the configuration file is not found anywhere. + # + # @param :filename [String] Specified file name (default = search the default paths) + # @param :logger [Logger] Logger object + # @param :test [Boolean] Configuration file test mode (log some extra debugging, raises errors) + # @return [Hash] Parsed configuration file + def self.config(options_in = {}) + # Initialize the logger - if not passed, set to a throwaway object. + options, logger = OctocatalogDiff::API::V1::Common.logger_from_options(options_in) + + # Locate the configuration file + paths = [options.fetch(:filename, DEFAULT_PATHS)].compact + config_file = first_file(paths) + + # Can't find the configuration file? + if config_file.nil? + message = "Unable to find configuration file in #{paths.join(':')}" + raise OctocatalogDiff::Errors::ConfigurationFileNotFoundError, message if options[:test] + logger.debug message + return {} + end + + # Load/parse the configuration file - this returns a hash + settings = load_config_file(config_file, logger) + + # Debug the configuration file if requested. + debug_config_file(settings, logger) if options[:test] + + # Return the settings hash + logger.debug "Loaded #{settings.keys.size} settings from #{config_file}" + settings + end + + # Private: Print debugging details for the configuration file. + # + # @param settings [Hash] Parsed settings from load_config_file + # @param logger [Logger] Logger object + def self.debug_config_file(settings, logger) + unless settings.is_a?(Hash) + raise ArgumentError, "Settings must be hash not #{settings.class}" + end + + settings.each { |key, val| logger.debug ":#{key} => (#{val.class}) #{val.inspect}" } + end + + # Private: Load the configuration file from a given path. Returns the settings hash. + # + # @param filename [String] File name to load + # @param logger [Logger] Logger object + # @return [Hash] Settings + def self.load_config_file(filename, logger) + # This should never happen unless somebody calls this method directly outside of + # the published `.config` method. Check for problems anyway. + raise Errno::ENOENT, "File #{filename} doesn't exist" unless File.file?(filename) + + # Attempt to require in the file. Problems here will fall through to the rescued + # exception below. + logger.debug "Loading octocatalog-diff configuration from #{filename}" + load filename + + # The required file should contain `OctocatalogDiff::Config` with `.config` method. + # If this is undefined, raise an exception. + begin + loaded_class = Kernel.const_get(:OctocatalogDiff).const_get(:Config) + rescue NameError + message = 'Configuration must define OctocatalogDiff::Config!' + raise OctocatalogDiff::Errors::ConfigurationFileContentError, message + end + + unless loaded_class.respond_to?(:config) + message = 'Configuration must define OctocatalogDiff::Config.config!' + raise OctocatalogDiff::Errors::ConfigurationFileContentError, message + end + + # The configuration file looks like it defines the correct method, so read it. + # Make sure it's a hash. + options = loaded_class.config + unless options.is_a?(Hash) + message = "Configuration must be Hash not #{options.class}!" + raise OctocatalogDiff::Errors::ConfigurationFileContentError, message + end + + options + rescue Exception => exc # rubocop:disable Lint/RescueException + logger.fatal "#{exc.class} error with #{filename}: #{exc.message}\n#{exc.backtrace}" + raise exc + end + + # Private: Find the first element of the given array that is a file and return it. + # Return nil if none of the elements in the array are files. + # + # @param search_paths [Array] Paths to check + def self.first_file(search_paths) + search_paths.flatten.compact.each do |path| + return path if File.file?(path) + end + nil + end + end + end + end +end diff --git a/lib/octocatalog-diff/api/v1/diff.rb b/lib/octocatalog-diff/api/v1/diff.rb new file mode 100644 index 00000000..916d61eb --- /dev/null +++ b/lib/octocatalog-diff/api/v1/diff.rb @@ -0,0 +1,171 @@ +# frozen_string_literal: true + +require_relative 'common' + +module OctocatalogDiff + module API + module V1 + # This class represents a `diff` produced by a catalog-diff operation. This has traditionally + # been stored as an array with: + # [0] Type of change - '+', '-', '!', '~' + # [1] Type, title, and maybe structure, delimited by "\f" + # [2] Content of the "old" catalog + # [3] Content of the "new" catalog + # [4] File and line of the "old" catalog + # [5] File and line of the "new" catalog + # This object seeks to preserve this traditional structure, while providing methods to make it + # easier to deal with. We recommend using the named options, rather than #raw or the indexed array, + # as the raw object and indexed array are not guaranteed to be stable. + class Diff + attr_reader :raw + + # Constructor: Accepts a diff in the traditional array format and stores it. + # @param raw [Array] Diff in the traditional format + def initialize(raw) + unless raw.is_a?(Array) + raise ArgumentError, 'OctocatalogDiff::API::V1::Diff#initialize expects Array argument' + end + @raw = raw + end + + # Public: Retrieve an indexed value from the array + # @return [?] Indexed value + def [](i) + @raw[i] + end + + # Public: Get the change type + # @return [String] Change type symbol (~, !, +, -) + def diff_type + @raw[0] + end + + # Public: Is this an addition? + # @return [Boolean] True if this is an addition + def addition? + diff_type == '+' + end + + # Public: Is this a removal? + # @return [Boolean] True if this is an addition + def removal? + diff_type == '-' + end + + # Public: Is this a change? + # @return [Boolean] True if this is an change + def change? + diff_type == '~' || diff_type == '!' + end + + # Public: Get the resource type + # @return [String] Resource type + def type + @raw[1].split(/\f/)[0] + end + + # Public: Get the resource title + # @return [String] Resource title + def title + @raw[1].split(/\f/)[1] + end + + # Public: Get the structure of the resource as an array + # @return [Array] Structure of resource + def structure + @raw[1].split(/\f/)[2..-1] + end + + # Public: Get the "old" value, i.e. "from" catalog + # @return [?] "old" value + def old_value + return nil if addition? + @raw[2] + end + + # Public: Get the "new" value, i.e. "to" catalog + # @return [?] "old" value + def new_value + return nil if removal? + return @raw[2] if addition? + @raw[3] + end + + # Public: Get the filename from the "old" location + # @return [String] Filename + def old_file + x = old_location + x.nil? ? nil : x['file'] + end + + # Public: Get the line number from the "old" location + # @return [String] Line number + def old_line + x = old_location + x.nil? ? nil : x['line'] + end + + # Public: Get the filename from the "new" location + # @return [String] Filename + def new_file + x = new_location + x.nil? ? nil : x['file'] + end + + # Public: Get the line number from the "new" location + # @return [String] Line number + def new_line + x = new_location + x.nil? ? nil : x['line'] + end + + # Public: Convert this object to a hash + # @return [Hash] Hash with keys set by these methods + def to_h + { + diff_type: diff_type, + type: type, + title: title, + structure: structure, + old_value: old_value, + new_value: new_value, + old_file: old_file, + old_line: old_line, + new_file: new_file, + new_line: new_line + } + end + + # Public: String inspection + # @return [String] String for inspection + def inspect + to_h.inspect + end + + # Public: To string + # @return [String] Compact string representation + def to_s + raw.inspect + end + + private + + # Private: Get the "old" location, i.e. location in the "from" catalog + # @return [Hash] of resource + def old_location + return nil if addition? + return @raw[3] if removal? + @raw[4] + end + + # Private: Get the "new" location, i.e. location in the "to" catalog + # @return [Hash] of resource + def new_location + return @raw[3] if addition? + return nil if removal? + @raw[5] + end + end + end + end +end diff --git a/lib/octocatalog-diff/catalog-diff/cli.rb b/lib/octocatalog-diff/catalog-diff/cli.rb deleted file mode 100644 index 745a2921..00000000 --- a/lib/octocatalog-diff/catalog-diff/cli.rb +++ /dev/null @@ -1,211 +0,0 @@ -# frozen_string_literal: true - -require_relative 'cli/catalogs' -require_relative 'cli/diffs' -require_relative 'cli/options' -require_relative 'cli/printer' -require_relative '../catalog-util/cached_master_directory' -require_relative 'cli/helpers/fact_override' -require_relative '../version' - -require 'logger' -require 'socket' - -module OctocatalogDiff - module CatalogDiff - # This is the CLI for catalog-diff. It's responsible for parsing the command line - # arguments and then handing off to appropriate methods to perform the catalog-diff. - class Cli - # Version number - VERSION = OctocatalogDiff::Version::VERSION - - # Exit codes - EXITCODE_SUCCESS_NO_DIFFS = 0 - EXITCODE_FAILURE = 1 - EXITCODE_SUCCESS_WITH_DIFFS = 2 - - # The default type+title+attribute to ignore in catalog-diff. - DEFAULT_IGNORES = [ - { type: 'Class' } # Don't care about classes themselves, only what they actually do! - ].freeze - - # The default options. - DEFAULT_OPTIONS = { - from_env: 'origin/master', - to_env: '.', - colors: true, - debug: false, - quiet: false, - format: :color_text, - display_source_file_line: false, - compare_file_text: true, - display_datatype_changes: true, - parallel: true, - suppress_absent_file_details: true, - hiera_path: 'hieradata' - }.freeze - - # This method is the one to call externally. It is possible to specify alternate - # command line arguments, for testing. - # @param argv [Array] Use specified arguments (defaults to ARGV) - # @param logger [Logger] Logger object - # @param opts [Hash] Additional options - # @return [Fixnum] Exit code: 0=no diffs, 1=something went wrong, 2=worked but there are diffs - def self.cli(argv = ARGV, logger = Logger.new(STDERR), opts = {}) - # Save a copy of argv to print out later in debugging - argv_save = argv.dup - - # Are there additional ARGV to munge, e.g. that have been supplied in the options from a - # configuration file? - if opts.key?(:additional_argv) - raise ArgumentError, ':additional_argv must be array!' unless opts[:additional_argv].is_a?(Array) - argv.concat opts[:additional_argv] - end - - # Parse command line - options = parse_opts(argv) - - # Additional options from hard-coded specified options. These are only processed if - # there are not already values defined from command line options. - # Note: do NOT use 'options[k] ||= v' here because if the value of options[k] is boolean(false) - # it will then be overridden. Whereas the intent is to define values only for those keys that don't exist. - opts.each { |k, v| options[k] = v unless options.key?(k) } - veto_options = %w(enc header hiera_config include_tags) - veto_options.each { |x| options.delete(x.to_sym) if options["no_#{x}".to_sym] } - options[:ignore].concat opts.fetch(:additional_ignores, []) - - # Incorporate default options where needed. - # Note: do NOT use 'options[k] ||= v' here because if the value of options[k] is boolean(false) - # it will then be overridden. Whereas the intent is to define values only for those keys that don't exist. - DEFAULT_OPTIONS.each { |k, v| options[k] = v unless options.key?(k) } - veto_with_none_options = %w(hiera_path hiera_path_strip) - veto_with_none_options.each { |x| options.delete(x.to_sym) if options[x.to_sym] == :none } - - # Fact overrides come in here - 'options' is modified - setup_fact_overrides(options) - - # Configure the logger and logger.debug initial information - # 'logger' is modified and used - setup_logger(logger, options, argv_save) - - # --catalog-only is a special case that compiles the catalog for the "to" branch - # and then exits, without doing any 'diff' whatsoever. Support that option. - return catalog_only(logger, options) if options[:catalog_only] - - # Set up the cached master directory - maintain it, adjust options if needed. However, if we - # are getting the 'from' catalog from PuppetDB, then don't do this. - unless options[:cached_master_dir].nil? || options[:from_puppetdb] - OctocatalogDiff::CatalogUtil::CachedMasterDirectory.run(options, logger) - end - - # bootstrap_then_exit is a special case that only prepares directories and does not - # depend on facts. This happens within the 'catalogs' object, since bootstrapping and - # preparing catalogs are tightly coupled operations. However this does not actually - # build catalogs. - catalogs_obj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) - return bootstrap_then_exit(logger, catalogs_obj) if options[:bootstrap_then_exit] - - # Compile catalogs - catalogs = catalogs_obj.catalogs - logger.info "Catalogs compiled for #{options[:node]}" - - # Cache catalogs if master caching is enabled. If a catalog is being read from the cached master - # directory, set the compilation directory attribute, so that the "compilation directory dependent" - # suppressor will still work. - %w(from to).each do |x| - next unless options["#{x}_env".to_sym] == options.fetch(:master_cache_branch, 'origin/master') - next if options[:cached_master_dir].nil? - catalogs[x.to_sym].compilation_dir = options["#{x}_catalog_compilation_dir".to_sym] || options[:cached_master_dir] - rc = OctocatalogDiff::CatalogUtil::CachedMasterDirectory.save_catalog_in_cache_dir( - options[:node], - options[:cached_master_dir], - catalogs[x.to_sym] - ) - logger.debug "Cached master catalog for #{options[:node]}" if rc - end - - # Compute diffs - diffs_obj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(options, logger) - diffs = diffs_obj.diffs(catalogs) - logger.info "Diffs computed for #{options[:node]}" - - # Display diffs - logger.info 'No differences' if diffs.empty? - printer_obj = OctocatalogDiff::CatalogDiff::Cli::Printer.new(options, logger) - printer_obj.printer(diffs, catalogs[:from].compilation_dir, catalogs[:to].compilation_dir) - - # Return the diff object if requested (generally for testing) or otherwise return exit code - return diffs if opts[:RETURN_DIFFS] - diffs.any? ? EXITCODE_SUCCESS_WITH_DIFFS : EXITCODE_SUCCESS_NO_DIFFS - end - - # Parse command line options with 'optparse'. Returns a hash with the parsed arguments. - # @param argv [Array] Command line arguments (MUST be specified) - # @return [Hash] Options - def self.parse_opts(argv) - options = { ignore: DEFAULT_IGNORES.dup } - Options.parse_options(argv, options) - end - - # Fact overrides come in here - def self.setup_fact_overrides(options) - [:from_fact_override, :to_fact_override].each do |key| - o = options["#{key}_in".to_sym] - next unless o.is_a?(Array) - next unless o.any? - options[key] ||= [] - options[key].concat o.map { |x| OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(x) } - end - end - - # Helper method: Configure and setup logger - def self.setup_logger(logger, options, argv_save) - # Configure the logger - logger.level = Logger::INFO - logger.level = Logger::DEBUG if options[:debug] - logger.level = Logger::ERROR if options[:quiet] - - # Some debugging information up front - version_display = ENV['OCTOCATALOG_DIFF_CUSTOM_VERSION'] || VERSION - logger.debug "Running octocatalog-diff #{version_display} with ruby #{RUBY_VERSION}" - logger.debug "Command line arguments: #{argv_save.inspect}" - logger.debug "Running on host #{Socket.gethostname} (#{RUBY_PLATFORM})" - end - - # Compile the catalog only - def self.catalog_only(logger, options) - # Indicate where we are - logger.debug "Compiling catalog --catalog-only for #{options[:node]}" - - # Compile catalog - catalog_opts = options.merge( - from_catalog: '-', # Prevents a compile - to_catalog: nil, # Forces a compile - ) - cat_obj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(catalog_opts, logger) - catalogs = cat_obj.catalogs - - # If the catalog compilation failed, an exception would have been thrown. So if - # we get here, the catalog succeeded. Dump the catalog to the appropriate place - # and exit successfully. - if options[:output_file] - File.open(options[:output_file], 'w') { |f| f.write(catalogs[:to].catalog_json) } - logger.info "Wrote catalog to #{options[:output_file]}" - else - puts catalogs[:to].catalog_json - end - return [catalogs[:from], catalogs[:to]] if options[:RETURN_DIFFS] # For integration testing - EXITCODE_SUCCESS_NO_DIFFS - end - - # --bootstrap-then-exit command - def self.bootstrap_then_exit(logger, catalogs_obj) - catalogs_obj.bootstrap_then_exit - return EXITCODE_SUCCESS_NO_DIFFS - rescue OctocatalogDiff::CatalogDiff::Cli::Catalogs::BootstrapError => exc - logger.fatal("--bootstrap-then-exit error: bootstrap failed (#{exc})") - return EXITCODE_FAILURE - end - end - end -end diff --git a/lib/octocatalog-diff/catalog-diff/cli/catalogs.rb b/lib/octocatalog-diff/catalog-diff/cli/catalogs.rb deleted file mode 100644 index 78971847..00000000 --- a/lib/octocatalog-diff/catalog-diff/cli/catalogs.rb +++ /dev/null @@ -1,246 +0,0 @@ -# frozen_string_literal: true - -require 'json' -require 'open3' -require 'yaml' -require_relative '../../catalog-util/bootstrap' # For BootstrapError -require_relative '../../catalog' -require_relative '../../util/parallel' - -module OctocatalogDiff - module CatalogDiff - class Cli - # Helper class to construct catalogs, performing all necessary steps such as - # bootstrapping directories, installing facts, and running puppet. - class Catalogs - # Exceptions that are anticipated can be caught in the calling class and tested for explicitly in spec tests. - class BootstrapError < RuntimeError; end - class CatalogError < RuntimeError; end - - # Constructor - # @param options [Hash] Options - # @param logger [Logger] Logger object - def initialize(options, logger) - @options = options - @logger = logger - @catalogs = nil - raise '@logger must not be nil' if @logger.nil? - end - - # Compile catalogs. This handles building both the old and new catalog (in parallel) and returns - # only when both catalogs have been built. - # @return [Hash] { :from => [OctocatalogDiff::Catalog], :to => [OctocatalogDiff::Catalog] } - def catalogs - @catalogs ||= build_catalog_parallelizer - end - - # Handles the "bootstrap then exit" option, which bootstraps directories but - # exits without compiling catalogs. - def bootstrap_then_exit - @logger.debug('Begin bootstrap_then_exit') - OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory_parallelizer(@options, @logger) - @logger.debug('Success bootstrap_then_exit') - @logger.info('Successfully completed --bootstrap-then-exit action') - rescue OctocatalogDiff::CatalogUtil::Bootstrap::BootstrapError => exc - @logger.error("Bootstrap exception: #{exc}") - raise BootstrapError, "Bootstrap exception: #{exc}" - end - - private - - # Parallelizes bootstrapping of directories and building catalogs. - # @return [Hash] { :from => OctocatalogDiff::Catalog, :to => OctocatalogDiff::Catalog } - def build_catalog_parallelizer - # Construct parallel tasks. The array supplied to OctocatalogDiff::Util::Parallel is the task portion - # of each of the tuples in catalog_tasks. - catalog_tasks = build_catalog_tasks - - # Update any tasks for catalogs that do not need to be compiled. This is the case when --catalog-only - # is specified and only one catalog is to be built. This will change matching catalog tasks to the 'noop' type. - catalog_tasks.map! do |x| - if @options["#{x[0]}_catalog".to_sym] == '-' - x[1].args[:backend] = :noop - elsif @options["#{x[0]}_catalog".to_sym].is_a?(String) - x[1].args[:json] = File.read(@options["#{x[0]}_catalog".to_sym]) - x[1].args[:backend] = :json - end - x - end - - # Initialize the objects for each parallel task. Initializing the object is very fast and does not actually - # build the catalog. - result = {} - catalog_tasks.each do |x| - result[x[0]] = OctocatalogDiff::Catalog.new(x[1].args) - @logger.debug "Initialized #{result[x[0]].builder} for #{x[0]}-catalog" - end - - # Disable --compare-file-text if either (or both) of the chosen backends do not support it - if @options.fetch(:compare_file_text, false) - result.each do |_key, val| - next unless val.convert_file_resources == false - @logger.debug "Disabling --compare-file-text; not supported by #{val.builder}" - @options[:compare_file_text] = false - catalog_tasks.map! do |x| - x[1].args[:compare_file_text] = false - x - end - break - end - end - - # Inject the starting object into the catalog tasks - catalog_tasks.map! do |x| - x[1].args[:object] = result[x[0]] - x - end - - # Execute the parallelized catalog builds - passed_catalog_tasks = catalog_tasks.map { |x| x[1] } - parallel_catalogs = OctocatalogDiff::Util::Parallel.run_tasks(passed_catalog_tasks, @logger, @options[:parallel]) - - # If the catalogs array is empty at this point, there is an unexpected size mismatch. This should - # never happen, but test for it anyway. - unless parallel_catalogs.size == catalog_tasks.size - # :nocov: - raise "BUG: mismatch catalog_result (#{parallel_catalogs.size} vs #{catalog_tasks.size})" - # :nocov: - end - - # Construct result hash. Will eventually be in the format - # { :from => OctocatalogDiff::Catalog, :to => OctocatalogDiff::Catalog } - - # Analyze the results from parallel run. - catalog_tasks.each do |x| - # The `parallel_catalog_obj` is a OctocatalogDiff::Util::Parallel::Result. Get the first element from - # the parallel_catalogs output. - parallel_catalog_obj = parallel_catalogs.shift - - # Add the result to the 'result' hash - add_parallel_result(result, parallel_catalog_obj, x) - end - - # Things have succeeded if the :to and :from catalogs exist at this point. If not, things have - # failed, and an exception should be thrown. - raise CatalogError, 'One or more catalogs failed to compile.' unless result.key?(:to) && result.key?(:from) - result - end - - # Get catalog compilation tasks. - # @return [Array<[key, task]>] Catalog tasks - def build_catalog_tasks - [:from, :to].map do |key| - # These are arguments to OctocatalogDiff::Util::Parallel::Task. In most cases the arguments - # of OctocatalogDiff::Util::Parallel::Task are taken directly from options, but there are - # some defaults or otherwise-named options that must be set here. - args = @options.merge( - tag: key.to_s, - branch: @options["#{key}_env".to_sym], - bootstrapped_dir: @options["bootstrapped_#{key}_dir".to_sym], - basedir: @options[:basedir], - compare_file_text: @options.fetch(:compare_file_text, true), - retry_failed_catalog: @options.fetch(:retry_failed_catalog, 0), - parser: @options["parser_#{key}".to_sym] - ) - - # If any options are in the form of 'to_SOMETHING' or 'from_SOMETHING', this sets the option to - # 'SOMETHING' for the catalog if it matches this key. For example, when compiling the 'to' catalog - # when an option of :to_some_arg => 'foo', this sets :some_arg => foo, and deletes :to_some_arg and - # :from_some_arg. - @options.keys.select { |x| x.to_s =~ /^(to|from)_/ }.each do |opt_key| - args[opt_key.to_s.sub(/^(to|from)_/, '').to_sym] = @options[opt_key] if opt_key.to_s.start_with?(key.to_s) - args.delete(opt_key) - end - - # The task is a OctocatalogDiff::Util::Parallel::Task object that contains the method to execute, - # validator method, text description, and arguments to provide when calling the method. - task = OctocatalogDiff::Util::Parallel::Task.new( - method: method(:build_catalog), - validator: method(:catalog_validator), - validator_args: { task: key }, - description: "build_catalog for #{@options["#{key}_env".to_sym]}", - args: args - ) - - # The format of `catalog_tasks` will be a tuple, where the first element is the key - # (e.g. :to or :from) and the second element is the OctocatalogDiff::Util::Parallel::Task object. - [key, task] - end.compact - end - - # Given a result from the 'parallel' run and a corresponding (key,task) tuple, add valid - # catalogs to the 'result' hash and throw errors for invalid catalogs. - # @param result [Hash] Result hash for build_catalog_parallelizer (may be modified) - # @param parallel_catalog_obj [OctocatalogDiff::Util::Parallel::Result] Parallel catalog result - # @param key_task_tuple [Array] Key, task tuple - def add_parallel_result(result, parallel_catalog_obj, key_task_tuple) - # Expand the tuple into variables - key, task = key_task_tuple - - # For reporting purposes, get the branch name. - branch = task.args[:branch] - - # Check the result of the parallel run on this object. - if parallel_catalog_obj.status.nil? - # The compile was killed because another task failed. - @logger.warn "Catalog compile for #{branch} was aborted due to another failure" - - elsif parallel_catalog_obj.output.is_a?(OctocatalogDiff::Catalog) - # The result is a catalog, but we do not know if it was successfully compiled - # until we test the validity. - catalog = parallel_catalog_obj.output - if catalog.valid? - # The catalog was successfully compiled. - result[key] = parallel_catalog_obj.output - else - # The catalog failed, but a catalog object was returned so that better error reporting - # can take place. In this error reporting, we will replace 'Error:' with '[Puppet Error]' - # and remove the compilation directory (which is a tmpdir) to reveal only the relative - # path to the files involved. - dir = catalog.compilation_dir || '' - dir_regex = Regexp.new(Regexp.escape(dir) + '/environments/[^/]+/') - error_display = catalog.error_message.split("\n").map do |line| - line.sub(/^Error:/, '[Puppet Error]').gsub(dir_regex, '') - end.join("\n") - raise CatalogError, "Catalog for #{branch} failed to compile due to errors:\n#{error_display}" - end - else - # Something unhandled went wrong, and an exception was thrown. Reveal a generic message. - msg = parallel_catalog_obj.exception.message - message = "Catalog for '#{key}' (#{branch}) failed to compile with #{parallel_catalog_obj.exception.class}: #{msg}" - message += "\n" + parallel_catalog_obj.exception.backtrace.map { |x| " #{x}" }.join("\n") if @options[:debug] - raise CatalogError, message - end - end - - # Performs the steps necessary to build a catalog. - # @param opts [Hash] Options hash - # @return [Hash] { :rc => exit code, :catalog => Catalog as JSON string } - def build_catalog(opts, logger = @logger) - logger.debug("Setting up Puppet catalog build for #{opts[:branch]}") - catalog = opts[:object] - logger.debug("Catalog for #{opts[:branch]} will be built with #{catalog.builder}") - time_start = Time.now - catalog.build(logger) - time_it_took = Time.now - time_start - retries_str = " retries = #{catalog.retries}" if catalog.retries.is_a?(Fixnum) - time_str = "in #{time_it_took} seconds#{retries_str}" - status_str = catalog.valid? ? 'successfully built' : 'failed' - logger.debug "Catalog for #{opts[:branch]} #{status_str} with #{catalog.builder} #{time_str}" - catalog - end - - # Validate a catalog in the parallel execution - # @param catalog [OctocatalogDiff::Catalog] Catalog object - # @param logger [Logger] Logger object (presently unused) - # @param args [Hash] Additional arguments set specifically for validator - # @return [Boolean] true if catalog is valid, false otherwise - def catalog_validator(catalog = nil, _logger = @logger, args = {}) - return false unless catalog.is_a?(OctocatalogDiff::Catalog) - catalog.validate_references if args[:task] == :to - catalog.valid? - end - end - end - end -end diff --git a/lib/octocatalog-diff/catalog-diff/cli/diffs.rb b/lib/octocatalog-diff/catalog-diff/cli/diffs.rb deleted file mode 100644 index ee79464d..00000000 --- a/lib/octocatalog-diff/catalog-diff/cli/diffs.rb +++ /dev/null @@ -1,147 +0,0 @@ -# frozen_string_literal: true - -require_relative '../differ' - -module OctocatalogDiff - module CatalogDiff - class Cli - # Wrapper around OctocatalogDiff::CatalogDiff::Differ to provide the logger object, set up - # ignores, and add additional ignores for items dependent upon the compilation directory. - class Diffs - # Constructor - # @param options [Hash] Options from cli/options - # @param logger [Logger] Logger object - def initialize(options, logger) - @options = options - @logger = logger - end - - # The method to call externally, passing in the catalogs as a hash (see parameter). This - # sets up options and ignores and then actually performs the diffs. The result is the array - # of diffs. - # @param catalogs [Hash] { :to => OctocatalogDiff::Catalog, :from => OctocatalogDiff::Catalog } - # @return [Array] Array of diffs - def diffs(catalogs) - @logger.debug 'Begin compute diffs between catalogs' - diff_opts = @options.merge(logger: @logger) - - # Construct the actual differ object that the present one wraps - differ = OctocatalogDiff::CatalogDiff::Differ.new(diff_opts, catalogs[:from], catalogs[:to]) - differ.ignore(attr: 'tags') unless @options.fetch(:include_tags, false) - differ.ignore(@options.fetch(:ignore, [])) - - # Handle --ignore-tags option, the ability to tag resources within modules/manifests and - # have catalog-diff ignore them. - if @options[:ignore_tags].is_a?(Array) && @options[:ignore_tags].any? - # Go through the "to" catalog and identify any resources that have been tagged with one or more - # specified "ignore tags." Add any such items to the ignore list. The 'to' catalog has the authoritative - # list of dynamic ignores. - catalogs[:to].resources.each do |resource| - next unless tagged_for_ignore?(resource) - differ.ignore(type: resource['type'], title: resource['title']) - @logger.debug "Ignoring type='#{resource['type']}', title='#{resource['title']}' based on tag in to-catalog" - end - - # Go through the "from" catalog and identify any resources that have been tagged with one or more - # specified "ignore tags." Only mark the resources for ignoring if they do not appear in the 'to' - # catalog, thereby allowing the 'to' catalog to be the authoritative ignore list. This allows deleted - # items that were previously ignored to continue to be ignored. - catalogs[:from].resources.each do |resource| - next if catalogs[:to].resource(type: resource['type'], title: resource['title']) - next unless tagged_for_ignore?(resource) - differ.ignore(type: resource['type'], title: resource['title']) - @logger.debug "Ignoring type='#{resource['type']}', title='#{resource['title']}' based on tag in from-catalog" - end - end - - # Actually perform the diff - diff_result = differ.diff - diff_result.delete_if { |element| change_due_to_compilation_dir?(element, catalogs) } - @logger.debug 'Success compute diffs between catalogs' - diff_result - end - - # Catch anything that explictly changed as a result of different compilation directories and - # warn about it. These are probably things that should be refactored. For now we're going to pull - # these out after the fact so we can warn about them if they do show up. - # @param change [Array(diff format)] Change in diff format - # @param catalogs [Hash] { :to => OctocatalogDiff::Catalog, :from => OctocatalogDiff::Catalog } - # @return [Boolean] True if change includes compilation directory, false otherwise - def change_due_to_compilation_dir?(change, catalogs) - dir1 = catalogs.fetch(:to).compilation_dir - dir2 = catalogs.fetch(:from).compilation_dir - return false if dir1.nil? || dir2.nil? - - dir1_rexp = Regexp.escape(dir1) - dir2_rexp = Regexp.escape(dir2) - dir = "(?:#{dir1_rexp}|#{dir2_rexp})" - - # Check for added/removed resources where the title of the resource includes the compilation directory - if change[0] == '+' || change[0] == '-' - if change[1] =~ /^([^\f]+)\f([^\f]*#{dir}[^\f]*)/ - message = "Resource #{Regexp.last_match(1)}[#{Regexp.last_match(2)}]" - message += ' appears to depend on catalog compilation directory. Suppressed from results.' - @logger.warn message - return true - end - end - - # Check for a change where the difference in a parameter exactly corresponds to the difference in the - # compilation directory. - if change[0] == '~' || change[0] == '!' - from_before = nil - from_after = nil - from_match = false - to_before = nil - to_after = nil - to_match = false - - if change[2] =~ /^(.*)#{dir2}(.*)$/m - from_before = Regexp.last_match(1) || '' - from_after = Regexp.last_match(2) || '' - from_match = true - end - - if change[3] =~ /^(.*)#{dir1}(.*)$/m - to_before = Regexp.last_match(1) || '' - to_after = Regexp.last_match(2) || '' - to_match = true - end - - if from_match && to_match && to_before == from_before && to_after == from_after - message = "Resource key #{change[1].gsub(/\f/, ' => ')}" - message += ' appears to depend on catalog compilation directory. Suppressed from results.' - @logger.warn message - return true - end - - if from_match || to_match - message = "Resource key #{change[1].gsub(/\f/, ' => ')}" - message += ' may depend on catalog compilation directory, but there may be differences.' - message += ' This is included in results for now, but please verify.' - @logger.warn message - end - end - - false - end - - private - - # Determine if a resource is tagged with any ignore-tag. - # @param resource [Hash] The resource - # @return [Boolean] true if tagged for ignore, false if not - def tagged_for_ignore?(resource) - return false unless @options[:ignore_tags].is_a?(Array) - return false unless resource.key?('tags') && resource['tags'].is_a?(Array) - @options[:ignore_tags].each do |tag| - # tag_with_type will be like: 'ignored_catalog_diff__mymodule__mytype' - tag_with_type = [tag, resource['type'].downcase.gsub(/\W/, '_')].join('__') - return true if resource['tags'].include?(tag) || resource['tags'].include?(tag_with_type) - end - false - end - end - end - end -end diff --git a/lib/octocatalog-diff/catalog-diff/cli/helpers/fact_override.rb b/lib/octocatalog-diff/catalog-diff/cli/helpers/fact_override.rb deleted file mode 100644 index 11f11103..00000000 --- a/lib/octocatalog-diff/catalog-diff/cli/helpers/fact_override.rb +++ /dev/null @@ -1,100 +0,0 @@ -# frozen_string_literal: true - -require 'json' - -module OctocatalogDiff - module CatalogDiff - class Cli - class Helpers - # Since input from the command line is in the format of a string, this class helps to guess - # at the data type. - class FactOverride - # Accessors - attr_reader :key, :value - - # Constructor: Input will be a string (since it comes from command line). - # This code will make a best guess at the data type (or use a supplied data type if any). - # @param input [String] Input in the format: key=(data type)value - def initialize(input, key = nil) - # Normally the input will be a string in the format key=(data type)value where the data - # type is optional and the parentheses are literal. Example: - # foo=1 (auto-determine data type - in this case it would be a fixnum) - # foo=(fixnum)1 (will be a fixnum) - # foo=(string)1 (will be '1' the string) - # If input is not a string, we can still construct the object if the key is given. - # That input would come directly from code and not from the command line, since inputs - # from the command line are always strings. - if input.is_a?(String) - unless input.include?('=') - raise ArgumentError, "Fact override '#{input}' is not in 'key=(data type)value' format" - end - @key, raw_value = input.strip.split('=', 2) - @value = parsed_value(raw_value) - elsif key.nil? - message = "Define a key when the input is not a string (#{input.class} => #{input.inspect})" - raise ArgumentError, message - else - @key = key - @value = input - end - end - - private - - # Guess the datatype from a particular input - # @param input [String] Input in string format - # @return [?] Output in appropriate format - def parsed_value(input) - # If data type is explicitly given - if input =~ /^\((\w+)\)(.*)$/m - datatype = Regexp.last_match(1) - value = Regexp.last_match(2) - return convert_to_data_type(datatype.downcase, value) - end - - # Guess data type - return input.to_i if input =~ /^-?\d+$/ - return input.to_f if input =~ /^-?\d*\.\d+$/ - return true if input.casecmp('true').zero? - return false if input.casecmp('false').zero? - input - end - - # Handle data type that's explicitly given - # @param datatype [String] Data type (as a string) - # @param value [String] Value given - # @return [?] Value converted to specified data type - def convert_to_data_type(datatype, value) - return value if datatype == 'string' - return parse_json(value) if datatype == 'json' - return nil if datatype == 'nil' - if datatype == 'fixnum' - return Regexp.last_match(1).to_i if value =~ /^(-?\d+)$/ - raise ArgumentError, "Illegal fixnum '#{value}'" - end - if datatype == 'float' - return Regexp.last_match(1).to_f if value =~ /^(-?\d*\.\d+)$/ - return Regexp.last_match(1).to_f if value =~ /^(-?\d+)$/ - raise ArgumentError, "Illegal float '#{value}'" - end - if datatype == 'boolean' - return true if value.casecmp('true').zero? - return false if value.casecmp('false').zero? - raise ArgumentError, "Illegal boolean '#{value}'" - end - raise ArgumentError, "Unknown data type '#{datatype}'" - end - - # Parse JSON value - # @param input [String] Input, hopefully in JSON format - # @return [?] Output data structure - def parse_json(input) - JSON.parse(input) - rescue JSON::ParserError => exc - raise JSON::ParserError, "Failed to parse JSON: input=#{input} error=#{exc}" - end - end - end - end - end -end diff --git a/lib/octocatalog-diff/catalog-diff/cli/options.rb b/lib/octocatalog-diff/catalog-diff/cli/options.rb deleted file mode 100644 index dbc26dde..00000000 --- a/lib/octocatalog-diff/catalog-diff/cli/options.rb +++ /dev/null @@ -1,185 +0,0 @@ -# frozen_string_literal: true - -require_relative '../cli' -require_relative '../../facts' -require_relative '../../version' - -require 'optparse' - -module OctocatalogDiff - module CatalogDiff - class Cli - # This class contains the option parser. 'parse_options' is the external entry point. - class Options - # The usage banner. - BANNER = 'Usage: catalog-diff -n [-f ] [-t ]'.freeze - - # List of classes - def self.classes - @classes ||= [] - end - - # Define the Option class and newoption() method for use by catalog-diff/cli/options/*.rb files - class Option - DEFAULT_WEIGHT = 999 - def self.has_weight(w) # rubocop:disable Style/PredicateName - @weight = w - end - - def self.weight - @weight || DEFAULT_WEIGHT - end - - def self.name - self::NAME - end - - def self.newoption(name, &block) - klass = Class.new(OctocatalogDiff::CatalogDiff::Cli::Options::Option) - klass.const_set('NAME', name) - klass.class_exec(&block) - Options.classes.push(klass) - end - end - - # Method to call all of the other methods in this class. Except in very specific circumstances, - # this should be the method called from outside of this class. - # @param argv [Array] Array of command line arguments - # @param defaults [Hash] Default values - # @return [Hash] Parsed options - def self.parse_options(argv, defaults = {}) - options = defaults.dup - Options.classes.clear - ::OptionParser.new do |parser| - parser.banner = "#{BANNER}\n\n" - option_classes.each do |klass| - obj = klass.new - obj.parse(parser, options) - end - parser.on_tail('-v', '--version', 'Show version information about this program and quit.') do - puts "octocatalog-diff #{OctocatalogDiff::Version::VERSION}" - exit - end - end.parse! argv - options - end - - # Read in *.rb files in the 'options' directory and create classes from them. - # Sort the classes according to weight and name and return the list of sorted classes. - # @return [Array] Sorted classes - def self.option_classes - files = Dir.glob(File.join(File.dirname(__FILE__), 'options', '*.rb')) - files.each { |file| load file } # Populates self.classes - classes.sort do |a, b| - [ - a.weight <=> b.weight, - a.name.downcase <=> b.name.downcase, - a.object_id <=> b.object_id - ].find(&:nonzero?) - end - end - - # Sets up options that can be defined globally or for just one branch. For example, with a - # CLI name of 'puppet-binary' this will acknowledge 3 options: --puppet-binary (global), - # --from-puppet-binary (for the from branch only), and --to-puppet-binary (for the to branch - # only). The only options that will be created are the 'to' and 'from' variants, but the global - # option will populate any of the 'to' and 'from' variants that are missing. - # @param :datatype [?] Expected data type - def self.option_globally_or_per_branch(opts = {}) - datatype = opts.fetch(:datatype, '') - return option_globally_or_per_branch_string(opts) if datatype.is_a?(String) - return option_globally_or_per_branch_array(opts) if datatype.is_a?(Array) - raise ArgumentError, "option_globally_or_per_branch not equipped to handle #{datatype.class}" - end - - # See description of `option_globally_or_per_branch`. This implements the logic for a string value. - # @param :parser [OptionParser object] The OptionParser argument - # @param :options [Hash] Options hash being constructed; this is modified in this method. - # @param :cli_name [String] Name of option on command line (e.g. puppet-binary) - # @param :option_name [Symbol] Name of option in the options hash (e.g. :puppet_binary) - # @param :desc [String] Description of option on the command line; will have "for the XX branch" appended - def self.option_globally_or_per_branch_string(opts) - parser = opts.fetch(:parser) - options = opts.fetch(:options) - cli_name = opts.fetch(:cli_name) - option_name = opts.fetch(:option_name) - desc = opts.fetch(:desc) - - flag = "#{cli_name} STRING" - from_option = "from_#{option_name}".to_sym - to_option = "to_#{option_name}".to_sym - parser.on("--#{flag}", "#{desc} globally") do |x| - validate_option(opts[:validator], x) if opts[:validator] - translated = translate_option(opts[:translator], x) - options[to_option] ||= translated - options[from_option] ||= translated - end - parser.on("--to-#{flag}", "#{desc} for the to branch") do |x| - validate_option(opts[:validator], x) if opts[:validator] - options[to_option] = translate_option(opts[:translator], x) - end - parser.on("--from-#{flag}", "#{desc} for the from branch") do |x| - validate_option(opts[:validator], x) if opts[:validator] - options[from_option] = translate_option(opts[:translator], x) - end - end - - # See description of `option_globally_or_per_branch`. This implements the logic for an array. - # @param :parser [OptionParser object] The OptionParser argument - # @param :options [Hash] Options hash being constructed; this is modified in this method. - # @param :cli_name [String] Name of option on command line (e.g. puppet-binary) - # @param :option_name [Symbol] Name of option in the options hash (e.g. :puppet_binary) - # @param :desc [String] Description of option on the command line; will have "for the XX branch" appended - def self.option_globally_or_per_branch_array(opts = {}) - parser = opts.fetch(:parser) - options = opts.fetch(:options) - cli_name = opts.fetch(:cli_name) - option_name = opts.fetch(:option_name) - desc = opts.fetch(:desc) - - flag = "#{cli_name} STRING1[,STRING2[,...]]" - from_option = "from_#{option_name}".to_sym - to_option = "to_#{option_name}".to_sym - parser.on("--#{flag}", Array, "#{desc} globally") do |x| - validate_option(opts[:validator], x) if opts[:validator] - translated = translate_option(opts[:translator], x) - options[to_option] ||= [] - options[to_option].concat translated - options[from_option] ||= [] - options[from_option].concat translated - end - parser.on("--to-#{flag}", Array, "#{desc} for the to branch") do |x| - validate_option(opts[:validator], x) if opts[:validator] - options[to_option] ||= [] - options[to_option].concat translate_option(opts[:translator], x) - end - parser.on("--from-#{flag}", Array, "#{desc} for the from branch") do |x| - validate_option(opts[:validator], x) if opts[:validator] - options[from_option] ||= [] - options[from_option].concat translate_option(opts[:translator], x) - end - end - - # If a validator was provided, run the validator on the supplied value. The validator is expected to - # throw an error if there is a problem. Note that the validator runs *before* the translator if both - # a validator and translator are supplied. - # @param validator [Code] Validation function - # @param value [?] Value to validate (typically a String but can really be anything) - def self.validate_option(validator, value) - validator.call(value) - end - - # If a translator was provided, run the translator on the supplied value. The translator is expected - # to return the data type needed for the option (typically a String but can really be anything). Note - # that the translator runs *after* the validator if both a validator and translator are supplied. - # @param translator [Code] Translator function - # @param value [?] Original input value - # @return [?] Translated value - def self.translate_option(translator, value) - return value if translator.nil? - translator.call(value) - end - end - end - end -end diff --git a/lib/octocatalog-diff/catalog-diff/cli/printer.rb b/lib/octocatalog-diff/catalog-diff/cli/printer.rb deleted file mode 100644 index 7cad15f5..00000000 --- a/lib/octocatalog-diff/catalog-diff/cli/printer.rb +++ /dev/null @@ -1,54 +0,0 @@ -# frozen_string_literal: true - -require_relative '../display' - -module OctocatalogDiff - module CatalogDiff - class Cli - # Wrapper around OctocatalogDiff::CatalogDiff::Display to set the options and - # output to a file or the screen depending on selection. - class Printer - # Class for thrown exceptions - class PrinterError < RuntimeError - end - - # Constructor - # @param options [Hash] Options from cli/options - # @param logger [Logger] Logger object - def initialize(options, logger) - @options = options - @logger = logger - end - - # The method to call externally, passing in diffs. This takes the appropriate action - # based on options, which is either to write the result into an output file, or print - # the result on STDOUT. Does not return anything. - # @param diffs [OctocatalogDiff::CatalogDiff::Differ] Difference array - # @param from_dir [String] Directory in which "from" catalog was compiled - # @param to_dir [String] Directory in which "to" catalog was compiled - def printer(diffs, from_dir = nil, to_dir = nil) - display_opts = @options.merge(compilation_from_dir: from_dir, compilation_to_dir: to_dir) - diff_text = OctocatalogDiff::CatalogDiff::Display.output(diffs, display_opts, @logger) - if @options[:output_file].nil? - puts diff_text unless diff_text.empty? - else - output_to_file(diff_text) - end - end - - private - - # Output to a file, handling errors related to writing files. - # @param diff_in [String|Array] Text to write to file - def output_to_file(diff_in) - diff_text = diff_in.is_a?(Array) ? diff_in.join("\n") : diff_in - File.open(@options[:output_file], 'w') { |f| f.write(diff_text) } - @logger.info "Wrote diff to #{@options[:output_file]}" - rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR => exc - @logger.error "Cannot write to #{@options[:output_file]}: #{exc}" - raise PrinterError, "Cannot write to #{@options[:output_file]}: #{exc}" - end - end - end - end -end diff --git a/lib/octocatalog-diff/catalog-diff/differ.rb b/lib/octocatalog-diff/catalog-diff/differ.rb index 3805779d..1c677e20 100644 --- a/lib/octocatalog-diff/catalog-diff/differ.rb +++ b/lib/octocatalog-diff/catalog-diff/differ.rb @@ -7,6 +7,7 @@ require 'stringio' require_relative '../catalog' +require_relative '../errors' require_relative 'filter' module OctocatalogDiff @@ -55,10 +56,6 @@ module CatalogDiff # The heavy lifting is still handled by 'hashdiff' but we're pre-simplifying the input and post-processing # the output to make it easier to deal with later. class Differ - # This class is to distinguish handled errors from unhandled ones, for spec testing. - class DifferError < RuntimeError - end - # Constructor # @param catalog1_in [OctocatalogDiff::Catalog] First catalog to compare # @param catalog2_in [OctocatalogDiff::Catalog] Second catalog to compare @@ -594,7 +591,7 @@ def dig_out_key(hash_in, key_array) # @return [Hash] Internal simplified hash object def catalog_resources(catalog_in, name = 'Passed catalog') return catalog_in.resources if catalog_in.is_a?(OctocatalogDiff::Catalog) - raise DifferError, "#{name} is not a valid catalog (input datatype: #{catalog_in.class})" + raise OctocatalogDiff::Errors::DifferError, "#{name} is not a valid catalog (input datatype: #{catalog_in.class})" end # Turn array of resources into a hash by serialized keys. For consistency with 'hashdiff' diff --git a/lib/octocatalog-diff/catalog-util/bootstrap.rb b/lib/octocatalog-diff/catalog-util/bootstrap.rb index 7590b1ce..018cac34 100644 --- a/lib/octocatalog-diff/catalog-util/bootstrap.rb +++ b/lib/octocatalog-diff/catalog-util/bootstrap.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require_relative '../bootstrap' +require_relative '../errors' require_relative '../util/parallel' require_relative 'git' @@ -8,14 +9,10 @@ module OctocatalogDiff module CatalogUtil - # Methods to bootstrap a directory. Intended to be called from catalog-diff/cli. This handles + # Methods to bootstrap a directory. Intended to be called from cli. This handles # parallelization of bootstrap, and formats arguments as expected by the higher level bootstrap # script. class Bootstrap - # Exceptions that are anticipated can be caught in the calling class and tested - # for explicitly in spec tests. - class BootstrapError < RuntimeError; end - # Bootstrap directories specified by --bootstrapped-from-dir and --bootstrapped-to-dir # command line options. Bootstrapping occurs in parallel. This takes no parameters (options come # from options) and returns nothing (it raises an exception if something fails). @@ -28,7 +25,7 @@ def self.bootstrap_directory_parallelizer(options, logger) message = 'Must specify a from-branch other than . when using --bootstrapped-from-dir!' \ ' Please use "-f " argument.' logger.error(message) - raise BootstrapError, message + raise OctocatalogDiff::Errors::BootstrapError, message end opts = options.merge(branch: options[:from_env], @@ -43,7 +40,7 @@ def self.bootstrap_directory_parallelizer(options, logger) message = 'Must specify a to-branch other than . when using --bootstrapped-to-dir!' \ ' Please use "-t " argument.' logger.error(message) - raise BootstrapError, message + raise OctocatalogDiff::Errors::BootstrapError, message end opts = options.merge(branch: options[:to_env], @@ -58,7 +55,7 @@ def self.bootstrap_directory_parallelizer(options, logger) message = 'Specify one or more of --bootstrapped-from-dir / --bootstrapped-to-dir / --cached-master-dir' \ ' when using --bootstrap_then_exit' logger.error(message) - raise BootstrapError, message + raise OctocatalogDiff::Errors::BootstrapError, message end # Bootstrap the directories in parallel. Since there are no results here that we @@ -78,13 +75,13 @@ def self.bootstrap_directory_parallelizer(options, logger) logger.debug("Success bootstrap_directory for #{result.args[:tag]}") else errmsg = "Failed bootstrap_directory for #{result.args[:tag]}: #{result.exception.class} #{result.exception.message}" - raise BootstrapError, errmsg + raise OctocatalogDiff::Errors::BootstrapError, errmsg end end end # Performs the actual bootstrap of a directory. Intended to be called by bootstrap_directory_parallelizer - # above, or as part of the parallelized catalog build process from catalog-diff/cli/catalogs. + # above, or as part of the parallelized catalog build process from util/catalogs. # @param logger [Logger] Logger object # @param dir_opts [Hash] Directory options: branch, path, tag def self.bootstrap_directory(options, logger) @@ -104,9 +101,9 @@ def self.git_checkout(logger, dir_opts) logger.debug("Begin git checkout #{dir_opts[:basedir]}:#{dir_opts[:branch]} -> #{dir_opts[:path]}") OctocatalogDiff::CatalogUtil::Git.check_out_git_archive(dir_opts.merge(logger: logger)) logger.debug("Success git checkout #{dir_opts[:basedir]}:#{dir_opts[:branch]} -> #{dir_opts[:path]}") - rescue OctocatalogDiff::CatalogUtil::Git::GitCheckoutError => exc + rescue OctocatalogDiff::Errors::GitCheckoutError => exc logger.error("Git checkout error: #{exc}") - raise BootstrapError, exc + raise OctocatalogDiff::Errors::BootstrapError, exc end # Install bootstrap script in the target directory. This allows proper bootstrapping from the @@ -121,7 +118,7 @@ def self.install_bootstrap_script(logger, opts) else File.join(opts[:basedir], opts[:bootstrap_script]) end - raise BootstrapError, "Bootstrap script #{src} does not exist" unless File.file?(src) + raise OctocatalogDiff::Errors::BootstrapError, "Bootstrap script #{src} does not exist" unless File.file?(src) logger.debug('Begin install bootstrap script in target directory') @@ -146,7 +143,9 @@ def self.run_bootstrap(logger, opts) output = result[:output].split(/[\r\n]+/) output.each { |x| logger.debug("Bootstrap: #{x}") } end - raise BootstrapError, "bootstrap failed for #{opts[:path]}: #{result[:output]}" unless (result[:status_code]).zero? + unless (result[:status_code]).zero? + raise OctocatalogDiff::Errors::BootstrapError, "bootstrap failed for #{opts[:path]}: #{result[:output]}" + end logger.debug("Success bootstrap in #{opts[:path]}") result[:output] end diff --git a/lib/octocatalog-diff/catalog-util/cached_master_directory.rb b/lib/octocatalog-diff/catalog-util/cached_master_directory.rb index ac4b67a9..00a10a2a 100644 --- a/lib/octocatalog-diff/catalog-util/cached_master_directory.rb +++ b/lib/octocatalog-diff/catalog-util/cached_master_directory.rb @@ -2,7 +2,7 @@ require_relative 'bootstrap' require_relative 'git' -require_relative '../catalog-diff/cli/catalogs' +require_relative '../util/catalogs' require 'fileutils' @@ -134,7 +134,7 @@ def self.git_repo_checkout_bootstrap(options, logger) fake_options[:from_env] = master_branch(options) logger.debug 'Begin bootstrap cached master directory' - catalogs_obj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(fake_options, logger) + catalogs_obj = OctocatalogDiff::Util::Catalogs.new(fake_options, logger) catalogs_obj.bootstrap_then_exit logger.debug 'Success bootstrap cached master directory' diff --git a/lib/octocatalog-diff/catalog-util/enc/pe.rb b/lib/octocatalog-diff/catalog-util/enc/pe.rb index bfe23edb..9888bbad 100644 --- a/lib/octocatalog-diff/catalog-util/enc/pe.rb +++ b/lib/octocatalog-diff/catalog-util/enc/pe.rb @@ -2,6 +2,7 @@ require_relative 'pe/v1' require_relative '../../util/httparty' +require_relative '../../errors' require_relative '../facts' module OctocatalogDiff @@ -10,9 +11,6 @@ class ENC # Support the Puppet Enterprise classification API. # Documentation: https://docs.puppet.com/pe/latest/nc_index.html class PE - # Error class that can be caught - class ClassificationError < RuntimeError; end - # Allow the main ENC object to retrieve these values attr_reader :content, :error_message @@ -69,7 +67,7 @@ def execute(logger) begin @content = @api.result(response[:parsed], logger) @error_message = nil - rescue OctocatalogDiff::CatalogUtil::ENC::PE::ClassificationError => exc + rescue OctocatalogDiff::Errors::PEClassificationError => exc @error_message = exc.message logger.error "PE ENC failed: #{exc.message}" return @@ -87,7 +85,7 @@ def facts(logger) begin result = facts_obj.facts logger.debug "Success retrieving facts for #{@node} from #{self.class}" - rescue OctocatalogDiff::Facts::FactRetrievalError, OctocatalogDiff::Facts::FactSourceError => exc + rescue OctocatalogDiff::Errors::FactRetrievalError, OctocatalogDiff::Errors::FactSourceError => exc @content = nil @error_message = "Fact retrieval failed: #{exc.class} - #{exc.message}" logger.error @error_message diff --git a/lib/octocatalog-diff/catalog-util/enc/pe/v1.rb b/lib/octocatalog-diff/catalog-util/enc/pe/v1.rb index f3aee5a3..aba353d3 100644 --- a/lib/octocatalog-diff/catalog-util/enc/pe/v1.rb +++ b/lib/octocatalog-diff/catalog-util/enc/pe/v1.rb @@ -4,6 +4,8 @@ require 'uri' require 'yaml' +require_relative '../../../errors' + module OctocatalogDiff module CatalogUtil class ENC @@ -50,7 +52,7 @@ def result(parsed, logger) %w(classes parameters).each do |required_key| next if parsed[required_key] logger.debug parsed.keys.inspect - raise OctocatalogDiff::CatalogUtil::ENC::PE::ClassificationError, "Response missing: #{required_key}" + raise OctocatalogDiff::Errors::PEClassificationError, "Response missing: #{required_key}" end obj = { 'classes' => parsed['classes'], 'parameters' => parsed['parameters'] } diff --git a/lib/octocatalog-diff/catalog-util/git.rb b/lib/octocatalog-diff/catalog-util/git.rb index 5e4189d3..6e71039b 100644 --- a/lib/octocatalog-diff/catalog-util/git.rb +++ b/lib/octocatalog-diff/catalog-util/git.rb @@ -6,15 +6,13 @@ require 'shellwords' require 'tempfile' +require_relative '../errors' + module OctocatalogDiff module CatalogUtil # Class to perform a git checkout (via 'git archive') of a branch from the base git # directory into another targeted directory. class Git - # Trapped errors - class GitCheckoutError < RuntimeError - end - # Check out a branch via 'git archive' from one directory into another. # @param options [Hash] Options hash: # - :branch => Branch name to check out @@ -28,27 +26,39 @@ def self.check_out_git_archive(options = {}) logger = options.fetch(:logger) # Validate parameters - raise GitCheckoutError, "Source directory #{dir.inspect} does not exist" if dir.nil? || !File.directory?(dir) - raise GitCheckoutError, "Target directory #{path.inspect} does not exist" if dir.nil? || !File.directory?(path) - - # To get the options working correctly (-o pipefail in particular) this needs to run under - # bash. It's just creating a script, rather than figuring out all the shell escapes... - begin - tmp_script = Tempfile.new(['git-checkout', '.sh']) - tmp_script.write "#!/bin/bash\n" - tmp_script.write "set -euf -o pipefail\n" - tmp_script.write "git archive --format=tar #{Shellwords.escape(branch)} | \\\n" - tmp_script.write " ( cd #{Shellwords.escape(path)} && tar -xf - )\n" - tmp_script.close - FileUtils.chmod 0o755, tmp_script.path + if dir.nil? || !File.directory?(dir) + raise OctocatalogDiff::Errors::GitCheckoutError, "Source directory #{dir.inspect} does not exist" + end + if path.nil? || !File.directory?(path) + raise OctocatalogDiff::Errors::GitCheckoutError, "Target directory #{path.inspect} does not exist" + end - logger.debug("Begin git archive #{dir}:#{branch} -> #{path}") - output, status = Open3.capture2e(tmp_script.path, chdir: dir) - raise GitCheckoutError, "Git archive #{branch}->#{path} failed: #{output}" unless status.exitstatus.zero? - logger.debug("Success git archive #{dir}:#{branch}") - ensure - FileUtils.rm_f tmp_script.path if File.exist?(tmp_script.path) + # Create and execute checkout script + script = create_git_checkout_script(branch, path) + logger.debug("Begin git archive #{dir}:#{branch} -> #{path}") + output, status = Open3.capture2e(script, chdir: dir) + unless status.exitstatus.zero? + raise OctocatalogDiff::Errors::GitCheckoutError, "Git archive #{branch}->#{path} failed: #{output}" end + logger.debug("Success git archive #{dir}:#{branch}") + end + + # Create the temporary file used to interact with the git command line. + # To get the options working correctly (-o pipefail in particular) this needs to run under + # bash. It's just creating a script, rather than figuring out all the shell escapes... + # @param branch [String] Branch name + # @param path [String] Target directory + # @return [String] Name of script + def self.create_git_checkout_script(branch, path) + tmp_script = Tempfile.new(['git-checkout', '.sh']) + tmp_script.write "#!/bin/bash\n" + tmp_script.write "set -euf -o pipefail\n" + tmp_script.write "git archive --format=tar #{Shellwords.escape(branch)} | \\\n" + tmp_script.write " ( cd #{Shellwords.escape(path)} && tar -xf - )\n" + tmp_script.close + FileUtils.chmod 0o755, tmp_script.path + at_exit { FileUtils.rm_f tmp_script.path if File.exist?(tmp_script.path) } + tmp_script.path end # Determine the SHA of origin/master (or any other branch really) in the git repo @@ -58,7 +68,9 @@ def self.check_out_git_archive(options = {}) def self.branch_sha(options = {}) branch = options.fetch(:branch) dir = options.fetch(:basedir) - raise GitCheckoutError, "Git directory #{dir.inspect} does not exist" if dir.nil? || !File.directory?(dir) + if dir.nil? || !File.directory?(dir) + raise Errno::ENOENT, "Git directory #{dir.inspect} does not exist" + end repo = Rugged::Repository.new(dir) repo.branches[branch].target_id end diff --git a/lib/octocatalog-diff/catalog.rb b/lib/octocatalog-diff/catalog.rb index 1fd3d1f4..e0754bc5 100644 --- a/lib/octocatalog-diff/catalog.rb +++ b/lib/octocatalog-diff/catalog.rb @@ -9,6 +9,7 @@ require_relative 'catalog/puppetdb' require_relative 'catalog/puppetmaster' require_relative 'catalog-util/fileresources' +require_relative 'errors' module OctocatalogDiff # This class represents a catalog. Generation of the catalog is handled via one of the @@ -18,11 +19,6 @@ class Catalog # Readable attr_reader :built, :catalog, :catalog_json - # Error classes that we can throw - class PuppetVersionError < RuntimeError; end - class CatalogError < RuntimeError; end - class ReferenceValidationError < RuntimeError; end - # Constructor # @param :backend [Symbol] If set, this will force a backend # @param :json [String] JSON catalog content (will avoid running Puppet to compile catalog) @@ -159,8 +155,8 @@ def resource(opts = {}) # This is a compatibility layer for the resources, which are in a different place in Puppet 3.x and Puppet 4.x # @return [Array] Resource array def resources - raise CatalogError, 'Catalog does not appear to have been built' if !valid? && error_message.nil? - raise CatalogError, error_message unless valid? + raise OctocatalogDiff::Errors::CatalogError, 'Catalog does not appear to have been built' if !valid? && error_message.nil? + raise OctocatalogDiff::Errors::CatalogError, error_message unless valid? return @catalog['data']['resources'] if @catalog['data'].is_a?(Hash) && @catalog['data']['resources'].is_a?(Array) return @catalog['resources'] if @catalog['resources'].is_a?(Array) # This is a bug condition @@ -183,7 +179,7 @@ def valid? end # Determine if all of the (before, notify, require, subscribe) targets are actually in the catalog. - # Raise a ReferenceValidationError for any found to be missing. + # Raise a OctocatalogDiff::Errors::ReferenceValidationError for any found to be missing. # Uses @options[:validate_references] to influence which references are checked. def validate_references # Skip out early if no reference validation has been requested. @@ -223,7 +219,7 @@ def validate_references formatted_references.flatten! plural = formatted_references.size == 1 ? '' : 's' errors = formatted_references.join('; ') - raise ReferenceValidationError, "Catalog has broken reference#{plural}: #{errors}" + raise OctocatalogDiff::Errors::ReferenceValidationError, "Catalog has broken reference#{plural}: #{errors}" end private diff --git a/lib/octocatalog-diff/catalog/computed.rb b/lib/octocatalog-diff/catalog/computed.rb index 4d716da2..ed10f37a 100644 --- a/lib/octocatalog-diff/catalog/computed.rb +++ b/lib/octocatalog-diff/catalog/computed.rb @@ -89,7 +89,15 @@ def environment def cleanup_checkout_dir(checkout_dir, logger) return unless File.directory?(checkout_dir) logger.debug("Cleaning up temporary directory #{checkout_dir}") - FileUtils.remove_entry_secure checkout_dir + # Sometimes this seems to break when handling the recursive removal when running under + # a parallel environment. Trap and ignore the errors here if we don't care about them. + begin + FileUtils.remove_entry_secure checkout_dir + rescue Errno::ENOTEMPTY, Errno::ENOENT => exc + # :nocov: + logger.debug "cleanup_checkout_dir(#{checkout_dir}) logged #{exc.class} - this can be ignored" + # :nocov: + end end # Private method: Bootstrap a directory diff --git a/lib/octocatalog-diff/catalog/puppetdb.rb b/lib/octocatalog-diff/catalog/puppetdb.rb index cf06493e..389de2b5 100644 --- a/lib/octocatalog-diff/catalog/puppetdb.rb +++ b/lib/octocatalog-diff/catalog/puppetdb.rb @@ -3,6 +3,7 @@ require 'json' require 'stringio' +require_relative '../errors' require_relative '../puppetdb' module OctocatalogDiff @@ -67,11 +68,11 @@ def fetch_catalog(logger) # Set the other variables @catalog_json = ::JSON.generate(@catalog) @error_message = nil - rescue OctocatalogDiff::PuppetDB::ConnectionError => exc + rescue OctocatalogDiff::Errors::PuppetDBConnectionError => exc @error_message = "Catalog retrieval failed (#{exc.class}) (#{exc.message})" - rescue OctocatalogDiff::PuppetDB::NotFoundError => exc + rescue OctocatalogDiff::Errors::PuppetDBNodeNotFoundError => exc @error_message = "Node #{node} not found in PuppetDB (#{exc.message})" - rescue OctocatalogDiff::PuppetDB::PuppetDBError => exc + rescue OctocatalogDiff::Errors::PuppetDBGenericError => exc @error_message = "Catalog retrieval failed for node #{node} from PuppetDB (#{exc.message})" rescue ::JSON::GeneratorError => exc @error_message = "Failed to generate result from PuppetDB as JSON (#{exc.message})" diff --git a/lib/octocatalog-diff/cli.rb b/lib/octocatalog-diff/cli.rb new file mode 100644 index 00000000..459f4538 --- /dev/null +++ b/lib/octocatalog-diff/cli.rb @@ -0,0 +1,189 @@ +# frozen_string_literal: true + +require_relative 'api/v1' +require_relative 'catalog-util/cached_master_directory' +require_relative 'errors' +require_relative 'util/catalogs' +require_relative 'version' + +require_relative 'cli/diffs' +require_relative 'cli/options' +require_relative 'cli/printer' +require_relative 'cli/helpers/fact_override' + +require 'logger' +require 'socket' + +module OctocatalogDiff + # This is the CLI for catalog-diff. It's responsible for parsing the command line + # arguments and then handing off to appropriate methods to perform the catalog-diff. + class Cli + # Version number + VERSION = OctocatalogDiff::Version::VERSION + + # Exit codes + EXITCODE_SUCCESS_NO_DIFFS = 0 + EXITCODE_FAILURE = 1 + EXITCODE_SUCCESS_WITH_DIFFS = 2 + + # The default type+title+attribute to ignore in catalog-diff. + DEFAULT_IGNORES = [ + { type: 'Class' } # Don't care about classes themselves, only what they actually do! + ].freeze + + # The default options. + DEFAULT_OPTIONS = { + from_env: 'origin/master', + to_env: '.', + colors: true, + debug: false, + quiet: false, + format: :color_text, + display_source_file_line: false, + compare_file_text: true, + display_datatype_changes: true, + parallel: true, + suppress_absent_file_details: true, + hiera_path: 'hieradata' + }.freeze + + # This method is the one to call externally. It is possible to specify alternate + # command line arguments, for testing. + # @param argv [Array] Use specified arguments (defaults to ARGV) + # @param logger [Logger] Logger object + # @param opts [Hash] Additional options + # @return [Fixnum] Exit code: 0=no diffs, 1=something went wrong, 2=worked but there are diffs + def self.cli(argv = ARGV, logger = Logger.new(STDERR), opts = {}) + # Save a copy of argv to print out later in debugging + argv_save = argv.dup + + # Are there additional ARGV to munge, e.g. that have been supplied in the options from a + # configuration file? + if opts.key?(:additional_argv) + raise ArgumentError, ':additional_argv must be array!' unless opts[:additional_argv].is_a?(Array) + argv.concat opts[:additional_argv] + end + + # Parse command line + options = parse_opts(argv) + + # Additional options from hard-coded specified options. These are only processed if + # there are not already values defined from command line options. + # Note: do NOT use 'options[k] ||= v' here because if the value of options[k] is boolean(false) + # it will then be overridden. Whereas the intent is to define values only for those keys that don't exist. + opts.each { |k, v| options[k] = v unless options.key?(k) } + veto_options = %w(enc header hiera_config include_tags) + veto_options.each { |x| options.delete(x.to_sym) if options["no_#{x}".to_sym] } + options[:ignore].concat opts.fetch(:additional_ignores, []) + + # Incorporate default options where needed. + # Note: do NOT use 'options[k] ||= v' here because if the value of options[k] is boolean(false) + # it will then be overridden. Whereas the intent is to define values only for those keys that don't exist. + DEFAULT_OPTIONS.each { |k, v| options[k] = v unless options.key?(k) } + veto_with_none_options = %w(hiera_path hiera_path_strip) + veto_with_none_options.each { |x| options.delete(x.to_sym) if options[x.to_sym] == :none } + + # Fact overrides come in here - 'options' is modified + setup_fact_overrides(options) + + # Configure the logger and logger.debug initial information + # 'logger' is modified and used + setup_logger(logger, options, argv_save) + + # --catalog-only is a special case that compiles the catalog for the "to" branch + # and then exits, without doing any 'diff' whatsoever. Support that option. + return catalog_only(logger, options) if options[:catalog_only] + + # Set up the cached master directory - maintain it, adjust options if needed. However, if we + # are getting the 'from' catalog from PuppetDB, then don't do this. + unless options[:cached_master_dir].nil? || options[:from_puppetdb] + OctocatalogDiff::CatalogUtil::CachedMasterDirectory.run(options, logger) + end + + # bootstrap_then_exit is a special case that only prepares directories and does not + # depend on facts. This happens within the 'catalogs' object, since bootstrapping and + # preparing catalogs are tightly coupled operations. However this does not actually + # build catalogs. + if options[:bootstrap_then_exit] + catalogs_obj = OctocatalogDiff::Util::Catalogs.new(options, logger) + return bootstrap_then_exit(logger, catalogs_obj) + end + + # Compile catalogs and do catalog-diff + catalog_diff = OctocatalogDiff::API::V1.catalog_diff(options.merge(logger: logger)) + diffs = catalog_diff.diffs + + # Display diffs + printer_obj = OctocatalogDiff::Cli::Printer.new(options, logger) + printer_obj.printer(diffs, catalog_diff.from.compilation_dir, catalog_diff.to.compilation_dir) + + # Return the diff object if requested (generally for testing) or otherwise return exit code + return diffs if opts[:RETURN_DIFFS] + diffs.any? ? EXITCODE_SUCCESS_WITH_DIFFS : EXITCODE_SUCCESS_NO_DIFFS + end + + # Parse command line options with 'optparse'. Returns a hash with the parsed arguments. + # @param argv [Array] Command line arguments (MUST be specified) + # @return [Hash] Options + def self.parse_opts(argv) + options = { ignore: DEFAULT_IGNORES.dup } + Options.parse_options(argv, options) + end + + # Fact overrides come in here + def self.setup_fact_overrides(options) + [:from_fact_override, :to_fact_override].each do |key| + o = options["#{key}_in".to_sym] + next unless o.is_a?(Array) + next unless o.any? + options[key] ||= [] + options[key].concat o.map { |x| OctocatalogDiff::Cli::Helpers::FactOverride.new(x) } + end + end + + # Helper method: Configure and setup logger + def self.setup_logger(logger, options, argv_save) + # Configure the logger + logger.level = Logger::INFO + logger.level = Logger::DEBUG if options[:debug] + logger.level = Logger::ERROR if options[:quiet] + + # Some debugging information up front + version_display = ENV['OCTOCATALOG_DIFF_CUSTOM_VERSION'] || VERSION + logger.debug "Running octocatalog-diff #{version_display} with ruby #{RUBY_VERSION}" + logger.debug "Command line arguments: #{argv_save.inspect}" + logger.debug "Running on host #{Socket.gethostname} (#{RUBY_PLATFORM})" + end + + # Compile the catalog only + def self.catalog_only(logger, options) + opts = options.merge(logger: logger) + to_catalog = OctocatalogDiff::API::V1.catalog(opts) + + # If the catalog compilation failed, an exception would have been thrown. So if + # we get here, the catalog succeeded. Dump the catalog to the appropriate place + # and exit successfully. + if options[:output_file] + File.open(options[:output_file], 'w') { |f| f.write(to_catalog.to_json) } + logger.info "Wrote catalog to #{options[:output_file]}" + else + puts to_catalog.to_json + end + + return EXITCODE_SUCCESS_NO_DIFFS unless options[:RETURN_DIFFS] # For integration testing + # :nocov: + dummy_catalog = OctocatalogDiff::API::V1::Catalog.new(OctocatalogDiff::Catalog.new(backend: :noop)) + [dummy_catalog, to_catalog] + # :nocov: + end + + # --bootstrap-then-exit command + def self.bootstrap_then_exit(logger, catalogs_obj) + catalogs_obj.bootstrap_then_exit + return EXITCODE_SUCCESS_NO_DIFFS + rescue OctocatalogDiff::Errors::BootstrapError => exc + logger.fatal("--bootstrap-then-exit error: bootstrap failed (#{exc})") + return EXITCODE_FAILURE + end + end +end diff --git a/lib/octocatalog-diff/cli/diffs.rb b/lib/octocatalog-diff/cli/diffs.rb new file mode 100644 index 00000000..97ab6a8c --- /dev/null +++ b/lib/octocatalog-diff/cli/diffs.rb @@ -0,0 +1,145 @@ +# frozen_string_literal: true + +require_relative '../catalog-diff/differ' + +module OctocatalogDiff + class Cli + # Wrapper around OctocatalogDiff::CatalogDiff::Differ to provide the logger object, set up + # ignores, and add additional ignores for items dependent upon the compilation directory. + class Diffs + # Constructor + # @param options [Hash] Options from cli/options + # @param logger [Logger] Logger object + def initialize(options, logger) + @options = options + @logger = logger + end + + # The method to call externally, passing in the catalogs as a hash (see parameter). This + # sets up options and ignores and then actually performs the diffs. The result is the array + # of diffs. + # @param catalogs [Hash] { :to => OctocatalogDiff::Catalog, :from => OctocatalogDiff::Catalog } + # @return [Array] Array of diffs + def diffs(catalogs) + @logger.debug 'Begin compute diffs between catalogs' + diff_opts = @options.merge(logger: @logger) + + # Construct the actual differ object that the present one wraps + differ = OctocatalogDiff::CatalogDiff::Differ.new(diff_opts, catalogs[:from], catalogs[:to]) + differ.ignore(attr: 'tags') unless @options.fetch(:include_tags, false) + differ.ignore(@options.fetch(:ignore, [])) + + # Handle --ignore-tags option, the ability to tag resources within modules/manifests and + # have catalog-diff ignore them. + if @options[:ignore_tags].is_a?(Array) && @options[:ignore_tags].any? + # Go through the "to" catalog and identify any resources that have been tagged with one or more + # specified "ignore tags." Add any such items to the ignore list. The 'to' catalog has the authoritative + # list of dynamic ignores. + catalogs[:to].resources.each do |resource| + next unless tagged_for_ignore?(resource) + differ.ignore(type: resource['type'], title: resource['title']) + @logger.debug "Ignoring type='#{resource['type']}', title='#{resource['title']}' based on tag in to-catalog" + end + + # Go through the "from" catalog and identify any resources that have been tagged with one or more + # specified "ignore tags." Only mark the resources for ignoring if they do not appear in the 'to' + # catalog, thereby allowing the 'to' catalog to be the authoritative ignore list. This allows deleted + # items that were previously ignored to continue to be ignored. + catalogs[:from].resources.each do |resource| + next if catalogs[:to].resource(type: resource['type'], title: resource['title']) + next unless tagged_for_ignore?(resource) + differ.ignore(type: resource['type'], title: resource['title']) + @logger.debug "Ignoring type='#{resource['type']}', title='#{resource['title']}' based on tag in from-catalog" + end + end + + # Actually perform the diff + diff_result = differ.diff + diff_result.delete_if { |element| change_due_to_compilation_dir?(element, catalogs) } + @logger.debug 'Success compute diffs between catalogs' + diff_result + end + + # Catch anything that explictly changed as a result of different compilation directories and + # warn about it. These are probably things that should be refactored. For now we're going to pull + # these out after the fact so we can warn about them if they do show up. + # @param change [Array(diff format)] Change in diff format + # @param catalogs [Hash] { :to => OctocatalogDiff::Catalog, :from => OctocatalogDiff::Catalog } + # @return [Boolean] True if change includes compilation directory, false otherwise + def change_due_to_compilation_dir?(change, catalogs) + dir1 = catalogs.fetch(:to).compilation_dir + dir2 = catalogs.fetch(:from).compilation_dir + return false if dir1.nil? || dir2.nil? + + dir1_rexp = Regexp.escape(dir1) + dir2_rexp = Regexp.escape(dir2) + dir = "(?:#{dir1_rexp}|#{dir2_rexp})" + + # Check for added/removed resources where the title of the resource includes the compilation directory + if change[0] == '+' || change[0] == '-' + if change[1] =~ /^([^\f]+)\f([^\f]*#{dir}[^\f]*)/ + message = "Resource #{Regexp.last_match(1)}[#{Regexp.last_match(2)}]" + message += ' appears to depend on catalog compilation directory. Suppressed from results.' + @logger.warn message + return true + end + end + + # Check for a change where the difference in a parameter exactly corresponds to the difference in the + # compilation directory. + if change[0] == '~' || change[0] == '!' + from_before = nil + from_after = nil + from_match = false + to_before = nil + to_after = nil + to_match = false + + if change[2] =~ /^(.*)#{dir2}(.*)$/m + from_before = Regexp.last_match(1) || '' + from_after = Regexp.last_match(2) || '' + from_match = true + end + + if change[3] =~ /^(.*)#{dir1}(.*)$/m + to_before = Regexp.last_match(1) || '' + to_after = Regexp.last_match(2) || '' + to_match = true + end + + if from_match && to_match && to_before == from_before && to_after == from_after + message = "Resource key #{change[1].gsub(/\f/, ' => ')}" + message += ' appears to depend on catalog compilation directory. Suppressed from results.' + @logger.warn message + return true + end + + if from_match || to_match + message = "Resource key #{change[1].gsub(/\f/, ' => ')}" + message += ' may depend on catalog compilation directory, but there may be differences.' + message += ' This is included in results for now, but please verify.' + @logger.warn message + end + end + + false + end + + private + + # Determine if a resource is tagged with any ignore-tag. + # @param resource [Hash] The resource + # @return [Boolean] true if tagged for ignore, false if not + def tagged_for_ignore?(resource) + return false unless @options[:ignore_tags].is_a?(Array) + return false unless resource.key?('tags') && resource['tags'].is_a?(Array) + @options[:ignore_tags].each do |tag| + # tag_with_type will be like: 'ignored_catalog_diff__mymodule__mytype' + tag_with_type = [tag, resource['type'].downcase.gsub(/\W/, '_')].join('__') + return true if resource['tags'].include?(tag) || resource['tags'].include?(tag_with_type) + end + false + end + end + end +end diff --git a/lib/octocatalog-diff/cli/helpers/fact_override.rb b/lib/octocatalog-diff/cli/helpers/fact_override.rb new file mode 100644 index 00000000..dccbe568 --- /dev/null +++ b/lib/octocatalog-diff/cli/helpers/fact_override.rb @@ -0,0 +1,98 @@ +# frozen_string_literal: true + +require 'json' + +module OctocatalogDiff + class Cli + class Helpers + # Since input from the command line is in the format of a string, this class helps to guess + # at the data type. + class FactOverride + # Accessors + attr_reader :key, :value + + # Constructor: Input will be a string (since it comes from command line). + # This code will make a best guess at the data type (or use a supplied data type if any). + # @param input [String] Input in the format: key=(data type)value + def initialize(input, key = nil) + # Normally the input will be a string in the format key=(data type)value where the data + # type is optional and the parentheses are literal. Example: + # foo=1 (auto-determine data type - in this case it would be a fixnum) + # foo=(fixnum)1 (will be a fixnum) + # foo=(string)1 (will be '1' the string) + # If input is not a string, we can still construct the object if the key is given. + # That input would come directly from code and not from the command line, since inputs + # from the command line are always strings. + if input.is_a?(String) + unless input.include?('=') + raise ArgumentError, "Fact override '#{input}' is not in 'key=(data type)value' format" + end + @key, raw_value = input.strip.split('=', 2) + @value = parsed_value(raw_value) + elsif key.nil? + message = "Define a key when the input is not a string (#{input.class} => #{input.inspect})" + raise ArgumentError, message + else + @key = key + @value = input + end + end + + private + + # Guess the datatype from a particular input + # @param input [String] Input in string format + # @return [?] Output in appropriate format + def parsed_value(input) + # If data type is explicitly given + if input =~ /^\((\w+)\)(.*)$/m + datatype = Regexp.last_match(1) + value = Regexp.last_match(2) + return convert_to_data_type(datatype.downcase, value) + end + + # Guess data type + return input.to_i if input =~ /^-?\d+$/ + return input.to_f if input =~ /^-?\d*\.\d+$/ + return true if input.casecmp('true').zero? + return false if input.casecmp('false').zero? + input + end + + # Handle data type that's explicitly given + # @param datatype [String] Data type (as a string) + # @param value [String] Value given + # @return [?] Value converted to specified data type + def convert_to_data_type(datatype, value) + return value if datatype == 'string' + return parse_json(value) if datatype == 'json' + return nil if datatype == 'nil' + if datatype == 'fixnum' + return Regexp.last_match(1).to_i if value =~ /^(-?\d+)$/ + raise ArgumentError, "Illegal fixnum '#{value}'" + end + if datatype == 'float' + return Regexp.last_match(1).to_f if value =~ /^(-?\d*\.\d+)$/ + return Regexp.last_match(1).to_f if value =~ /^(-?\d+)$/ + raise ArgumentError, "Illegal float '#{value}'" + end + if datatype == 'boolean' + return true if value.casecmp('true').zero? + return false if value.casecmp('false').zero? + raise ArgumentError, "Illegal boolean '#{value}'" + end + raise ArgumentError, "Unknown data type '#{datatype}'" + end + + # Parse JSON value + # @param input [String] Input, hopefully in JSON format + # @return [?] Output data structure + def parse_json(input) + JSON.parse(input) + rescue JSON::ParserError => exc + raise JSON::ParserError, "Failed to parse JSON: input=#{input} error=#{exc}" + end + end + end + end +end diff --git a/lib/octocatalog-diff/cli/options.rb b/lib/octocatalog-diff/cli/options.rb new file mode 100644 index 00000000..a9762b91 --- /dev/null +++ b/lib/octocatalog-diff/cli/options.rb @@ -0,0 +1,183 @@ +# frozen_string_literal: true + +require_relative '../cli' +require_relative '../facts' +require_relative '../version' + +require 'optparse' + +module OctocatalogDiff + class Cli + # This class contains the option parser. 'parse_options' is the external entry point. + class Options + # The usage banner. + BANNER = 'Usage: catalog-diff -n [-f ] [-t ]'.freeze + + # List of classes + def self.classes + @classes ||= [] + end + + # Define the Option class and newoption() method for use by cli/options/*.rb files + class Option + DEFAULT_WEIGHT = 999 + def self.has_weight(w) # rubocop:disable Style/PredicateName + @weight = w + end + + def self.weight + @weight || DEFAULT_WEIGHT + end + + def self.name + self::NAME + end + + def self.newoption(name, &block) + klass = Class.new(OctocatalogDiff::Cli::Options::Option) + klass.const_set('NAME', name) + klass.class_exec(&block) + Options.classes.push(klass) + end + end + + # Method to call all of the other methods in this class. Except in very specific circumstances, + # this should be the method called from outside of this class. + # @param argv [Array] Array of command line arguments + # @param defaults [Hash] Default values + # @return [Hash] Parsed options + def self.parse_options(argv, defaults = {}) + options = defaults.dup + Options.classes.clear + ::OptionParser.new do |parser| + parser.banner = "#{BANNER}\n\n" + option_classes.each do |klass| + obj = klass.new + obj.parse(parser, options) + end + parser.on_tail('-v', '--version', 'Show version information about this program and quit.') do + puts "octocatalog-diff #{OctocatalogDiff::Version::VERSION}" + exit + end + end.parse! argv + options + end + + # Read in *.rb files in the 'options' directory and create classes from them. + # Sort the classes according to weight and name and return the list of sorted classes. + # @return [Array] Sorted classes + def self.option_classes + files = Dir.glob(File.join(File.dirname(__FILE__), 'options', '*.rb')) + files.each { |file| load file } # Populates self.classes + classes.sort do |a, b| + [ + a.weight <=> b.weight, + a.name.downcase <=> b.name.downcase, + a.object_id <=> b.object_id + ].find(&:nonzero?) + end + end + + # Sets up options that can be defined globally or for just one branch. For example, with a + # CLI name of 'puppet-binary' this will acknowledge 3 options: --puppet-binary (global), + # --from-puppet-binary (for the from branch only), and --to-puppet-binary (for the to branch + # only). The only options that will be created are the 'to' and 'from' variants, but the global + # option will populate any of the 'to' and 'from' variants that are missing. + # @param :datatype [?] Expected data type + def self.option_globally_or_per_branch(opts = {}) + datatype = opts.fetch(:datatype, '') + return option_globally_or_per_branch_string(opts) if datatype.is_a?(String) + return option_globally_or_per_branch_array(opts) if datatype.is_a?(Array) + raise ArgumentError, "option_globally_or_per_branch not equipped to handle #{datatype.class}" + end + + # See description of `option_globally_or_per_branch`. This implements the logic for a string value. + # @param :parser [OptionParser object] The OptionParser argument + # @param :options [Hash] Options hash being constructed; this is modified in this method. + # @param :cli_name [String] Name of option on command line (e.g. puppet-binary) + # @param :option_name [Symbol] Name of option in the options hash (e.g. :puppet_binary) + # @param :desc [String] Description of option on the command line; will have "for the XX branch" appended + def self.option_globally_or_per_branch_string(opts) + parser = opts.fetch(:parser) + options = opts.fetch(:options) + cli_name = opts.fetch(:cli_name) + option_name = opts.fetch(:option_name) + desc = opts.fetch(:desc) + + flag = "#{cli_name} STRING" + from_option = "from_#{option_name}".to_sym + to_option = "to_#{option_name}".to_sym + parser.on("--#{flag}", "#{desc} globally") do |x| + validate_option(opts[:validator], x) if opts[:validator] + translated = translate_option(opts[:translator], x) + options[to_option] ||= translated + options[from_option] ||= translated + end + parser.on("--to-#{flag}", "#{desc} for the to branch") do |x| + validate_option(opts[:validator], x) if opts[:validator] + options[to_option] = translate_option(opts[:translator], x) + end + parser.on("--from-#{flag}", "#{desc} for the from branch") do |x| + validate_option(opts[:validator], x) if opts[:validator] + options[from_option] = translate_option(opts[:translator], x) + end + end + + # See description of `option_globally_or_per_branch`. This implements the logic for an array. + # @param :parser [OptionParser object] The OptionParser argument + # @param :options [Hash] Options hash being constructed; this is modified in this method. + # @param :cli_name [String] Name of option on command line (e.g. puppet-binary) + # @param :option_name [Symbol] Name of option in the options hash (e.g. :puppet_binary) + # @param :desc [String] Description of option on the command line; will have "for the XX branch" appended + def self.option_globally_or_per_branch_array(opts = {}) + parser = opts.fetch(:parser) + options = opts.fetch(:options) + cli_name = opts.fetch(:cli_name) + option_name = opts.fetch(:option_name) + desc = opts.fetch(:desc) + + flag = "#{cli_name} STRING1[,STRING2[,...]]" + from_option = "from_#{option_name}".to_sym + to_option = "to_#{option_name}".to_sym + parser.on("--#{flag}", Array, "#{desc} globally") do |x| + validate_option(opts[:validator], x) if opts[:validator] + translated = translate_option(opts[:translator], x) + options[to_option] ||= [] + options[to_option].concat translated + options[from_option] ||= [] + options[from_option].concat translated + end + parser.on("--to-#{flag}", Array, "#{desc} for the to branch") do |x| + validate_option(opts[:validator], x) if opts[:validator] + options[to_option] ||= [] + options[to_option].concat translate_option(opts[:translator], x) + end + parser.on("--from-#{flag}", Array, "#{desc} for the from branch") do |x| + validate_option(opts[:validator], x) if opts[:validator] + options[from_option] ||= [] + options[from_option].concat translate_option(opts[:translator], x) + end + end + + # If a validator was provided, run the validator on the supplied value. The validator is expected to + # throw an error if there is a problem. Note that the validator runs *before* the translator if both + # a validator and translator are supplied. + # @param validator [Code] Validation function + # @param value [?] Value to validate (typically a String but can really be anything) + def self.validate_option(validator, value) + validator.call(value) + end + + # If a translator was provided, run the translator on the supplied value. The translator is expected + # to return the data type needed for the option (typically a String but can really be anything). Note + # that the translator runs *after* the validator if both a validator and translator are supplied. + # @param translator [Code] Translator function + # @param value [?] Original input value + # @return [?] Translated value + def self.translate_option(translator, value) + return value if translator.nil? + translator.call(value) + end + end + end +end diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/basedir.rb b/lib/octocatalog-diff/cli/options/basedir.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/basedir.rb rename to lib/octocatalog-diff/cli/options/basedir.rb index 81b9bef4..4b5b8d53 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/basedir.rb +++ b/lib/octocatalog-diff/cli/options/basedir.rb @@ -3,7 +3,7 @@ # Option to set the base checkout directory of puppet repository # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:basedir) do +OctocatalogDiff::Cli::Options::Option.newoption(:basedir) do has_weight 10 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_current.rb b/lib/octocatalog-diff/cli/options/bootstrap_current.rb similarity index 86% rename from lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_current.rb rename to lib/octocatalog-diff/cli/options/bootstrap_current.rb index 19a23597..0a39bc19 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_current.rb +++ b/lib/octocatalog-diff/cli/options/bootstrap_current.rb @@ -4,7 +4,7 @@ # run when the catalog builds in the current directory). # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:bootstrap_current) do +OctocatalogDiff::Cli::Options::Option.newoption(:bootstrap_current) do has_weight 48 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_environment.rb b/lib/octocatalog-diff/cli/options/bootstrap_environment.rb similarity index 90% rename from lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_environment.rb rename to lib/octocatalog-diff/cli/options/bootstrap_environment.rb index 0e04b4ce..5532503f 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_environment.rb +++ b/lib/octocatalog-diff/cli/options/bootstrap_environment.rb @@ -3,7 +3,7 @@ # Allow the bootstrap environment to be set up via the command line. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:bootstrap_environment) do +OctocatalogDiff::Cli::Options::Option.newoption(:bootstrap_environment) do has_weight 50 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_script.rb b/lib/octocatalog-diff/cli/options/bootstrap_script.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_script.rb rename to lib/octocatalog-diff/cli/options/bootstrap_script.rb index eb1b1d88..9638e468 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_script.rb +++ b/lib/octocatalog-diff/cli/options/bootstrap_script.rb @@ -5,7 +5,7 @@ # to be done. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:bootstrap_script) do +OctocatalogDiff::Cli::Options::Option.newoption(:bootstrap_script) do has_weight 40 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_then_exit.rb b/lib/octocatalog-diff/cli/options/bootstrap_then_exit.rb similarity index 83% rename from lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_then_exit.rb rename to lib/octocatalog-diff/cli/options/bootstrap_then_exit.rb index 76c62423..abef1fb4 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrap_then_exit.rb +++ b/lib/octocatalog-diff/cli/options/bootstrap_then_exit.rb @@ -3,7 +3,7 @@ # Option to bootstrap directories and then exit # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:bootstrap_then_exit) do +OctocatalogDiff::Cli::Options::Option.newoption(:bootstrap_then_exit) do has_weight 70 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrapped_dirs.rb b/lib/octocatalog-diff/cli/options/bootstrapped_dirs.rb similarity index 91% rename from lib/octocatalog-diff/catalog-diff/cli/options/bootstrapped_dirs.rb rename to lib/octocatalog-diff/cli/options/bootstrapped_dirs.rb index 6fb0bb4a..83133eba 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/bootstrapped_dirs.rb +++ b/lib/octocatalog-diff/cli/options/bootstrapped_dirs.rb @@ -4,7 +4,7 @@ # to save time when diffing multiple catalogs on this system. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:bootstrapped_dirs) do +OctocatalogDiff::Cli::Options::Option.newoption(:bootstrapped_dirs) do has_weight 60 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/cached_master_dir.rb b/lib/octocatalog-diff/cli/options/cached_master_dir.rb similarity index 89% rename from lib/octocatalog-diff/catalog-diff/cli/options/cached_master_dir.rb rename to lib/octocatalog-diff/cli/options/cached_master_dir.rb index 039ccb76..4abd08a4 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/cached_master_dir.rb +++ b/lib/octocatalog-diff/cli/options/cached_master_dir.rb @@ -4,7 +4,7 @@ # has not changed. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:cached_master_dir) do +OctocatalogDiff::Cli::Options::Option.newoption(:cached_master_dir) do has_weight 160 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/catalog_only.rb b/lib/octocatalog-diff/cli/options/catalog_only.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/catalog_only.rb rename to lib/octocatalog-diff/cli/options/catalog_only.rb index ea9f5ca1..11298e50 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/catalog_only.rb +++ b/lib/octocatalog-diff/cli/options/catalog_only.rb @@ -4,7 +4,7 @@ # diffing activity. The catalog will be printed to STDOUT or written to the output file. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:catalog_only) do +OctocatalogDiff::Cli::Options::Option.newoption(:catalog_only) do has_weight 290 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/color.rb b/lib/octocatalog-diff/cli/options/color.rb similarity index 85% rename from lib/octocatalog-diff/catalog-diff/cli/options/color.rb rename to lib/octocatalog-diff/cli/options/color.rb index b66f9602..ad4ea1b1 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/color.rb +++ b/lib/octocatalog-diff/cli/options/color.rb @@ -3,7 +3,7 @@ # Color printing option # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:color) do +OctocatalogDiff::Cli::Options::Option.newoption(:color) do has_weight 80 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/command_line.rb b/lib/octocatalog-diff/cli/options/command_line.rb similarity index 76% rename from lib/octocatalog-diff/catalog-diff/cli/options/command_line.rb rename to lib/octocatalog-diff/cli/options/command_line.rb index 0e34c4a8..932cc343 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/command_line.rb +++ b/lib/octocatalog-diff/cli/options/command_line.rb @@ -3,11 +3,11 @@ # Provide additional command line flags to set when running Puppet to compile catalogs. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:command_line) do +OctocatalogDiff::Cli::Options::Option.newoption(:command_line) do has_weight 510 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'command-line', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/compare_file_text.rb b/lib/octocatalog-diff/cli/options/compare_file_text.rb similarity index 89% rename from lib/octocatalog-diff/catalog-diff/cli/options/compare_file_text.rb rename to lib/octocatalog-diff/cli/options/compare_file_text.rb index 07817f11..9db998e6 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/compare_file_text.rb +++ b/lib/octocatalog-diff/cli/options/compare_file_text.rb @@ -6,7 +6,7 @@ # what is most often desired. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:compare_file_text) do +OctocatalogDiff::Cli::Options::Option.newoption(:compare_file_text) do has_weight 210 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/create_symlinks.rb b/lib/octocatalog-diff/cli/options/create_symlinks.rb similarity index 78% rename from lib/octocatalog-diff/catalog-diff/cli/options/create_symlinks.rb rename to lib/octocatalog-diff/cli/options/create_symlinks.rb index 4660eb8c..d8808cb3 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/create_symlinks.rb +++ b/lib/octocatalog-diff/cli/options/create_symlinks.rb @@ -4,11 +4,11 @@ # environment. This is useful only in conjunction with `--preserve-environments`. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:create_symlinks) do +OctocatalogDiff::Cli::Options::Option.newoption(:create_symlinks) do has_weight 503 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'create-symlinks', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/debug.rb b/lib/octocatalog-diff/cli/options/debug.rb similarity index 83% rename from lib/octocatalog-diff/catalog-diff/cli/options/debug.rb rename to lib/octocatalog-diff/cli/options/debug.rb index 4a1acebc..fc8a6c7e 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/debug.rb +++ b/lib/octocatalog-diff/cli/options/debug.rb @@ -3,7 +3,7 @@ # Debugging option # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:debug) do +OctocatalogDiff::Cli::Options::Option.newoption(:debug) do has_weight 110 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/debug_bootstrap.rb b/lib/octocatalog-diff/cli/options/debug_bootstrap.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/debug_bootstrap.rb rename to lib/octocatalog-diff/cli/options/debug_bootstrap.rb index befcff1d..a8ca0461 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/debug_bootstrap.rb +++ b/lib/octocatalog-diff/cli/options/debug_bootstrap.rb @@ -5,7 +5,7 @@ # any effect. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:debug_bootstrap) do +OctocatalogDiff::Cli::Options::Option.newoption(:debug_bootstrap) do has_weight 49 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/display_datatype_changes.rb b/lib/octocatalog-diff/cli/options/display_datatype_changes.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/display_datatype_changes.rb rename to lib/octocatalog-diff/cli/options/display_datatype_changes.rb index 98c16d67..6186ab0c 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/display_datatype_changes.rb +++ b/lib/octocatalog-diff/cli/options/display_datatype_changes.rb @@ -6,7 +6,7 @@ # difference. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:display_datatype_changes) do +OctocatalogDiff::Cli::Options::Option.newoption(:display_datatype_changes) do has_weight 280 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/display_detail_add.rb b/lib/octocatalog-diff/cli/options/display_detail_add.rb similarity index 84% rename from lib/octocatalog-diff/catalog-diff/cli/options/display_detail_add.rb rename to lib/octocatalog-diff/cli/options/display_detail_add.rb index bcd637ea..feecc5f7 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/display_detail_add.rb +++ b/lib/octocatalog-diff/cli/options/display_detail_add.rb @@ -3,7 +3,7 @@ # Provide ability to display details of 'added' resources in the output. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:display_detail_add) do +OctocatalogDiff::Cli::Options::Option.newoption(:display_detail_add) do has_weight 250 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/display_source_file_line.rb b/lib/octocatalog-diff/cli/options/display_source_file_line.rb similarity index 82% rename from lib/octocatalog-diff/catalog-diff/cli/options/display_source_file_line.rb rename to lib/octocatalog-diff/cli/options/display_source_file_line.rb index 09fabcdc..dec973fe 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/display_source_file_line.rb +++ b/lib/octocatalog-diff/cli/options/display_source_file_line.rb @@ -3,7 +3,7 @@ # Display source filename and line number for diffs # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:display_source_file_line) do +OctocatalogDiff::Cli::Options::Option.newoption(:display_source_file_line) do has_weight 200 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/enc.rb b/lib/octocatalog-diff/cli/options/enc.rb similarity index 94% rename from lib/octocatalog-diff/catalog-diff/cli/options/enc.rb rename to lib/octocatalog-diff/cli/options/enc.rb index 33b0cb9d..c982d6ec 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/enc.rb +++ b/lib/octocatalog-diff/cli/options/enc.rb @@ -3,7 +3,7 @@ # Path to external node classifier, relative to the base directory of the checkout. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:enc) do +OctocatalogDiff::Cli::Options::Option.newoption(:enc) do has_weight 240 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/environment.rb b/lib/octocatalog-diff/cli/options/environment.rb similarity index 77% rename from lib/octocatalog-diff/catalog-diff/cli/options/environment.rb rename to lib/octocatalog-diff/cli/options/environment.rb index fb116778..e5729282 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/environment.rb +++ b/lib/octocatalog-diff/cli/options/environment.rb @@ -4,11 +4,11 @@ # with `--preserve-environments`. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:environment) do +OctocatalogDiff::Cli::Options::Option.newoption(:environment) do has_weight 502 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'environment', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/existing_catalogs.rb b/lib/octocatalog-diff/cli/options/existing_catalogs.rb similarity index 92% rename from lib/octocatalog-diff/catalog-diff/cli/options/existing_catalogs.rb rename to lib/octocatalog-diff/cli/options/existing_catalogs.rb index df4a0f6b..70267962 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/existing_catalogs.rb +++ b/lib/octocatalog-diff/cli/options/existing_catalogs.rb @@ -6,7 +6,7 @@ # These files must exist and be in Puppet catalog format. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:existing_catalogs) do +OctocatalogDiff::Cli::Options::Option.newoption(:existing_catalogs) do has_weight 30 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/fact_file.rb b/lib/octocatalog-diff/cli/options/fact_file.rb similarity index 93% rename from lib/octocatalog-diff/catalog-diff/cli/options/fact_file.rb rename to lib/octocatalog-diff/cli/options/fact_file.rb index 86f14d79..7f1ccb02 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/fact_file.rb +++ b/lib/octocatalog-diff/cli/options/fact_file.rb @@ -3,7 +3,7 @@ # Allow an existing fact file to be provided, to avoid pulling facts from PuppetDB. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:fact_file) do +OctocatalogDiff::Cli::Options::Option.newoption(:fact_file) do has_weight 150 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/fact_override.rb b/lib/octocatalog-diff/cli/options/fact_override.rb similarity index 81% rename from lib/octocatalog-diff/catalog-diff/cli/options/fact_override.rb rename to lib/octocatalog-diff/cli/options/fact_override.rb index 1fe5239c..6e8c5d0c 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/fact_override.rb +++ b/lib/octocatalog-diff/cli/options/fact_override.rb @@ -3,13 +3,13 @@ # Allow override of facts on the command line. Fact overrides can be supplied for the 'to' or 'from' catalog, # or for both. There is some attempt to handle data types here (since all items on the command line are strings) # by permitting a data type specification as well. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:fact_override) do +OctocatalogDiff::Cli::Options::Option.newoption(:fact_override) do has_weight 320 def parse(parser, options) # Set 'fact_override_in' because more processing is needed, once the command line options # have been parsed, to make this into the final form 'fact_override'. - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'fact-override', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/facts_terminus.rb b/lib/octocatalog-diff/cli/options/facts_terminus.rb similarity index 90% rename from lib/octocatalog-diff/catalog-diff/cli/options/facts_terminus.rb rename to lib/octocatalog-diff/cli/options/facts_terminus.rb index d7e76ba5..eff42a31 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/facts_terminus.rb +++ b/lib/octocatalog-diff/cli/options/facts_terminus.rb @@ -5,7 +5,7 @@ # on which this is running. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:facts_terminus) do +OctocatalogDiff::Cli::Options::Option.newoption(:facts_terminus) do has_weight 310 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/filters.rb b/lib/octocatalog-diff/cli/options/filters.rb similarity index 81% rename from lib/octocatalog-diff/catalog-diff/cli/options/filters.rb rename to lib/octocatalog-diff/cli/options/filters.rb index a998c56e..60121351 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/filters.rb +++ b/lib/octocatalog-diff/cli/options/filters.rb @@ -2,10 +2,10 @@ # Specify one or more filters to apply to the results of the catalog difference. # For a list of available filters and further explanation, please refer to -# [Filtering results](/doc/advanced-filter.md). +# Filtering results. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:filters) do +OctocatalogDiff::Cli::Options::Option.newoption(:filters) do has_weight 199 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/from_puppetdb.rb b/lib/octocatalog-diff/cli/options/from_puppetdb.rb similarity index 85% rename from lib/octocatalog-diff/catalog-diff/cli/options/from_puppetdb.rb rename to lib/octocatalog-diff/cli/options/from_puppetdb.rb index 33092264..d71f3529 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/from_puppetdb.rb +++ b/lib/octocatalog-diff/cli/options/from_puppetdb.rb @@ -3,7 +3,7 @@ # Set --from-puppetdb to pull most recent catalog from PuppetDB instead of compiling # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:from_puppetdb) do +OctocatalogDiff::Cli::Options::Option.newoption(:from_puppetdb) do has_weight 300 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/header.rb b/lib/octocatalog-diff/cli/options/header.rb similarity index 94% rename from lib/octocatalog-diff/catalog-diff/cli/options/header.rb rename to lib/octocatalog-diff/cli/options/header.rb index 745e0e1a..bd763862 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/header.rb +++ b/lib/octocatalog-diff/cli/options/header.rb @@ -3,7 +3,7 @@ # Provide ability to set custom header or to display no header at all # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:header) do +OctocatalogDiff::Cli::Options::Option.newoption(:header) do has_weight 260 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/hiera_config.rb b/lib/octocatalog-diff/cli/options/hiera_config.rb similarity index 90% rename from lib/octocatalog-diff/catalog-diff/cli/options/hiera_config.rb rename to lib/octocatalog-diff/cli/options/hiera_config.rb index 71c76d7c..353075f4 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/hiera_config.rb +++ b/lib/octocatalog-diff/cli/options/hiera_config.rb @@ -3,7 +3,7 @@ # Specify a relative path to the Hiera yaml file # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:hiera_config) do +OctocatalogDiff::Cli::Options::Option.newoption(:hiera_config) do has_weight 180 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/hiera_path.rb b/lib/octocatalog-diff/cli/options/hiera_path.rb similarity index 95% rename from lib/octocatalog-diff/catalog-diff/cli/options/hiera_path.rb rename to lib/octocatalog-diff/cli/options/hiera_path.rb index 611df6e0..534f4693 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/hiera_path.rb +++ b/lib/octocatalog-diff/cli/options/hiera_path.rb @@ -4,7 +4,7 @@ # Puppet control repo template, the value of this should be 'hieradata', which is the default. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:hiera_path) do +OctocatalogDiff::Cli::Options::Option.newoption(:hiera_path) do has_weight 181 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/hiera_path_strip.rb b/lib/octocatalog-diff/cli/options/hiera_path_strip.rb similarity index 92% rename from lib/octocatalog-diff/catalog-diff/cli/options/hiera_path_strip.rb rename to lib/octocatalog-diff/cli/options/hiera_path_strip.rb index b583c2d9..e2a0c2c1 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/hiera_path_strip.rb +++ b/lib/octocatalog-diff/cli/options/hiera_path_strip.rb @@ -3,7 +3,7 @@ # Specify the path to strip off the datadir to munge hiera.yaml file # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:hiera_path_strip) do +OctocatalogDiff::Cli::Options::Option.newoption(:hiera_path_strip) do has_weight 182 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/hostname.rb b/lib/octocatalog-diff/cli/options/hostname.rb similarity index 86% rename from lib/octocatalog-diff/catalog-diff/cli/options/hostname.rb rename to lib/octocatalog-diff/cli/options/hostname.rb index 17076b9b..59761687 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/hostname.rb +++ b/lib/octocatalog-diff/cli/options/hostname.rb @@ -4,7 +4,7 @@ # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:hostname) do +OctocatalogDiff::Cli::Options::Option.newoption(:hostname) do has_weight 1 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/ignore.rb b/lib/octocatalog-diff/cli/options/ignore.rb similarity index 93% rename from lib/octocatalog-diff/catalog-diff/cli/options/ignore.rb rename to lib/octocatalog-diff/cli/options/ignore.rb index d818fb47..677fbedf 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/ignore.rb +++ b/lib/octocatalog-diff/cli/options/ignore.rb @@ -3,7 +3,7 @@ # Options used when comparing catalogs - set ignored changes. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:ignore) do +OctocatalogDiff::Cli::Options::Option.newoption(:ignore) do has_weight 130 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/ignore_attr.rb b/lib/octocatalog-diff/cli/options/ignore_attr.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/ignore_attr.rb rename to lib/octocatalog-diff/cli/options/ignore_attr.rb index 417bd810..696d6f46 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/ignore_attr.rb +++ b/lib/octocatalog-diff/cli/options/ignore_attr.rb @@ -3,7 +3,7 @@ # Specify attributes to ignore # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:ignore_attr) do +OctocatalogDiff::Cli::Options::Option.newoption(:ignore_attr) do has_weight 190 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/ignore_tags.rb b/lib/octocatalog-diff/cli/options/ignore_tags.rb similarity index 92% rename from lib/octocatalog-diff/catalog-diff/cli/options/ignore_tags.rb rename to lib/octocatalog-diff/cli/options/ignore_tags.rb index 95b99c90..f29beeca 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/ignore_tags.rb +++ b/lib/octocatalog-diff/cli/options/ignore_tags.rb @@ -4,7 +4,7 @@ # to ignore any changes for any defined type where this tag is set. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:ignore_tags) do +OctocatalogDiff::Cli::Options::Option.newoption(:ignore_tags) do has_weight 400 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/include_tags.rb b/lib/octocatalog-diff/cli/options/include_tags.rb similarity index 85% rename from lib/octocatalog-diff/catalog-diff/cli/options/include_tags.rb rename to lib/octocatalog-diff/cli/options/include_tags.rb index 6cd8cb73..b92c8be4 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/include_tags.rb +++ b/lib/octocatalog-diff/cli/options/include_tags.rb @@ -3,7 +3,7 @@ # Options used when comparing catalogs - tags are generally ignored; you can un-ignore them. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:include_tags) do +OctocatalogDiff::Cli::Options::Option.newoption(:include_tags) do has_weight 140 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/master_cache_branch.rb b/lib/octocatalog-diff/cli/options/master_cache_branch.rb similarity index 83% rename from lib/octocatalog-diff/catalog-diff/cli/options/master_cache_branch.rb rename to lib/octocatalog-diff/cli/options/master_cache_branch.rb index 547cead4..e894fdde 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/master_cache_branch.rb +++ b/lib/octocatalog-diff/cli/options/master_cache_branch.rb @@ -3,7 +3,7 @@ # Allow override of the branch that is cached. This defaults to 'origin/master'. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:master_cache_branch) do +OctocatalogDiff::Cli::Options::Option.newoption(:master_cache_branch) do has_weight 160 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/output_file.rb b/lib/octocatalog-diff/cli/options/output_file.rb similarity index 86% rename from lib/octocatalog-diff/catalog-diff/cli/options/output_file.rb rename to lib/octocatalog-diff/cli/options/output_file.rb index a3f490e0..c3b1578f 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/output_file.rb +++ b/lib/octocatalog-diff/cli/options/output_file.rb @@ -3,7 +3,7 @@ # Output file option # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:output_file) do +OctocatalogDiff::Cli::Options::Option.newoption(:output_file) do has_weight 90 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/output_format.rb b/lib/octocatalog-diff/cli/options/output_format.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/output_format.rb rename to lib/octocatalog-diff/cli/options/output_format.rb index a7276b43..af143d2f 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/output_format.rb +++ b/lib/octocatalog-diff/cli/options/output_format.rb @@ -3,7 +3,7 @@ # Output format option # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:output_format) do +OctocatalogDiff::Cli::Options::Option.newoption(:output_format) do has_weight 100 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/parallel.rb b/lib/octocatalog-diff/cli/options/parallel.rb similarity index 84% rename from lib/octocatalog-diff/catalog-diff/cli/options/parallel.rb rename to lib/octocatalog-diff/cli/options/parallel.rb index 3b354fcd..933a7db3 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/parallel.rb +++ b/lib/octocatalog-diff/cli/options/parallel.rb @@ -3,7 +3,7 @@ # Disable or enable parallel processing of catalogs. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:parallel) do +OctocatalogDiff::Cli::Options::Option.newoption(:parallel) do has_weight 300 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/parser.rb b/lib/octocatalog-diff/cli/options/parser.rb similarity index 96% rename from lib/octocatalog-diff/catalog-diff/cli/options/parser.rb rename to lib/octocatalog-diff/cli/options/parser.rb index 9be266aa..2a7ba1eb 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/parser.rb +++ b/lib/octocatalog-diff/cli/options/parser.rb @@ -3,7 +3,7 @@ # Enable future parser for both branches or for just one # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:parser) do +OctocatalogDiff::Cli::Options::Option.newoption(:parser) do has_weight 270 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/pass_env_vars.rb b/lib/octocatalog-diff/cli/options/pass_env_vars.rb similarity index 91% rename from lib/octocatalog-diff/catalog-diff/cli/options/pass_env_vars.rb rename to lib/octocatalog-diff/cli/options/pass_env_vars.rb index 8068bdbf..c70b6e3f 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/pass_env_vars.rb +++ b/lib/octocatalog-diff/cli/options/pass_env_vars.rb @@ -5,7 +5,7 @@ # available. Setting these variables is your responsibility outside of octocatalog-diff. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:pass_env_vars) do +OctocatalogDiff::Cli::Options::Option.newoption(:pass_env_vars) do has_weight 600 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_ca.rb b/lib/octocatalog-diff/cli/options/pe_enc_ssl_ca.rb similarity index 90% rename from lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_ca.rb rename to lib/octocatalog-diff/cli/options/pe_enc_ssl_ca.rb index 898e5df1..efaee276 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_ca.rb +++ b/lib/octocatalog-diff/cli/options/pe_enc_ssl_ca.rb @@ -5,7 +5,7 @@ # matches the name you are using to connecting. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:pe_enc_ssl_ca) do +OctocatalogDiff::Cli::Options::Option.newoption(:pe_enc_ssl_ca) do has_weight 352 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_cert.rb b/lib/octocatalog-diff/cli/options/pe_enc_ssl_client_cert.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_cert.rb rename to lib/octocatalog-diff/cli/options/pe_enc_ssl_client_cert.rb index 30fba827..26da8165 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_cert.rb +++ b/lib/octocatalog-diff/cli/options/pe_enc_ssl_client_cert.rb @@ -4,7 +4,7 @@ # --pe-enc-ssl-client-key in order to work. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:pe_enc_ssl_client_cert) do +OctocatalogDiff::Cli::Options::Option.newoption(:pe_enc_ssl_client_cert) do has_weight 353 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_key.rb b/lib/octocatalog-diff/cli/options/pe_enc_ssl_client_key.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_key.rb rename to lib/octocatalog-diff/cli/options/pe_enc_ssl_client_key.rb index ee3a6ba3..a30f9025 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_ssl_client_key.rb +++ b/lib/octocatalog-diff/cli/options/pe_enc_ssl_client_key.rb @@ -4,7 +4,7 @@ # --pe-enc-ssl-client-cert in order to work. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:pe_enc_ssl_client_key) do +OctocatalogDiff::Cli::Options::Option.newoption(:pe_enc_ssl_client_key) do has_weight 354 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token.rb b/lib/octocatalog-diff/cli/options/pe_enc_token.rb similarity index 89% rename from lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token.rb rename to lib/octocatalog-diff/cli/options/pe_enc_token.rb index 8b31d927..90844849 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token.rb +++ b/lib/octocatalog-diff/cli/options/pe_enc_token.rb @@ -6,7 +6,7 @@ # of the token. (Use --pe-enc-token-file to read the content of the token from a file.) # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:pe_enc_token) do +OctocatalogDiff::Cli::Options::Option.newoption(:pe_enc_token) do has_weight 351 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token_file.rb b/lib/octocatalog-diff/cli/options/pe_enc_token_file.rb similarity index 91% rename from lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token_file.rb rename to lib/octocatalog-diff/cli/options/pe_enc_token_file.rb index 967d5300..eeddf3b3 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_token_file.rb +++ b/lib/octocatalog-diff/cli/options/pe_enc_token_file.rb @@ -6,7 +6,7 @@ # in a file, to read the content of the token from the file. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:pe_enc_token_file) do +OctocatalogDiff::Cli::Options::Option.newoption(:pe_enc_token_file) do has_weight 351 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_url.rb b/lib/octocatalog-diff/cli/options/pe_enc_url.rb similarity index 91% rename from lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_url.rb rename to lib/octocatalog-diff/cli/options/pe_enc_url.rb index 37198f29..5330fdbc 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/pe_enc_url.rb +++ b/lib/octocatalog-diff/cli/options/pe_enc_url.rb @@ -8,7 +8,7 @@ # https://your-pe-console-server:4433/classifier-api # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:pe_enc_url) do +OctocatalogDiff::Cli::Options::Option.newoption(:pe_enc_url) do has_weight 350 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/preserve_environments.rb b/lib/octocatalog-diff/cli/options/preserve_environments.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/preserve_environments.rb rename to lib/octocatalog-diff/cli/options/preserve_environments.rb index 1f714f99..6a15a2e3 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/preserve_environments.rb +++ b/lib/octocatalog-diff/cli/options/preserve_environments.rb @@ -5,7 +5,7 @@ # to work correctly. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:preserve_environments) do +OctocatalogDiff::Cli::Options::Option.newoption(:preserve_environments) do has_weight 501 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_binary.rb b/lib/octocatalog-diff/cli/options/puppet_binary.rb similarity index 74% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppet_binary.rb rename to lib/octocatalog-diff/cli/options/puppet_binary.rb index 5fae1100..f3b1398c 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_binary.rb +++ b/lib/octocatalog-diff/cli/options/puppet_binary.rb @@ -3,11 +3,11 @@ # Set --puppet-binary, --to-puppet-binary, --from-puppet-binary # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppet_binary) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppet_binary) do has_weight 300 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'puppet-binary', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master.rb b/lib/octocatalog-diff/cli/options/puppet_master.rb similarity index 75% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppet_master.rb rename to lib/octocatalog-diff/cli/options/puppet_master.rb index 4f1f959f..ce48b6d0 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master.rb +++ b/lib/octocatalog-diff/cli/options/puppet_master.rb @@ -3,11 +3,11 @@ # Specify the hostname, or hostname:port, for the Puppet Master. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppet_master) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppet_master) do has_weight 320 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'puppet-master', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_api_version.rb b/lib/octocatalog-diff/cli/options/puppet_master_api_version.rb similarity index 83% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_api_version.rb rename to lib/octocatalog-diff/cli/options/puppet_master_api_version.rb index b1ab0346..e38cf374 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_api_version.rb +++ b/lib/octocatalog-diff/cli/options/puppet_master_api_version.rb @@ -5,11 +5,11 @@ # specifying API version as 3. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppet_master_api_version) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppet_master_api_version) do has_weight 320 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'puppet-master-api-version', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_ca.rb b/lib/octocatalog-diff/cli/options/puppet_master_ssl_ca.rb similarity index 82% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_ca.rb rename to lib/octocatalog-diff/cli/options/puppet_master_ssl_ca.rb index 247111b6..7f6d5b61 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_ca.rb +++ b/lib/octocatalog-diff/cli/options/puppet_master_ssl_ca.rb @@ -5,11 +5,11 @@ # matches the name you are using to connecting. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppet_master_ssl_ca) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppet_master_ssl_ca) do has_weight 320 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'puppet-master-ssl-ca', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_cert.rb b/lib/octocatalog-diff/cli/options/puppet_master_ssl_client_cert.rb similarity index 81% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_cert.rb rename to lib/octocatalog-diff/cli/options/puppet_master_ssl_client_cert.rb index 881a439d..6870c2b8 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_cert.rb +++ b/lib/octocatalog-diff/cli/options/puppet_master_ssl_client_cert.rb @@ -4,11 +4,11 @@ # client certificate keypair to the Puppet Master. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppet_master_ssl_client_cert) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppet_master_ssl_client_cert) do has_weight 320 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'puppet-master-ssl-client-cert', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_key.rb b/lib/octocatalog-diff/cli/options/puppet_master_ssl_client_key.rb similarity index 81% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_key.rb rename to lib/octocatalog-diff/cli/options/puppet_master_ssl_client_key.rb index f4bd0d85..467dbb50 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppet_master_ssl_client_key.rb +++ b/lib/octocatalog-diff/cli/options/puppet_master_ssl_client_key.rb @@ -4,11 +4,11 @@ # client certificate keypair to the Puppet Master. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppet_master_ssl_client_key) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppet_master_ssl_client_key) do has_weight 320 def parse(parser, options) - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch( + OctocatalogDiff::Cli::Options.option_globally_or_per_branch( parser: parser, options: options, cli_name: 'puppet-master-ssl-client-key', diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_api_version.rb b/lib/octocatalog-diff/cli/options/puppetdb_api_version.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_api_version.rb rename to lib/octocatalog-diff/cli/options/puppetdb_api_version.rb index 7550853a..fa8412fe 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_api_version.rb +++ b/lib/octocatalog-diff/cli/options/puppetdb_api_version.rb @@ -2,7 +2,7 @@ # the default. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppetdb_api_version) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_api_version) do has_weight 319 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_ca.rb b/lib/octocatalog-diff/cli/options/puppetdb_ssl_ca.rb similarity index 89% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_ca.rb rename to lib/octocatalog-diff/cli/options/puppetdb_ssl_ca.rb index 2f24614a..ed700dc8 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_ca.rb +++ b/lib/octocatalog-diff/cli/options/puppetdb_ssl_ca.rb @@ -5,7 +5,7 @@ # matches the name you are using to connecting. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_ca) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_ca) do has_weight 310 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_cert.rb b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_cert.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_cert.rb rename to lib/octocatalog-diff/cli/options/puppetdb_ssl_client_cert.rb index 5ac729d1..ad0b26a8 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_cert.rb +++ b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_cert.rb @@ -4,7 +4,7 @@ # --puppetdb-ssl-client-key in order to work. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_cert) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_cert) do has_weight 310 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_key.rb b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_key.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_key.rb rename to lib/octocatalog-diff/cli/options/puppetdb_ssl_client_key.rb index a0ce6324..8282feb0 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_key.rb +++ b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_key.rb @@ -4,7 +4,7 @@ # --puppetdb-ssl-client-cert in order to work. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_key) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_key) do has_weight 310 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password.rb b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_password.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password.rb rename to lib/octocatalog-diff/cli/options/puppetdb_ssl_client_password.rb index 680ab5b5..3d218e25 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password.rb +++ b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_password.rb @@ -5,7 +5,7 @@ # the text of the password won't appear in the process list. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_cert) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_cert) do has_weight 310 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password_file.rb b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_password_file.rb similarity index 86% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password_file.rb rename to lib/octocatalog-diff/cli/options/puppetdb_ssl_client_password_file.rb index 95d90483..9de04a32 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_ssl_client_password_file.rb +++ b/lib/octocatalog-diff/cli/options/puppetdb_ssl_client_password_file.rb @@ -3,7 +3,7 @@ # Specify the password for a PEM or PKCS12 private key, by reading it from a file. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_password_file) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_ssl_client_password_file) do has_weight 310 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_url.rb b/lib/octocatalog-diff/cli/options/puppetdb_url.rb similarity index 90% rename from lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_url.rb rename to lib/octocatalog-diff/cli/options/puppetdb_url.rb index 14551505..d69c9273 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/puppetdb_url.rb +++ b/lib/octocatalog-diff/cli/options/puppetdb_url.rb @@ -5,7 +5,7 @@ # Specify the base URL for PuppetDB. This will generally look like https://puppetdb.yourdomain.com:8081 # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:puppetdb_url) do +OctocatalogDiff::Cli::Options::Option.newoption(:puppetdb_url) do has_weight 310 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/quiet.rb b/lib/octocatalog-diff/cli/options/quiet.rb similarity index 83% rename from lib/octocatalog-diff/catalog-diff/cli/options/quiet.rb rename to lib/octocatalog-diff/cli/options/quiet.rb index f4c33565..e133f02d 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/quiet.rb +++ b/lib/octocatalog-diff/cli/options/quiet.rb @@ -3,7 +3,7 @@ # Quiet option # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:quiet) do +OctocatalogDiff::Cli::Options::Option.newoption(:quiet) do has_weight 120 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/retry_failed_catalog.rb b/lib/octocatalog-diff/cli/options/retry_failed_catalog.rb similarity index 86% rename from lib/octocatalog-diff/catalog-diff/cli/options/retry_failed_catalog.rb rename to lib/octocatalog-diff/cli/options/retry_failed_catalog.rb index 668f0d72..0deeb810 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/retry_failed_catalog.rb +++ b/lib/octocatalog-diff/cli/options/retry_failed_catalog.rb @@ -4,7 +4,7 @@ # a failed catalog multiple times before kicking out an error message. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:retry_failed_catalog) do +OctocatalogDiff::Cli::Options::Option.newoption(:retry_failed_catalog) do has_weight 230 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/safe_to_delete_cached_master_dir.rb b/lib/octocatalog-diff/cli/options/safe_to_delete_cached_master_dir.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/safe_to_delete_cached_master_dir.rb rename to lib/octocatalog-diff/cli/options/safe_to_delete_cached_master_dir.rb index 77d84947..eed644a3 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/safe_to_delete_cached_master_dir.rb +++ b/lib/octocatalog-diff/cli/options/safe_to_delete_cached_master_dir.rb @@ -5,7 +5,7 @@ # cached directory). # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:safe_to_delete_cached_master_dir) do +OctocatalogDiff::Cli::Options::Option.newoption(:safe_to_delete_cached_master_dir) do has_weight 160 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/storeconfigs.rb b/lib/octocatalog-diff/cli/options/storeconfigs.rb similarity index 85% rename from lib/octocatalog-diff/catalog-diff/cli/options/storeconfigs.rb rename to lib/octocatalog-diff/cli/options/storeconfigs.rb index f009f804..52fecb1c 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/storeconfigs.rb +++ b/lib/octocatalog-diff/cli/options/storeconfigs.rb @@ -3,7 +3,7 @@ # Set storeconfigs (integration with PuppetDB for collected resources) # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:storeconfigs) do +OctocatalogDiff::Cli::Options::Option.newoption(:storeconfigs) do has_weight 220 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/suppress_absent_file_details.rb b/lib/octocatalog-diff/cli/options/suppress_absent_file_details.rb similarity index 87% rename from lib/octocatalog-diff/catalog-diff/cli/options/suppress_absent_file_details.rb rename to lib/octocatalog-diff/cli/options/suppress_absent_file_details.rb index 583774d5..915bc1db 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/suppress_absent_file_details.rb +++ b/lib/octocatalog-diff/cli/options/suppress_absent_file_details.rb @@ -5,7 +5,7 @@ # include user, group, mode, and content, because a removed file has none of those. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:suppress_absent_file_details) do +OctocatalogDiff::Cli::Options::Option.newoption(:suppress_absent_file_details) do has_weight 600 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/to_from_branch.rb b/lib/octocatalog-diff/cli/options/to_from_branch.rb similarity index 88% rename from lib/octocatalog-diff/catalog-diff/cli/options/to_from_branch.rb rename to lib/octocatalog-diff/cli/options/to_from_branch.rb index 14d759a7..774dd8b4 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/to_from_branch.rb +++ b/lib/octocatalog-diff/cli/options/to_from_branch.rb @@ -4,7 +4,7 @@ # the current contents of the base code directory without any git checkouts. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:to_from_branch) do +OctocatalogDiff::Cli::Options::Option.newoption(:to_from_branch) do has_weight 20 def parse(parser, options) diff --git a/lib/octocatalog-diff/catalog-diff/cli/options/validate_references.rb b/lib/octocatalog-diff/cli/options/validate_references.rb similarity index 91% rename from lib/octocatalog-diff/catalog-diff/cli/options/validate_references.rb rename to lib/octocatalog-diff/cli/options/validate_references.rb index 71ceb1a9..40e59d29 100644 --- a/lib/octocatalog-diff/catalog-diff/cli/options/validate_references.rb +++ b/lib/octocatalog-diff/cli/options/validate_references.rb @@ -5,7 +5,7 @@ # parameters are to be checked. # @param parser [OptionParser object] The OptionParser argument # @param options [Hash] Options hash being constructed; this is modified in this method. -OctocatalogDiff::CatalogDiff::Cli::Options::Option.newoption(:validate_references) do +OctocatalogDiff::Cli::Options::Option.newoption(:validate_references) do has_weight 205 def parse(parser, options) diff --git a/lib/octocatalog-diff/cli/printer.rb b/lib/octocatalog-diff/cli/printer.rb new file mode 100644 index 00000000..17e55f83 --- /dev/null +++ b/lib/octocatalog-diff/cli/printer.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require_relative '../catalog-diff/display' +require_relative '../errors' + +module OctocatalogDiff + class Cli + # Wrapper around OctocatalogDiff::CatalogDiff::Display to set the options and + # output to a file or the screen depending on selection. + class Printer + # Constructor + # @param options [Hash] Options from cli/options + # @param logger [Logger] Logger object + def initialize(options, logger) + @options = options + @logger = logger + end + + # The method to call externally, passing in diffs. This takes the appropriate action + # based on options, which is either to write the result into an output file, or print + # the result on STDOUT. Does not return anything. + # @param diffs [OctocatalogDiff::CatalogDiff::Differ] Difference array + # @param from_dir [String] Directory in which "from" catalog was compiled + # @param to_dir [String] Directory in which "to" catalog was compiled + def printer(diffs, from_dir = nil, to_dir = nil) + display_opts = @options.merge(compilation_from_dir: from_dir, compilation_to_dir: to_dir) + diff_text = OctocatalogDiff::CatalogDiff::Display.output(diffs, display_opts, @logger) + if @options[:output_file].nil? + puts diff_text unless diff_text.empty? + else + output_to_file(diff_text) + end + end + + private + + # Output to a file, handling errors related to writing files. + # @param diff_in [String|Array] Text to write to file + def output_to_file(diff_in) + diff_text = diff_in.is_a?(Array) ? diff_in.join("\n") : diff_in + File.open(@options[:output_file], 'w') { |f| f.write(diff_text) } + @logger.info "Wrote diff to #{@options[:output_file]}" + rescue Errno::ENOENT, Errno::EACCES, Errno::EISDIR => exc + @logger.error "Cannot write to #{@options[:output_file]}: #{exc}" + raise OctocatalogDiff::Errors::PrinterError, "Cannot write to #{@options[:output_file]}: #{exc}" + end + end + end +end diff --git a/lib/octocatalog-diff/errors.rb b/lib/octocatalog-diff/errors.rb new file mode 100644 index 00000000..228475c3 --- /dev/null +++ b/lib/octocatalog-diff/errors.rb @@ -0,0 +1,33 @@ +# frozen_string_literal: true + +module OctocatalogDiff + # Contains error classes raised by this gem + class Errors + # Error classes for handled configuration file errors + class ConfigurationFileNotFoundError < RuntimeError; end + class ConfigurationFileContentError < RuntimeError; end + + # Error classes for building catalogs + class BootstrapError < RuntimeError; end + class CatalogError < RuntimeError; end + class PuppetVersionError < RuntimeError; end + class ReferenceValidationError < RuntimeError; end + class GitCheckoutError < RuntimeError; end + + # Error classes for retrieving facts + class FactSourceError < RuntimeError; end + class FactRetrievalError < RuntimeError; end + + # Errors for PuppetDB + class PuppetDBNodeNotFoundError < RuntimeError; end + class PuppetDBGenericError < RuntimeError; end + class PuppetDBConnectionError < RuntimeError; end + + # Errors for Puppet Enterprise + class PEClassificationError < RuntimeError; end + + # Miscellanous catalog-diff errors + class DifferError < RuntimeError; end + class PrinterError < RuntimeError; end + end +end diff --git a/lib/octocatalog-diff/facts.rb b/lib/octocatalog-diff/facts.rb index 0bda7eab..dcaded85 100644 --- a/lib/octocatalog-diff/facts.rb +++ b/lib/octocatalog-diff/facts.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative 'errors' require_relative 'facts/json' require_relative 'facts/yaml' require_relative 'facts/puppetdb' @@ -119,9 +120,5 @@ def override(key, value) @facts['values'][key] = value end end - - # Separate classes to handle errors we throw explicitly - class FactSourceError < RuntimeError; end - class FactRetrievalError < RuntimeError; end end end diff --git a/lib/octocatalog-diff/facts/puppetdb.rb b/lib/octocatalog-diff/facts/puppetdb.rb index 206ca8c5..d2638d4f 100644 --- a/lib/octocatalog-diff/facts/puppetdb.rb +++ b/lib/octocatalog-diff/facts/puppetdb.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative '../errors' require_relative '../facts' require_relative '../puppetdb' require 'yaml' @@ -42,21 +43,21 @@ def self.fact_retriever(options = {}, node) result.map { |x| facts[x['name']] = x['value'] } if facts.empty? message = "Unable to retrieve facts for node #{node} from PuppetDB (empty or nil)!" - raise OctocatalogDiff::Facts::FactRetrievalError, message + raise OctocatalogDiff::Errors::FactRetrievalError, message end # Create a structure compatible with YAML fact files. obj_to_return = { 'name' => node, 'values' => {} } facts.each { |k, v| obj_to_return['values'][k.sub(/^::/, '')] = v } break # Not return, to avoid LocalJumpError in Ruby 2.2 - rescue OctocatalogDiff::PuppetDB::ConnectionError => exc - exception_class = OctocatalogDiff::Facts::FactSourceError + rescue OctocatalogDiff::Errors::PuppetDBConnectionError => exc + exception_class = OctocatalogDiff::Errors::FactSourceError exception_message = "Fact retrieval failed (#{exc.class}) (#{exc.message})" - rescue OctocatalogDiff::PuppetDB::NotFoundError => exc - exception_class = OctocatalogDiff::Facts::FactRetrievalError + rescue OctocatalogDiff::Errors::PuppetDBNodeNotFoundError => exc + exception_class = OctocatalogDiff::Errors::FactRetrievalError exception_message = "Node #{node} not found in PuppetDB (#{exc.message})" - rescue OctocatalogDiff::PuppetDB::PuppetDBError => exc - exception_class = OctocatalogDiff::Facts::FactRetrievalError + rescue OctocatalogDiff::Errors::PuppetDBGenericError => exc + exception_class = OctocatalogDiff::Errors::FactRetrievalError exception_message = "Fact retrieval failed for node #{node} from PuppetDB (#{exc.message})" end end diff --git a/lib/octocatalog-diff/puppetdb.rb b/lib/octocatalog-diff/puppetdb.rb index d7afb727..b9c036ac 100644 --- a/lib/octocatalog-diff/puppetdb.rb +++ b/lib/octocatalog-diff/puppetdb.rb @@ -1,5 +1,6 @@ # frozen_string_literal: true +require_relative 'errors' require_relative 'util/httparty' require 'uri' @@ -14,11 +15,6 @@ module OctocatalogDiff # A standard way to connect to PuppetDB from the various scripts in this repository. class PuppetDB - # This class raises errors for certain handled problems - class NotFoundError < RuntimeError; end - class PuppetDBError < RuntimeError; end - class ConnectionError < RuntimeError; end - # Allow connections to be read (used in tests for now) attr_reader :connections @@ -87,7 +83,7 @@ def initialize(options = {}) def get(path) _get(path) rescue Net::OpenTimeout, Errno::ECONNREFUSED => exc - raise ConnectionError, "#{exc.class} connecting to PuppetDB (need VPN on?): #{exc.message}" + raise OctocatalogDiff::Errors::PuppetDBConnectionError, "#{exc.class} connecting to PuppetDB (need VPN on?): #{exc.message}" end private @@ -120,8 +116,8 @@ def _get(path) # Handle all non-200's from PuppetDB unless response[:code] == 200 - raise NotFoundError, "404 - #{response[:error]}" if response[:code] == 404 - raise PuppetDBError, "#{response[:code]} - #{response[:error]}" + raise OctocatalogDiff::Errors::PuppetDBNodeNotFoundError, "404 - #{response[:error]}" if response[:code] == 404 + raise OctocatalogDiff::Errors::PuppetDBGenericError, "#{response[:code]} - #{response[:error]}" end # PuppetDB can return 'Not Found' as a string with a 200 response code @@ -129,7 +125,7 @@ def _get(path) # PuppetDB can also return an error message in a 200; we'll call this a 500 if response.key?(:error) - raise PuppetDBError, "500 - #{response[:error]}" + raise OctocatalogDiff::Errors::PuppetDBGenericError, "500 - #{response[:error]}" end # If we get here without raising an error, it will fall out of the begin/rescue diff --git a/lib/octocatalog-diff/util/catalogs.rb b/lib/octocatalog-diff/util/catalogs.rb new file mode 100644 index 00000000..d77ca4f1 --- /dev/null +++ b/lib/octocatalog-diff/util/catalogs.rb @@ -0,0 +1,242 @@ +# frozen_string_literal: true + +require 'json' +require 'open3' +require 'yaml' +require_relative '../catalog' +require_relative '../errors' +require_relative 'parallel' + +module OctocatalogDiff + module Util + # Helper class to construct catalogs, performing all necessary steps such as + # bootstrapping directories, installing facts, and running puppet. + class Catalogs + # Constructor + # @param options [Hash] Options + # @param logger [Logger] Logger object + def initialize(options, logger) + @options = options + @logger = logger + @catalogs = nil + raise '@logger must not be nil' if @logger.nil? + end + + # Compile catalogs. This handles building both the old and new catalog (in parallel) and returns + # only when both catalogs have been built. + # @return [Hash] { :from => [OctocatalogDiff::Catalog], :to => [OctocatalogDiff::Catalog] } + def catalogs + @catalogs ||= build_catalog_parallelizer + end + + # Handles the "bootstrap then exit" option, which bootstraps directories but + # exits without compiling catalogs. + def bootstrap_then_exit + @logger.debug('Begin bootstrap_then_exit') + OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory_parallelizer(@options, @logger) + @logger.debug('Success bootstrap_then_exit') + @logger.info('Successfully completed --bootstrap-then-exit action') + end + + private + + # Parallelizes bootstrapping of directories and building catalogs. + # @return [Hash] { :from => OctocatalogDiff::Catalog, :to => OctocatalogDiff::Catalog } + def build_catalog_parallelizer + # Construct parallel tasks. The array supplied to OctocatalogDiff::Util::Parallel is the task portion + # of each of the tuples in catalog_tasks. + catalog_tasks = build_catalog_tasks + + # Update any tasks for catalogs that do not need to be compiled. This is the case when --catalog-only + # is specified and only one catalog is to be built. This will change matching catalog tasks to the 'noop' type. + catalog_tasks.map! do |x| + if @options["#{x[0]}_catalog".to_sym] == '-' + x[1].args[:backend] = :noop + elsif @options["#{x[0]}_catalog".to_sym].is_a?(String) + x[1].args[:json] = File.read(@options["#{x[0]}_catalog".to_sym]) + x[1].args[:backend] = :json + end + x + end + + # Initialize the objects for each parallel task. Initializing the object is very fast and does not actually + # build the catalog. + result = {} + catalog_tasks.each do |x| + result[x[0]] = OctocatalogDiff::Catalog.new(x[1].args) + @logger.debug "Initialized #{result[x[0]].builder} for #{x[0]}-catalog" + end + + # Disable --compare-file-text if either (or both) of the chosen backends do not support it + if @options.fetch(:compare_file_text, false) + result.each do |_key, val| + next unless val.convert_file_resources == false + @logger.debug "Disabling --compare-file-text; not supported by #{val.builder}" + @options[:compare_file_text] = false + catalog_tasks.map! do |x| + x[1].args[:compare_file_text] = false + x + end + break + end + end + + # Inject the starting object into the catalog tasks + catalog_tasks.map! do |x| + x[1].args[:object] = result[x[0]] + x + end + + # Execute the parallelized catalog builds + passed_catalog_tasks = catalog_tasks.map { |x| x[1] } + parallel_catalogs = OctocatalogDiff::Util::Parallel.run_tasks(passed_catalog_tasks, @logger, @options[:parallel]) + + # If the catalogs array is empty at this point, there is an unexpected size mismatch. This should + # never happen, but test for it anyway. + unless parallel_catalogs.size == catalog_tasks.size + # :nocov: + raise "BUG: mismatch catalog_result (#{parallel_catalogs.size} vs #{catalog_tasks.size})" + # :nocov: + end + + # Construct result hash. Will eventually be in the format + # { :from => OctocatalogDiff::Catalog, :to => OctocatalogDiff::Catalog } + + # Analyze the results from parallel run. + catalog_tasks.each do |x| + # The `parallel_catalog_obj` is a OctocatalogDiff::Util::Parallel::Result. Get the first element from + # the parallel_catalogs output. + parallel_catalog_obj = parallel_catalogs.shift + + # Add the result to the 'result' hash + add_parallel_result(result, parallel_catalog_obj, x) + end + + # Things have succeeded if the :to and :from catalogs exist at this point. If not, things have + # failed, and an exception should be thrown. + return result if result.key?(:to) && result.key?(:from) + + # This is believed to be a bug condition. + # :nocov: + raise OctocatalogDiff::Errors::CatalogError, 'One or more catalogs failed to compile.' + # :nocov: + end + + # Get catalog compilation tasks. + # @return [Array<[key, task]>] Catalog tasks + def build_catalog_tasks + [:from, :to].map do |key| + # These are arguments to OctocatalogDiff::Util::Parallel::Task. In most cases the arguments + # of OctocatalogDiff::Util::Parallel::Task are taken directly from options, but there are + # some defaults or otherwise-named options that must be set here. + args = @options.merge( + tag: key.to_s, + branch: @options["#{key}_env".to_sym] || '-', + bootstrapped_dir: @options["bootstrapped_#{key}_dir".to_sym], + basedir: @options[:basedir], + compare_file_text: @options.fetch(:compare_file_text, true), + retry_failed_catalog: @options.fetch(:retry_failed_catalog, 0), + parser: @options["parser_#{key}".to_sym] + ) + + # If any options are in the form of 'to_SOMETHING' or 'from_SOMETHING', this sets the option to + # 'SOMETHING' for the catalog if it matches this key. For example, when compiling the 'to' catalog + # when an option of :to_some_arg => 'foo', this sets :some_arg => foo, and deletes :to_some_arg and + # :from_some_arg. + @options.keys.select { |x| x.to_s =~ /^(to|from)_/ }.each do |opt_key| + args[opt_key.to_s.sub(/^(to|from)_/, '').to_sym] = @options[opt_key] if opt_key.to_s.start_with?(key.to_s) + args.delete(opt_key) + end + + # The task is a OctocatalogDiff::Util::Parallel::Task object that contains the method to execute, + # validator method, text description, and arguments to provide when calling the method. + task = OctocatalogDiff::Util::Parallel::Task.new( + method: method(:build_catalog), + validator: method(:catalog_validator), + validator_args: { task: key }, + description: "build_catalog for #{@options["#{key}_env".to_sym]}", + args: args + ) + + # The format of `catalog_tasks` will be a tuple, where the first element is the key + # (e.g. :to or :from) and the second element is the OctocatalogDiff::Util::Parallel::Task object. + [key, task] + end.compact + end + + # Given a result from the 'parallel' run and a corresponding (key,task) tuple, add valid + # catalogs to the 'result' hash and throw errors for invalid catalogs. + # @param result [Hash] Result hash for build_catalog_parallelizer (may be modified) + # @param parallel_catalog_obj [OctocatalogDiff::Util::Parallel::Result] Parallel catalog result + # @param key_task_tuple [Array] Key, task tuple + def add_parallel_result(result, parallel_catalog_obj, key_task_tuple) + # Expand the tuple into variables + key, task = key_task_tuple + + # For reporting purposes, get the branch name. + branch = task.args[:branch] + + # Check the result of the parallel run on this object. + if parallel_catalog_obj.status.nil? + # The compile was killed because another task failed. + @logger.warn "Catalog compile for #{branch} was aborted due to another failure" + + elsif parallel_catalog_obj.output.is_a?(OctocatalogDiff::Catalog) + # The result is a catalog, but we do not know if it was successfully compiled + # until we test the validity. + catalog = parallel_catalog_obj.output + if catalog.valid? + # The catalog was successfully compiled. + result[key] = parallel_catalog_obj.output + else + # The catalog failed, but a catalog object was returned so that better error reporting + # can take place. In this error reporting, we will replace 'Error:' with '[Puppet Error]' + # and remove the compilation directory (which is a tmpdir) to reveal only the relative + # path to the files involved. + dir = catalog.compilation_dir || '' + dir_regex = Regexp.new(Regexp.escape(dir) + '/environments/[^/]+/') + error_display = catalog.error_message.split("\n").map do |line| + line.sub(/^Error:/, '[Puppet Error]').gsub(dir_regex, '') + end.join("\n") + message = "Catalog for #{branch} failed to compile due to errors:\n#{error_display}" + raise OctocatalogDiff::Errors::CatalogError, message + end + else + # Something unhandled went wrong, and an exception was thrown. Reveal a generic message. + msg = parallel_catalog_obj.exception.message + message = "Catalog for '#{key}' (#{branch}) failed to compile with #{parallel_catalog_obj.exception.class}: #{msg}" + message += "\n" + parallel_catalog_obj.exception.backtrace.map { |x| " #{x}" }.join("\n") if @options[:debug] + raise OctocatalogDiff::Errors::CatalogError, message + end + end + + # Performs the steps necessary to build a catalog. + # @param opts [Hash] Options hash + # @return [Hash] { :rc => exit code, :catalog => Catalog as JSON string } + def build_catalog(opts, logger = @logger) + logger.debug("Setting up Puppet catalog build for #{opts[:branch]}") + catalog = opts[:object] + logger.debug("Catalog for #{opts[:branch]} will be built with #{catalog.builder}") + time_start = Time.now + catalog.build(logger) + time_it_took = Time.now - time_start + retries_str = " retries = #{catalog.retries}" if catalog.retries.is_a?(Fixnum) + time_str = "in #{time_it_took} seconds#{retries_str}" + status_str = catalog.valid? ? 'successfully built' : 'failed' + logger.debug "Catalog for #{opts[:branch]} #{status_str} with #{catalog.builder} #{time_str}" + catalog + end + + # Validate a catalog in the parallel execution + # @param catalog [OctocatalogDiff::Catalog] Catalog object + # @param logger [Logger] Logger object (presently unused) + # @param args [Hash] Additional arguments set specifically for validator + # @return [Boolean] true if catalog is valid, false otherwise + def catalog_validator(catalog = nil, _logger = @logger, args = {}) + return false unless catalog.is_a?(OctocatalogDiff::Catalog) + catalog.validate_references if args[:task] == :to + catalog.valid? + end + end + end +end diff --git a/rake/doc.rb b/rake/doc.rb index 9f2440c0..d6df649c 100644 --- a/rake/doc.rb +++ b/rake/doc.rb @@ -2,7 +2,7 @@ require 'optparse' require 'rugged' -require_relative '../lib/octocatalog-diff/catalog-diff/cli/options' +require_relative '../lib/octocatalog-diff/cli/options' require_relative '../lib/octocatalog-diff/version' module OctocatalogDiff @@ -15,7 +15,7 @@ class Doc DOC_TEMPLATE = File.expand_path('./templates/optionsref.erb', File.dirname(__FILE__)) DOC_NAME = 'doc/optionsref.md'.freeze DOC_OUTPUT = File.expand_path("../#{DOC_NAME}", File.dirname(__FILE__)) - CODE_PATH = File.expand_path('../lib/octocatalog-diff/catalog-diff/cli/options', File.dirname(__FILE__)) + CODE_PATH = File.expand_path('../lib/octocatalog-diff/cli/options', File.dirname(__FILE__)) def file_content(filename) @fc ||= {} @@ -35,10 +35,10 @@ def file_content(filename) end def initialize - OctocatalogDiff::CatalogDiff::Cli::Options.classes.clear + OctocatalogDiff::Cli::Options.classes.clear options = {} @obj = ::OptionParser.new do |parser| - OctocatalogDiff::CatalogDiff::Cli::Options.option_classes.each do |klass| + OctocatalogDiff::Cli::Options.option_classes.each do |klass| obj = klass.new obj.parse(parser, options) end diff --git a/rake/templates/optionsref.erb b/rake/templates/optionsref.erb index b19ac0da..a5c2fe40 100644 --- a/rake/templates/optionsref.erb +++ b/rake/templates/optionsref.erb @@ -34,3 +34,11 @@ Usage: octocatalog-diff [command line options] <% end %> + +## Using these options in API calls + +Most of these options can also be used when making calls to the [API](/doc/dev/api.md). + +Generally, parameters for the API are named corresponding to the names of the command line parameters, with dashes (`-`) converted to underscores (`_`). For example, the command line option `--hiera-config` is passed to the API as the symbol `:hiera_config`. + +Each of the options above has a link to the source file where it is declared, should you wish to review the specific parameter names and data structures that are being set. diff --git a/spec/octocatalog-diff/fixtures/cli-configs/invalid.rb b/spec/octocatalog-diff/fixtures/cli-configs/invalid.rb new file mode 100644 index 00000000..f2379fc5 --- /dev/null +++ b/spec/octocatalog-diff/fixtures/cli-configs/invalid.rb @@ -0,0 +1,9 @@ +# This is a configuration file for octocatalog-diff + +module OctocatalogDiff + class Config + def self.config + raise 'Fizz Buzz' + end + end +end diff --git a/spec/octocatalog-diff/fixtures/cli-configs/not-class.rb b/spec/octocatalog-diff/fixtures/cli-configs/not-class.rb new file mode 100644 index 00000000..9167fd8f --- /dev/null +++ b/spec/octocatalog-diff/fixtures/cli-configs/not-class.rb @@ -0,0 +1,9 @@ +# This is a configuration file for octocatalog-diff + +module OctocatalogDiff + class ConfigFooBar + def self.config + raise 'Fizz Buzz' + end + end +end diff --git a/spec/octocatalog-diff/fixtures/cli-configs/not-hash.rb b/spec/octocatalog-diff/fixtures/cli-configs/not-hash.rb new file mode 100644 index 00000000..701be83c --- /dev/null +++ b/spec/octocatalog-diff/fixtures/cli-configs/not-hash.rb @@ -0,0 +1,9 @@ +# This is a configuration file for octocatalog-diff + +module OctocatalogDiff + class Config + def self.config + %w(apple banana) + end + end +end diff --git a/spec/octocatalog-diff/fixtures/cli-configs/not-proper.rb b/spec/octocatalog-diff/fixtures/cli-configs/not-proper.rb new file mode 100644 index 00000000..cc53d262 --- /dev/null +++ b/spec/octocatalog-diff/fixtures/cli-configs/not-proper.rb @@ -0,0 +1,13 @@ +# This is a configuration file for octocatalog-diff + +module OctocatalogDiff + class Config + def self.foobuzz + { + header: :default, + hiera_config: 'config/hiera.yaml', + hiera_path: 'hieradata' + } + end + end +end diff --git a/spec/octocatalog-diff/fixtures/cli-configs/not-ruby.rb b/spec/octocatalog-diff/fixtures/cli-configs/not-ruby.rb new file mode 100644 index 00000000..a5536213 --- /dev/null +++ b/spec/octocatalog-diff/fixtures/cli-configs/not-ruby.rb @@ -0,0 +1,3 @@ +Ruby is not here. +It should fail to compile. +And raise an error. diff --git a/spec/octocatalog-diff/fixtures/cli-configs/valid.rb b/spec/octocatalog-diff/fixtures/cli-configs/valid.rb new file mode 100755 index 00000000..a0dc9cc3 --- /dev/null +++ b/spec/octocatalog-diff/fixtures/cli-configs/valid.rb @@ -0,0 +1,13 @@ +# This is a configuration file for octocatalog-diff + +module OctocatalogDiff + class Config + def self.config + { + header: :default, + hiera_config: 'config/hiera.yaml', + hiera_path: 'hieradata' + } + end + end +end diff --git a/spec/octocatalog-diff/integration/api_catalog_compile_spec.rb b/spec/octocatalog-diff/integration/api_catalog_compile_spec.rb new file mode 100644 index 00000000..d5e0e198 --- /dev/null +++ b/spec/octocatalog-diff/integration/api_catalog_compile_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require_relative '../tests/spec_helper' + +require OctocatalogDiff::Spec.require_path('api/v1') +require OctocatalogDiff::Spec.require_path('util/catalogs') + +describe OctocatalogDiff::API::V1 do + context 'with correct command line arguments and working catalog' do + before(:all) do + logger, @logger_str = OctocatalogDiff::Spec.setup_logger + options = { + logger: logger, + node: 'rspec-node.github.net', + bootstrapped_to_dir: OctocatalogDiff::Spec.fixture_path('repos/default'), + fact_file: OctocatalogDiff::Spec.fixture_path('facts/facts.yaml'), + puppet_binary: OctocatalogDiff::Spec::PUPPET_BINARY, + hiera_config: 'config/hiera.yaml', + hiera_path_strip: '/var/lib/puppet', + to_env: 'master' + } + @result = described_class.catalog(options) + end + + it 'should return a catalog object' do + expect(@result).to be_a_kind_of(OctocatalogDiff::API::V1::Catalog) + expect(@result.raw).to be_a_kind_of(OctocatalogDiff::Catalog) + end + + it 'should be a valid catalog' do + expect(@result.valid?).to eq(true) + end + + it 'should contain an expected resource' do + expect(@result.resource(type: 'Ssh_authorized_key', title: 'bob@local')).to be_a_kind_of(Hash) + end + + it 'should log to the logger' do + expect(@logger_str.string).to match(/Compiling catalog for rspec-node.github.net/) + expect(@logger_str.string).to match(/Initialized OctocatalogDiff::Catalog::Noop for from-catalog/) + expect(@logger_str.string).to match(/Initialized OctocatalogDiff::Catalog::Computed for to-catalog/) + expect(@logger_str.string).to match(/Catalog for master will be built with OctocatalogDiff::Catalog::Computed/) + expect(@logger_str.string).to match(/Calling build for object OctocatalogDiff::Catalog::Computed/) + expect(@logger_str.string).to match(/Catalog for master successfully built with OctocatalogDiff::Catalog::Computed/) + end + end + + context 'with correct command line arguments and failing catalog' do + it 'should raise CatalogError' do + options = { + node: 'rspec-node.github.net', + bootstrapped_to_dir: OctocatalogDiff::Spec.fixture_path('repos/default'), + fact_file: OctocatalogDiff::Spec.fixture_path('facts/facts.yaml'), + puppet_binary: OctocatalogDiff::Spec::PUPPET_BINARY, + to_env: 'master' + } + expect do + described_class.catalog(options) + end.to raise_error(OctocatalogDiff::Errors::CatalogError) + end + end + + context 'with incorrect command line arguments' do + it 'should raise ArgumentError if called without an options hash' do + expect do + described_class.catalog + end.to raise_error(ArgumentError, 'Usage: #catalog(options_hash)') + end + + it 'should raise ArgumentError if node is not a string' do + expect do + described_class.catalog(node: {}) + end.to raise_error(ArgumentError, 'Node name must be passed to OctocatalogDiff::Catalog::Computed') + end + end +end diff --git a/spec/octocatalog-diff/integration/arbitrary_command_line_spec.rb b/spec/octocatalog-diff/integration/arbitrary_command_line_spec.rb index d9ea4964..de7af8b5 100644 --- a/spec/octocatalog-diff/integration/arbitrary_command_line_spec.rb +++ b/spec/octocatalog-diff/integration/arbitrary_command_line_spec.rb @@ -24,31 +24,23 @@ end it 'should contain resource from environments/foo site.pp' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-site"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain resource from environments/foo modules/foo' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-module"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-module' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should not contain resource from environments/production' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-production-site"] - )).to eq(false) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-production-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(false) end it 'should not contain resource from main modules/foo' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/foo-module"] - )).to eq(false) + resource = { diff_type: '+', type: 'File', title: '/tmp/foo-module' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(false) end end @@ -71,24 +63,18 @@ end it 'should contain resource from environments/foo site.pp only in to catalog' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-site"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain resource from environments/foo modules/foo only in to catalog' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-module"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-module' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain resource from environments/production only in from catalog' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['-', "File\f/tmp/environment-production-site"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-production-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(false) end end @@ -112,31 +98,23 @@ end it 'should contain resource from environments/foo site.pp' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-site"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain resource from environments/foo modules/foo' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-module"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-module' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should not contain resource from environments/production' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-production-site"] - )).to eq(false) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-production-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(false) end it 'should not contain resource from main modules/foo' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/foo-module"] - )).to eq(false) + resource = { diff_type: '+', type: 'File', title: '/tmp/foo-module' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(false) end end @@ -160,31 +138,23 @@ end it 'should contain resource from environments/foo site.pp' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-site"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should not contain resource from environments/foo modules/foo' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-foo-module"] - )).to eq(false) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-foo-module' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(false) end it 'should not contain resource from environments/production' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/environment-production-site"] - )).to eq(false) + resource = { diff_type: '+', type: 'File', title: '/tmp/environment-production-site' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(false) end it 'should contain resource from main modules/foo' do - expect(OctocatalogDiff::Spec.array_contains_partial_array?( - @result.diffs, - ['+', "File\f/tmp/foo-module"] - )).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/foo-module' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end end end diff --git a/spec/octocatalog-diff/integration/bootstrap_script_spec.rb b/spec/octocatalog-diff/integration/bootstrap_script_spec.rb index 66651b4f..4f455f64 100644 --- a/spec/octocatalog-diff/integration/bootstrap_script_spec.rb +++ b/spec/octocatalog-diff/integration/bootstrap_script_spec.rb @@ -53,7 +53,7 @@ it 'should print error from bootstrap failing' do expect(@result[:exception].message).to match(/Catalog for 'to' \(.\) failed to compile with.+::BootstrapError/) - expect(@result[:exception].message).to match(/OctocatalogDiff::CatalogUtil::Bootstrap::BootstrapError/) + expect(@result[:exception].message).to match(/OctocatalogDiff::Errors::BootstrapError/) expect(@result[:exception].message).not_to match(/Could not find class (::)?test/) end @@ -92,18 +92,8 @@ end it 'should contain the added resource' do - answer = [ - '+', - "File\f/tmp/foo", - { - 'type' => 'File', - 'title' => '/tmp/foo', - 'tags' => %w(class file test), - 'exported' => false, - 'parameters' => { 'content' => "Test 123\n" } - } - ] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/foo' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should print debugging output from bootstrap script' do @@ -139,18 +129,8 @@ end it 'should contain the added resource' do - answer = [ - '+', - "File\f/tmp/foo", - { - 'type' => 'File', - 'title' => '/tmp/foo', - 'tags' => %w(class file test), - 'exported' => false, - 'parameters' => { 'content' => "Test 123\n" } - } - ] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { diff_type: '+', type: 'File', title: '/tmp/foo' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should not print debugging output from bootstrap script' do diff --git a/spec/octocatalog-diff/integration/catalog_compute_spec.rb b/spec/octocatalog-diff/integration/catalog_compute_spec.rb index 3ecd7cef..d0b82383 100644 --- a/spec/octocatalog-diff/integration/catalog_compute_spec.rb +++ b/spec/octocatalog-diff/integration/catalog_compute_spec.rb @@ -2,7 +2,7 @@ require_relative 'integration_helper' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/catalogs') +require OctocatalogDiff::Spec.require_path('/util/catalogs') require OctocatalogDiff::Spec.require_path('/catalog') require OctocatalogDiff::Spec.require_path('/facts') @@ -48,7 +48,7 @@ if @has_git && @has_tar && @has_bash options = @default_options.merge(enc: 'environments/production/config/enc.sh') logger, _logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = testobj.catalogs @to = result[:to] @from = result[:from] @@ -111,7 +111,7 @@ if @has_git && @has_tar options = @default_options.dup logger, _logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = testobj.catalogs @to = result[:to] @from = result[:from] @@ -175,7 +175,7 @@ options = @default_options.merge(hiera_config: 'environments/production/config/hiera.yaml', hiera_path_strip: '/var/lib/puppet') logger, _logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = testobj.catalogs @to = result[:to] @from = result[:from] @@ -257,7 +257,7 @@ to_env: '.' ) logger, _logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = testobj.catalogs @to = result[:to] @from = result[:from] diff --git a/spec/octocatalog-diff/integration/catalog_only_spec.rb b/spec/octocatalog-diff/integration/catalog_only_spec.rb index fecda1c5..0f416008 100644 --- a/spec/octocatalog-diff/integration/catalog_only_spec.rb +++ b/spec/octocatalog-diff/integration/catalog_only_spec.rb @@ -32,21 +32,21 @@ it 'should set the from-catalog to a no-op catalog type' do pending 'catalog compilation failed' unless @result[:exitcode] == 2 from_catalog = @result[:diffs][0] - expect(from_catalog).to be_a_kind_of(OctocatalogDiff::Catalog) + expect(from_catalog).to be_a_kind_of(OctocatalogDiff::API::V1::Catalog) expect(from_catalog.builder).to eq('OctocatalogDiff::Catalog::Noop') end it 'should set the to-catalog to a computed catalog type' do pending 'catalog compilation failed' unless @result[:exitcode] == 2 to_catalog = @result[:diffs][1] - expect(to_catalog).to be_a_kind_of(OctocatalogDiff::Catalog) + expect(to_catalog).to be_a_kind_of(OctocatalogDiff::API::V1::Catalog) expect(to_catalog.builder).to eq('OctocatalogDiff::Catalog::Computed') end it 'should have log messages indicating catalog compilations' do pending 'catalog compilation failed' unless @result[:exitcode] == 2 logs = @result[:logs] - expect(logs).to match(/Compiling catalog --catalog-only for rspec-node.github.net/) + expect(logs).to match(/Compiling catalog for rspec-node.github.net/) expect(logs).to match(/Initialized OctocatalogDiff::Catalog::Noop for from-catalog/) expect(logs).to match(/Initialized OctocatalogDiff::Catalog::Computed for to-catalog/) end @@ -55,8 +55,8 @@ pending 'catalog compilation failed' unless @result[:exitcode] == 2 to_catalog = @result[:diffs][1] expect(to_catalog.valid?).to eq(true) - expect(to_catalog.catalog).to be_a_kind_of(Hash) - expect(to_catalog.catalog_json).to be_a_kind_of(String) + expect(to_catalog.to_h).to be_a_kind_of(Hash) + expect(to_catalog.to_json).to be_a_kind_of(String) expect(to_catalog.error_message).to be(nil) end diff --git a/spec/octocatalog-diff/integration/cli_spec.rb b/spec/octocatalog-diff/integration/cli_spec.rb new file mode 100644 index 00000000..b40f439a --- /dev/null +++ b/spec/octocatalog-diff/integration/cli_spec.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +require_relative '../tests/spec_helper' + +require 'open3' +require 'shellwords' + +describe 'bin/octocatalog-diff' do + let(:script) { File.expand_path('../../../bin/octocatalog-diff', File.dirname(__FILE__)) } + let(:ls_l) { Open3.capture2e("ls -l #{script}").first } + let(:config_test) { '--config-test' } + let(:normal_settings) do + [ + '-d', + '-n rspec-node.github.net', + '--fact-file', OctocatalogDiff::Spec.fixture_path('facts/facts.yaml'), + '--from-catalog', OctocatalogDiff::Spec.fixture_path('catalogs/tiny-catalog.json'), + '--bootstrapped-to-dir', OctocatalogDiff::Spec.fixture_path('repos/default'), + '--puppet-binary', OctocatalogDiff::Spec::PUPPET_BINARY + ].map { |x| Shellwords.escape(x) }.join(' ') + end + + it 'should exist' do + expect(File.file?(script)).to eq(true), ls_l + end + + it 'should be executable' do + expect(File.executable?(script)).to eq(true), ls_l + end + + context 'with an invalid configuration file' do + let(:cfg) { OctocatalogDiff::Spec.fixture_path('cli-configs/invalid.rb') } + let(:env) { { 'OCTOCATALOG_DIFF_CONFIG_FILE' => cfg } } + + it 'should error with --config-test' do + text, status = Open3.capture2e(env, "#{script} #{config_test}") + expect(status.exitstatus).to eq(1), text + expect(text).to match(%r{Loading octocatalog-diff configuration from .+/fixtures/cli-configs/invalid.rb}) + expect(text).to match(/FATAL .+: Fizz Buzz/) + end + + it 'should error with normal settings' do + text, status = Open3.capture2e(env, "#{script} #{normal_settings}") + expect(status.exitstatus).to eq(1), text + expect(text).to match(%r{Loading octocatalog-diff configuration from .+/fixtures/cli-configs/invalid.rb}) + expect(text).to match(/FATAL .+: Fizz Buzz/) + end + end + + context 'with a valid configuration file' do + let(:cfg) { OctocatalogDiff::Spec.fixture_path('cli-configs/valid.rb') } + let(:env) { { 'OCTOCATALOG_DIFF_CONFIG_FILE' => cfg } } + + it 'should print values with --config-test and exit' do + text, status = Open3.capture2e(env, "#{script} #{config_test}") + expect(status.exitstatus).to eq(0), text + expect(text).to match(%r{Loading octocatalog-diff configuration from .+/fixtures/cli-configs/valid.rb}) + expect(text).to match(/:header => \(Symbol\) :default/) + expect(text).to match(%r{:hiera_config => \(String\) "config/hiera.yaml"}) + expect(text).to match(/:hiera_path => \(String\) "hieradata"/) + expect(text).to match(/Exiting now because --config-test was specified/) + end + + it 'should print settings details and then invoke the main CLI' do + text, status = Open3.capture2e(env, "#{script} #{normal_settings}") + expect(status.exitstatus).to eq(2), text + expect(text).to match(%r{Loading octocatalog-diff configuration from .+/fixtures/cli-configs/valid.rb}) + expect(text).to match(%r{Loaded 3 settings from .+/fixtures/cli-configs/valid.rb}) + expect(text).to match(/Initialized OctocatalogDiff::Catalog::Computed for to-catalog/) + expect(text).to match(/Entering catdiff; catalog sizes: 2, 21/) + expect(text).to match(/Entering filter_diffs_for_absent_files with 14 diffs/) + expect(text).to match(/Added resources: 14/) + expect(text).to match(/\+ Ssh_authorized_key\[root@6def27049c06f48eea8b8f37329f40799d07dc84\]/) + end + end +end diff --git a/spec/octocatalog-diff/integration/convert_file_resources_spec.rb b/spec/octocatalog-diff/integration/convert_file_resources_spec.rb index 3719bcc1..f288945d 100644 --- a/spec/octocatalog-diff/integration/convert_file_resources_spec.rb +++ b/spec/octocatalog-diff/integration/convert_file_resources_spec.rb @@ -27,23 +27,39 @@ end it 'should contain /tmp/foo1' do - answer = ['~', "File\f/tmp/foo1\fparameters\fcontent", "content of foo-old\n", "content of foo-new\n"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/foo1', + structure: %w(parameters content), + old_value: "content of foo-old\n", + new_value: "content of foo-new\n" + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain /tmp/binary1' do - answer = [ - '~', - "File\f/tmp/binary1\fparameters\fcontent", - '{md5}e0897d525d5d600a037622b62fc99a4c', - '{md5}97918b387001eb04ae7cb20b13e07f43' - ] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/binary1', + structure: %w(parameters content), + old_value: '{md5}e0897d525d5d600a037622b62fc99a4c', + new_value: '{md5}97918b387001eb04ae7cb20b13e07f43' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain /tmp/bar2' do - answer = ['~', "File\f/tmp/bar2\fparameters\fcontent", "content of bar\n", "content of new-bar\n"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/bar2', + structure: %w(parameters content), + old_value: "content of bar\n", + new_value: "content of new-bar\n" + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end end @@ -71,38 +87,63 @@ end it 'should contain /tmp/binary1' do - answer = [ - '~', - "File\f/tmp/binary1\fparameters\fsource", - 'puppet:///modules/test/binary-old', - 'puppet:///modules/test/binary-new' - ] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/binary1', + structure: %w(parameters source), + old_value: 'puppet:///modules/test/binary-old', + new_value: 'puppet:///modules/test/binary-new' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain /tmp/binary3' do - answer = [ - '~', - "File\f/tmp/binary3\fparameters\fsource", - 'puppet:///modules/test/binary-old', - 'puppet:///modules/test/binary-old2' - ] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/binary3', + structure: %w(parameters source), + old_value: 'puppet:///modules/test/binary-old', + new_value: 'puppet:///modules/test/binary-old2' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain /tmp/foo1' do - answer = ['~', "File\f/tmp/foo1\fparameters\fsource", 'puppet:///modules/test/foo-old', 'puppet:///modules/test/foo-new'] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/foo1', + structure: %w(parameters source), + old_value: 'puppet:///modules/test/foo-old', + new_value: 'puppet:///modules/test/foo-new' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain /tmp/bar content' do - answer = ['!', "File\f/tmp/bar\fparameters\fcontent", nil, "content of bar\n"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '!', + type: 'File', + title: '/tmp/bar', + structure: %w(parameters content), + old_value: nil, + new_value: "content of bar\n" + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should contain /tmp/bar source' do - answer = ['!', "File\f/tmp/bar\fparameters\fsource", 'puppet:///modules/test/bar-old', nil] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], answer)).to eq(true) + resource = { + diff_type: '!', + type: 'File', + title: '/tmp/bar', + structure: %w(parameters source), + old_value: 'puppet:///modules/test/bar-old', + new_value: nil + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end end @@ -118,7 +159,7 @@ ] ) expect(result[:exitcode]).to eq(-1) - expect(result[:exception]).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(result[:exception]).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(result[:exception].message).to match(/failed to compile with Errno::ENOENT/) expect(result[:exception].message).to match(%r{Unable to resolve 'puppet:///modules/test/foo-new'}) end diff --git a/spec/octocatalog-diff/integration/integration_helper.rb b/spec/octocatalog-diff/integration/integration_helper.rb index a06acad8..7ffc0da4 100644 --- a/spec/octocatalog-diff/integration/integration_helper.rb +++ b/spec/octocatalog-diff/integration/integration_helper.rb @@ -1,5 +1,6 @@ require_relative '../tests/spec_helper' -require OctocatalogDiff::Spec.require_path('catalog-diff/cli') +require OctocatalogDiff::Spec.require_path('/cli') +require OctocatalogDiff::Spec.require_path('/errors') require 'json' require 'ostruct' @@ -109,12 +110,12 @@ def self.integration(options = {}) stdout_strio = StringIO.new $stdout = stdout_strio - # Tell OctocatalogDiff::CatalogDiff::Cli.cli to return the JSON differences and not a numeric exit code + # Tell OctocatalogDiff::Cli.cli to return the JSON differences and not a numeric exit code # for a full catalog-diff. options[:RETURN_DIFFS] = true - # Run the OctocatalogDiff::CatalogDiff::Cli.cli and validate output format. - result = OctocatalogDiff::CatalogDiff::Cli.cli(argv, logger, options) + # Run the OctocatalogDiff::Cli.cli and validate output format. + result = OctocatalogDiff::Cli.cli(argv, logger, options) if result.is_a?(Fixnum) return { logs: logger_string.string, @@ -123,7 +124,7 @@ def self.integration(options = {}) } end - raise "OctocatalogDiff::CatalogDiff::Cli.cli should return array, got #{result.inspect}" unless result.is_a?(Array) + raise "OctocatalogDiff::Cli.cli should return array, got #{result.inspect}" unless result.is_a?(Array) # Return hash OpenStruct.new( diff --git a/spec/octocatalog-diff/integration/modulepath_spec.rb b/spec/octocatalog-diff/integration/modulepath_spec.rb index aa618bcf..0892d3d3 100644 --- a/spec/octocatalog-diff/integration/modulepath_spec.rb +++ b/spec/octocatalog-diff/integration/modulepath_spec.rb @@ -69,19 +69,25 @@ end let(:module_answer) do - ['~', - "File\f/tmp/modulestest\fparameters\fcontent", - "Modules Test\n", - "New content of modulestest\n"] + { + diff_type: '~', + type: 'File', + title: '/tmp/modulestest', + structure: %w(parameters content), + old_value: "Modules Test\n", + new_value: "New content of modulestest\n" + } end let(:site_answer) do - [ - '~', - "File\f/tmp/sitetest\fparameters\fcontent", - "Site Test\n", - "New content of sitetest\n" - ] + { + diff_type: '~', + type: 'File', + title: '/tmp/sitetest', + structure: %w(parameters content), + old_value: "Site Test\n", + new_value: "New content of sitetest\n" + } end context 'with environment.conf' do @@ -102,8 +108,8 @@ expect(@result[:exitcode]).to eq(2), OctocatalogDiff::Integration.format_exception(@result) expect(@result[:diffs]).to be_a_kind_of(Array) expect(@result[:diffs].size).to eq(2) - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], module_answer)).to eq(true) - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], site_answer)).to eq(true) + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], module_answer)).to eq(true) + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], site_answer)).to eq(true) end end @@ -125,8 +131,8 @@ expect(@result[:exitcode]).to eq(2), OctocatalogDiff::Integration.format_exception(@result) expect(@result[:diffs]).to be_a_kind_of(Array) expect(@result[:diffs].size).to eq(2) - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], module_answer)).to eq(true) - expect(OctocatalogDiff::Spec.array_contains_partial_array?(@result[:diffs], site_answer)).to eq(true) + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], module_answer)).to eq(true) + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], site_answer)).to eq(true) end end end diff --git a/spec/octocatalog-diff/integration/pe_enc_spec.rb b/spec/octocatalog-diff/integration/pe_enc_spec.rb index 6da2f6ee..7cc747cc 100644 --- a/spec/octocatalog-diff/integration/pe_enc_spec.rb +++ b/spec/octocatalog-diff/integration/pe_enc_spec.rb @@ -129,7 +129,7 @@ def self.respond(code, message, content_type = nil, body = '') } result = OctocatalogDiff::Integration.integration(opts) expect(result[:exitcode]).to eq(-1) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/OpenSSL::SSL::SSLError/) end @@ -194,7 +194,7 @@ def self.respond(code, message, content_type = nil, body = '') } result = OctocatalogDiff::Integration.integration(opts) expect(result[:exitcode]).to eq(-1) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/Failed ENC: Response from https:.+rspec-node.xyz.github.net was 403/) end @@ -212,7 +212,7 @@ def self.respond(code, message, content_type = nil, body = '') } result = OctocatalogDiff::Integration.integration(opts) expect(result[:exitcode]).to eq(-1) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/Failed ENC: Response from https:.+rspec-node.xyz.github.net was 403/) end diff --git a/spec/octocatalog-diff/integration/preserve_environments_spec.rb b/spec/octocatalog-diff/integration/preserve_environments_spec.rb index 86c692fc..38ebc106 100644 --- a/spec/octocatalog-diff/integration/preserve_environments_spec.rb +++ b/spec/octocatalog-diff/integration/preserve_environments_spec.rb @@ -2,7 +2,7 @@ require_relative 'integration_helper' -OctocatalogDiff::Spec.require_path('/catalog-diff/cli/catalogs') +OctocatalogDiff::Spec.require_path('/util/catalogs') describe 'preserve environments integration' do context 'without --preserve-environments set' do @@ -22,8 +22,8 @@ expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) end - it 'should raise OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + it 'should raise OctocatalogDiff::Errors::CatalogError' do + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) end it 'should fail because ::bar could not be located' do @@ -98,7 +98,7 @@ it 'should exit with error status due modules in production environment not being found' do expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(@result.exception.message).to match(/Errno::ENOENT: No such file or directory - Environment directory/) end end @@ -121,7 +121,7 @@ it 'should error on missing environment' do expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(@result.exception.message).to match(%r{Environment directory .+/environments/fluffy does not exist}) end end @@ -151,35 +151,45 @@ end it 'should display proper diffs' do - diffs = @result.diffs - - expect( - OctocatalogDiff::Spec.array_contains_partial_array?( - diffs, - ['~', "File\f/tmp/bar\fparameters\fcontent", 'one', 'two'] - ) - ).to eq(true) - - expect( - OctocatalogDiff::Spec.array_contains_partial_array?( - diffs, - ['~', "File\f/tmp/bar\fparameters\fowner", 'one', 'two'] - ) - ).to eq(true) - - expect( - OctocatalogDiff::Spec.array_contains_partial_array?( - diffs, - ['~', "File\f/tmp/foo\fparameters\fcontent", 'one', 'two'] - ) - ).to eq(true) - - expect( - OctocatalogDiff::Spec.array_contains_partial_array?( - diffs, - ['~', "File\f/tmp/sitetest\fparameters\fcontent", 'one', 'two'] - ) - ).to eq(true) + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/bar', + structure: %w(parameters content), + old_value: 'one', + new_value: 'two' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) + + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/bar', + structure: %w(parameters owner), + old_value: 'one', + new_value: 'two' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) + + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/foo', + structure: %w(parameters content), + old_value: 'one', + new_value: 'two' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) + + resource = { + diff_type: '~', + type: 'File', + title: '/tmp/sitetest', + structure: %w(parameters content), + old_value: 'one', + new_value: 'two' + } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end it 'should handle hieradata properly' do @@ -208,7 +218,7 @@ it 'should error on missing site directory' do expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(@result.exception.message).to match(/Could not find class (::)?sitetest/) end end @@ -231,7 +241,7 @@ it 'should error on missing module' do expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(@result.exception.message).to match(/Could not find class (::)?foo/) end end @@ -254,7 +264,7 @@ it 'should raise exception due to missing symlink request' do expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(@result.exception.message).to match(%r{Catalog for 'from' \(origin/master\) failed.+ Errno::ENOENT}) expect(@result.exception.message).to match(%r{Specified directory .+/preserve-environments/fluffy doesn't exist}) end @@ -303,7 +313,7 @@ it 'should error on missing site directory' do expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(@result.exception.message).to match(/Could not find class (::)?sitetest/) end end @@ -326,7 +336,7 @@ it 'should error on missing site directory' do expect(@result.exitcode).to eq(-1), OctocatalogDiff::Integration.format_exception(@result) - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::CatalogError) expect(@result.exception.message).to match(/Could not find class (::)?sitetest/) end end diff --git a/spec/octocatalog-diff/integration/puppetdb_spec.rb b/spec/octocatalog-diff/integration/puppetdb_spec.rb index 00f511ad..5e22f550 100644 --- a/spec/octocatalog-diff/integration/puppetdb_spec.rb +++ b/spec/octocatalog-diff/integration/puppetdb_spec.rb @@ -22,7 +22,7 @@ opts = { argv: ['-n', 'not-found-node.github.net'], spec_repo: 'tiny-repo' } result = OctocatalogDiff::Integration.integration_with_puppetdb(s_opts, opts) expect(result[:exitcode]).to eq(-1), OctocatalogDiff::Integration.format_exception(result) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/FactRetrievalError: Node not-found-node.github.net not found in PuppetDB/) end end @@ -53,7 +53,7 @@ opts = { argv: args, spec_repo: 'tiny-repo' } result = OctocatalogDiff::Integration.integration_with_puppetdb(s_opts, opts) expect(result[:exitcode]).to eq(-1), OctocatalogDiff::Integration.format_exception(result) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/OpenSSL::SSL::SSLError/) end @@ -71,7 +71,7 @@ opts = { argv: args, spec_repo: 'tiny-repo' } result = OctocatalogDiff::Integration.integration_with_puppetdb(s_opts, opts) expect(result[:exitcode]).to eq(-1), OctocatalogDiff::Integration.format_exception(result) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/OpenSSL::SSL::SSLError/) end end @@ -88,7 +88,7 @@ it 'should fail to connect to authenticated puppetdb with no client cert', retry: 3 do opts = { argv: ['-n', 'rspec-node.github.net'], spec_repo: 'tiny-repo' } result = OctocatalogDiff::Integration.integration_with_puppetdb(s_opts, opts) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/OpenSSL::SSL::SSLError/) end @@ -127,7 +127,7 @@ opts = { argv: arg, spec_repo: 'tiny-repo' } result = OctocatalogDiff::Integration.integration_with_puppetdb(s_opts, opts) expect(result[:exitcode]).to eq(-1), OctocatalogDiff::Integration.format_exception(result) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/OpenSSL::PKey::RSAError/) end @@ -140,7 +140,7 @@ opts = { argv: arg, spec_repo: 'tiny-repo' } result = OctocatalogDiff::Integration.integration_with_puppetdb(s_opts, opts) expect(result[:exitcode]).to eq(-1), OctocatalogDiff::Integration.format_exception(result) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/OpenSSL::PKey::RSAError/) end end diff --git a/spec/octocatalog-diff/integration/puppetmaster_spec.rb b/spec/octocatalog-diff/integration/puppetmaster_spec.rb index 2902516b..b6d11f4c 100644 --- a/spec/octocatalog-diff/integration/puppetmaster_spec.rb +++ b/spec/octocatalog-diff/integration/puppetmaster_spec.rb @@ -157,7 +157,7 @@ def self.response(method, uri, _headers, body) } result = OctocatalogDiff::Integration.integration(opts) expect(result[:exitcode]).to eq(-1) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/OpenSSL::SSL::SSLError/) end @@ -174,7 +174,7 @@ def self.response(method, uri, _headers, body) } result = OctocatalogDiff::Integration.integration(opts) expect(result[:exitcode]).to eq(-1) - expect(result[:exception].class.to_s).to eq('OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError') + expect(result[:exception].class.to_s).to eq('OctocatalogDiff::Errors::CatalogError') expect(result[:exception].message).to match(/foobaz.local: 404/) end diff --git a/spec/octocatalog-diff/integration/reference_validation_spec.rb b/spec/octocatalog-diff/integration/reference_validation_spec.rb index b8f6b6f7..43705a0b 100644 --- a/spec/octocatalog-diff/integration/reference_validation_spec.rb +++ b/spec/octocatalog-diff/integration/reference_validation_spec.rb @@ -99,7 +99,7 @@ def self.catalog_contains_resource(result, type, title) end it 'should raise ReferenceValidationError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Catalog::ReferenceValidationError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::ReferenceValidationError) end it 'should have formatted error messages' do @@ -122,7 +122,7 @@ def self.catalog_contains_resource(result, type, title) end it 'should raise ReferenceValidationError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Catalog::ReferenceValidationError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::ReferenceValidationError) end it 'should have formatted error messages' do @@ -141,7 +141,7 @@ def self.catalog_contains_resource(result, type, title) end it 'should raise ReferenceValidationError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Catalog::ReferenceValidationError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::ReferenceValidationError) end it 'should have formatted error messages' do @@ -160,7 +160,7 @@ def self.catalog_contains_resource(result, type, title) end it 'should raise ReferenceValidationError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Catalog::ReferenceValidationError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::ReferenceValidationError) end it 'should have formatted error messages' do @@ -220,7 +220,7 @@ def self.catalog_contains_resource(result, type, title) end it 'should raise ReferenceValidationError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Catalog::ReferenceValidationError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::ReferenceValidationError) end it 'should have formatted error messages' do @@ -255,19 +255,8 @@ def self.catalog_contains_resource(result, type, title) diffs = @result.diffs expect(diffs).to be_a_kind_of(Array) expect(diffs.size).to eq(1) - - answer = [ - '-', - "Exec\fbefore caller", - { - 'type' => 'Exec', - 'title' => 'before caller', - 'tags' => ['before_callers', 'class', 'default', 'exec', 'node', 'test', 'test::before_callers'], - 'exported' => false, - 'parameters' => { 'command' => '/bin/true' } - } - ] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(diffs, answer)).to eq(true) + resource = { diff_type: '-', type: 'Exec', title: 'before caller' } + expect(OctocatalogDiff::Spec.diff_match?(@result[:diffs], resource)).to eq(true) end end @@ -285,7 +274,7 @@ def self.catalog_contains_resource(result, type, title) end it 'should raise ReferenceValidationError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Catalog::ReferenceValidationError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::ReferenceValidationError) end it 'should have formatted error messages' do @@ -329,7 +318,7 @@ def self.catalog_contains_resource(result, type, title) end it 'should raise ReferenceValidationError' do - expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Catalog::ReferenceValidationError) + expect(@result.exception).to be_a_kind_of(OctocatalogDiff::Errors::ReferenceValidationError) end it 'should have formatted error messages from to-catalog only' do diff --git a/spec/octocatalog-diff/integration/yaml_diff_spec.rb b/spec/octocatalog-diff/integration/yaml_diff_spec.rb index e32ccd72..28d79326 100644 --- a/spec/octocatalog-diff/integration/yaml_diff_spec.rb +++ b/spec/octocatalog-diff/integration/yaml_diff_spec.rb @@ -21,27 +21,23 @@ end it 'should contain the "similar JSON" static file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/static/similar-yaml.json\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true) + resource = { diff_type: '~', type: 'File', title: '/tmp/static/similar-yaml.json', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(true) end it 'should contain the "similar YAML" static file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/static/similar-yaml.yaml\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true) + resource = { diff_type: '~', type: 'File', title: '/tmp/static/similar-yaml.yaml', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(true) end it 'should contain the "similar JSON" template file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/template/similar-yaml.json\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true) + resource = { diff_type: '~', type: 'File', title: '/tmp/template/similar-yaml.json', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(true) end it 'should contain the "similar YAML" template file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/template/similar-yaml.yaml\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true) + resource = { diff_type: '~', type: 'File', title: '/tmp/template/similar-yaml.yaml', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(true) end end @@ -62,27 +58,23 @@ end it 'should contain the "similar JSON" static file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/static/similar-yaml.json\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true) + resource = { diff_type: '~', type: 'File', title: '/tmp/static/similar-yaml.json', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(true) end it 'should not contain the "similar YAML" static file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/static/similar-yaml.yaml\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(false) + resource = { diff_type: '~', type: 'File', title: '/tmp/static/similar-yaml.yaml', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(false) end it 'should contain the "similar JSON" template file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/template/similar-yaml.json\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(true) + resource = { diff_type: '~', type: 'File', title: '/tmp/template/similar-yaml.json', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(true) end it 'should not contain the "similar YAML" template file as a diff' do - arr = @result.diffs - answer = ['~', "File\f/tmp/template/similar-yaml.yaml\fparameters\fcontent"] - expect(OctocatalogDiff::Spec.array_contains_partial_array?(arr, answer)).to eq(false) + resource = { diff_type: '~', type: 'File', title: '/tmp/template/similar-yaml.yaml', structure: %w(parameters content) } + expect(OctocatalogDiff::Spec.diff_match?(@result.diffs, resource)).to eq(false) end end end diff --git a/spec/octocatalog-diff/mocks/puppetdb.rb b/spec/octocatalog-diff/mocks/puppetdb.rb index 30902712..4d37d7c7 100644 --- a/spec/octocatalog-diff/mocks/puppetdb.rb +++ b/spec/octocatalog-diff/mocks/puppetdb.rb @@ -2,6 +2,7 @@ require_relative '../tests/spec_helper' +require OctocatalogDiff::Spec.require_path('/errors') require OctocatalogDiff::Spec.require_path('/puppetdb') module OctocatalogDiff @@ -59,7 +60,7 @@ def override_facts(hostname) # @return [String] JSON catalog def catalog(hostname) fixture_file = OctocatalogDiff::Spec.fixture_path(File.join('catalogs', "#{hostname}.json")) - raise OctocatalogDiff::PuppetDB::NotFoundError, '404 - Not Found' unless File.file?(fixture_file) + raise OctocatalogDiff::Errors::PuppetDBNodeNotFoundError, '404 - Not Found' unless File.file?(fixture_file) JSON.parse(File.read(fixture_file)) end end diff --git a/spec/octocatalog-diff/tests/api/v1/catalog-compile_spec.rb b/spec/octocatalog-diff/tests/api/v1/catalog-compile_spec.rb new file mode 100644 index 00000000..26a28ff6 --- /dev/null +++ b/spec/octocatalog-diff/tests/api/v1/catalog-compile_spec.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require 'json' + +require_relative '../../spec_helper' + +require OctocatalogDiff::Spec.require_path('/api/v1/catalog-compile') + +describe OctocatalogDiff::API::V1::CatalogCompile do + describe '#catalog' do + it 'should raise error if no options are passed' do + expect { described_class.catalog }.to raise_error(ArgumentError) + end + + it 'should raise error if non-hash options are passed' do + expect { described_class.catalog([]) }.to raise_error(ArgumentError) + end + + it 'should use the passed-in logger' do + logger, _logger_str = OctocatalogDiff::Spec.setup_logger + options = { logger: logger } + expect(OctocatalogDiff::Util::Catalogs).to receive(:new) { |*args| raise args.last.object_id.to_s } + expect { described_class.catalog(options) }.to raise_error(RuntimeError, logger.object_id.to_s) + end + + it 'should construct a logger if one is not passed in' do + expect(OctocatalogDiff::Util::Catalogs).to receive(:new) { |*args| raise args.last.class.to_s } + expect { described_class.catalog({}) }.to raise_error(RuntimeError, 'Logger') + end + + it 'should remove logger from options passed to catalogs class' do + logger, _logger_str = OctocatalogDiff::Spec.setup_logger + options = { foo: 'bar', logger: logger } + expect(OctocatalogDiff::Util::Catalogs).to receive(:new) { |*args| raise args.first.to_json } + raised_error = nil + begin + described_class.catalog(options) + rescue RuntimeError => exc + raised_error = exc.message + end + expect(raised_error).not_to be_nil + raised_error_parsed = JSON.parse(raised_error) + expect(raised_error_parsed['foo']).to eq('bar') + expect(raised_error_parsed['logger']).to be_nil + end + + it 'should call OctocatalogDiff::Util::Catalogs and return to-key' do + obj = OpenStruct.new(catalogs: { to: 'to-catalog', from: 'from-catalog' }) + expect(OctocatalogDiff::API::V1::Catalog).to receive(:new).with('to-catalog').and_return('to-catalog') + expect(OctocatalogDiff::Util::Catalogs).to receive(:new).and_return(obj) + result = described_class.catalog({}) + expect(result).to eq('to-catalog') + end + end +end diff --git a/spec/octocatalog-diff/tests/api/v1/catalog-diff_spec.rb b/spec/octocatalog-diff/tests/api/v1/catalog-diff_spec.rb new file mode 100644 index 00000000..6898524d --- /dev/null +++ b/spec/octocatalog-diff/tests/api/v1/catalog-diff_spec.rb @@ -0,0 +1,87 @@ +# frozen_string_literal: true + +require 'ostruct' + +require_relative '../../spec_helper' + +require OctocatalogDiff::Spec.require_path('/api/v1/catalog-diff') +require OctocatalogDiff::Spec.require_path('/cli/diffs') +require OctocatalogDiff::Spec.require_path('/util/catalogs') + +describe OctocatalogDiff::API::V1::CatalogDiff do + describe '#catalog_diff' do + before(:each) do + @from_catalog = OctocatalogDiff::Catalog.new(backend: :noop) + @to_catalog = OctocatalogDiff::Catalog.new(backend: :noop) + end + + it 'should raise error if no options are passed' do + expect { described_class.catalog_diff }.to raise_error(ArgumentError) + end + + it 'should raise error if non-hash options are passed' do + expect { described_class.catalog_diff([]) }.to raise_error(ArgumentError) + end + + context 'with :cached_master_dir undefined' do + before(:each) do + catalog_obj = OpenStruct.new(catalogs: { from: @from_catalog, to: @to_catalog }) + expect(OctocatalogDiff::Util::Catalogs).to receive(:new).and_return(catalog_obj) + + diffs_obj = double + allow(diffs_obj).to receive(:diffs).and_return([['diff-1'], ['diff-2']]) + expect(OctocatalogDiff::Cli::Diffs).to receive(:new).and_return(diffs_obj) + + logger, @logger_str = OctocatalogDiff::Spec.setup_logger + @result = described_class.catalog_diff(logger: logger, node: 'foo') + end + + it 'should return the expected data structure' do + expect(@result.diffs[0].raw).to eq(['diff-1']) + expect(@result.diffs[1].raw).to eq(['diff-2']) + expect(@result.from.raw).to eq(@from_catalog) + expect(@result.to.raw).to eq(@to_catalog) + end + + it 'should log the expected messages' do + expect(@logger_str.string).to match(/Compiling catalogs for foo/) + expect(@logger_str.string).to match(/Catalogs compiled for foo/) + expect(@logger_str.string).to match(/Diffs computed for foo/) + expect(@logger_str.string).not_to match(/No differences/) + expect(@logger_str.string).not_to match(/Cached master catalog for foo/) + end + end + + context 'with :cached_master_dir defined' do + before(:each) do + expect(@from_catalog).to receive(:"compilation_dir=").with('foo') + + catalog_obj = OpenStruct.new(catalogs: { from: @from_catalog, to: @to_catalog }) + expect(OctocatalogDiff::Util::Catalogs).to receive(:new).and_return(catalog_obj) + + expect(OctocatalogDiff::CatalogUtil::CachedMasterDirectory).to receive(:save_catalog_in_cache_dir).and_return('yes') + + diffs_obj = double + allow(diffs_obj).to receive(:diffs).and_return([]) + expect(OctocatalogDiff::Cli::Diffs).to receive(:new).and_return(diffs_obj) + + logger, @logger_str = OctocatalogDiff::Spec.setup_logger + @result = described_class.catalog_diff(logger: logger, node: 'foo', cached_master_dir: 'foo', from_env: 'origin/master') + end + + it 'should return the expected data structure' do + expect(@result.diffs).to eq([]) + expect(@result.from.raw).to eq(@from_catalog) + expect(@result.to.raw).to eq(@to_catalog) + end + + it 'should log the expected messages' do + expect(@logger_str.string).to match(/Compiling catalogs for foo/) + expect(@logger_str.string).to match(/Catalogs compiled for foo/) + expect(@logger_str.string).to match(/Diffs computed for foo/) + expect(@logger_str.string).to match(/No differences/) + expect(@logger_str.string).to match(/Cached master catalog for foo/) + end + end + end +end diff --git a/spec/octocatalog-diff/tests/api/v1/catalog_spec.rb b/spec/octocatalog-diff/tests/api/v1/catalog_spec.rb new file mode 100644 index 00000000..51edbe1d --- /dev/null +++ b/spec/octocatalog-diff/tests/api/v1/catalog_spec.rb @@ -0,0 +1,107 @@ +# frozen_string_literal: true + +require_relative '../../spec_helper' + +require OctocatalogDiff::Spec.require_path('/catalog') +require OctocatalogDiff::Spec.require_path('/api/v1/catalog') + +describe OctocatalogDiff::API::V1::Catalog do + context 'with a non-catalog' do + describe '#initialize' do + it 'should raise ArgumentError' do + expect { described_class.new(nil) }.to raise_error(ArgumentError) + end + end + end + + context 'with a valid catalog' do + before(:all) do + @catalog = OctocatalogDiff::Catalog.new(json: OctocatalogDiff::Spec.fixture_read('catalogs/catalog-1.json')) + @testobj = described_class.new(@catalog) + end + + describe '#initialize' do + it 'should set @raw' do + expect(@testobj.raw).to eq(@catalog) + end + end + + describe '#builder' do + it 'should wrap catalog method' do + expect(@testobj.builder).to eq(@catalog.builder) + expect(@testobj.builder).to be_a_kind_of(String) + end + end + + describe '#to_json' do + it 'should wrap catalog method' do + expect(@testobj.to_json).to eq(@catalog.catalog_json) + expect(@testobj.to_json).to be_a_kind_of(String) + end + end + + describe '#compilation_dir' do + it 'should wrap catalog method if nil' do + expect(@testobj.compilation_dir).to eq(@catalog.compilation_dir) + expect(@testobj.compilation_dir).to be_nil + end + + it 'should wrap catalog method if not nil' do + expect(@catalog).to receive(:compilation_dir).and_return('foo') + expect(@testobj.compilation_dir).to eq('foo') + end + end + + describe '#error_message' do + it 'should wrap catalog method if nil' do + expect(@testobj.error_message).to eq(@catalog.error_message) + expect(@testobj.error_message).to be_nil + end + + it 'should wrap catalog method if not nil' do + expect(@catalog).to receive(:error_message).and_return('foo') + expect(@testobj.error_message).to eq('foo') + end + end + + describe '#puppet_version' do + it 'should wrap catalog method if nil' do + expect(@testobj.puppet_version).to eq(@catalog.puppet_version) + expect(@testobj.puppet_version).to be_nil + end + + it 'should wrap catalog method if not nil' do + expect(@catalog).to receive(:puppet_version).and_return('foo') + expect(@testobj.puppet_version).to eq('foo') + end + end + + describe '#resource' do + it 'should wrap catalog method' do + param = { type: 'Package', title: 'ruby1.8-dev' } + expect(@testobj.resource(param)).to eq(@catalog.resource(param)) + end + end + + describe '#resources' do + it 'should wrap catalog method' do + expect(@testobj.resources).to eq(@catalog.resources) + expect(@testobj.resources).to be_a_kind_of(Array) + end + end + + describe '#valid?' do + it 'should wrap catalog method' do + expect(@testobj.valid?).to eq(@catalog.valid?) + expect(@testobj.valid?).to be_a_kind_of(TrueClass) + end + end + + describe '#to_h' do + it 'should wrap catalog method' do + expect(@testobj.to_h).to eq(@catalog.catalog) + expect(@testobj.to_h).to be_a_kind_of(Hash) + end + end + end +end diff --git a/spec/octocatalog-diff/tests/api/v1/common_spec.rb b/spec/octocatalog-diff/tests/api/v1/common_spec.rb new file mode 100644 index 00000000..0b8842e4 --- /dev/null +++ b/spec/octocatalog-diff/tests/api/v1/common_spec.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +require 'json' + +require_relative '../../spec_helper' + +require OctocatalogDiff::Spec.require_path('/api/v1/common') + +describe OctocatalogDiff::API::V1::Common do + describe '#logger_from_options' do + it 'should use the passed-in logger' do + logger, _logger_str = OctocatalogDiff::Spec.setup_logger + options = { logger: logger, foo: 'bar' } + result_opts, result_logger = described_class.logger_from_options(options) + expect(result_logger).to eq(logger) + expect(result_opts).to eq(foo: 'bar', logger: nil) + end + + it 'should construct a logger if one is not passed in' do + result_opts, result_logger = described_class.logger_from_options(foo: 'bar') + expect(result_logger).to be_a_kind_of(Logger) + expect(result_opts).to eq(foo: 'bar', logger: nil) + end + + it 'should remove logger from options passed to catalogs class' do + logger, _logger_str = OctocatalogDiff::Spec.setup_logger + options = { foo: 'bar', logger: logger } + result_opts, result_logger = described_class.logger_from_options(options) + expect(result_opts[:foo]).to eq('bar') + expect(result_opts[:logger]).to be_nil + expect(result_logger).to eq(logger) + end + end +end diff --git a/spec/octocatalog-diff/tests/api/v1/config_spec.rb b/spec/octocatalog-diff/tests/api/v1/config_spec.rb new file mode 100644 index 00000000..61d6f0f3 --- /dev/null +++ b/spec/octocatalog-diff/tests/api/v1/config_spec.rb @@ -0,0 +1,266 @@ +# frozen_string_literal: true + +require_relative '../../spec_helper' + +require OctocatalogDiff::Spec.require_path('/api/v1/config') +require OctocatalogDiff::Spec.require_path('/errors') + +describe OctocatalogDiff::API::V1::Config do + before(:each) do + @logger, @logger_str = OctocatalogDiff::Spec.setup_logger + end + + after(:each) do + begin + OctocatalogDiff.send(:remove_const, :Config) + rescue NameError # rubocop:disable Lint/HandleExceptions + # Don't care if it's not defined already + end + end + + describe '#config' do + let(:filename) { '/fizz/buzz.rb' } + + context 'with missing configuration file' do + let(:pattern) { Regexp.new("Unable to find configuration file in #{filename}") } + + context 'in test mode' do + it 'should raise ConfigurationFileNotFoundError' do + expect(File).to receive(:'file?').with(filename).and_return(false) + expect do + described_class.config(logger: @logger, filename: filename, test: true) + end.to raise_error(OctocatalogDiff::Errors::ConfigurationFileNotFoundError, pattern) + end + end + + context 'in normal mode' do + it 'should return {}' do + expect(File).to receive(:'file?').with(filename).and_return(false) + result = described_class.config(logger: @logger, filename: filename) + expect(result).to eq({}) + expect(@logger_str.string).to match(pattern) + end + end + end + + context 'with found configuration file' do + let(:pattern) { Regexp.new('Loaded 1 settings from /fizz/buzz.rb') } + let(:debug_pattern) { Regexp.new(':foo => \(String\) "bar"') } + + context 'in test mode' do + it 'should print settings to log and return settings' do + expect(File).to receive(:'file?').with(filename).and_return(true) + expect(described_class).to receive(:load_config_file).and_return(foo: 'bar') + result = described_class.config(logger: @logger, filename: filename, test: true) + expect(result).to eq(foo: 'bar') + expect(@logger_str.string).to match(pattern) + expect(@logger_str.string).to match(debug_pattern) + end + end + + context 'in normal mode' do + it 'should return settings' do + expect(File).to receive(:'file?').with(filename).and_return(true) + expect(described_class).to receive(:load_config_file).and_return(foo: 'bar') + result = described_class.config(logger: @logger, filename: filename) + expect(result).to eq(foo: 'bar') + expect(@logger_str.string).to match(pattern) + expect(@logger_str.string).not_to match(debug_pattern) + end + end + end + end + + describe '#debug_config_file' do + it 'should raise error if non-hash is passed in' do + expect do + described_class.debug_config_file(nil, @logger) + end.to raise_error(ArgumentError, /Settings must be hash not NilClass/) + end + + it 'should log keys and values in the hash' do + described_class.debug_config_file({ foo: 'bar', baz: ['buzz'] }, @logger) + expect(@logger_str.string).to match(/:foo => \(String\) "bar"/) + expect(@logger_str.string).to match(/:baz => \(Array\) \["buzz"\]/) + end + end + + describe '#load_config_file' do + context 'with a non-existent file' do + let(:filename) { OctocatalogDiff::Spec.fixture_path('this-does-not-exist.rb') } + + it 'should raise Errno::ENOENT' do + expect do + described_class.load_config_file(filename, @logger) + end.to raise_error(Errno::ENOENT, /File.+doesn't exist/) + end + + it 'should log fatal message' do + exception = nil + begin + described_class.load_config_file(filename, @logger) + rescue Errno::ENOENT => exc + exception = exc + end + expect(exception.message).to match(/this-does-not-exist.rb doesn't exist/) + expect(@logger_str.string).to match(/FATAL .+ Errno::ENOENT error with .+this-does-not-exist.rb/) + end + end + + context 'with an invalid file' do + let(:filename) { OctocatalogDiff::Spec.fixture_path('cli-configs/not-ruby.rb') } + + it 'should raise SyntaxError' do + expect do + described_class.load_config_file(filename, @logger) + end.to raise_error(SyntaxError) + end + + it 'should log fatal message' do + exception = nil + begin + described_class.load_config_file(filename, @logger) + rescue SyntaxError => exc + exception = exc + end + expect(exception).to be_a_kind_of(SyntaxError) + expect(exception.message).to match(/unexpected tIDENTIFIER/) + expect(@logger_str.string).to match(/DEBUG -- : Loading octocatalog-diff configuration from/) + expect(@logger_str.string).to match(/FATAL .+ SyntaxError error with .+not-ruby.rb/) + end + end + + context 'with a file that throws an exception' do + let(:filename) { OctocatalogDiff::Spec.fixture_path('cli-configs/invalid.rb') } + + it 'should raise RuntimeError' do + expect do + described_class.load_config_file(filename, @logger) + end.to raise_error(RuntimeError, /Fizz Buzz/) + end + + it 'should log fatal message' do + exception = nil + begin + described_class.load_config_file(filename, @logger) + rescue RuntimeError => exc + exception = exc + end + expect(exception).to be_a_kind_of(RuntimeError) + expect(exception.message).to eq('Fizz Buzz') + expect(@logger_str.string).to match(/DEBUG -- : Loading octocatalog-diff configuration from/) + expect(@logger_str.string).to match(/FATAL .+ RuntimeError error with .+invalid.rb/) + end + end + + context 'with a file that does not define a .config method' do + let(:filename) { OctocatalogDiff::Spec.fixture_path('cli-configs/not-proper.rb') } + + it 'should raise ConfigurationFileContentError' do + pattern = Regexp.new('must define OctocatalogDiff::Config.config!') + expect do + described_class.load_config_file(filename, @logger) + end.to raise_error(OctocatalogDiff::Errors::ConfigurationFileContentError, pattern) + end + + it 'should log fatal message' do + exception = nil + begin + described_class.load_config_file(filename, @logger) + rescue OctocatalogDiff::Errors::ConfigurationFileContentError => exc + exception = exc + end + expect(exception).to be_a_kind_of(OctocatalogDiff::Errors::ConfigurationFileContentError) + expect(exception.message).to eq('Configuration must define OctocatalogDiff::Config.config!') + expect(@logger_str.string).to match(/Configuration must define OctocatalogDiff::Config.config!/) + end + end + + context 'with a file that does not define OctocatalogDiff::Config' do + let(:filename) { OctocatalogDiff::Spec.fixture_path('cli-configs/not-class.rb') } + + it 'should raise ConfigurationFileContentError' do + pattern = Regexp.new('must define OctocatalogDiff::Config') + expect do + described_class.load_config_file(filename, @logger) + end.to raise_error(OctocatalogDiff::Errors::ConfigurationFileContentError, pattern) + end + + it 'should log fatal message' do + exception = nil + begin + described_class.load_config_file(filename, @logger) + rescue OctocatalogDiff::Errors::ConfigurationFileContentError => exc + exception = exc + end + expect(exception).to be_a_kind_of(OctocatalogDiff::Errors::ConfigurationFileContentError) + expect(exception.message).to match(/Configuration must define OctocatalogDiff::Config/) + expect(@logger_str.string).to match(/Configuration must define OctocatalogDiff::Config/) + end + end + + context 'with a file that does not define a hash' do + let(:filename) { OctocatalogDiff::Spec.fixture_path('cli-configs/not-hash.rb') } + + it 'should raise ConfigurationFileContentError' do + pattern = Regexp.new('Configuration must be Hash not Array!') + expect do + described_class.load_config_file(filename, @logger) + end.to raise_error(OctocatalogDiff::Errors::ConfigurationFileContentError, pattern) + end + + it 'should log fatal message' do + exception = nil + begin + described_class.load_config_file(filename, @logger) + rescue OctocatalogDiff::Errors::ConfigurationFileContentError => exc + exception = exc + end + expect(exception).to be_a_kind_of(OctocatalogDiff::Errors::ConfigurationFileContentError) + expect(exception.message).to eq('Configuration must be Hash not Array!') + expect(@logger_str.string).to match(/Configuration must be Hash not Array!/) + end + end + + context 'with a valid file' do + let(:filename) { OctocatalogDiff::Spec.fixture_path('cli-configs/valid.rb') } + + it 'should return the expected settings' do + result = described_class.load_config_file(filename, @logger) + answer = { header: :default, hiera_config: 'config/hiera.yaml', hiera_path: 'hieradata' } + expect(result).to eq(answer) + end + + it 'should log debug message' do + described_class.load_config_file(filename, @logger) + expect(@logger_str.string).to match(/DEBUG -- : Loading octocatalog-diff configuration from/) + end + end + end + + describe '#first_file' do + before(:each) do + allow(File).to receive(:'file?') { |x| x =~ /^present/ } + end + + it 'should accept an empty array and return nil' do + expect(described_class.first_file([])).to be_nil + end + + it 'should accept a single missing file and return nil' do + expect(described_class.first_file(['missing1'])).to be_nil + end + + it 'should accept a multiple missing files and return nil' do + expect(described_class.first_file(%w(missing1 missing2 missing3))).to be_nil + end + + it 'should accept nil in the array and still work' do + expect(described_class.first_file(['missing1', nil, 'missing2', 'present1'])).to eq('present1') + end + + it 'should flatten arrays and still work' do + expect(described_class.first_file(['missing1', [nil, 'missing2'], ['present1']])).to eq('present1') + end + end +end diff --git a/spec/octocatalog-diff/tests/api/v1/diff_spec.rb b/spec/octocatalog-diff/tests/api/v1/diff_spec.rb new file mode 100644 index 00000000..15c0d20a --- /dev/null +++ b/spec/octocatalog-diff/tests/api/v1/diff_spec.rb @@ -0,0 +1,308 @@ +# frozen_string_literal: true + +require_relative '../../spec_helper' + +require OctocatalogDiff::Spec.require_path('/api/v1/diff') + +describe OctocatalogDiff::API::V1::Diff do + let(:type_title) { "File\f/etc/foo" } + let(:parameters) { { 'parameters' => { 'owner' => 'root' } } } + let(:tts) { "File\f/etc/foo\fparameters\fcontent" } + + let(:loc_1) { { 'file' => '/var/tmp/foo.pp', 'line' => 35 } } + let(:loc_2) { { 'file' => '/var/tmp/foo.pp', 'line' => 12 } } + + let(:add_1) { ['+', type_title, parameters] } + let(:add_2) { ['+', type_title, parameters, loc_2] } + + let(:del_1) { ['-', type_title, parameters] } + let(:del_2) { ['-', type_title, parameters, loc_1] } + + let(:chg_1) { ['~', tts, 'old', 'new'] } + let(:chg_2) { ['~', tts, 'old', 'new', loc_1, loc_2] } + + describe '#[]' do + it 'should return expected numeric values from an add/remove array' do + testobj = described_class.new(add_1) + expect(testobj[0]).to eq('+') + expect(testobj[1]).to eq(type_title) + expect(testobj[2]).to eq(parameters) + expect(testobj[3]).to be_nil + end + + it 'should return expected numeric values from a change array' do + testobj = described_class.new(chg_2) + expect(testobj[0]).to eq('~') + expect(testobj[1]).to eq(tts) + expect(testobj[2]).to eq('old') + expect(testobj[3]).to eq('new') + expect(testobj[4]).to eq(loc_1) + expect(testobj[5]).to eq(loc_2) + expect(testobj[6]).to be_nil + end + end + + describe '#diff_type' do + it 'should identify the symbol' do + testobj = described_class.new(chg_2) + expect(testobj.diff_type).to eq('~') + end + end + + describe '#addition?' do + it 'should return true for an addition' do + testobj = described_class.new(add_2) + expect(testobj.addition?).to eq(true) + end + + it 'should return false for a removal' do + testobj = described_class.new(del_2) + expect(testobj.addition?).to eq(false) + end + + it 'should return false for a change' do + testobj = described_class.new(chg_2) + expect(testobj.addition?).to eq(false) + end + end + + describe '#removal?' do + it 'should return true for an addition' do + testobj = described_class.new(add_2) + expect(testobj.removal?).to eq(false) + end + + it 'should return false for a removal' do + testobj = described_class.new(del_2) + expect(testobj.removal?).to eq(true) + end + + it 'should return false for a change' do + testobj = described_class.new(chg_2) + expect(testobj.removal?).to eq(false) + end + end + + describe '#change?' do + it 'should return true for an addition' do + testobj = described_class.new(add_2) + expect(testobj.change?).to eq(false) + end + + it 'should return false for a removal' do + testobj = described_class.new(del_2) + expect(testobj.change?).to eq(false) + end + + it 'should return false for a change' do + testobj = described_class.new(chg_2) + expect(testobj.change?).to eq(true) + end + end + + describe '#type' do + it 'should return the type' do + testobj = described_class.new(chg_2) + expect(testobj.type).to eq('File') + end + end + + describe '#title' do + it 'should return the title when there is no structure' do + testobj = described_class.new(add_2) + expect(testobj.title).to eq('/etc/foo') + end + + it 'should return the title when there is structure' do + testobj = described_class.new(chg_2) + expect(testobj.title).to eq('/etc/foo') + end + end + + describe '#structure' do + it 'should return an empty array for an addition' do + testobj = described_class.new(add_2) + expect(testobj.structure).to eq([]) + end + + it 'should return the proper array for a change' do + testobj = described_class.new(chg_2) + expect(testobj.structure).to eq(%w(parameters content)) + end + end + + describe '#old_value' do + it 'should return nil for an addition' do + testobj = described_class.new(add_2) + expect(testobj.old_value).to be_nil + end + + it 'should return the entire structure for a removal' do + testobj = described_class.new(del_2) + expect(testobj.old_value).to eq(parameters) + end + + it 'should return the old value for a change' do + testobj = described_class.new(chg_2) + expect(testobj.old_value).to eq('old') + end + end + + describe '#new_value' do + it 'should return the entire structure for an addition' do + testobj = described_class.new(add_2) + expect(testobj.new_value).to eq(parameters) + end + + it 'should return nil for a removal' do + testobj = described_class.new(del_2) + expect(testobj.new_value).to be_nil + end + + it 'should return the new value for a change' do + testobj = described_class.new(chg_2) + expect(testobj.new_value).to eq('new') + end + end + + describe '#old_file' do + it 'should return nil for an addition' do + testobj = described_class.new(add_2) + expect(testobj.old_file).to be_nil + end + + it 'should return the filename for a removal' do + testobj = described_class.new(del_2) + expect(testobj.old_file).to eq(loc_1['file']) + end + + it 'should return nil when information is not present for a removal' do + testobj = described_class.new(del_1) + expect(testobj.old_file).to be_nil + end + + it 'should return the filename for a change' do + testobj = described_class.new(chg_2) + expect(testobj.old_file).to eq(loc_1['file']) + end + + it 'should return nil when information is not present for a change' do + testobj = described_class.new(chg_1) + expect(testobj.old_file).to be_nil + end + end + + describe '#old_line' do + it 'should return nil for an addition' do + testobj = described_class.new(add_2) + expect(testobj.old_line).to be_nil + end + + it 'should return the line for a removal' do + testobj = described_class.new(del_2) + expect(testobj.old_line).to eq(loc_1['line']) + end + + it 'should return nil when information is not present for a removal' do + testobj = described_class.new(del_1) + expect(testobj.old_line).to be_nil + end + + it 'should return the line for a change' do + testobj = described_class.new(chg_2) + expect(testobj.old_line).to eq(loc_1['line']) + end + + it 'should return nil when information is not present for a change' do + testobj = described_class.new(chg_1) + expect(testobj.old_line).to be_nil + end + end + + describe '#new_file' do + it 'should return nil for a removal' do + testobj = described_class.new(del_2) + expect(testobj.new_file).to be_nil + end + + it 'should return the filename for an addition' do + testobj = described_class.new(add_2) + expect(testobj.new_file).to eq(loc_2['file']) + end + + it 'should return nil when information is not present for an addition' do + testobj = described_class.new(add_1) + expect(testobj.new_file).to be_nil + end + + it 'should return the filename for a change' do + testobj = described_class.new(chg_2) + expect(testobj.new_file).to eq(loc_2['file']) + end + + it 'should return nil when information is not present for a change' do + testobj = described_class.new(chg_1) + expect(testobj.new_file).to be_nil + end + end + + describe '#new_line' do + it 'should return nil for a removal' do + testobj = described_class.new(del_2) + expect(testobj.new_line).to be_nil + end + + it 'should return the line for an addition' do + testobj = described_class.new(add_2) + expect(testobj.new_line).to eq(loc_2['line']) + end + + it 'should return nil when information is not present for an addition' do + testobj = described_class.new(add_1) + expect(testobj.new_line).to be_nil + end + + it 'should return the line for a change' do + testobj = described_class.new(chg_2) + expect(testobj.new_line).to eq(loc_2['line']) + end + + it 'should return nil when information is not present for a change' do + testobj = described_class.new(chg_1) + expect(testobj.new_line).to be_nil + end + end + + describe '#to_h' do + it 'should return a hash with the expected keys and values' do + methods = %w(diff_type type title structure old_value new_value old_line new_line old_file new_file) + testobj = described_class.new(chg_2) + result = testobj.to_h + methods.each do |method_name| + method = method_name.to_sym + expect(result.key?(method)).to eq(true) + expect(result[method]).to eq(testobj.send(method)) + end + end + end + + describe '#inspect' do + it 'should return a string' do + testobj = described_class.new(chg_2) + expect(testobj.inspect).to be_a_kind_of(String) + end + end + + describe '#to_s' do + it 'should return a string' do + testobj = described_class.new(chg_2) + expect(testobj.to_s).to be_a_kind_of(String) + end + end + + describe '#initialize' do + it 'should raise ArgumentError if called with a non-array' do + expect { described_class.new('foo') }.to raise_error(ArgumentError) + end + end +end diff --git a/spec/octocatalog-diff/tests/api/v1_spec.rb b/spec/octocatalog-diff/tests/api/v1_spec.rb new file mode 100644 index 00000000..ad2ec232 --- /dev/null +++ b/spec/octocatalog-diff/tests/api/v1_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require_relative '../spec_helper' + +require OctocatalogDiff::Spec.require_path('/api/v1') + +describe OctocatalogDiff::API::V1 do + describe '#catalog' do + it 'should call CatalogCompile.catalog with passed-in arguments' do + args = { foo: 'bar' } + expect(OctocatalogDiff::API::V1::CatalogCompile).to receive(:catalog).with(args) + expect { described_class.catalog(args) }.not_to raise_error + end + end + + describe '#catalog_diff' do + it 'should call CatalogDiff.catalog_diff with passed-in arguments' do + args = { foo: 'bar' } + expect(OctocatalogDiff::API::V1::CatalogDiff).to receive(:catalog_diff).with(args) + expect { described_class.catalog_diff(args) }.not_to raise_error + end + end + + describe '#config' do + it 'should call CatalogDiff.config with passed-in arguments' do + args = { foo: 'bar' } + expect(OctocatalogDiff::API::V1::Config).to receive(:config).with(args) + expect { described_class.config(args) }.not_to raise_error + end + end +end diff --git a/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb b/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb index 8d9594a5..19089ea0 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb +++ b/spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb @@ -3,6 +3,7 @@ require_relative '../spec_helper' require OctocatalogDiff::Spec.require_path('/catalog') require OctocatalogDiff::Spec.require_path('/catalog-diff/differ') +require OctocatalogDiff::Spec.require_path('/errors') require 'json' # Read this about the fixtures: @@ -61,7 +62,7 @@ it 'should raise exception when something other than a catalog is passed in' do expect do OctocatalogDiff::CatalogDiff::Differ.new(@options, 'This is not a catalog!', @empty_puppet_catalog) - end.to raise_error(OctocatalogDiff::CatalogDiff::Differ::DifferError) + end.to raise_error(OctocatalogDiff::Errors::DifferError) end end diff --git a/spec/octocatalog-diff/tests/catalog-util/bootstrap_spec.rb b/spec/octocatalog-diff/tests/catalog-util/bootstrap_spec.rb index bb4eb969..391caa5a 100644 --- a/spec/octocatalog-diff/tests/catalog-util/bootstrap_spec.rb +++ b/spec/octocatalog-diff/tests/catalog-util/bootstrap_spec.rb @@ -3,6 +3,7 @@ require_relative '../spec_helper' require OctocatalogDiff::Spec.require_path('/catalog-util/bootstrap') +require OctocatalogDiff::Spec.require_path('/errors') require 'fileutils' @@ -25,7 +26,7 @@ } expect do OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory_parallelizer(opts, logger) - end.to raise_error(OctocatalogDiff::CatalogUtil::Bootstrap::BootstrapError, /Must specify a from-branch/) + end.to raise_error(OctocatalogDiff::Errors::BootstrapError, /Must specify a from-branch/) expect(logger_str.string).to match(/Must specify a from-branch/) end @@ -38,7 +39,7 @@ } expect do OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory_parallelizer(opts, logger) - end.to raise_error(OctocatalogDiff::CatalogUtil::Bootstrap::BootstrapError, /Must specify a to-branch/) + end.to raise_error(OctocatalogDiff::Errors::BootstrapError, /Must specify a to-branch/) expect(logger_str.string).to match(/Must specify a to-branch/) end @@ -47,7 +48,7 @@ opts = {} expect do OctocatalogDiff::CatalogUtil::Bootstrap.bootstrap_directory_parallelizer(opts, logger) - end.to raise_error(OctocatalogDiff::CatalogUtil::Bootstrap::BootstrapError, /Specify one or more of/) + end.to raise_error(OctocatalogDiff::Errors::BootstrapError, /Specify one or more of/) expect(logger_str.string).to match(/Specify one or more of/) end @@ -163,4 +164,73 @@ end end end + + describe '#git_checkout' do + context 'with successful git checkout' do + it 'should log success messages' do + expect(OctocatalogDiff::CatalogUtil::Git).to receive(:check_out_git_archive) + logger, logger_str = OctocatalogDiff::Spec.setup_logger + opts = { basedir: '/tmp/foo', branch: 'foo', path: '/tmp/bar' } + described_class.git_checkout(logger, opts) + expect(logger_str.string).to match(%r{Begin git checkout /tmp/foo:foo -> /tmp/bar}) + expect(logger_str.string).to match(%r{Success git checkout /tmp/foo:foo -> /tmp/bar}) + end + end + + context 'with failed git checkout' do + it 'should log error messages and raise OctocatalogDiff::Errors::BootstrapError' do + expect(OctocatalogDiff::CatalogUtil::Git).to receive(:check_out_git_archive) + .and_raise(OctocatalogDiff::Errors::GitCheckoutError, 'Oopsie') + logger, logger_str = OctocatalogDiff::Spec.setup_logger + opts = { basedir: '/tmp/foo', branch: 'foo', path: '/tmp/bar' } + expect { described_class.git_checkout(logger, opts) }.to raise_error(OctocatalogDiff::Errors::BootstrapError) + expect(logger_str.string).to match(%r{Begin git checkout /tmp/foo:foo -> /tmp/bar}) + expect(logger_str.string).to match(/Git checkout error: Oopsie/) + end + end + end + + describe '#run_bootstrap' do + before(:each) do + @logger, @logger_str = OctocatalogDiff::Spec.setup_logger + end + + context 'with successful run' do + before(:each) do + expect(OctocatalogDiff::Bootstrap).to receive(:bootstrap).and_return(status_code: 0, output: 'worked') + end + + context 'with bootstrap debugging' do + it 'should succeed and print debugging messages' do + opts = { bootstrap_script: 'foo.sh', debug_bootstrap: true, path: '/tmp/bar' } + result = described_class.run_bootstrap(@logger, opts) + expect(result).to eq('worked') + expect(@logger_str.string).to match(%r{Begin bootstrap with 'foo.sh' in /tmp/bar}) + expect(@logger_str.string).to match(/Bootstrap: worked/) + expect(@logger_str.string).to match(%r{Success bootstrap in /tmp/bar}) + end + end + + context 'without bootstrap debugging' do + it 'should succeed without debugging messages' do + opts = { bootstrap_script: 'foo.sh', path: '/tmp/bar' } + result = described_class.run_bootstrap(@logger, opts) + expect(result).to eq('worked') + expect(@logger_str.string).to match(%r{Begin bootstrap with 'foo.sh' in /tmp/bar}) + expect(@logger_str.string).not_to match(/Bootstrap: worked/) + expect(@logger_str.string).to match(%r{Success bootstrap in /tmp/bar}) + end + end + end + + context 'with failed run' do + it 'should raise OctocatalogDiff::Errors::BootstrapError' do + expect(OctocatalogDiff::Bootstrap).to receive(:bootstrap).and_return(status_code: 1, output: 'Oopsie') + opts = { bootstrap_script: 'foo.sh', path: '/tmp/bar' } + expect { described_class.run_bootstrap(@logger, opts) }.to raise_error(OctocatalogDiff::Errors::BootstrapError) + expect(@logger_str.string).to match(%r{Begin bootstrap with 'foo.sh' in /tmp/bar}) + expect(@logger_str.string).to match(/Bootstrap: Oopsie/) + end + end + end end diff --git a/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb b/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb index b8ba00b2..caff7a1c 100644 --- a/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb +++ b/spec/octocatalog-diff/tests/catalog-util/builddir_spec.rb @@ -3,7 +3,7 @@ require_relative '../spec_helper' require OctocatalogDiff::Spec.require_path('/facts') require OctocatalogDiff::Spec.require_path('/catalog-util/builddir') -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/helpers/fact_override') +require OctocatalogDiff::Spec.require_path('/cli/helpers/fact_override') require 'socket' require 'yaml' @@ -531,7 +531,7 @@ context 'with fact overrides' do it 'should create and populate the fact file' do overrides_raw = %w(ipaddress=10.30.50.70 fizz=buzz jsontest=(json){"foo":"bar"}) - overrides = overrides_raw.map { |x| OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(x) } + overrides = overrides_raw.map { |x| OctocatalogDiff::Cli::Helpers::FactOverride.new(x) } options = { basedir: OctocatalogDiff::Spec.fixture_path('repos/default'), fact_file: OctocatalogDiff::Spec.fixture_path('facts/valid-facts.yaml'), diff --git a/spec/octocatalog-diff/tests/catalog-util/enc/pe_spec.rb b/spec/octocatalog-diff/tests/catalog-util/enc/pe_spec.rb index 1129a44e..456d4ea6 100644 --- a/spec/octocatalog-diff/tests/catalog-util/enc/pe_spec.rb +++ b/spec/octocatalog-diff/tests/catalog-util/enc/pe_spec.rb @@ -200,7 +200,7 @@ @logger, @logger_str = OctocatalogDiff::Spec.setup_logger fact_obj = double('OctocatalogDiff::CatalogUtil::Facts') - allow(fact_obj).to receive(:facts).and_raise(OctocatalogDiff::Facts::FactRetrievalError, 'Fact Error') + allow(fact_obj).to receive(:facts).and_raise(OctocatalogDiff::Errors::FactRetrievalError, 'Fact Error') allow(OctocatalogDiff::CatalogUtil::Facts).to receive(:new).and_return(fact_obj) opts = { node: 'foo', pe_enc_url: 'https://localhost:4433/classifier-api' } @@ -213,7 +213,7 @@ end it 'should set error message' do - answer = 'Fact retrieval failed: OctocatalogDiff::Facts::FactRetrievalError - Fact Error' + answer = 'Fact retrieval failed: OctocatalogDiff::Errors::FactRetrievalError - Fact Error' expect(@testobj.error_message).to eq(answer) end @@ -221,7 +221,7 @@ log = @logger_str.string expect(log).to match(/DEBUG.+Beginning OctocatalogDiff::CatalogUtil::ENC::PE#execute for foo/) expect(log).to match(/DEBUG.+Start retrieving facts for foo from OctocatalogDiff::CatalogUtil::ENC::PE/) - expect(log).to match(/ERROR.+Fact retrieval failed: OctocatalogDiff::Facts::FactRetrievalError - Fact Error/) + expect(log).to match(/ERROR.+Fact retrieval failed: OctocatalogDiff::Errors::FactRetrievalError - Fact Error/) end end end diff --git a/spec/octocatalog-diff/tests/catalog-util/git_spec.rb b/spec/octocatalog-diff/tests/catalog-util/git_spec.rb new file mode 100644 index 00000000..ba428337 --- /dev/null +++ b/spec/octocatalog-diff/tests/catalog-util/git_spec.rb @@ -0,0 +1,117 @@ +# frozen_string_literal: true + +require_relative '../spec_helper' + +require OctocatalogDiff::Spec.require_path('catalog-util/git') +require OctocatalogDiff::Spec.require_path('errors') + +require 'ostruct' + +describe OctocatalogDiff::CatalogUtil::Git do + before(:each) do + @logger, @logger_str = OctocatalogDiff::Spec.setup_logger + allow(File).to receive(:'directory?').with('/tmp/foo').and_return(false) + allow(File).to receive(:'directory?').with('/tmp/bar').and_return(true) + end + + describe '#check_out_git_archive' do + context 'with invalid directory' do + it 'should raise OctocatalogDiff::Errors::GitCheckoutError if basedir is nil' do + opts = { branch: 'foo', path: '/tmp/foo', basedir: nil, logger: @logger } + expect do + described_class.check_out_git_archive(opts) + end.to raise_error(OctocatalogDiff::Errors::GitCheckoutError, /Source directory/) + end + + it 'should raise OctocatalogDiff::Errors::GitCheckoutError if basedir does not exist' do + opts = { branch: 'foo', path: '/tmp/foo', basedir: '/tmp/foo', logger: @logger } + expect do + described_class.check_out_git_archive(opts) + end.to raise_error(OctocatalogDiff::Errors::GitCheckoutError, /Source directory/) + end + + it 'should raise OctocatalogDiff::Errors::GitCheckoutError if path is nil' do + opts = { branch: 'foo', path: nil, basedir: '/tmp/bar', logger: @logger } + expect do + described_class.check_out_git_archive(opts) + end.to raise_error(OctocatalogDiff::Errors::GitCheckoutError, /Target directory/) + end + + it 'should raise OctocatalogDiff::Errors::GitCheckoutError if path does not exist' do + opts = { branch: 'foo', path: '/tmp/foo', basedir: '/tmp/bar', logger: @logger } + expect do + described_class.check_out_git_archive(opts) + end.to raise_error(OctocatalogDiff::Errors::GitCheckoutError, /Target directory/) + end + end + + context 'with valid directory' do + context 'with successful script run' do + it 'should log proper messages and not raise error' do + expect(described_class).to receive(:create_git_checkout_script).and_return('/tmp/baz.sh') + expect(Open3).to receive(:capture2e) + .with('/tmp/baz.sh', chdir: '/tmp/bar') + .and_return(['asldfkj', OpenStruct.new(exitstatus: 0)]) + opts = { branch: 'foo', path: '/tmp/bar', basedir: '/tmp/bar', logger: @logger } + described_class.check_out_git_archive(opts) + expect(@logger_str.string).to match(%r{Success git archive /tmp/bar:foo}) + end + end + + context 'with failed script run' do + it 'should raise OctocatalogDiff::Errors::GitCheckoutError' do + expect(described_class).to receive(:create_git_checkout_script).and_return('/tmp/baz.sh') + expect(Open3).to receive(:capture2e) + .with('/tmp/baz.sh', chdir: '/tmp/bar') + .and_return(['errors abound', OpenStruct.new(exitstatus: 1)]) + opts = { branch: 'foo', path: '/tmp/bar', basedir: '/tmp/bar', logger: @logger } + expect do + described_class.check_out_git_archive(opts) + end.to raise_error(OctocatalogDiff::Errors::GitCheckoutError, 'Git archive foo->/tmp/bar failed: errors abound') + end + end + end + end + + describe '#create_git_checkout_script' do + it 'should create the temporary script' do + result = described_class.create_git_checkout_script('foo', '/tmp/baz') + expect(result).to be_a_kind_of(String) + expect(File.file?(result)).to eq(true) + + text = File.read(result) + expect(text).to match(/git archive --format=tar foo \|/) + expect(text).to match(%r{\( cd /tmp/baz && tar -xf - \)}) + + expect(File.executable?(result)).to eq(true) + end + end + + describe '#branch_sha' do + context 'with invalid directory' do + it 'should raise Errno::ENOENT if basedir is nil' do + opts = { branch: 'foo', basedir: nil } + expect do + described_class.branch_sha(opts) + end.to raise_error(Errno::ENOENT, /Git directory/) + end + + it 'should raise Errno::ENOENT if basedir does not exist' do + opts = { branch: 'foo', basedir: '/tmp/foo' } + expect do + described_class.branch_sha(opts) + end.to raise_error(Errno::ENOENT, /Git directory/) + end + end + + context 'with valid directory' do + it 'should return the sha from rugged' do + opts = { branch: 'foo', basedir: '/tmp/bar' } + expect(Rugged::Repository).to receive(:new).with('/tmp/bar') + .and_return(OpenStruct.new(branches: { 'foo' => OpenStruct.new(target_id: 'abcdef012345') })) + result = described_class.branch_sha(opts) + expect(result).to eq('abcdef012345') + end + end + end +end diff --git a/spec/octocatalog-diff/tests/catalog/puppetdb_spec.rb b/spec/octocatalog-diff/tests/catalog/puppetdb_spec.rb index 852a57bf..2d69a447 100644 --- a/spec/octocatalog-diff/tests/catalog/puppetdb_spec.rb +++ b/spec/octocatalog-diff/tests/catalog/puppetdb_spec.rb @@ -8,6 +8,7 @@ require OctocatalogDiff::Spec.require_path('/catalog') require OctocatalogDiff::Spec.require_path('/catalog/puppetdb') require OctocatalogDiff::Spec.require_path('/catalog-util/builddir') +require OctocatalogDiff::Spec.require_path('/errors') describe OctocatalogDiff::Catalog::PuppetDB do context 'with working catalog' do @@ -106,16 +107,16 @@ it 'should set error message for connection error' do puppetdb = double('OctocatalogDiff::PuppetDB') - allow(puppetdb).to receive(:get).and_raise(OctocatalogDiff::PuppetDB::ConnectionError, 'test') + allow(puppetdb).to receive(:get).and_raise(OctocatalogDiff::Errors::PuppetDBConnectionError, 'test') allow(OctocatalogDiff::PuppetDB).to receive(:new).and_return(puppetdb) @obj.send(:fetch_catalog, @logger) - expect(@obj.error_message).to match(/Catalog retrieval failed \(.*::ConnectionError\) \(test\)/) + expect(@obj.error_message).to match(/Catalog retrieval failed \(.*::PuppetDBConnectionError\) \(test\)/) end it 'should set error message for not found error' do puppetdb = double('OctocatalogDiff::PuppetDB') - allow(puppetdb).to receive(:get).and_raise(OctocatalogDiff::PuppetDB::NotFoundError, 'test') + allow(puppetdb).to receive(:get).and_raise(OctocatalogDiff::Errors::PuppetDBNodeNotFoundError, 'test') allow(OctocatalogDiff::PuppetDB).to receive(:new).and_return(puppetdb) @obj.send(:fetch_catalog, @logger) @@ -124,7 +125,7 @@ it 'should set error message for puppetdb error' do puppetdb = double('OctocatalogDiff::PuppetDB') - allow(puppetdb).to receive(:get).and_raise(OctocatalogDiff::PuppetDB::PuppetDBError, 'test') + allow(puppetdb).to receive(:get).and_raise(OctocatalogDiff::Errors::PuppetDBGenericError, 'test') allow(OctocatalogDiff::PuppetDB).to receive(:new).and_return(puppetdb) @obj.send(:fetch_catalog, @logger) diff --git a/spec/octocatalog-diff/tests/catalog_spec.rb b/spec/octocatalog-diff/tests/catalog_spec.rb index 12021607..fa40996c 100644 --- a/spec/octocatalog-diff/tests/catalog_spec.rb +++ b/spec/octocatalog-diff/tests/catalog_spec.rb @@ -4,6 +4,7 @@ require_relative '../mocks/puppetdb' require OctocatalogDiff::Spec.require_path('/catalog') +require OctocatalogDiff::Spec.require_path('/errors') describe OctocatalogDiff::Catalog do context 'backends' do @@ -311,7 +312,7 @@ it 'should raise error' do expect do @catalog.resource(type: 'System::User', title: 'alice') - end.to raise_error(OctocatalogDiff::Catalog::CatalogError, /Broken!/) + end.to raise_error(OctocatalogDiff::Errors::CatalogError, /Broken!/) end end @@ -319,7 +320,7 @@ it 'should throw an error' do expect do @catalog.resources - end.to raise_error(OctocatalogDiff::Catalog::CatalogError, /Broken!/) + end.to raise_error(OctocatalogDiff::Errors::CatalogError, /Broken!/) end end @@ -476,7 +477,7 @@ 'exec[subscribe caller 2] -> subscribe[Exec[subscribe target 2]]', 'exec[subscribe caller 3] -> subscribe[Exec[subscribe target]]' ].join('; ') - expect { catalog.validate_references }.to raise_error(OctocatalogDiff::Catalog::ReferenceValidationError, error_str) + expect { catalog.validate_references }.to raise_error(OctocatalogDiff::Errors::ReferenceValidationError, error_str) end end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/diffs_spec.rb b/spec/octocatalog-diff/tests/cli/diffs_spec.rb similarity index 89% rename from spec/octocatalog-diff/tests/catalog-diff/cli/diffs_spec.rb rename to spec/octocatalog-diff/tests/cli/diffs_spec.rb index c86a3d3c..4e0a38b4 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/diffs_spec.rb +++ b/spec/octocatalog-diff/tests/cli/diffs_spec.rb @@ -1,11 +1,12 @@ # frozen_string_literal: true -require_relative '../../spec_helper' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/diffs') +require_relative '../spec_helper' + +require OctocatalogDiff::Spec.require_path('/cli/diffs') require 'json' -describe OctocatalogDiff::CatalogDiff::Cli::Diffs do +describe OctocatalogDiff::Cli::Diffs do before(:all) do @cat_tiny_1 = OctocatalogDiff::Catalog.new( node: 'my.rspec.node', @@ -45,7 +46,7 @@ "Class\fFizzbuzz", { 'type' => 'Class', 'title' => 'Fizzbuzz', 'tags' => %w(class fizzbuzz), 'exported' => false }, { 'file' => nil, 'line' => nil }]] - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_tiny_1, to: @cat_tiny_2) expect(result).to eq(answer) expect(@logger_str.string).not_to match(/WARN/) @@ -53,7 +54,7 @@ it 'should suppress tags when :include_tags is false' do opts = { include_tags: false } - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_tiny_1, to: @cat_tiny_tags) expect(result).to eq([]) expect(@logger_str.string).not_to match(/WARN/) @@ -63,7 +64,7 @@ opts = { include_tags: true } loc_map = { 'file' => nil, 'line' => nil } answer = [['!', "Stage\fmain\ftags", ['stage'], ['blah::foo', 'stage'], loc_map, loc_map]] - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_tiny_1, to: @cat_tiny_tags) expect(result).to eq(answer) expect(@logger_str.string).not_to match(/WARN/) @@ -71,7 +72,7 @@ it 'should pass ignore options' do opts = { ignore: { type: 'Class', title: 'Fizzbuzz' } } - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_tiny_1, to: @cat_tiny_2) expect(result).to eq([]) expect(@logger_str.string).not_to match(/WARN/) @@ -85,7 +86,7 @@ { type: 'Varies_Due_To_Compilation_Dir_4' } ] } - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_compilation_dir_1, to: @cat_compilation_dir_2) expect(result).to eq([]) expect(@logger_str.string).to match(%r{Varies_Due_To_Compilation_Dir_1\[/path/to/catalog2\] .*Suppressed}) @@ -99,7 +100,7 @@ { type: 'Varies_Due_To_Compilation_Dir_3' }, { type: 'Varies_Due_To_Compilation_Dir_4' } ] } - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_compilation_dir_1, to: @cat_compilation_dir_2) expect(result).to eq([]) r1 = %r{Varies_Due_To_Compilation_Dir_2\[/aldsfjalkfjalksfd/path/to/catalog2/dflkjasfkljasdf\].*Suppressed} @@ -117,7 +118,7 @@ { attr: "parameters\fdir_in_first_cat" }, { attr: "parameters\fdir_in_second_cat" } ] } - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_compilation_dir_1, to: @cat_compilation_dir_2) expect(result).to eq([]) expect(@logger_str.string).to match(/WARN -- : Resource key.*parameters => dir .*Suppressed/) @@ -133,7 +134,7 @@ { attr: "parameters\fdir" }, { attr: "parameters\fdir_in_middle" } ] } - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_compilation_dir_1, to: @cat_compilation_dir_2) expect(result.size).to eq(2) common_str = "Varies_Due_To_Compilation_Dir_3\fCommon Title\fparameters\f" @@ -150,7 +151,7 @@ { type: 'Varies_Due_To_Compilation_Dir_2' }, { type: 'Varies_Due_To_Compilation_Dir_3' } ] } - testobj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + testobj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) result = testobj.diffs(from: @cat_compilation_dir_1, to: @cat_compilation_dir_2) answer = [[ '~', @@ -169,7 +170,7 @@ cat2 = OctocatalogDiff::Catalog.new(json: File.read(OctocatalogDiff::Spec.fixture_path('catalogs/ignore-tags-new.json'))) opts = { ignore_tags: ['ignored_catalog_diff'] } answer = JSON.parse(File.read(OctocatalogDiff::Spec.fixture_path('diffs/ignore-tags-partial.json'))) - obj = OctocatalogDiff::CatalogDiff::Cli::Diffs.new(opts, @logger) + obj = OctocatalogDiff::Cli::Diffs.new(opts, @logger) diffs = obj.diffs(from: cat1, to: cat2) expect(diffs.size).to eq(8) answer.each do |x| diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/helpers/fact_override_spec.rb b/spec/octocatalog-diff/tests/cli/helpers/fact_override_spec.rb similarity index 64% rename from spec/octocatalog-diff/tests/catalog-diff/cli/helpers/fact_override_spec.rb rename to spec/octocatalog-diff/tests/cli/helpers/fact_override_spec.rb index 9003aa72..72e463ef 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/helpers/fact_override_spec.rb +++ b/spec/octocatalog-diff/tests/cli/helpers/fact_override_spec.rb @@ -1,58 +1,59 @@ # frozen_string_literal: true -require_relative '../../../spec_helper' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/helpers/fact_override') +require_relative '../../spec_helper' + +require OctocatalogDiff::Spec.require_path('/cli/helpers/fact_override') require 'json' -describe OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride do +describe OctocatalogDiff::Cli::Helpers::FactOverride do context 'with faulty input' do describe '#new' do it 'should raise ArgumentError when string lacks an =' do arg = 'dkfjladksfjaldfjdslkfjads' expect do - _foo = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + _foo = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) end.to raise_error(ArgumentError, /Fact override.*is not in 'key=\(data type\)value' format/) end it 'should raise ArgumentError when non-string lacks a key' do arg = ['dkfjladksfjaldfjdslkfjads'] expect do - _foo = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + _foo = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) end.to raise_error(ArgumentError, /Define a key when the input is not a string/) end it 'should raise JSON::ParserError if JSON fails to parse' do arg = 'key=(json){akdsfjalsdkfjasdf}' expect do - _foo = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + _foo = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) end.to raise_error(JSON::ParserError, /unexpected token at '\{akdsfjalsdkfjasdf\}'/) end it 'should raise ArgumentError when unrecognized data type is specified' do arg = 'key=(chicken)blahblah' expect do - _foo = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + _foo = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) end.to raise_error(ArgumentError, /Unknown data type 'chicken'/) end it 'should raise ArgumentError when boolean is specified but not supplied' do arg = 'key=(boolean)blahblah' expect do - _foo = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + _foo = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) end.to raise_error(ArgumentError, /Illegal boolean 'blahblah'/) end it 'should raise ArgumentError when fixnum is specified but not supplied' do arg = 'key=(fixnum)blahblah' expect do - _foo = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + _foo = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) end.to raise_error(ArgumentError, /Illegal fixnum 'blahblah'/) end it 'should raise ArgumentError when float is specified but not supplied' do arg = 'key=(float)blahblah' expect do - _foo = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + _foo = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) end.to raise_error(ArgumentError, /Illegal float 'blahblah'/) end end @@ -61,116 +62,116 @@ context 'with proper typed input' do describe '#new' do it 'should pass through a string' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)chicken') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)chicken') expect(testobj.key).to eq('foo') expect(testobj.value).to eq('chicken') end it 'should pass through an empty string' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)') expect(testobj.key).to eq('foo') expect(testobj.value).to eq('') end it 'should pass through a multi-line string' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new("foo=(string)foo\nbar") + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new("foo=(string)foo\nbar") expect(testobj.key).to eq('foo') expect(testobj.value).to eq("foo\nbar") end it 'should pass through a positive integer' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(fixnum)42') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(fixnum)42') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(42) end it 'should pass through a negative integer' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(fixnum)-42') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(fixnum)-42') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(-42) end it 'should pass through a positive float' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(float)42.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(float)42.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(42.15) end it 'should pass through a negative float' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(float)-42.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(float)-42.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(-42.15) end it 'should pass through a positive float with no leading digit' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(float).15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(float).15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(0.15) end it 'should pass through a negative float with no leading digit' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(float)-.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(float)-.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(-0.15) end it 'should handle true boolean' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)true') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)true') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(true) end it 'should handle true boolean case-insensitive' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)TrUe') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)TrUe') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(true) end it 'should handle false boolean' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)false') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)false') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(false) end it 'should handle false boolean case-insensitive' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)FaLsE') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(boolean)FaLsE') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(false) end it 'should parse JSON' do arg = 'foo=(json){"bar":"baz"}' - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg) + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg) expect(testobj.key).to eq('foo') expect(testobj.value).to eq('bar' => 'baz') end it 'should return string even when input looks like a number' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)42') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)42') expect(testobj.key).to eq('foo') expect(testobj.value).to eq('42') end it 'should return string even when input looks like a float' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)42.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)42.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq('42.15') end it 'should return string even when input looks like a boolean' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)true') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(string)true') expect(testobj.key).to eq('foo') expect(testobj.value).to eq('true') end it 'shouuld pass through a nil with no argument' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(nil)') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(nil)') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(nil) end it 'should pass through a nil with superfluous argument' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=(nil)blahblahblah') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=(nil)blahblahblah') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(nil) end @@ -180,79 +181,79 @@ context 'with proper guessed string input' do describe '#new' do it 'should pass through a string' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=chicken') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=chicken') expect(testobj.key).to eq('foo') expect(testobj.value).to eq('chicken') end it 'should pass through an empty string' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=') expect(testobj.key).to eq('foo') expect(testobj.value).to eq('') end it 'should pass through a multi-line string' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new("foo=foo\nbar") + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new("foo=foo\nbar") expect(testobj.key).to eq('foo') expect(testobj.value).to eq("foo\nbar") end it 'should pass through a positive integer' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=42') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=42') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(42) end it 'should pass through a negative integer' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=-42') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=-42') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(-42) end it 'should pass through a positive float' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=42.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=42.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(42.15) end it 'should pass through a negative float' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=-42.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=-42.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(-42.15) end it 'should pass through a positive float with no leading digit' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(0.15) end it 'should pass through a negative float with no leading digit' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=-.15') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=-.15') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(-0.15) end it 'should handle true boolean' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=true') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=true') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(true) end it 'should handle true boolean case-insensitive' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=TrUe') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=TrUe') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(true) end it 'should handle false boolean' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=false') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=false') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(false) end it 'should handle false boolean case-insensitive' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new('foo=FaLsE') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new('foo=FaLsE') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(false) end @@ -262,32 +263,32 @@ context 'with non-string input' do describe '#new' do it 'should pass through a fixnum without manipulation' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(42, 'foo') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new(42, 'foo') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(42) end it 'should pass through a float without manipulation' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(42.15, 'foo') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new(42.15, 'foo') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(42.15) end it 'should pass through a boolean without manipulation' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(false, 'foo') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new(false, 'foo') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(false) end it 'should pass through a nil without manipulation' do - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(nil, 'foo') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new(nil, 'foo') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(nil) end it 'should pass through a hash without manipulation' do arg = { 'foo' => 'bar', 'baz' => [1, 2, 3, 4, 5] } - testobj = OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride.new(arg, 'foo') + testobj = OctocatalogDiff::Cli::Helpers::FactOverride.new(arg, 'foo') expect(testobj.key).to eq('foo') expect(testobj.value).to eq(arg) end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/basedir_spec.rb b/spec/octocatalog-diff/tests/cli/options/basedir_spec.rb similarity index 94% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/basedir_spec.rb rename to spec/octocatalog-diff/tests/cli/options/basedir_spec.rb index 0901b530..8f0e5d85 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/basedir_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/basedir_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_basedir' do it 'should handle --basedir with existing path' do dirpath = OctocatalogDiff::Spec.fixture_path('facts') diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_current_spec.rb b/spec/octocatalog-diff/tests/cli/options/bootstrap_current_spec.rb similarity index 83% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_current_spec.rb rename to spec/octocatalog-diff/tests/cli/options/bootstrap_current_spec.rb index cece5c8e..56f0bd91 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_current_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/bootstrap_current_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_bootstrap_current' do it 'should handle --bootstrap-current' do result = run_optparse(['--bootstrap-current']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_environment_spec.rb b/spec/octocatalog-diff/tests/cli/options/bootstrap_environment_spec.rb similarity index 97% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_environment_spec.rb rename to spec/octocatalog-diff/tests/cli/options/bootstrap_environment_spec.rb index 784c9f62..5fc21686 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_environment_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/bootstrap_environment_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_bootstrap_environment' do it 'should not set options[:bootstrap_environment] if no environment variables are set' do result = run_optparse(['--bootstrap-script', 'my-bootstrap-script']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_script_spec.rb b/spec/octocatalog-diff/tests/cli/options/bootstrap_script_spec.rb similarity index 86% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_script_spec.rb rename to spec/octocatalog-diff/tests/cli/options/bootstrap_script_spec.rb index 549d9afa..2ee00608 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_script_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/bootstrap_script_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_bootstrap_script' do it 'should set options[:bootstrap_script]' do result = run_optparse(['--bootstrap-script', 'my-bootstrap-script']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_then_exit_spec.rb b/spec/octocatalog-diff/tests/cli/options/bootstrap_then_exit_spec.rb similarity index 83% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_then_exit_spec.rb rename to spec/octocatalog-diff/tests/cli/options/bootstrap_then_exit_spec.rb index 720f86e7..1b765e83 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrap_then_exit_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/bootstrap_then_exit_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_bootstrap_then_exit' do it 'should handle --bootstrap-then-exit' do result = run_optparse(['--bootstrap-then-exit']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrapped_dirs_spec.rb b/spec/octocatalog-diff/tests/cli/options/bootstrapped_dirs_spec.rb similarity index 96% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrapped_dirs_spec.rb rename to spec/octocatalog-diff/tests/cli/options/bootstrapped_dirs_spec.rb index 0ac08cbe..2dd1a534 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/bootstrapped_dirs_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/bootstrapped_dirs_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_bootstrapped_dirs' do before(:all) do @tmpdir = Dir.mktmpdir diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/cached_master_dir_spec.rb b/spec/octocatalog-diff/tests/cli/options/cached_master_dir_spec.rb similarity index 95% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/cached_master_dir_spec.rb rename to spec/octocatalog-diff/tests/cli/options/cached_master_dir_spec.rb index a47d8b36..ba917ef7 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/cached_master_dir_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/cached_master_dir_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_cached_master_dir' do before(:each) do @tmpdir = Dir.mktmpdir diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/catalog_only_spec.rb b/spec/octocatalog-diff/tests/cli/options/catalog_only_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/catalog_only_spec.rb rename to spec/octocatalog-diff/tests/cli/options/catalog_only_spec.rb index f371164b..eaac6bd1 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/catalog_only_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/catalog_only_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_catalog_only' do include_examples 'true/false option', 'catalog-only', :catalog_only end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/color_spec.rb b/spec/octocatalog-diff/tests/cli/options/color_spec.rb similarity index 87% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/color_spec.rb rename to spec/octocatalog-diff/tests/cli/options/color_spec.rb index 9972b381..2c76e926 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/color_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/color_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_color' do it 'should set colors off for output to file' do target = File.absolute_path(__FILE__) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/command_line_spec.rb b/spec/octocatalog-diff/tests/cli/options/command_line_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/command_line_spec.rb rename to spec/octocatalog-diff/tests/cli/options/command_line_spec.rb index 62b6d169..350c3d05 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/command_line_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/command_line_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_command_line' do include_examples 'global array option', 'command-line', :command_line end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/compare_file_text_spec.rb b/spec/octocatalog-diff/tests/cli/options/compare_file_text_spec.rb similarity index 78% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/compare_file_text_spec.rb rename to spec/octocatalog-diff/tests/cli/options/compare_file_text_spec.rb index 952ed7aa..40f259a6 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/compare_file_text_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/compare_file_text_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_compare_file_text' do include_examples 'true/false option', 'compare-file-text', :compare_file_text end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/create_symlinks_spec.rb b/spec/octocatalog-diff/tests/cli/options/create_symlinks_spec.rb similarity index 78% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/create_symlinks_spec.rb rename to spec/octocatalog-diff/tests/cli/options/create_symlinks_spec.rb index 68bee765..e2933681 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/create_symlinks_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/create_symlinks_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_create_symlinks' do include_examples 'global array option', 'create-symlinks', :create_symlinks end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/debug_bootstrap_spec.rb b/spec/octocatalog-diff/tests/cli/options/debug_bootstrap_spec.rb similarity index 83% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/debug_bootstrap_spec.rb rename to spec/octocatalog-diff/tests/cli/options/debug_bootstrap_spec.rb index 4390ea0c..b2ee5906 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/debug_bootstrap_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/debug_bootstrap_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_debug_bootstrap' do it 'should handle --debug-bootstrap' do result = run_optparse(['--debug-bootstrap']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/debug_spec.rb b/spec/octocatalog-diff/tests/cli/options/debug_spec.rb similarity index 74% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/debug_spec.rb rename to spec/octocatalog-diff/tests/cli/options/debug_spec.rb index 7bdb1bee..5093d494 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/debug_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/debug_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_debug' do include_examples 'true/false option', 'debug', :debug end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/display_datatype_changes_spec.rb b/spec/octocatalog-diff/tests/cli/options/display_datatype_changes_spec.rb similarity index 80% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/display_datatype_changes_spec.rb rename to spec/octocatalog-diff/tests/cli/options/display_datatype_changes_spec.rb index f7650da7..3be74177 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/display_datatype_changes_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/display_datatype_changes_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_display_datatype_changes' do include_examples 'true/false option', 'display-datatype-changes', :display_datatype_changes end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/display_detail_add_spec.rb b/spec/octocatalog-diff/tests/cli/options/display_detail_add_spec.rb similarity index 78% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/display_detail_add_spec.rb rename to spec/octocatalog-diff/tests/cli/options/display_detail_add_spec.rb index 05a9cc5a..b643c0f7 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/display_detail_add_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/display_detail_add_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_display_detail_add' do include_examples 'true/false option', 'display-detail-add', :display_detail_add end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/display_source_file_line_spec.rb b/spec/octocatalog-diff/tests/cli/options/display_source_file_line_spec.rb similarity index 79% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/display_source_file_line_spec.rb rename to spec/octocatalog-diff/tests/cli/options/display_source_file_line_spec.rb index 68eaebbe..167dd186 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/display_source_file_line_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/display_source_file_line_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_display_source_file_line' do include_examples 'true/false option', 'display-source', :display_source_file_line end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/enc_spec.rb b/spec/octocatalog-diff/tests/cli/options/enc_spec.rb similarity index 97% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/enc_spec.rb rename to spec/octocatalog-diff/tests/cli/options/enc_spec.rb index 32e36f02..b283a033 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/enc_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/enc_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do context 'with a relative path' do describe '#opt_enc' do let(:basedir) { OctocatalogDiff::Spec.fixture_path('configs') } diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/environment_spec.rb b/spec/octocatalog-diff/tests/cli/options/environment_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/environment_spec.rb rename to spec/octocatalog-diff/tests/cli/options/environment_spec.rb index ff2c1abb..96daaf7e 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/environment_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/environment_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_environment' do include_examples 'global string option', 'environment', :environment end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/existing_catalogs_spec.rb b/spec/octocatalog-diff/tests/cli/options/existing_catalogs_spec.rb similarity index 94% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/existing_catalogs_spec.rb rename to spec/octocatalog-diff/tests/cli/options/existing_catalogs_spec.rb index 30d0f379..1814c1be 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/existing_catalogs_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/existing_catalogs_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_existing_catalogs' do before(:all) do @cat = OctocatalogDiff::Spec.fixture_path('catalogs/tiny-catalog.json') diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/fact_file_spec.rb b/spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb similarity index 97% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/fact_file_spec.rb rename to spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb index 4abbc700..11aa471d 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/fact_file_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/fact_file_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_fact_file' do it 'should read facts from a YAML file' do fact_file = OctocatalogDiff::Spec.fixture_path('facts/facts.yaml') diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/fact_override_spec.rb b/spec/octocatalog-diff/tests/cli/options/fact_override_spec.rb similarity index 89% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/fact_override_spec.rb rename to spec/octocatalog-diff/tests/cli/options/fact_override_spec.rb index 03d12257..e16fccdf 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/fact_override_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/fact_override_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_fact_override' do include_examples 'global array option', 'fact-override', :fact_override_in diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/facts_terminus_spec.rb b/spec/octocatalog-diff/tests/cli/options/facts_terminus_spec.rb similarity index 90% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/facts_terminus_spec.rb rename to spec/octocatalog-diff/tests/cli/options/facts_terminus_spec.rb index 0ab50f50..0594d57c 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/facts_terminus_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/facts_terminus_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_facts_terminus' do valid = %w(yaml facter) valid.each do |fmt| diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/filters_spec.rb b/spec/octocatalog-diff/tests/cli/options/filters_spec.rb similarity index 90% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/filters_spec.rb rename to spec/octocatalog-diff/tests/cli/options/filters_spec.rb index c7c4ef10..09bb8564 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/filters_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/filters_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_ignore_equivalent_yaml_files' do it 'should accept comma delimited parameters for --filters' do result = run_optparse(['--filters', 'fizzbuzz,barbuzz']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/from_puppetdb_spec.rb b/spec/octocatalog-diff/tests/cli/options/from_puppetdb_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/from_puppetdb_spec.rb rename to spec/octocatalog-diff/tests/cli/options/from_puppetdb_spec.rb index 935ebadb..2a464d7c 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/from_puppetdb_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/from_puppetdb_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_from_puppetdb' do include_examples 'true/false option', 'from-puppetdb', :from_puppetdb end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/header_spec.rb b/spec/octocatalog-diff/tests/cli/options/header_spec.rb similarity index 97% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/header_spec.rb rename to spec/octocatalog-diff/tests/cli/options/header_spec.rb index 107d4b6a..b6edeb87 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/header_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/header_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_header' do it 'should error when --header and --no-header are both specified' do expect { run_optparse(['--header', 'fizzbuzz', '--no-header']) }.to raise_error(ArgumentError) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_config_spec.rb b/spec/octocatalog-diff/tests/cli/options/hiera_config_spec.rb similarity index 94% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_config_spec.rb rename to spec/octocatalog-diff/tests/cli/options/hiera_config_spec.rb index 8b48e07b..9ae97c4e 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_config_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/hiera_config_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_hiera_config' do it 'should handle --hiera-config' do result = run_optparse(['--hiera-config', 'adflkadfs']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_path_spec.rb b/spec/octocatalog-diff/tests/cli/options/hiera_path_spec.rb similarity index 96% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_path_spec.rb rename to spec/octocatalog-diff/tests/cli/options/hiera_path_spec.rb index d186964b..e39cc9da 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_path_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/hiera_path_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_hiera_path' do it 'should set options[:hiera_path] when relative path is specified' do result = run_optparse(['--hiera-path', 'foo/bar/baz']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_path_strip_spec.rb b/spec/octocatalog-diff/tests/cli/options/hiera_path_strip_spec.rb similarity index 96% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_path_strip_spec.rb rename to spec/octocatalog-diff/tests/cli/options/hiera_path_strip_spec.rb index b4c5e0d6..acde4b1c 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hiera_path_strip_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/hiera_path_strip_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_hiera_path_strip' do it 'should set options[:hiera_path_strip] when path is specified' do result = run_optparse(['--hiera-path-strip', '/var/tmp/foo/bar/baz']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hostname_spec.rb b/spec/octocatalog-diff/tests/cli/options/hostname_spec.rb similarity index 85% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/hostname_spec.rb rename to spec/octocatalog-diff/tests/cli/options/hostname_spec.rb index 3da914b8..2fe898b1 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/hostname_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/hostname_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_hostname' do it 'should set options[:node] when hostname is set with short form' do result = run_optparse(['-n', 'octonode.rspec']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_attr_spec.rb b/spec/octocatalog-diff/tests/cli/options/ignore_attr_spec.rb similarity index 95% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_attr_spec.rb rename to spec/octocatalog-diff/tests/cli/options/ignore_attr_spec.rb index 431cebe3..71b07dd1 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_attr_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/ignore_attr_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_ignore_attr' do it 'should add one additional ignore' do result = run_optparse(['--ignore-attr', 'attr1']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_spec.rb b/spec/octocatalog-diff/tests/cli/options/ignore_spec.rb similarity index 97% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_spec.rb rename to spec/octocatalog-diff/tests/cli/options/ignore_spec.rb index fcd85c65..8dae55fa 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/ignore_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_ignore' do it 'should add one additional ignore' do result = run_optparse(['--ignore', 'Foo[Bar]']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_tags_spec.rb b/spec/octocatalog-diff/tests/cli/options/ignore_tags_spec.rb similarity index 96% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_tags_spec.rb rename to spec/octocatalog-diff/tests/cli/options/ignore_tags_spec.rb index 475007ab..c59f77d7 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/ignore_tags_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/ignore_tags_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_ignore_tags' do it 'should error when --ignore-tags and --no-ignore-tags are both specified' do expect { run_optparse(['--ignore-tags', 'fizzbuzz', '--no-ignore-tags']) }.to raise_error(ArgumentError) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/include_tags_spec.rb b/spec/octocatalog-diff/tests/cli/options/include_tags_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/include_tags_spec.rb rename to spec/octocatalog-diff/tests/cli/options/include_tags_spec.rb index bbc4f1d4..f2294c9a 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/include_tags_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/include_tags_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_include_tags' do include_examples 'true/false option', 'include-tags', :include_tags end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/master_cache_branch_spec.rb b/spec/octocatalog-diff/tests/cli/options/master_cache_branch_spec.rb similarity index 85% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/master_cache_branch_spec.rb rename to spec/octocatalog-diff/tests/cli/options/master_cache_branch_spec.rb index ab0fcd18..b38e23c5 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/master_cache_branch_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/master_cache_branch_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppet_master_cache_branch' do it 'should handle --puppet-master-api-version with a string arg' do result = run_optparse(['--master-cache-branch', 'foobar']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/output_file_spec.rb b/spec/octocatalog-diff/tests/cli/options/output_file_spec.rb similarity index 93% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/output_file_spec.rb rename to spec/octocatalog-diff/tests/cli/options/output_file_spec.rb index b55793ae..aa2aaf09 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/output_file_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/output_file_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_output_file' do it 'should set absolute path for output to file' do target = File.absolute_path(__FILE__) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/output_format_spec.rb b/spec/octocatalog-diff/tests/cli/options/output_format_spec.rb similarity index 90% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/output_format_spec.rb rename to spec/octocatalog-diff/tests/cli/options/output_format_spec.rb index ec787774..0a8c7a84 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/output_format_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/output_format_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_output_format' do valid = %w(text json) valid.each do |fmt| diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/parallel_spec.rb b/spec/octocatalog-diff/tests/cli/options/parallel_spec.rb similarity index 75% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/parallel_spec.rb rename to spec/octocatalog-diff/tests/cli/options/parallel_spec.rb index 9b10256c..48ed8523 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/parallel_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/parallel_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_parallel' do include_examples 'true/false option', 'parallel', :parallel end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/parser_spec.rb b/spec/octocatalog-diff/tests/cli/options/parser_spec.rb similarity index 97% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/parser_spec.rb rename to spec/octocatalog-diff/tests/cli/options/parser_spec.rb index 0c5f7abf..10b5b61e 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/parser_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/parser_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_parser' do @parser_args = ['--parser', '--parser-from', '--parser-to'] @supported_parsers = %w(default future) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pass_env_vars_spec.rb b/spec/octocatalog-diff/tests/cli/options/pass_env_vars_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/pass_env_vars_spec.rb rename to spec/octocatalog-diff/tests/cli/options/pass_env_vars_spec.rb index e28dca20..bdc3628e 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pass_env_vars_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/pass_env_vars_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_pass_env_vars' do it 'should add one pass environment variable' do result = run_optparse(['--pass-env-vars', 'FOO']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_ca_spec.rb b/spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_ca_spec.rb similarity index 91% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_ca_spec.rb rename to spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_ca_spec.rb index d299f94a..1879d1e3 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_ca_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_ca_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_pe_enc_ssl_ca' do it 'should handle --pe-enc-ssl-ca with a valid file' do result = run_optparse(['--pe-enc-ssl-ca', OctocatalogDiff::Spec.fixture_path('ssl/generated/ca.crt')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_client_cert_spec.rb b/spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_client_cert_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_client_cert_spec.rb rename to spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_client_cert_spec.rb index 97513dfb..fdad1cc7 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_client_cert_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_client_cert_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_pe_enc_ssl_client_cert' do it 'should handle --pe-enc-ssl-client-cert with a valid file' do result = run_optparse(['--pe-enc-ssl-client-cert', OctocatalogDiff::Spec.fixture_path('ssl/generated/client.crt')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_client_key_spec.rb b/spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_client_key_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_client_key_spec.rb rename to spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_client_key_spec.rb index 49ecb446..a976c7ad 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_ssl_client_key_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/pe_enc_ssl_client_key_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_pe_enc_ssl_client_key' do it 'should handle --pe-enc-ssl-client-key with a valid file' do result = run_optparse(['--pe-enc-ssl-client-key', OctocatalogDiff::Spec.fixture_path('ssl/generated/client.key')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_token_file_spec.rb b/spec/octocatalog-diff/tests/cli/options/pe_enc_token_file_spec.rb similarity index 96% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_token_file_spec.rb rename to spec/octocatalog-diff/tests/cli/options/pe_enc_token_file_spec.rb index 2bacfa20..c28e5fcc 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_token_file_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/pe_enc_token_file_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do context 'with a relative path' do describe '#opt_pe_enc_token_file' do let(:basedir) { OctocatalogDiff::Spec.fixture_path('configs') } diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_token_spec.rb b/spec/octocatalog-diff/tests/cli/options/pe_enc_token_spec.rb similarity index 84% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_token_spec.rb rename to spec/octocatalog-diff/tests/cli/options/pe_enc_token_spec.rb index fbe236e2..e6296823 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_token_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/pe_enc_token_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_pe_enc_token' do it 'should handle --pe-enc-token with a string arg' do result = run_optparse(['--pe-enc-token', 'foobar']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_url_spec.rb b/spec/octocatalog-diff/tests/cli/options/pe_enc_url_spec.rb similarity index 91% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_url_spec.rb rename to spec/octocatalog-diff/tests/cli/options/pe_enc_url_spec.rb index 44169833..a69258da 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/pe_enc_url_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/pe_enc_url_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_pe_enc_url' do it 'should handle --pe-enc-url with HTTPS URL' do result = run_optparse(['--pe-enc-url', 'https://pe-enc.your-domain-here.com:4433/classifier-api']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/preserve_environments_spec.rb b/spec/octocatalog-diff/tests/cli/options/preserve_environments_spec.rb similarity index 79% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/preserve_environments_spec.rb rename to spec/octocatalog-diff/tests/cli/options/preserve_environments_spec.rb index b078bdff..0b95a4ec 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/preserve_environments_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/preserve_environments_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_preserve_environments' do include_examples 'true/false option', 'preserve-environments', :preserve_environments end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_binary_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppet_binary_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_binary_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppet_binary_spec.rb index 313e3c47..fec63ec0 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_binary_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppet_binary_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppet_binary' do include_examples 'global string option', 'puppet-binary', :puppet_binary end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_api_version_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppet_master_api_version_spec.rb similarity index 96% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_api_version_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppet_master_api_version_spec.rb index 8e4e2c91..f90c8c36 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_api_version_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppet_master_api_version_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppet_master_api_version' do it 'should handle --puppet-master-api-version with API version 2 as a string' do result = run_optparse(['--puppet-master-api-version', '2']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppet_master_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppet_master_spec.rb index 562ee8b9..96ecca3d 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppet_master_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppet_master' do include_examples 'global string option', 'puppet-master', :puppet_master end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_ca_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_ca_spec.rb similarity index 96% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_ca_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_ca_spec.rb index 1891ef15..11c4a149 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_ca_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_ca_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppet_master_ssl_ca' do it 'should handle --puppet-master-ssl-ca with a valid file' do result = run_optparse(['--puppet-master-ssl-ca', OctocatalogDiff::Spec.fixture_path('ssl/generated/ca.crt')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_client_cert_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_client_cert_spec.rb similarity index 95% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_client_cert_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_client_cert_spec.rb index cdb5c1a3..53573bce 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_client_cert_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_client_cert_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do let(:fixture) { OctocatalogDiff::Spec.fixture_path('ssl/generated/client.crt') } let(:answer) { File.read(fixture) } diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_client_key_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_client_key_spec.rb similarity index 95% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_client_key_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_client_key_spec.rb index 0b82fdb3..4705b278 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppet_master_ssl_client_key_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppet_master_ssl_client_key_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do let(:fixture) { OctocatalogDiff::Spec.fixture_path('ssl/generated/client.key') } let(:answer) { File.read(fixture) } diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_api_version_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_api_version_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_api_version_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppetdb_api_version_spec.rb index b64f6b9b..1624b430 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_api_version_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_api_version_spec.rb @@ -1,6 +1,6 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppetdb_api_version' do it 'should handle --puppetdb-api-version with API version 3' do result = run_optparse(['--puppetdb-api-version', '3']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_ca_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_ca_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_ca_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_ca_spec.rb index 3d60c2f3..2ff4729e 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_ca_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_ca_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppetdb_ssl_ca' do it 'should handle --puppetdb-ssl-ca with a valid file' do result = run_optparse(['--puppetdb-ssl-ca', OctocatalogDiff::Spec.fixture_path('ssl/generated/ca.crt')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_cert_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_cert_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_cert_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_cert_spec.rb index 48ed3d46..16d441ef 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_cert_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_cert_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppetdb_ssl_client_cert' do it 'should handle --puppetdb-ssl-client-cert with a valid file' do result = run_optparse(['--puppetdb-ssl-client-cert', OctocatalogDiff::Spec.fixture_path('ssl/generated/client.crt')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_key_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_key_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_key_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_key_spec.rb index 2575e2c0..53097530 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_key_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_key_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppetdb_ssl_client_key' do it 'should handle --puppetdb-ssl-client-key with a valid file' do result = run_optparse(['--puppetdb-ssl-client-key', OctocatalogDiff::Spec.fixture_path('ssl/generated/client.key')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_password_file_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_password_file_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_password_file_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_password_file_spec.rb index c57f0c44..afc5d7ff 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_password_file_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_password_file_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppetdb_ssl_client_password_file' do it 'should handle --puppetdb-ssl-client-password-file with a valid file' do result = run_optparse(['--puppetdb-ssl-client-password-file', OctocatalogDiff::Spec.fixture_path('facts/facts.yaml')]) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_password_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_password_spec.rb similarity index 86% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_password_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_password_spec.rb index 9e6d5c97..7de03a07 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_ssl_client_password_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_ssl_client_password_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppetdb_ssl_client_password' do it 'should handle --puppetdb-ssl-client-password with valid text' do result = run_optparse(['--puppetdb-ssl-client-password', 'secret']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_url_spec.rb b/spec/octocatalog-diff/tests/cli/options/puppetdb_url_spec.rb similarity index 93% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_url_spec.rb rename to spec/octocatalog-diff/tests/cli/options/puppetdb_url_spec.rb index 7bfc8c3a..adc9c739 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/puppetdb_url_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/puppetdb_url_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_puppetdb_url' do it 'should handle --puppetdb-url with HTTP URL' do result = run_optparse(['--puppetdb-url', 'http://puppetdb.your-domain-here.com:8080']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/quiet_spec.rb b/spec/octocatalog-diff/tests/cli/options/quiet_spec.rb similarity index 74% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/quiet_spec.rb rename to spec/octocatalog-diff/tests/cli/options/quiet_spec.rb index e191c358..6eb62dd4 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/quiet_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/quiet_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_quiet' do include_examples 'true/false option', 'quiet', :quiet end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/retry_failed_catalog_spec.rb b/spec/octocatalog-diff/tests/cli/options/retry_failed_catalog_spec.rb similarity index 92% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/retry_failed_catalog_spec.rb rename to spec/octocatalog-diff/tests/cli/options/retry_failed_catalog_spec.rb index 773fa389..5a40c6b0 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/retry_failed_catalog_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/retry_failed_catalog_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_retry_failed_catalog' do it 'should handle --retry-failed-catalog with integer' do result = run_optparse(['--retry-failed-catalog', '42']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/safe_to_delete_cached_master_dir_spec.rb b/spec/octocatalog-diff/tests/cli/options/safe_to_delete_cached_master_dir_spec.rb similarity index 93% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/safe_to_delete_cached_master_dir_spec.rb rename to spec/octocatalog-diff/tests/cli/options/safe_to_delete_cached_master_dir_spec.rb index 0e2d3425..b01e95d4 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/safe_to_delete_cached_master_dir_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/safe_to_delete_cached_master_dir_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_safe_to_delete_cached_master_dir' do it 'should be set to a directory path' do path = File.join(File.dirname(__FILE__), 'cached-master') diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/storeconfigs_spec.rb b/spec/octocatalog-diff/tests/cli/options/storeconfigs_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/storeconfigs_spec.rb rename to spec/octocatalog-diff/tests/cli/options/storeconfigs_spec.rb index 85a6e7bd..6bfe0f3f 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/storeconfigs_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/storeconfigs_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_storeconfigs' do include_examples 'true/false option', 'storeconfigs', :storeconfigs end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/suppress_absent_file_details_spec.rb b/spec/octocatalog-diff/tests/cli/options/suppress_absent_file_details_spec.rb similarity index 80% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/suppress_absent_file_details_spec.rb rename to spec/octocatalog-diff/tests/cli/options/suppress_absent_file_details_spec.rb index d97d6bb9..de32b463 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/suppress_absent_file_details_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/suppress_absent_file_details_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_suppress_absent_file_details' do include_examples 'true/false option', 'suppress-absent-file-details', :suppress_absent_file_details end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/to_from_branch_spec.rb b/spec/octocatalog-diff/tests/cli/options/to_from_branch_spec.rb similarity index 90% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/to_from_branch_spec.rb rename to spec/octocatalog-diff/tests/cli/options/to_from_branch_spec.rb index 839c5dd5..3afa4e1e 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/to_from_branch_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/to_from_branch_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_to_from_branch' do it 'should set options[:from_env]' do result = run_optparse(['-f', 'origin/rspec-from-branch']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options/validate_references_spec.rb b/spec/octocatalog-diff/tests/cli/options/validate_references_spec.rb similarity index 95% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options/validate_references_spec.rb rename to spec/octocatalog-diff/tests/cli/options/validate_references_spec.rb index 3c65f2ce..77c46fa2 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options/validate_references_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options/validate_references_spec.rb @@ -2,7 +2,7 @@ require_relative '../options_helper' -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#opt_validate_references' do it 'should accept an array of arguments' do result = run_optparse(['--validate-references', 'before', '--validate-references', 'require']) diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options_helper.rb b/spec/octocatalog-diff/tests/cli/options_helper.rb similarity index 94% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options_helper.rb rename to spec/octocatalog-diff/tests/cli/options_helper.rb index f010afbf..810e1970 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options_helper.rb +++ b/spec/octocatalog-diff/tests/cli/options_helper.rb @@ -1,5 +1,8 @@ -require_relative '../../spec_helper' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/options') +# frozen_string_literal: true + +require_relative '../spec_helper' + +require OctocatalogDiff::Spec.require_path('/cli/options') # We actually call the top-level "parse_options" which will call all of # the methods. This test therefore ensures that (a) parse_options contains @@ -8,7 +11,7 @@ # @param options_in [Hash] Default options # @return [Hash] Parsed options def run_optparse(argv = [], options_in = {}) - OctocatalogDiff::CatalogDiff::Cli::Options.parse_options(argv, options_in) + OctocatalogDiff::Cli::Options.parse_options(argv, options_in) end # Many boolean command line flags have very similar tests. Specifying --option sets diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/options_spec.rb b/spec/octocatalog-diff/tests/cli/options_spec.rb similarity index 75% rename from spec/octocatalog-diff/tests/catalog-diff/cli/options_spec.rb rename to spec/octocatalog-diff/tests/cli/options_spec.rb index f8352ffe..527050dc 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/options_spec.rb +++ b/spec/octocatalog-diff/tests/cli/options_spec.rb @@ -1,15 +1,15 @@ # frozen_string_literal: true -require_relative '../../spec_helper' +require_relative '../spec_helper' require_relative 'options_helper' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/options') +require OctocatalogDiff::Spec.require_path('/cli/options') require OctocatalogDiff::Spec.require_path('/version') -describe OctocatalogDiff::CatalogDiff::Cli::Options do +describe OctocatalogDiff::Cli::Options do describe '#option_globally_or_per_branch' do it 'should raise an error if an invalid data type is passed' do expect do - OctocatalogDiff::CatalogDiff::Cli::Options.option_globally_or_per_branch(datatype: {}) + OctocatalogDiff::Cli::Options.option_globally_or_per_branch(datatype: {}) end.to raise_error(ArgumentError) end end diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/printer_spec.rb b/spec/octocatalog-diff/tests/cli/printer_spec.rb similarity index 86% rename from spec/octocatalog-diff/tests/catalog-diff/cli/printer_spec.rb rename to spec/octocatalog-diff/tests/cli/printer_spec.rb index e763d856..ab97ba16 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/printer_spec.rb +++ b/spec/octocatalog-diff/tests/cli/printer_spec.rb @@ -1,12 +1,14 @@ # frozen_string_literal: true -require_relative '../../spec_helper' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/printer') +require_relative '../spec_helper' + +require OctocatalogDiff::Spec.require_path('/cli/printer') +require OctocatalogDiff::Spec.require_path('/errors') require 'json' require 'tempfile' -describe OctocatalogDiff::CatalogDiff::Cli::Printer do +describe OctocatalogDiff::Cli::Printer do describe '#printer' do before(:all) do @diff = JSON.parse(File.read(OctocatalogDiff::Spec.fixture_path('diffs/catalog-1-vs-catalog-2.json'))) @@ -29,7 +31,7 @@ logger, logger_str = OctocatalogDiff::Spec.setup_logger # Run the method. Make sure it doesn't print anything to STDOUT. - testobj = OctocatalogDiff::CatalogDiff::Cli::Printer.new(opts, logger) + testobj = OctocatalogDiff::Cli::Printer.new(opts, logger) expect do _result = testobj.printer(@diff) end.not_to output.to_stdout @@ -59,10 +61,10 @@ logger, logger_str = OctocatalogDiff::Spec.setup_logger # Run the method. Make sure it raises the error. - testobj = OctocatalogDiff::CatalogDiff::Cli::Printer.new(opts, logger) + testobj = OctocatalogDiff::Cli::Printer.new(opts, logger) expect do _result = testobj.printer(@diff) - end.to raise_error(OctocatalogDiff::CatalogDiff::Cli::Printer::PrinterError) + end.to raise_error(OctocatalogDiff::Errors::PrinterError) # Make sure log messages are correct expect(logger_str.string).to match(/DEBUG -- : Generating non-colored text output/) @@ -79,7 +81,7 @@ logger, logger_str = OctocatalogDiff::Spec.setup_logger # Run the method. Make sure it prints to STDOUT. - testobj = OctocatalogDiff::CatalogDiff::Cli::Printer.new(opts, logger) + testobj = OctocatalogDiff::Cli::Printer.new(opts, logger) expect do _result = testobj.printer(@diff) end.to output(/Class\[Openssl::Package\]/).to_stdout diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli_spec.rb b/spec/octocatalog-diff/tests/cli_spec.rb similarity index 77% rename from spec/octocatalog-diff/tests/catalog-diff/cli_spec.rb rename to spec/octocatalog-diff/tests/cli_spec.rb index be1df526..c2fc227f 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli_spec.rb +++ b/spec/octocatalog-diff/tests/cli_spec.rb @@ -1,15 +1,17 @@ # frozen_string_literal: true -require_relative '../spec_helper' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli') +require_relative 'spec_helper' -describe OctocatalogDiff::CatalogDiff::Cli do +require OctocatalogDiff::Spec.require_path('/cli') +require OctocatalogDiff::Spec.require_path('/errors') + +describe OctocatalogDiff::Cli do describe '#parse_opts' do # There is more test coverage in cli/options for each specific # option that's recognized here. it 'should parse a basic option (in this case --hostname)' do argv = ['--hostname', 'octonode.rspec'] - result = OctocatalogDiff::CatalogDiff::Cli.parse_opts(argv) + result = OctocatalogDiff::Cli.parse_opts(argv) expect(result[:node]).to eq('octonode.rspec') end end @@ -32,12 +34,12 @@ # this writing are debug OFF and colored text ON. If those defaults have changed, # the remaining tests may be broken. logger, logger_str = OctocatalogDiff::Spec.setup_logger - result = OctocatalogDiff::CatalogDiff::Cli.cli(default_argv.dup, logger, {}) + result = OctocatalogDiff::Cli.cli(default_argv.dup, logger, {}) expect(result).to eq(0) expect(logger_str.string).not_to match(/DEBUG/) logger_str.truncate(0) - result2 = OctocatalogDiff::CatalogDiff::Cli.cli(default_argv.dup, logger, debug: true) + result2 = OctocatalogDiff::Cli.cli(default_argv.dup, logger, debug: true) expect(result2).to eq(0) expect(logger_str.string).to match(/DEBUG -- : Generating colored text output/) end @@ -45,7 +47,7 @@ it 'should accept an additional ARGV array with single element' do opts = { additional_argv: %w(--debug) } logger, logger_str = OctocatalogDiff::Spec.setup_logger - result = OctocatalogDiff::CatalogDiff::Cli.cli(default_argv, logger, opts) + result = OctocatalogDiff::Cli.cli(default_argv, logger, opts) expect(result).to eq(0) expect(logger_str.string).to match(/DEBUG -- : Generating colored text output/) end @@ -53,7 +55,7 @@ it 'should accept an additional ARGV array with multiple elements' do opts = { additional_argv: %w(--debug --no-color) } logger, logger_str = OctocatalogDiff::Spec.setup_logger - result = OctocatalogDiff::CatalogDiff::Cli.cli(default_argv, logger, opts) + result = OctocatalogDiff::Cli.cli(default_argv, logger, opts) expect(result).to eq(0) expect(logger_str.string).to match(/DEBUG -- : Generating non-colored text output/) end @@ -62,7 +64,7 @@ opts = { additional_argv: 'this is not an array' } logger, _logger_str = OctocatalogDiff::Spec.setup_logger expect do - OctocatalogDiff::CatalogDiff::Cli.cli(default_argv, logger, opts) + OctocatalogDiff::Cli.cli(default_argv, logger, opts) end.to raise_error(ArgumentError, /additional_argv must be array/) end end @@ -85,7 +87,7 @@ puppet_binary: OctocatalogDiff::Spec::PUPPET_BINARY, master_cache_branch: 'master' } - @result = OctocatalogDiff::CatalogDiff::Cli.cli(argv, logger, opts) + @result = OctocatalogDiff::Cli.cli(argv, logger, opts) end after(:all) do @@ -113,6 +115,15 @@ expect(@result).to eq(2) end end + + context 'with :bootstrap_then_exit set' do + it 'should construct catalog object and call bootstrap_then_exit' do + expect(OctocatalogDiff::Util::Catalogs).to receive(:new).and_return('xxx') + expect(described_class).to receive(:bootstrap_then_exit).and_return('yyy') + result = described_class.cli(['--bootstrap-then-exit']) + expect(result).to eq('yyy') + end + end end describe '#setup_logger' do @@ -149,44 +160,44 @@ describe '#setup_fact_overrides' do it 'should make no adjustments when there are no fact overrides' do options = {} - OctocatalogDiff::CatalogDiff::Cli.setup_fact_overrides(options) + OctocatalogDiff::Cli.setup_fact_overrides(options) expect(options).to eq({}) end it 'should skip fact overrides that are not arrays' do options = { from_fact_override_in: true } - OctocatalogDiff::CatalogDiff::Cli.setup_fact_overrides(options) + OctocatalogDiff::Cli.setup_fact_overrides(options) expect(options).to eq(from_fact_override_in: true) end it 'should skip fact overrides that are empty arrays' do options = { from_fact_override_in: [] } - OctocatalogDiff::CatalogDiff::Cli.setup_fact_overrides(options) + OctocatalogDiff::Cli.setup_fact_overrides(options) expect(options).to eq(from_fact_override_in: []) end it 'should adjust options with one fact override' do options = { from_fact_override_in: ['foo=bar'] } - OctocatalogDiff::CatalogDiff::Cli.setup_fact_overrides(options) + OctocatalogDiff::Cli.setup_fact_overrides(options) expect(options[:from_fact_override]).to be_a_kind_of(Array) expect(options[:from_fact_override].size).to eq(1) ffo = options[:from_fact_override].first - expect(ffo).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride) + expect(ffo).to be_a_kind_of(OctocatalogDiff::Cli::Helpers::FactOverride) expect(ffo.key).to eq('foo') expect(ffo.value).to eq('bar') end it 'should adjust options with multiple fact overrides' do options = { to_fact_override_in: ['foo=bar', 'baz=buzz'] } - OctocatalogDiff::CatalogDiff::Cli.setup_fact_overrides(options) + OctocatalogDiff::Cli.setup_fact_overrides(options) expect(options[:to_fact_override]).to be_a_kind_of(Array) expect(options[:to_fact_override].size).to eq(2) tfo = options[:to_fact_override] - expect(tfo[0]).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride) + expect(tfo[0]).to be_a_kind_of(OctocatalogDiff::Cli::Helpers::FactOverride) expect(tfo[0].key).to eq('foo') expect(tfo[0].value).to eq('bar') - expect(tfo[1]).to be_a_kind_of(OctocatalogDiff::CatalogDiff::Cli::Helpers::FactOverride) + expect(tfo[1]).to be_a_kind_of(OctocatalogDiff::Cli::Helpers::FactOverride) expect(tfo[1].key).to eq('baz') expect(tfo[1].value).to eq('buzz') end @@ -197,13 +208,13 @@ before(:each) do catalog_json = File.read(OctocatalogDiff::Spec.fixture_path('catalogs/tiny-catalog.json')) catalogs = { to: OctocatalogDiff::Catalog.new(json: catalog_json) } - d = double('OctocatalogDiff::CatalogDiff::Cli::Catalogs') - allow(OctocatalogDiff::CatalogDiff::Cli::Catalogs).to receive(:new).and_return(d) + d = double('OctocatalogDiff::Util::Catalogs') + allow(OctocatalogDiff::Util::Catalogs).to receive(:new).and_return(d) allow(d).to receive(:catalogs).and_return(catalogs) logger, @logger_str = OctocatalogDiff::Spec.setup_logger @tmpdir = Dir.mktmpdir catfile = File.join(@tmpdir, 'catalog.json') - @rc = OctocatalogDiff::CatalogDiff::Cli.catalog_only(logger, node: 'fizz', output_file: catfile) + @rc = OctocatalogDiff::Cli.catalog_only(logger, node: 'fizz', output_file: catfile) end after(:each) do @@ -213,7 +224,7 @@ it 'should store the catalog and exit' do expect(File.file?(File.join(@tmpdir, 'catalog.json'))).to eq(true) expect(@rc).to eq(0) - expect(@logger_str.string).to match(/Compiling catalog --catalog-only for fizz/) + expect(@logger_str.string).to match(/Compiling catalog for fizz/) expect(@logger_str.string).to match(%r{Wrote catalog to .*/catalog.json}) end end @@ -222,33 +233,33 @@ it 'should output to STDOUT and exit' do catalog_json = File.read(OctocatalogDiff::Spec.fixture_path('catalogs/tiny-catalog.json')) catalogs = { to: OctocatalogDiff::Catalog.new(json: catalog_json) } - d = double('OctocatalogDiff::CatalogDiff::Cli::Catalogs') - allow(OctocatalogDiff::CatalogDiff::Cli::Catalogs).to receive(:new).and_return(d) + d = double('OctocatalogDiff::Util::Catalogs') + allow(OctocatalogDiff::Util::Catalogs).to receive(:new).and_return(d) allow(d).to receive(:catalogs).and_return(catalogs) logger, logger_str = OctocatalogDiff::Spec.setup_logger rexp = Regexp.new('"document_type": "Catalog"') - expect { @rc = OctocatalogDiff::CatalogDiff::Cli.catalog_only(logger, node: 'fizz') }.to output(rexp).to_stdout + expect { @rc = OctocatalogDiff::Cli.catalog_only(logger, node: 'fizz') }.to output(rexp).to_stdout expect(@rc).to eq(0) - expect(logger_str.string).to match(/Compiling catalog --catalog-only for fizz/) + expect(logger_str.string).to match(/Compiling catalog for fizz/) end end end describe '#bootstrap_then_exit' do it 'should succeed and exit 0' do - d = double('OctocatalogDiff::CatalogDiff::Cli::Catalogs') + d = double('OctocatalogDiff::Util::Catalogs') allow(d).to receive(:bootstrap_then_exit) logger, logger_str = OctocatalogDiff::Spec.setup_logger - rc = OctocatalogDiff::CatalogDiff::Cli.bootstrap_then_exit(logger, d) + rc = OctocatalogDiff::Cli.bootstrap_then_exit(logger, d) expect(rc).to eq(0) expect(logger_str.string).to eq('') end it 'should fail and exit 1 if BootstrapError occurs' do - d = double('OctocatalogDiff::CatalogDiff::Cli::Catalogs') - allow(d).to receive(:bootstrap_then_exit).and_raise(OctocatalogDiff::CatalogDiff::Cli::Catalogs::BootstrapError, 'hello') + d = double('OctocatalogDiff::Util::Catalogs') + allow(d).to receive(:bootstrap_then_exit).and_raise(OctocatalogDiff::Errors::BootstrapError, 'hello') logger, logger_str = OctocatalogDiff::Spec.setup_logger - rc = OctocatalogDiff::CatalogDiff::Cli.bootstrap_then_exit(logger, d) + rc = OctocatalogDiff::Cli.bootstrap_then_exit(logger, d) expect(rc).to eq(1) expect(logger_str.string).to match(/--bootstrap-then-exit error: bootstrap failed \(hello\)/) end diff --git a/spec/octocatalog-diff/tests/facts/puppetdb_spec.rb b/spec/octocatalog-diff/tests/facts/puppetdb_spec.rb index c08bd310..9138a829 100644 --- a/spec/octocatalog-diff/tests/facts/puppetdb_spec.rb +++ b/spec/octocatalog-diff/tests/facts/puppetdb_spec.rb @@ -2,6 +2,7 @@ require_relative '../spec_helper' require_relative '../../mocks/puppetdb' +require OctocatalogDiff::Spec.require_path('/errors') require OctocatalogDiff::Spec.require_path('/facts/puppetdb') describe OctocatalogDiff::Facts::PuppetDB do @@ -27,7 +28,7 @@ node = 'fjoaewjroisajdfoisdjfaojeworjsdofjsdofawejr' expect do OctocatalogDiff::Facts::PuppetDB.fact_retriever(@opts, node) - end.to raise_error(OctocatalogDiff::Facts::FactRetrievalError) + end.to raise_error(OctocatalogDiff::Errors::FactRetrievalError) end end end @@ -79,31 +80,31 @@ let(:opts) { { puppetdb_url: 'https://mocked-puppetdb.somedomain.xyz:8081', node: 'valid-facts' } } let(:node) { 'valid-facts' } - it 'should handle OctocatalogDiff::PuppetDB::ConnectionError' do + it 'should handle OctocatalogDiff::Errors::PuppetDBConnectionError' do obj = double('OctocatalogDiff::PuppetDB') - allow(obj).to receive(:get).and_raise(OctocatalogDiff::PuppetDB::ConnectionError, 'test message') + allow(obj).to receive(:get).and_raise(OctocatalogDiff::Errors::PuppetDBConnectionError, 'test message') allow(OctocatalogDiff::PuppetDB).to receive(:new) { |*_arg| obj } expect do OctocatalogDiff::Facts::PuppetDB.fact_retriever(opts, node) - end.to raise_error(OctocatalogDiff::Facts::FactSourceError, /Fact retrieval failed \(.*ConnectionError\) \(test/) + end.to raise_error(OctocatalogDiff::Errors::FactSourceError, /Fact retrieval failed \(.*ConnectionError\) \(test/) end - it 'should handle OctocatalogDiff::PuppetDB::NotFoundError' do + it 'should handle OctocatalogDiff::Errors::PuppetDBNodeNotFoundError' do obj = double('OctocatalogDiff::PuppetDB') - allow(obj).to receive(:get).and_raise(OctocatalogDiff::PuppetDB::NotFoundError, 'test message') + allow(obj).to receive(:get).and_raise(OctocatalogDiff::Errors::PuppetDBNodeNotFoundError, 'test message') allow(OctocatalogDiff::PuppetDB).to receive(:new) { |*_arg| obj } expect do OctocatalogDiff::Facts::PuppetDB.fact_retriever(opts, node) - end.to raise_error(OctocatalogDiff::Facts::FactRetrievalError, /Node valid-facts not found in PuppetDB \(test/) + end.to raise_error(OctocatalogDiff::Errors::FactRetrievalError, /Node valid-facts not found in PuppetDB \(test/) end - it 'should handle OctocatalogDiff::PuppetDB::PuppetDBError' do + it 'should handle OctocatalogDiff::Errors::PuppetDBGenericError' do obj = double('OctocatalogDiff::PuppetDB') - allow(obj).to receive(:get).and_raise(OctocatalogDiff::PuppetDB::PuppetDBError, 'test message') + allow(obj).to receive(:get).and_raise(OctocatalogDiff::Errors::PuppetDBGenericError, 'test message') allow(OctocatalogDiff::PuppetDB).to receive(:new) { |*_arg| obj } expect do OctocatalogDiff::Facts::PuppetDB.fact_retriever(opts, node) - end.to raise_error(OctocatalogDiff::Facts::FactRetrievalError, /Fact retrieval failed for node valid-facts from PuppetDB/) + end.to raise_error(OctocatalogDiff::Errors::FactRetrievalError, /Fact retrieval failed for node valid-facts/) end end end diff --git a/spec/octocatalog-diff/tests/puppetdb_spec.rb b/spec/octocatalog-diff/tests/puppetdb_spec.rb index 4e598c07..9b2c9ecc 100644 --- a/spec/octocatalog-diff/tests/puppetdb_spec.rb +++ b/spec/octocatalog-diff/tests/puppetdb_spec.rb @@ -2,6 +2,7 @@ # Test the OctocatalogDiff::PuppetDB library require_relative 'spec_helper' +require OctocatalogDiff::Spec.require_path('/errors') require OctocatalogDiff::Spec.require_path('/puppetdb') require 'uri' @@ -174,7 +175,7 @@ def ssl_test(server_opts, opts = {}) puppetdb_url: 'http://127.0.0.1:1' } testobj = OctocatalogDiff::PuppetDB.new(opts) - expect { testobj.get('/foo') }.to raise_error(OctocatalogDiff::PuppetDB::ConnectionError) + expect { testobj.get('/foo') }.to raise_error(OctocatalogDiff::Errors::PuppetDBConnectionError) end it 'should timeout correctly' do @@ -187,7 +188,7 @@ def ssl_test(server_opts, opts = {}) } testobj = OctocatalogDiff::PuppetDB.new(opts) time_begin = Time.now.to_i - expect { testobj.get('/foo') }.to raise_error(OctocatalogDiff::PuppetDB::ConnectionError) + expect { testobj.get('/foo') }.to raise_error(OctocatalogDiff::Errors::PuppetDBConnectionError) time_end = Time.now.to_i expect(time_end - time_begin).to be <= 5 end @@ -463,17 +464,17 @@ def ssl_test(server_opts, opts = {}) it 'should handle 404 responses' do allow(OctocatalogDiff::Util::HTTParty).to receive(:get).and_return(code: 404, error: 'oh noez') - expect { @testobj.send(:get, '/foo') }.to raise_error(OctocatalogDiff::PuppetDB::NotFoundError, /oh noez/) + expect { @testobj.send(:get, '/foo') }.to raise_error(OctocatalogDiff::Errors::PuppetDBNodeNotFoundError, /oh noez/) end it 'should handle !=200, !=404 responses' do allow(OctocatalogDiff::Util::HTTParty).to receive(:get).and_return(code: 499, error: 'oh noez') - expect { @testobj.send(:get, '/foo') }.to raise_error(OctocatalogDiff::PuppetDB::PuppetDBError, /oh noez/) + expect { @testobj.send(:get, '/foo') }.to raise_error(OctocatalogDiff::Errors::PuppetDBGenericError, /oh noez/) end it 'should handle responses with :error' do allow(OctocatalogDiff::Util::HTTParty).to receive(:get).and_return(code: 200, error: 'oh noez') - expect { @testobj.send(:get, '/foo') }.to raise_error(OctocatalogDiff::PuppetDB::PuppetDBError, /500 - oh noez/) + expect { @testobj.send(:get, '/foo') }.to raise_error(OctocatalogDiff::Errors::PuppetDBGenericError, /500 - oh noez/) end it 'should handle unparseable responses' do diff --git a/spec/octocatalog-diff/tests/spec_helper.rb b/spec/octocatalog-diff/tests/spec_helper.rb index a58d1a03..568cfb0c 100644 --- a/spec/octocatalog-diff/tests/spec_helper.rb +++ b/spec/octocatalog-diff/tests/spec_helper.rb @@ -18,7 +18,7 @@ # external things are external add_filter '/lib/octocatalog-diff/external/' # simplecov doesn't properly show coverage inside optparse blocks - add_filter '/lib/octocatalog-diff/catalog-diff/cli/options/' + add_filter '/lib/octocatalog-diff/cli/options/' end end @@ -122,6 +122,25 @@ def self.array_contains_partial_array?(subject, lookup) false end + # Determine if a OctocatalogDiff::API::V1::Diff (or an array of those) matches a lookup hash. This + # returns true if the object (or any object in the array) matches all keys given in the lookup hash. + # @param diff_in [OctocatalogDiff::API::V1::Diff or Array] diff(s) to search + # @param lookup [Hash] Lookup hash + def self.diff_match?(diff_in, lookup) + diffs = [diff_in].flatten + diffs.each do |diff| + flag = true + lookup.to_h.each do |key, val| + unless diff.send(key) == val + flag = false + break + end + end + return true if flag + end + false + end + # Mock out a small shell script that tests for environment variable setting. # This takes the LAST command line argument, gets the value of that variable, # and prints it to STDERR. diff --git a/spec/octocatalog-diff/tests/catalog-diff/cli/catalogs_spec.rb b/spec/octocatalog-diff/tests/util/catalogs_spec.rb similarity index 86% rename from spec/octocatalog-diff/tests/catalog-diff/cli/catalogs_spec.rb rename to spec/octocatalog-diff/tests/util/catalogs_spec.rb index 145425a2..736a2d33 100644 --- a/spec/octocatalog-diff/tests/catalog-diff/cli/catalogs_spec.rb +++ b/spec/octocatalog-diff/tests/util/catalogs_spec.rb @@ -1,10 +1,12 @@ # frozen_string_literal: true -require_relative '../../spec_helper' -require_relative '../../../mocks/puppetdb' -require OctocatalogDiff::Spec.require_path('/catalog-diff/cli/catalogs') +require_relative '../spec_helper' +require_relative '../../mocks/puppetdb' + require OctocatalogDiff::Spec.require_path('/catalog') +require OctocatalogDiff::Spec.require_path('/errors') require OctocatalogDiff::Spec.require_path('/facts') +require OctocatalogDiff::Spec.require_path('/util/catalogs') require 'json' require 'open3' @@ -33,7 +35,7 @@ def valid? end # Here begin the tests -describe OctocatalogDiff::CatalogDiff::Cli::Catalogs do +describe OctocatalogDiff::Util::Catalogs do before(:all) do # These are the default options for all tests. @default_options = { @@ -90,8 +92,8 @@ def valid? it 'should error when neither directory is specified' do options = @default_options.merge(from_env: 'master') logger, logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) - expect { testobj.bootstrap_then_exit }.to raise_error(OctocatalogDiff::CatalogDiff::Cli::Catalogs::BootstrapError) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) + expect { testobj.bootstrap_then_exit }.to raise_error(OctocatalogDiff::Errors::BootstrapError) expect(logger_string.string).to match(%r{Specify one or more of --bootstrapped-from-dir / --bootstrapped-to-dir}) end @@ -103,9 +105,9 @@ def valid? tmpdir2 = Dir.mktmpdir options = @default_options.merge(basedir: tmpdir2, bootstrapped_from_dir: tmpdir1, from_env: 'asdfasdfasdf') logger, logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) - expect { testobj.bootstrap_then_exit }.to raise_error(OctocatalogDiff::CatalogDiff::Cli::Catalogs::BootstrapError) - expect(logger_string.string).to match(/ERROR -- : Bootstrap exception: Failed bootstrap_directory for from_dir/) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) + expect { testobj.bootstrap_then_exit }.to raise_error(OctocatalogDiff::Errors::BootstrapError) + expect(logger_string.string).to match(/DEBUG .+ Failed bootstrap from_dir/) ensure OctocatalogDiff::Spec.clean_up_tmpdir(tmpdir1) OctocatalogDiff::Spec.clean_up_tmpdir(tmpdir2) @@ -119,9 +121,9 @@ def valid? tmpdir1 = Dir.mktmpdir options = @default_options.merge(bootstrapped_from_dir: tmpdir1, from_env: 'asdfasdfasdf') logger, logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) - expect { testobj.bootstrap_then_exit }.to raise_error(OctocatalogDiff::CatalogDiff::Cli::Catalogs::BootstrapError) - expect(logger_string.string).to match(/ERROR -- : Bootstrap exception: Failed bootstrap_directory for from_dir/) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) + expect { testobj.bootstrap_then_exit }.to raise_error(OctocatalogDiff::Errors::BootstrapError) + expect(logger_string.string).to match(/DEBUG .+ Failed bootstrap from_dir/) ensure OctocatalogDiff::Spec.clean_up_tmpdir(tmpdir1) end @@ -136,13 +138,13 @@ def valid? bootstrapped_from_dir: @dir1, bootstrapped_to_dir: @dir2) logger, logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) path_save = ENV['PATH'] begin @bootstrap_error_message = nil ENV['PATH'] = '/usr/sbin:/sbin:/usr/bin:/bin:/usr/local/bin:/usr/local/sbin' testobj.bootstrap_then_exit - rescue OctocatalogDiff::CatalogDiff::Cli::Catalogs::BootstrapError => exc + rescue OctocatalogDiff::Errors::BootstrapError => exc @bootstrap_error_message = "BootstrapError #{exc}: #{logger_string.string}" ensure ENV['PATH'] = path_save @@ -194,9 +196,9 @@ def valid? pending 'bash, git, and/or tar are required for most tests' unless @has_tar options = @default_options.merge(enc: 'asdkfjlfjkalksdfads') logger, _logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) re = %r{ENC.*/asdkfjlfjkalksdfads wasn't found} - expect { testobj.catalogs }.to raise_error(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError, re) + expect { testobj.catalogs }.to raise_error(OctocatalogDiff::Errors::CatalogError, re) end end end @@ -207,9 +209,9 @@ def valid? pending 'bash, git, and/or tar are required for most tests' unless @has_tar options = @default_options.merge(hiera_config: 'asdkfjlfjkalksdfads') logger, _logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) re = %r{hiera.yaml.*/asdkfjlfjkalksdfads\) wasn't found} - expect { testobj.catalogs }.to raise_error(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError, re) + expect { testobj.catalogs }.to raise_error(OctocatalogDiff::Errors::CatalogError, re) end end end @@ -226,7 +228,7 @@ def valid? to_catalog: OctocatalogDiff::Spec.fixture_path('catalogs/tiny-catalog-2.json') ) logger, logger_string = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = testobj.catalogs test_val = result[:from].catalog_json.gsub(/\s+/, '') @@ -250,7 +252,7 @@ def valid? it 'should select noop backend if incoming catalog is a minus sign' do options = { from_catalog: '-', to_catalog: '-', from_branch: 'foo', to_branch: 'bar' } logger, logger_str = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = testobj.send(:build_catalog_parallelizer) expect(logger_str.string).to match(/Initialized OctocatalogDiff::Catalog::Noop for from-catalog/) expect(logger_str.string).to match(/Initialized OctocatalogDiff::Catalog::Noop for to-catalog/) @@ -276,7 +278,7 @@ def valid? OctocatalogDiff::Mocks::PuppetDB.new end logger, logger_str = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = testobj.send(:build_catalog_parallelizer) expect(logger_str.string).to match(/Initialized OctocatalogDiff::Catalog::JSON for to-catalog/) expect(logger_str.string).to match(/Initialized OctocatalogDiff::Catalog::PuppetDB for from-catalog/) @@ -288,13 +290,31 @@ def valid? expect(result[:from].builder.to_s).to eq('OctocatalogDiff::Catalog::PuppetDB') expect(result[:to].builder.to_s).to eq('OctocatalogDiff::Catalog::JSON') end + + it 'should raise OctocatalogDiff::Errors::CatalogError if either catalog fails' do + options = { + to_catalog: OctocatalogDiff::Spec.fixture_path('catalogs/tiny-catalog.json'), + from_fact_file: OctocatalogDiff::Spec.fixture_path('facts/facts.yaml'), + bootstrapped_from_dir: OctocatalogDiff::Spec.fixture_path('repos/failing-catalog'), + node: 'tiny-catalog-2-puppetdb', + from_branch: 'foo', + from_env: 'foo-env', + puppet_binary: OctocatalogDiff::Spec::PUPPET_BINARY + } + logger, logger_str = OctocatalogDiff::Spec.setup_logger + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) + expect do + testobj.send(:build_catalog_parallelizer) + end.to raise_error(OctocatalogDiff::Errors::CatalogError) + expect(logger_str.string).to match(/Failed build_catalog for foo-env/) + end end describe '#add_parallel_result' do it 'should warn when catalog compilation is aborted' do options = { from_catalog: '-', to_catalog: '-', from_branch: 'foo', to_branch: 'bar' } logger, logger_str = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) pcr = double('OctocatalogDiff::Util::Parallel::Result') allow(pcr).to receive(:status).and_return(nil) @@ -331,7 +351,7 @@ def valid? options = { from_catalog: '-', to_catalog: '-', from_branch: 'foo', to_branch: 'bar' } logger, logger_str = OctocatalogDiff::Spec.setup_logger - testobj = OctocatalogDiff::CatalogDiff::Cli::Catalogs.new(options, logger) + testobj = OctocatalogDiff::Util::Catalogs.new(options, logger) result = { to: '!!!', from: 'blank' } lines = [ @@ -342,7 +362,7 @@ def valid? answer = Regexp.new(lines.join('(.|\n)*')) expect do testobj.send(:add_parallel_result, result, pcr, key_task_tuple) - end.to raise_error(OctocatalogDiff::CatalogDiff::Cli::Catalogs::CatalogError, answer) + end.to raise_error(OctocatalogDiff::Errors::CatalogError, answer) expect(logger_str.string).to eq('') end