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.501 second using v1.01-cache-2.11-cpan-7dc5eeec69e )