Всем привет!
В этой статье я хочу рассказать, как создать свою функцию в SIL.
SIL расшифровывается, как Simple Issue Language, был создан разработчиками компании cPrime для автоматизации ручных действий в Atlassian Jira и Confluence.
Основное преимущество SIL заключается в том, что SIL содержит функции, которые не требуют знания API Atlassian Jira или Atlassian Confluence для их использования. Это значительно снижает порог вхождения в SIL и делает программный код на SIL меньше по объему, нежели аналогичный код на Java или Groovy.
Например, вы хотите выбрать тикеты из Jira по запросу, чтобы потом произвести над ними какие-то действия. Для этого на Java или Groovy Вам бы пришлось написать с десяток строк кода. На SIL это одна строка:
Более того, на Java или Groovy Вам пришлось бы обеспечить совместимость кода на Jira 7 и Jira 8. В SIL Вам думать о совместимости не нужно. SelectIssues будет работать на всех версиях Jira, которые поддерживает SIL.
Вы можете найти больше про SIL здесь.
А что делать, если мне нужно сделать что-то такое, для чего функций в SIL нет? Например, мне нужно получить данные из плагина Table Grid Next Generation или сформировать PDF файл с помощью плагина PDF exporter for Jira.
В этом случае Вам доступны две опции:
В этой статье мы остановимся на том, как написать свой Jira плагин, чтобы расширить функции SIL. Для того, чтобы повторить действия из этой статьи Вам понадобятся Atlassian SDK и git.
Плагин, который будет расширять SIL, должен содержать логику, которая будет добавлять Ваши функции в SIL. Чтобы каждый раз не добавлять эту логику в плагин, а с концентрироваться только на написании функций, я сделал архетип maven, который будет создавать все необходимое в новом плагине.
Сначала склонируем архетип из репозитория:
Будет создана папка sil-extenstion-archetype. Перейдем в нее:
Теперь установим архетип в Ваш локальный репозиторий maven:
Переходим в папку выше и создаем новый плагин
Вам будут заданы стандартные вопросы при создании проекта через maven. Привожу свои ответы на вопросы. Вы можете их изменить.
После этого плагин будет создан.
Переходим в созданную папку( в моем случае это sil-extension) и запускаем Jira:
Вы увидите экран SIL Manager. Выбираем опцию New File:
Создайте файл test.sil следующего содержания:
Экран в Jira будет выглядеть примерно вот так:
Наш плагин добавил три функции: SayHello, SayHello2, SayHello3. Test.sil проверяет, что функции добавились в SIL.
Запустим test.sil, нажав на кнопку Run. Во вкладке Console Вы должы увидеть следующий текст:
Если Вы увидели такой текст, то наши функции успешно добавились в SIL.
Теперь поговорим о том, что нужно изменить в плагине, чтобы создать свою функцию.
Каждая функция, которую Вы хотите добавить в SIL, должна иметь свой класс. Этот класс должен быть наследником класса AbstractSILRoutine.
Для того, чтобы понять, что нужно добавить в новый класс, давайте, посмотрим на доступные примеры.
Первая строка:
Эта строка определяет типы и количество параметров, которые будут переданы в Вашу функцию. Функция в SIL выглядет вот так:
Соответсвенно {{ TypeInst.STRING }} говорит о том, что у нас будет один параметр и его тип будет String. Если Вы хотите передать два параметра типа String, то нужно изменить строку вот так:
В SIL Вы можете вызвать Вашу функцию вот так:
Если Ваша функция может принимать как один, так и два параметра. То срока будет выглядеть вот так:
Далее идет:
Мы наследуем наш класс от AbstractSILRoutine, что означает что наш класс будет возвращать параметр типа String.
Далее:
Это конструктор. Вам ничего в нем менять, скорее всего, не придется.
Далее:
Здесь мы определяем тип возвращаемого параметра. В нашем случае это String.
Далее:
Это основная точка входа для Вашей функции. При выполнении функции в SIL, Вы попадете сюда. Вся логика находится здесь.
Эта функция принимает два параметра:
silContext — позволяет достать переменные Jira и SIL.
Например, Ваш SIL скрипт работает ка пост функция и Вы хотите получить тикет, под которым выполняется скрипт:
list — позволяет получить значения параметров, переданных в функцию SIL.
Строка:
возвращает значение. Вы должны возвращать значения, которые будут понятны SIL, поэтому используйте SILValueFactory для генерации значений.
Далее:
Здесь определяется вид функции в SIL Manager. Когда Вы начинаете печатать в SIL manager, то Вы виде подсказки доступных функций. В нашем случае Вы увидите:
Вы создали свой класс. Теперь нужно сделать так, чтобы SIL знал о Вашей функции. Это делается в файле ESLauncher.java. В этом файле есть вот такие строчки:
Эта строка говорит о том, что мы добавляем класс SayHello в SIL под именем SayHello. Имя класса и функции могут не совпадать.
Далее нужно добавить вот такую строку:
Измените SayHello на имя Вашей функции. Эта строчка выгрузит Вашу функцию из SIL, если вы удалите Ваш плагин из Jira.
В классе SayHello2, мы возвращаем List.
Для того, чтобы это заработало, нужно еще изменить возвращаемое значение на TypeInst.STRING_ARR and унаследоваться от AbstractSILRoutine with KeyableArraySILObject.
В SIL Вы вызываете SayHello2 вот так:
В SayHello3 мы возвращаем Map:
В SIL можно вызвать SayHello3 вот так:
В этом случае мы получаем элементы массива не по индексу, а по ключам.
Если Вы посмотрите на код в Java, то мы в обоих случаях работаем с KeyableArraySILObject. Дело в том, что в SIL List и Map реализуются классом KeyableArraySILObject. Т.е. к любому массиву в SIL, можно обращаться как по индексу, так и по ключу.
Мы умеем возвращать из функции SIL массив. Теперь давайте посмотрим, как передать массив в качестве параметра.
Код будет выглядеть вот так:
Сначала мы получаем из параметра объект класса GenericArraySILObject, а потом получаем из него Map.
В SIL можно передавать массив вот так:
На этом я заканчиваю эту статью. Надеюсь, Вы получили достаточно знаний для того, чтобы написать свою функцию в SIL.
В этой статье я хочу рассказать, как создать свою функцию в SIL.
Вступление
SIL расшифровывается, как Simple Issue Language, был создан разработчиками компании cPrime для автоматизации ручных действий в Atlassian Jira и Confluence.
Основное преимущество SIL заключается в том, что SIL содержит функции, которые не требуют знания API Atlassian Jira или Atlassian Confluence для их использования. Это значительно снижает порог вхождения в SIL и делает программный код на SIL меньше по объему, нежели аналогичный код на Java или Groovy.
Например, вы хотите выбрать тикеты из Jira по запросу, чтобы потом произвести над ними какие-то действия. Для этого на Java или Groovy Вам бы пришлось написать с десяток строк кода. На SIL это одна строка:
selectIssues("Ваш JQL запрос");
Более того, на Java или Groovy Вам пришлось бы обеспечить совместимость кода на Jira 7 и Jira 8. В SIL Вам думать о совместимости не нужно. SelectIssues будет работать на всех версиях Jira, которые поддерживает SIL.
Вы можете найти больше про SIL здесь.
А что делать, если мне нужно сделать что-то такое, для чего функций в SIL нет? Например, мне нужно получить данные из плагина Table Grid Next Generation или сформировать PDF файл с помощью плагина PDF exporter for Jira.
В этом случае Вам доступны две опции:
- SIL Groovy Connector — этот плагин позволяет написать код с иcпользованием Jira Java API на Java или Groovy и вызывать этот код из SIL скрипта.
- Написать свой Jira плагин, который добавит Ваши функции в SIL, и потом использовать Ваши функции в SIL скриптах
В этой статье мы остановимся на том, как написать свой Jira плагин, чтобы расширить функции SIL. Для того, чтобы повторить действия из этой статьи Вам понадобятся Atlassian SDK и git.
Устанавливаем maven архетип
Плагин, который будет расширять SIL, должен содержать логику, которая будет добавлять Ваши функции в SIL. Чтобы каждый раз не добавлять эту логику в плагин, а с концентрироваться только на написании функций, я сделал архетип maven, который будет создавать все необходимое в новом плагине.
Сначала склонируем архетип из репозитория:
git clone https://alex1mmm@bitbucket.org/alex1mmm/sil-extension-archetype.git --branch v1 --single-branch
Будет создана папка sil-extenstion-archetype. Перейдем в нее:
cd sil-extension-archetype
Теперь установим архетип в Ваш локальный репозиторий maven:
atlas-mvn install
Создаем плагин
Переходим в папку выше и создаем новый плагин
cd ..
atlas-mvn archetype:generate -DarchetypeCatalog=local
Вам будут заданы стандартные вопросы при создании проекта через maven. Привожу свои ответы на вопросы. Вы можете их изменить.
Choose archetype:
1: local -> com.cprime.jira.sil.extension:sil-extension-archetype (This is the com.cprime.jira.sil.extension:sil-extension plugin for Atlassian JIRA.)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): :
Define value for property 'groupId': ru.matveev.alexey.sil.extension
Define value for property 'artifactId': sil-extension
Define value for property 'version' 1.0-SNAPSHOT: :
Define value for property 'package' ru.matveev.alexey.sil.extension: :
Confirm properties configuration:
groupId: ru.matveev.alexey.sil.extension
artifactId: sil-extension
version: 1.0-SNAPSHOT
package: ru.matveev.alexey.sil.extension
Y: : Y
После этого плагин будет создан.
Тестируем плагин
Переходим в созданную папку( в моем случае это sil-extension) и запускаем Jira:
cd sil-extension
atlas-run</code>
Открываем Jira в Вашем браузере
<code>http://localhost:2990/jira/plugins/servlet/silmanager?autoSelectTree=sil.scripts
Вы увидите экран SIL Manager. Выбираем опцию New File:
Создайте файл test.sil следующего содержания:
runnerLog(SayHello("Alexey"));
string[] res = SayHello2("Alexey", "Matveev");
runnerLog(res[0]);
runnerLog(res[1]);
res = SayHello3("Alexey", "Matveev");
runnerLog(res["param1"]);
runnerLog(res["param2"]);
Экран в Jira будет выглядеть примерно вот так:
Наш плагин добавил три функции: SayHello, SayHello2, SayHello3. Test.sil проверяет, что функции добавились в SIL.
Запустим test.sil, нажав на кнопку Run. Во вкладке Console Вы должы увидеть следующий текст:
Hello Alexey
Hello Alexey
Hello Matveev
Hello Alexey
Hello Matveev
Done.
Если Вы увидели такой текст, то наши функции успешно добавились в SIL.
Теперь поговорим о том, что нужно изменить в плагине, чтобы создать свою функцию.
Создаем Java класс для нашей функции
Каждая функция, которую Вы хотите добавить в SIL, должна иметь свой класс. Этот класс должен быть наследником класса AbstractSILRoutine.
Для того, чтобы понять, что нужно добавить в новый класс, давайте, посмотрим на доступные примеры.
SayHello.java
public class SayHello extends AbstractSILRoutine<MutableString> {
private static final SILType[][] types = {{ TypeInst.STRING }};
public SayHello(ClassLoader classLoader, String name) {
super(classLoader, name, types);
}
@Override
public SILType<MutableString> getReturnType() { return TypeInst.STRING; }
@Override
protected SILValue<MutableString> runRoutine(SILContext silContext, List<SILValue<?>> list) {
SILValue param = list.get(0);
return SILValueFactory.string( "Hello " + param.toStringValue());
}
@Override
public String getParams() { return "(name)"; }
Первая строка:
private static final SILType[][] types = {{ TypeInst.STRING }};
Эта строка определяет типы и количество параметров, которые будут переданы в Вашу функцию. Функция в SIL выглядет вот так:
mymethod(myparameter);
Соответсвенно {{ TypeInst.STRING }} говорит о том, что у нас будет один параметр и его тип будет String. Если Вы хотите передать два параметра типа String, то нужно изменить строку вот так:
private static final SILType[][] types = {{ TypeInst.STRING, TypeInst.STRING }};
В SIL Вы можете вызвать Вашу функцию вот так:
mymethod(myparameter1, myparameter2);
Если Ваша функция может принимать как один, так и два параметра. То срока будет выглядеть вот так:
private static final SILType[][] types = {{ TypeInst.STRING},
{TypeInst.STRING, TypeInst.STRING }};
Далее идет:
public class SayHello extends AbstractSILRoutine<MutableString>
Мы наследуем наш класс от AbstractSILRoutine, что означает что наш класс будет возвращать параметр типа String.
Далее:
public SayHello(ClassLoader classLoader, String name) {
super(classLoader, name, types);
}
Это конструктор. Вам ничего в нем менять, скорее всего, не придется.
Далее:
@Override
public SILType<MutableString> getReturnType() { return TypeInst.STRING; }
Здесь мы определяем тип возвращаемого параметра. В нашем случае это String.
Далее:
@Override
protected SILValue<MutableString> runRoutine(SILContext silContext, List<SILValue<?>> list) {
SILValue param = list.get(0);
return SILValueFactory.string( "Hello " + param.toStringValue());
}
Это основная точка входа для Вашей функции. При выполнении функции в SIL, Вы попадете сюда. Вся логика находится здесь.
Эта функция принимает два параметра:
silContext — позволяет достать переменные Jira и SIL.
Например, Ваш SIL скрипт работает ка пост функция и Вы хотите получить тикет, под которым выполняется скрипт:
Issue issue = (Issue) silContext.getAllMetaInformation().get("issue");
list — позволяет получить значения параметров, переданных в функцию SIL.
SILValue param = list.get(0);
Строка:
SILValueFactory.string( "Hello " + param.toStringValue());
возвращает значение. Вы должны возвращать значения, которые будут понятны SIL, поэтому используйте SILValueFactory для генерации значений.
Далее:
@Override
public String getParams() { return "(name)"; }
Здесь определяется вид функции в SIL Manager. Когда Вы начинаете печатать в SIL manager, то Вы виде подсказки доступных функций. В нашем случае Вы увидите:
yourmethod(name)
Добавим наш класс в SIL engine
Вы создали свой класс. Теперь нужно сделать так, чтобы SIL знал о Вашей функции. Это делается в файле ESLauncher.java. В этом файле есть вот такие строчки:
RoutineRegistry.register(new SayHello( classLoader,"SayHello"));
Эта строка говорит о том, что мы добавляем класс SayHello в SIL под именем SayHello. Имя класса и функции могут не совпадать.
Далее нужно добавить вот такую строку:
RoutineRegistry.unregister("SayHello");
Измените SayHello на имя Вашей функции. Эта строчка выгрузит Вашу функцию из SIL, если вы удалите Ваш плагин из Jira.
Больше о SIL
В классе SayHello2, мы возвращаем List.
SILValue param1 = list.get(0);
SILValue param2 = list.get(1);
List<String> res = new ArrayList<>();
res.add("Hello " + param1.toStringValue());
res.add("Hello " + param2.toStringValue());
return SILValueFactory.stringArray(res);
Для того, чтобы это заработало, нужно еще изменить возвращаемое значение на TypeInst.STRING_ARR and унаследоваться от AbstractSILRoutine with KeyableArraySILObject.
В SIL Вы вызываете SayHello2 вот так:
string[] res = SayHello2("Alexey", "Matveev");
runnerLog(res[0]);
runnerLog(res[1]);
В SayHello3 мы возвращаем Map:
SILValue param1 = list.get(0);
SILValue param2 = list.get(1);
Map<String, String> res = new HashMap<>();
res.put("param1","Hello " + param1.toStringValue());
res.put("param2","Hello " + param2.toStringValue());
return SILValueFactory.stringArray(res);
В SIL можно вызвать SayHello3 вот так:
res = SayHello3("Alexey", "Matveev");
runnerLog(res["param1"]);
runnerLog(res["param2"]);
В этом случае мы получаем элементы массива не по индексу, а по ключам.
Если Вы посмотрите на код в Java, то мы в обоих случаях работаем с KeyableArraySILObject. Дело в том, что в SIL List и Map реализуются классом KeyableArraySILObject. Т.е. к любому массиву в SIL, можно обращаться как по индексу, так и по ключу.
Передаем массив в качестве параметра
Мы умеем возвращать из функции SIL массив. Теперь давайте посмотрим, как передать массив в качестве параметра.
Код будет выглядеть вот так:
@Override
protected SILValue<MutableString> runRoutine(SILContext silContext, List<SILValue<?>> list) {
GenericArraySILObject rowsToUpdate = (GenericArraySILObject) list.get(0).getObject();
Map<String, int[]> keys = rowsToUpdate.getKeysMapping()
......
}
Сначала мы получаем из параметра объект класса GenericArraySILObject, а потом получаем из него Map.
В SIL можно передавать массив вот так:
string[] arr;
arr["key1"] = "value1";
arr["key2"] = "value2";
yourmethod(arr);
На этом я заканчиваю эту статью. Надеюсь, Вы получили достаточно знаний для того, чтобы написать свою функцию в SIL.