Json 创建Jenkins插件以添加参数

Json 创建Jenkins插件以添加参数,json,maven,plugins,parameters,jenkins,Json,Maven,Plugins,Parameters,Jenkins,我正在编写一个Jenkins插件(这是第一次),它连接到nexus存储库,根据GAV搜索提取工件列表。config.jelly允许用户指定要从哪些组中提取工件,然后index.jelly在用户实际执行构建时填充groupId、artifactId和version的单独选择框。其思想是,当用户单击“构建”按钮时,这些工件坐标在构建过程中可用。当我单击“构建”按钮时,出现以下错误: javax.servlet.ServletException: java.lang.ClassCastExceptio

我正在编写一个Jenkins插件(这是第一次),它连接到nexus存储库,根据GAV搜索提取工件列表。config.jelly允许用户指定要从哪些组中提取工件,然后index.jelly在用户实际执行构建时填充groupId、artifactId和version的单独选择框。其思想是,当用户单击“构建”按钮时,这些工件坐标在构建过程中可用。当我单击“构建”按钮时,出现以下错误:

javax.servlet.ServletException: java.lang.ClassCastException: net.sf.json.JSONNull cannot be cast to net.sf.json.JSONObject
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:778)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:858)
at org.kohsuke.stapler.MetaClass$6.doDispatch(MetaClass.java:248)
at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:728)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:858)
at org.kohsuke.stapler.Stapler.invoke(Stapler.java:631)
at org.kohsuke.stapler.Stapler.service(Stapler.java:225)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:848)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:686)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1494)
at hudson.util.PluginServletFilter$1.doFilter(PluginServletFilter.java:96)
at hudson.util.PluginServletFilter.doFilter(PluginServletFilter.java:88)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1482)
at hudson.security.csrf.CrumbFilter.doFilter(CrumbFilter.java:48)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1482)
at hudson.security.ChainedServletFilter$1.doFilter(ChainedServletFilter.java:84)
at hudson.security.ChainedServletFilter.doFilter(ChainedServletFilter.java:76)
at hudson.security.HudsonFilter.doFilter(HudsonFilter.java:164)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1482)
at org.kohsuke.stapler.compression.CompressionFilter.doFilter(CompressionFilter.java:46)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1482)
at hudson.util.CharacterEncodingFilter.doFilter(CharacterEncodingFilter.java:81)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1474)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:499)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:137)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:533)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:231)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1086)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:428)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:193)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1020)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:135)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:116)
at org.eclipse.jetty.server.Server.handle(Server.java:370)
at org.eclipse.jetty.server.AbstractHttpConnection.handleRequest(AbstractHttpConnection.java:489)
at org.eclipse.jetty.server.AbstractHttpConnection.content(AbstractHttpConnection.java:960)
at org.eclipse.jetty.server.AbstractHttpConnection$RequestHandler.content(AbstractHttpConnection.java:1021)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:865)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:240)
at org.eclipse.jetty.server.AsyncHttpConnection.handle(AsyncHttpConnection.java:82)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:668)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:52)
at winstone.BoundedExecutorService$1.run(BoundedExecutorService.java:77)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassCastException: net.sf.json.JSONNull cannot be cast to net.sf.json.JSONObject
at hudson.model.ParametersDefinitionProperty._doBuild(ParametersDefinitionProperty.java:132)
at hudson.model.AbstractProject.doBuild(AbstractProject.java:1849)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.kohsuke.stapler.Function$InstanceFunction.invoke(Function.java:298)
at org.kohsuke.stapler.Function.bindAndInvoke(Function.java:161)
at org.kohsuke.stapler.Function.bindAndInvokeAndServeResponse(Function.java:96)
at org.kohsuke.stapler.MetaClass$1.doDispatch(MetaClass.java:120)
at org.kohsuke.stapler.NameBasedDispatcher.dispatch(NameBasedDispatcher.java:53)
at org.kohsuke.stapler.Stapler.tryInvoke(Stapler.java:728)
... 46 more

我意识到JSONNull不是JSONObject的子类,但我不明白为什么首先会有JSONNull。我还没有让Eclipse绑定到调试端口,所以我只是使用jenkins.out.log和jenkins.err.log日志作为跟踪插件运行的一种方式。我使用Fiddler捕获了以下事务,响应代码为500(内部服务器错误):

在我的ClassParameterDefinition中,我覆盖了以下方法,期望“构建”按钮点击会出现在这里:

@Override
    public ParameterValue createValue(StaplerRequest req, JSONObject jo) {
        System.out.println(new Date().toString() + " createValue(" + jo.toString() + ")");
        ClassParameterValue value = req.bindJSON(ClassParameterValue.class, jo);

        value.setGroupId(this.groupId);
        value.setArtifactId(this.artifactId);
        value.setVersion(this.version);
        return value;
    }
我的index.jelly文件如下所示:

<?jelly escape-by-default='true'?>
<j:jelly xmlns:j="jelly:core" xmlns:st="jelly:stapler" xmlns:d="jelly:define"
    xmlns:l="/lib/layout" xmlns:t="/lib/hudson" xmlns:f="/lib/form"
    xmlns:i="jelly:fmt" xmlns:p="/lib/hudson/project">

    <!-- This is the input form when a user does a build. -->

    <j:invokeStatic className="org.test.ClassParameterDefinition" method="getFullArtifactList" var="fullArtifactList" />
    <j:invokeStatic className="org.test.ClassParameterDefinition" method="fetchGroupList" var="groupList" />

    <![CDATA[
    <script type="text/javascript">
        var artifactList = [];
        var versionList = [];

        function createArtifactList(fullArtifactList, groupId) {
            artifactList = [];
            for(var a = 0; a < fullArtifactList.length; a++) {
                var found = false;
                for(var l = 0; l < artifactList.length; l++) {
                    if(fullArtifactList[a].groupId == groupId) {
                        if(fullArtifactList[a].artifactId == artifactList[l]) {
                            found = true
                            break
                        }
                    }
                }
                if(fullArtifactList[a].groupId == groupId) {
                    if(!found) {
                        artifactList.push(fullArtifactList[a].artifactId)
                    }
                }
            }
            artifactList.sort(function (a, b) {
                return a.toLowerCase().localeCompare(b.toLowerCase())
            })
            populateArtifactSelect(artifactList)
        }

        function populateArtifactSelect(artifactList) {
            console.log('Populating the artifactId drop down')
            document.getElementById('artifactIdSelect').innerHTML = ""
            for(var a = 0; a < artifactList.length; a++) {
                opt = document.createElement("option")
                opt.value = artifactList[a]
                opt.text = artifactList[a]
                document.getElementById('artifactIdSelect').appendChild(opt)
            }
            createVersionList(${fullArtifactList}, document.getElementById('groupIdSelect').value, document.getElementById('artifactIdSelect').value)
        }

        function createVersionList(fullArtifactList, groupId, artifactId) {
            versionList = [];
            for(var a = 0; a < fullArtifactList.length; a++) {
                if(fullArtifactList[a].groupId == groupId) {
                    if(fullArtifactList[a].artifactId == artifactId) {
                        versionList.push(fullArtifactList[a].version)
                    }
                }
            }
            populateVersionSelect(versionList)
        }

        function populateVersionSelect(versionList) {
            console.log('Populating the version drop down')
            document.getElementById('versionIdSelect').innerHTML = ""
            for(var v = 0; v < versionList.length; v++) {
                opt = document.createElement("option")
                opt.value = versionList[v]
                opt.text = versionList[v]
                document.getElementById('versionIdSelect').appendChild(opt)
            }
        }
    </script>
    ]]>

    <j:set var="it" value="${it.build}" />
    <f:entry title="Group ID" description="${%group.id.description}" field="groupId">
        <select id="groupIdSelect" name="groupId" onchange="createArtifactList(${fullArtifactList}, this.value)">
            <j:forEach var="group" items="${groupList}">
                <option value="${group}">${group}</option>
            </j:forEach>
        </select>
    </f:entry>

    <f:entry title="Artifact ID" description="${%artifact.id.description}" field="artifactId">
        <select id="artifactIdSelect" name="artifactId" onchange="createVersionList(${fullArtifactList}, document.getElementById('groupIdSelect').value, this.value)"></select>
    </f:entry>

    <f:entry title="Version" description="${%version.description}" field="version">
        <select name="version" id="versionIdSelect"></select>
    </f:entry>

    <![CDATA[
        <script type="text/javascript">
            createArtifactList(${fullArtifactList}, document.getElementById('groupIdSelect').value)
        </script>
    ]]>

</j:jelly>

var-artifactList=[];
var versionList=[];
函数createArtifactList(fullArtifactList,groupId){
工件列表=[];
对于(var a=0;a
${group}
createArtifactList(${fullArtifactList},document.getElementById('groupIdSelect').value)
]]>
  • 为什么在“Build”按钮提交表单时会创建一个JSONNull对象
  • 代码实际上是否试图转到我正在重写的createValue方法

经过相当多的插件阅读和反复试验,我发现了这个问题。希望这对其他人有帮助

我的index.jelly文件缺少名称字段,我的ClassParameterDescription在构造函数中需要它并调用super(name)

也就是说,我能够使参数可用的唯一方法是,我确信有更好的方法来做到这一点,但由于这是我的第一个插件,我对目前正在运行的产品感到满意,所以我将以下部分添加到我的index.jelly中:

<div name="parameter">
        <input type="hidden" name="name" value="${it.name}" />
        <input type="hidden" id="groupIdValue" name="groupId" value="document.getElementById('groupIdSelect').value" />
        <input type="hidden" id="artifactIdValue" name="artifactId" value="document.getElementById('artifactIdSelect').value" />
        <input type="hidden" id="versionValue" name="version" value="document.getElementById('versionSelect').value" />
    </div>

在selectonchange方法中也必须更新这些值

然后将这些变量放入ClassParameterValue.java类中的环境变量中,并可通过$groupId、$artifactId和$version访问它们。或在windows批处理文件上作为%groupId%、%artifactId%和%version%

我从Jenkins源代码()的标签参数插件中得到了提示

<div name="parameter">
        <input type="hidden" name="name" value="${it.name}" />
        <input type="hidden" id="groupIdValue" name="groupId" value="document.getElementById('groupIdSelect').value" />
        <input type="hidden" id="artifactIdValue" name="artifactId" value="document.getElementById('artifactIdSelect').value" />
        <input type="hidden" id="versionValue" name="version" value="document.getElementById('versionSelect').value" />
    </div>