This commit is contained in:
Robin Shen 2025-09-25 15:10:13 +08:00
parent 207fcb65e8
commit 3e16c2fe66
3 changed files with 32 additions and 31 deletions

View File

@ -62,19 +62,11 @@ public class BuildSpecSchemaResource {
private final ImplementationRegistry implementationRegistry;
private final Yaml yaml;
private String schema;
private volatile String schema;
@Inject
public BuildSpecSchemaResource(ImplementationRegistry implementationRegistry) {
this.implementationRegistry = implementationRegistry;
// Configure YAML output
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setPrettyFlow(true);
this.yaml = new Yaml(options);
this.implementationRegistry = implementationRegistry;
}
private void processProperty(Map<String, Object> currentNode, Object bean, PropertyDescriptor property) {
@ -91,24 +83,28 @@ public class BuildSpecSchemaResource {
descriptionSections.add("NOTE: If set, the value can only contain one line");
}
InputStream grammarStream = null;
if (getter.getAnnotation(Patterns.class) != null) {
if (getter.getAnnotation(Interpolative.class) != null) {
grammarStream = PatternSet.class.getResourceAsStream("InterpolativePatternSet.g4");
} else {
grammarStream = PatternSet.class.getResourceAsStream("PatternSet.g4");
try {
if (getter.getAnnotation(Patterns.class) != null) {
if (getter.getAnnotation(Interpolative.class) != null) {
grammarStream = PatternSet.class.getResourceAsStream("InterpolativePatternSet.g4");
} else {
grammarStream = PatternSet.class.getResourceAsStream("PatternSet.g4");
}
} else if (getter.getAnnotation(RetryCondition.class) != null) {
grammarStream = io.onedev.server.buildspec.job.retrycondition.RetryCondition.class.getResourceAsStream("RetryCondition.g4");
} else if (getter.getAnnotation(UserMatch.class) != null) {
grammarStream = io.onedev.server.util.usermatch.UserMatch.class.getResourceAsStream("UserMatch.g4");
}
} else if (getter.getAnnotation(RetryCondition.class) != null) {
grammarStream = io.onedev.server.buildspec.job.retrycondition.RetryCondition.class.getResourceAsStream("RetryCondition.g4");
} else if (getter.getAnnotation(UserMatch.class) != null) {
grammarStream = io.onedev.server.util.usermatch.UserMatch.class.getResourceAsStream("UserMatch.g4");
}
if (grammarStream != null) {
try {
var grammar = IOUtils.toString(grammarStream, StandardCharsets.UTF_8);
descriptionSections.add("NOTE: If set, the value should conform with below ANTLR v4 grammar:\n\n" + grammar);
} catch (IOException e) {
throw new RuntimeException(e);
if (grammarStream != null) {
try {
var grammar = IOUtils.toString(grammarStream, StandardCharsets.UTF_8);
descriptionSections.add("NOTE: If set, the value should conform with below ANTLR v4 grammar:\n\n" + grammar);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
} finally {
IOUtils.closeQuietly(grammarStream);
}
}
@ -480,7 +476,10 @@ public class BuildSpecSchemaResource {
rootNode.put("required", requiredList);
rootNode.put("additionalProperties", false);
schema = yaml.dump(rootNode);
DumperOptions options = new DumperOptions();
options.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
options.setPrettyFlow(true);
schema = new Yaml(options).dump(rootNode);
}
return schema;
}

View File

@ -1,5 +1,7 @@
package io.onedev.server.rest.resource;
import static javax.ws.rs.core.Response.Status.NOT_ACCEPTABLE;
import java.io.Serializable;
import java.nio.charset.StandardCharsets;
import java.text.MessageFormat;
@ -2143,6 +2145,7 @@ public class McpHelperResource {
var project = getProject(projectPath);
Project.push(project);
String schemaNotice = "\n\n**NOTE**: AI assistant may call the getBuildSpecSchema tool to know exact syntax of build spec";
try {
var buildSpec = BuildSpec.parse(buildSpecString.getBytes(StandardCharsets.UTF_8));
List<String> validationErrors = new ArrayList<>();
@ -2154,14 +2157,14 @@ public class McpHelperResource {
if (validationErrors.isEmpty()) {
return Response.ok(VersionedYamlDoc.fromBean(buildSpec).toYaml()).build();
} else {
return Response.ok(Joiner.on("\n").join(validationErrors)).build();
return Response.status(NOT_ACCEPTABLE).entity(Joiner.on("\n").join(validationErrors) + schemaNotice).build();
}
} catch (Exception e) {
var explicitException = ExceptionUtils.find(e, ExplicitException.class);
if (explicitException != null) {
return Response.ok(explicitException.getMessage()).build();
return Response.status(NOT_ACCEPTABLE).entity(explicitException.getMessage() + schemaNotice).build();
} else {
return Response.ok(Throwables.getStackTraceAsString(e)).build();
return Response.status(NOT_ACCEPTABLE).entity(Throwables.getStackTraceAsString(e) + schemaNotice).build();
}
} finally {
Project.pop();

View File

@ -21,7 +21,6 @@ public class RegExValidator implements ConstraintValidator<RegEx, String> {
@Override
public boolean isValid(String value, ConstraintValidatorContext constraintContext) {
System.out.println("Validating value: " + value);
if (value == null)
return true;
if (pattern.matcher(value).matches()) {