1#include "PrChangesList.h"
2
3#include <DiffHelper.h>
4#include <GitHistory.h>
5#include <FileDiffView.h>
6#include <PrChangeListItem.h>
7#include <PullRequest.h>
8#include <GitRemote.h>
9#include <GitConfig.h>
10#include <QLogger.h>
11
12#include <QGridLayout>
13#include <QLabel>
14#include <QScrollArea>
15
16using namespace GitServer;
17using namespace QLogger;
18
19PrChangesList::PrChangesList(const QSharedPointer<GitBase> &git, QWidget *parent)
20 : QFrame(parent)
21 , mGit(git)
22{
23 QScopedPointer<GitRemote> gitRemote(new GitRemote(mGit));
24 gitRemote->fetch();
25}
26
27void PrChangesList::loadData(const GitServer::PullRequest &prInfo)
28{
29 GitExecResult ret;
30 bool showDiff = true;
31 QString head;
32
33 if (prInfo.headRepo != prInfo.baseRepo)
34 {
35 QScopedPointer<GitConfig> git(new GitConfig(mGit));
36 const auto ret = git->getGitValue(QString("remote.%1.url").arg(prInfo.headRepo.split("/").constFirst()));
37
38 if (ret.output.isEmpty())
39 {
40 const auto response = QMessageBox::question(
41 this, tr("Getting remote branch"),
42 tr("The head branch of the Pull Request is not in the same repository. In order to show "
43 "the changes the remote must be added. <b>Do you want to get the remote branch?</b>"));
44
45 if (response == QMessageBox::Yes)
46 {
47 QScopedPointer<GitRemote> git(new GitRemote(mGit));
48 const auto remoteAdded = git->addRemote(prInfo.headUrl, prInfo.headRepo.split("/").constFirst());
49
50 showDiff = remoteAdded.success;
51
52 if (!showDiff)
53 QLog_Warning("UI", QString("Problems adding a remote: {%1}").arg(remoteAdded.output));
54 }
55 else
56 showDiff = false;
57
58 if (!showDiff)
59 return;
60 }
61
62 head = QString("%1/%2").arg(prInfo.headRepo.split("/").constFirst(), prInfo.head);
63 }
64 else
65 {
66 QScopedPointer<GitConfig> git(new GitConfig(mGit));
67 auto retBase = git->getRemoteForBranch(prInfo.head);
68 head = QString("%1/%2").arg(retBase.success ? retBase.output : "origin", prInfo.head);
69 }
70
71 QScopedPointer<GitConfig> gitConfig(new GitConfig(mGit));
72 auto retBase = gitConfig->getRemoteForBranch(prInfo.head);
73 const auto base = QString("%1/%2").arg(retBase.success ? retBase.output : "origin", prInfo.base);
74
75 QScopedPointer<GitHistory> git(new GitHistory(mGit));
76 ret = git->getBranchesDiff(base, head);
77
78 if (ret.success)
79 {
80 auto diff = ret.output;
81 auto changes = DiffHelper::splitDiff(diff);
82
83 if (!changes.isEmpty())
84 {
85 delete layout();
86
87 const auto mainLayout = new QVBoxLayout();
88 mainLayout->setContentsMargins(20, 20, 20, 20);
89 mainLayout->setSpacing(0);
90
91 for (auto &change : changes)
92 {
93 const auto changeListItem = new PrChangeListItem(change);
94 connect(changeListItem, &PrChangeListItem::gotoReview, this, &PrChangesList::gotoReview);
95 connect(changeListItem, &PrChangeListItem::addCodeReview, this, &PrChangesList::addCodeReview);
96
97 mListItems.append(changeListItem);
98
99 mainLayout->addWidget(changeListItem);
100 mainLayout->addSpacing(10);
101 }
102
103 const auto mIssuesFrame = new QFrame();
104 mIssuesFrame->setObjectName("IssuesViewFrame");
105 mIssuesFrame->setLayout(mainLayout);
106
107 const auto mScroll = new QScrollArea();
108 mScroll->setWidgetResizable(true);
109 mScroll->setWidget(mIssuesFrame);
110
111 const auto aLayout = new QVBoxLayout(this);
112 aLayout->setContentsMargins(QMargins());
113 aLayout->setSpacing(0);
114 aLayout->addWidget(mScroll);
115 }
116 }
117}
118
119void PrChangesList::onReviewsReceived(PullRequest pr)
120{
121 using Bookmark = QPair<int, int>;
122 QMultiMap<QString, Bookmark> bookmarksPerFile;
123
124 auto comments = pr.reviewComment;
125
126 for (const auto &review : qAsConst(pr.reviews))
127 {
128 QMap<int, QVector<CodeReview>> reviews;
129 QVector<int> codeReviewIds;
130
131 auto iter = comments.begin();
132
133 while (iter != comments.end())
134 {
135 if (iter->reviewId == review.id)
136 {
137 codeReviewIds.append(iter->id);
138 reviews[iter->id].append(*iter);
139 comments.erase(iter);
140 }
141 else if (codeReviewIds.contains(iter->replyToId))
142 {
143 reviews[iter->replyToId].append(*iter);
144 comments.erase(iter);
145 }
146 else
147 ++iter;
148 }
149
150 if (!reviews.isEmpty())
151 {
152 for (auto &codeReviews : reviews)
153 {
154 std::sort(codeReviews.begin(), codeReviews.end(),
155 [](const CodeReview &r1, const CodeReview &r2) { return r1.creation < r2.creation; });
156
157 const auto first = codeReviews.constFirst();
158
159 if (!first.outdated)
160 bookmarksPerFile.insert(first.diff.file, { first.diff.line, first.id });
161 else
162 bookmarksPerFile.insert(first.diff.file, { first.diff.originalLine, first.id });
163 }
164 }
165 }
166
167 for (auto iter : qAsConst(mListItems))
168 {
169 QMap<int, int> bookmarks;
170 const auto values = bookmarksPerFile.values(iter->getFileName());
171
172 for (auto bookmark : qAsConst(values))
173 {
174 if (bookmark.first >= iter->getStartingLine() && bookmark.first <= iter->getEndingLine())
175 bookmarks.insert(bookmark.first, bookmark.second);
176 }
177
178 if (!bookmarks.isEmpty())
179 iter->setBookmarks(bookmarks);
180 }
181}
182
183void PrChangesList::addLinks(PullRequest pr, const QMap<int, int> &reviewLinkToComments)
184{
185 QMultiMap<QString, QPair<int, int>> bookmarksPerFile;
186
187 for (auto reviewId : reviewLinkToComments)
188 {
189 for (const auto &review : qAsConst(pr.reviewComment))
190 {
191 if (review.id == reviewId)
192 {
193 if (!review.outdated)
194 bookmarksPerFile.insert(review.diff.file, { review.diff.line, review.id });
195 else
196 bookmarksPerFile.insert(review.diff.file, { review.diff.originalLine, review.id });
197
198 break;
199 }
200 }
201 }
202
203 for (const auto &iter : qAsConst(mListItems))
204 {
205 QMap<int, int> bookmarks;
206
207 const auto values = bookmarksPerFile.values(iter->getFileName());
208 for (const auto &bookmark : values)
209 {
210 if (bookmark.first >= iter->getStartingLine() && bookmark.first <= iter->getEndingLine())
211 bookmarks.insert(bookmark.first, reviewLinkToComments.key(bookmark.second));
212 }
213
214 if (!bookmarks.isEmpty())
215 iter->setBookmarks(bookmarks);
216 }
217}
218