├── .gitignore ├── .ruby-version ├── Gemfile ├── LICENSE ├── README.md ├── Rakefile ├── example-box └── Vagrantfile ├── lib ├── vagrant-git.rb └── vagrant-git │ ├── action.rb │ ├── config.rb │ ├── git.rb │ ├── plugin.rb │ └── version.rb └── vagrant-git.gemspec /.gitignore: -------------------------------------------------------------------------------- 1 | Gemfile.lock 2 | pkg 3 | example-box/.vagrant 4 | -------------------------------------------------------------------------------- /.ruby-version: -------------------------------------------------------------------------------- 1 | ruby-2.2.3 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "http://rubygems.org" 2 | 3 | group :development do 4 | gem "vagrant", :git => "git://github.com/mitchellh/vagrant.git" 5 | end 6 | 7 | group :plugins do 8 | gem "vagrant-git", path: "." 9 | end 10 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2006-2013 Learnosity Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vagrant-git 2 | 3 | `vagrant-git` is a [Vagrant](http://vagrantup.com) plugin for checking out and updating git repos. It has a very simple configuration to either clone or pull repositories after a VM boots (but before it's provisioned). 4 | 5 | The plugin doesn't do anything special, but it helps to centralise environment configuration declaratively in the Vagrantfile, rather than relying on scripting. 6 | 7 | Currently the plugin only supports cloning into the host machine, so care should be taken to clone the repositories into a directory accessible by the guest. [vagrant-sparseimage](https://github.com/Learnosity/vagrant-sparseimage) integrates well for this use job, or a standard file share should be use. 8 | 9 | When you run `vagrant up` or `vagrant provision`, this plugin will clone or pull the various specified git repos. It does not attempt to handle a dirty working tree: `git pull` will simply fail. This is to prevent mistakenly clobbering any changes. In order to get a 10 | 11 | Planning to implement a command - `vagrant git` - supporting `list`, `pull`, `clone` and `reset` to streamline this a little. 12 | 13 | 14 | ## Dependencies 15 | 16 | Only supports Vagrant > 1.2. 17 | 18 | Requires `git`. 19 | 20 | ## Installation 21 | 22 | See **building** below for building the gem. 23 | 24 | Use `vagrant plugin` to install the gem in your Vagrant environment: 25 | 26 | ```bash 27 | $ vagrant plugin install vagrant-git 28 | ``` 29 | 30 | ## Configuration 31 | 32 | See `example-box/vagrantfile` for an example configuration. 33 | 34 | The following config properties for `config.git` are required: 35 | 36 | * **target**: *string*: the repository to clone. This must be a fully qualified git ref spec. 37 | * **path**: *string*: the path in the host or the guest to clone or pull the repo into 38 | 39 | The following properties are optional (but not yet supported): 40 | 41 | * **branch**: Which branch to check out / pull 42 | * **clone_in_host**: *boolean*: true to execute git commands in the host, false to execute them in the guest. NOT YET SUPPORTED for false. 43 | * **sync_on_load**: whether to do a fetch & pull when starting up the VM 44 | * **set_upstream**: a different remote URL to set the upstream origin to after cloning the repository 45 | 46 | ## Building 47 | 48 | ```bash 49 | $ bundle install 50 | $ cd ./example-box/ 51 | $ bundle exec vagrant up 52 | ``` 53 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'rubygems' 2 | require 'bundler/setup' 3 | Bundler::GemHelper.install_tasks 4 | -------------------------------------------------------------------------------- /example-box/Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | # Vagrantfile API/syntax version. Don't touch unless you know what you're doing! 5 | VAGRANTFILE_API_VERSION = "2" 6 | 7 | Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| 8 | config.vm.box = "ubuntu/trusty64" 9 | config.vm.network "private_network", ip: "192.168.66.10" 10 | 11 | config.vm.synced_folder '.', '/vagrant', disabled: true 12 | # enable if you want to access the repo via a share 13 | #config.vm.synced_folder './vagrant-git', '/tmp/vagrant-git' 14 | 15 | config.git.add_repo do |rc| 16 | rc.target = 'https://github.com/Learnosity/vagrant-git.git' 17 | rc.path = '/tmp/vagrant-git' 18 | rc.branch = 'master' 19 | rc.clone_in_host = true 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /lib/vagrant-git.rb: -------------------------------------------------------------------------------- 1 | begin 2 | require "vagrant" 3 | rescue LoadError 4 | raise "The Vagrant Hello plugin must be run within Vagrant." 5 | end 6 | 7 | # This is a sanity check to make sure no one is attempting to install 8 | # this into an early Vagrant version. 9 | if Vagrant::VERSION < "1.2.0" 10 | raise "The Vagrant Hello plugin is only compatible with Vagrant 1.2+" 11 | end 12 | 13 | require "vagrant-git/plugin" 14 | 15 | require "pathname" 16 | 17 | module VagrantPlugins 18 | module VagrantGit 19 | def self.source_root 20 | @source_root ||= Pathname.new(File.expand_path("../../", __FILE__)) 21 | end 22 | 23 | #I18n.load_path << File.expand_path('locales/en.yml', source_root) 24 | #I18n.reload! 25 | 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/vagrant-git/action.rb: -------------------------------------------------------------------------------- 1 | require 'vagrant-git/git' 2 | 3 | module VagrantPlugins 4 | module VagrantGit 5 | module Action 6 | class HandleRepos 7 | def initialize(app, env) 8 | @app = app 9 | @env = env 10 | end 11 | 12 | def call(env) 13 | @app.call(env) 14 | @env = env 15 | 16 | @vm = env[:machine] 17 | errors = {} 18 | 19 | @vm.config.git.to_hash[:repos].each do |rc| 20 | errors[rc.path] = [] 21 | if not rc.clone_in_host 22 | raise 'NotImplemented: clone_in_host=>false' 23 | end 24 | 25 | if File.exist? "#{rc.path}/.git" 26 | if rc.sync_on_load 27 | Git::fetch(rc.path) 28 | Git::pull(rc.path, {:branch => rc.branch}) 29 | end 30 | else 31 | p = Git::clone(rc.target, rc.path, {:branch => rc.branch}) 32 | 33 | if p.success? and rc.set_upstream 34 | @vm.ui.info("Clone done - setting upstream of #{rc.path} to #{rc.set_upstream}") 35 | if not Git::set_upstream(rc.path, rc.set_upstream).success? 36 | err = "Failed to change upstream to #{rc.set_upstream} in #{rc.path}" 37 | errors[rc.path].push(err) 38 | @vm.ui.error(err) 39 | end 40 | elsif !p.success? 41 | err = "Failed to clone #{rc.target} into #{rc.path}" 42 | errors[rc.path].push(err) 43 | @vm.ui.error(err) 44 | end 45 | 46 | if File.exist? "#{rc.path}/.gitmodules" 47 | p = Git::submodule(rc.path) 48 | if p.success? 49 | @vm.ui.info("Checked out submodules.") 50 | else 51 | err ="WARNING: Failed to check out submodules for #{rc.path}" 52 | errors[rc.path].push(err) 53 | @vm.ui.error(err) 54 | end 55 | end 56 | end 57 | end 58 | 59 | # Reprint any errors 60 | errors = errors.reject { |k, v| v.length == 0 } 61 | if errors.length > 0 62 | @vm.ui.error("WARNING: Encountered errors when cloning repos.") 63 | errors.each do |repo, errs| 64 | @vm.ui.error("-- #{repo} --") 65 | errs.each do |e| 66 | @vm.ui.error(e) 67 | end 68 | end 69 | @vm.ui.error("If these were due to transient network issues, try again with:") 70 | @vm.ui.error("\tvagrant halt") 71 | @vm.ui.error("\tvagrant up") 72 | end 73 | end 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /lib/vagrant-git/config.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module VagrantGit 3 | class Config < Vagrant.plugin("2", :config) 4 | # Singleton for each VM 5 | @@repo_configs = [] 6 | class << self 7 | attr_accessor :repo_configs 8 | end 9 | 10 | def to_hash 11 | { :repos => @@repo_configs } 12 | end 13 | 14 | def add_repo 15 | # Yield a new repo config object to the config block 16 | rc = RepoConfig.new 17 | yield rc 18 | @@repo_configs.push rc 19 | end 20 | 21 | def validate(machine) 22 | errors = {} 23 | @@repo_configs.each_with_index do |rc, i| 24 | rc_errors = rc.validate 25 | if rc_errors.length > 0 26 | errors[i] = rc_errors 27 | end 28 | end 29 | errors 30 | end 31 | 32 | def finalize! 33 | @@repo_configs.each do |config| 34 | config.finalize! 35 | end 36 | end 37 | end 38 | 39 | class RepoConfig 40 | # Config for a single repo 41 | # Assumes that the agent has permission to check out, or that it's public 42 | 43 | attr_accessor :target, :path, :clone_in_host, :branch, :sync_on_load, :set_upstream 44 | 45 | @@required = [:target, :path] 46 | 47 | def validate 48 | errors = {} 49 | if @target.nil? 50 | errors[:target] = ["target must not be nil."] 51 | end 52 | if @path.nil? 53 | errors[:path] = ["path must not be nil."] 54 | end 55 | errors 56 | end 57 | 58 | def finalize! 59 | if @clone_in_host.nil? 60 | @clone_in_host = true 61 | end 62 | if @sync_on_load.nil? 63 | @sync_on_load = false 64 | end 65 | end 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/vagrant-git/git.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module VagrantGit 3 | module Git 4 | class << self 5 | # Run the command, wait for exit and return the Process object. 6 | def run(cmd) 7 | pid = spawn(cmd) 8 | Process.waitpid(pid) 9 | return $? 10 | end 11 | 12 | def clone(target, path, opts = {}) 13 | branch = opts[:branch] 14 | if branch.nil? 15 | return run("git clone '#{target}' '#{path}'") 16 | else 17 | return run("git clone -b '#{branch}' '#{target}' '#{path}'") 18 | end 19 | end 20 | def fetch(path) 21 | return run("cd '#{path}'; git fetch") 22 | end 23 | 24 | def pull(path, opts = {}) 25 | branch = opts[:branch] 26 | if branch.nil? 27 | return run("cd '#{path}'; git fetch; git pull;") 28 | else 29 | return run("cd '#{path}'; git pull origin '#{branch}';") 30 | end 31 | end 32 | 33 | def submodule(path) 34 | return run("cd '#{path}' && git submodule update --init --recursive") 35 | end 36 | 37 | def set_upstream(path, target) 38 | return run("cd '#{path}'; git remote set-url origin '#{target}';") 39 | end 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/vagrant-git/plugin.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module VagrantGit 3 | class Plugin < Vagrant.plugin("2") 4 | name "vagrant git support" 5 | description <<-DESC 6 | A vagrant plugin to allow checking out git repositories as part of 7 | vagrant tasks. 8 | DESC 9 | 10 | config(:git) do 11 | require File.expand_path("../config", __FILE__) 12 | Config 13 | end 14 | 15 | require File.expand_path("../action", __FILE__) 16 | %w{up reload}.each do |action| 17 | action_hook(:git, "machine_action_#{action}".to_sym) do |hook| 18 | hook.after( 19 | Vagrant::Action::Builtin::SyncedFolderCleanup, 20 | Action::HandleRepos 21 | ) 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /lib/vagrant-git/version.rb: -------------------------------------------------------------------------------- 1 | module VagrantPlugins 2 | module VagrantGit 3 | VERSION = "0.1.7" 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /vagrant-git.gemspec: -------------------------------------------------------------------------------- 1 | # -*- encoding: utf-8 -*- 2 | $:.unshift File.expand_path("../lib", __FILE__) 3 | 4 | require 'vagrant-git/version.rb' 5 | 6 | Gem::Specification.new do |s| 7 | s.name = 'vagrant-git' 8 | s.version = VagrantPlugins::VagrantGit::VERSION 9 | s.platform = Gem::Platform::RUBY 10 | s.authors = ['Daniel Bryan', 'Alan Garfield'] 11 | s.license = 'MIT' 12 | s.email = ['danbryan@gmail.com', 'alan.garfield@learnosity.com'] 13 | s.homepage = 'https://github.com/Learnosity/vagrant-git' 14 | s.summary = %q{A vagrant plugin to allow checking out git repositories as part of vagrant tasks.} 15 | s.description = %q{A vagrant plugin to allow checking out git repositories as part of vagrant tasks.} 16 | 17 | s.files = `git ls-files`.split($/) 18 | s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) } 19 | s.require_paths = ['lib'] 20 | 21 | s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= 22 | 23 | if s.respond_to? :specification_version 24 | current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION 25 | s.specification_version = 2 26 | end 27 | 28 | s.add_development_dependency 'bundler', '>= 1.2.0' 29 | end 30 | --------------------------------------------------------------------------------