Skip to content

Commit

Permalink
[cli] better format errors in case of a missing required parameter
Browse files Browse the repository at this point in the history
  • Loading branch information
rmannibucau committed Feb 21, 2024
1 parent 269f020 commit adda1f7
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 8 deletions.
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<CF, C extends Runnable> implements CliCommand<C> {
private final String name;
private final String description;
Expand Down Expand Up @@ -59,10 +63,26 @@ public List<Parameter> parameters() {

@Override
public Instance<C> create(final Configuration configuration, final List<Instance<?>> 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<CF, C extends Runnable> extends BaseCliCommand<CF, C> {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Map<String, String>, 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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 + ")");
}

Expand Down

0 comments on commit adda1f7

Please sign in to comment.