Skip to content
This repository has been archived by the owner on Sep 9, 2020. It is now read-only.

Allow using various git diff options for comparisons #126

Closed
wants to merge 8 commits into from

Conversation

timmartin19
Copy link

Instead of having to do funky stuff with soft git resets, this allows the user
to pass a --diff option. This option can be anything that works with both
git diff-tree and git rev-list. This option does not work with mercurial
yet. This is particularly helpful in CI pipelines that rely on PRs.
Effectively, you run git lint --diff 'HEAD ^<target-branch>'

The change basically works by looking at all the commits that are different
instead of just the --last-commit. It uses the git rev-list command to
determine which commits are different. It then uses the same modified_lines
function with a slight modification. modified lines now uses a regex OR
condition for all of the commits instead of just one commit.

Instead of having to do funky stuff with soft git resets, this allows the user
to pass a `--diff` option.  This option can be anything that works with both
`git diff-tree` and `git rev-list`.  This option does not work with mercurial
yet.  This is particularly helpful in CI pipelines that rely on PRs.
Effectively, you run `git lint --diff 'HEAD ^<target-branch>'`

The change basically works by looking at all the commits that are different
instead of just the `--last-commit`.  It uses the `git rev-list` command to
determine which commits are different.  It then uses the same `modified_lines`
function with a slight modification.  `modified lines` now uses a regex OR
condition for all of the commits instead of just one commit.
It wanted to break the arguments onto multiple line in the usage. This made it
less readable IMO so I disabled the linter for that section
Can't satisfy pycodestyle and docopt at the same time without breaking
it onto multiple lines.  Doesn't read as well in my opinion.
@timmartin19
Copy link
Author

Addresses #60 and #110

@sk-
Copy link
Owner

sk- commented Jun 21, 2018

Thanks @timmartin19 for the PR, I like the idea, but would like to clarify and simplify some things.

  • With this option --last-commit could be simplified to mean --diff=HEAD^..HEAD.
  • We should somehow restrict the diff to be only made against HEAD, because otherwise the results are going to be (mostly) meaningless. If you need to diff a range that's not ending in HEAD you actually need to reset the repo so that the results are accurate.
  • Will this work in a CI environment, I know that the repo is in a weird state in which the HEAD is dettached.
  • We would need to have an integration test to validate that the listing of the files is working as intended.

last_commit = vcs.last_commit()
commits = [last_commit]

if arguments['--diff'] and vcs.__name__ != 'gitlint.git':
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you could do vcs != gitlint.git

gitlint/git.py Outdated

# Split as bytes, as the output may have some non unicode characters.
blame_lines = subprocess.check_output(
['git', 'blame', '--porcelain', filename]).split(
os.linesep.encode('utf-8'))
regex_pattern = r'^({}) (?P<line>\d+) (\d+)'.format(
'|'.join(commits)).encode('utf-8')
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For safety I'd prefer to escape the commits.

@@ -17,6 +17,7 @@
import os
import sys

from docopt import DocoptExit
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I follow the Google style guide, so we only import modules.

gitlint/git.py Outdated
command = [
'git', 'diff-tree', '-r', '--root', '--no-commit-id', '--name-status'
]
command.extend(diff_target.split(' '))
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In which cases is the argument going to have spaces, could you give some examples.

@timmartin19
Copy link
Author

@sk- I think you're absolutely right about always comparing against HEAD. What if it was something like this git lint --diff <commit|branch> and we always compare that commit/branch against the current HEAD? For example, this PR might use git lint --diff master which would translate to git diff-tree master..HEAD. In this case, git lint --diff HEAD^ would be equivalent to git lint --last-commit

I don't think a detached HEAD will cause any problems since we aren't making any changes nor committing. That being said, I'll play with it in a branch in my fork on travis and play with it in Jenkins.

It gets pretty hard to compare arbitrarily.  Instead, it now simply compares a
target branch or commit against the current head.  This also simplifies
`--last-commit` since it's effectively the same as `--diff HEAD^`.  This did
require some refactoring to keep the code base clean.

Also, adding an e2e test for comparing a branch multiple commits ahead
of master against master.
I really need to set up the local commit hooks
@timmartin19
Copy link
Author

I checked whether it worked with travis. Do to their use of --depth=50 when cloning, you need to do one of two things:

  1. Tell travis not to use depth when cloning. In your .travis.yml

    git:
    depth: false

  2. Explicitly overwrite the configuration before running git lint

    git config --replace-all remote.origin.fetch +refs/heads/:refs/remotes/origin/

@timmartin19
Copy link
Author

@sk- Is there anything else you need for this PR?

@sk-
Copy link
Owner

sk- commented Jul 16, 2018

@timmartin19 Hi Tim, the fact that you still need to wrangle with the git settings in order to be able to run it in Travis makes me doubt about the general usefulness of the PR, as the motivating case was exactly to support CI (hence the mention of git reset).

@timmartin19
Copy link
Author

timmartin19 commented Jul 16, 2018

@sk- That's a quirk of travis as far as I can tell. We're running it in Jenkins now with no special adjustments and it's working just fine. Also, this does not break (like the current CI mechanism) when you force push. The soft reset mechanism being used in Travis is not really workable across different CI tools.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants