groovy - 尝试使用 JIRA Scriptrunner 自定义 REST 端点时出现 404

标签 groovy jira jira-plugin jira-rest-api

我正在尝试使用 Script Runner 添加自定义 JIRA REST 端点。

REST 端点需要设置用户属性:提供用户列表,并为每个用户提供用户属性列表。

这是我迄今为止拼凑的脚本:

import com.atlassian.jira.component.ComponentAccessor
import com.atlassian.jira.bc.user.search.UserSearchService
import com.atlassian.sal.api.user.UserManager
import com.onresolve.scriptrunner.runner.rest.common.CustomEndpointDelegate

import groovy.json.JsonBuilder
import groovy.json.JsonSlurper
import groovy.transform.BaseScript

import javax.servlet.http.HttpServletRequest
import javax.ws.rs.core.MultivaluedMap
import javax.ws.rs.core.Response

@BaseScript CustomEndpointDelegate delegate

setUserProperties(httpMethod: "POST", groups: ["jira-administrators"])
{ MultivaluedMap queryParams, String body, HttpServletRequest request ->

  def userPropertyManager = ComponentAccessor.getUserPropertyManager()
  def userManager = ComponentAccessor.getUserManager()
  def userSearchService = ComponentAccessor.getComponent(UserSearchService.class)

  def json = new JsonSlurper().parseText(body)
  def propertyCount = 0
  def customerList = new ArrayList<>()
  json.each {
    aCustomer ->
      def user = userManager.getUserByName(aCustomer.name.toString())
      aCustomer.properties.each {
        aProperty ->
          userPropertyManager.getPropertySet(user).setString("jira.meta." + aProperty.key.toString(), aProperty.value.toString())
          propertyCount++
      }
      customerList.add(user)
  }

  def response = new ArrayList<>()
  response.add( new JsonSlurper().parseText('{ "properties_changed": ' + propertyCount + ' }') )
  response.add( customerList )

  return Response.ok( new JsonBuilder(response).toPrettyString() ).build();
}

内联脚本编辑器提示这一行: def user = userManager.getUserByName(aCustomer.name.toString()) ,更准确地说,aCustomer.name 下有一条红色波浪线,错误为

[Static type checking] - No such property: name for class:
java.lang.object
 @ line 28, column 44.

<罢工>

编辑:根据@GlennV的回答,这并不是很重要,可以忽略。

此脚本的先前(工作)迭代在另一台服务器上运行,使用电子邮件地址,请参阅 How to get a user by email in JIRA Script Runner 。但是,如上所述,现在我不是通过电子邮件地址而是通过用户名获取用户。

这是我用来测试的 userprops.json 文件:

[
  {
    "name": "felicity.smoak",
    "email": "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="2741424b4e444e535e09544a48464c67565242424944484954484b4e43465342430944484a" rel="noreferrer noopener nofollow">[email protected]</a>",
    "properties": {
      "Company": "Queen Consolidated",
      "Foo": "bar"
    }
  },
  {
    "name": "johnny.cash",
    "email": "<a href="https://stackoverflow.com/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="670d080f09091e490406140f270906140f110e0b0b024904080a" rel="noreferrer noopener nofollow">[email protected]</a>",
    "properties": {
      "Company": "Nashville",
      "Nickname": "The Man In Black"
    }
  }
]

我用这个 curl 命令进行测试:

curl -X POST \
    -i \
    -H "X-Atlassian-Token: nocheck" \
    -H "Content-type: text/json" \
    --data "@userprops.json" \
    -u "$JIRA_USER":"$JIRA_PASSWORD" \
    http://"$JIRA_SERVER"/rest/scriptrunner/latest/custom/setUserProperties

$JIRA_USER$JIRA_PASSWORD$JIRA_SERVER 只是占位符,我用它们来匿名化 Stack Overflow。实际值是正确的。

这是输出:

HTTP/1.1 404 Not Found
Server: nginx
Date: Wed, 07 Sep 2016 14:55:38 GMT
Content-Type: application/json;charset=UTF-8
Content-Length: 0
Connection: keep-alive
X-AREQUESTID: 0123456789
X-ASEN: SEN-123456789
Set-Cookie: JSESSIONID=1A2B3C4D5E6F1A2B3C4D5E6F1A2B3C4D5E6F; Path=/; Secure; HttpOnly
X-Seraph-LoginReason: OK
Set-Cookie: atlassian.xsrf.token=ABCD-EFGH-IJKL-MNOP|abcdef0123456789abcdef0123456789abcdef0123456789|lin; Path=/; Secure
X-ASESSIONID: xyz123
X-AUSERNAME: amedee.vangasse
Cache-Control: no-cache, no-store, no-transform
X-Content-Type-Options: nosniff

所以它没有找到我应该根据 Scriptrunner documentation 找到它的 REST 端点。

如果我使用任何我知道错误的网址,那么我会收到预期的“哎呀,您发现了一个死链接”。错误页面。只有使用正确的 URL,我才会得到 404 + 没有其他输出。

另外,当我添加 doSomething 示例并尝试 GET 时,我得到了 404 和内容长度 0。在任何其他错误的 URL 上执行 GET 都会得到 404 和几 KiB 的内容长度。

-Dplugin.script.roots= 参数未在 setenv.sh 中定义,也不应该定义,因为该脚本是内联的。仅文件系统上的脚本以及默认 scripts 目录之外的脚本需要设置脚本根,如 Scriptrunner documentation 中所述。

也在 Atlassian Answers 上询问。

编辑:我按照 Glenn 的建议将 customerList.add(user) 向下移动了一行,并且在 atlassian-jira.log 中收到了此错误:

2016-09-09 11:01:43,683 http-nio-8086-exec-23 ERROR amedee.vangasse 661x42160x1 qq01uq 213.224.9.178,127.0.0.1 /rest/scriptrunner/latest/custom/customadmin/com.onresolve.scriptrunner.canned.common.rest.CustomRestEndpoint [c.a.p.r.c.error.jersey.ThrowableExceptionMapper] Uncaught exception thrown by REST service: Cannot get property 'name' on null object
java.lang.NullPointerException: Cannot get property 'name' on null object
        at org.codehaus.groovy.runtime.NullObject.getProperty(NullObject.java:60)
        at org.codehaus.groovy.runtime.InvokerHelper.getProperty(InvokerHelper.java:172)
        at org.codehaus.groovy.runtime.callsite.NullCallSite.getProperty(NullCallSite.java:47)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGetProperty(AbstractCallSite.java:296)
        at com.onresolve.scriptrunner.runner.RestEndpointManager$_onFullSystemStart_closure5.doCall(RestEndpointManager.groovy:141)
        ... 3 filtered
        at java.lang.reflect.Method.invoke(Method.java:497)
        at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:93)
        at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:325)
        at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:294)
        at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1021)
        at groovy.lang.Closure.call(Closure.java:426)
        at groovy.lang.Closure.call(Closure.java:442)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2030)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2015)
        at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2056)
        at org.codehaus.groovy.runtime.dgm$162.invoke(Unknown Source)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:274)
        at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:56)
        at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
        at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:125)
        at com.onresolve.scriptrunner.runner.RestEndpointManager.onFullSystemStart(RestEndpointManager.groovy:131)
        at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.refresh(UserCustomScriptEndpoint.groovy:364)
        at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.saveConfiguredItems(UserCustomScriptEndpoint.groovy:359)
        at com.onresolve.scriptrunner.runner.rest.common.UserCustomScriptEndpoint.addListener(UserCustomScriptEndpoint.groovy:127)
        ... 3 filtered
        at java.lang.reflect.Method.invoke(Method.java:497)
        at com.sun.jersey.spi.container.JavaMethodInvokerFactory$1.invoke(JavaMethodInvokerFactory.java:60)
        ... 13 filtered
        at com.atlassian.plugins.rest.module.RestDelegatingServletFilter$JerseyOsgiServletContainer.doFilter(RestDelegatingServletFilter.java:154)
        ... 1 filtered
        at com.atlassian.plugins.rest.module.RestDelegatingServletFilter.doFilter(RestDelegatingServletFilter.java:68)
        ... 86 filtered
        at com.atlassian.jira.security.JiraSecurityFilter.doFilter(JiraSecurityFilter.java:70)
        ... 16 filtered
        at com.atlassian.plugins.rest.module.servlet.RestSeraphFilter.doFilter(RestSeraphFilter.java:37)
        ... 73 filtered
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:745)

这也不是 nginx 代理的问题,因为当我 ssh 进入服务器和本地主机上的 curl 时,我得到相同的 404。

最佳答案

Script Runner 使用 Groovy 的 CompileStatic提供有关编译错误的提示。当有足够的类型信息可用时,这可以正常工作。

但是,在上面的代码中,您的 json 实例不包含有关其所包含元素的任何类型信息,因此 Groovy(在编译时)不知道 aCustomer> 实例有一个 name 字段,因此它会发出警告。不过,您的代码没有任何问题,因此如果您向 REST 资源发送请求,它应该可以正常工作。

如果您的请求返回 2xx 以外的状态代码,则可能存在其他问题。

关于 404。这意味着未找到,因此要么您发送请求的 URL 存在错误,要么您的 REST 脚本无法正确供 Script Runner 使用。我会首先检查 $JIRA_SERVER 的值。如果将其粘贴到浏览器中,它应该正确加载 JIRA。如果没问题,那么我会检查 Script Runner 是否知道它需要查找脚本的路径。 -Dplugin.script.roots= 参数是否在 setenv.sh (或 setenv.bat)中定义?有关此内容的更多详细信息,请访问 here .

关于groovy - 尝试使用 JIRA Scriptrunner 自定义 REST 端点时出现 404,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39371582/

相关文章:

groovy - 如何在 Groovy 中复制文件

git - Jira如何链接到git?

intellij-idea - 如何将 IntelliJ IDEA 与免费的 Jira 实例连接?

java - 为什么我的插件中的 Webwork 方法会落入 JIRA 的 ActionSupport 类?

javascript - 如何将同一小工具的多个实例分开

java - 将 docx4j 与 JIRA 插件集成时遇到问题

grails - Groovy SQL 数据源连接处理,withTransaction

java - Grails 中 Quartz 工作的 withTransaction?

java - 在数据库中存储 BLOB 的最佳方式是什么?

python - 无法通过 REST api https url 连接到 JIRA Python