Merge pull request #273 from Murmele/Amend

Implement Amend Dialog
This commit is contained in:
Kas 2022-10-10 18:33:03 +02:00 committed by GitHub
commit ff418c49eb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 778 additions and 54 deletions

208
src/dialogs/AmendDialog.cpp Normal file
View File

@ -0,0 +1,208 @@
#include "AmendDialog.h"
#include <QGridLayout>
#include <QLabel>
#include <QLineEdit>
#include <QTextEdit>
#include <QPushButton>
#include <QCheckBox>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QDateTimeEdit>
#include <QRadioButton>
#include <QGroupBox>
enum Row { Author = 0, Committer, CommitMessageLabel, CommitMessage, Buttons };
class DateSelectionGroupWidget : public QGroupBox {
Q_OBJECT
public:
DateSelectionGroupWidget(QWidget *parent = nullptr)
: QGroupBox(tr("Datetime source"), parent) {
QHBoxLayout *l = new QHBoxLayout();
current = new QRadioButton(tr("Current"), this);
current->setObjectName("Current");
manual = new QRadioButton(tr("Manual"), this);
manual->setObjectName("Manual");
original = new QRadioButton(tr("Original"), this);
original->setObjectName("Original");
current->setChecked(true);
connect(current, &QRadioButton::clicked,
[this]() { emit typeChanged(type()); });
connect(manual, &QRadioButton::clicked,
[this]() { emit typeChanged(type()); });
connect(original, &QRadioButton::clicked,
[this]() { emit typeChanged(type()); });
l->addWidget(current);
l->addWidget(manual);
l->addWidget(original);
setLayout(l);
}
ContributorInfo::SelectedDateTimeType type() {
if (original->isChecked()) {
return ContributorInfo::SelectedDateTimeType::Original;
} else if (manual->isChecked()) {
return ContributorInfo::SelectedDateTimeType::Manual;
}
return ContributorInfo::SelectedDateTimeType::Current;
}
signals:
void typeChanged(ContributorInfo::SelectedDateTimeType);
private:
QRadioButton *current;
QRadioButton *manual;
QRadioButton *original;
};
class InfoBox : public QGroupBox {
Q_OBJECT
public:
enum LocalRow { Name = 0, Email, DateType, CommitDate };
InfoBox(const QString &title, const git::Signature &signature,
QWidget *parent = nullptr)
: QGroupBox(title + ":", parent), m_signature(signature) {
setObjectName(title);
auto *l = new QVBoxLayout();
auto *lName = new QLabel(tr("Name:"), this);
m_name = new QLineEdit(signature.name(), this);
m_name->setObjectName("Name");
auto *hName = new QHBoxLayout();
hName->addWidget(lName);
hName->addWidget(m_name);
auto *lEmail = new QLabel(tr("Email:"), this);
m_email = new QLineEdit(signature.email(), this);
m_email->setObjectName("Email");
auto *hEmail = new QHBoxLayout();
hEmail->addWidget(lEmail);
hEmail->addWidget(m_email);
m_commitDateType = new DateSelectionGroupWidget(this);
m_commitDateType->setObjectName(title + "CommitDateType");
m_lCommitDate = new QLabel(tr("Commit date:"), this);
m_commitDate = new QDateTimeEdit(signature.date().toLocalTime(), this);
m_commitDate->setObjectName(title + "CommitDate");
QSizePolicy sp(QSizePolicy::Expanding, QSizePolicy::Preferred);
m_commitDate->setSizePolicy(sp);
auto *hDate = new QHBoxLayout();
hDate->addWidget(m_lCommitDate);
hDate->addWidget(m_commitDate);
l->addLayout(hName);
l->addLayout(hEmail);
l->addWidget(m_commitDateType);
l->addLayout(hDate);
setLayout(l);
dateTimeTypeChanged(m_commitDateType->type());
connect(m_commitDateType, &DateSelectionGroupWidget::typeChanged, this,
&InfoBox::dateTimeTypeChanged);
}
ContributorInfo getInfo() const {
ContributorInfo ci;
ci.name = name();
ci.email = email();
ci.commitDate = commitDate();
ci.commitDateType = commitDateType();
return ci;
}
private slots:
void dateTimeTypeChanged(const ContributorInfo::SelectedDateTimeType type) {
const auto enabled = type == ContributorInfo::SelectedDateTimeType::Manual;
m_lCommitDate->setVisible(enabled);
m_commitDate->setVisible(enabled);
}
private:
QString name() const { return m_name->text(); }
QString email() const { return m_email->text(); }
QDateTime commitDate() const {
if (commitDateType() == ContributorInfo::SelectedDateTimeType::Original) {
return m_signature.date().toLocalTime();
} else {
return m_commitDate->dateTime();
}
}
ContributorInfo::SelectedDateTimeType commitDateType() const {
return m_commitDateType->type();
}
QLineEdit *m_name;
QLineEdit *m_email;
QDateTimeEdit *m_commitDate;
QLabel *m_lCommitDate;
DateSelectionGroupWidget *m_commitDateType;
git::Signature m_signature;
};
AmendDialog::AmendDialog(const git::Signature &author,
const git::Signature &committer,
const QString &commitMessage, QWidget *parent)
: QDialog(parent) {
auto *l = new QGridLayout();
// author
// committer
// message
m_authorInfo = new InfoBox(tr("Author"), author, this);
l->addWidget(m_authorInfo, Row::Author, 0, 1, 2);
m_committerInfo = new InfoBox(tr("Committer"), committer, this);
l->addWidget(m_committerInfo, Row::Committer, 0, 1, 2);
auto *lMessage = new QLabel(tr("Commit Message:"), this);
m_commitMessage = new QTextEdit(commitMessage, this);
m_commitMessage->setObjectName("Textlabel Commit Message");
l->addWidget(lMessage, Row::CommitMessageLabel, 0);
l->addWidget(m_commitMessage, Row::CommitMessage, 0, 1, 2);
auto *ok = new QPushButton(tr("Amend"), this);
auto *cancel = new QPushButton(tr("Cancel"), this);
connect(ok, &QPushButton::clicked, this, &QDialog::accept);
connect(cancel, &QPushButton::clicked, this, &QDialog::reject);
auto *hl = new QHBoxLayout();
hl->addWidget(cancel);
hl->addWidget(ok);
l->addLayout(hl, Buttons, 1);
setLayout(l);
}
AmendInfo AmendDialog::getInfo() const {
AmendInfo ai;
ai.authorInfo = m_authorInfo->getInfo();
ai.committerInfo = m_committerInfo->getInfo();
ai.commitMessage = commitMessage();
return ai;
}
QString AmendDialog::commitMessage() const {
return m_commitMessage->toPlainText();
}
#include "AmendDialog.moc"

41
src/dialogs/AmendDialog.h Normal file
View File

@ -0,0 +1,41 @@
#include <QDialog>
#include <QDateTime>
#include "git/Signature.h"
class QLineEdit;
class QTextEdit;
class QCheckBox;
class QDateTimeEdit;
class DateSelectionGroupWidget;
class QLabel;
class InfoBox;
class AmendDialog;
struct ContributorInfo {
enum class SelectedDateTimeType { Current, Manual, Original };
QString name;
QString email;
QDateTime commitDate;
SelectedDateTimeType commitDateType;
};
struct AmendInfo {
ContributorInfo authorInfo;
ContributorInfo committerInfo;
QString commitMessage;
};
class AmendDialog : public QDialog {
public:
AmendDialog(const git::Signature &author, const git::Signature &committer,
const QString &commitMessage, QWidget *parent = nullptr);
AmendInfo getInfo() const;
private:
QString commitMessage() const;
InfoBox *m_authorInfo;
InfoBox *m_committerInfo;
QTextEdit *m_commitMessage;
};

View File

@ -3,6 +3,7 @@ add_library(
AboutDialog.cpp
AccountDialog.cpp
AddRemoteDialog.cpp
AmendDialog.cpp
BranchDelegate.cpp
BranchTableModel.cpp
CheckoutDialog.cpp

View File

@ -20,6 +20,7 @@
#include "git2/diff.h"
#include "git2/refs.h"
#include "git2/revert.h"
#include "git2/commit.h"
#include <QDateTime>
#include <QJsonArray>
#include <QJsonDocument>
@ -240,6 +241,16 @@ bool Commit::revert() const {
return !error;
}
bool Commit::amend(const Signature &author, const Signature &committer,
const QString &commitMessage, const Tree &tree) const {
Repository repo = this->repo();
git_oid oid;
int error = git_commit_amend(&oid, *this, "HEAD", &*author, &*committer, NULL,
commitMessage.toUtf8(), tree);
emit repo.notifier()->referenceUpdated(repo.head());
return !error;
}
bool Commit::reset(git_reset_t type, const QStringList &paths) const {
QVector<char *> rawPaths;
QVector<QByteArray> storage;

View File

@ -65,6 +65,9 @@ public:
// Revert this commit in the index and workdir.
bool revert() const;
bool amend(const Signature &author, const Signature &committer,
const QString &commitMessage, const Tree &tree) const;
// Reset HEAD to this commit.
bool reset(git_reset_t type = GIT_RESET_MIXED,
const QStringList &paths = QStringList()) const;

View File

@ -188,6 +188,15 @@ Config Repository::appConfig() const {
bool Repository::isBare() const { return git_repository_is_bare(d->repo); }
Signature Repository::signature(const QString &name, const QString &email) {
return Signature(name, email);
}
Signature Repository::signature(const QString &name, const QString &email,
const QDateTime &date) {
return Signature(name, email, date);
}
Signature Repository::defaultSignature(bool *fake, const QString &overrideUser,
const QString &overrideEmail) const {
QString name, email;
@ -538,6 +547,24 @@ Commit Repository::lookupCommit(const Id &id) const {
return Commit(commit);
}
bool Repository::amend(const git::Commit &commitToAmend,
const git::Signature &author,
const git::Signature &committer,
const QString &commitMessage) {
// Write the index tree.
Index idx = index();
if (!idx.isValid())
return false;
// Add new staged files to the amended commit
Tree tree = idx.writeTree();
if (!tree.isValid())
return false;
return commitToAmend.amend(author, committer, commitMessage, tree);
}
Commit Repository::commit(const QString &message,
const AnnotatedCommit &mergeHead, bool *fakeSignature,
const QString &overrideUser,

View File

@ -92,6 +92,10 @@ public:
const QString &overrideUser = QString(),
const QString &overrideEmail = QString()) const;
Signature signature(const QString &name, const QString &email);
Signature signature(const QString &name, const QString &email,
const QDateTime &date);
// ignore
bool isIgnored(const QString &path) const;
@ -151,6 +155,9 @@ public:
const QString &message,
const AnnotatedCommit &mergeHead = AnnotatedCommit());
bool amend(const Commit &commitToAmend, const Signature &author,
const Signature &committer, const QString &commitMessage);
QList<Commit> starredCommits() const;
bool isCommitStarred(const Id &commit) const;
void setCommitStarred(const Id &commit, bool starred);

View File

@ -17,6 +17,23 @@ Signature::Signature(git_signature *signature, bool owned)
: d(
signature, owned ? git_signature_free : [](git_signature *) {}) {}
Signature::Signature(const QString &name, const QString &email) {
git_signature *signature = nullptr;
git_signature_now(&signature, name.toUtf8(), email.toUtf8());
d = QSharedPointer<git_signature>(signature, git_signature_free);
}
Signature::Signature(const QString &name, const QString &email,
const QDateTime &date) {
git_signature *signature = nullptr;
auto offset = date.offsetFromUtc() / 60;
git_signature_new(&signature, name.toUtf8(), email.toUtf8(),
date.toSecsSinceEpoch(), offset);
d = QSharedPointer<git_signature>(signature, git_signature_free);
}
Signature::operator const git_signature *() const { return d.data(); }
QString Signature::name() const { return d->name; }

View File

@ -35,6 +35,8 @@ public:
private:
Signature(git_signature *signature = nullptr, bool owned = false);
Signature(const QString &name, const QString &email);
Signature(const QString &name, const QString &email, const QDateTime &date);
operator const git_signature *() const;
QSharedPointer<git_signature> d;

View File

@ -48,8 +48,6 @@ const QString kPathspecFmt = "pathspec:%1";
// FIXME: Use 'core.abbrev' config instead?
const int kShortIdSize = 7;
enum Role { DiffRole = Qt::UserRole, CommitRole, GraphRole, GraphColorRole };
enum GraphSegment {
Dot,
Top,
@ -344,7 +342,7 @@ public:
return mStatus.isFinished() ? QVariant() : mProgress;
case DiffRole: {
case CommitList::Role::DiffRole: {
if (status)
return QVariant::fromValue(this->status());
@ -354,10 +352,10 @@ public:
return QVariant::fromValue(diff);
}
case CommitRole:
case CommitList::Role::CommitRole:
return status ? QVariant() : QVariant::fromValue(row.commit);
case GraphRole: {
case CommitList::Role::GraphRole: {
QVariantList columns;
foreach (const Column &column, row.columns) {
QVariantList segments;
@ -369,7 +367,7 @@ public:
return columns;
}
case GraphColorRole: {
case CommitList::Role::GraphColorRole: {
QVariantList columns;
foreach (const Column &column, row.columns) {
QVariantList segments;
@ -571,7 +569,7 @@ public:
QVariant data(const QModelIndex &index,
int role = Qt::DisplayRole) const override {
switch (role) {
case DiffRole: {
case CommitList::Role::DiffRole: {
git::Commit commit = mCommits.at(index.row());
bool ignoreWhitespace = Settings::instance()->isWhitespaceIgnored();
git::Diff diff = commit.diff(git::Commit(), -1, ignoreWhitespace);
@ -579,7 +577,7 @@ public:
return QVariant::fromValue(diff);
}
case CommitRole:
case CommitList::Role::CommitRole:
return QVariant::fromValue(mCommits.at(index.row()));
}
@ -650,8 +648,9 @@ public:
// Draw graph.
painter->save();
QVariantList columns = index.data(GraphRole).toList();
QVariantList colorColumns = index.data(GraphColorRole).toList();
QVariantList columns = index.data(CommitList::Role::GraphRole).toList();
QVariantList colorColumns =
index.data(CommitList::Role::GraphColorRole).toList();
for (int i = 0; i < columns.size(); ++i) {
int x = rect.x();
int y = rect.y();
@ -759,7 +758,8 @@ public:
rect.setWidth(rect.width() - constants.hMargin);
// Draw content.
git::Commit commit = index.data(CommitRole).value<git::Commit>();
git::Commit commit =
index.data(CommitList::Role::CommitRole).value<git::Commit>();
if (commit.isValid()) {
const QFontMetrics &fm = opt.fontMetrics;
QRect star = rect;

View File

@ -24,6 +24,8 @@ class CommitList : public QListView {
Q_OBJECT
public:
enum Role { DiffRole = Qt::UserRole, CommitRole, GraphRole, GraphColorRole };
CommitList(Index *index, QWidget *parent = nullptr);
// Get the status diff item.

View File

@ -353,8 +353,8 @@ public:
committer.join(", "));
// Set date range.
QDate lastDate = last.committer().date().date();
QDate firstDate = first.committer().date().date();
QDate lastDate = last.committer().date().toLocalTime().date();
QDate firstDate = first.committer().date().toLocalTime().date();
QString lastDateStr = lastDate.toString(Qt::DefaultLocaleShortDate);
QString firstDateStr = firstDate.toString(Qt::DefaultLocaleShortDate);
QString dateStr = (lastDate == firstDate)
@ -391,7 +391,7 @@ public:
git::Commit commit = commits.first();
git::Signature author = commit.author();
git::Signature committer = commit.committer();
QDateTime date = commit.committer().date();
QDateTime date = commit.committer().date().toLocalTime();
mHash->setText(brightText(tr("Id:")) + " " + commit.shortId());
mAuthorCommitterDate->setDate(
brightText(date.toString(Qt::DefaultLocaleLongDate)));

View File

@ -23,6 +23,7 @@
#include "ToolBar.h"
#include "app/Application.h"
#include "conf/Settings.h"
#include "dialogs/AmendDialog.h"
#include "dialogs/CheckoutDialog.h"
#include "dialogs/CommitDialog.h"
#include "dialogs/DeleteBranchDialog.h"
@ -40,6 +41,7 @@
#include "git/Signature.h"
#include "git/TagRef.h"
#include "git/Tree.h"
#include "git/Signature.h"
#include "git2/merge.h"
#include "host/Accounts.h"
#include "index/Index.h"
@ -1877,25 +1879,7 @@ void RepoView::amendCommit() {
if (!commit.isValid())
return;
QList<git::Commit> parents = commit.parents();
switch (parents.size()) {
case 0:
// Return to the unborn HEAD state.
// FIXME: Prompt to reset?
head.remove(true);
mDetails->setCommitMessage(commit.message());
refresh();
break;
case 1:
// Reset to parent commit.
promptToReset(parents.first(), GIT_RESET_SOFT, commit);
break;
default:
// FIXME: Return to merging state?
break;
}
promptToAmend(commit);
}
void RepoView::promptToCheckout() {
@ -2159,18 +2143,54 @@ void RepoView::promptToDeleteTag(const git::Reference &ref) {
dialog->open();
}
void RepoView::promptToReset(const git::Commit &commit, git_reset_t type,
const git::Commit &commitToAmend) {
void RepoView::promptToAmend(const git::Commit &commit) {
auto *d = new AmendDialog(commit.author(), commit.committer(),
commit.message(), this);
d->setAttribute(Qt::WA_DeleteOnClose);
connect(d, &QDialog::accepted, [this, d, commit]() {
auto info = d->getInfo();
git::Signature author = getSignature(info.authorInfo);
git::Signature committer = getSignature(info.committerInfo);
amend(commit, author, committer, info.commitMessage);
});
d->show();
}
void RepoView::amend(const git::Commit &commit, const git::Signature &author,
const git::Signature &committer,
const QString &commitMessage) {
git::Reference head = mRepo.head();
Q_ASSERT(head.isValid());
QString title = tr("Amend");
if (!mRepo.amend(commit, author, committer, commitMessage)) {
error(addLogEntry(tr("Amending commit %1").arg(commit.link()), title),
tr("amend"), head.name());
} else {
head = mRepo.head();
Q_ASSERT(head.isValid());
QString text =
tr("%1 to %2", "update ref").arg(head.name(), head.target().link());
addLogEntry(text, title);
}
}
void RepoView::promptToReset(const git::Commit &commit, git_reset_t type) {
git::Branch head = mRepo.head();
if (!head.isValid()) {
QString title = commitToAmend ? tr("Amend") : tr("Reset");
QString title = tr("Reset");
LogEntry *entry = addLogEntry(tr("<i>no branch</i>"), title);
entry->addEntry(LogEntry::Error, tr("You are not currently on a branch."));
return;
}
QString id = commitToAmend ? commitToAmend.shortId() : commit.shortId();
QString title = commitToAmend ? tr("Amend") : tr("Reset");
QString id = commit.shortId();
QString title = tr("Reset");
switch (type) {
case GIT_RESET_SOFT:
title += " Soft";
@ -2184,10 +2204,8 @@ void RepoView::promptToReset(const git::Commit &commit, git_reset_t type,
}
title += "?";
QString text = commitToAmend
? tr("Are you sure you want to amend '%1'?").arg(id)
: tr("Are you sure you want to reset '%1' to '%2'?")
.arg(head.name(), id);
QString text =
tr("Are you sure you want to reset '%1' to '%2'?").arg(head.name(), id);
QMessageBox *dialog = new QMessageBox(QMessageBox::Warning, title, text,
QMessageBox::Cancel, this);
dialog->setAttribute(Qt::WA_DeleteOnClose);
@ -2211,16 +2229,10 @@ void RepoView::promptToReset(const git::Commit &commit, git_reset_t type,
dialog->setInformativeText(info);
QString buttonText = commitToAmend ? tr("Amend") : tr("Reset");
QString buttonText = tr("Reset");
QPushButton *accept = dialog->addButton(buttonText, QMessageBox::AcceptRole);
connect(accept, &QPushButton::clicked, this,
[this, commit, type, commitToAmend] {
reset(commit, type, commitToAmend);
// Pre-populate the commit message editor.
if (commitToAmend)
mDetails->setCommitMessage(commitToAmend.message());
});
[this, commit, type] { reset(commit, type); });
dialog->open();
}
@ -2901,6 +2913,13 @@ bool RepoView::checkForConflicts(LogEntry *parent, const QString &action) {
return true;
}
git::Signature RepoView::getSignature(const ContributorInfo &info) {
if (info.commitDateType != ContributorInfo::SelectedDateTimeType::Current)
return mRepo.signature(info.name, info.email, info.commitDate);
return mRepo.signature(info.name, info.email);
}
bool RepoView::match(QObject *search, QObject *parent) {
QObjectList children = parent->children();
for (auto child : children) {

View File

@ -41,6 +41,7 @@ class PathspecWidget;
class ReferenceWidget;
class RemoteCallbacks;
class ToolBar;
class ContributorInfo;
namespace git {
class Result;
@ -262,9 +263,12 @@ public:
void promptToAddTag(const git::Commit &commit);
void promptToDeleteTag(const git::Reference &ref);
void promptToAmend(const git::Commit &commit);
void amend(const git::Commit &commit, const git::Signature &author,
const git::Signature &committer, const QString &commitMessage);
// reset
void promptToReset(const git::Commit &commit, git_reset_t type,
const git::Commit &commitToAmend = git::Commit());
void promptToReset(const git::Commit &commit, git_reset_t type);
void reset(const git::Commit &commit, git_reset_t type,
const git::Commit &commitToAmend = git::Commit());
@ -392,6 +396,8 @@ private:
bool checkForConflicts(LogEntry *parent, const QString &action);
git::Signature getSignature(const ContributorInfo &info);
git::Repository mRepo;
Index *mIndex;

View File

@ -101,4 +101,5 @@ test(NAME rebase)
test(NAME TreeView)
test(NAME Submodule)
test(NAME referencelist)
test(NAME amend)
test(NAME SshConfig)

368
test/amend.cpp Normal file
View File

@ -0,0 +1,368 @@
#include "Test.h"
#include "git/Signature.h"
#include "git/Reference.h"
#include "git/Tree.h"
#include "ui/MainWindow.h"
#include "ui/DoubleTreeWidget.h"
#include "ui/RepoView.h"
#include "ui/TreeView.h"
#include "dialogs/AmendDialog.h"
#include <QTextEdit>
#include <QRadioButton>
#include <QDateTimeEdit>
#include <QLineEdit>
#define INIT_REPO(repoPath, /* bool */ useTempDir) \
QString path = Test::extractRepository(repoPath, useTempDir); \
QVERIFY(!path.isEmpty()); \
git::Repository repo = git::Repository::open(path); \
QVERIFY(repo.isValid());
class TestAmend : public QObject {
Q_OBJECT
private slots:
void testAmend();
void testAmendAddFile();
void testAmendDialog();
void testAmendDialog2();
};
using namespace git;
void TestAmend::testAmend() {
INIT_REPO("CherryPickAuthorEmail.zip", true);
git::Reference master = repo.lookupRef(QString("refs/heads/master"));
QVERIFY(master.isValid());
auto c = master.annotatedCommit().commit();
QCOMPARE(c.message(), "changes");
QCOMPARE(c.author().email(), "martin.marmsoler@gmail.com");
QCOMPARE(c.author().name(), "Martin Marmsoler");
QCOMPARE(
c.author().date(),
QDateTime::fromString("Sun May 22 10:36:26 2022 +0200", Qt::RFC2822Date));
QCOMPARE(c.committer().name(), "Martin Marmsoler");
QCOMPARE(c.committer().email(), "martin.marmsoler@gmail.com");
QCOMPARE(
c.committer().date(),
QDateTime::fromString("Sun May 22 10:36:26 2022 +0200", Qt::RFC2822Date));
const QString commitMessage = "New commit message";
auto authorSignature = repo.signature(
"New Author", "New Author Email",
QDateTime::fromString("Sun May 23 10:36:26 2022 +0200", Qt::RFC2822Date));
auto committerSignature = repo.signature(
"New Committer", "New Committer Email",
QDateTime::fromString("Sun May 23 11:36:26 2022 +0200", Qt::RFC2822Date));
Tree tree;
c.amend(authorSignature, committerSignature, commitMessage, tree);
master = repo.lookupRef(QString("refs/heads/master"));
QVERIFY(master.isValid());
c = master.annotatedCommit().commit();
QCOMPARE(c.message(), "New commit message");
QCOMPARE(c.author().email(), "New Author Email");
QCOMPARE(c.author().name(), "New Author");
QCOMPARE(
c.author().date(),
QDateTime::fromString("Sun May 23 10:36:26 2022 +0200", Qt::RFC2822Date));
QCOMPARE(c.committer().name(), "New Committer");
QCOMPARE(c.committer().email(), "New Committer Email");
QCOMPARE(
c.committer().date(),
QDateTime::fromString("Sun May 23 11:36:26 2022 +0200", Qt::RFC2822Date));
}
void TestAmend::testAmendAddFile() {
// Create repo
Test::ScratchRepository mRepo;
auto mMainBranch = mRepo->unbornHeadName();
auto mWindow = new MainWindow(mRepo);
mWindow->show();
QVERIFY(QTest::qWaitForWindowExposed(mWindow));
RepoView *view = mWindow->currentView();
{
// Add file and refresh.
QFile file(mRepo->workdir().filePath("test"));
QVERIFY(file.open(QFile::WriteOnly));
QTextStream(&file) << "This will be a test." << endl;
Test::refresh(view);
auto doubleTree = view->findChild<DoubleTreeWidget *>();
QVERIFY(doubleTree);
auto files = doubleTree->findChild<TreeView *>("Unstaged");
QVERIFY(files);
QAbstractItemModel *model = files->model();
QCOMPARE(model->rowCount(), 1);
// Click on the check box.
QModelIndex index = model->index(0, 0);
QTest::mouseClick(files->viewport(), Qt::LeftButton,
Qt::KeyboardModifiers(),
files->checkRect(index).center());
// Commit and refresh.
QTextEdit *editor = view->findChild<QTextEdit *>("MessageEditor");
QVERIFY(editor);
editor->setText("base commit");
view->commit();
Test::refresh(view, false);
// Create branch and stage changes
git::Branch branch2 =
mRepo->createBranch("branch2", mRepo->head().target());
QVERIFY(branch2.isValid());
view->checkout(branch2);
QCOMPARE(mRepo->head().name(), QString("branch2"));
// Check if file has correct content
QVERIFY(branch2.isValid());
auto c = branch2.annotatedCommit().commit();
QCOMPARE(c.blob("test").content(), "This will be a test.\n");
}
// Stage file with changes
{
QFile file(mRepo->workdir().filePath("test"));
QVERIFY(file.open(QFile::WriteOnly));
QTextStream(&file) << "Changes made" << endl;
Test::refresh(view);
auto doubleTree = view->findChild<DoubleTreeWidget *>();
QVERIFY(doubleTree);
// Staging the file
auto files = doubleTree->findChild<TreeView *>("Unstaged");
QVERIFY(files);
QAbstractItemModel *model = files->model();
QCOMPARE(model->rowCount(), 1);
// Click on the check box. to stage file
QModelIndex index = model->index(0, 0);
QTest::mouseClick(files->viewport(), Qt::LeftButton,
Qt::KeyboardModifiers(),
files->checkRect(index).center());
}
// Check that changes applied after amending
{
// Amend changes
git::Reference branch2 = mRepo->lookupRef(QString("refs/heads/branch2"));
QVERIFY(branch2.isValid());
auto c = branch2.annotatedCommit().commit();
auto authorSignature = mRepo->signature("New Author", "New Author Email");
auto committerSignature =
mRepo->signature("New Committer", "New Committer Email");
QCOMPARE(mRepo->amend(c, authorSignature, committerSignature,
"New commit message"),
true);
{
branch2 = mRepo->lookupRef(QString("refs/heads/branch2"));
QVERIFY(branch2.isValid());
c = branch2.annotatedCommit().commit();
QCOMPARE(c.message(), "New commit message");
QCOMPARE(c.author().email(), "New Author Email");
QCOMPARE(c.author().name(), "New Author");
QCOMPARE(c.committer().name(), "New Committer");
QCOMPARE(c.committer().email(), "New Committer Email");
QCOMPARE(c.blob("test").content(), "Changes made\n");
}
}
}
void TestAmend::testAmendDialog() {
// Checking that original information is passed to the return function
// correctly Name and email will not be changed. Only different datetypes are
// tested
Test::ScratchRepository repo;
auto authorSignature = repo->signature(
"New Author", "New Author Email",
QDateTime::fromString("Sun May 23 10:36:26 2022 +0200", Qt::RFC2822Date));
auto committerSignature = repo->signature(
"New Committer", "New Committer Email",
QDateTime::fromString("Sun May 23 11:36:26 2022 +0200", Qt::RFC2822Date));
{
AmendDialog d(authorSignature, committerSignature, "Test commit message");
d.show();
{
const auto *authorCommitDateTimeTypeSelection =
d.findChild<QWidget *>(tr("Author") + "CommitDateType");
QVERIFY(authorCommitDateTimeTypeSelection);
auto *authorCurrent =
authorCommitDateTimeTypeSelection->findChild<QRadioButton *>(
"Current");
QVERIFY(authorCurrent);
auto *authorOriginal =
authorCommitDateTimeTypeSelection->findChild<QRadioButton *>(
"Original");
QVERIFY(authorOriginal);
auto *authorManual =
authorCommitDateTimeTypeSelection->findChild<QRadioButton *>(
"Manual");
QVERIFY(authorManual);
auto *authorCommitDate =
d.findChild<QDateTimeEdit *>(tr("Author") + "CommitDate");
QVERIFY(authorCommitDate);
authorCommitDate->setDateTime(
QDateTime(QDate(2012, 7, 6), QTime(8, 30, 5)));
// current
authorCurrent->click();
auto info = d.getInfo();
QCOMPARE(info.authorInfo.commitDateType,
ContributorInfo::SelectedDateTimeType::Current);
QCOMPARE(authorCommitDate->isVisible(), false);
// original
authorOriginal->click();
info = d.getInfo();
QCOMPARE(info.authorInfo.commitDateType,
ContributorInfo::SelectedDateTimeType::Original);
QCOMPARE(authorCommitDate->isVisible(), false);
QCOMPARE(info.authorInfo.commitDate,
QDateTime::fromString("Sun May 23 10:36:26 2022 +0200",
Qt::RFC2822Date));
// manual
authorManual->click();
info = d.getInfo();
QCOMPARE(info.authorInfo.commitDateType,
ContributorInfo::SelectedDateTimeType::Manual);
QCOMPARE(authorCommitDate->isVisible(), true);
QCOMPARE(info.authorInfo.commitDate,
QDateTime(QDate(2012, 7, 6), QTime(8, 30, 5)));
}
{
const auto *committerCommitDateTimeTypeSelection =
d.findChild<QWidget *>(tr("Committer") + "CommitDateType");
QVERIFY(committerCommitDateTimeTypeSelection);
auto *committerCurrent =
committerCommitDateTimeTypeSelection->findChild<QRadioButton *>(
"Current");
QVERIFY(committerCurrent);
auto *committerOriginal =
committerCommitDateTimeTypeSelection->findChild<QRadioButton *>(
"Original");
QVERIFY(committerOriginal);
auto *committerManual =
committerCommitDateTimeTypeSelection->findChild<QRadioButton *>(
"Manual");
QVERIFY(committerManual);
auto *committerCommitDate =
d.findChild<QDateTimeEdit *>(tr("Committer") + "CommitDate");
QVERIFY(committerCommitDate);
committerCommitDate->setDateTime(
QDateTime(QDate(2013, 5, 2), QTime(11, 22, 7)));
// current
committerCurrent->click();
auto info = d.getInfo();
QCOMPARE(info.committerInfo.commitDateType,
ContributorInfo::SelectedDateTimeType::Current);
QCOMPARE(committerCommitDate->isVisible(), false);
// original
committerOriginal->click();
info = d.getInfo();
QCOMPARE(info.committerInfo.commitDateType,
ContributorInfo::SelectedDateTimeType::Original);
QCOMPARE(committerCommitDate->isVisible(), false);
QCOMPARE(info.committerInfo.commitDate,
QDateTime::fromString("Sun May 23 11:36:26 2022 +0200",
Qt::RFC2822Date));
// manual
committerManual->click();
info = d.getInfo();
QCOMPARE(info.committerInfo.commitDateType,
ContributorInfo::SelectedDateTimeType::Manual);
QCOMPARE(committerCommitDate->isVisible(), true);
QCOMPARE(info.committerInfo.commitDate,
QDateTime(QDate(2013, 5, 2), QTime(11, 22, 7)));
}
auto info = d.getInfo();
QCOMPARE(info.authorInfo.name, "New Author");
QCOMPARE(info.authorInfo.email, "New Author Email");
QCOMPARE(info.committerInfo.name, "New Committer");
QCOMPARE(info.committerInfo.email, "New Committer Email");
QCOMPARE(info.commitMessage, "Test commit message");
}
}
void TestAmend::testAmendDialog2() {
// Test changing author name, author email, committer name, committer email
Test::ScratchRepository repo;
auto authorSignature = repo->signature(
"New Author", "New Author Email",
QDateTime::fromString("Sun May 23 10:36:26 2022 +0200", Qt::RFC2822Date));
auto committerSignature = repo->signature(
"New Committer", "New Committer Email",
QDateTime::fromString("Sun May 23 11:36:26 2022 +0200", Qt::RFC2822Date));
AmendDialog d(authorSignature, committerSignature, "Test commit message");
auto commitMessageEditor =
d.findChild<QTextEdit *>("Textlabel Commit Message");
QVERIFY(commitMessageEditor);
commitMessageEditor->setText("Changing the commit message");
// Author
{
const auto *author = d.findChild<QWidget *>(tr("Author"));
QVERIFY(author);
auto *name = author->findChild<QLineEdit *>("Name");
QVERIFY(name);
auto *email = author->findChild<QLineEdit *>("Email");
QVERIFY(email);
name->setText("Another author name");
email->setText("Another author email address");
}
// Committer
{
const auto *committer = d.findChild<QWidget *>(tr("Committer"));
QVERIFY(committer);
auto *name = committer->findChild<QLineEdit *>("Name");
QVERIFY(name);
auto *email = committer->findChild<QLineEdit *>("Email");
QVERIFY(email);
name->setText("Another committer name");
email->setText("Another committer email address");
}
const auto info = d.getInfo();
QCOMPARE(info.authorInfo.name, "Another author name");
QCOMPARE(info.authorInfo.email, "Another author email address");
QCOMPARE(info.committerInfo.name, "Another committer name");
QCOMPARE(info.committerInfo.email, "Another committer email address");
QCOMPARE(info.commitMessage, "Changing the commit message");
}
TEST_MAIN(TestAmend)
#include "amend.moc"

View File

@ -8,8 +8,10 @@
//
#include "Test.h"
#include "dialogs/AmendDialog.h"
#include "dialogs/CloneDialog.h"
#include "dialogs/StartDialog.h"
#include "qnamespace.h"
#include "ui/CommitList.h"
#include "ui/DetailView.h"
#include "ui/DiffView/DiffView.h"
@ -22,6 +24,7 @@
#include <QLineEdit>
#include <QMenu>
#include <QPushButton>
#include <QTextEdit>
#include <QTextStream>
#include <QToolButton>
@ -141,6 +144,13 @@ void TestInitRepo::amendCommit() {
view->amendCommit();
auto dialog = view->findChild<AmendDialog *>();
QVERIFY(dialog);
dialog->findChild<QTextEdit *>()->setText("Some other commit message");
dialog->accept();
qWait(300);
{
auto timeout =
Timeout(10000, "Repository didn't detect status change in time");
@ -153,8 +163,9 @@ void TestInitRepo::amendCommit() {
QVERIFY(commitList);
QAbstractItemModel *commitModel = commitList->model();
QModelIndex index = commitModel->index(0, 0);
QString name = commitModel->data(index, Qt::DisplayRole).toString();
QCOMPARE(name, QString("Uncommitted changes"));
auto commit = commitModel->data(index, CommitList::Role::CommitRole)
.value<git::Commit>();
QCOMPARE(commit.message(), QString("Some other commit message"));
}
void TestInitRepo::editFile() {