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

assignments outgoing #149

Merged
merged 3 commits into from
Oct 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,32 @@ mutation MutateCreateIssue($id: ID!, $title: String!, $body: String!) {
...IssueDataExtensive
}
}
}
}
mutation MutateAssignUser($id: ID!, $user: ID!) {
addAssigneesToAssignable(input:{assignableId: $id, assigneeIds: [$user]}){
assignable {
...on Issue {
timelineItems(itemTypes: [ASSIGNED_EVENT], last: 1) {
nodes {
...TimelineItemData
}
}
}
}
clientMutationId
}
}
mutation MutateUnassignUser($id: ID!, $user: ID!) {
removeAssigneesFromAssignable(input:{assignableId: $id, assigneeIds: [$user]}){
assignable {
...on Issue {
timelineItems(itemTypes: [UNASSIGNED_EVENT], last: 1) {
nodes {
...TimelineItemData
}
}
}
}
clientMutationId
}
}
58 changes: 58 additions & 0 deletions sync-github/src/main/kotlin/gropius/sync/github/GithubSync.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@ package gropius.sync.github
import gropius.model.architecture.IMSProject
import gropius.model.issue.Issue
import gropius.model.issue.Label
import gropius.model.issue.timeline.Assignment
import gropius.model.issue.timeline.IssueComment
import gropius.model.template.IMSTemplate
import gropius.model.template.IssueState
import gropius.model.user.GropiusUser
import gropius.model.user.IMSUser
import gropius.model.user.User
import gropius.sync.*
import gropius.sync.github.config.IMSConfigManager
import gropius.sync.github.config.IMSProjectConfig
import gropius.sync.github.generated.*
import gropius.sync.github.generated.MutateAddLabelMutation.Data.AddLabelsToLabelable.Labelable.Companion.asIssue
import gropius.sync.github.generated.MutateAssignUserMutation.Data.AddAssigneesToAssignable.Assignable.Companion.asIssue
import gropius.sync.github.generated.MutateCreateCommentMutation.Data.AddComment.CommentEdge.Node.Companion.asIssueTimelineItems
import gropius.sync.github.generated.MutateRemoveLabelMutation.Data.RemoveLabelsFromLabelable.Labelable.Companion.asIssue
import gropius.sync.github.generated.MutateUnassignUserMutation.Data.RemoveAssigneesFromAssignable.Assignable.Companion.asIssue
import gropius.sync.github.generated.fragment.TimelineItemData.Companion.asNode
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
Expand Down Expand Up @@ -172,6 +177,59 @@ final class GithubSync(
return null
}

override suspend fun syncSingleAssigned(
imsProject: IMSProject, issueId: String, assignment: Assignment, users: List<User>
): TimelineItemConversionInformation? {
val assignedUser = assignment.user().value
val imsUsers =
if (assignedUser as? IMSUser != null) listOf(assignedUser) else if (assignedUser as? GropiusUser != null) assignedUser.imsUsers()
.filter { it.ims().value == imsProject.ims().value } else emptyList()
val ids = imsUsers.map {
it.templatedFields["github_id"]!!
}
if (ids.isEmpty()) {
return null
}
val response = githubDataService.mutation(
imsProject, users, MutateAssignUserMutation(issueId, ids.first()), gropiusUserList(users)
).second
val item =
response.data?.addAssigneesToAssignable?.assignable?.asIssue()?.timelineItems?.nodes?.lastOrNull()?.asNode()
if (item != null) {
return TODOTimelineItemConversionInformation(imsProject.rawId!!, item.id)
}
logger.error("${response.data} ${response.errors}")
//TODO("ERROR HANDLING")
return null
}

override suspend fun syncSingleUnassigned(
imsProject: IMSProject, issueId: String, assignment: Assignment, users: List<User>
): TimelineItemConversionInformation? {
val assignedUser = assignment.user().value
val imsUsers =
if (assignedUser as? IMSUser != null) listOf(assignedUser) else if (assignedUser as? GropiusUser != null) assignedUser.imsUsers()
.filter { it.ims().value == imsProject.ims().value } else emptyList()
val ids = imsUsers.map {
it.templatedFields["github_id"]!!
}
if (ids.isEmpty()) {
return null
}
val response = githubDataService.mutation(
imsProject, users, MutateUnassignUserMutation(issueId, ids.first()), gropiusUserList(users)
).second
val item =
response.data?.removeAssigneesFromAssignable?.assignable?.asIssue()?.timelineItems?.nodes?.lastOrNull()
?.asNode()
if (item != null) {
return TODOTimelineItemConversionInformation(imsProject.rawId!!, item.id)
}
logger.error("${response.data} ${response.errors}")
//TODO("ERROR HANDLING")
return null
}

override suspend fun syncAddedLabel(
imsProject: IMSProject, issueId: String, label: Label, users: List<User>
): TimelineItemConversionInformation? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ class UnassignedTimelineItem(
gropiusId
) else RemovedAssignmentEvent(createdAt, createdAt)
val opposite = issue.timelineItems().filterIsInstance<Assignment>().sortedBy { it.createdAt }
.lastOrNull { it.user().value.username == user }
.lastOrNull { it.user().value.username == user } // TODO: Catch multiple
if ((event == null) || (opposite == null)) {
return listOf<TimelineItem>() to convInfo;
}
Expand Down
74 changes: 70 additions & 4 deletions sync-jira/src/main/kotlin/gropius/sync/jira/JiraSync.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ package gropius.sync.jira
import gropius.model.architecture.IMSProject
import gropius.model.issue.Issue
import gropius.model.issue.Label
import gropius.model.issue.timeline.Assignment
import gropius.model.issue.timeline.IssueComment
import gropius.model.template.IMSTemplate
import gropius.model.template.IssueState
import gropius.model.user.GropiusUser
import gropius.model.user.IMSUser
import gropius.model.user.User
import gropius.sync.*
import gropius.sync.jira.config.IMSConfig
Expand All @@ -17,10 +20,7 @@ import io.ktor.client.plugins.*
import io.ktor.client.statement.*
import io.ktor.http.*
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.*
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Component
import java.time.OffsetDateTime
Expand Down Expand Up @@ -301,6 +301,72 @@ final class JiraSync(
return issueDataService.findByImsProject(imsProject.rawId!!)
}

override suspend fun syncSingleAssigned(
imsProject: IMSProject, issueId: String, assignment: Assignment, users: List<User>
): TimelineItemConversionInformation? {
val assignedUser = assignment.user().value
val imsUsers =
if (assignedUser as? IMSUser != null) listOf(assignedUser) else if (assignedUser as? GropiusUser != null) assignedUser.imsUsers()
.filter { it.ims().value == imsProject.ims().value } else emptyList()
val ids = imsUsers.map { it.username }
if (ids.isEmpty()) {
return null
}
val response = jiraDataService.request(
imsProject, users, HttpMethod.Put, gropiusUserList(users), JsonObject(
mapOf(
"fields" to JsonObject(
mapOf(
"assignee" to JsonObject(
mapOf(
"name" to JsonPrimitive(ids.first())
)
)
)
)
)
)
) {
appendPathSegments("issue")
appendPathSegments(issueId)
parameters.append("returnIssue", "true")
parameters.append("expand", "names,schema,editmeta,changelog")

}
val changelogEntry = response.second.body<IssueBean>().changelog.histories.lastOrNull()
return JiraTimelineItemConversionInformation(
imsProject.rawId!!,
if (changelogEntry?.items?.singleOrNull()?.field == "assignee") changelogEntry.id else ""
)
}

override suspend fun syncSingleUnassigned(
imsProject: IMSProject, issueId: String, assignment: Assignment, users: List<User>
): TimelineItemConversionInformation? {
val response = jiraDataService.request(
imsProject, users, HttpMethod.Put, gropiusUserList(users), JsonObject(
mapOf(
"fields" to JsonObject(
mapOf(
"assignee" to JsonNull
)
)
)
)
) {
appendPathSegments("issue")
appendPathSegments(issueId)
parameters.append("returnIssue", "true")
parameters.append("expand", "names,schema,editmeta,changelog")

}
val changelogEntry = response.second.body<IssueBean>().changelog.histories.lastOrNull()
return JiraTimelineItemConversionInformation(
imsProject.rawId!!,
if (changelogEntry?.items?.singleOrNull()?.field == "assignee") changelogEntry.id else ""
)
}

override suspend fun syncComment(
imsProject: IMSProject, issueId: String, issueComment: IssueComment, users: List<User>
): TimelineItemConversionInformation? {
Expand Down
99 changes: 99 additions & 0 deletions sync/src/main/kotlin/gropius/sync/AbstractSync.kt
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,30 @@ abstract class AbstractSync(
imsProject: IMSProject, issueId: String, label: Label, users: List<User>
): TimelineItemConversionInformation?

/**
* Incorporate an added assignment
* @param imsProject IMS project to sync
* @param issueId GitHub ID of the issue
* @param assignment Assignment to sync
* @param users List of users involved in this timeline item, sorted with most relevant first
* @return Conversion information
*/
abstract suspend fun syncSingleAssigned(
imsProject: IMSProject, issueId: String, assignment: Assignment, users: List<User>
): TimelineItemConversionInformation?

/**
* Incorporate a removed assignment
* @param imsProject IMS project to sync
* @param issueId GitHub ID of the issue
* @param assignment Assignment to sync
* @param users List of users involved in this timeline item, sorted with most relevant first
* @return Conversion information
*/
abstract suspend fun syncSingleUnassigned(
imsProject: IMSProject, issueId: String, assignment: Assignment, users: List<User>
): TimelineItemConversionInformation?

/**
* Create an issue on the IMS
* @param imsProject IMS project to sync
Expand Down Expand Up @@ -886,6 +910,81 @@ abstract class AbstractSync(
private suspend fun syncOutgoingAssignments(
timeline: List<TimelineItem>, imsProject: IMSProject, issueInfo: IssueConversionInformation
) {
val virtualIDs = mutableMapOf<TimelineItem, String>()

val modifiedTimeline =
timeline.filterIsInstance<Assignment>() + timeline.filterIsInstance<RemovedAssignmentEvent>()
val groups = modifiedTimeline.groupBy {
when (it) {
is Assignment -> it
is RemovedAssignmentEvent -> it.removedAssignment().value!!
else -> throw IllegalStateException("Kotlin Generator Defective")
}
}
for ((assignment, relevantTimeline) in groups) {
syncOutgoingSingleAssignment(
relevantTimeline.sortedBy { it.createdAt }, imsProject, issueInfo, assignment, virtualIDs
)
}
}

/**
* Sync Outgoing Assignments
* @param relevantTimeline Timeline of the issue
* @param imsProject IMS project to sync
* @param issueInfo Issue to sync
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

missing dokka

* @param assignment Assignment to sync
* @param virtualIDs mapping for timeline items that are geerated with generated ids and do not exist in the database
*/
private suspend fun syncOutgoingSingleAssignment(
relevantTimeline: List<TimelineItem>,
imsProject: IMSProject,
issueInfo: IssueConversionInformation,
assignment: Assignment,
virtualIDs: Map<TimelineItem, String>
) {
var assignmentIsSynced = false
val finalBlock = findFinalTypeBlock(relevantTimeline)
for (item in finalBlock) {
val relevantEvent = collectedSyncInfo.timelineItemConversionInformationService.findByImsProjectAndGropiusId(
imsProject.rawId!!, item.rawId ?: virtualIDs[item]!!
)
if (relevantEvent?.githubId != null) {
assignmentIsSynced = true
}
}
if (!assignmentIsSynced) {
if (shouldSyncType<RemovedAssignmentEvent, Assignment>(
imsProject, finalBlock, relevantTimeline, true, virtualIDs
)
) {
val conversionInformation = syncSingleUnassigned(imsProject,
issueInfo.githubId,
assignment!!,
finalBlock.map { it.lastModifiedBy().value })
if (conversionInformation != null) {
conversionInformation.gropiusId = finalBlock.map { it.rawId ?: virtualIDs[it]!! }.first()
collectedSyncInfo.timelineItemConversionInformationService.save(
conversionInformation
).awaitSingle()
}
}
if (shouldSyncType<Assignment, RemovedAssignmentEvent>(
imsProject, finalBlock, relevantTimeline, false, virtualIDs
)
) {
val conversionInformation = syncSingleAssigned(imsProject,
issueInfo.githubId,
assignment!!,
finalBlock.map { it.lastModifiedBy().value })
if (conversionInformation != null) {
conversionInformation.gropiusId = finalBlock.map { it.rawId ?: virtualIDs[it]!! }.first()
collectedSyncInfo.timelineItemConversionInformationService.save(
conversionInformation
).awaitSingle()
}
}
}
}

/**
Expand Down