generate JSON schema

This commit is contained in:
Nicolas De Loof 2017-12-18 19:33:39 +01:00
parent 95e53a69e8
commit 7ec6e07199
7 changed files with 128 additions and 26 deletions

View File

@ -1,19 +1,14 @@
package org.jenkinsci.plugins.casc;
import hudson.ExtensionList;
import hudson.Plugin;
import hudson.init.InitMilestone;
import hudson.init.Initializer;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
import org.yaml.snakeyaml.Yaml;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -48,29 +43,19 @@ public class ConfigurationAsCode extends Plugin {
// for documentation generation in index.jelly
public List<?> getConfigurators() {
List<Object> elements = new ArrayList<>();
for (RootElementConfigurator c : getRootConfigurators()) {
for (RootElementConfigurator c : RootElementConfigurator.all()) {
elements.add(c);
listElements(elements, c.describe());
}
return elements;
}
static List<RootElementConfigurator> getRootConfigurators() {
List<RootElementConfigurator> configurators = new ArrayList<>();
final Jenkins jenkins = Jenkins.getInstance();
configurators.addAll(jenkins.getExtensionList(RootElementConfigurator.class));
// Check for Descriptors with a global.jelly view
final ExtensionList<Descriptor> descriptors = jenkins.getExtensionList(Descriptor.class);
for (Descriptor descriptor : descriptors) {
if (descriptor.getGlobalConfigPage() != null) {
configurators.add(new DescriptorRootElementConfigurator(descriptor));
}
}
return configurators;
// for documentation generation in index.jelly
public List<?> getRootConfigurators() {
return RootElementConfigurator.all();
}
private void listElements(List<Object> elements, Set<Attribute> attributes) {
for (Attribute attribute : attributes) {

View File

@ -1,12 +1,10 @@
package org.jenkinsci.plugins.casc;
import com.google.common.primitives.Primitives;
import hudson.Extension;
import hudson.ExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Describable;
import hudson.remoting.Which;
import hudson.util.Secret;
import jenkins.model.Jenkins;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
@ -38,7 +36,7 @@ public abstract class Configurator<T> implements ExtensionPoint {
public static Configurator lookupRootElement(String name) {
for (RootElementConfigurator c : ConfigurationAsCode.getRootConfigurators()) {
for (RootElementConfigurator c : RootElementConfigurator.all()) {
if (c.getName().equals(name)) {
return (Configurator) c;
}

View File

@ -1,7 +1,5 @@
package org.jenkinsci.plugins.casc;
import jenkins.model.Jenkins;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
@ -29,7 +27,7 @@ public class DocumentationGeneration {
documented.add(Integer.class);
// ...
for (RootElementConfigurator c : ConfigurationAsCode.getRootConfigurators()) {
for (RootElementConfigurator c : RootElementConfigurator.all()) {
final String name = c.getName();
document(name, c.describe());
}

View File

@ -1,5 +1,11 @@
package org.jenkinsci.plugins.casc;
import hudson.ExtensionList;
import hudson.model.Descriptor;
import jenkins.model.Jenkins;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
/**
@ -9,6 +15,22 @@ import java.util.Set;
*/
public interface RootElementConfigurator {
static List<RootElementConfigurator> all() {
List<RootElementConfigurator> configurators = new ArrayList<>();
final Jenkins jenkins = Jenkins.getInstance();
configurators.addAll(jenkins.getExtensionList(RootElementConfigurator.class));
// Check for Descriptors with a global.jelly view
final ExtensionList<Descriptor> descriptors = jenkins.getExtensionList(Descriptor.class);
for (Descriptor descriptor : descriptors) {
if (descriptor.getGlobalConfigPage() != null) {
configurators.add(new DescriptorRootElementConfigurator(descriptor));
}
}
return configurators;
}
String getName();
Set<Attribute> describe();

View File

@ -0,0 +1,45 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout">
<j:choose>
<j:when test="${it.type.enum}">
"type": "string",
"enum": [
<j:forEach items="${it.type.values()}" var="v" varStatus="st">
"${v}"<j:if test="${!st.last}">,</j:if>
</j:forEach>
]
</j:when>
<j:otherwise>
<j:switch on="${it.type.name}">
<j:case value="java.lang.String">
"type": "string"
</j:case>
<j:case value="boolean">
"type": "boolean"
</j:case>
<j:case value="java.lang.Boolean">
"type": "boolean"
</j:case>
<j:case value="int">
"type": "integer",
"format": "uint32"
</j:case>
<j:case value="java.lang.Integer">
"type": "integer",
"format": "uint32"
</j:case>
<j:case value="long">
"type": "integer",
"format": "uint64"
</j:case>
<j:case value="java.lang.Long">
"type": "integer",
"format": "uint64"
</j:case>
<j:default>
"type": "#/definitions/${it.type.name}"
</j:default>
</j:switch>
</j:otherwise>
</j:choose>
</j:jelly>

View File

@ -0,0 +1,38 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout">
<st:contentType value="application/json"/>
{
"$schema": "http://json-schema.org/draft-06/schema#",
"id": "http://jenkins.io/configuration-as-code#",
"description": "Jenkins Configuration as Code",
"type": "object",
"properties": {
<j:forEach items="${it.rootConfigurators}" var="r" varStatus="rst">
"${r.name}": {
"type": "object",
"$ref": "#/definitions/${r.target.name}"
}<j:if test="${!rst.last}">,</j:if>
</j:forEach>
},
"definitions": {
<j:forEach items="${it.configurators}" var="c" varStatus="cst">
"${c.target.name}": {
"type": "object",
"properties": {
<j:forEach items="${c.attributes}" var="a" varStatus="ast">
"${a.name}": {
<j:if test="${a.multiple}">
"type": "array",
"items": {
</j:if>
<st:include page="schema.jelly" it="${a}"/>
<j:if test="${a.multiple}">}</j:if>
} <j:if test="${!ast.last}">,</j:if>
</j:forEach>
}
}<j:if test="${!cst.last}">,</j:if>
</j:forEach>
}
}
</j:jelly>

View File

@ -0,0 +1,16 @@
<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:l="/lib/layout">
"schema" : {
"oneOf": [
<j:forEach items="${app.getDescriptorList(it.type)}" var="d" varStatus="st">
<j:invokeStatic className="org.jenkinsci.plugins.casc.DescribableAttribute" method="getSymbolName" var="symbol">
<j:arg value="${d}" type="hudson.model.Descriptor"/>
<j:arg value="${it.type}"/>
</j:invokeStatic>
{
"${symbol}": { "type": "#/definitions/${d.klass.toJavaClass().name}" }
}<j:if test="${!st.last}">,</j:if>
</j:forEach>
]
}
</j:jelly>