Rendre les fonctions SIL portables entre les versions dans Jira

Bonjour à tous!

Dans cet article, nous poursuivons la discussion sur le développement de nos propres fonctions pour SIL. L'article précédent peut être lu ici .

L'un des principaux avantages de SIL est que le code écrit en SIL fonctionnera sur toutes les versions de Jira, nous devons donc également faire fonctionner nos fonctions personnalisées.

Créer un plugin à partir de sil-extension-archetype


Clonez l'archétype:

git clone https://alex1mmm@bitbucket.org/alex1mmm/sil-extension-archetype.git --branch v1 --single-branch

Installez l'archétype dans le référentiel local et créez un plugin à partir de cet archétype. Plus de détails sur la façon de procéder peuvent être trouvés ici .

Ajouter des services SIL


Afin de rendre notre fonction portable entre les différentes versions de Jira, nous utiliserons les services fournis par SIL. Ceux. nous allons proxy nos appels à l'API Java Jira via SIL Java Api.

Mais comment savoir quels services SIL propose?

Nous installons SIL et nous nous rendons à l'adresse suivante:

localhost : 2990 / jira / plugins / servlet / upm / osgi

Vous verrez des informations OSGI sur tous les plugins dans Jira:



nous trouverons le plugin dans la liste KATL Commons et ouvrirons les services enregistrés:



JMUserServices, JMProjectServices sont les services qui exportent Sil.

Nous savons maintenant quels services SIL sont disponibles et, par le nom du service, nous pouvons deviner son objectif.

Voyons le code dans le plugin créé


Nous savons maintenant quels services nous sont offerts. Utilisons-les dans notre plugin.

BeanService.java


@Named
public class BeanService {
    @Getter
    private final KIssueService kIssueService;
    @Getter
    private final ClassLoaderService classLoaderService;
    @Getter
    private final CurrentUserHelper currentUserHelper;
    @Getter
    private final JMIssueSearchServices jmIssueSearchServices;
    @Getter
    private final UserHelper userHelper;
    @Getter
    private final JMIssueServices jmIssueServices;
    @Inject
    public BeanService(@ComponentImport KIssueService kIssueService,
                       @ComponentImport CurrentUserHelper currentUserHelper,
                       @ComponentImport JMIssueSearchServices     jmIssueSearchServices,
                       @ComponentImport UserHelper userHelper,
                       @ComponentImport JMIssueServices jmIssueServices,
                       ClassLoaderService classLoaderService) {
        this.kIssueService = kIssueService;
        this.classLoaderService = classLoaderService;
        this.currentUserHelper = currentUserHelper;
        this.jmIssueSearchServices = jmIssueSearchServices;
        this.userHelper = userHelper;
        this.jmIssueServices = jmIssueServices;
    }
}

Cette classe contient tous les services que nous utiliserons pour nos fonctions. Je crée une telle classe séparée afin de ne pas dupliquer l'appel aux services dans chaque fonction.

Regardons ces lignes:

@Getter
 private final KIssueService kIssueService;

Getteril s'agit d'une annotation Lombok qui crée une méthode get pour la propriété kIssueService.

Nous créons des propriétés de classe pour chaque service utilisé. Ensuite, nous obtenons ces services via le constructeur.

    public BeanService(@ComponentImport KIssueService kIssueService,
                       @ComponentImport CurrentUserHelper currentUserHelper,
                       @ComponentImport JMIssueSearchServices jmIssueSearchServices,
                       @ComponentImport UserHelper userHelper,
                       @ComponentImport JMIssueServices jmIssueServices,
                       ClassLoaderService classLoaderService) {
        this.kIssueService = kIssueService;
        this.classLoaderService = classLoaderService;
        this.currentUserHelper = currentUserHelper;
        this.jmIssueSearchServices = jmIssueSearchServices;
        this.userHelper = userHelper;
        this.jmIssueServices = jmIssueServices;
    }

Terminé.

Ajoutez le bean BeanService à la classe ESLauncher et passez ce bean à nos fonctions:

/*   BeanService */
private final BeanService beanService;

@Inject
public ESLauncher(@ComponentImport EventPublisher eventPublisher,
                  PluginInfoService pluginInfoService,
                  @ComponentImport CommonPluginConfigurationService commonPluginConfigurationService,
                  @ComponentImport HostConfigurationProvider hostConfigurationProvider,
                  @ClasspathComponent PluginConfigurationServiceImpl pluginConfigurationService,
/*  BeanService */
                  BeanService beanService)
{
    super(eventPublisher, pluginInfoService, hostConfigurationProvider, pluginConfigurationService);

    log.error("eslauncher constructor");
    this.beanService = beanService;

}

@Override
public void doAtLaunch() {
    super.doAtLaunch();
    log.error("eslauncher doatlaunch");
    RoutineRegistry.register(new SayHello( beanService,"SayHello"));
    RoutineRegistry.register(new SayHello2( beanService,"SayHello2"));
    RoutineRegistry.register(new SayHello3( beanService,"SayHello3"));

}

Nous pouvons maintenant utiliser BeanService dans nos fonctions.

SayHello.java


Dans SayHello.java, nous créerons une fonction qui acceptera l'adresse e-mail de l'utilisateur, vérifiera que l'utilisateur qui exécute le script administrateur, supprimera tous les tickets créés par l'utilisateur avec l'adresse e-mail transmise.

Bien sûr, nous pouvons faire cette logique sans écrire notre propre fonction. Le code SIL ressemblera à ceci:

function deleteIssueForUser(string userEmail) {
  if (isUserInGroup("jira-administrators", currentUserKey())) {
    string[] issues = selectIssues("reporter = " + currentUserKey());
    for (string issue in issues) {
      deleteIssue(issue);
    }
  }
}

deleteIssueForUser("user@email.com");

Mais je voulais faire un petit exemple qui montrerait les principes de base du travail.

Voici le texte de la classe:

@Slf4j
public class SayHello extends AbstractSILRoutine<MutableString> {
    private static final SILType[][] types = {{ TypeInst.STRING }};
    private final BeanService beanService;

    public SayHello(BeanService beanService, String name) {
        super(beanService.getClassLoaderService().getPluginClassLoader(), name, types);
        this.beanService = beanService;
    }

    @Override
    public SILType<MutableString> getReturnType() {
        return TypeInst.STRING;
    }


    @Override
    protected SILValue<MutableString>  runRoutine(SILContext silContext, List<SILValue<?>> list)  {
        SILValue param = list.get(0);
        String userEmail = param.toStringValue();
        KIssueService kIssueService = beanService.getKIssueService();
        CurrentUserHelper currentUserHelper = beanService.getCurrentUserHelper();
        JMIssueSearchServices jmIssueSearchServices = beanService.getJmIssueSearchServices();
        UserHelper userHelper = beanService.getUserHelper();
        JMIssueServices jmIssueServices = beanService.getJmIssueServices();
        ApplicationUser requestedUser = userHelper.getUserByEmail(userEmail);

        if (currentUserHelper.isUserAdministrator()) {
            SearchService.ParseResult parseResult = jmIssueSearchServices.getSearchService().parseQuery(requestedUser, "reporter = " + requestedUser.getKey());
            List<Issue> issues = (List<Issue>) kIssueService.searchIssues(requestedUser, parseResult.getQuery());
            issues.stream().forEach(issue -> kIssueService.deindexIssue(jmIssueServices.getIssueManager().getIssueByCurrentKey(issue.getKey())));
        }
        return SILValueFactory.string( "issues deleted");

    }

    @Override
    public String getParams() {
        return "(userEmail)";
    }
}

Nous implémentons la logique dans la méthode runRoutine:

    @Override
    protected SILValue<MutableString>  runRoutine(SILContext silContext, List<SILValue<?>> list)  {

/*     */

        SILValue param = list.get(0);
        String userEmail = param.toStringValue();

/*       SIL */

        KIssueService kIssueService = beanService.getKIssueService();
        CurrentUserHelper currentUserHelper = beanService.getCurrentUserHelper();
        JMIssueSearchServices jmIssueSearchServices = beanService.getJmIssueSearchServices();
        UserHelper userHelper = beanService.getUserHelper();
        JMIssueServices jmIssueServices = beanService.getJmIssueServices();

/*  SIL UserHelper,   ApplicationUser    */

        ApplicationUser requestedUser = userHelper.getUserByEmail(userEmail);

/*  SIL CurrentUserHelper,  ,     Jira */

        if (currentUserHelper.isUserAdministrator()) {

/*   SIL      JQL  */

            SearchService.ParseResult parseResult = jmIssueSearchServices.getSearchService().parseQuery(requestedUser, "reporter = " + requestedUser.getKey());
            List<Issue> issues = (List<Issue>) kIssueService.searchIssues(requestedUser, parseResult.getQuery());

/*    */

            issues.stream().forEach(issue -> kIssueService.deindexIssue(jmIssueServices.getIssueManager().getIssueByCurrentKey(issue.getKey())));
        }
        return SILValueFactory.string( "issues deleted");

    }

J'ai fait des commentaires sur le code.

Service KIssueFieldsService


Je voudrais parler séparément de ce service. Dans SIL, dans toutes les méthodes où vous souhaitez transférer un champ personnalisé, nous pouvons transférer le nom du champ ou l'identifiant du champ au format customfield_NNNNN ou l'alias du champ.

Si nous n'utilisions pas les services SIL, nous devions alors implémenter cette logique nous-mêmes. Mais en utilisant le service KIssueFieldsService, nous utilisons cette fonctionnalité avec une seule ligne:

CustomField customField= this.kIssueFieldsService.getCustomField(customFieldName);

Vous savez maintenant comment créer des fonctions SIL portables entre les versions de Jira.

All Articles