Compare commits

...

2 Commits

Author SHA1 Message Date
UncleStab
199a6d66f1 feat(core): (#2881) Added testing for missingDefaults 2025-03-26 16:12:55 +01:00
Tijn Koppert
5e88ef0eb5 feat(core): (#2881) Warning when input and trigger have no defaults 2025-03-26 14:02:18 +01:00
3 changed files with 70 additions and 1 deletions

View File

@@ -13,6 +13,7 @@ import io.kestra.core.repositories.FlowRepositoryInterface;
import io.kestra.core.serializers.JacksonMapper;
import io.kestra.core.serializers.YamlParser;
import io.kestra.core.utils.ListUtils;
import io.kestra.plugin.core.trigger.Schedule;
import jakarta.inject.Inject;
import jakarta.inject.Singleton;
import lombok.extern.slf4j.Slf4j;
@@ -149,6 +150,37 @@ public class FlowService {
}
}
public List<String> missingDefaults(Flow flow) {
// Find inputs without defaults
Set<String> inputsWithoutDefaults = flow.getInputs().stream()
.filter(input -> input.getDefaults() == null)
.map(input -> input.getId())
.collect(Collectors.toSet());
// If all inputs have defaults, no need to check schedules
if (inputsWithoutDefaults.isEmpty()) {
return List.of();
}
// Find schedules with missing inputs or null inputs
return flow.getTriggers().stream()
.filter(trigger -> trigger instanceof Schedule)
.map(trigger -> (Schedule) trigger)
.filter(schedule -> {
Map<String, Object> scheduleInputs = schedule.getInputs();
return scheduleInputs == null || inputsWithoutDefaults.stream().anyMatch(inputId -> !scheduleInputs.containsKey(inputId));
})
.map(schedule -> {
Map<String, Object> scheduleInputs = Optional.ofNullable(schedule.getInputs()).orElse(Collections.emptyMap());
String missingInputs = inputsWithoutDefaults.stream()
.filter(inputId -> !scheduleInputs.containsKey(inputId))
.collect(Collectors.joining(", "));
return "Schedule '" + schedule.getId() + "' is missing inputs for: " + missingInputs;
})
.toList();
}
// check if subflow is present in given namespace
public List<String> checkValidSubflows(Flow flow, String tenantId) {
List<io.kestra.plugin.core.flow.Subflow> subFlows = ListUtils.emptyOnNull(flow.getTasks()).stream()

View File

@@ -9,6 +9,7 @@ import io.kestra.core.models.property.Property;
import io.kestra.core.repositories.FlowRepositoryInterface;
import io.kestra.plugin.core.debug.Echo;
import io.kestra.plugin.core.debug.Return;
import io.kestra.plugin.core.trigger.Schedule;
import jakarta.inject.Inject;
import jakarta.validation.ConstraintViolationException;
import org.junit.jupiter.api.Test;
@@ -234,6 +235,35 @@ class FlowServiceTest {
assertThat(warnings.getFirst().to(), is("io.kestra.core.runners.test.TaskWithAlias"));
}
@Test
void warnMissingDefault() {
Flow flow = Flow.builder()
.id("missing_default")
.namespace("qa")
.inputs(List.of(
StringInput.builder()
.id("user")
.type(Type.STRING)
.build()
))
.tasks(Collections.singletonList(Return.builder()
.id("hello")
.type("io.kestra.core.tasks.log.Log")
.format(Property.of("test"))
.build()
))
.triggers(List.of(
Schedule.builder()
.id("every_minute")
.type("io.kestra.core.models.triggers.types.Schedule")
.cron("*/1 * * * *")
.build()
))
.build();
assertThat(flowService.missingDefaults(flow), containsInAnyOrder("Schedule '", "' is missing inputs for: "));
}
@SuppressWarnings("deprecation")
@Test
void propertyRenamingDeprecation() {

View File

@@ -605,7 +605,14 @@ public class FlowController {
validateConstraintViolationBuilder.deprecationPaths(flowService.deprecationPaths(flowParse));
validateConstraintViolationBuilder.warnings(flowService.warnings(flowParse, tenantService.resolveTenant()));
validateConstraintViolationBuilder.infos(flowService.relocations(flow).stream().map(relocation -> relocation.from() + " is replaced by " + relocation.to()).toList());
List<String> relocationsList = flowService.relocations(flow)
.stream()
.map(relocation -> relocation.from()
+ " is replaced by " + relocation.to())
.toList();
validateConstraintViolationBuilder.infos(Stream
.concat(relocationsList.stream(), flowService.missingDefaults(flowParse).stream())
.toList());
validateConstraintViolationBuilder.flow(flowParse.getId());
validateConstraintViolationBuilder.namespace(flowParse.getNamespace());