diff --git a/fusion-api/src/main/java/io/yupiik/fusion/framework/api/configuration/MissingRequiredParameterException.java b/fusion-api/src/main/java/io/yupiik/fusion/framework/api/configuration/MissingRequiredParameterException.java new file mode 100644 index 00000000..a6f66d00 --- /dev/null +++ b/fusion-api/src/main/java/io/yupiik/fusion/framework/api/configuration/MissingRequiredParameterException.java @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2022 - present - Yupiik SAS - https://www.yupiik.com + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package io.yupiik.fusion.framework.api.configuration; + +public class MissingRequiredParameterException extends IllegalArgumentException { + public MissingRequiredParameterException(final String msg) { + super(msg); + } +} diff --git a/fusion-cli/src/main/java/io/yupiik/fusion/cli/internal/BaseCliCommand.java b/fusion-cli/src/main/java/io/yupiik/fusion/cli/internal/BaseCliCommand.java index d087c948..f393c127 100644 --- a/fusion-cli/src/main/java/io/yupiik/fusion/cli/internal/BaseCliCommand.java +++ b/fusion-cli/src/main/java/io/yupiik/fusion/cli/internal/BaseCliCommand.java @@ -18,12 +18,16 @@ import io.yupiik.fusion.framework.api.Instance; import io.yupiik.fusion.framework.api.RuntimeContainer; import io.yupiik.fusion.framework.api.configuration.Configuration; +import io.yupiik.fusion.framework.api.configuration.MissingRequiredParameterException; import io.yupiik.fusion.framework.api.container.DefaultInstance; import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; +import static java.util.Comparator.comparing; +import static java.util.stream.Collectors.joining; + public class BaseCliCommand implements CliCommand { private final String name; private final String description; @@ -59,10 +63,26 @@ public List parameters() { @Override public Instance create(final Configuration configuration, final List> dependents) { - return new DefaultInstance<>( - null, null, - constructor.apply(configurationProvider.apply(configuration), dependents), - dependents); + final C conf; + try { + conf = constructor.apply(configurationProvider.apply(configuration), dependents); + } catch (final + MissingRequiredParameterException missingRequiredParameterException) { // "No value for 'xxx.xxx'" + final var rewritten = new MissingRequiredParameterException( + // format as an option and not a config/system prop + missingRequiredParameterException.getMessage().replace(" '", " '--").replace('.', '-') + + formatLightHelp()); + rewritten.setStackTrace(new StackTraceElement[0]); + throw rewritten; + } + return new DefaultInstance<>(null, null, conf, dependents); + } + + private String formatLightHelp() { + return parameters.isEmpty() ? "" : ('\n' + parameters.stream() + .sorted(comparing(Parameter::cliName)) + .map(p -> p.cliName() + ": " + p.description()) + .collect(joining("\n", "Available parameters:\n", "\n"))); } public static class ContainerBaseCliCommand extends BaseCliCommand { diff --git a/fusion-cli/src/test/java/io/yupiik/fusion/cli/internal/BaseCliCommandTest.java b/fusion-cli/src/test/java/io/yupiik/fusion/cli/internal/BaseCliCommandTest.java new file mode 100644 index 00000000..63b19cb0 --- /dev/null +++ b/fusion-cli/src/test/java/io/yupiik/fusion/cli/internal/BaseCliCommandTest.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 - present - Yupiik SAS - https://www.yupiik.com + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package io.yupiik.fusion.cli.internal; + +import io.yupiik.fusion.framework.api.configuration.MissingRequiredParameterException; +import org.junit.jupiter.api.Test; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +class BaseCliCommandTest { + @Test + void errorMessage() { + assertEquals( + """ + No value for '--test-dummy' + Available parameters: + --test-dummy: Some param. + """, + assertThrows(IllegalArgumentException.class, () -> new BaseCliCommand, Runnable>( + "test", + "...", + c -> { + // simulate a parameter required=true which is missing + throw new MissingRequiredParameterException("No value for 'test.dummy'"); + }, + (conf, deps) -> { + throw new UnsupportedOperationException("shouldn't be called in this test"); + }, + List.of(new CliCommand.Parameter("test.dummy", "--test-dummy", "Some param."))) + .create(key -> Optional.empty(), List.of())) + .getMessage()); + } +} diff --git a/fusion-processor/src/main/java/io/yupiik/fusion/framework/processor/internal/generator/ConfigurationFactoryGenerator.java b/fusion-processor/src/main/java/io/yupiik/fusion/framework/processor/internal/generator/ConfigurationFactoryGenerator.java index c17dfcad..a7740d1c 100644 --- a/fusion-processor/src/main/java/io/yupiik/fusion/framework/processor/internal/generator/ConfigurationFactoryGenerator.java +++ b/fusion-processor/src/main/java/io/yupiik/fusion/framework/processor/internal/generator/ConfigurationFactoryGenerator.java @@ -284,10 +284,8 @@ private String lookup(final String name, final boolean required, final String ma return "configuration.get(" + name + ")" + mapper + (required ? - ".orElseThrow(() -> new IllegalArgumentException(\"No value for '" + - name - .replace("\n", "\\\n") - .replace("\"", "\\\"") + "'\"))" : + ".orElseThrow(() -> new io.yupiik.fusion.framework.api.configuration.MissingRequiredParameterException(\"No value for '" + + name.substring(1, name.length() - 1) + "'\"))" : ".orElse(" + defaultValue + ")"); }