-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathCodeReviewRound.swift
More file actions
154 lines (129 loc) · 4.95 KB
/
CodeReviewRound.swift
File metadata and controls
154 lines (129 loc) · 4.95 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
import Foundation
import LanguageServerProtocol
import GitHelper
public struct CodeReviewRequest: Equatable, Codable {
public struct FileChange: Equatable, Codable {
public let changes: [PRChange]
public var selectedChanges: [PRChange]
public init(changes: [PRChange]) {
self.changes = changes
self.selectedChanges = changes
}
}
public var fileChange: FileChange
public var changedFileUris: [DocumentUri] { fileChange.changes.map { $0.uri } }
public var selectedFileUris: [DocumentUri] { fileChange.selectedChanges.map { $0.uri } }
public init(fileChange: FileChange) {
self.fileChange = fileChange
}
public static func from(_ changes: [PRChange]) -> CodeReviewRequest {
return .init(fileChange: .init(changes: changes))
}
public mutating func updateSelectedChanges(by fileUris: [DocumentUri]) {
fileChange.selectedChanges = fileChange.selectedChanges.filter { fileUris.contains($0.uri) }
}
}
public struct CodeReviewResponse: Equatable, Codable {
public struct FileComment: Equatable, Codable, Hashable {
public let uri: DocumentUri
public let originalContent: String
public var comments: [ReviewComment]
public var url: URL? { URL(string: uri) }
public init(uri: DocumentUri, originalContent: String, comments: [ReviewComment]) {
self.uri = uri
self.originalContent = originalContent
self.comments = comments
}
}
public var fileComments: [FileComment]
public var allComments: [ReviewComment] {
fileComments.flatMap { $0.comments }
}
public init(fileComments: [FileComment]) {
self.fileComments = fileComments
}
public func merge(with other: CodeReviewResponse) -> CodeReviewResponse {
var mergedResponse = self
for newFileComment in other.fileComments {
if let index = mergedResponse.fileComments.firstIndex(where: { $0.uri == newFileComment.uri }) {
// Merge comments for existing URI
var mergedComments = mergedResponse.fileComments[index].comments + newFileComment.comments
mergedComments.sortByEndLine()
mergedResponse.fileComments[index].comments = mergedComments
} else {
// Append new URI with sorted comments
var newReview = newFileComment
newReview.comments.sortByEndLine()
mergedResponse.fileComments.append(newReview)
}
}
return mergedResponse
}
}
public struct CodeReviewRound: Equatable, Codable {
public enum Status: Equatable, Codable {
case waitForConfirmation, accepted, running, completed, error, cancelled
public func canTransitionTo(_ newStatus: Status) -> Bool {
switch (self, newStatus) {
case (.waitForConfirmation, .accepted): return true
case (.waitForConfirmation, .cancelled): return true
case (.accepted, .running): return true
case (.accepted, .cancelled): return true
case (.running, .completed): return true
case (.running, .error): return true
case (.running, .cancelled): return true
default: return false
}
}
}
public let id: String
public let turnId: String
public var status: Status {
didSet { statusHistory.append(status) }
}
public private(set) var statusHistory: [Status]
public var request: CodeReviewRequest?
public var response: CodeReviewResponse?
public var error: String?
public init(
id: String = UUID().uuidString,
turnId: String,
status: Status,
request: CodeReviewRequest? = nil,
response: CodeReviewResponse? = nil,
error: String? = nil
) {
self.id = id
self.turnId = turnId
self.status = status
self.request = request
self.response = response
self.error = error
self.statusHistory = [status]
}
public static func fromError(turnId: String, error: String) -> CodeReviewRound {
.init(turnId: turnId, status: .error, error: error)
}
public func withResponse(_ response: CodeReviewResponse) -> CodeReviewRound {
var round = self
round.response = response
return round
}
public func withStatus(_ status: Status) -> CodeReviewRound {
var round = self
round.status = status
return round
}
public func withError(_ error: String) -> CodeReviewRound {
var round = self
round.error = error
round.status = .error
return round
}
}
extension Array where Element == ReviewComment {
// Order in asc
public mutating func sortByEndLine() {
self.sort(by: { $0.range.end.line < $1.range.end.line })
}
}