summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatias Linares <matias@deprecated.org>2024-10-05 10:43:00 -0300
committerMatias Linares <matias@deprecated.org>2024-10-05 10:43:00 -0300
commit39349a7e1e4fbb16e4a71d7f741b0725e73caeb7 (patch)
tree72dc36cca5c3feca1afa3594999b5d44b1cf0483
parentb31efe70f22cd0535dbcb7ef596a365ad44c3dc3 (diff)
downloadkodereviewer-39349a7e1e4fbb16e4a71d7f741b0725e73caeb7.tar.gz
Add review changes functionality!
-rw-r--r--kodereviewer/data.py8
-rw-r--r--kodereviewer/network_manager.py42
-rw-r--r--kodereviewer/qml/PullRequestPage.qml43
-rw-r--r--kodereviewer/qml/ReviewDialog.qml69
4 files changed, 136 insertions, 26 deletions
diff --git a/kodereviewer/data.py b/kodereviewer/data.py
index 0d1bef6..8c4a0e6 100644
--- a/kodereviewer/data.py
+++ b/kodereviewer/data.py
@@ -108,6 +108,8 @@ class PullRequest(QObject):
_assignee: User | None
_labels: list[Label]
+ _last_commit: str
+
_comments: list[Comment]
_files: list[ChangedFile]
@@ -134,6 +136,8 @@ class PullRequest(QObject):
self._labels = [Label(label) for label in data['labels']]
+ self._last_commit = data['head']['sha']
+
# At first this is empty until it's updated with a request
self._comments = []
self._files = []
@@ -182,6 +186,10 @@ class PullRequest(QObject):
def username(self) -> str:
return self._user.username
+ @Property(str, constant=True)
+ def last_commit(self) -> str:
+ return self._last_commit
+
@Property(list, constant=True)
def labels(self) -> list[Label]:
return self._labels
diff --git a/kodereviewer/network_manager.py b/kodereviewer/network_manager.py
index ebc2797..3296153 100644
--- a/kodereviewer/network_manager.py
+++ b/kodereviewer/network_manager.py
@@ -1,4 +1,7 @@
+import json
+import logging
import re
+from enum import StrEnum
from typing import Optional
from PySide6.QtCore import QObject, QSettings, Signal, Slot, Property, qDebug
@@ -14,6 +17,15 @@ QML_IMPORT_MAJOR_VERSION = 1
PULL_REQUEST_LIST_URL = re.compile(r'/pulls$')
COMMENT_LIST_URL = re.compile(r'/issues/(\d+)/comments')
FILE_LIST_URL = re.compile(r'/pulls/(\d+)/files')
+CREATE_REVIEW_URL = re.compile(r'/pulls/(\d+)/reviews')
+
+logger = logging.getLogger(__name__)
+
+
+class ReviewEvent(StrEnum):
+ APPROVE = 'APPROVE'
+ REQUEST_CHANGES = 'REQUEST_CHANGES'
+ COMMENT = 'COMMENT'
@QmlElement
@@ -76,8 +88,10 @@ class NetworkManager(QObject):
pull_request: Optional[PullRequest] = self._project.find_pull_request(pull_request_number)
if pull_request is not None:
pull_request.load_files(response_body)
+ elif (match := CREATE_REVIEW_URL.search(reply.url().toString())):
+ logger.info(f'Got review reply: {response_body}')
else:
- print(f"Can't handle {reply.url()}")
+ logger.info(f"Can't handle {reply.url()}")
@Slot()
def getPullRequests(self) -> None:
@@ -85,8 +99,30 @@ class NetworkManager(QObject):
@Slot(int)
def getPullRequestComments(self, number: int) -> None:
- self._manager.get(self._request_factory.createRequest(f'/issues/{number}/comments'))
+ self._manager.get(
+ self._request_factory.createRequest(f'/issues/{number}/comments')
+ )
@Slot(int)
def getFiles(self, pull_request_number) -> None:
- self._manager.get(self._request_factory.createRequest(f'/pulls/{pull_request_number}/files'))
+ self._manager.get(
+ self._request_factory.createRequest(
+ f'/pulls/{pull_request_number}/files'
+ )
+ )
+
+ @Slot(int, str, str, str)
+ def createReview(
+ self, pull_request_number: str, commit_id: str,
+ body: str, event: ReviewEvent
+ ) -> None:
+ request = self._request_factory.createRequest(
+ f'/pulls/{pull_request_number}/reviews'
+ )
+ data = {
+ 'commit_id': commit_id,
+ 'body': body,
+ 'event': event,
+ 'comments': []
+ }
+ self._manager.post(request, json.dumps(data).encode())
diff --git a/kodereviewer/qml/PullRequestPage.qml b/kodereviewer/qml/PullRequestPage.qml
index da2b8e5..b9106c1 100644
--- a/kodereviewer/qml/PullRequestPage.qml
+++ b/kodereviewer/qml/PullRequestPage.qml
@@ -30,32 +30,18 @@ Kirigami.ScrollablePage {
}
]
- Kirigami.Dialog {
+ ReviewDialog {
id: reviewChangesDialog
- standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
- title: i18nc("@title:window", "Review changes")
- padding: Kirigami.Units.largeSpacing
- preferredWidth: Kirigami.Units.gridUnit * 20
- ColumnLayout {
- MarkdownTextArea {
- Layout.fillWidth: true
- }
- Kirigami.Separator {
- Kirigami.FormData.isSection: true
- Layout.fillWidth: true
- }
- QQC2.RadioButton {
- text: "Approve"
- }
- QQC2.RadioButton {
- text: "Comment"
- }
- QQC2.RadioButton {
- text: "Request changes"
- }
+ onAccepted: {
+ print('Sending', root.pullRequest.number, root.pullRequest.last_commit,
+ reviewBodyText, event)
+ root.connection.createReview(
+ root.pullRequest.number, root.pullRequest.last_commit,
+ reviewBodyText, event
+ )
+ clearForm()
}
}
-
Loader {
id: commentModelLoader
active: !!root.pullRequest
@@ -136,6 +122,17 @@ Kirigami.ScrollablePage {
}
}
+ RowLayout {
+ QQC2.Label {
+ text: "Last commit: "
+ elide: Text.ElideRight
+ }
+ QQC2.Label {
+ text: root.pullRequest ? root.pullRequest.last_commit : ""
+ elide: Text.ElideLeft
+ }
+ }
+
Loader {
id: labelModelLoader
active: !!root.pullRequest
diff --git a/kodereviewer/qml/ReviewDialog.qml b/kodereviewer/qml/ReviewDialog.qml
new file mode 100644
index 0000000..7dcaf9c
--- /dev/null
+++ b/kodereviewer/qml/ReviewDialog.qml
@@ -0,0 +1,69 @@
+pragma ComponentBehavior: Bound
+import QtQuick
+import QtCore
+import QtQuick.Controls as QQC2
+import QtQuick.Layouts
+
+import org.kde.kirigami as Kirigami
+import org.kde.kirigamiaddons.formcard as FormCard
+
+import org.deprecated.kodereviewer 1.0
+
+
+Kirigami.Dialog {
+ id: root
+ standardButtons: Kirigami.Dialog.Ok | Kirigami.Dialog.Cancel
+ title: i18nc("@title:window", "Review changes")
+ padding: Kirigami.Units.largeSpacing
+ preferredWidth: Kirigami.Units.gridUnit * 20
+ property string event: ''
+ property alias reviewBodyText: reviewBody.text
+ ColumnLayout {
+ MarkdownTextArea {
+ id: reviewBody
+ Layout.fillWidth: true
+ }
+ Kirigami.Separator {
+ Kirigami.FormData.isSection: true
+ Layout.fillWidth: true
+ }
+ QQC2.RadioButton {
+ id: approveRadioButton
+ text: "Approve"
+ onCheckedChanged: if(checked) {
+ root.event = 'APPROVE'
+ }
+ }
+ QQC2.RadioButton {
+ id: commentRadioButton
+ text: "Comment"
+ onCheckedChanged: if(checked) {
+ root.event = 'COMMENT'
+ }
+ }
+ QQC2.RadioButton {
+ id: requestChangesRadioButton
+ text: "Request changes"
+ onCheckedChanged: if(checked) {
+ root.event = 'REQUEST_CHANGES'
+ }
+ }
+ }
+
+ function requiredFieldsFilled() {
+ return event != '' && reviewBodyText != ''
+ }
+
+ function clearForm() {
+ reviewBodyText = ''
+ approveRadioButton.checked = false
+ commentRadioButton.checked = false
+ requestChangesRadioButton = false
+ event = ''
+ }
+
+ Component.onCompleted: {
+ const button = standardButton(Kirigami.Dialog.Ok);
+ button.enabled = Qt.binding( () => requiredFieldsFilled() );
+ }
+}