3

I currently have continuous deployment set up with a Travis CI job. All pushes are sent to the staging server and merges to the master to the production server. The problem is that the deployment to the production server is done before the merge is accepted. The continuous integration tests have to all pass, but the deployment occurs before manual code review is done.

The question is, what is a lightweight method to ensure that a deployment to the production server only takes place after the merge request has been accepted?

As a reference, the following code is used for deployment:

#!/bin/bash

# exit with nonzero exit code if anything fails
set -e

# Add the SSH login key
chmod 600 veleda-deploy-key
mv veleda-deploy-key ~/.ssh/id_rsa

# Register the Veleda staging and production server SSH keys
echo '|1|BqdQKtUnA/AtCT/p2M7wgMq3wlY=|lH39cRtAE64wd6EG3ry2J9ewXic= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBH3antqwy3D4NVVfHQX3SQc/g4wl/SAVC9w9QEry7hhQmB0SJIprwNAq8Hy2DzVCS7kTj/q7fCiiL7oAznrax+0=' >> $HOME/.ssh/known_hosts
echo '|1|+Z7oOsZ+zdL6u8o8VSWp+bRzd2g=|XMw2HyJIHoekOYlJYw1n75plL2E= ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCJ/fa/mr577/qCuRXqUNccfmhpUtmi46LSyE7nDbOgxv8kZFs7yQ/sh6TM5npR+ZIbe9I0qmdvA+cE1QfvN21E=' >> $HOME/.ssh/known_hosts

# Select the remote to push to depending on the branch
if [ $TRAVIS_BRANCH != 'production' ] ; then
    echo "Pushing to staging"
    export REMOTE=staging.veleda.io
else
    echo "Pushing to production"
    export REMOTE=veleda.io
fi

# Push to the remote server
git remote add deploy "deploy@$REMOTE:/home/deploy/repo/"
git push -f deploy $TRAVIS_BRANCH

# Unpack and update the Docker services
ssh -t deploy@"$REMOTE" "\
    mkdir -p veleda &&
    git --work-tree=./veleda --git-dir=./repo checkout -f $TRAVIS_BRANCH &&
    cd veleda &&
    ./start.sh"
  • 2
    IMHO the code review (and all other steps requiring human intervention) should be plugged into the pipeline somewhere before the commit to master stage to reduce head-of-the-line blocking for the rest of the team. – Dan Cornilescu Mar 15 '18 at 22:43
  • Do you mean like feature branches? The review process happens during the pull request – Moritz Mar 15 '18 at 22:52
  • I don't favour feature branches myself, but yes, at pull request - which I suppose shouldn't proceed with the commit until the review is approved, right? – Dan Cornilescu Mar 15 '18 at 22:57
  • Let me verify that again – Moritz Mar 15 '18 at 23:05
  • Moritz how about making your comment (on the answer) into a self-answer? For posterity? – Bookeater Mar 19 '18 at 11:34
3

One could use conditional builds https://docs.travis-ci.com/user/conditional-builds-stages-jobs/

If code is merged into master one could decide to deploy code to production, but I personally prefer a human intervention by a Product Owner.

jobs:
  include:
      if: branch = master

or

stages:
  - name: deploy
    # require the branch name to be master
    if: branch = master

At other projects I preferred to deploy only tags to enforce the git flow (tags should be created otherwise no deployment to production).

stages:
  - name: deploy
    # require the tag name to match a regular expression
    if: tag =~ ^v1

One could also try (I did not try it yet) whether the if works in combination with script sections:

https://github.com/030/ansible-firefox/blob/master/.travis.yml

Last remark: I would avoid creating such scripts (the ones you included in the question) as most CI tools contain condition checks.

  • In my case I decided to add another long-lived branch, production, and only after creating a merge request to that branch is it deployed to the production server. This means that changes can be reviewed on the feature branches without pushing to production. This was the case when the master branch was equivalent to the version on the production server. – Moritz Mar 18 '18 at 14:30
  • If you use this method you need to use add a type clause to the condition if you don't want random pull requests to master to cause a deploy. E.g. if: branch = master AND type = push – Ryan Crichton Jul 17 '18 at 11:58
1

The updated deploy script in the question supports the following workflow (and requires this server setup):

  1. Create a feature branch and push commits to it
  2. Each push deploys the code to the staging server
  3. Review the code with merge request (feature branch --> master)
  4. After merging to master, create a new merge request (master --> production)

Due to Github merge request errata, I rebase when merging to master but normal merges when merging to production. The reason behind this is that Github creates new commits (different SHA1) when rebasing.

The rebase and merge behavior on GitHub deviates slightly from git rebase. Rebase and merge on GitHub will always update the committer information and create new commit SHAs, whereas git rebase outside of GitHub does not change the committer information when the rebase happens on top of an ancestor commit.

The main difference with this workflow to 030's answer is that a production branch is used instead of tags.

For bonus points use staging SSL certificates from Let's Encrypt on your staging server. To enable it while using a reverse proxy in Docker, set LETSENCRYPT_TEST=true

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.