Woodrow Barlow Woodrow Barlow - 7 days ago 5
Git Question

automated push to a github repo with travis

I have a gitub.io repo which hosts my webpage -- the source for that webpage (uncompiled Jade / Sass code) is in a separate public repo. Travis-CI is set up to watch my source repo for changes and run the compile suite, generating the HTML/CSS that will get pushed to the github.io repo.

Can I set up Travis to automatically do a push to a github repo I own if the compile passed, without hard-coding my username and password into my

.travis.yml
file (obviously this is a security concern)?

I've seen this question, but it wasn't answered with Travis in mind -- I don't think I can use keypair authentication because I'd need to put the private key in the repo or in the travis script, which is just as big a security hole as putting in my password.




For anyone else who winds up here, I found the following information using roidrage's answer as a springboard:


  1. Travis uses public/private key encryption to allow you to embed sensitive information in a
    .travis.yml
    file. You can install their gem called "travis" and use it to encrypt stuff, and they'll decrypt it securely on their end. Documentation: http://docs.travis-ci.com/user/encryption-keys/

  2. On github, you can generate a "personal access token" in your applications settings. This can be used like a password by applications. Encrypt that using the above technique and throw it in your yaml.


Answer

This can be achieved by storing a token to access GitHub in an encrypted way in the .travis.yml file. See our docs for examples on how to encrypt data.

As for the push to GitHub Pages, there's a blog post summing up the steps quite well, and it even points to a script that you can use in your build.

A mirror of the script is here:

#!/usr/bin/env bash

# This script was written to facilitate the deployment process of Pelican
# websites using Travis CI. See this blog post for more information:
# http://kevinyap.ca/2014/06/deploying-pelican-sites-using-travis-ci/

usage="Usage: $(basename "$0") (deploy | diff | serve)

Commands:
  deploy     Upload site to Github Pages
  diff       Compare locally generated site to live site
  serve      Generate and serve site (auto-reloads on changes)"

TARGET_REPO="iKevinY/iKevinY.github.io"
GH_PAGES_BRANCH="master"

DEVELOP_CONF="pelicanconf.py"
PUBLISH_CONF="publishconf.py"

OUTPUT_DIR="output"
REMOTE_DIR="remote"

PY_CMD="python3"
SERVER="http.server"
PORT="8000"

rootPath="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"

generate_site() {
  # Based on http://zonca.github.io/2013/09/automatically-build-pelican-and-publish-to-github-pages.html
  if [ "$TRAVIS" == "true" ]; then
    # Ensure that builds triggered by pull requests are not deployed
    if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
      echo "Successfully built pull request #$TRAVIS_PULL_REQUEST."
      exit 0
    fi

    echo "Deploying site to $GH_PAGES_BRANCH branch of $TARGET_REPO."
    git config --global user.email "travis@travis-ci.org"
    git config --global user.name "Travis CI"
  else
    cd "$rootPath" || exit 1
    pelican -s $PUBLISH_CONF
  fi

  # Pull hash and commit message of the most recent commit
  commitHash=$(git rev-parse HEAD)
  commitMessage=$(git log -1 --pretty=%B)

  # Clone the GitHub Pages branch and rsync it with the newly generated files
  GITHUB_REPO=https://${GH_TOKEN:-git}@github.com/${TARGET_REPO}.git
  git clone --branch $GH_PAGES_BRANCH --depth 1 "$GITHUB_REPO" $REMOTE_DIR &> /dev/null
  rsync -r --exclude=.git --delete $OUTPUT_DIR/ $REMOTE_DIR/
  pushd $REMOTE_DIR > /dev/null

  git add -A
  git status -s

  $1  # execute the function that was passed as an argument
}

push_changes() {
  if [ "$TRAVIS" == "true" ]; then
    longMessage="Generated by $commitHash; pushed by build #$TRAVIS_BUILD_NUMBER."
    git commit -m "$commitMessage" -m "$longMessage"
    git push origin $GH_PAGES_BRANCH &> /dev/null || echo "Push failed."
  else
    read -rp "Push changes to GitHub Pages? [y/N] " response
    if [[ "$response" =~ ^[Yy]$ ]]; then
      git commit -m "$commitMessage" -m "Generated by $commitHash."
      git push origin $GH_PAGES_BRANCH
    fi

    popd > /dev/null
    rm -rf -- $REMOTE_DIR $OUTPUT_DIR && echo "Removed $REMOTE_DIR and $OUTPUT_DIR."
  fi
}

case "$1" in
  'deploy')
    generate_site push_changes
    ;;

  'diff')
    generate_site 'git --no-pager diff --cached --color-words'
    ;;

  'serve')
    developPath=${rootPath}/develop
    local_ip=$(ifconfig | grep 'inet ' | awk 'NR==2 {print $2}')

    # Seed directory with site content
    cd "$rootPath" && pelican -s $DEVELOP_CONF > /dev/null
    echo "Serving HTTP at $(tput bold)${local_ip}:${PORT}$(tput sgr0)."

    cleanup() {
      pkill -f $SERVER
      cd "$rootPath" && rm -r "$developPath" && echo && exit 0
    }

    trap cleanup SIGINT

    (pelican -rs $DEVELOP_CONF 2> /dev/null) &
    (cd "$developPath" || exit 1; $PY_CMD -m $SERVER $PORT 1> /dev/null) &
    wait
    ;;

  *)
    echo "$usage"
    exit 2
    ;;

esac