statamic / spock

Automatically perform git commits, pushes, and other cli actions when Statamic content changes
95 stars 16 forks source link

Spock + Laravel Forge #50

Closed rcknr closed 4 years ago

rcknr commented 4 years ago

Hi! I have a setup with Statamic, Spock and Laravel Forge and quite often get the following failure when quick deploy runs:

error: cannot lock ref 'refs/remotes/origin/master': is at \ but expected \ From gitlab.com:organizayion/reposotory ! \..\ master -> origin/master (unable to update local ref)

I have the following deployment script:

git fetch

LOCAL=$(git rev-parse @)
REMOTE=$(git rev-parse @{u})

[ $LOCAL = $REMOTE ] && exit 0

git pull origin master
# composer update, php-fpm restart, etc

After getting this deployment failure notification and checking the server the repository is at the latest commit and there are no other problems. I would really appreciate if someone could help me out finding where the problem is and how can I address it. Thanks!

jasonvarga commented 4 years ago

This is more of a Git issue than a Spock one.

I don't know the answer, but I just Googled your error and came across this https://stackoverflow.com/questions/11796580/git-pull-error-error-remote-ref-is-at-but-expected

Perhaps someone on your team has force pushed and rewrote the history? You can try the solutions on that thread.

rcknr commented 4 years ago

Well, I've researched it too before posting here. That article doesn't apply in this case. I believe this happens as a side-effect of what Spock does.

jasonvarga commented 4 years ago

If you run those commands on your server manually, do you get the same error?

jesseleite commented 4 years ago

That error you pasted is in your Forge deployment log, correct?

I believe this happens as a side-effect of what Spock does.

Curious what you mean by that? Spock itself is really pretty simple in that it runs a git add, git commit, and git push (when push is enabled), as if you had manually SSH'd into production and ran those commands yourself.

It's fairly common to see conflict/divergence issues when committing and pushing from multiple places (ie. your dev environements, your production server, etc). However, given that cannot lock ref 'refs/remotes/origin/master' error, I'm not sure that's the case here.

When googling, I came across this one: https://github.com/desktop/desktop/issues/5438. Maybe one of the upvoted solutions in that thread are worth looking into?

rcknr commented 4 years ago

If you run those commands on your server manually, do you get the same error?

No, that's the thing. When I check the server the repository is up to date and I never get the same error by executing fetch manually. Thanks for the link! There's no concrete problem pointed out there but I had a look at my git config file and found some minor discrepancies there. I'll test if adjusting the config helps. I've looked into Spock code as well to try to narrow down the problem but I haven't come up with a conclusion for this particular issue yet. What I noticed, by the way, was that sometimes there are no files added to a commit and upon executing the commit command you get an error exit code which is logged. I was wondering if it was a good idea to check staged files before running the commit command (i.e. git diff-index --quiet HEAD || git commit). I believe this was mentioned here too but closed prematurely (#49). Also worth mentioning that I'm running a queue on the server which Spock also uses. Might it have an effect to the way how multiple commands are executed?

jesseleite commented 4 years ago

What I noticed, by the way, was that sometimes there are no files added to a commit and upon executing the commit command you get an error exit code which is logged.

For the record, Git integration in v3 (the replacement to Spock for v3) doesn't do this. It will only commit if git status has changes to commit 👍

Also worth mentioning that I'm running a queue on the server which Spock also uses. Might it have an effect to the way how multiple commands are executed?

That's very possible. Does this error happen every time Spock commits and Forge tries to quick deploy?

rcknr commented 4 years ago

For the record, Git integration in v3 (the replacement to Spock for v3) doesn't do this. It will only commit if git status has changes to commit 👍

That's great! How about v2 though? Does it make sense to execute git commit and git push if there are no files in affectedPaths in a given event.

One workaround I came up with specific for Forge and Spock is to check $FORGE_DEPLOY_AUTHOR variable in the deploy script and exiting if its equal to "Spock" (default setting).

jesseleite commented 4 years ago

That's great! How about v2 though? Does it make sense to execute git commit and git push if there are no files in affectedPaths in a given event.

Nope, that's why we don't commit in those cases on v3 🙂. We're pretty head down on v3 at the moment, but would consider a PR to Spock for v2 for this.

Also didn't know about $FORGE_DEPLOY_AUTHOR, neat!

rcknr commented 4 years ago

Also didn't know about $FORGE_DEPLOY_AUTHOR, neat!

I think it was added pretty recently as I have just learned about it myself. There are some more useful details in the docs: https://forge.laravel.com/docs/1.0/sites/deployments.html

I went ahead and created a pull request to address the empty commit issue.

rcknr commented 3 years ago

I'd like to add a few things in case someone is having similar issue. With Forge to cancel deployments initiated by Spock commits I use commit author data provided by Forge:

[[ "$FORGE_DEPLOY_AUTHOR" == "Spock" ]] && echo "Commit by $FORGE_DEPLOY_AUTHOR" && exit 0

So if commit author is "Spock" (which is the default setting) exit the script with status 0 which won't produce a failed deployment notification. If there are multiple commits done by Spock they may come to quickly and Forge will be still running a deployment for a previous commit. In this case, Forge will perform a re-deployment which is distinguishable by the value of FORGE_REDEPLOY and FORGE_MANUAL_DEPLOY set to 1. In this case FORGE_DEPLOY_AUTHOR and FORGE_DEPLOY_MESSAGE variables will be empty (a bug of Forge) and you have to fill them in manually:

if [ -z "$FORGE_DEPLOY_AUTHOR" ]; then
    FORGE_DEPLOY_AUTHOR=$(git show -s --format='%an' "$FORGE_DEPLOY_COMMIT")
fi

if [ -z "$FORGE_DEPLOY_MESSAGE" ]; then
    FORGE_DEPLOY_MESSAGE=$(git show -s --format='%s' "$FORGE_DEPLOY_COMMIT")
fi

In the deployment script, this has to be done before you check the value of FORGE_DEPLOY_AUTHOR.

With these two additions to my deployment script I'm not able to cancel out deployment for Spock commits without triggering failed deployment notifications.