GroovyでのJira Automation

画像






大規模な組織では、自動化、他のシステムとの統合、および他のカスタマイズなど、標準の配信にはない追加機能をJIRAに固定する必要があります。 多くの場合、これはサードパーティのプラグインによって解決されます。 アトラシアンマーケットには膨大な数のプラグインがあります。 しかし、適切なプラグインがない場合はどうでしょうか? 明らかに自分で書いてください。 もう1つの拡張オプションは、JIRAでスクリプトを使用する機能を追加するプラグインです: ScriptRunner (Groovy)、 Jira Scripting Suite (SIL)、 JJupin (Jython)。



この記事では、 AdaptavistのScriptRunnerで最も人気のある機能について説明ます



ScriptRunnerでは、JIRA Java APIを直接使用できるGroovyでスクリプトを作成できます。 つまり 独自のプラグインを作成するときとほぼ同じ機能を使用できます。 Groovyで拡張機能を作成することだけがはるかに快適です。xml-configsで大騒ぎせず、mavenの痛みと依存関係の問題で、コードだけです。 JIRAには、豊富で十分に文書化されたJava APIがあります。 Rest APIとは異なり、Java APIでは、Webインターフェースなどで実行できるすべてのことを実行できます。 Groovyは、Javaに似た構文を持つスクリプト言語です。 Javaバイトコードにコンパイルされ、JVMによって実行され、ネイティブライブラリと同様にJavaライブラリで動作し、静的および動的な型指定とクロージャの両方をサポートします。 残念ながら、第4バージョンのScriptRrunnerは有料になりました。これを覚えておいてください。



Scriptrunner



プラグインの3番目のバージョンから、すべてのスクリプトは1つの特定のディレクトリ( %scriptroot% )に存在する必要があります。 デフォルトでは、これは<jira-app-dir> / scriptsディレクトリです。 次のように、jvm argsの-Dplugin.script.rootsパラメーターを編集することで変更できます。
-Dplugin.script.roots="/home/jira/jira-data/scripts/"
      
      



jvm argsのパラメーターを追加または変更する方法については、 こちらをご覧ください



ScriptRunnerには、目的とアプリケーションが異なるいくつかの基本的な種類のカスタムスクリプトがあります。



PostFunction 。 問題が別のステータスに転送された後に実行されます。 特定の遷移に関連付けられています。

バリデーター 問題を別のステータスに転送しようとしたときのデータの検証。 ステータス変換を有効または無効にします。 特定の遷移に関連付けられています。

条件 ステータス変換を実行できるかどうかを決定する論理式。 そうでない場合は、ステータスを変更するためのボタンを非表示にします。 特定の遷移に関連付けられています。

リスナー IssueEventイベントに反応します。 たとえば、課題を作成または更新します。 どのイベントにどのイベントに応答するかを指定できます。

JQL関数 問題を検索するJQL関数。



管理パネルを使用して、ブラウザウィンドウで任意のスクリプトを直接実行できます。これは、小さなスクリプトのテストに非常に便利です。 最初のスクリプトを作成して実行しましょう。 プラグインをJIRAテストインスタンスにインストールします(まだインストールしていない場合)。 [管理]> [アドオン]> [ScriptRunner]> [スクリプトコンソール]に移動します。 ご覧のとおり、[実行]ボタンは、コンソールのコードをここから実行できることを明確に示しています。 3番目のバージョンでは、コンソールウィンドウの構文が強調表示され、ミスを犯すのが少し難しくなりました。 右側のファイル/スクリプトブックマークに注意してください。 %scriptroot%からの相対パスを指定することで、スクリプトを実行できます。 次のコードをウィンドウに貼り付け、問題のキーをインスタンスに実際に存在するものに置き換えます。

 import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.IssueManager import com.atlassian.jira.issue.MutableIssue IssueManager issueManager = ComponentAccessor.getIssueManager() //  PRJ-1    issue. MutableIssue curIssue = issueManager.getIssueObject("PRJ-1") String result = curIssue.key + ": " + curIssue.summary
      
      





スクリプトの結果として、スクリプトの最後の変数の内容、この場合は結果が表示されます。





作業環境のセットアップ



非常に小さなスクリプトのみを作成する場合は、このセクションをスキップできます。 もちろん、コード補完、デバッグモード、バージョン管理システム、その他の機能を備えたIDEで開発する方が便利な場合もあります。 IntelliJ IDEAはIDEとして私たちに適しています;すぐにGroovyをサポートします。 そのため、 IntelliJ IDEA (Community Editionに適しています )、 Java SDKGroovyをインストールする必要があります 。 IDEAをインストールし、新しいプロジェクトを作成します([ファイル]> [新しいプロジェクト])。 Groovyプロジェクトを選択し、JDKおよびGroovyへのパスを指定します。

新しいプロジェクト






ここで、コード補完が利用できるようにJIRAライブラリを接続する必要があります。 最も簡単なオプションは、 クラスlibフォルダーを<jira-app-dir> / atlassian-jira / WEB-INFからコピーすることです 。 最良のオプションは、公式サイトからソースをダウンロードすることです。 プロジェクト設定を開きます: ファイル>プロジェクト構造>プロジェクト設定>ライブラリクラスlibフォルダーをプロジェクトに追加します。

プロジェクトライブラリ






それでは、リモートデバッグを設定しましょう。 JIRAでデバッグモードを有効にするには、パラメーターをjvm argsに追加する必要があります。
 -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=8000
      
      



その後、 「実行」>「構成の編集」を開き、新しいリモート構成を追加します。 [設定]タブで、「Jira Debug」などの設定名を入力し、JIRAが配置されているホストを指定します。 当然、デバッグ用のポート番号は、jvm argsのアドレスパラメータで指定したポート番号と同じである必要があります。



確認します。 プロジェクトのルートにスクリプトを作成します。 このスクリプトをJIRAインスタンスの%scriptroot%フォルダーにコピーします。 デバッグの実行:[実行]> ['Jira Debug'のデバッグ]をクリックします。 次のメッセージが表示されます: ターゲットVMに接続、アドレス:%your_host%、トランスポート: 'ソケット'。 スクリプトコンソールで、スクリプトの名前を入力し、[実行]をクリックします。 次のようなものが表示されるはずです。

Groovyデバッグ






JIRAはデバッグをリリースするまで応答しないことに注意してください。 デバッグ用に別のインスタンスが必ず必要です。 ところで、IDEAでは、Groovyコンソール( ツール> Groovyコンソール )を使用して、Groovyコードを確認できます。



スクリプト



エンティティを操作するために、JIRA APIは対応する名前のコンポーネントを使用します。それらのいくつかは、IssueManager、ProjectManager、UserManager、SearchService、CustomFieldManager、CommentManagerです。 それらのインスタンスは、ComponentAccessorを介して取得できます。以下に例を示します。 目的のメソッドを検索する際に、コード補完を備えたIDEAが役立ちます。説明-JIRA Java APIドキュメント JIRA自体のインターフェイスを介してエンティティのIDを確認できます。編集または表示するためのリンクを見つけるだけで、ほとんどの場合、URLには必要なIDが含まれます。 ネットワークにはJavaでJIRAを使用した多くの例があり、ほとんどの場合、このコードは変更なしでGroovyで動作することは注目に値します。



おそらく、スクリプトで最も一般的なタスクは問題の変更でしょう。 概要といくつかのカスタムフィールドを変更するコードを書きましょう。

 import com.atlassian.crowd.embedded.api.User import com.atlassian.jira.ComponentManager import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.event.type.EventDispatchOption import com.atlassian.jira.issue.CustomFieldManager import com.atlassian.jira.issue.IssueManager import com.atlassian.jira.issue.ModifiedValue import com.atlassian.jira.issue.MutableIssue import com.atlassian.jira.issue.fields.CustomField import com.atlassian.jira.issue.util.DefaultIssueChangeHolder //  - ComponentManager componentManager = ComponentManager.getInstance() IssueManager issueManager = ComponentAccessor.getIssueManager() CustomFieldManager customFieldManager = componentManager.getCustomFieldManager() //   User curUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() //  issue    MutableIssue curIssue = issueManager.getIssueObject("PRJ-1") // 1.     Summary. //       issue. curIssue.summary = "New summary" //   issue  Jira. //  ,      event IssueUpdated,    ,   . //     issue,   issue,         . issueManager.updateIssue(curUser, curIssue, EventDispatchOption.ISSUE_UPDATED, false) // 2.    . (1) //     . CustomField cfReleaseVersion = customFieldManager.getCustomFieldObjectByName("Release Version") //         event curIssue.setCustomFieldValue(cfReleaseVersion, "3.5") issueManager.updateIssue(curUser, curIssue, EventDispatchOption.ISSUE_UPDATED, false) // 3.    . (2) //     id. CustomField cfUpdateVersion = customFieldManager.getCustomFieldObject("customfield_13500") // ""   ,    event       issue. cfUpdateVersion.updateValue(null, curIssue, new ModifiedValue(null, "2.4"), new DefaultIssueChangeHolder())
      
      





次に、コメント付きのいくつかの例。

JQLクエリによる検索の問題
 import com.atlassian.crowd.embedded.api.User import com.atlassian.jira.bc.issue.search.SearchService import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.Issue import com.atlassian.jira.issue.IssueManager import com.atlassian.jira.web.bean.PagerFilter IssueManager issueManager = ComponentAccessor.getIssueManager() SearchService searchService = ComponentAccessor.getComponent(SearchService.class) User curUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() // JQL-   issue,      String JqlQuery = "created > -2d" def parseResult = searchService.parseQuery(curUser, JqlQuery) def searchResult = searchService.search(curUser, parseResult.getQuery(), PagerFilter.getUnlimitedFilter()) def IssuesByJql = searchResult.issues.collect { issueManager.getIssueObject(it.id) } return IssuesByJql
      
      





課題間のリンク作成
 import com.atlassian.crowd.embedded.api.User import com.atlassian.jira.ComponentManager import com.atlassian.jira.component.ComponentAccessor import com.atlassian.jira.issue.IssueManager import com.atlassian.jira.issue.link.IssueLinkManager import com.atlassian.jira.issue.link.IssueLinkType import com.atlassian.jira.issue.link.IssueLinkTypeManager IssueManager issueManager = ComponentAccessor.getIssueManager() IssueLinkManager issueLinkManager = ComponentManager.getInstance().getIssueLinkManager() IssueLinkTypeManager issueLinkTypeManager = (IssueLinkTypeManager) ComponentManager.getComponentInstanceOfType(IssueLinkTypeManager.class) User curUser = ComponentAccessor.getJiraAuthenticationContext().getLoggedInUser() //      IssueLinkType duplicateLinkType = issueLinkTypeManager.getIssueLinkTypesByName("Duplicate")?.first() if (duplicateLinkType != null) { def issue_1 = issueManager.getIssueObject("PRJ-1") def issue_2 = issueManager.getIssueObject("PRJ-2") //   PRJ-1 duplicates PRJ-2 issueLinkManager.createIssueLink(issue_1.id, issue_2.id, duplicateLinkType.id, null, curUser) }
      
      







WorkFlowスクリプト(PostFunction、Validator、Condition)では、現在の課題は課題変数を介してアクセスでき、ScriptRunnerによってバインドされます。 傍聴者の編成は少し異なります。 AbstractIssueEventListenerを継承する独自のクラスを作成する必要があります。

最も単純なリスナーは次のようになります。

 package Listeners //      %scriptroot%/Listeners import com.atlassian.jira.event.issue.AbstractIssueEventListener import com.atlassian.jira.event.issue.IssueEvent import com.atlassian.jira.issue.Issue import org.apache.log4j.Level import org.apache.log4j.Logger class SimpleListener extends AbstractIssueEventListener { Logger log = Logger.getLogger(this.class.simpleName) @Override void workflowEvent(IssueEvent event) { this.customEvent(event) } @Override void customEvent(IssueEvent event) { Issue curIssue = event.issue log.setLevel(Level.DEBUG) log.debug("Event catch: ${event.eventTypeId} fired for ${curIssue.key} (${curIssue.issueTypeObject.name}).") } }
      
      





おわりに



Groovyでは、httpリクエストの実行、データベースからのデータの読み取り、レターの送信、JIRA Java APIおよび標準Javaライブラリの使用が可能です。 ScriptRunner自体には、スクリプトフィールド、単体テスト、組み込みスクリプトなど、この記事では触れなかった多くの機能がまだあります。 JIRAをバージョン7にアップグレードする予定がある場合(または既に使用している場合)は、4つ目の有料バージョンのScriptRunnerしかインストールできないことに注意してください。 ただし、すべての基本機能は、2番目と3番目の無料バージョンで利用できます。 上記のスクリプトは、JIRA 6.4.12(Java 8)およびScriptRunner 3.0.16でテストされました。



資源



ScriptRunner公式サイト

Atlassian MarketplaceのScriptRunner

Groovy公式ウェブサイト

JIRA APIドキュメント

Rocking With Jira ScriptRunnerの記事 (注意、時々時代遅れのコード)

古いScriptRunnerドキュメント(3.0より前のバージョン用)



All Articles