Rake it Up (How I Manage My Jekyll Site)

A few years ago I ported this site to Jekyll. It honestly hasn’t changed much since then, but I have been through various interactions of deployment methods. For a little over a year I have used Rake to manage creating new posts and deploying the site. It use to be way more complicated with tasks defined to create drafts and move them to a published state. But I have found it much more productive to keep it as simple as possible and leave my drafted posts elsewhere.

In theory I could use any build tool for this because Rake is just doing executing the Jekyll commands from as any tool would from the command line. As appose to using Jekyll’s API. But at the time it seemed like a good fit. Here is the current status:

_config.yml


#
# == Configuration relevant to deployment
post:
  template: _post.txt
  extension: md
editor: 'mvim -v'
git:
  branch: master
transfer:
  command: rsync
  settings: -avp --delete
  source: _site/
  destination: "[email protected]/www/dir"

Rakefile


#
# == Dependencies
#

require 'rake'
require 'yaml'
require 'fileutils'
require 'rbconfig'

#
# == Configuration
#

# Set "rake watch" as default task
task :default => :watch

#Tag date YYYY-MM-DD HH:MM:SS +/-TTTT
TAG_DATE = Time.now.strftime("%Y-%m-%d-%H-%M")
# Load the configuration file
CONFIG = YAML.load_file("_config.yml")
# Get and parse the date
DATE = Time.now.strftime("%Y-%m-%d")
# Current time
CURRENT_TIME= Time.now.strftime("%Y-%m-%d %H:%M:%S")

#
# == Helper functions
#

# Add title case method to String.
class String
  def titlecase
    downcase.split.map {|w| capitalization_exceptions.include?(w) ? w : w.capitalize}.join(" ").upfirst
  end

  def upfirst
    self[0,1].capitalize + self[1,length-1]
  end

  private
    def capitalization_exceptions
      [
        'of','a','the','and','an','or','nor','but','if','then','else','when','up','at','from','by','on',
        'off','for','in','out','over','to'
      ]
    end
end

# Execute a system command
def execute(command)
  system "#{command}"
end

# Chech the title
def check_title(title)
  if title.nil? or title.empty?
    raise "Please add a title to your file."
  end
end

# Transform the filename and date to a slug
def transform_to_slug(title, extension)
  characters = /("|'|!|\?|:|\s\z)/
  whitespace = /\s/
  "#{title.gsub(characters,"").gsub(whitespace,"-").downcase}.#{extension}"
end


# Save the file with the title in the YAML front matter
def write_file(content, title, directory, filename)
  title = title.titlecase
  content = content.gsub("title:", "title: \"#{title}\"")
  parsed_content = content.gsub("date:", "date: \"#{CURRENT_TIME}\"")
  File.write("#{directory}/#{filename}", parsed_content)
  puts "#{filename} was created in '#{directory}'."
end

# Create the file with the slug and open the default editor
def create_file(directory, filename, content, title, editor)
  if File.exists?("#{directory}/#{filename}")
    raise "The file already exists."
  else
    write_file(content, title, directory, filename)
    if editor && !editor.nil?
      sleep 1
      execute("#{editor} #{directory}/#{filename}")
    end
  end
end

# Allow passing argv to tasks without throwing
# undefined task errors.
def escape_argv(argv)
  # This defines an empty task at runtime for
  # each argv item.
  argv.each { |a| task a.to_sym do ; end }
end

#
# == Tasks
#

# rake post "My Post Title"
desc "Create a post in _posts"
task :post do
  escape_argv(ARGV)
  title = ARGV[1]
  if title.nil? or title.empty?
    raise "Please add a title to your file."
  end
  template = CONFIG["post"]["template"]
  extension = CONFIG["post"]["extension"]
  editor = CONFIG["editor"]
  filename = transform_to_slug("#{DATE}-#{title}", extension)
  content = File.read(template)
  create_file('_posts', filename, content, title, editor)
end

# rake build
desc "Build the site"
task :build do
  execute("bundle exec jekyll build")
end

# rake watch
desc "Serve the site locally and watch for changes"
task :watch do
  execute("bundle exec jekyll serve")
end


# rake deploy "Commit message"
desc "Deploy the site to a remote git repo"
task :deploy do
  escape_argv(ARGV)
  message = ARGV[1]
  branch = CONFIG["git"]["branch"]
  command = CONFIG["transfer"]["command"]
  source = CONFIG["transfer"]["source"]
  destination = CONFIG["transfer"]["destination"]
  settings = CONFIG["transfer"]["settings"]
  if message.nil? or message.empty?
    message = CURRENT_TIME
  end
  if branch.nil? or branch.empty?
    raise "Please add a branch."
  else
    execute("bundle exec jekyll build")
    execute("git add .")
    execute("git tag #{TAG_DATE}")
    execute("git commit -m \"#{CURRENT_TIME}\"")
    execute("git push --follow-tags origin #{branch} && git push --tags")
  end
  if command.nil? or command.empty?
    raise "Please choose a file transfer command."
  else
    Rake::Task[:build].invoke
    execute("rsync #{settings} #{source} #{destination}")
    puts "Your site was transfered."
  end
end

Update: I added a method for automatically adjusting the title case of a new post.