diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 0000000..6891a5f --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,5 @@ +fixtures: + repositories: + stdlib: "git://github.com/puppetlabs/puppetlabs-stdlib.git" + symlinks: + git: "#{source_dir}" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 92de487..f7aa582 100644 --- a/.gitignore +++ b/.gitignore @@ -26,5 +26,9 @@ Thumbs.db obj/ [Rr]elease*/ _ReSharper*/ +pkg/* [Tt]est[Rr]esult* -*~ \ No newline at end of file +.project +*~ +*.sublime-project +*.sublime-workspace diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..599a3b8 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,35 @@ +language: ruby +bundler_args: --without development +script: "bundle exec rake validate && bundle exec rake lint && bundle exec rake spec SPEC_OPTS='--format documentation'" +before_install: + - sudo apt-get install -qq augeas-tools augeas-lenses libaugeas-dev libaugeas-ruby +rvm: + - 1.8.7 + - 1.9.3 + - 2.0.0 +env: + matrix: + - PUPPET_GEM_VERSION="~> 2.6.0" + - PUPPET_GEM_VERSION="~> 2.7.0" + - PUPPET_GEM_VERSION="~> 3.0.0" + - PUPPET_GEM_VERSION="~> 3.1.0" + - PUPPET_GEM_VERSION="~> 3.2.0" + - PUPPET_GEM_VERSION="~> 3.3.1" +matrix: + allow_failures: + - env: PUPPET_GEM_VERSION="~> 2.6.0" + exclude: + - rvm: 1.9.3 + env: PUPPET_GEM_VERSION="~> 2.7.0" + - rvm: 1.9.3 + env: PUPPET_GEM_VERSION="~> 2.6.0" + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 2.6.0" + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 2.7.0" + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 3.0.0" + - rvm: 2.0.0 + env: PUPPET_GEM_VERSION="~> 3.1.0" +notifications: + email: false \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..dd6e6ed --- /dev/null +++ b/Gemfile @@ -0,0 +1,20 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'rake', :require => false + gem 'rspec-puppet', :require => false + gem 'puppetlabs_spec_helper', :require => false + gem 'ruby-augeas', :require => false + gem 'rspec-puppet-augeas', :require => false + gem 'rspec-system', :require => false + gem 'rspec-system-puppet', :require => false + gem 'puppet-lint', :require => false +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby \ No newline at end of file diff --git a/Modulefile b/Modulefile index 338a703..03393dd 100644 --- a/Modulefile +++ b/Modulefile @@ -1,5 +1,5 @@ -name 'nesi-git' -version '0.0.1' +name 'Aethylred-git' +version '0.1.2' source 'https://github.com/nesi/puppet-git' author 'Aaron Hicks' license 'GPL3' diff --git a/README.markdown b/README.markdown index b04574e..a942e76 100644 --- a/README.markdown +++ b/README.markdown @@ -1,81 +1,97 @@ # puppet-git ============ -A puppet module for managing git resources +[![Build Status](https://travis-ci.org/nesi/puppet-git.png?branch=master)](https://travis-ci.org/nesi/puppet-git) -# To install into puppet +A puppet module for managing the installation and configuration of [git](http://git-scm.com/). -Clone into your puppet configuration in your `puppet/modules` directory: +**WARNING** Changes to how Puppet sets up the environment variables with `exec` resources means this module no longer works as intended when managing repositories as any user other than root. It is recommended that the [Puppetlabs vcsrepo module](https://github.com/puppetlabs/puppetlabs-vcsrepo) is used manage repositories. - git clone git://github.com/nesi/puppet-git.git git +## Feature Roadmap -Or if you're managing your Puppet configuration with git, in your `puppet` directory: +This module is going to be refactored to operate in conjunction to the vcsrepo module. It will manage the installation of git, the configuration of git specific settings, executing git commands, and eventually the management of git hook scripts. - git submodule add git://github.com/nesi/puppet-git.git modules/git --init --recursive - cd modules/git - git checkout master - git pull - cd ../.. - git commit -m "added git submodule from https://github.com/nesi/puppet-git" +#### Implemented Features: +* Installs git from packages +* Optionally installs git-svn from packages (defaults installed) +* Optionally installs git-gui from packages (defaults not installed) -It might seem bit excessive, but it will make sure the submodule isn't headless... +#### Features not yet updated +* Initialising user accounts with git configurations + +#### Features to be Implemented +* Sets git user's globals settings +* Sets git repository local settings +* Executes git commands +* Pushes hook scripts into git repositories # Usage ## To install git -A basic install with the defaults would be: - - include git +A basic install with the defaults would be: +```puppet +include git +``` -Otherwise using the parametrs: - - class{git: - svn => true, - gui => true, - } +Otherwise using the parametrs: +```puppet +class{git: + svn => 'installed', + gui => 'installed', +} +``` ### Parameters -* *svn* if true the git-svn package will also be installed -* *gui* if true the git-gui package will also be installed +* **ensure**: Sets the ensure parameter passed to the git package. The default is `installed`. +* **svn**: Sets the ensure paramater passed to the git-svn package. The default is `installed`. +* **gui**: Sets the ensure parameter passed to the git-gui package. The default is `absent`. +* **package**: Specifies a custom package. The default is `git`, except for older versions of Debian and Ubuntu where the default is `git-core`. +* **git_root**: Currently does nothing, it's functionality is to be reviewed. ## To set up git for a user This basically sets the users name and email as git global variables, and should allow them to just use git. The username should be a valid user account. -With default settings just use: - - git::user{'username':} +With default settings just use: +```puppet +git::user{'username':} +``` -Otherwise using parameters: - - git::user{'username': - user_name => 'Some User', - user_email => 'someuser@example.org', - } +Otherwise using parameters: +```puppet +git::user{'username': + user_name => 'Some User', + user_email => 'someuser@example.org', +} +``` ### Parameters * *user_name* sets the user's name to the specified string, and not the default of `${name} on ${fqdn}`, where fqdn is the fully qualified domain name as discovered by facter. * *user_email* sets the user's email address to the specified string, and not the default of `${name}@${fqdn}`, where fqdn is the fully qualified domain name as discovered by facter. -## To specify a git repository - -This will clone a git repository from a vaild git URI to a specified path on the target server. It is **strongly** recommended that *read-only* git URIs are used. If no source is given, the target path will simply be initialised as a git repository. +## To specify a git repository -With minimum parameters, should create the directory `/usr/src/repo` and run `git init` in it: +**Using the `git::repo` class is depreciated and `vcsrepo` should be considered instead.** - git::repo{'repo_name': - path => '/usr/src/repo', - } - -With minimum parameters to clone from a remote source: +This will clone a git repository from a vaild git URI to a specified path on the target server. It is **strongly** recommended that *read-only* git URIs are used. If no source is given, the target path will simply be initialised as a git repository. - git::repo{'repo_name': - path => '/usr/src/repo', - source => 'git://example.org/example/repo.git' - } +With minimum parameters, should create the directory `/usr/src/repo` and run `git init` in it: +```puppet +git::repo{'repo_name': + path => '/usr/src/repo', +} +``` + +With minimum parameters to clone from a remote source: +```puppet +git::repo{'repo_name': + path => '/usr/src/repo', + source => 'git://example.org/example/repo.git' +} +``` ### Parameters @@ -96,6 +112,8 @@ With minimum parameters to clone from a remote source: # Attribution +## puppet-blank + This module is derived from the puppet-blank module by Aaron Hicks (aethylred@gmail.com) * https://github.com/Aethylred/puppet-blank @@ -104,6 +122,19 @@ This module has been developed for the use with Open Source Puppet (Apache 2.0 l * http://puppetlabs.com/puppet/puppet-open-source/ +## rspec-puppet-augeas + +This module includes the [Travis](https://travis-ci.org) configuration to use [`rspec-puppet-augeas`](https://github.com/domcleal/rspec-puppet-augeas) to test and verify changes made to files using the [`augeas` resource](http://docs.puppetlabs.com/references/latest/type.html#augeas) available in Puppet. Check the `rspec-puppet-augeas` [documentation](https://github.com/domcleal/rspec-puppet-augeas/blob/master/README.md) for usage. + +This will require a copy of the original input files to `spec/fixtures/augeas` using the same filesystem layout that the resource expects: +``` +$ tree spec/fixtures/augeas/ +spec/fixtures/augeas/ +`-- etc + `-- ssh + `-- sshd_config +``` + # Gnu General Public License This file is part of the git Puppet module. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..268c50c --- /dev/null +++ b/Rakefile @@ -0,0 +1,24 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/rake_tasks' +require 'rspec-system/rake_task' +require 'puppet-lint/tasks/puppet-lint' +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] + +desc "Check for puppet and ruby syntax errors." +task :validate do + if ENV['PUPPET_GEM_VERSION'] == '~> 2.6.0' + puppet_parse_command = 'puppet --parseonly --ignoreimport' + else + puppet_parse_command = 'puppet parser validate --noop' + end + Dir['manifests/**/*.pp'].each do |path| + sh "#{puppet_parse_command} #{path}" + end + ruby_parse_command = 'ruby -c' + Dir['spec/**/*.rb'].each do |path| + sh "#{ruby_parse_command} #{path}" + end +end diff --git a/manifests/init.pp b/manifests/init.pp index 3dd3bda..800775b 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -31,13 +31,45 @@ # # Somewhat derived from https://github.com/theforeman/puppet-git class git( - $gui = false, - $svn = true, + $ensure = 'installed', + $package = $git::params::package, + $gui = 'absent', + $svn = 'installed', $git_root = false ) inherits git::params { - class{'git::install': - gui => $gui, - svn => $svn, - git_root => $git_root, + + # ensure statement for the git package overrides svn and gui ensure. + case $ensure { + /^installed$|^(\d+)?(\.(x|\*|\d+))?(\.(x|\*|\d+))?(|-(\S+))$/: { + $ensure_svn = $svn + $ensure_gui = $gui + } + default: { + $ensure_svn = 'absent' + $ensure_gui = 'absent' + } + } + + package{'git': + ensure => $ensure, + name => $package, + } + + package{'git-svn': + ensure => $ensure_svn, + name => $git::params::svn_package, } + + package{'git-gui': + ensure => $ensure_gui, + name => $git::params::gui_package, + } + + # Need to consider if this should happen or not. + # if $git_root { + # $root_name = "root on ${::fqdn}" + # $root_email = "root@${::fqdn}" + # git::user{'root':} + # } + } diff --git a/manifests/install.pp b/manifests/install.pp deleted file mode 100644 index f7b4090..0000000 --- a/manifests/install.pp +++ /dev/null @@ -1,42 +0,0 @@ -# Git installer manifest -# DO NOT USE DIRECTLY -# -# Use this instead: -# include git -# -# or: -# class {'git': -# svn => true, -# gui => true, -#} - -class git::install( - $gui, - $svn, - $git_root -){ - require git::params - - if ! defined(Package[$git::params::package]) { - package{$git::params::package: ensure => installed} - } - - if $svn { - package{$git::params::svn_package: ensure => installed} - } else { - package{$git::params::svn_package: ensure => absent} - } - - if $gui { - package{$git::params::gui_package: ensure => installed} - } else { - package{$git::params::gui_package: ensure => absent} - } - - if $git_root { - $root_name = "root on ${::fqdn}" - $root_email = "root@${::fqdn}" - git::user{'root':} - } - -} diff --git a/manifests/params.pp b/manifests/params.pp index 7ee199c..938e02a 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -4,23 +4,31 @@ class git::params { - case $::operatingsystem { - 'Scientific','CentOS','Ubuntu','Debian','Amazon','Archlinux','Gentoo','Fedora' :{ - $svn_package = 'git-svn' - $gui_package = 'git-gui' - $bin = '/usr/bin/git' - if $::operatingsystem =~ /^(Debian|Ubuntu)$/ and versioncmp($::operatingsystemrelease, "12") < 0 { + # Common variables: + $svn_package = 'git-svn' + $gui_package = 'git-gui' + $bin = '/usr/bin/git' + $su_cmd = '/bin/su' + + case $::osfamily { + Debian: { + if $::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemrelease, '11') < 0 { $package = 'git-core' }else{ - $package = 'git' - } - $grep_cmd = $::operatingsystem ? { - Archlinux => '/usr/bin/grep', - default => '/bin/grep' + $package = 'git' } + $grep_cmd = '/bin/grep' + } + RedHat: { + $package = 'git' + $grep_cmd = '/bin/grep' + } + ArchLinux:{ + $package = 'git' + $grep_cmd = '/usr/bin/grep' } default:{ - warning("git not configured for ${::operatingsystem} on ${::fqdn}") + fail("The NeSI Git Puppet module does not support ${::osfamily} family of operating systems") } } } diff --git a/manifests/repo.pp b/manifests/repo.pp index 2c91f96..e758e9c 100644 --- a/manifests/repo.pp +++ b/manifests/repo.pp @@ -24,14 +24,25 @@ $owner = 'root', $group = 'root', $update = false, - $bare = false + $bare = false, + $timeout = 60 ){ + warning('Using git::repo is depreciated!') + require git require git::params validate_bool($bare, $update) + if $owner != 'root' { + $su_do = "${git::params::su_cmd} ${owner} -c \"" + $su_end = '"' + } else { + $su_do = '' + $su_end = '' + } + if $branch { $real_branch = $branch } else { @@ -39,12 +50,12 @@ } if $source { - $init_cmd = "${git::params::bin} clone -b ${real_branch} ${source} ${path} --recursive" + $init_cmd = "${su_do}${git::params::bin} clone -b ${real_branch} ${source} ${path} --recursive${su_end}" } else { if $bare { - $init_cmd = "${git::params::bin} init --bare ${path}" + $init_cmd = "${su_do}${git::params::bin} init --bare ${path}${su_end}" } else { - $init_cmd = "${git::params::bin} init ${path}" + $init_cmd = "${su_do}${git::params::bin} init ${path}${su_end}" } } @@ -58,43 +69,45 @@ file{$path: ensure => directory, owner => $owner, + group => $group, recurse => true, } } exec {"git_repo_${name}": - command => $init_cmd, - user => $owner, - creates => $creates, - require => Package[$git::params::package], - timeout => 600, + command => $init_cmd, + user => $owner, + provider => shell, + creates => $creates, + require => Package[$git::params::package], + timeout => $timeout, } # I think tagging works, but it's possible setting a tag and a branch will just fight. # It should change branches too... if $git_tag { exec {"git_${name}_co_tag": - user => $owner, - cwd => $path, - command => "${git::params::bin} checkout ${git_tag}", - unless => "${git::params::bin} describe --tag|${git::params::grep_cmd} -P '${git_tag}'", - require => Exec["git_repo_${name}"], + cwd => $path, + provider => shell, + command => "${su_do}${git::params::bin} checkout ${git_tag}${su_end}", + unless => "${su_do}${git::params::bin} describe --tag|${git::params::grep_cmd} -P '${git_tag}'${su_end}", + require => Exec["git_repo_${name}"], } } elsif ! $bare { exec {"git_${name}_co_branch": - user => $owner, - cwd => $path, - command => "${git::params::bin} checkout ${branch}", - unless => "${git::params::bin} branch|${git::params::grep_cmd} -P '\\* ${branch}'", - require => Exec["git_repo_${name}"], + cwd => $path, + provider => shell, + command => "${su_do}${git::params::bin} checkout ${real_branch}${su_end}", + unless => "${su_do}${git::params::bin} branch|${git::params::grep_cmd} -P '\\* ${real_branch}'${su_end}", + require => Exec["git_repo_${name}"], } if $update { exec {"git_${name}_pull": - user => $owner, - cwd => $path, - command => "${git::params::bin} reset --hard origin/${branch}", - unless => "${git::params::bin} fetch && ${git::params::bin} diff origin/${branch} --no-color --exit-code", - require => Exec["git_repo_${name}"], + cwd => $path, + provider => shell, + command => "${su_do}${git::params::bin} reset --hard origin/${real_branch}${su_end}", + unless => "${su_do}${git::params::bin} fetch && ${git::params::bin} diff origin/${real_branch} --no-color --exit-code${su_end}", + require => Exec["git_repo_${name}"], } } } diff --git a/metadata.json b/metadata.json deleted file mode 100644 index 8ce7797..0000000 --- a/metadata.json +++ /dev/null @@ -1,12 +0,0 @@ -/* -+-----------------------------------------------------------------------+ -| | -| ==> DO NOT EDIT THIS FILE! <== | -| | -| You should edit the `Modulefile` and run `puppet-module build` | -| to generate the `metadata.json` file for your releases. | -| | -+-----------------------------------------------------------------------+ -*/ - -{} diff --git a/spec/classes/init_spec.rb b/spec/classes/init_spec.rb new file mode 100644 index 0000000..f7ed37a --- /dev/null +++ b/spec/classes/init_spec.rb @@ -0,0 +1,143 @@ +require 'spec_helper' +describe 'git', :type => :class do + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + } + end + describe "with no parameters" do + it { should include_class('git::params') } + it { should contain_package('git').with( + 'ensure' => 'installed', + 'name' => 'git' + ) } + it { should contain_package('git-svn').with( + 'ensure' => 'installed', + 'name' => 'git-svn' + ) } + it { should contain_package('git-gui').with( + 'ensure' => 'absent', + 'name' => 'git-gui' + ) } + end + describe "with ensure => absent" do + let :params do + { + :ensure => 'absent', + } + end + it { should include_class('git::params') } + it { should contain_package('git').with( + 'ensure' => 'absent' + ) } + it { should contain_package('git-svn').with( + 'ensure' => 'absent' + ) } + it { should contain_package('git-gui').with( + 'ensure' => 'absent' + ) } + end + describe "with svn => absent" do + let :params do + { + :svn => 'absent', + } + end + it { should include_class('git::params') } + it { should contain_package('git-svn').with( + 'ensure' => 'absent' + ) } + end + describe "with gui => installed" do + let :params do + { + :gui => 'installed', + } + end + it { should include_class('git::params') } + it { should contain_package('git-gui').with( + 'ensure' => 'installed' + ) } + end + end + + context "on an later (post 11) Ubuntu OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '11', + } + end + describe "with no parameters" do + it { should include_class('git::params') } + it { should contain_package('git').with( + 'ensure' => 'installed', + 'name' => 'git' + ) } + end + end + + context "on an early (pre 11) Ubuntu OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '10', + } + end + describe "with no parameters" do + it { should include_class('git::params') } + it { should contain_package('git').with( + 'ensure' => 'installed', + 'name' => 'git-core' + ) } + end + end + + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + } + end + describe "with no parameters" do + it { should include_class('git::params') } + it { should contain_package('git').with( + 'ensure' => 'installed', + 'name' => 'git' + ) } + end + end + + context "on a ArchLinux OS" do + let :facts do + { + :osfamily => 'ArchLinux', + } + end + describe "with no parameters" do + it { should include_class('git::params') } + it { should contain_package('git').with( + 'ensure' => 'installed', + 'name' => 'git' + ) } + end + end + + context "on an Unknown OS" do + let :facts do + { + :osfamily => 'Unknown', + } + end + it do + expect { + should include_class('puppet::params') + }.to raise_error(Puppet::Error, /The NeSI Git Puppet module does not support Unknown family of operating systems/) + end + end + +end diff --git a/spec/spec.opts b/spec/spec.opts index 91cd642..de653df 100644 --- a/spec/spec.opts +++ b/spec/spec.opts @@ -1,6 +1,4 @@ ---format -s +--format s --colour ---loadby -mtime +--loadby mtime --backtrace diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index a4aeeae..76b8923 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -1,18 +1,5 @@ -require 'pathname' -dir = Pathname.new(__FILE__).parent -$LOAD_PATH.unshift(dir, dir + 'lib', dir + '../lib') - -require 'mocha' -require 'puppet' -gem 'rspec', '=1.2.9' -require 'spec/autorun' - -Spec::Runner.configure do |config| - config.mock_with :mocha -end - -# We need this because the RAL uses 'should' as a method. This -# allows us the same behaviour but with a different method name. -class Object - alias :must :should -end +require 'puppetlabs_spec_helper/module_spec_helper' +require 'rspec-puppet-augeas' +RSpec.configure do |c| + c.augeas_fixtures = File.join(File.dirname(File.expand_path(__FILE__)), 'fixtures', 'augeas') +end \ No newline at end of file diff --git a/spec/spec_helper_system.rb b/spec/spec_helper_system.rb new file mode 100644 index 0000000..1f7c553 --- /dev/null +++ b/spec/spec_helper_system.rb @@ -0,0 +1,26 @@ +require 'rspec-system/spec_helper' +require 'rspec-system-puppet/helpers' +require 'rspec-system-serverspec/helpers' +include Serverspec::Helper::RSpecSystem +include Serverspec::Helper::DetectOS +include RSpecSystemPuppet::Helpers + +RSpec.configure do |c| + # Project root + proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Enable colour + c.tty = true + + c.include RSpecSystemPuppet::Helpers + + # This is where we 'setup' the nodes before running our tests + c.before :suite do + # Install puppet + puppet_install + + # Install modules and dependencies + puppet_module_install(:source => proj_root, :module_name => 'git') + # shell('puppet module install puppetlabs-stdlib --version 2.4.0') + end +end \ No newline at end of file