自从发现了Github Pages和Jekyll这个东西以后,终于发现最适合自己的Blog写作方式了。但是Github Pages的jekyll运行于Safe模式,直接将jekyll工程到gh-pages分支并利用github pages自动生成静态网页存在一定的缺陷,比如自定义的Plugins无法使用等,这就有些不爽了。虽然网上有很多介绍的方法是采用本地jekyll生成静态页面并push到gh-pages上进行,但这并不“科学”!我们要的是自动化的处理。还好,有Travis CI的存在。

Travis CI我就不再仔细介绍了,可以访问相关网站 https://travis-ci.org

那么怎么利用travis ci自动构建上传后的jekyll blog呢。主要配置步骤如下:

申请具有写权限的Github token

Travis CI与github账号关联之后,会申请一个token,但是这个token不具备Github代码仓库的写权限,因此,需要申请一个新的token,申请新的Github token的方法如下图所示:

申请github token的方法

申请完该token之后,请记录该token的值,应该是一串hash序列字符串。

安装travis并生成供travis环境变量使用的travis秘钥

安装travis环境

1
gem install travis

生成秘钥

1
travis encrypt 'GIT_NAME="YOUR_USERNAME" GIT_EMAIL="YOUR_EMAIL" GH_TOKEN=$上一步生成的token'

生成的秘钥是一大串字符串,这个字符串会在下面的配置文件中使用。

编写Travis CI自动构建使用的配置文件

Travis CI的配置文件为.travis.yml,将其内容修改为:

1
2
3
4
5
6
7
language: ruby
install:
- bundle install
script: bundle exec rake deploy --quiet
env:
  global:
    secure: "$上一步生成的token"

添加Rakefile文件

本文中的Travis CI的构建文件采用的是rake方法,因此需要在工程根目录中增加一个rakefile文件,其内容参考如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#############################################################################
#
# Modified version of jekyllrb Rakefile
# https://github.com/jekyll/jekyll/blob/master/Rakefile
#
#############################################################################

require 'rake'
require 'date'
require 'yaml'

CONFIG = YAML.load(File.read('_config.yml'))
USERNAME = CONFIG["username"] || ENV['GIT_NAME']
REPO = CONFIG["repo"] || "#{USERNAME}.github.io"

# Determine source and destination branch
# User or organization: source -> master
# Project: master -> gh-pages
# Name of source branch for user/organization defaults to "source"
if REPO == "#{USERNAME}.github.io"
  SOURCE_BRANCH = CONFIG['branch'] || "source"
  DESTINATION_BRANCH = "master"
else
  SOURCE_BRANCH = "master"
  DESTINATION_BRANCH = "gh-pages"
end

def check_destination
  unless Dir.exist? CONFIG["destination"]
    sh "git clone https://#{ENV['GIT_NAME']}:#{ENV['GH_TOKEN']}@github.com/#{USERNAME}/#{REPO}.git #{CONFIG["destination"]}"
  end
end

task :deploy do
    # Detect pull request
    if ENV['TRAVIS_PULL_REQUEST'].to_s.to_i > 0
      puts 'Pull request detected. Not proceeding with deploy.'
      exit
    end

    # Configure git if this is run in Travis CI
    if ENV["TRAVIS"]
      sh "git config --global user.name '#{ENV['GIT_NAME']}'"
      sh "git config --global user.email '#{ENV['GIT_EMAIL']}'"
      sh "git config --global push.default simple"
    end

    # Make sure destination folder exists as git repo
    check_destination

    sh "git checkout #{SOURCE_BRANCH}"
    # Generate the site
    #sh "bundle exec jekyll build"
    
    puts CONFIG["destination"]

    Dir.chdir(CONFIG["destination"]) { sh "git checkout #{DESTINATION_BRANCH}" }

    sh "bundle exec jekyll build"

    # Commit and push to github
    sha = `git log`.match(/[a-z0-9]{40}/)[0]
    Dir.chdir(CONFIG["destination"]) do
      sh "git add --all ."
      sh "git commit -m 'Updating to #{USERNAME}/#{REPO}@#{sha}.'"
      sh "git push --quiet origin #{DESTINATION_BRANCH}"
      puts "Pushed updated branch #{DESTINATION_BRANCH} to GitHub Pages"
    end
end

修改_config.yml文件

上面的Rakefile的构建工作中,将master分支和gh-pages分支分别放在了不同的目录中,以保证上传时不影响master分支,为了保证该机制的实施需要修改jekyll的_config.yml文件。修改后的_config.yml文件务必包含以下内容:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
exclude:
  - README.md
  - Rakefile
  - Gemfile
  - Gemfile.lock
  - changelog.md
  - "*.Rmd"
  - vendor
  - .travis.yml
destination: ../build_site/

增加一个Gemfile

最后的最后,在jekyll工程根目录增加一个gemfile,用于Travis CI构建依赖环境的使用。Gemfile的内容如下:

1
2
3
4
source "http://production.cf.rubygems.org/"

gem "rake", "~> 10.1.1"
gem "github-pages", "~> 28"

至此,好好的享受Travis CI带来的自动构建服务吧~~

参考资料

  1. https://github.com/mfenner/jekyll-travis