├── .gitignore ├── Gemfile ├── commit_hooks ├── r10k_syntax_check.sh ├── config.cfg ├── ruby_syntax_check.sh ├── erb_template_syntax_check.sh ├── puppet_manifest_syntax_check.sh ├── yaml_syntax_check.sh ├── puppet_epp_syntax_check.sh ├── json_syntax_check.sh ├── rspec_puppet_checks.sh ├── puppet_manifest_documentation_check.sh └── puppet_lint_checks.sh ├── post-update ├── update ├── README.md ├── deploy-git-hook ├── pre-receive ├── pre-commit └── LICENSE /.gitignore: -------------------------------------------------------------------------------- 1 | .project 2 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gem 'r10k' 4 | gem 'rspec-puppet' 5 | gem 'json_pure' 6 | gem 'psych' 7 | gem 'metadata-json-lint' 8 | gem 'yaml-lint' 9 | gem 'puppet', '3.8.6' 10 | gem 'puppet-lint', '2.0.0' 11 | -------------------------------------------------------------------------------- /commit_hooks/r10k_syntax_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # This script assumes you have installed r10k and will perform a syntax check on the Puppetfile if existing 4 | 5 | echo "Performing a syntax check on the r10k Puppetfile:" 6 | r10k puppetfile check --puppetfile "$1" 7 | 8 | if [[ $? -ne 0 ]] 9 | then 10 | exit 1 11 | fi 12 | -------------------------------------------------------------------------------- /commit_hooks/config.cfg: -------------------------------------------------------------------------------- 1 | CHECK_PUPPET_LINT="enabled" # enabled, permissive or disabled (permissive runs but return code is ignored) 2 | CHECK_PUPPET_DOCS="enabled" # enabled, permissive or disabled (permissive runs but return code is ignored) 3 | USE_PUPPET_FUTURE_PARSER="disabled" # enabled or disabled 4 | CHECK_INITIAL_COMMIT="disabled" # enabled or disabled 5 | CHECK_RSPEC="enabled" # enabled or disabled 6 | CHECK_R10K="enabled" # enabled or disabled 7 | export PUPPET_LINT_OPTIONS="" # puppet-lint options to use if no rc file is present. Defaults to "--no-140chars-check" 8 | export PUPPET_LINT_FAIL_ON_WARNINGS="true" # Set the puppet-lint option --fail-on-warnings 9 | UNSET_RUBY_ENV="enabled" # enabled or disabled. Required for Gitlab. 10 | PATH="$PATH:/opt/puppetlabs/puppet/bin" 11 | -------------------------------------------------------------------------------- /commit_hooks/ruby_syntax_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script expects $1 to be passed and for $1 to be the filesystem location 4 | # to an RB file for which it will run syntax checks against. If $2 is passed, 5 | # it will be stripped off of the path to provide prettier output, which is 6 | # particularly useful for server-side hooks when tempdirs are created. 7 | 8 | syntax_errors=0 9 | error_msg=$(mktemp /tmp/error_msg_ruby-syntax.XXXXX) 10 | 11 | if [ $2 ]; then 12 | module_path=$(echo $1 | sed -e 's|'$2'||') 13 | else 14 | module_path=$1 15 | fi 16 | 17 | # Check ruby template syntax 18 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking ruby syntax for $module_path...$(tput sgr0)" 19 | cat $1 | ruby -c > $error_msg 2>&1 20 | if [ $? -ne 0 ]; then 21 | cat $error_msg | sed -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" 22 | syntax_errors=`expr $syntax_errors + 1` 23 | echo -e "$(tput setaf 1)Error: ruby syntax error in $module_path (see above)$(tput sgr0)" 24 | fi 25 | rm $error_msg 26 | 27 | if [ "$syntax_errors" -ne 0 ]; then 28 | echo -e "$(tput setaf 1)Error: $syntax_errors syntax errors found in ruby files. Commit will be aborted.$(tput sgr0)" 29 | exit 1 30 | fi 31 | 32 | exit 0 33 | 34 | -------------------------------------------------------------------------------- /commit_hooks/erb_template_syntax_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script expects $1 to be passed and for $1 to be the filesystem location 4 | # to an ERB file for which it will run syntax checks against. If $2 is passed, 5 | # it will be stripped off of the path to provide prettier output, which is 6 | # particularly useful for server-side hooks when tempdirs are created. 7 | 8 | syntax_errors=0 9 | error_msg="$(mktemp /tmp/error_msg_erb-syntax.XXXXX)" 10 | 11 | if [[ $2 ]]; then 12 | module_path="${1##*$2}" 13 | else 14 | module_path=$1 15 | fi 16 | 17 | # Check ERB template syntax 18 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking erb template syntax for $module_path...$(tput sgr0)" 19 | erb -P -x -T - "$1" | ruby -c 2> "$error_msg" 1>&2 20 | if [ $? -ne 0 ]; then 21 | sed -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" "$error_msg" 22 | syntax_errors=$((syntax_errors + 1)) 23 | echo -e "$(tput setaf 1)Error: erb syntax error in $module_path (see above)$(tput sgr0)" 24 | fi 25 | rm -f "$error_msg" 26 | 27 | if [ "$syntax_errors" -ne 0 ]; then 28 | echo -e "$(tput setaf 1)Error: $syntax_errors syntax errors found in templates. Commit will be aborted.$(tput sgr0)" 29 | exit 1 30 | fi 31 | 32 | exit 0 33 | -------------------------------------------------------------------------------- /commit_hooks/puppet_manifest_syntax_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script expects $1 to be passed and for $1 to be the filesystem location 4 | # to a puppet manifest file for which it will run syntax checks against. 5 | 6 | manifest_path="$1" 7 | USE_PUPPET_FUTURE_PARSER="$2" 8 | 9 | syntax_errors=0 10 | error_msg=$(mktemp /tmp/error_msg_puppet-syntax.XXXXX) 11 | manifest_name="$manifest_path" 12 | error_msg_filter="sed" 13 | 14 | # Get list of new/modified manifest and template files to check (in git index) 15 | # Check puppet manifest syntax 16 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking puppet manifest syntax for $manifest_name...$(tput sgr0)" 17 | if [[ $USE_PUPPET_FUTURE_PARSER != "enabled" ]]; then 18 | puppet parser validate --color=false "$1" > "$error_msg" 19 | else 20 | puppet parser validate --parser future --color=false "$1" > "$error_msg" 21 | fi 22 | 23 | if [[ $? -ne 0 ]]; then 24 | syntax_errors=$((syntax_errors + 1)) 25 | $error_msg_filter -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" < "$error_msg" 26 | echo -e "$(tput setaf 1)Error: puppet syntax error in $manifest_name (see above)$(tput sgr0)" 27 | fi 28 | rm -f "$error_msg" 29 | 30 | if [[ $syntax_errors -ne 0 ]]; then 31 | echo -e "$(tput setaf 1)Error: $syntax_errors syntax error(s) found in puppet manifests. Commit will be aborted.$(tput sgr0)" 32 | exit 1 33 | fi 34 | 35 | exit 0 36 | -------------------------------------------------------------------------------- /commit_hooks/yaml_syntax_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script expects $1 to be passed and for $1 to be the filesystem location 4 | # to a yaml file for which it will run syntax checks against. 5 | 6 | syntax_errors=0 7 | error_msg=$(mktemp /tmp/error_msg_yaml-syntax.XXXXX) 8 | 9 | if [[ $2 ]]; then 10 | module_path="${1##*$2}" 11 | else 12 | module_path=$1 13 | fi 14 | 15 | if [ -f $PWD/.yamllint ] 16 | then 17 | YAMLLINT_CONFIG="-c $PWD/.yamllint" 18 | elif [ -f ~/.yamllint ] 19 | then 20 | YAMLLINT_CONFIG="-c $HOME/.yamllint" 21 | fi 22 | 23 | # Check YAML file syntax 24 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking yaml syntax for $module_path...$(tput sgr0)" 25 | if type yamllint > /dev/null 2>&1; then 26 | yamllint $YAMLLINT_CONFIG -f parsable $1 &> "$error_msg" 27 | else 28 | ruby -e "require 'yaml'; YAML.parse(File.open('$1'))" 2> "$error_msg" > /dev/null 29 | fi 30 | # prepare output 31 | if [ $? -ne 0 ]; then 32 | sed -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" "$error_msg" 33 | syntax_errors=$((syntax_errors + 1)) 34 | echo -e "$(tput setaf 1)Error: yaml syntax error in $module_path (see above)$(tput sgr0)" 35 | fi 36 | rm -f "$error_msg" 37 | 38 | if [[ $syntax_errors -ne 0 ]]; then 39 | echo -e "$(tput setaf 1)Error: $syntax_errors syntax error(s) found in hiera yaml. Commit will be aborted.$(tput sgr0)" 40 | exit 1 41 | fi 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /commit_hooks/puppet_epp_syntax_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script expects $1 to be passed and for $1 to be the filesystem location 4 | # to a puppet epp template file for which it will run syntax checks against. 5 | 6 | epp_template_path="$1" 7 | module_dir="$2" 8 | 9 | syntax_errors=0 10 | error_msg=$(mktemp /tmp/error_msg_puppet-syntax.XXXXX) 11 | 12 | if [ $module_dir ]; then 13 | epp_template_name=$(echo $epp_template_path | sed -e 's|'$module_dir'||') 14 | error_msg_filter="sed -e s|$module_dir||" 15 | else 16 | epp_template_name="$epp_template_path" 17 | error_msg_filter="sed" 18 | fi 19 | 20 | # Get list of new/modified epp template and template files to check (in git index) 21 | # Check puppet epp template syntax 22 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking puppet epp template syntax for $epp_template_name...$(tput sgr0)" 23 | puppet epp validate --color=false $1 > $error_msg 2>&1 24 | if [ $? -ne 0 ]; then 25 | syntax_errors=`expr $syntax_errors + 1` 26 | cat $error_msg | $error_msg_filter -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" 27 | echo -e "$(tput setaf 1)Error: puppet syntax error in $epp_template_name (see above)$(tput sgr0)" 28 | fi 29 | rm -f $error_msg 30 | 31 | if [ "$syntax_errors" -ne 0 ]; then 32 | echo -e "$(tput setaf 1)Error: $syntax_errors syntax error(s) found in puppet epp templates. Commit will be aborted.$(tput sgr0)" 33 | exit 1 34 | fi 35 | 36 | exit 0 37 | -------------------------------------------------------------------------------- /commit_hooks/json_syntax_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script expects $1 to be passed and for $1 to be the filesystem location 4 | # to a json file for which it will run syntax checks against. 5 | 6 | syntax_errors=0 7 | error_msg=$(mktemp /tmp/error_msg_json-syntax.XXXXX) 8 | 9 | if [ $2 ]; then 10 | module_path=$(echo $1 | sed -e 's|'$2'||') 11 | else 12 | module_path=$1 13 | fi 14 | 15 | # Check json file syntax 16 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking json syntax for $module_path...$(tput sgr0)" 17 | ruby -e "require 'rubygems'; require 'json'; JSON.parse(File.read('$1'))" 2> $error_msg > /dev/null 18 | if [ $? -ne 0 ]; then 19 | cat $error_msg | sed -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" 20 | syntax_errors=`expr $syntax_errors + 1` 21 | echo -e "$(tput setaf 1)Error: json syntax error in $module_path (see above)$(tput sgr0)" 22 | fi 23 | rm -f $error_msg 24 | 25 | if which metadata-json-lint > /dev/null 2>&1; then 26 | if [[ "$(basename $1)" == 'metadata.json' ]]; then 27 | metadata-json-lint $1 2> $error_msg >&2 28 | if [ $? -ne 0 ]; then 29 | cat $error_msg | sed -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" 30 | syntax_errors=`expr $syntax_errors + 1` 31 | echo -e "$(tput setaf 1)Error: json syntax error in $module_path (see above)$(tput sgr0)" 32 | fi 33 | fi 34 | else 35 | echo "metadata-json-lint gem not installed. Skipping metadata-json-lint tests..." 36 | fi 37 | 38 | if [ "$syntax_errors" -ne 0 ]; then 39 | echo -e "$(tput setaf 1)Error: $syntax_errors syntax error(s) found in json file. Commit will be aborted.$(tput sgr0)" 40 | exit 1 41 | fi 42 | 43 | exit 0 44 | -------------------------------------------------------------------------------- /commit_hooks/rspec_puppet_checks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git_root=`git rev-parse --show-toplevel` 4 | syntax_errors=0 5 | error_msg=$(mktemp /tmp/error_msg_rspec-puppet.XXXXX) 6 | 7 | if [ $2 ]; then 8 | module_path=$(echo $1 | sed -e 's|'$2'||') 9 | else 10 | module_path=$1 11 | fi 12 | 13 | # Run rspec-puppet tests 14 | oldpwd=$(pwd) 15 | tmpchangedmodules='' 16 | #get a list of files changed under the modules directory so we can 17 | #sort/uniq them later 18 | for changedfile in `git diff --raw --cached --name-only --diff-filter=ACM | grep '^modules' | grep -E '\.pp$|\.rb$'`; do 19 | changeddir=$(dirname $changedfile | cut -d"/" -f1,2) 20 | tmpchangedmodules="$tmpchangedmodules\n$changeddir" 21 | done 22 | 23 | #sort/uniq so we only run rspec tests once 24 | changedmodules=$(echo -e "$tmpchangedmodules" | sort -u) 25 | 26 | 27 | #now that we have the list of modules that changed, run rspec for each module 28 | for module_dir in $changedmodules; do 29 | #only run rspec if the "spec" directory exists 30 | if [ -d "${module_dir}/spec" ]; then 31 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Running rspec-puppet tests for module $module_path...$(tput sgr0)" 32 | cd $module_dir 33 | #this will run rspec for every test in the module 34 | rspec > $error_msg 35 | RC=$? 36 | if [ $RC -ne 0 ]; then 37 | cat $error_msg | sed -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" 38 | echo -e "$(tput setaf 1)Error: rspec-puppet test(s) failed for $module_dir (see above)$(tput sgr0)" 39 | syntax_errors=`expr $syntax_errors + 1` 40 | fi 41 | fi 42 | done 43 | 44 | cd $oldpwd > /dev/null 45 | 46 | rm $error_msg 47 | 48 | if [ "$syntax_errors" -ne 0 ]; then 49 | echo -e "$(tput setaf 1)Error: $syntax_errors rspec-puppet test(s) failed. Commit will be aborted.$(tput sgr0)" 50 | exit 1 51 | fi 52 | 53 | exit 0 54 | -------------------------------------------------------------------------------- /commit_hooks/puppet_manifest_documentation_check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # This script expects $1 to be passed and for $1 to be the filesystem location 4 | # to a puppet manifest file for which it will run syntax checks against. 5 | 6 | CHECK_PUPPET_DOCS="$1" 7 | manifest_path="$2" 8 | module_dir="$3" 9 | USE_PUPPET_FUTURE_PARSER="$4" 10 | 11 | documentations_errors=0 12 | error_msg=$(mktemp /tmp/error_msg_puppet-docs.XXXXX) 13 | 14 | if [[ $module_dir ]]; then 15 | manifest_name="${manifest_path##*$module_dir}" 16 | error_msg_filter="sed -e s|$module_dir||" 17 | else 18 | manifest_name="$manifest_path" 19 | error_msg_filter="sed" 20 | fi 21 | 22 | # Get list of new/modified manifest and template files to check (in git index) 23 | # Check puppet manifest syntax 24 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking puppet documentation for $manifest_name...$(tput sgr0)" 25 | if [[ $USE_PUPPET_FUTURE_PARSER != "enabled" ]]; then 26 | puppet strings --color=false "$manifest_path" | grep -Eo -e '^\[warn\]:.*$' > "$error_msg" 27 | else 28 | puppet strings --parser future --color=false "$manifest_path" | grep -Eo -e '^\[warn\]:.*$' > "$error_msg" 29 | fi 30 | 31 | if [[ $? -ne 1 ]]; then 32 | documentations_errors=$((documentations_errors + 1)) 33 | $error_msg_filter -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" < "$error_msg" 34 | echo -e "$(tput setaf 1)Error: faulty puppet documentation in $manifest_name (see above)$(tput sgr0)" 35 | fi 36 | rm -f "$error_msg" 37 | 38 | if [[ $documentations_errors -ne 0 ]]; then 39 | if [[ $CHECK_PUPPET_DOCS == "permissive" ]] ; then 40 | echo -e "$(tput setaf 6)Documentation checks in permissive mode. Commit won't be aborted$(tput sgr0)" 41 | else 42 | echo -e "$(tput setaf 1)Error: $documentations_errors faulty documentation(s) found in puppet manifests. Commit will be aborted.$(tput sgr0)" 43 | exit 1 44 | fi 45 | fi 46 | 47 | exit 0 48 | -------------------------------------------------------------------------------- /post-update: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # This hook does two things: 4 | # 5 | # 1. update the "info" files that allow the list of references to be 6 | # queries over dumb transports such as http 7 | # 8 | # 2. if this repository looks like it is a non-bare repository, and 9 | # the checked-out branch is pushed to, then update the working copy. 10 | # This makes "push" function somewhat similarly to darcs and bzr. 11 | # 12 | # To enable this hook, make this file executable by "chmod +x post-update". 13 | 14 | git-update-server-info 15 | 16 | is_bare=$(git-config --get --bool core.bare) 17 | 18 | if [ -z "$is_bare" ] 19 | then 20 | # for compatibility's sake, guess 21 | git_dir_full=$(cd $GIT_DIR; pwd) 22 | case $git_dir_full in */.git) is_bare=false;; *) is_bare=true;; esac 23 | fi 24 | 25 | update_wc() { 26 | ref=$1 27 | echo "Push to checked out branch $ref" >&2 28 | if [ ! -f $GIT_DIR/logs/HEAD ] 29 | then 30 | echo "E:push to non-bare repository requires a HEAD reflog" >&2 31 | exit 1 32 | fi 33 | if (cd $GIT_WORK_TREE; git-diff-files -q --exit-code >/dev/null) 34 | then 35 | wc_dirty=0 36 | else 37 | echo "W:unstaged changes found in working copy" >&2 38 | wc_dirty=1 39 | desc="working copy" 40 | fi 41 | if git diff-index --cached HEAD@{1} >/dev/null 42 | then 43 | index_dirty=0 44 | else 45 | echo "W:uncommitted, staged changes found" >&2 46 | index_dirty=1 47 | if [ -n "$desc" ] 48 | then 49 | desc="$desc and index" 50 | else 51 | desc="index" 52 | fi 53 | fi 54 | if [ "$wc_dirty" -ne 0 -o "$index_dirty" -ne 0 ] 55 | then 56 | new=$(git rev-parse HEAD) 57 | echo "W:stashing dirty $desc - see git-stash(1)" >&2 58 | ( trap 'echo trapped $$; git symbolic-ref HEAD "'"$ref"'"' 2 3 13 15 ERR EXIT 59 | git-update-ref --no-deref HEAD HEAD@{1} 60 | cd $GIT_WORK_TREE 61 | git stash save "dirty $desc before update to $new"; 62 | git-symbolic-ref HEAD "$ref" 63 | ) 64 | fi 65 | 66 | # eye candy - show the WC updates :) 67 | echo "Updating working copy" >&2 68 | (cd $GIT_WORK_TREE 69 | git-diff-index -R --name-status HEAD >&2 70 | git-reset --hard HEAD) 71 | } 72 | 73 | if [ "$is_bare" = "false" ] 74 | then 75 | active_branch=`git-symbolic-ref HEAD` 76 | export GIT_DIR=$(cd $GIT_DIR; pwd) 77 | GIT_WORK_TREE=${GIT_WORK_TREE-..} 78 | for ref 79 | do 80 | if [ "$ref" = "$active_branch" ] 81 | then 82 | update_wc $ref 83 | fi 84 | done 85 | fi 86 | 87 | if ! /usr/bin/puppet --noop $GIT_WORK_TREE/manifests/site.pp --parseonly 88 | then 89 | echo 1>&2 90 | echo 1>&2 91 | echo 1>&2 92 | echo "ATTENTION!! YOU JUST BROKE PUPPET WITH THAT LAST COMMIT" 1>&2 93 | echo "Please see the above error and correct it!" 1>&2 94 | echo 1>&2 95 | exit 1 96 | fi 97 | -------------------------------------------------------------------------------- /commit_hooks/puppet_lint_checks.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # $1 is the puppet-lint mode (enabled, permissive, disabled) 4 | # This script expects $2 to be passed and for $2 to be the filesystem location 5 | # to a puppet manifest file for which it will run style guide checks against. 6 | 7 | CHECK_PUPPET_LINT="$1" 8 | manifest_path="$2" 9 | module_dir="$3" 10 | 11 | syntax_errors=0 12 | error_msg="$(mktemp /tmp/error_msg_puppet-lint.XXXXX)" 13 | 14 | opts=${PUPPET_LINT_OPTIONS:-"--no-140chars-check"} 15 | 16 | if [[ $module_dir ]]; then 17 | manifest_name="${manifest_path##*$module_dir}" 18 | error_msg_filter="sed -e s|$module_dir||" 19 | else 20 | manifest_name="$manifest_path" 21 | error_msg_filter="sed" 22 | fi 23 | 24 | # De-lint puppet manifests 25 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Checking puppet style guide compliance for ${manifest_name}...$(tput sgr0)" 26 | 27 | # Set the puppet lint option to fail on warnings if true. 28 | if [ "${PUPPET_LINT_FAIL_ON_WARNINGS}" = true ]; then 29 | puppet_lint_cmd="puppet-lint --fail-on-warnings --with-filename --relative" 30 | elif [ "${PUPPET_LINT_FAIL_ON_WARNINGS}" = false ]; then 31 | puppet_lint_cmd="puppet-lint --with-filename --relative" 32 | else 33 | echo "Configuration Option PUPPET_LINT_FAIL_ON_WARNINGS not set to a boolean value" 34 | exit 1 35 | fi 36 | 37 | # If a file named .puppet-lint.rc exists at the base of the repo then use it to 38 | # enable or disable checks. 39 | puppet_lint_rcfile="${3}.puppet-lint.rc" 40 | if [[ -f $puppet_lint_rcfile ]]; then 41 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Applying custom config from ${puppet_lint_rcfile}$(tput sgr0)" 42 | puppet_lint_cmd="$puppet_lint_cmd --config $puppet_lint_rcfile" 43 | else 44 | puppet_lint_cmd="$puppet_lint_cmd $opts" 45 | fi 46 | 47 | # If a file named .puppet-lint.rc exists in the directory where the file is located 48 | # enable or disable checks. 49 | puppet_lint_rcfile="$(dirname "$manifest_name")/.puppet-lint.rc" 50 | if [[ -f $puppet_lint_rcfile ]]; then 51 | $ERRORS_ONLY || echo -e "$(tput setaf 6)Applying custom config from ${puppet_lint_rcfile}$(tput sgr0)" 52 | puppet_lint_cmd="$puppet_lint_cmd --config $puppet_lint_rcfile" 53 | fi 54 | 55 | $puppet_lint_cmd "$2" 2>"$error_msg" >&2 56 | RC=$? 57 | if [[ $RC -ne 0 ]]; then 58 | syntax_errors=$(wc -l "$error_msg" | awk '{print $1}') 59 | $error_msg_filter -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" < "$error_msg" 60 | echo -e "$(tput setaf 1)Error: styleguide violation in $manifest_name (see above)$(tput sgr0)" 61 | elif [[ -s $error_msg ]]; then 62 | $error_msg_filter -e "s/^/$(tput setaf 3)/" -e "s/$/$(tput sgr0)/" < "$error_msg" 63 | echo -e "$(tput setaf 1)Warning: styleguide violation in $manifest_name (see above)$(tput sgr0)" 64 | fi 65 | rm -f "$error_msg" 66 | 67 | if [[ $syntax_errors -ne 0 ]]; then 68 | if [[ $CHECK_PUPPET_LINT == "permissive" ]] ; then 69 | echo -e "$(tput setaf 6)Puppet-lint run in permissive mode. Commit won't be aborted$(tput sgr0)" 70 | else 71 | echo -e "Error: $syntax_errors styleguide violation(s) found. Commit will be aborted. 72 | Please follow the puppet style guide outlined at: 73 | http://docs.puppetlabs.com/guides/style_guide.html" | sed -e "s/^/$(tput setaf 1)/" -e "s/$/$(tput sgr0)/" 74 | exit 1 75 | fi 76 | fi 77 | 78 | exit 0 79 | -------------------------------------------------------------------------------- /update: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # An hook script to mail out commit update information. 4 | # Called by git-receive-pack with arguments: refname sha1-old sha1-new 5 | # 6 | # To enable this hook: 7 | # (1) change the recipient e-mail address 8 | # (2) make this file executable by "chmod +x update". 9 | # 10 | 11 | project=$(cat $GIT_DIR/description) 12 | [ -f $GIT_DIR/commit-list ] && recipients=$(cat $GIT_DIR/commit-list) 13 | [ -n "$recipients" ] || exit 0 14 | 15 | ref_type=$(git cat-file -t "$3") 16 | 17 | # Only allow annotated tags in a shared repo 18 | # Remove this code to treat dumb tags the same as everything else 19 | # case "$1","$ref_type" in 20 | # refs/tags/*,commit) 21 | # echo "*** Un-annotated tags are not allowed in this repo" >&2 22 | # echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." 23 | # exit 1;; 24 | # refs/tags/*,tag) 25 | # echo "### Pushing version '${1##refs/tags/}' to the masses" >&2 26 | # # recipients="release-announce@somwehere.com announce@somewhereelse.com" 27 | # ;; 28 | # esac 29 | 30 | # set this to 'cat' to get a very detailed listing. 31 | # short only kicks in when an annotated tag is added 32 | short='git shortlog' 33 | 34 | # see 'date --help' for info on how to write this 35 | # The default is a human-readable iso8601-like format with minute 36 | # precision ('2006-01-25 15:58 +0100' for example) 37 | date_format="%F %R %z" 38 | 39 | # Set to the number of pathname components you want in the subject line to 40 | # indicate which components of a project changed. 41 | num_path_components=2 42 | 43 | # Set subject 44 | (if expr "$2" : '0*$' >/dev/null ; then 45 | subject="Changes to '${1##refs/heads/}'" 46 | echo "Subject: $subject" 47 | else 48 | base=$(git-merge-base "$2" "$3") 49 | subject=$(git-diff-tree -r --name-only "$base" "$3" | 50 | cut -d/ -f-$num_path_components | sort -u | xargs echo -n) 51 | commits=$(git-rev-list "$3" "^$base" | wc -l) 52 | if [ "$commits" -ne 1 ] ; then 53 | subject="$commits commits - $subject" 54 | fi 55 | branch="${1##refs/heads/}" 56 | if [ "$branch" != "master" ] ; then 57 | subject="Branch '$branch' - $subject" 58 | fi 59 | echo "Subject: $subject" 60 | fi 61 | 62 | echo "To: $recipients" 63 | echo "X-Project: $project" 64 | module=$(basename `readlink -f $GIT_DIR`) 65 | echo "X-Git-Module: $module" 66 | echo "" 67 | 68 | if expr "$2" : '0*$' >/dev/null 69 | then 70 | # new ref 71 | case "$1" in 72 | refs/tags/*) 73 | # a pushed and annotated tag (usually) means a new version 74 | tag="${1##refs/tags/}" 75 | if [ "$ref_type" = tag ]; then 76 | tagger=$(git cat-file tag $3 | \ 77 | sed -n '4s/tagger \([^>]*>\)[^0-9]*\([0-9]*\).*/\1/p') 78 | ts=$(git cat-file tag $3 | \ 79 | sed -n '4s/tagger \([^>]*>\)[^0-9]*\([0-9]*\).*/\2/p') 80 | date=$(date --date="1970-01-01 00:00:00 $ts seconds" +"$date_format") 81 | echo "Tag '$tag' created by $tagger at $date" 82 | git cat-file tag $3 | sed -n '5,$p' 83 | echo 84 | fi 85 | prev=$(git describe "$3^" | sed 's/-g.*//') 86 | # the first tag in a repo will yield no $prev 87 | if [ -z "$prev" ]; then 88 | echo "Changes since the dawn of time:" 89 | git rev-list --pretty $3 | $short 90 | else 91 | echo "Changes since $prev:" 92 | git rev-list --pretty $prev..$3 | $short 93 | echo --- 94 | git diff $prev..$3 | diffstat -p1 95 | echo --- 96 | fi 97 | ;; 98 | 99 | refs/heads/*) 100 | branch="${1##refs/heads/}" 101 | echo "New branch '$branch' available with the following commits:" 102 | git-rev-list --pretty "$3" $(git-rev-parse --not --all) 103 | ;; 104 | esac 105 | else 106 | case "$base" in 107 | "$2") 108 | git diff "$3" "^$base" | diffstat -p1 109 | echo 110 | echo "New commits:" 111 | ;; 112 | *) 113 | echo "Rebased ref, commits from common ancestor:" 114 | ;; 115 | esac 116 | git-rev-list "$3" "^$base" | while read rev; do git-show $rev; echo ""; echo ""; done 117 | fi) | /usr/local/bin/send-unicode-email.py $recipients 118 | exit 0 119 | 120 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | puppet-git-hooks 2 | ================ 3 | 4 | Git hooks to assist puppet module development. Client side hooks allow for 5 | various checks before commits are staged. Server side hooks are provided 6 | for infrastructural reinforcement of various standardization compliances. 7 | 8 | Current supported pre-commit (client side) checks 9 | ================================================= 10 | 11 | * Puppet manifest syntax 12 | * Puppet epp template syntax 13 | * Erb template syntax 14 | * Puppet-lint 15 | * Rspec-puppet 16 | * Yaml (hiera data) syntax 17 | * r10k puppetfile syntax 18 | 19 | Current supported pre-receive (server side) checks 20 | ================================================== 21 | 22 | * Puppet manifest syntax 23 | * Puppet epp template syntax 24 | * Erb template syntax 25 | * Ruby syntax 26 | * Puppet-lint 27 | * Yaml (hiera data) syntax 28 | 29 | Installing dependencies 30 | ======================= 31 | 32 | You can install all required dependencies with bundler. List of dependencies 33 | you will find in `Gemfile`. By default it installs puppet in version 3.8.6, 34 | if you wish, change it to one, which you use. To install run bundler inside 35 | your checkout: 36 | 37 | ```bash 38 | bundle install 39 | ``` 40 | 41 | Usage 42 | ===== 43 | 44 | In your git repository you can symlink the pre-commit file from this 45 | repository to the .git/hooks/pre-commit of your repository you want to 46 | implement this feature. 47 | 48 | ```bash 49 | $ ln -s /path/to/this/repo/puppet-git-hooks/pre-commit .git/hooks/pre-commit 50 | ``` 51 | 52 | If you are using git submodules this can be achieved by getting the gitdir 53 | from the .git file in your submodule and symlinking to that gitdir location/ 54 | 55 | ```bash 56 | $ cat .git 57 | $ ln -s /path/to/this/repo/puppet-git-hooks/pre-commit ../path/to/git/dir/from/previous/command/hooks/pre-commit 58 | ``` 59 | 60 | deploy-git-hook 61 | =============== 62 | 63 | usage: deploy-git-hook -d /path/to/git/repository [-a] [-c] [-r] [-u] 64 | 65 | -h this help screen 66 | -d path install the hooks to the specified path 67 | -a deploy pre-commit and pre-receive hooks 68 | -c deploy only the pre-commit hook 69 | -r deploy only the pre-receive hook 70 | -u deploy only the post-update hook 71 | -g enable to install in Git Lab repo custom_hooks 72 | 73 | returns status code of 0 for success, otherwise, failure 74 | 75 | examples: 76 | 77 | 1) to install pre-commit and pre-receive the hooks to foo git repo: 78 | 79 | deploy-git-hook -d /path/to/foo -a 80 | 81 | 2) to install only the pre-commit hook to bar git repo: 82 | 83 | deploy-git-hook -d /path/to/bar -c 84 | 85 | 3) to install only the pre-commit and pre-receive hook to foobar git repo: 86 | 87 | deploy-git-hook -d /path/to/foobar -c -r 88 | 89 | In a wrapper 90 | =============== 91 | You can call from your own custom pre-commit. This allows you to combine 92 | these with your own checks. 93 | 94 | For example, if you've cloned this repo to ~/.puppet-git-hooks 95 | 96 | 97 | The .git/hooks/pre-commit with your puppet code might look like this: 98 | 99 | ```bash 100 | #!/bin/bash 101 | 102 | # my_other_checks 103 | 104 | # puppet-git-hooks 105 | if [ -e ~/.puppet-git-hooks/pre-commit ]; then 106 | ~/.puppet-git-hooks/pre-commit 107 | fi 108 | ``` 109 | 110 | Additionally you can call pre-commit script with two options `-s` and `-a`. 111 | First one silence standard informations, which file is currently being 112 | checked. Second one allow you to check whole repo, not only files changed 113 | locally. 114 | 115 | Configuration 116 | =============== 117 | You can set configuration options in commit_hooks/config.cfg 118 | This file is sourced by the pre-commit/receive hooks. 119 | 120 | Current options: 121 | * CHECK_PUPPET_LINT 122 | * USE_PUPPET_FUTURE_PARSER (only used by Puppet < 4) 123 | * CHECK_INITIAL_COMMIT 124 | * CHECK_RSPEC 125 | * PUPPET_LINT_OPTIONS 126 | * PUPPET_LINT_FAIL_ON_WARNINGS 127 | * UNSET_RUBY_ENV (for GitLab users) 128 | 129 | Maintainers 130 | =========== 131 | 132 | * [David Wahlstrom](https://github.com/drwahl) 133 | * [Paweł Szczepaniak](https://github.com/krzyzakp) 134 | 135 | We are still looking for additional maintainers. Please contact me via 136 | [github issue](https://github.com/drwahl/puppet-git-hooks/issues/new) 137 | if you are interested in helping maintain this project. Thank you! 138 | 139 | -------------------------------------------------------------------------------- /deploy-git-hook: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | usage() { 4 | cat <<-EOF 5 | usage: ${0} -d /path/to/git/repository [-a] [-c] [-r] [-u] 6 | 7 | -h this help screen 8 | -d path install the hooks to the specified path 9 | -a deploy pre-commit and pre-receive hooks 10 | -c deploy only the pre-commit hook 11 | -r deploy only the pre-receive hook 12 | -u deploy only the post-update hook 13 | -g enable to install in Git Lab repo custom_hooks 14 | -l enable to install in Gitolite 3.6+ repo-specific hooks 15 | -b enable to install in Stash/BitBucket Server [pre/post]-receive.d 16 | 17 | returns status code of 0 for success, otherwise, failure 18 | 19 | examples: 20 | 21 | 1) to install pre-commit and pre-receive the hooks to foo git repo: 22 | 23 | ${0} -d /path/to/foo -a 24 | 25 | 2) to install only the pre-commit hook to bar git repo: 26 | 27 | ${0} -d /path/to/bar -c 28 | 29 | 3) to install only the pre-commit and pre-receive hook to foobar git repo: 30 | 31 | ${0} -d /path/to/foobar -c -r 32 | 33 | EOF 34 | } 35 | 36 | while getopts ":d:abcghlru" opt; do 37 | case $opt in 38 | a) 39 | INST_COMMIT=1 40 | INST_RECEIVE=1 41 | ;; 42 | b) 43 | BITBUCKET_REPO=1 44 | ;; 45 | c) 46 | INST_COMMIT=1 47 | ;; 48 | d) 49 | GIT_REPO="$OPTARG" 50 | ;; 51 | g) 52 | GITLAB_REPO=1 53 | ;; 54 | h) 55 | usage 56 | exit -1 57 | ;; 58 | l) 59 | GITOLITE_REPO=1 60 | ;; 61 | r) 62 | INST_RECEIVE=1 63 | ;; 64 | u) 65 | INST_UPDATE=1 66 | ;; 67 | \?) 68 | echo "Invalid option: -$OPTARG" >&2 69 | usage 70 | ;; 71 | esac 72 | done 73 | 74 | # We need at least one hook to deploy 75 | if [[ -z "${INST_COMMIT}" \ 76 | && -z "${INST_RECEIVE}" \ 77 | && -z "${INST_UPDATE}" ]]; then 78 | echo "Error: You must specify at least one hook to deploy" >&2 79 | usage 80 | exit -2 81 | fi 82 | 83 | # We need to have a git repository specified 84 | if [ -z "${GIT_REPO}" ]; then 85 | echo "Error: No repository specified" >&2 86 | usage 87 | exit -3 88 | fi 89 | 90 | # Validate the provided repository is a gitolite repository 91 | if [ "${GITOLITE_REPO}" = "1" ]; then 92 | if [ ! -f "${GIT_REPO}/conf/gitolite.conf" ]; then 93 | echo "Error: Not a gitolite admin repository" >&2 94 | exit -7 95 | fi 96 | fi 97 | 98 | # Check if the repo specified is a submodule 99 | if [ -f "${GIT_REPO}/.git" ]; then 100 | SUBMODULE_REPO=$(cat "${GIT_REPO}/.git" | grep 'gitdir' | awk '{print $2}') 101 | GIT_REPO="$(cd "${GIT_REPO}" ; cd "${SUBMODULE_REPO}" ; pwd)" 102 | elif [ "${BITBUCKET_REPO}" = "1" ]; then 103 | GIT_REPO="${GIT_REPO}" 104 | elif [ -f "${GIT_REPO}/hooks" ]; then 105 | # This is for bare repos 106 | GIT_REPO="${GIT_REPO}" 107 | else 108 | GIT_REPO="${GIT_REPO}/.git" 109 | fi 110 | 111 | GIT_REPO=$(cd "${GIT_REPO}" ; pwd) 112 | 113 | # Make sure the repo specified is valid, submodule or normal 114 | if [[ -n "${SUBMODULE_REPO}" && ! -d "${GIT_REPO}" ]]; then 115 | echo "Error: Submodule not a valid repository" >&2 116 | exit -3 117 | elif [[ -z "${SUBMODULE_REPO}" && ! -d "${GIT_REPO}" ]]; then 118 | echo "Error: Not a valid repository" >&2 119 | exit -3 120 | fi 121 | 122 | # Cleanup the hooks directory so it works properly 123 | HOOKS_DIR=$(dirname "${0}") 124 | HOOKS_DIR=$(cd "${HOOKS_DIR}" ; pwd) 125 | 126 | # Check if it's Git Lab, needs to go into custom_hooks 127 | if [ "${GITLAB_REPO}" = "1" ]; then 128 | REAL_HOOKS_DIR="custom_hooks" 129 | # Check if it's Gitolite, needs repo-specific hook directory 130 | elif [ "${GITOLITE_REPO}" = "1" ]; then 131 | REAL_HOOKS_DIR="../local/hooks/repo-specific" 132 | else 133 | REAL_HOOKS_DIR="hooks" 134 | fi 135 | 136 | # Make sure the hooks directory exists -- mainly for Git Lab and Gitolite 137 | if [ ! -d "${GIT_REPO}/${REAL_HOOKS_DIR}" ]; then 138 | mkdir -p "${GIT_REPO}/${REAL_HOOKS_DIR}" 139 | fi 140 | 141 | # Install the hooks! 142 | if [ "${GITOLITE_REPO}" = "1" ]; then 143 | if [ "${INST_COMMIT}" = "1" ]; then 144 | echo "Error: pre-commit hooks outside of Gitolite's scope, use non-gitolite arguments to local repo" >&2 145 | exit -8 146 | fi 147 | 148 | # Do real copies instead of symlinks in order to not require submodules 149 | # Change naming on files to be more descriptive for gitolite configuration and prevent possible naming collision 150 | if [ "${INST_RECEIVE}" = "1" ]; then 151 | cp -f "${HOOKS_DIR}/pre-receive" "${GIT_REPO}/${REAL_HOOKS_DIR}/puppet-git-hooks.pre-receive" \ 152 | && cp -rf "${HOOKS_DIR}/commit_hooks" "${GIT_REPO}/${REAL_HOOKS_DIR}/" \ 153 | && echo "pre-receive hook deployed successfully" \ 154 | || ( echo "pre-receive hook failed to deploy to gitolite repo" >&2 ; exit -9 ) 155 | fi 156 | 157 | if [ "${INST_UPDATE}" = "1" ]; then 158 | cp -f "${HOOKS_DIR}/post-update" "${GIT_REPO}/${REAL_HOOKS_DIR}/puppet-git-hooks.post-update" \ 159 | && echo "post-update hook deployed successfully" \ 160 | || ( echo "post-update hook failed to deploy to gitolite repo" >&2 ; exit -10 ) 161 | fi 162 | else 163 | if [ "${INST_COMMIT}" = "1" ]; then 164 | ln -sf "${HOOKS_DIR}/pre-commit" "${GIT_REPO}/${REAL_HOOKS_DIR}/pre-commit" \ 165 | && echo "pre-commit hook deployed successfully" \ 166 | || ( echo "pre-commit hook failed to deploy" >&2 ; exit -4 ) 167 | fi 168 | 169 | if [ "${INST_RECEIVE}" = "1" ]; then 170 | if [ "${BITBUCKET_REPO}" = "1" ]; then 171 | # Use pre-receive.d directory and 'full' name for BitBucket 172 | ln -sf "${HOOKS_DIR}/pre-receive" "${GIT_REPO}/${REAL_HOOKS_DIR}/pre-receive.d/puppet-git-hooks-pre-receive" \ 173 | && echo "pre-receive hook deployed successfully" \ 174 | || ( echo "pre-receive hook failed to deploy" >&2 ; exit -5 ) 175 | else 176 | ln -sf "${HOOKS_DIR}/pre-receive" "${GIT_REPO}/${REAL_HOOKS_DIR}/pre-receive" \ 177 | && echo "pre-receive hook deployed successfully" \ 178 | || ( echo "pre-receive hook failed to deploy" >&2 ; exit -5 ) 179 | fi 180 | fi 181 | 182 | if [ "${INST_UPDATE}" = "1" ]; then 183 | ln -sf "${HOOKS_DIR}/post-update" "${GIT_REPO}/${REAL_HOOKS_DIR}/post-update" \ 184 | && echo "post-update hook deployed successfully" \ 185 | || ( echo "post-update hook failed to deploy" >&2 ; exit -6 ) 186 | fi 187 | fi 188 | -------------------------------------------------------------------------------- /pre-receive: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Puppet attempts to source ~/.puppet and will error if $HOME is not set 4 | if [[ -z $HOME ]] 5 | then 6 | HOME="$(getent passwd "${USER}" | awk -F ':' '{print $6}')" 7 | export HOME 8 | fi 9 | 10 | failures=0 11 | RC=0 12 | 13 | hook_dir="$(dirname "$0")" 14 | hook_symlink="$(readlink -f "$0")" 15 | 16 | # Figure out where commit hooks are if pre-receive is setup as a symlink 17 | if [[ ! -z "$hook_symlink" ]]; then 18 | subhook_root="$(dirname "$hook_symlink")/commit_hooks" 19 | else 20 | subhook_root="$hook_dir/commit_hooks" 21 | fi 22 | 23 | tmptree=$(mktemp -d) 24 | 25 | # Prevent tput from throwing an error by ensuring that $TERM is always set 26 | if [[ -z "$TERM" ]]; then 27 | TERM=dumb 28 | fi 29 | export TERM 30 | 31 | # Decide if we want puppet-lint 32 | # Decide if we want the puppet future parser (already on puppet 4?) 33 | CHECK_PUPPET_LINT="enabled" 34 | USE_PUPPET_FUTURE_PARSER="enabled" 35 | CHECK_INITIAL_COMMIT="disabled" 36 | if [[ -e ${subhook_root}/config.cfg ]] ; then 37 | source "${subhook_root}/config.cfg" 38 | fi 39 | 40 | # This is required for GitLab 41 | # See https://github.com/drwahl/puppet-git-hooks/issues/76 42 | if [[ $UNSET_RUBY_ENV == "enabled" ]] ; then 43 | unset BUNDLE_GEMFILE RUBYLIB RUBYOPT GEM_HOME 44 | fi 45 | 46 | # Only puppet 3.2.1 - 3.8 support "--parser future" option. 47 | if [[ "$USE_PUPPET_FUTURE_PARSER" == "enabled" ]]; then 48 | case $(puppet --version) in 49 | 3.2.[1-9]) ;; 50 | 3.[3-8]*) ;; 51 | *) USE_PUPPET_FUTURE_PARSER="disabled" ;; 52 | esac 53 | fi 54 | 55 | while read -r oldrev newrev refname; do 56 | git archive "$newrev" | tar x -C "$tmptree" 57 | 58 | # for a new branch oldrev is 0{40}, set oldrev to the commit where we branched off the parent 59 | if [[ $oldrev == "0000000000000000000000000000000000000000" ]]; then 60 | oldrev=$(git rev-list --boundary $newrev --not --all | sed -n 's/^-//p') 61 | fi 62 | 63 | files_list='' 64 | if [[ "x$oldrev" == 'x' ]]; then 65 | if [[ $CHECK_INITIAL_COMMIT != "disabled" ]] ; then 66 | files_list=$(git ls-tree --full-tree -r HEAD --name-only) 67 | else 68 | echo "Skipping file checks this is the initial commit..." 69 | fi 70 | else 71 | files_list=$(git diff --name-only "$oldrev" "$newrev" --diff-filter=ACM) 72 | fi 73 | 74 | for changedfile in $files_list; do 75 | tmpmodule="$tmptree/$changedfile" 76 | [[ -f "$tmpmodule" ]] || continue 77 | #check puppet manifest syntax 78 | if type puppet >/dev/null 2>&1; then 79 | if [[ $(echo "$changedfile" | grep -q '\.*\.epp$'; echo $?) -eq 0 ]]; then 80 | ${subhook_root}/puppet_epp_syntax_check.sh "$tmpmodule" "${tmptree}/" 81 | RC=$? 82 | if [[ $RC -ne 0 ]]; then 83 | failures=$((failures + 1)) 84 | fi 85 | elif [[ $(echo "$changedfile" | grep -q '\.*\.pp$'; echo $?) -eq 0 ]]; then 86 | ${subhook_root}/puppet_manifest_syntax_check.sh "$tmpmodule" "${tmptree}/" "$USE_PUPPET_FUTURE_PARSER" 87 | RC=$? 88 | if [[ $RC -ne 0 ]]; then 89 | failures=$((failures + 1)) 90 | fi 91 | fi 92 | else 93 | echo "puppet not installed. Skipping puppet syntax checks..." 94 | fi 95 | 96 | if type ruby >/dev/null 2>&1; then 97 | #check ruby syntax 98 | if [[ $(echo "$changedfile" | grep -q '\.*\.rb$'; echo $?) -eq 0 ]]; then 99 | ${subhook_root}/ruby_syntax_check.sh "$tmpmodule" "${tmptree}/" 100 | RC=$? 101 | if [[ $RC -ne 0 ]]; then 102 | failures=$((failures + 1)) 103 | fi 104 | fi 105 | 106 | #check erb (template file) syntax 107 | if type erb >/dev/null 2>&1; then 108 | if [[ $(echo "$changedfile" | grep -q '\.*\.erb$'; echo $?) -eq 0 ]]; then 109 | ${subhook_root}/erb_template_syntax_check.sh "$tmpmodule" "${tmptree}/" 110 | RC=$? 111 | if [[ $RC -ne 0 ]]; then 112 | failures=$((failures + 1)) 113 | fi 114 | fi 115 | else 116 | echo "erb not installed. Skipping erb template checks..." 117 | fi 118 | 119 | #check hiera data (json) syntax 120 | if [[ $(echo "$changedfile" | grep -q '\.*\.json$'; echo $?) -eq 0 ]]; then 121 | ${subhook_root}/json_syntax_check.sh "$tmpmodule" "${tmptree}/" 122 | RC=$? 123 | if [[ $RC -ne 0 ]]; then 124 | failures=$((failures + 1)) 125 | fi 126 | fi 127 | else 128 | echo "ruby not installed. Skipping ruby/erb/json checks..." 129 | fi 130 | 131 | if type yamllint >/dev/null 2>&1 || type ruby >/dev/null 2>&1; then 132 | #check hiera data (yaml/yml/eyaml/eyml) syntax 133 | if echo "$changedfile" | grep -iq '\.e\?ya\?ml$'; then 134 | ${subhook_root}/yaml_syntax_check.sh "$tmpmodule" "${tmptree}/" 135 | RC=$? 136 | if [[ $RC -ne 0 ]]; then 137 | failures=$((failures + 1)) 138 | fi 139 | fi 140 | else 141 | echo "yamllint nor ruby not installed. Skipping yaml checks..." 142 | fi 143 | 144 | #puppet manifest styleguide compliance 145 | if [[ $CHECK_PUPPET_LINT != "disabled" ]] ; then 146 | if type puppet-lint >/dev/null 2>&1; then 147 | if [[ $(echo "$changedfile" | grep -q '\.*\.pp$' ; echo $?) -eq 0 ]]; then 148 | ${subhook_root}/puppet_lint_checks.sh "$CHECK_PUPPET_LINT" "$tmpmodule" "${tmptree}/" 149 | RC=$? 150 | if [[ $RC -ne 0 ]]; then 151 | failures=$((failures + 1)) 152 | fi 153 | fi 154 | else 155 | echo "puppet-lint not installed. Skipping puppet-lint tests..." 156 | fi 157 | fi 158 | #r10k puppetfile syntax check 159 | if [[ "$CHECK_R10K" != "disabled" ]] ; then 160 | if hash r10k >/dev/null 2>&1; then 161 | if [[ "$changedfile" = "Puppetfile" ]]; then 162 | "${subhook_root}/r10k_syntax_check.sh" "$tmptree/$changedfile" 163 | RC=$? 164 | if [[ "$RC" -ne 0 ]]; then 165 | failures=$((failures + 1)) 166 | fi 167 | fi 168 | else 169 | echo "r10k not installed. Skipping r10k Puppetfile test..." 170 | fi 171 | fi 172 | done 173 | done 174 | rm -rf "$tmptree" 175 | 176 | #summary 177 | if [[ $failures -ne 0 ]]; then 178 | echo -e "$(tput setaf 1)Error: $failures subhooks failed. Declining push.$(tput sgr0)" 179 | exit 1 180 | fi 181 | 182 | exit 0 183 | -------------------------------------------------------------------------------- /pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | TERM=${TERM:-unknown}; export TERM 4 | 5 | git_root=$(git rev-parse --show-toplevel) 6 | failures=0 7 | RC=0 8 | 9 | hook_dir="$(dirname "$0")" 10 | hook_symlink="$(readlink "$0")" 11 | 12 | # Manage arguments passed to script 13 | while getopts ":a" o; do 14 | case "${o}" in 15 | a) 16 | CHECK_ALL=true;; 17 | s) 18 | export ERRORS_ONLY=true;; 19 | esac 20 | done 21 | 22 | # Figure out where commit hooks are 23 | if [[ ! -z "$hook_symlink" ]] && ! [[ "$hook_symlink" == ../* ]]; then 24 | #pre-commit is setup as a symlink 25 | subhook_root="$(dirname "$hook_symlink")/commit_hooks" 26 | else 27 | #commit_hooks should be with pre-commit 28 | subhook_root="${hook_dir}/commit_hooks" 29 | fi 30 | 31 | # If using submodules, we need to read proper subhook root 32 | if [[ -f "${git_root}/.git" ]]; then 33 | IFS=": " 34 | while read -r name value 35 | do 36 | if [[ "$name" == "gitdir" ]]; then 37 | submodule_hookdir="$value" 38 | fi 39 | done < "${git_root}/.git" 40 | if [[ ! -z "$submodule_hookdir" ]]; then 41 | subhook_root="${git_root}/${submodule_hookdir}/hooks/commit_hooks" 42 | fi 43 | fi 44 | 45 | # Decide if we want puppet-lint 46 | CHECK_PUPPET_LINT=${CHECK_PUPPET_LINT:-"enabled"} 47 | if [[ -e ${subhook_root}/config.cfg ]] ; then 48 | source "${subhook_root}/config.cfg" 49 | fi 50 | 51 | # Only puppet 3.2.1 - 3.8 support "--parser future" option. 52 | if [[ "$USE_PUPPET_FUTURE_PARSER" == "enabled" ]]; then 53 | case $(puppet --version) in 54 | 3.2.[1-9]) ;; 55 | 3.[3-8]*) ;; 56 | *) USE_PUPPET_FUTURE_PARSER="disabled" ;; 57 | esac 58 | fi 59 | 60 | SAVEIFS=$IFS 61 | IFS=$(echo -en "\n\b") 62 | 63 | if [ $CHECK_ALL ]; then 64 | files_to_check=$(find "$git_root" -path "${git_root}/.git" -prune -o -print) 65 | else 66 | files_to_check=$(git diff --cached --name-only --diff-filter=ACM) 67 | fi 68 | 69 | # On cygwin/windows, puppet is a symlink to native puppet install, which needs windows paths. 70 | if [[ "$OSTYPE" == "cygwin" ]] && file -L $(which puppet) 2>/dev/null | grep -q 'DOS batch file' && type cygpath >/dev/null 2>&1; then 71 | USE_NATIVE="YES" 72 | fi 73 | for changedfile in $files_to_check; do 74 | [[ -f "$changedfile" ]] || continue 75 | if [ "$USE_NATIVE" == "YES" ]; then 76 | changedfile_native="`cygpath -w "$changedfile"`" 77 | else 78 | changedfile_native="$changedfile" 79 | fi 80 | #check puppet manifest syntax 81 | if type puppet >/dev/null 2>&1; then 82 | if echo "$changedfile" | grep -iq '\.epp$'; then 83 | ${subhook_root}/puppet_epp_syntax_check.sh "$changedfile" 84 | RC=$? 85 | if [[ "$RC" -ne 0 ]]; then 86 | failures=$((failures + 1)) 87 | fi 88 | elif echo "$changedfile" | grep -iq '\.pp$'; then 89 | ${subhook_root}/puppet_manifest_syntax_check.sh "$changedfile_native" "$USE_PUPPET_FUTURE_PARSER" 90 | RC=$? 91 | if [[ "$RC" -ne 0 ]]; then 92 | failures=$((failures + 1)) 93 | fi 94 | fi 95 | else 96 | echo "puppet not installed. Skipping puppet syntax checks..." 97 | fi 98 | 99 | if type ruby >/dev/null 2>&1; then 100 | #check erb (template file) syntax 101 | if type erb >/dev/null 2>&1; then 102 | if echo "$changedfile" | grep -iq '\.erb$'; then 103 | ${subhook_root}/erb_template_syntax_check.sh "$changedfile" 104 | RC=$? 105 | if [[ "$RC" -ne 0 ]]; then 106 | failures=$((failures + 1)) 107 | fi 108 | fi 109 | else 110 | echo "erb not installed. Skipping erb template checks..." 111 | fi 112 | 113 | #check json (i.e. metadata.json) syntax 114 | if echo "$changedfile" | grep -iq '\.json$'; then 115 | ${subhook_root}/json_syntax_check.sh "$changedfile" 116 | RC=$? 117 | if [[ "$RC" -ne 0 ]]; then 118 | failures=$((failures + 1)) 119 | fi 120 | fi 121 | else 122 | echo "ruby not installed. Skipping erb/json checks..." 123 | fi 124 | 125 | if type yamllint >/dev/null 2>&1 || type ruby >/dev/null 2>&1; then 126 | #check hiera data (yaml/yml/eyaml/eyml) syntax 127 | if echo "$changedfile" | grep -iq '\.e\?ya\?ml$'; then 128 | ${subhook_root}/yaml_syntax_check.sh "$changedfile" 129 | RC=$? 130 | if [[ "$RC" -ne 0 ]]; then 131 | failures=$((failures + 1)) 132 | fi 133 | fi 134 | else 135 | echo "yamllint nor ruby not installed. Skipping yaml checks..." 136 | fi 137 | 138 | #puppet manifest styleguide compliance 139 | if [[ "$CHECK_PUPPET_LINT" != "disabled" ]] ; then 140 | if type puppet-lint >/dev/null 2>&1; then 141 | if echo "$changedfile" | grep -iq '\.pp$'; then 142 | if [[ "$failures" -eq 0 ]]; then 143 | ${subhook_root}/puppet_lint_checks.sh "$CHECK_PUPPET_LINT" "$changedfile" 144 | RC=$? 145 | if [[ "$RC" -ne 0 ]]; then 146 | failures=$((failures + 1)) 147 | fi 148 | else 149 | echo "Skipping puppet-lint check due to prior errors." 150 | fi 151 | fi 152 | else 153 | echo "puppet-lint not installed. Skipping puppet-lint tests..." 154 | fi 155 | fi 156 | 157 | #puppet manifest documentation checks 158 | if [[ "$CHECK_PUPPET_DOCS" != "disabled" ]] ; then 159 | if puppet strings >/dev/null 2>&1; then 160 | if echo "$changedfile" | grep -iq '\.pp$'; then 161 | ${subhook_root}/puppet_manifest_documentation_check.sh "$CHECK_PUPPET_DOCS" "$changedfile" 162 | RC=$? 163 | if [[ "$RC" -ne 0 ]]; then 164 | failures=$((failures + 1)) 165 | fi 166 | fi 167 | else 168 | echo "puppet strings not installed. Skipping puppet documentation checks..." 169 | fi 170 | fi 171 | done 172 | IFS=$SAVEIFS 173 | 174 | #rspec test validation 175 | if [[ "$CHECK_RSPEC" != "disabled" ]] ; then 176 | if hash rspec >/dev/null 2>&1; then 177 | ${subhook_root}/rspec_puppet_checks.sh 178 | RC=$? 179 | if [[ "$RC" -ne 0 ]]; then 180 | failures=$((failures + 1)) 181 | fi 182 | else 183 | echo "rspec not installed. Skipping rspec-puppet tests..." 184 | fi 185 | fi 186 | 187 | #r10k puppetfile syntax check 188 | if [[ "$CHECK_R10K" != "disabled" ]] ; then 189 | if hash r10k >/dev/null 2>&1; then 190 | if [[ "$changedfile" = "Puppetfile" ]]; then 191 | "${subhook_root}/r10k_syntax_check.sh" 192 | RC=$? 193 | if [[ "$RC" -ne 0 ]]; then 194 | failures=$((failures + 1)) 195 | fi 196 | fi 197 | else 198 | echo "r10k not installed. Skipping r10k Puppetfile test..." 199 | fi 200 | fi 201 | 202 | #summary 203 | if [[ "$failures" -ne 0 ]]; then 204 | echo -e "$(tput setaf 1)Error: ${failures} subhooks failed. Please fix above errors.$(tput sgr0)" 205 | exit 1 206 | fi 207 | 208 | exit 0 209 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | {description} 294 | Copyright (C) {year} {fullname} 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | {signature of Ty Coon}, 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | --------------------------------------------------------------------------------