diff --git a/plugins/github.rb b/plugins/github.rb new file mode 100644 index 0000000..aac83d8 --- /dev/null +++ b/plugins/github.rb @@ -0,0 +1,167 @@ +require 'tmpdir' + +# Usage: +# add to ruhoh-site/plugins/publish/github.rb +# - Your GitHub remote must be setup properly but The command will try to walk you through it. +# - You must have a clean working directory to publish to GitHub pages since the hook is actually triggered by commits. +# +# $ cd ruhoh-site +# $ bundle exec ruhoh publish github +class Ruhoh + class Publish::Github + def run(opts={}, config={}) + return false unless can_switch_branch? + + _deploy_type = project_page? ? "Project" : "User/Org" + _source_branch = source_branch + _deploy_branch = deploy_branch + _origin_remote = origin_remote + Ruhoh::Friend.say { + plain "Deploying to GitHub Pages." + plain "(Settings based on origin remote name: #{ _origin_remote })" + plain " Type: #{ _deploy_type } page." + plain " Source: '#{ _source_branch }' branch." + plain " Compiled: '#{ _deploy_branch }' branch." + } + + if deploy_branch? + puts "Currently in deploy branch: '#{ deploy_branch }'; switching to source branch: '#{ source_branch }'..." + `git checkout #{ source_branch }` + end + + ruhoh = compile + + # Add to deploy_branch + return false unless checkout_deploy_branch + system("git", "rm", "-rf", ".") + FileUtils.cp_r(File.join(ruhoh.config['compiled_path'], '.'), '.') + `git add .` # system() doesn't work for some reason =/ + + # Commit and push + system("git", "commit", "-m", "#{ source_branch }: #{ last_commit_message(source_branch) }") + system("git", "push", "origin", deploy_branch) + system('git', 'checkout', source_branch) + end + + def compile + ruhoh = Ruhoh.new + #ruhoh.setup + ruhoh.env = 'production' + #ruhoh.setup_paths + ruhoh.setup_plugins + + config_overrides = set_configuration(ruhoh.config) + ruhoh.config.merge!(config_overrides) + + ruhoh.config['compiled_path'] = File.join(Dir.tmpdir, 'compiled') + ruhoh.compile + ruhoh + end + + # Set GitHub-specific configuration settings. + def set_configuration(config) + opts = {} + opts['compile_as_root'] = true + #opts['base_path'] = "/" + + if project_page? + if !config['production_url'] || config['production_url'] == "http://sample.com" + #opts['base_path'] = "/#{ repository_name }/" + + #Ruhoh::Friend.say { plain "base_path set to: #{ opts['base_path'] } for GitHub project page support" } + else + Ruhoh::Friend.say { + plain "base_path set to: '#{ opts['base_path'] }' because config['production_url'] = '#{ config['production_url'] }'" + } + end + end + + opts + end + + def deploy_branch + @deploy_branch ||= project_page? ? 'gh-pages' : 'master' + end + + def source_branch + (deploy_branch == 'gh-pages') ? 'master' : 'gh-pages' + end + + def deploy_branch? + get_branch == deploy_branch + end + + def stage_clean? + system('git', 'diff', '--staged', '--exit-code') + end + + def working_directory_clean? + system('git', 'diff', '--exit-code') + end + + def can_switch_branch? + return true if working_directory_clean? && stage_clean? + + puts "Aborting: Deploying requires a clean working directory and staging area." + puts " - Commit changes to add them to the compile output." + puts " - `git stash` changes to omit them from compile output." + false + end + + def checkout_deploy_branch + return false unless can_switch_branch? + + return true if system('git', 'checkout', deploy_branch) + return true if system("git", "checkout", "--orphan", deploy_branch) + + puts "Aborting: Switching to #{ deploy_branch } branch failed." + false + end + + def get_branch + branch = nil + `git branch --no-color`.each_line do |line| + if line.start_with?("*") + branch = line + break + end + end + + #omit the * and space + branch[2, branch.length].strip + end + + def last_commit_message(branch) + `git show #{ branch } --summary --pretty=oneline --no-color`.lines.first + end + + # Extract the remote URL from the origin remote signature + # Example: + # origin git@github.com:jaderade/hello-world.git (fetch) + def origin_remote + `git remote -v`.lines.first.split(/\s+/)[1] + end + + # Extract the repository name from the remote Url + # Example formats: + # git@github.com:jaderade/hello-world.git + # https://github.com/jaderade/hello-world.git + # + # Should extract "hello-world" from above example. + def repository_name + remote = origin_remote + remote = remote.include?(':') ? + remote.split(':')[1] : + remote.gsub(/^(http|https):\/\/github.com\//, '') + + # Parse username/.git + remote.split('/')[1].chomp('.git') + end + + # Does the repository name reflect a GitHub Project page? + # Anything other than username.github.io OR username.github.com + def project_page? + !(repository_name =~ /[\w-]+\.github\.(?:io|com)/) + end + end +end