Config-Resolver

 view release on metacpan or  search on metacpan

bin/config-resolver.pl  view on Meta::CPAN

=item --plugins

A comma delimited list of plugin names. See L</PLUGINS>

=item --plugin xxx:key=value

This is the mechanism you use to pass options to your plugins.

Example:

 --plugin ssm:endpoint_url=http://localhost:4566

=item -V, --parameters

You can supply key/value pairs at the command line to do simple
templating operations.

 echo 'foo=${foo}' | config-resolver -V 'foo=bar&bar=buz'

=item -r, --resolve

bin/config-resolver.pl  view on Meta::CPAN

or tokens when more advanced plugins (AWS SSM, AWS Secrets Manager,
etc) are not available.

  ${file:///var/run/secrets/token}

=back

=head2 Plugin Configuration

Many plugins, like C<ssm>, require configuration (e.g., the AWS
region, or a custom endpoint for local testing). You can provide this
configuration in two ways, which are layered:

=head3 1. The RC File (Defaults)

On startup, the script will attempt to load a configuration file from:

  $HOME/.config-resolverrc

This file (in JSON or YAML format) is the perfect place to set your
team- or user-wide defaults.

B<Example C<~/.config-resolverrc>:>

 {
   "ssm": {
     "region": "us-east-1",
     "endpoint_url": "http://localhost:4566"
   },
   "another_plugin": {
     "foo": "bar"
   }
 }

=head3 2. Command-Line Overrides (Specifics)

You can override or provide new settings for any plugin on the command
line using the C<--plugin:*> option. This is the top layer and will

bin/config-resolver.pl  view on Meta::CPAN

The syntax is:

  --plugin PROTOCOL:key=value

You can repeat the C<--plugin> option to build up the configuration.

B<Example:>

  config-resolver.pl \
      --plugin ssm:region=us-west-2 \
      --plugin ssm:endpoint_url=http://localhost:4566 \
      -t my-template.tpl

The script merges these two sources, giving command-line options final
priority, and passes the result to the resolver engine.

=head2 Plugin "Setup-Only" Execution Mode

This script does not have a default command (like C<resolve> or C<dump>).
This intentional design enables a powerful "init-only" workflow for plugins
that need to perform on-demand setup or initialization tasks.

bin/config-resolver.pl  view on Meta::CPAN


=over 4

=item 1. Define Configuration Keys

In your plugin's documentation, define the keys a user must set in
their C<.config-resolverrc> file .

  # In .config-resolverrc
  [plugin ssm]
    endpoint_url = http://localhost:4566
    
    # --- Keys for your one-time setup ---
    seed_file = /opt/my-app/localstack-seed.json
    load_on_init = false # <-- Default to false!

=item 2. Add Logic to Your Plugin's C<new()>

In your plugin's C<new()> constructor, check for your flag.

  # In lib/Config/Resolver/Plugin/SSM.pm

lib/Config/Resolver.pm  view on Meta::CPAN

 my $config_ext = $resolver_ext->resolve(
     '${reverse(greeting)}', { greeting => 'hello' }
 );
 # $config_ext is now 'olleh'
 
 # 3. Pluggable Backends (for ssm://, vault://, etc.)
 
 # A) Dynamically load installed plugins...

 my $my_plugin_config = {
     'ssm' => { 'endpoint_url' => 'http://localhost:4566' }
 };

 my $resolver_plugins = Config::Resolver->new(
     plugins       => [ 'SSM' ],
     plugin_config => $my_plugin_config,
 );
 
 my $ssm_val = $resolver_plugins->resolve('ssm://my/ssm/path');

 # B) Manual "shim" injection

t/01_plugin_config.t  view on Meta::CPAN

  my $mock = MockCLI->new(
    commands      => { foo => sub { return 0; } },
    option_specs  => \@option_specs,
    extra_options => ['parameters_hash'],
  );

  $mock->{_mock_rc}          = undef;
  $mock->{_mock_plugin_args} = [
    'ssm:region=us-east-1',
    'vault:addr=http://local',
    'ssm:endpoint_url=http://test'  # Test adding a second key to ssm
  ];

  my $config;
  {
    local $ENV{HOME} = $EMPTY_HOME;
    $config = $mock->_build_plugin_config();
  }

  my $expected = {
    ssm => {
      region       => 'us-east-1',
      endpoint_url => 'http://test',
    },
    vault => { addr => 'http://local', },
  };

  is_deeply( $config, $expected, 'Correctly parses multiple CLI plugins into a hash' );
};

# --- Test 4: The "RC File Only" Case ---
subtest 'Test Case: RC file only' => sub {
  # 1. Create a temp environment

t/01_plugin_config.t  view on Meta::CPAN

  is_deeply( $config, $expected, 'Correctly reads real RC file' );
};

# --- Test 5: The "Merge" Case (CLI wins) ---
subtest 'Test Case: RC and CLI merge (CLI wins)' => sub {
  # 1. Create a temp environment
  my $temp_dir     = tempdir( CLEANUP => 1 );
  my $rc_file_path = File::Spec->catfile( $temp_dir, '.config-resolverrc' );

  # 2. Write the temp RC file
  my $rc_file_content = "[plugin SSM]\nregion = us-east-1\nendpoint_url = http://prod.example.com\n";
  open my $fh, '>', $rc_file_path or die "Could not write $rc_file_path: $!";
  print $fh $rc_file_content;
  close $fh;

  # 3. Create the mock
  my $mock = MockCLI->new(
    commands      => { foo => sub { return 0; } },
    option_specs  => \@option_specs,
    extra_options => ['parameters_hash'],
  );

t/01_plugin_config.t  view on Meta::CPAN

  my $config;
  {
    local $ENV{HOME} = $temp_dir;
    $config = $mock->_build_plugin_config();
  }

  # 5. Check the result
  my $expected = {
    ssm => {
      region       => 'us-west-2',                # <-- The overridden value
      endpoint_url => 'http://prod.example.com',  # <-- The value from the RC
    }
  };
  is_deeply( $config, $expected, 'CLI arguments correctly override real RC file' );
};

# --- Test 6: The "Malformed Args" Case ---
# Test that we correctly warn and skip bad input.
subtest 'Test Case: Malformed arguments' => sub {
  my $mock = MockCLI->new(
    commands      => { foo => sub { return 0; } },



( run in 0.384 second using v1.01-cache-2.11-cpan-657826877f4 )