Skip to content

Conversation

@taufek
Copy link
Contributor

@taufek taufek commented Jan 14, 2018

Previously, Overcommit::HookContext::PrePush::modified_files is set as [] which
does not give us any value in applicable_files as in PreCommit context.

This change updates the method to return list of added and updated files in current branch:

  1. compared between current branch and tracking branch if tracking branch is available.

  2. compared between current branch with parent branch if tracking branch is not available.

This gives us above values in applicable_files in PrePush context.

One usage example is we can create a hook to scan prohibited keywords such as eval, console.log, etc. before pushing to remote. Previously we can only do it in PreCommit hook but now we could also do it in PrePush.

I think this will also allow us to reuse existing hooks for PreCommit in PrePush context that relies on applicable_files method.

@taufek taufek force-pushed the tj-pre-push-mod-files branch 18 times, most recently from ea44027 to 664a981 Compare January 15, 2018 02:01
Copy link
Owner

@sds sds left a comment

Choose a reason for hiding this comment

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

Hey @taufek, thanks for the pull request. This would be a great feature to add.

My concern here is that you are not determining the modified refs from the list passed to the pre-push hook, but are inferring them from the current state of the local repository.

I imagine this works correctly in most cases, but I'm concerned that there are issues with this implementation which are not obvious because we're obtaining the refs ourselves rather than using the refs Git passes to the pre-push hook. For example, you can run git push origin HEAD:refs/heads/name-of-your-branch from a detached head (perhaps odd, but definitely possible).

I can appreciate this implementation makes it easier to test, but I think we need to be rigorous in our solution here and utilize the refs Git passes to the hook.

end

def parent_branch
`git show-branch -a \
Copy link
Owner

Choose a reason for hiding this comment

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

On a local repo of mine with a lot of remote branches, this can display warnings like:

warning: ignoring origin/some-remote-branch; cannot handle more than 25 refs

Would need to filter out stderr to avoid.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch. Will update accordingly.

@taufek
Copy link
Contributor Author

taufek commented Jan 16, 2018

Thank you @sds for the feedback. It does make sense. I will dig further and incorporate your suggestion here.

@taufek taufek force-pushed the tj-pre-push-mod-files branch from 0d53662 to 5047375 Compare January 19, 2018 17:12
@taufek
Copy link
Contributor Author

taufek commented Jan 19, 2018

@sds ,

I've updated based on your feedback. What do you think?

@taufek taufek force-pushed the tj-pre-push-mod-files branch 3 times, most recently from f3a63ba to 8c6eca9 Compare January 19, 2018 23:41
Copy link
Owner

@sds sds left a comment

Choose a reason for hiding this comment

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

Thanks for making those changes, @taufek. We're getting close here.

`git push -u origin project-branch 2>&1 > #{File::NULL}`

touch 'added-1'
`echo add >> added-1`
Copy link
Owner

Choose a reason for hiding this comment

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

Similar to why we use the touch helper above, you should use the echo helper here. It saves us having to spawn a child process—which is slower than appending to the file directly in Ruby. A small optimization in this localized example, but when applied across the entire repository it has significant benefits.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

TIL. Will update accordingly.

# @param ref [String] git ref
# @return [String] ref's sha1
def get_sha1(ref)
`git show-ref --head`.
Copy link
Owner

Choose a reason for hiding this comment

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

This seems unnecessarily expensive (listing all the refs and then filtering for the one of interest). Any reason why

git rev-parse my-ref

...wouldn't suffice here?

Copy link
Contributor Author

@taufek taufek Jan 22, 2018

Choose a reason for hiding this comment

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

Definitely will try this out.

def get_sha1(ref)
`git show-ref --head`.
split("\n").
find { |x| x =~ /#{Regexp.quote(ref)}/i }.
Copy link
Owner

Choose a reason for hiding this comment

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

Another danger here is you aren't anchoring your regex with ^ / $, so a ref of foo will match foo, foobar, somefoobar, etc. Fortunately we should be able to avoid entirely with git rev-parse ....

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍🏻

touch 'delete-me'
`echo delete >> delete-me`
`git add . 2>&1 > #{File::NULL}`
`git commit -m "Initial commit" 2>&1 > #{File::NULL}`
Copy link
Owner

Choose a reason for hiding this comment

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

If we intend to have with_remote_repo be a generic spec helper, it should create the most generic possible setup, and thus should not create any files/commits/objects.

`git commit -m "Initial commit" 2>&1 > #{File::NULL}`

Dir.chdir '..' do
remote_url = "file://#{File.expand_path('some-repo')}"
Copy link
Owner

Choose a reason for hiding this comment

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

We should not hard code some-repo here (that assumes we know how the repo helper is implemented), but obtain it from the name of the repo directory that was created.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

My thought was to create a repo with a remote with some default files. Your comment does make sense. It could easily misinterpreted and it is not generic enough for re-use.

end

Dir.chdir '../local-repo' do
yield if block_given?
Copy link
Owner

Choose a reason for hiding this comment

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

Not to be overly pedantic, but when I read with_remote_repo I would expect that the block I pass would execute within the context of the remote repository, but I'll admit it's a bit hard to describe what we're trying to do concisely.

yield if block_given?
end
end
end
Copy link
Owner

Choose a reason for hiding this comment

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

Looking at the issues with this implementation of with_remote_repo, I'm not entirely convinced this helper is going to get you much. We should probably stick with first principles in the specs:

remote_repo = repo do
  # Create remote repository to our liking
  ...
end

local_repo = repo do
  `git remote add origin file://#{remote_repo}`
  `git fetch origin && git reset --hard origin/master`

  # Create local repository to our liking
  ...
  # Validate expectations
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This will work. Thanks for the tip

touch 'added-1'
`echo add >> added-1`
`echo append >> update-me`
`rm delete-me`
Copy link
Owner

Choose a reason for hiding this comment

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

FileUtils.rm (again to avoid a child process).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍🏻

end

describe '#modified_files' do
let(:remote_url) { "file://#{File.expand_path('some-repo')}" }
Copy link
Owner

Choose a reason for hiding this comment

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

The use of some-repo here is cheating a bit as it assumes we know the name of the directory of the repository, which we don't (it is returned by the repo helper).

We can work around this by creating the remote repo in the let so we have the reference.

let(:remote_repo) do
  repo do
    ...
  end
end

let(:remote_url) { "file://#{remote_repo}" }

You can then enter the repo in the specs to perform additional custom setup work:

it ... do
  Dir.chdir remote_repo do
    ...
  end
end

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Looks good. Will try this out.

@taufek taufek force-pushed the tj-pre-push-mod-files branch 2 times, most recently from 718fd06 to f64d664 Compare January 23, 2018 15:57
Previously, `Overcommit::HookContext::PrePush::modified_files` is set as `[]` which
does not give us any value in `applicable_files` as in `PreCommit` context.

This change updates the method to return list of added and updated files:

1. compared between current branch and tracking branch if tracking branch is available.

2. compared between current branch with parent branch if tracking branch is not available.

This gives us above values in `applicable_files` in `PrePush` context.

One usage example is we can create a hook to scan prohibited keywords such as `eval`, `console.log`, etc. before pushing to remote. Previously we can only do it in `PreCommit` hook but now we could also do it in `PrePush`.
@taufek taufek force-pushed the tj-pre-push-mod-files branch from f64d664 to 0ad7976 Compare January 23, 2018 15:59
@taufek
Copy link
Contributor Author

taufek commented Jan 23, 2018

@sds,

This is ready for re-review.

Copy link
Owner

@sds sds left a comment

Choose a reason for hiding this comment

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

You're amazing, @taufek. Thanks for writing such thorough tests!

@sds sds merged commit 9af0b3c into sds:master Jan 24, 2018
@taufek
Copy link
Contributor Author

taufek commented Jan 24, 2018

Thanks @sds. Can't do it without you. I've learned so much.

@taufek taufek deleted the tj-pre-push-mod-files branch January 27, 2018 16:16
taufek added a commit to taufek/overcommit that referenced this pull request Feb 5, 2018
Continuation from sds#536 where it added `modified_files` for `PrePush` context.
This is to add `modified_lines_in_file` for `PrePush` context.
taufek added a commit to taufek/overcommit that referenced this pull request Feb 5, 2018
Continuation from sds#536 where it added `modified_files` for `PrePush` context.
This is to add `modified_lines_in_file` for `PrePush` context.
taufek added a commit to taufek/overcommit that referenced this pull request Feb 5, 2018
Continuation from sds#536 where it added `modified_files` for `PrePush` context.
This is to add `modified_lines_in_file` for `PrePush` context.
sds pushed a commit that referenced this pull request Feb 5, 2018
Continuation from #536 where it added `modified_files` for `PrePush` context.
This is to add `modified_lines_in_file` for `PrePush` context.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants