Skip to content
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

Pre push testsuites #258

Closed
wants to merge 10 commits into from
Closed

Pre push testsuites #258

wants to merge 10 commits into from

Conversation

Mte90
Copy link

@Mte90 Mte90 commented Jan 10, 2017

Q A
Branch master
Bug fix? no
New feature? yes
Tests pass? yes/no
Documented? no
Fixed tickets #252

It is an experiment to get the #252 working, actually there is the problem that if we have a grumphp.yml like that:

parameters:
    git_dir: .
    bin_dir: vendor/bin
    ignore_unstaged_changes: false
    tasks: 
        codeception:
            config_file: ~
            fail_fast: false
            suite: ~
            test: ~
    testsuites:
        git_pre_push:
            tasks: 
                - codeception

It's working but codeception is executed also on commit, and I have no idea how to avoid that.

New Task Checklist:

  • Is the README.md file updated?
  • Does the task run in the correct context?
  • Are all CI services returning green?

COMMIT_MSG_FILE=$1

# Fetch the GIT diff and format it as command input:
DIFF=$(git diff -r -p -m -M --full-index --staged | cat)
Copy link
Contributor

Choose a reason for hiding this comment

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

This will mostly result in an empty set of files since on push the staged changes are mostly empty of should not be checked since those aren't the files that you're committing. We'll need to find a way to check which files are transfered to the remote.

Copy link
Author

@Mte90 Mte90 Jan 11, 2017

Choose a reason for hiding this comment

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

git diff --name-only origin/master..HEAD this show all the file changed in the commit not yet pushed. The problem is that require to specify the branch.

Copy link
Author

Choose a reason for hiding this comment

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

Ok I found the right one GIT_CURRENT_BRANCH=$(git name-rev --name-only HEAD) && git diff --name-only origin/$GIT_CURRENT_BRANCH..HEAD --oneline in that way get the actual branch

@@ -116,6 +116,10 @@ protected function getDefaultCommands()
$container->get('config'),
$container->get('locator.changed_files')
);
$commands[] = new Command\Git\PrePushCommand(
$container->get('config'),
$container->get('locator.changed_files')
Copy link
Contributor

Choose a reason for hiding this comment

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

Also here we'll need the files that are being pushed to the remote instead of the staged files.

Copy link
Author

Choose a reason for hiding this comment

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

for this one I have no idea what to do XD

Copy link
Contributor

Choose a reason for hiding this comment

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

You could make a new 'locator.pushed_files' locator?

$files = $this->getCommittedFiles($io);

$context = new TaskRunnerContext(
new GitPreCommitContext($files),
Copy link
Contributor

Choose a reason for hiding this comment

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

Here it's best to create a separate context.

@veewee
Copy link
Contributor

veewee commented Jan 10, 2017

@Mte90,

Thanks for looking into it!
You are right: It's working but codeception is executed also on commit, and I have no idea how to avoid that.

I think it should run on both pre-commit and pre-flush. If you want to disable one of those, you'll have to create custom testsuites in the grumphp.yml file so that the codecept does not run during pre-commit. I don't think there is an easier way to do this at the moment.

Note that there is also a vagrant git hook preset.
Feel free to ask additiontal questions. I will do my best to help you on the right track :)

@Mte90
Copy link
Author

Mte90 commented Jan 10, 2017

Ok so:

  • I need to find a commit to find the list of file before a push
  • I was thinking that the best way to execute a task only on an hook is to use commit_msg and put in that the task like in my example or add a new parameter in every task to specify when run the task
  • What is the custom testsuite syntax? maybe an example so I can try it

For the other feedback I will look it on next because actually is working and I don't know all the code of grumphp.

@veewee
Copy link
Contributor

veewee commented Jan 11, 2017

Not only one commit: all the files (in possibly multiple commits) that are being pushed.

A possibile solution is indeed to create a new metadata option like priority, which is available for every task. Depending on that new option, it will only run in one context.

About the testsuites: the documentation can be found here: https://github.com/phpro/grumphp/blob/master/doc/testsuites.md#overriding-git-hook-test-suites
By explicitly specifying the tasks that will run in a specific context, it is possible to only make it run during pre_commit or during pre_push.

@Mte90
Copy link
Author

Mte90 commented Jan 11, 2017

Ok so for the testsuits it's like in the example of my first comment so the idea is to have something like this:

parameters:
    git_dir: .
    bin_dir: vendor/bin
    ignore_unstaged_changes: false
    tasks: 
        codeception:
            config_file: ~
            fail_fast: false
            suite: ~
            test: ~
        grunt: ~
    testsuites:
        git_pre_commit:
            tasks:
                - grunt
        git_pre_push:
            tasks: 
                - codeception

In that way in tasks we define the task and in the hook specify when execute them.

@Mte90
Copy link
Author

Mte90 commented Jan 11, 2017

Uhm as I can see codeception it is not executed on pre-push the run method is not executed when is pre-push, but now there is also the new prepushcontext in all the tasks.

@Mte90
Copy link
Author

Mte90 commented Jan 11, 2017

Ok the problem is that the content don't have the files , I think that the problem is the other issue mentioned above

@Mte90
Copy link
Author

Mte90 commented Jan 11, 2017

Gitlib don't have a method to get the list of file waiting for a push, so I used git, the problem is how to get the context on ChangeFiles.php for locateFromGitRepository so in that way the code can executed only in that run.
Now grumphp it's working on push :-D

@veewee
Copy link
Contributor

veewee commented Jan 12, 2017

Hi @Mte90,
I'll try to make some time somewhere next week to review the code you've written.
Can you fix the CI tools in the meantime?

@Mte90
Copy link
Author

Mte90 commented Jan 12, 2017

I fixed few errors, but few of them are based of my no-complete code on ChangedFiles.php, because I not found the way to get the context in that method.

Copy link
Contributor

@veewee veewee left a comment

Choose a reason for hiding this comment

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

Hello @Mte90,

I've taken some time to review the changes and I must say: it is looking promising!
Can you also make sure that all the code you added has tested phpspec scenarios?
Currently the pre-push context is applied to a lot of tasks. This means that by default, GrumPHP runs all these tasks both on commit and on push.
In many occasions you want to commit and next push a commit. This means that the same code will be tested twice in a short amount of time. Is this something we would want to do?
Another possibility is to make this hook configurable so that it only runs in pre-push when it is configured to do so. Does that make sense to you?

GIT_CURRENT_BRANCH=$(git name-rev --name-only HEAD)

# Fetch the GIT diff and format it as command input:
DIFF=git diff --name-only origin/"$GIT_CURRENT_BRANCH"..HEAD --oneline
Copy link
Contributor

Choose a reason for hiding this comment

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

What if the remote branch does not exist yet?

Copy link
Author

Choose a reason for hiding this comment

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

good point, the problem that we need a point for to the difference.
probably it's better to find another command

Copy link
Author

@Mte90 Mte90 Jan 16, 2017

Choose a reason for hiding this comment

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

ok this one is blocking, after find a better way i will fix that, the vagrant one and also the code inside the changedfiles.php

Copy link
Author

Choose a reason for hiding this comment

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

ok with git rev-parse HEAD it's possible to get the latest commit in queue but I don't find a way to get the latest commit pushed.
The problem is that all the command require to have a remote reference so in any case that hook will not work without a first commit online.

@@ -0,0 +1,18 @@
#!/bin/sh

GIT_CURRENT_BRANCH=$(git name-rev --name-only HEAD)
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it's better to compare against a remote commit hash instead of a name?

# Run GrumPHP
(cd "./" && printf "%s\n" "${DIFF}" | exec 'vendor/phpro/grumphp/bin/grumphp' 'git:pre-push')

# Validate exit code of above command
Copy link
Contributor

Choose a reason for hiding this comment

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

The exit checks can be removed. The shell script will return the exit code of the last command executed.

Copy link
Author

Choose a reason for hiding this comment

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

so line 9?

Copy link
Contributor

Choose a reason for hiding this comment

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

The script can end with the grumphp command. There is no need for the $RC check.

@@ -0,0 +1,18 @@
#!/bin/sh
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you also add a hook for the vagrant preset?

Copy link
Author

Choose a reason for hiding this comment

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

I was thinking to committed the file but seems not, okay I will do asap.

Copy link
Author

Choose a reason for hiding this comment

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

done.

@@ -116,6 +116,10 @@ protected function getDefaultCommands()
$container->get('config'),
$container->get('locator.changed_files')
);
$commands[] = new Command\Git\PrePushCommand(
$container->get('config'),
$container->get('locator.changed_files')
Copy link
Contributor

Choose a reason for hiding this comment

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

You could make a new 'locator.pushed_files' locator?

/**
* @return FilesCollection
*/
protected function getCommittedFiles(ConsoleIO $io)
Copy link
Contributor

Choose a reason for hiding this comment

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

You could change the name to getPushedFiles()

@@ -41,8 +42,20 @@ public function __construct(Repository $repository, Filesystem $filesystem)
public function locateFromGitRepository()
Copy link
Contributor

Choose a reason for hiding this comment

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

Ad mentioned above, you should create a new pushed files locator

Copy link
Author

Choose a reason for hiding this comment

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

created.

@@ -41,8 +42,20 @@ public function __construct(Repository $repository, Filesystem $filesystem)
public function locateFromGitRepository()
{
$diff = $this->repository->getWorkingCopy()->getDiffStaged();
// if($context instanceof GitPrePushContext ) {
$actualbranch = trim(shell_exec('git name-rev --name-only HEAD'));
Copy link
Contributor

Choose a reason for hiding this comment

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

Try to avoid shell_exec. This is untestable code.
You can use the gitonomy library to run git commands through the ProcessBuilder:
\Gitonomy\Git\Repository::run()

@@ -41,8 +42,20 @@ public function __construct(Repository $repository, Filesystem $filesystem)
public function locateFromGitRepository()
{
$diff = $this->repository->getWorkingCopy()->getDiffStaged();
// if($context instanceof GitPrePushContext ) {
$actualbranch = trim(shell_exec('git name-rev --name-only HEAD'));
$diff = explode("\n", trim(shell_exec('git diff --name-only origin/' . $actualbranch . '..HEAD --oneline')));
Copy link
Contributor

Choose a reason for hiding this comment

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

As mentioned above: what if the remote branch does not exist? Maybe it's better to use a commit hash instead of the parsed branch name.

Copy link
Contributor

Choose a reason for hiding this comment

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

Does this code also skips deleted files?

use GrumPHP\Collection\FilesCollection;

/**
* Class GitPrePushontext
Copy link
Contributor

Choose a reason for hiding this comment

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

You can remove this type of class docblocks.

@veewee
Copy link
Contributor

veewee commented Jan 17, 2017

I've taken a look at the pre-push examples from git. It seems like you can access the committed files from STDIN:

#!/bin/sh

# An example hook script to verify what is about to be pushed.  Called by "git
# push" after it has checked the remote status, but before anything has been
# pushed.  If this script exits with a non-zero status nothing will be pushed.
#
# This hook is called with the following parameters:
#
# $1 -- Name of the remote to which the push is being done
# $2 -- URL to which the push is being done
#
# If pushing without using a named remote those arguments will be equal.
#
# Information about the commits which are being pushed is supplied as lines to
# the standard input in the form:
#
#   <local ref> <local sha1> <remote ref> <remote sha1>
#
# This sample shows how to prevent push of commits where the log message starts
# with "WIP" (work in progress).

remote="$1"
url="$2"

z40=0000000000000000000000000000000000000000

while read local_ref local_sha remote_ref remote_sha
do
	if [ "$local_sha" = $z40 ]
	then
		# Handle delete
		:
	else
		if [ "$remote_sha" = $z40 ]
		then
			# New branch, examine all commits
			range="$local_sha"
		else
			# Update to existing branch, examine new commits
			range="$remote_sha..$local_sha"
		fi

		# Check for WIP commit
		commit=`git rev-list -n 1 --grep '^WIP' "$range"`
		if [ -n "$commit" ]
		then
			echo >&2 "Found WIP commit in $local_ref, not pushing"
			exit 1
		fi
	fi
done

exit 0

So there are 2 things we can do:

  • find out how git sends these to STDIN during a push and use those commands in the locator.
  • use this STDIN to parse the diff and send it to the grumphp STDIN. If we do this one, we don't have to add an additional locator in the codebase, but we won't be able to run the git:pre-push command manually without the diff as STDIN.

@Mte90
Copy link
Author

Mte90 commented Jan 17, 2017

In any case that script use a remote for a comparison so we need to accept that is not possible to do a check without a remote. I didn't find a way to detect if the remote is empty or exist.

@veewee
Copy link
Contributor

veewee commented Jan 17, 2017

As you can see in the script, it can handle new remotes and deleted branches.
We surely need to pass the remote and url to the script so that we can handle other remote names then origin etc.
It is possible to show the tip of remote branches, but it is rather slow: git ls-remote [REMOTENAMEORURL]
I am also not sure what happens if the remote is ahead of the local branch.

@Mte90
Copy link
Author

Mte90 commented Jan 17, 2017

If remote is ahead it's not possible to do the push because there are difference between repos so the developer need to fix them before to push so for me it's not an our problem.
With origin\<branch name> we have an alias to the remote one so it's not a problem to find the remote and do a diff.
So we accept that is not possible to do it without a remote we can use the actual code of this pr else we need to improve the code and check if a remote exist if not get a list of all the file in the commits (that is not difficult). So in any case we can execute the hook and grumphp without any troubles.

@veewee
Copy link
Contributor

veewee commented Jan 17, 2017

I know it's not possible to push if the remote is ahead, but I was wondering if the pre-push hook will be executed before that check.
Not all remotes are named origin + it might be possible that you are pusing to another remote like e.g. upstream.
Also: the local branch name can be different from the local branch name.

So at this point, these are the questions that should be solved at the end of the PR:

  • What happens if no remote exists?
  • What happens if the remote is not named origin?
  • What happens if the remote branch has a different name?
  • What happens if the remote is not named at all (url mode)
  • What happens if the remote does not exist?
  • What happens if the remote is ahead? (Will the hook be executed)
  • Is it possible to run the grumphp command manually?
  • Is it possible to run the grumphp command with a diff of all the commited files in STDIN?
  • ...

Feel free to add additional questions to the list.
I'm sure we'll come to a good solution, but we'll need it to be bullet-proof :)

@Mte90
Copy link
Author

Mte90 commented Jan 17, 2017

All interesting question and I think that the easiest approach probably will be:

  • detect from the command itself of the push git push origin master that can help for the 1, 2, 3 and 5 points
  • for 4 and 7 need investigation
  • for 6 I already use the command for testing and actually work

So I will start work on how to get in the hook, the remote of the push with the branch in that way we can do our checks and see for the next points.

@veewee
Copy link
Contributor

veewee commented Jan 17, 2017

+1

@Mte90
Copy link
Author

Mte90 commented Jan 17, 2017

Ok I find it a way for git in the hook to get the remote and branch and do a check with that.
The new hook code execute next grumphp with the files changed.
If the branch not exist locally the hook is not executed and I have to check if the branch exist locally and not remotely what happen.

Now the problem is the grumphp pre-push command, without specify what is the remote and the branch I think we can use the origin/master. Actually the php code miss the part to check if the user added that parameter (origin master) in the command.
An user can have different branch not pushed so the easiest way is to ask to the user to specify if run the command directly without use the git hook.

done

# Clean exit:
exit 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

You will want to return the Grumphp exit code. 0 = always push

Copy link
Author

Choose a reason for hiding this comment

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

right

DIFF=$(git diff --name-only "$remote"/"$local_ref"..HEAD --oneline)

# Run GrumPHP
(cd "./" && printf "%s\n" "${DIFF}" | exec 'vendor/phpro/grumphp/bin/grumphp' 'git:pre-push')
Copy link
Contributor

Choose a reason for hiding this comment

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

This will run grumphp multiple times on multiple commits in a push.
You want to create ONE diff from ALL the changed commits and run grumphp only once with this diff.
You could also pass the parameters that you receive in this hook as parameters to the cli.
This way it is possible to add them to the context and use them in the tests. For example: You can create a task that does not allow you to push upstream.

Copy link
Author

Choose a reason for hiding this comment

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

the diff contain all the files for the push so is not executed multiple times

Copy link
Contributor

@veewee veewee Jan 18, 2017

Choose a reason for hiding this comment

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

This line is inside a while which is executed for every line in the STDIN.
More info:

The pre-push hook runs during git push, after the remote refs have been updated but before any objects have been transferred. It receives the name and location of the remote as parameters, and a list of to-be-updated refs through stdin. You can use it to validate a set of ref updates before a push occurs (a non-zero exit code will abort the push).

while read local_ref local_sha remote_ref remote_sha

Every input line is a commit which is pushed to the remote. So when there are many commits in one push, the grumphp executable is executed multiple times.

Copy link
Author

Choose a reason for hiding this comment

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

you are right -.-', I will fix it :-)

*/
public function locateFromGitPushedRepository()
{
$diff = explode("\n", \Gitonomy\Git\Repository::run('diff origin/master..HEAD --name-only --oneline'));
Copy link
Contributor

Choose a reason for hiding this comment

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

Mostly you aren't pushing to master. Most of my repositories dont even have a remote named origin :)
As you mentioned: this is something we can ask to the user. But maybe it's better to detect the defaults in the command?

Copy link
Author

Choose a reason for hiding this comment

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

yep this code require improvements :-)

Copy link
Author

Choose a reason for hiding this comment

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

there is a way to get the parameters in the cli?
because I was thinking that when someone do grumphp pre-push we need the other two parameter, the remote and the branch.

Copy link
Author

Choose a reason for hiding this comment

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

any suggestions for that?

Copy link
Contributor

Choose a reason for hiding this comment

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

I've found following page with some handy commands:
http://stackoverflow.com/questions/171550/find-out-which-remote-branch-a-local-branch-is-tracking

If your branch is tracking a remote, you can use following commands:

LOCAL_BRANCH=`git name-rev --name-only HEAD`
TRACKING_BRANCH=`git config branch.$LOCAL_BRANCH.merge`
TRACKING_REMOTE=`git config branch.$LOCAL_BRANCH.remote`
REMOTE_URL=`git config remote.$TRACKING_REMOTE.url`

If your branch is not tracking a remote, it is not possible to detect remote info.
In the git hook, you get these as parameters from git.

So a possible solution would be: if the branch is not tracking and you don't get the info from the git hook, the user gets an exception telling them to manually add the parameters to the grumphp command.

Copy link
Author

Choose a reason for hiding this comment

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

for us is not enough because we need to know what is the remote branch, a repo can have different remote so I think that we needto ask to them only if use grumphp pre-push because on hook we already know that info.

Copy link
Contributor

Choose a reason for hiding this comment

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

If there is one registered remote, we might just use that one? On multiple, we won't know the remote. This PR is getting a bit complex :)

Copy link
Contributor

Choose a reason for hiding this comment

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

If there is one registered remote, we might just use that one? On multiple, we won't know the remote. This PR is getting a bit complex :)

Copy link
Author

Choose a reason for hiding this comment

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

ok, when someone execute the command I will autodetect :-)

@veewee
Copy link
Contributor

veewee commented Feb 7, 2017

We've moved from PSR-0 to PSR-4. Can you rebase your changes against current master?
Is there something else you would like to know to get this issue going?

@Mte90
Copy link
Author

Mte90 commented Feb 7, 2017

I can move to psr-4 but I have no idea how to check if the code where needs checks.
The only things that is missing right now is #258 (comment) to complete the pr.

@Mte90
Copy link
Author

Mte90 commented Feb 9, 2017

The pr is complete, remain only tests (that I have already done for the hook and for the git:pre-push command).
And finally fix to PSR-4.

@Mte90
Copy link
Author

Mte90 commented Feb 22, 2017

any suggestions for psr-4? there is a tool for that?

@veewee
Copy link
Contributor

veewee commented Feb 24, 2017

Hi @Mte90, Sorry for the late response...
You can just use git rebase. However, since you changed a lot of tasks, you might get a lot of conflicts.

@Mte90
Copy link
Author

Mte90 commented Feb 24, 2017

rebase done without errors on git :-)

done

# Fetch the GIT diff and format it as command input:
DIFF=$(git diff --name-only "$remote"/"$local_ref"..HEAD --oneline)
Copy link
Contributor

Choose a reason for hiding this comment

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

I have not looked at the full PR and comments, but I have some experience with pre-push commands and I have a few suggestions.

I think it will be better to pass the 4 variables local_ref, local_sha, remote_ref and remote_sha to PHP instead of doing a diff and passing this data. Let's handle the logic on the PHP side. Passing the diff makes it impossible to retrieve basic information about the current state of the branch on the PHP end which is possibly needed for certain tasks to run on pre-push. Some examples:

  • If local_ref contains the string (delete) we are currently deleting the current branch. This will mean there is still a diff but we don't need to do any coding standards checks because the branch is being deleted.
  • If local_sha contains the SHA 0000000000000000000000000000000000000000 then we do not have a local branch, meaning we are in a detached HEAD state.
  • If remote_sha is 0000000000000000000000000000000000000000 then this is a brand new branch. There will not be a diff. We can use this information to perform a full coding standards check.

Also, this git diff command is not bullet proof, it assumes that the developer is pushing their currently checked out branch, but this is not necessarily the case. For example, if you have switched to a new branch and realized you have not yet pushed your previous branch, you can do this command:

$ git push my-previous-branch:my-previous-branch

In this case the diff will be made between the HEAD of the current branch and the remote of the previous branch, this has not the intended result. A better version would be:

$ git diff-tree --no-commit-id --name-only -r '$local_sha' '$remote_sha'

Copy link
Author

Choose a reason for hiding this comment

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

Grumphp internally base everything on the git diff that parse to find all the files involved in the commit/push so I dont' think that actually is the best choice.
My hope is to have that pr integrated and start to work on this edge-cases that during my development doesn't happened.

Copy link
Contributor

@pfrenssen pfrenssen Mar 31, 2017

Choose a reason for hiding this comment

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

I believe up to now Grumphp works on pre-commit only? In that case the diff is fine, since you won't be deleting branches, and the status of the local and remote branches are not important.

But when you do a pre-push then this becomes important and acting solely on a diff is not going to be enough.

Copy link
Author

Choose a reason for hiding this comment

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

ok so how suggest to change the script for the hook? The output is the same like actually?

Copy link
Contributor

Choose a reason for hiding this comment

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

We need the information about the remote and local branches and this needs to be passed to the tasks as well, so I would suggest to:

  • Instead of piping the list of files into the command, pass in the 4 parameters to the GitPrePushCommand as options.
  • Store the 4 parameters in the GitPrePushContext and provide getters for them so that this information is available to tasks: getLocalSHA1(), getLocalRef(), getRemoteSHA1(), getRemoteSHA1().
  • Inside GitPrePushContext::execute() there are 3 different possibilities for generating the file list:
    1. If the remote_sha1 is empty (it equals 0000000000000000000000000000000000000000) then this means we are pushing a brand new branch. We have no comparison point since we don't know which of the ancestor commits have already been checked. In this case we need to check all files.
    2. If the local_sha1 is empty or if local_ref matches the string (delete) then this means that the push is intended to delete the remote branch. In this case we should not populate the file list at all, since it is pointless to do any checks on a branch that is about to be deleted.
    3. When both local_sha1 and remote_sha1 are not empty, and local_ref does not match (delete) we are doing a push that updates an already existing remote branch with new code. In this case we can generate a list of files that have changed between the local_sha1 and remote_sha1 and can pass it to the context.

To generate the diffs on the PHP side, you can inject the Repository dependency into the PrePushCommand and then get the file list by calling $this->repository->run('diff-tree', ['--no-commit-id, ...]).

It would also be nice to have some helper methods on the context such as isNewBranch(), hasRemoteBranch(), isDeletingRemote().

Copy link
Author

Choose a reason for hiding this comment

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

Uhm means a rewrite of the local pr and I have no time for it, but I am open for a pr on mine to speed the integration of this feature.

Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe it's a better idea to create a new issue in which we can discuss what the pre-push should look like before we implement it. That way we can try to create a good architecture that fits every use-case before implementing 15 different versions?
This PR contains a lot of great findings and was good to determine the scope of the pre-push, but has become a bit messy due to the new issues we've detected during the development of this feature.
What do you think about this idea?

Copy link
Author

Choose a reason for hiding this comment

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

Maybe create a new branch of grumphp where work on this feature can be an idea with a roadmap, starting from a refactoring of this pr.

@Mte90
Copy link
Author

Mte90 commented Jun 21, 2017

Any chance for this feature?

@veewee
Copy link
Contributor

veewee commented Jun 22, 2017

Hi @Mte90,

As mentioned above: there are some edge cases which need to be covered first. Some parts of this PR need a rewrite as well. So in the current state, I am afraid I can't merge this one in.

@Mte90
Copy link
Author

Mte90 commented Aug 24, 2017

Very sad for it but I understand the problem but it is possible to give it more priority on this?

@pfrenssen
Copy link
Contributor

If you need this urgently and have the time for it you can have a look at implementing the missing functionality that I outlined in my analysis that I posted above in my comment from April 3.

@Mte90
Copy link
Author

Mte90 commented Jan 24, 2018

Unlucky I have no time anymore to work on this feature but I need it a lot.
Actually I am using a bash script that execute what I need manually.

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

Successfully merging this pull request may close these issues.

4 participants