From bcf5a8e21d64661cd0661374b4a64a4840dd173c Mon Sep 17 00:00:00 2001 From: Christian Kurz Date: Wed, 9 Oct 2024 17:01:57 +0200 Subject: [PATCH] outgoing templated fields --- .../kotlin/gropius/sync/github/GithubSync.kt | 11 ++++ .../main/kotlin/gropius/sync/jira/JiraSync.kt | 33 ++++++++++++ .../sync/jira/config/IMSProjectConfig.kt | 5 ++ .../main/kotlin/gropius/sync/AbstractSync.kt | 53 +++++++++++++++++++ 4 files changed, 102 insertions(+) diff --git a/sync-github/src/main/kotlin/gropius/sync/github/GithubSync.kt b/sync-github/src/main/kotlin/gropius/sync/github/GithubSync.kt index b719eb11..87caa27c 100644 --- a/sync-github/src/main/kotlin/gropius/sync/github/GithubSync.kt +++ b/sync-github/src/main/kotlin/gropius/sync/github/GithubSync.kt @@ -4,6 +4,7 @@ import gropius.model.architecture.IMSProject import gropius.model.issue.Issue import gropius.model.issue.Label import gropius.model.issue.timeline.IssueComment +import gropius.model.issue.timeline.TemplatedFieldChangedEvent import gropius.model.template.IMSTemplate import gropius.model.template.IssueState import gropius.model.user.User @@ -80,6 +81,10 @@ final class GithubSync( return imsProjectConfig.enableOutgoingComments } + override suspend fun isOutgoingTemplatedFieldsEnabled(imsProject: IMSProject): Boolean { + return false + } + override suspend fun isOutgoingTitleChangedEnabled(imsProject: IMSProject): Boolean { val imsProjectConfig = IMSProjectConfig(helper, imsProject) return imsProjectConfig.enableOutgoingTitleChanges @@ -209,6 +214,12 @@ final class GithubSync( return null } + override suspend fun syncTemplatedField( + imsProject: IMSProject, issueId: String, fieldChangedEvent: TemplatedFieldChangedEvent, users: List + ): TimelineItemConversionInformation? { + TODO("Remove this, as soon as the fallback is done in AbstractSync") + } + override suspend fun syncStateChange( imsProject: IMSProject, issueId: String, newState: IssueState, users: List ): TimelineItemConversionInformation? { diff --git a/sync-jira/src/main/kotlin/gropius/sync/jira/JiraSync.kt b/sync-jira/src/main/kotlin/gropius/sync/jira/JiraSync.kt index e50cbfde..a6d87c69 100644 --- a/sync-jira/src/main/kotlin/gropius/sync/jira/JiraSync.kt +++ b/sync-jira/src/main/kotlin/gropius/sync/jira/JiraSync.kt @@ -4,6 +4,7 @@ import gropius.model.architecture.IMSProject import gropius.model.issue.Issue import gropius.model.issue.Label import gropius.model.issue.timeline.IssueComment +import gropius.model.issue.timeline.TemplatedFieldChangedEvent import gropius.model.template.IMSTemplate import gropius.model.template.IssueState import gropius.model.user.User @@ -126,6 +127,11 @@ final class JiraSync( return imsProjectConfig.enableOutgoingState } + override suspend fun isOutgoingTemplatedFieldsEnabled(imsProject: IMSProject): Boolean { + val imsProjectConfig = IMSProjectConfig(helper, imsProject) + return imsProjectConfig.enableOutgoingTemplatedFields + } + override suspend fun fetchData(imsProjects: List) { for (imsProject in imsProjects) { jiraDataService.issueTemplate(imsProject) @@ -348,6 +354,33 @@ final class JiraSync( ) } + override suspend fun syncTemplatedField( + imsProject: IMSProject, issueId: String, fieldChangedEvent: TemplatedFieldChangedEvent, users: List + ): TimelineItemConversionInformation? { + val response = jiraDataService.request( + imsProject, users, HttpMethod.Put, gropiusUserList(users), JsonObject( + mapOf( + "fields" to JsonObject( + mapOf( + fieldChangedEvent.fieldName to JsonPrimitive(fieldChangedEvent.newValue) + ) + ) + ) + ) + ) { + appendPathSegments("issue") + appendPathSegments(issueId) + parameters.append("returnIssue", "true") + parameters.append("expand", "names,schema,editmeta,changelog") + + } + val changelogEntry = response.second.body().changelog.histories.lastOrNull() + return JiraTimelineItemConversionInformation( + imsProject.rawId!!, + if (changelogEntry?.items?.singleOrNull()?.field == fieldChangedEvent.fieldName) changelogEntry.id else "" + ) + } + override suspend fun syncStateChange( imsProject: IMSProject, issueId: String, newState: IssueState, users: List ): TimelineItemConversionInformation? { diff --git a/sync-jira/src/main/kotlin/gropius/sync/jira/config/IMSProjectConfig.kt b/sync-jira/src/main/kotlin/gropius/sync/jira/config/IMSProjectConfig.kt index a27406c7..77548009 100644 --- a/sync-jira/src/main/kotlin/gropius/sync/jira/config/IMSProjectConfig.kt +++ b/sync-jira/src/main/kotlin/gropius/sync/jira/config/IMSProjectConfig.kt @@ -21,6 +21,7 @@ data class IMSProjectConfig( val enableOutgoingAssignments: Boolean, val enableOutgoingTitleChanges: Boolean, val enableOutgoingState: Boolean, + val enableOutgoingTemplatedFields: Boolean, val defaultType: String?, val defaultTemplate: String? ) { @@ -40,6 +41,7 @@ data class IMSProjectConfig( enableOutgoingAssignments = helper.parseBoolean(imsProject.templatedFields["enable-outgoing-assignments"]), enableOutgoingTitleChanges = helper.parseBoolean(imsProject.templatedFields["enable-outgoing-title-changes"]), enableOutgoingState = helper.parseBoolean(imsProject.templatedFields["enable-outgoing-state"]), + enableOutgoingTemplatedFields = helper.parseBoolean(imsProject.templatedFields["enable-outgoing-templated-fields"]), defaultType = helper.parseString(imsProject.templatedFields["default-type"]), defaultTemplate = helper.parseString(imsProject.templatedFields["default-template"]) ) @@ -85,6 +87,9 @@ data class IMSProjectConfig( }.toString(), "enable-outgoing-state" to obj { "nullable" to true "type" to "boolean" + }.toString(), "enable-outgoing-templated-fields" to obj { + "nullable" to true + "type" to "boolean" }.toString()) + IMSConfigManager.COMMON_TEMPLATE_FIELDS } } diff --git a/sync/src/main/kotlin/gropius/sync/AbstractSync.kt b/sync/src/main/kotlin/gropius/sync/AbstractSync.kt index c2e48c48..37836408 100644 --- a/sync/src/main/kotlin/gropius/sync/AbstractSync.kt +++ b/sync/src/main/kotlin/gropius/sync/AbstractSync.kt @@ -150,6 +150,18 @@ abstract class AbstractSync( imsProject: IMSProject, issueId: String, newState: IssueState, users: List ): TimelineItemConversionInformation? + /** + * Incorporate a templated field change + * @param imsProject IMS project to sync + * @param issueId GitHub ID of the issue + * @param fieldChangedEvent Event describing the field change + * @param users List of users involved in this timeline item, sorted with most relevant first + * @return Conversion information + */ + abstract suspend fun syncTemplatedField( + imsProject: IMSProject, issueId: String, fieldChangedEvent: TemplatedFieldChangedEvent, users: List + ): TimelineItemConversionInformation? + /** * Incorporate an added label * @param imsProject IMS project to sync @@ -196,6 +208,13 @@ abstract class AbstractSync( */ abstract suspend fun isOutgoingLabelsEnabled(imsProject: IMSProject): Boolean + /** + * Check if Outgoing Sync of TemplatedFields is Enabled + * @param imsProject IMS project to check for + * @return true if and only if outgoing sync of templatedFields is enabled + */ + abstract suspend fun isOutgoingTemplatedFieldsEnabled(imsProject: IMSProject): Boolean + /** * Check if Outgoing Sync of Comments is Enabled * @param imsProject IMS project to check for @@ -660,6 +679,9 @@ abstract class AbstractSync( if (isOutgoingAssignmentsEnabled(imsProject)) { syncOutgoingAssignments(timeline, imsProject, issueInfo) } + if (isOutgoingTemplatedFieldsEnabled(imsProject)) { + syncOutgoingTemplatedFields(timeline, imsProject, issueInfo) + } if (isOutgoingStatesEnabled(imsProject)) { syncOutgoingStateChanges(timeline, imsProject, issueInfo) } @@ -844,6 +866,37 @@ abstract class AbstractSync( } } + /** + * Sync Outgoing TemplatedFields Changes + * @param timeline Timeline of the issue + * @param imsProject IMS project to sync + * @param issueInfo Issue to sync + */ + private suspend fun syncOutgoingTemplatedFields( + timeline: List, imsProject: IMSProject, issueInfo: IssueConversionInformation + ) { + val virtualIDs = mapOf()//For future features + val relevantTimeline = timeline.mapNotNull { it as? TemplatedFieldChangedEvent } + if (relevantTimeline.isEmpty()) return + val finalBlock = findFinalBlock(relevantTimeline) { it.fieldName to it.newValue } + if (finalBlock.none { + collectedSyncInfo.timelineItemConversionInformationService.findByImsProjectAndGropiusId( + imsProject.rawId!!, it.rawId!! + ) != null + }) { + val conversionInformation = syncTemplatedField(imsProject, + issueInfo.githubId, + finalBlock.first(), + finalBlock.map { it.createdBy().value }) + if (conversionInformation != null) { + conversionInformation.gropiusId = finalBlock.map { it.rawId ?: virtualIDs[it]!! }.first() + collectedSyncInfo.timelineItemConversionInformationService.save( + conversionInformation + ).awaitSingle() + } + } + } + /** * Sync Outgoing State Changes * @param timeline Timeline of the issue