Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: replace jira client #838

Merged
merged 76 commits into from
Feb 25, 2025

Conversation

jkazimierczak
Copy link
Contributor

Purpose

Replaces obsolete net.rcarz.jiraclient API client with custom API client that's compatible with Jira Cloud API v2.

TLDR

  • New API Client: A decoupled architecture using serializable dataclasses has been implemented. Mapping is handled within the infrastructure layer, minimizing required changes to other modules.
  • Domain Models: Cloud-specific variants of domain models (e.g., CloudIssue) have been introduced for prioritized modules to minimize scope of required migration.
  • Module Interface: The Module interface has been modified with generics to support both legacy and Cloud models. Module registrations have been minimized to just required modules for now.
  • Jira API: API v2 (Markdown) has been selected for initial implementation. Future integration with API v3 (Atlassian Document Format) should be easier basing on this PR.
  • Configuration: Authentication now requires email, an API token, and an account ID. Username/password authentication is no longer supported.
  • Feature-parity: New Client was provided with providing as much feature-parity as possible, so adaptation of remaining modules should be easier.

Approach

New API Client

The main point of integration between Arisa and the Jira API lies in the infrastructure directory - this is where all of the mapping happens between what API returns and what the Arisa operates on (Mappers.kt and Functions.kt). The initial idea was to identify all usages of old client, and provide new Jira API Client that has the feature-parity of the old client for all usages within the project, so quick drop-in replacement can be done where needed.

It quickly turned out that the old client was pretty coupled (internally) to the API models and operations performed on them, which expanded the surface of used endpoints by quite a bit. The new client is decoupled in this regard, as all used API models are defined as serializable dataclasses and do not depend on the API client.

Given the above, this allowed to introduce the new client with minimal modifications to the modules themselves.

Identify used properties within domain models

Current domain objects are quite lengthy in terms of properties they have, with domain.Issue being probably the biggest one. Given that the requirements handed to us prioritized Privacy and PrivateDuplicate modules the most, we began to identify which of the properties were actually needed. To refrain from rewriting or removing all present modules, we introduced Cloud variants of the domain models, which allowed to minimize the scope of the codebase migration to just required modules.

This was followed by modifying the Module interface to allow to specify issue type through generic type. To not break the existing modules, the Module interface extends the generic interface with the old Issue domain model, and new Cloud-compatible modules use CloudIssue domain model:

interface Module : ModuleBase<Issue> {}
interface CloudModule : ModuleBase<CloudIssue> {}

Although I'm not a fan of comments in code, I left the unused properties commented out, to easily see at glance which properties were previously needed and might be needed in the future if the rest of modules are going to be adapted to the Cloud Jira API. Similar stand true for Mappers.kt.

Modify module registries

As the interface was modified, registries and existing non-cloud modules disallowed us from compiling the Arisa. We've decided to remove the registrations of the non-compatible modules from the InstantRegistry, and comment out the Delayed and Linked registries (yet again, I despise the comments as a solution in this case).

API V2, V3 and ADF

Jira Cloud API exists in two versions, which have the same collection of operations. The main notable difference is that V3 uses Atlassian Document Format (ADF) in:

  • body in comments, including where comments are used in issue, issue link, and transition resources.
  • comments in worklogs.
  • description and environment fields in issues.
  • textarea type custom fields (multi-line text fields) in issues. Single line custom fields (textfield) accept a string and don't handle Atlassian Document Format content.

To minimize the work needed we've decided to go with API V2, which uses the markdown, as it was the case for old Jira 9.12.x API. This required minimal changes though, for example mentioning users is done purely through accountid and syntax slightly differed.

The current state of the models being decoupled from the API operations should allow easier introduction of ADF libraries provided by Atlassian (currently offered for Kotlin, Java and JavaScript). I haven't yet delved into how they work, but it should be possible to integrate the serialization/deserialization of ADF through custom serializers if necessary (similar to how we needed to provide serializers for URI and OffestDateTime classess).

Config changes

The new API switched authentication from username and password to email and API token. That means that Arisa local.yml config needs to have these specified:

arisa:
  credentials:
    accountId:
    email:
    apiToken:

Cloud Jira operates on account IDs instead of usernames, so it's necessary to specify the accountId of the user that is operating as Arisa bot. It should be possible to retrieve the accountId for Arisa through opening this endpoint in the browser:

https://jira-connection.atlassian.net/rest/api/2/user/picker?query=Arisa

Providing account ID is necessary, as some of the logic previously checked whether actions were performed by Arisa based on the username (which isn't supported anymore).

Note that the API Token is valid for the maximum of one year. API Token has to be created by the Arisa user. https://id.atlassian.com/manage-profile/security/api-tokens

FluentUpdate and FluentTransition

Previous library provided classes that allowed to fluently specify field updates and transitions. We've provided provided classes (apiclient.builders) that allow to construct the JSON in the same fluent fashion, but with slightly different syntax.

The example usages can be seen in Functions.kt and tests.

Tests

Introduction of the new client and new models are accompanied by the new test suite that test whether the deserialization of example API responses happens correctly and doesn't throw.

However, as a result of all modifications there were three test cases that didn't play nicely with modifications, namely:

  • ModuleRegistryTest:
    • should register a module for each config class - there was a disparity between all modules within project and only two of them being registered,
    • should register a module for each non-abstract module - this test being reflection based, finds all module classes within a project. As a result of us preserving the old modules, but not registering all of them, this test will fail natually,
  • RemoveVersionModuleTest:
    • should set to nouser when user changes version 5 times - I don't know exactly why this test fails as this module wasn't modified in any way, might be caused by the change in the domain models.

We've decided to keep these tests disabled for now, as the registry test will fail unless all modules are registered, while RemoveVersionModule tests were out of scope for now.

Future work

Migration of the existing modules should be rather easier given the groundwork this PR provides. Slight modifications might be necessary here and there though.

  • None of the prioritized modules seemed to use issue transitions. Although client has the methods to handle them, it's unknown at this point if they would work right away. In case of doubt, use logNetworkRequests debug config flag to see the endpoint, method and body of the HTTP requests,

  • Rest of modules should be slowly ported according to the specified priority,

  • Switch username/display name usages to use account IDs instead.

Checklist

  • Included tests
  • Updated documentation in README
    and docs folder
  • Tested in MCTEST-xxx

@CLAassistant
Copy link

CLAassistant commented Feb 24, 2025

CLA assistant check
All committers have signed the CLA.

@urielsalis urielsalis merged commit 5da0a64 into mojira:master Feb 25, 2025
3 checks passed
@jkazimierczak jkazimierczak deleted the fix/replace-jira-client branch February 25, 2025 17:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants