Добавление JQL-функции в Jira

Применимость

Jira 7.0.0 и более поздних версий.

Уровень опыта

Intermediate. Вы должны были пройти хотя бы один учебник для начинающих, прежде чем работать с этим учебником. См. Список учебников для разработчиков.

Временная оценка

Для завершения этого урока вам потребуется примерно полчаса.

Обзор учебника

В этом учебном пособии показано, как добавить JQL-функцию в Jira. Затем вы сможете использовать функцию в расширенной форме поиска, чтобы находить задачи только в тех проектах, к которым вы недавно обращались. В реальном мире пользователь, скорее всего, будет использовать эту функцию в сочетании с другим предложением поиска. Это было бы полезно в системах, которые имеют много проектов, и где пользователи обычно заботятся только о немногих.

Как используются функции в JQL-запросах? Запрос JQL состоит из одного или нескольких предложений. Каждое предложение состоит из поля, оператора и операнда. Например, assignee = fred, где:

  • Поле является assignee.
  • Оператор =.
  • Оператор - fred

В этом случае операнд является литеральной строкой fred. Но это также может быть функцией. Jira поставляется со многими встроенными функциями. И вы можете добавить их, как мы это сделаем.

В этом уроке вы создадите приложение функций JQL, состоящее из этих компонентов:

  1. Java-классы, инкапсулирующие логику приложения.
  2. Дескриптор приложения для включения модуля плагина в Jira.

Когда вы закончите, все эти компоненты будут упакованы в один JAR-файл.

Об этих инструкциях

Вы можете использовать любую поддерживаемую комбинацию операционной системы и IDE для создания этого приложения. Эти инструкции были написаны с использованием IntelliJ IDEA 2017.3 на macOS Sierra. Если вы используете другую операционную систему или комбинацию IDE, вы должны использовать эквивалентные операции для своей конкретной среды.

Этот учебник был последний раз проверен с помощью Jira 7.7.1, AMPS 6.3.15 и Atlassian SDK версии 6.3.10.

Прежде чем вы начнете

Чтобы завершить этот учебник, вам необходимо знать следующее:

  1. Основы разработки Java: классы, интерфейсы, методы, использование компилятора и т. д.
  2. Как создать проект Atlassian plugin с помощью Atlassian Plugin SDK.
  3. Основы использования и администрирования Jira, а также использование JQL Advanced Search.

Источник приложения

Мы рекомендуем вам проработать этот учебник. Если вы хотите пропустить или проверить свою работу, когда закончите, вы можете найти исходный код приложения на Atlassian Bitbucket.

Чтобы клонировать репозиторий, выполните следующую команду:


git clone https://bitbucket.org/atlassian_tutorial/jira-simple-jql-function.git

Кроме того, вы можете загрузить исходный код в виде ZIP-архива.

Шаг 1. Создайте проект приложения

На этом этапе вы будете использовать команду atlas- для создания кода-заглушки для вашего приложения и настройки кода-заглушки. Атлас-команды являются частью Atlasian Plugin SDK и автоматизируют большую часть разработки приложений для вас.

  1. Настройте SDK Atlassian Plugin и создайте проект, если вы еще этого не сделали.
  2. Чтобы создать скелет приложения, выполните следующую команду:

atlas-create-jira-plugin

  1. Чтобы определить ваше приложение, введите следующую информацию.

group-id

com.example.plugins.tutorial.jira

artifact-id

jira-simple-jql-function

version

1.0-SNAPSHOT

package

com.example.plugins.tutorial.jira

  1. Подтвердите свои записи при появлении запроса.

SDK создает исходные файлы проекта приложения в каталоге jira-simple-jql-function.

Шаг 2. Просмотрите и настройте POM

Это хорошая идея, чтобы ознакомиться с файлом конфигурации проекта, известным как POM (то есть, файл определения модели объекта проекта). На этом этапе вы просмотрите и настроите файл pom.xml. Файл объявляет зависимости проекта и другую информацию.

  1. Перейдите в новый каталог jira-simple-jql-function и откройте файл pom.xml.
  2. Добавьте название вашей компании или организации и URL вашего веб-сайта к элементу organization (следующий блок кода показывает, как он выглядит простым текстом):

<organization>
    <name>Example Company</name>
    <url>http://www.example.com/</url>
</organization>

  1. Обновите элемент description :

<description> Добавляет пользовательскую JQL-функцию с именем RecentProjects в JIRA. </ description>

  1. Сохраните и закройте файл.

Шаг 3. Добавьте модули плагина

Теперь вы будете использовать генератор модуля плагина (то есть другую команду atlas) для создания кода заглушки для модулей, требуемых приложением.

Для этого урока вам нужен модуль плагина JQL Function. Вы добавите его, используя команду atlas-create-HOSTAPP-plugin-module.

  1. Перейдите в корневую папку приложения, где находится pom.xml, и выполните следующую команду:

atlas-create-jira-plugin-module

  1. Выберите опцию JQL Function.
  2. При появлении запроса введите следующую информацию.

Enter New Classname

Введите новое имя класса

RecentProjectFunction

Package Name

Имя пакета

com.example.plugins.tutorial.jira.jql

 

  1. Выберите «N» для «Показать расширенную настройку».
  2. Выберите «N» для добавления другого модуля плагина.
  3. Подтвердите свой выбор.

Шаг 4. Просмотрите и настройте дескриптор приложения.

SDK добавила JQL-модуль функции в наш дескриптор приложения, который описывает приложение для Jira. Давайте настроем добавленную декларацию модуля.

  1. Перейдите в src / main / resources / и откройте файл atlassian-plugin.xml.
  2. Найдите элемент jql-function, а затем добавьте элементы fname и list после описания.

<jql-function name="Recent Project Function"
i18n-name-key="recent-project-function.name" 
 key="recent-project-function" 
 class="com.example.plugins.tutorial.jira.jql.RecentProjectFunction"> 
  <description key="recent-project-function.description">The Recent Project Function Plugin</description> 
  <fname>
  recentProjects
  </fname>   
<list>
true
</list> 
</jql-function> 

Имя fname представляет собой имя для нашей функции, так как оно будет использоваться в операторах JQL.

list указывает, возвращает ли эта функция список задач или одно значение.

  1. Сохраните и закройте файл.

Шаг 5. Напишите код приложения

SDK предоставил нам код заглушки для нашего класса. На этом этапе мы добавляем логику для нашей функции.

  1. Перейдите в src / main / java / com / example / plugins / tutorial / jira / jql / и откройте файл RecentProjectFunction.java.
  2. Замените import com.opensymphony.user.User; со следующим положением импорта:

import com.atlassian.jira.user.ApplicationUser;

  1. Обновить метод validate () для использования ApplicationUser вместо User

public MessageSet validate(ApplicationUser searcher, FunctionOperand operand, TerminalClause terminalClause) {
    return validateNumberOfArgs(operand, 1);
}

  1. Добавьте следующие положения импорта:

import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import com.atlassian.jira.user.UserHistoryItem;
import com.atlassian.jira.user.UserProjectHistoryManager;
import java.util.LinkedList;

  1. Перед определением класса добавьте аннотацию @Scanned:

@Scanned
public class RecentProjectFunction extends AbstractJqlFunction {
   ...

  1. Чтобы определить, какие проекты недавно посетил текущий пользователь, мы можем использовать UserProjectHistoryManager, который дает нам Jira. Внесите его в конструктор для нашего класса recentProjectFunction следующим образом:

@ComponentImport
private final UserProjectHistoryManager userProjectHistoryManager;
 
public RecentProjectFunction(UserProjectHistoryManager userProjectHistoryManager) {
   this.userProjectHistoryManager = userProjectHistoryManager;
}

  1. Наша функция пока не принимает никаких аргументов. В методе validate () измените количество аргументов от 1 до 0:

return validateNumberOfArgs(operand, 0);

  1. Функция getValues () - это основная часть работы. Замените ту, которую SDK дал нам с этой:

public List<QueryLiteral> getValues(QueryCreationContext queryCreationContext, FunctionOperand operand, TerminalClause terminalClause) {
    final List<QueryLiteral> literals = new LinkedList<>();
    final List<UserHistoryItem> projects = userProjectHistoryManager.getProjectHistoryWithoutPermissionChecks(queryCreationContext.getApplicationUser());
 
    for (final UserHistoryItem userHistoryItem : projects) {
        final String value = userHistoryItem.getEntityId();
 
        try {
            literals.add(new QueryLiteral(operand, Long.parseLong(value)));
        } catch (NumberFormatException e) {
            log.warn(String.format("User history returned a non numeric project IS '%s'.", value));
        }
    }   }
          return literals;
} 

Функция возвращает список QueryLiterals, которые представляют список идентификаторов недавно посещенных проектов, предлагаемых userProjectHistoryManager, и заполняет связанный список с результатами, преобразованными в QueryLiterals. Любой пользователь может использовать эту функцию, поэтому вместо этого мы используем getProjectHistoryWithoutPermissionChecks ().

Кроме того, мы можем использовать getProjectHistoryWithPermissionChecks (), который выполняет проверку разрешений на основе разрешений, которые пользователь должен иметь для проекта.

  1. В getMinimumNumberOfExpectedArguments () измените возвращаемое значение на 0:

public int getMinimumNumberOfExpectedArguments() {
  return 0;
}

  1. В getDataType () измените тип данных, возвращенный из TEXT в PROJECT, потому что мы возвращаем только список проектов.

return JiraDataTypes.PROJECT;

Весь класс должен выглядеть примерно так:


package com.example.plugins.tutorial.jira.jql;
 
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.user.UserHistoryItem;
import com.atlassian.jira.user.UserProjectHistoryManager;
import com.atlassian.plugin.spring.scanner.annotation.component.Scanned;
import com.atlassian.plugin.spring.scanner.annotation.imports.ComponentImport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.atlassian.jira.JiraDataType;
import com.atlassian.jira.JiraDataTypes;
import com.atlassian.jira.jql.operand.QueryLiteral;
import com.atlassian.jira.jql.query.QueryCreationContext;
import com.atlassian.jira.plugin.jql.function.AbstractJqlFunction;
import com.atlassian.jira.util.MessageSet;
import com.atlassian.query.clause.TerminalClause;
import com.atlassian.query.operand.FunctionOperand;
import java.util.LinkedList;
import java.util.List;
 
@Scanned
public class RecentProjectFunction extends AbstractJqlFunction {
    private static final Logger log = LoggerFactory.getLogger(RecentProjectFunction.class);
 
    @ComponentImport
    private final UserProjectHistoryManager userProjectHistoryManager;
    public RecentProjectFunction(UserProjectHistoryManager userProjectHistoryManager) 
{   this.userProjectHistoryManager = userProjectHistoryManager;     
}       
public MessageSet validate(ApplicationUser searcher, FunctionOperand operand, TerminalClause terminalClause) 
{    return validateNumberOfArgs(operand, 0); 
 }       public List<QueryLiteral> getValues(QueryCreationContext queryCreationContext, FunctionOperand operand, TerminalClause terminalClause)
 {         final List<QueryLiteral> literals = new LinkedList<>();         
           final List<UserHistoryItem> projects = userProjectHistoryManager.getProjectHistoryWithoutPermissionChecks(queryCreationContext.getApplicationUser());           
           for (final UserHistoryItem userHistoryItem : projects) 
{          final String value = userHistoryItem.getEntityId();               
try {                 literals.add(new QueryLiteral(operand, Long.parseLong(value)));             } 
catch (NumberFormatException e) {                 
log.warn(String.format("User history returned a non numeric project IS '%s'.", value));             
}         
}           return literals;     
}       public int getMinimumNumberOfExpectedArguments() 
{         return 0;     
}       
public JiraDataType getDataType() 
{         return JiraDataTypes.PROJECT;     
} 
} 

Шаг 6. Удалите тестовые файлы.

SDK был достаточно полезен, чтобы предоставить нам единичные и интеграционные тестовые файлы-заглушки для нашего кода приложения. Тем не менее, они действительно предназначены для того, чтобы стать отправными точками для вашего тестирования, поэтому они требуют больше внимания, чтобы быть полезными. Тестирование - большая тема, поэтому мы оставляем это для другого учебника под названием «Написание и запуск тестов приложений».

 

На данный момент просто удалите тесты, чтобы мы могли проверить приложение, не изменяя их.

 

В терминале перейдите в корневой каталог проекта и выполните следующую команду:


rm -rf src/main/test

Шаг 7. Запустите Jira и проверьте приложение.

Мы готовы попробовать приложение.

  1. Откройте окно терминала, перейдите в корневую папку приложения и запустите команду atlas-run (или atlas-debug, если вы хотите запустить отладчик в своей среде IDE).
  2. Откройте экземпляр Jira в браузере (URL-адрес указывается в выводе терминала).
  3. Войдите в систему, используя admin / admin по умолчанию.
  4. Создайте два или три проекта и заполните их несколькими задачами. Это даст нам некоторые данные для работы.
  5. В заголовке Jira нажмите Issues «Задачи» >«Search for Issues» «Поиск задач.
  6. Чтобы переключить форму для режима расширенного поиска с помощью JQL, нажмите «Дополнительно».
  7. В поле поиска введите следующее: project в recentProjects ()

Обратите внимание, что автозаполнение предлагает вам новую функцию в своих предложениях по завершению проекта.

  1. Нажмите значок поиска, чтобы выполнить поиск. Появляется список задач в недавно посещенных проектах.

Следующие шаги

Чтобы расширить функцию JQL, вы можете заставить ее принять параметр. Кроме того, функции, как правило, должны проверять разрешения в Jira, чтобы они возвращали только проекты, к которым у пользователя есть доступ. В нашем случае, поскольку мы используем недавнюю функцию истории, мы уже знаем, что пользователь может получить доступ к возвращенным проектам. Для получения дополнительной информации по этим темам см. Модуль плагина функции JQL.

Для получения дополнительной информации о пользовательских JQL-функциях см.

  • Расширенный поиск Jira.
  • Расширенные темы.

По материалам Atlassian JIRA  Server Developer Adding a JQL function to Jira