-
Notifications
You must be signed in to change notification settings - Fork 579
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
GitCommitBear.py: Detect revert commits #2241
Conversation
d98e1dd
to
e1d9e2f
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to add tests.
bears/vcs/git/GitCommitBear.py
Outdated
@@ -123,6 +123,9 @@ def run(self, allow_empty_commit_message: bool = False, **kwargs): | |||
yield Result(self, 'HEAD commit has no message.') | |||
return | |||
|
|||
if shortlog.startswith('Revert') and len(body) == 0: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So you are not detecting revert commits if they do have a reason?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think revert commits with reason have any problem.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When revert commits don't have any reason then they are wrong. Hence, detected only then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure what needs to be done here. On what was meant by the issue, whether you have to detect revert commits and an additional check if they don't have a reason, or for only when they don't have a reason. You should discuss this with someone cc @sils
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did mention @sils once on gitter asking something like this. Never got any response.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Then you need to change tests again accordingly, so its better to ask someone what to do first ;)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t particularly like this solution since reason could be given in the shortlog as well, and failing coala on a repository due to that is not good.
Also, is there a better way to detect reverting of commits? I couldn’t find one myself, but it seems this might over-trigger quite easily.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would also say: Simple by default, powerful if needed.
We should implement other settings controlling what is considered a revert commit. But that can be part of a new issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I would remove the len(body)
part
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And btw: I want to see a setting to enable looking for revert-commits 👍
480d390
to
b4e0f48
Compare
Commit message shortlog: Please no space before colon ;) |
unack b4e0f48 |
Comments not all addressed :) |
unack 0105d2b |
a80f473
to
28aa030
Compare
bears/vcs/git/GitCommitBear.py
Outdated
@@ -123,6 +127,9 @@ def run(self, allow_empty_commit_message: bool = False, **kwargs): | |||
yield Result(self, 'HEAD commit has no message.') | |||
return | |||
|
|||
if shortlog.startswith('Revert') and check_revert_commits: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For performance reasons, switch both conditions:
if check_revert_commits and shortlog.startswith('Revert'):
bears/vcs/git/GitCommitBear.py
Outdated
@@ -96,7 +96,9 @@ def get_host_from_remotes(): | |||
netloc = urlparse(url)[1] | |||
return netloc.split('.')[0] | |||
|
|||
def run(self, allow_empty_commit_message: bool = False, **kwargs): | |||
def run(self, allow_empty_commit_message: bool = False, | |||
check_revert_commits: bool = True, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe to fit the naming scheme: allow_revert_commits
? And it's by default False
? (tbh I'm not sure what should be default for this anyway...)
bears/vcs/git/GitCommitBear.py
Outdated
@@ -105,6 +107,8 @@ def run(self, allow_empty_commit_message: bool = False, **kwargs): | |||
|
|||
:param allow_empty_commit_message: Whether empty commit messages are | |||
allowed or not. | |||
:param check_revert_commits: whether revert commits are to be | |||
checked or not. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- Bad docstring indentation.
- First letter should be upper-case.
tests/vcs/git/GitCommitBearTest.py
Outdated
@@ -125,6 +125,14 @@ def test_empty_message(self): | |||
[]) | |||
self.assert_no_msgs() | |||
|
|||
def test_revert_commit(self): | |||
self.git_commit('Revert : identifies revert commit\n') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, you can maybe try to invoke git revert
itself. That way we can see if we are really compliant with git's revert commits. So commit some arbitrary stuff, and then revert and test.
unack 28aa030 |
tests/vcs/git/GitCommitBearTest.py
Outdated
@@ -125,6 +127,45 @@ def test_empty_message(self): | |||
[]) | |||
self.assert_no_msgs() | |||
|
|||
def test_revert_checks(self): | |||
self.run_git_command('commit', stdin='Test commit') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use self.run_git_command
for committing only after doing a git add
.
Otherwise this will fail due to empty diffs and as a result no commit would be made.
And a git rev-parse HEAD
on a repository with no commit will result in failures.
Consider using self.git_commit
instead as it allows empty commits and can be done even without doing a git add
Rather if you want to use run_git_command
, use it to generate a revert commit
For e.g self.run_git_command('revert', 'head')
bears/vcs/git/GitCommitBear.py
Outdated
headline_regex = re.compile(r'^This reverts commit [0-9a-f]{40}') | ||
sha_regex = re.compile(r'\b[0-9a-f]{40}\b') | ||
|
||
if (not allow_revert_commits_without_reason and |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question:
What will happen in case the user allows revert commits without reason and while generating a revert commit, say the shortlog doesn't match or the commit sha is altered for some reason ? (via a git commit --amend
for example)
tests/vcs/git/GitCommitBearTest.py
Outdated
'This is body of test commit1\n') | ||
commit_hash, _ = run_shell_command('git rev-parse HEAD') | ||
|
||
self.run_git_command('revert', 'head') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These revert commits are redundant since you are already making another commit on top of these, so Commit Bear is never run on them
(Similarly on line 179)
tests/vcs/git/GitCommitBearTest.py
Outdated
commit_hash, _ = run_shell_command('git rev-parse HEAD') | ||
self.run_git_command('revert', 'head') | ||
|
||
self.git_commit('Revert "Test commit3"\n\n' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the default format of a revert commit, you can omit creating this one manually and just use the commit generated in line 155
bears/vcs/git/GitCommitBear.py
Outdated
|
||
if revert_shortlog_regex.match(shortlog): | ||
reverted_shortlog = shortlog.lstrip('Revert ') | ||
reverted_shortlog = reverted_shortlog.strip('"') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider having a look at capturing and non-capturing regexes
bears/vcs/git/GitCommitBear.py
Outdated
commit_sha = re.search(HEADLINE_REGEX, headline).group(2) | ||
command = ('git log -n 1 ' + | ||
str(commit_sha) + ' --pretty=%B') | ||
rstdout, _ = run_shell_command(command) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Question : What would happen if the commit_sha is an invalid number (or a commit_hash that doesn't exist) ?
Refer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does the r
in rstdout
stand for?
use long self-explanatory variable names.
bears/vcs/git/GitCommitBear.py
Outdated
@@ -112,8 +119,7 @@ def get_host_from_remotes(): | |||
netloc = parsed_url.host | |||
return netloc.split('.')[0] | |||
|
|||
def run(self, | |||
allow_empty_commit_message: bool = False, | |||
def run(self, allow_empty_commit_message: bool = False, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this being modified?
bears/vcs/git/GitCommitBear.py
Outdated
@@ -151,6 +161,47 @@ def run(self, | |||
body, | |||
**self.get_issue_checks_metadata().filter_parameters(kwargs)) | |||
|
|||
def check_revert(self, shortlog, body, | |||
allow_revert_commits_without_reason: bool = False,): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a trailing comma is silly if the )
follows it.
You need to understand why you should use trailing commas.
bears/vcs/git/GitCommitBear.py
Outdated
""" | ||
Validates revert commits. | ||
|
||
:param shortlog: The shortlog message string. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these descriptions are laid out very messily.
bears/vcs/git/GitCommitBear.py
Outdated
REVERT_REGEX = re.compile(r'(Revert ")([\S+\s*]*)("$)') | ||
HEADLINE_REGEX = re.compile(r'(^This reverts commit )([0-9a-f]{40})') | ||
|
||
if REVERT_REGEX.match(shortlog): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
use
if not REVERT_REGEX.match(shortlog):
return
bears/vcs/git/GitCommitBear.py
Outdated
:param allow_revert_commits_without_reason: Whether reason is | ||
needed for revert commits. | ||
""" | ||
REVERT_REGEX = re.compile(r'(Revert ")([\S+\s*]*)("$)') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this regex creates useless capture groups, making it harder to read than it needs to be.
Also [\S+\s*]*
is invalid semantically.
Furthermore, there is no need to use a regex for this.
bears/vcs/git/GitCommitBear.py
Outdated
needed for revert commits. | ||
""" | ||
REVERT_REGEX = re.compile(r'(Revert ")([\S+\s*]*)("$)') | ||
HEADLINE_REGEX = re.compile(r'(^This reverts commit )([0-9a-f]{40})') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, this is using capture groups which are not used.
bears/vcs/git/GitCommitBear.py
Outdated
commit_sha = re.search(HEADLINE_REGEX, headline).group(2) | ||
command = ('git log -n 1 ' + | ||
str(commit_sha) + ' --pretty=%B') | ||
rstdout, _ = run_shell_command(command) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
what does the r
in rstdout
stand for?
use long self-explanatory variable names.
This detects revert commits and checks they have a reason as well. Closes coala#337
Please review @jayvdb @virresh @nalinbhardwaj @ishanSrt @newbazz |
self.run_uut(), | ||
['Shortlog of revert commit does not match the original commit.']) | ||
self.assert_no_msgs() | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kriti21
It would be great to have a test such as
_,__ = run_shell_command('echo "a" >> testfile.txt ')
self.run_git_command('add', 'testfile.txt')
self.run_git_command('commit', '-m', '"a commit"')
commit_hash, _ = run_shell_command('git rev-parse HEAD')
self.run_git_command('revert', 'HEAD', '--no-edit')
self.assertEqual(self.run_uut(),
['Revert commit does not have a reason.'])
"<Merged signature of 'run', 'check_shortlog', 'check_body'" | ||
", 'check_issue_reference'>") | ||
"<Merged signature of 'run', 'check_revert', 'check_shortlog'" | ||
", 'check_body', 'check_issue_reference'>") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please don't change existing test unless there's a reason. I don't see any such change in your patch which might affect this test.
Maybe write a new separate test for current change?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay it all cool 👍 you just added check_revert
self.git_commit('Test commit') | ||
commit_hash, _ = run_shell_command('git rev-parse HEAD') | ||
self.git_commit('Revert "Test commit"\n\n' | ||
'Abcdef blablabla commit ' + str(commit_hash) + '\n\n' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test content should be self explanatory about its existence.
Please use proper sentence in place of
Abcdef blablabla commit
:P
command) | ||
|
||
if previous_commit_stderr: | ||
yield Result(self, 'Invalid sha for reverted commit.') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sha -> SHA
|
||
shortlog_start_index = shortlog.find('"') | ||
shortlog_end_index = shortlog.rfind('"') | ||
reverted_shortlog = shortlog[shortlog_start_index + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
shortlog_start_index, shortlog_end_index and reverted_shortlog are confusing names in this context as, in other places of the code shortlog refers to the entire string including the subject and the message.
old_shortlog = previous_commit_stdout[:position] if position != - \ | ||
1 else previous_commit_stdout | ||
|
||
if old_shortlog != reverted_shortlog: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a problem if shortlog for the previous commit barely fit within the length limit as, to be a valid revert commit, it'll have to be rewritten with extra characters in the new commit and thereby cause an impossible situation.
I think the solution would be to rethink about the shortlog structure you require for a valid revert commit. I propose it should be written as
08b54a: Revert Commit
This reason to revert would be...
Reference if any
and this structure is also more aligned with the general guidelines.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The format followed is one that is generated by git itself for revert commits. This PR only checks if a reason for revert is mentioned or not. See link
I don't think changing shortlog structure would be most apt solution. One possible solution could be to increase shorlog length limit for revert commits (to maybe 60). @ksdme @jayvdb @damngamerz
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One possible solution could be to increase shorlog length limit for revert commits
Yes, whenever a revert commit is detected, and revert commits have been permitted in the repo, other rules which might reject the commit must be turned off.
yield Result(self, 'Invalid revert commit.') | ||
return | ||
|
||
sha_regex = re.compile(r'([0-9a-f]{40})') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As the intent is also to maintain readability why not support short SHA1 hashes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
git revert
doesnt do that
if not shortlog.startswith('Revert '): | ||
return | ||
|
||
shortlog_start_index = shortlog.find('"') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why can't I use single quotes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
git revert
doesnt do that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is about the requirement of the shortlog of the revert commit specifically to be written as Revert "Another Test commit2"
. I don't see any reason why using single quotes should cause a failure.
|
||
previous_commit_stdout = previous_commit_stdout.rstrip('\n') | ||
position = previous_commit_stdout.find('\n') | ||
old_shortlog = previous_commit_stdout[:position] if position != - \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this linebreak looks pretty confusing try breaking before the if
Lots of manual conflict resolution needed now that #2310 has landed. |
'This is body of test commit1\n') | ||
commit_hash, _ = run_shell_command('git rev-parse HEAD') | ||
|
||
self.git_commit('Revert "Another Test commit2"\n\n' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test method contains many testcases of revert features. I think it will be better if we can split this into several test method like test_revert_check_success
, test_revert_check_commit_no_reason
, test_revert_check_invalid_sha_commit
, etc
Duplicate of #2652 |
This detects revert commits
and checks they have a reason as well.
Closes #337
Checklist
them.
individually. It is not sufficient to have "fixup commits" on your PR,
our bot will still report the issues for the previous commit.) You will
likely receive a lot of bot comments and build failures if coala does not
pass on every single commit!