Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@robbat2
Last active April 4, 2019 22:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robbat2/28386d30a8d6810d5bbe3621c48110b4 to your computer and use it in GitHub Desktop.
Save robbat2/28386d30a8d6810d5bbe3621c48110b4 to your computer and use it in GitHub Desktop.
Makefile for git precommit
# Puppet validation & lint Makefile
# Copyright 2014-2015 Robin Johnson <robbat2@gentoo.org>
#
# Targets:
# all: does validate, lint, check-footer
# validate: runs validations on many filetypes
# lint: runs puppet-lint only
# check: alias for validate
# validate.${FILETYPE}: validate a specific filetype, eg validate.pp
#
# Validated file extensions:
# pp erb json rb yaml sudo
#
# Parameters:
# D="..." list of files to check
# Q=0 Normal output
# Q=1 Be extra quiet
# V=1 Be more verbose (shows each command)
# INCLUDE_SUBMODULE=1 Also check submodules
#
# This Makefile does try to go parallel wherever possible, running with a
# reasonable -j level is recommended.
#
# This makefile does NOT check submodule content by default.
#
# If you want to use this in a Git pre-commit hook, I suggest you do:
#------ CUT HERE AND REMOVE FIRST COLUMN: START --------
##!/bin/bash
#syntax_errors=0
#against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 # Empty tree
#git rev-parse --quiet --verify HEAD >/dev/null && against=HEAD
#CHANGES="$(git diff-index --diff-filter=AM --name-only --cached $against | tr '\n' ' ')"
#if [ -n "${CHANGES}" ]; then
# make -j -l4 --silent validate D="${CHANGES}"
# if [ "$?" -ne 0 ]
# then
# syntax_errors=$(($syntax_errors + 1))
# fi
#fi
#
## Whitespace check
#git diff-index --check --cached $against -- || syntax_errors=$(($syntax_errors + 1))
#
## Any other checks you want
#
#[ $syntax_errors -ne 0 ] && exit 1
# exit 0
#------ CUT HERE AND REMOVE FIRST COLUMN: END --------
ROOT_MAKEFILE = $(abspath $(lastword $(MAKEFILE_LIST)))
ROOT_DIR = $(dir $(ROOT_MAKEFILE))
CURRENT_DIR = $(notdir $(patsubst %/,%,$(dir $(mkfile_path))))
# Autogenerated files
AUTOGEN = hieradata/puppet/automated.yaml
PUPPET_VERSION := $(shell puppet --version)
PUPPET_PARSER_VALIDATE_PARSER_OPT = $(shell puppet parser validate --help)
LINT.PP_DISABLE_CHECKS := \
--no-80chars-check \
--no-documentation-check \
--no-arrow_alignment-check \
--no-140chars-check
LINT.PP_MAKE_OUTPUT_FORMAT = --log-format '%{path}:%{line}:%{KIND} %{message}'
ifdef LINT_LAZY
LINT.PP_DISABLE_CHECKS += \
--no-2sp_soft_tabs-check \
--no-arrow_alignment-check \
--no-double_quoted_strings-check \
--no-ensure_first_param-check \
--no-hard_tabs-check \
--no-only_variable_string-check \
--no-selector_inside_resource-check \
endif
LINT.PP = puppet-lint --fail-on-warnings \
$(LINT.PP_DISABLE_CHECKS) $(LINT.PP_MAKE_OUTPUT_FORMAT)
LINTFIX.PP = $(LINT.PP) --fix
VALIDATE.PP_OPTS = --color false --render-as s
# Puppet 2.x did not have it, and newer versions of Puppet 4 do not have it.
ifneq (,$(findstring --parser.,$(PUPPET_PARSER_VALIDATE_PARSER_OPT)))
VALIDATE.PP_OPTS += --parser future
endif
VALIDATE.PP = puppet parser validate $(VALIDATE.PP_OPTS)
CORRECT_VIM_FOOTER_SRCFILE = $(ROOT_DIR)/STYLE-GUIDE.md
ifneq (,$(wildcard $(CORRECT_VIM_FOOTER_SRCFILE)))
CORRECT_VIM_FOOTER_CMD := grep '^..vim:' $(CORRECT_VIM_FOOTER_SRCFILE)
CORRECT_VIM_FOOTER := $(shell $(CORRECT_VIM_FOOTER_CMD) )
endif
# quiet
Q := 0
Q_CMD := $(if $(filter 1,$(Q)),true,)
ECHO := $(Q_CMD) echo
MAKEOPT_Q := $(if $(filter 1,$(Q)),--no-print-directory,--print-directory)
# verbose
V := 0
V_CMD := $(if $(filter 0,$(V)),@,)
# Optionally validate all submodules
INCLUDE_SUBMODULE := 0
SUBMODULE_LIST = $(shell find -mindepth 2 -name .git -printf '%h\n' )
SUBMODULE_LIST_SUFFIX = $(addsuffix /%,$(SUBMODULE_LIST))
SUBMODULE_TRUE :=
SUBMODULE_FALSE := $(SUBMODULE_LIST_SUFFIX)
SUBMODULE_PATTERNS := $(if $(filter 1,$(INCLUDE_SUBMODULE)),$(SUBMODULE_TRUE),$(SUBMODULE_FALSE))
VALIDATE_EXT_AUTO := erb json pp rb yaml eyaml
VALIDATE_EXT_MANUAL := sudo
VALIDATE_EXT := $(VALIDATE_EXT_AUTO) $(VALIDATE_EXT_MANUAL)
VALIDATE_TARGETS := $(foreach v,$(VALIDATE_EXT),validate.$(v))
# VALIDATE_EXT_AUTO
FIND_ARGS := $(foreach v,$(VALIDATE_EXT_AUTO),-name '*.$(v)' -o) -false
D_ := $(shell find . $(FIND_ARGS))
D := $(filter-out $(SUBMODULE_PATTERNS),$(D_))
D_ERB := $(filter %.erb,$(D))
D_JSON := $(filter %.json,$(D))
D_PP := $(filter %.pp,$(D))
D_RB := $(filter %.rb,$(D))
D_YAML := \
$(filter %.yaml,$(D)) \
$(filter %.eyaml,$(D)) \
$(filter %.tmp-yaml,$(D)) \
$(filter %.tmp-eyaml,$(D))
# targets for each validated file
D_ERB_TARGETS := $(patsubst %,%.validate,$(D_ERB))
D_JSON_TARGETS := $(patsubst %,%.validate,$(D_JSON))
D_PP_LINT_TARGETS := $(patsubst %,%.lint,$(D_PP))
D_PP_LINTFIX_TARGETS := $(patsubst %,%.lint-fix,$(D_PP))
D_PP_VALIDATE_TARGETS := $(patsubst %,%.validate,$(D_PP))
D_RB_TARGETS := $(patsubst %,%.validate,$(D_RB))
D_YAML_TARGETS := $(patsubst %,%.validate,$(D_YAML))
# VALIDATE_EXT_MANUAL
ifeq ($(strip $(D)),)
D_SUDO_SRC := .
else
D_SUDO_SRC := $(D)
endif
D_SUDO_ := $(shell find $(D_SUDO_SRC) -path '*sudoers.d*' -exec find \{} -type f ! -name '*.erb' \;)
D_SUDO := $(filter-out $(SUBMODULE_PATTERNS),$(D_SUDO_))
# TODO: ability to disable checks: WIP TODO
ALL_CHECKS := $(VALIDATE_TARGETS) lint.pp.only lint.pp check-footer.pp check-footer.pp.all validate.pp.iterate validate.pp.all
EXCLUDE_CHECKS :=
CHECKS := $(filter-out $(EXCLUDE_CHECKS),$(ALL_CHECKS))
# default target:
all: validate lint check-footer.pp
# helper
check: validate
# autogenerated files
autogen: $(AUTOGEN)
# Lint and validate targets are summary ones
lint-fix: lint-fix.pp
lint: lint.pp
validate: $(VALIDATE_TARGETS)
# Normally we run both
lint.pp: validate.pp lint.pp.only
lint-fix.pp: lint-fix.pp.only
# But you can skip the validate if you really want
%.pp.lint: %.pp
$(V_CMD)$(ECHO) "(LINT.PP) $<" ; \
$(LINT.PP) $<
%.pp.lint-fix: %.pp
$(V_CMD)$(ECHO) "(LINTFIX.PP) $<" ; \
$(LINTFIX.PP) $<
lint.pp.only: $(D_PP_LINT_TARGETS)
lint-fix.pp.only: $(D_PP_LINTFIX_TARGETS)
validate.pp: validate.pp.all
validate.pp.all: $(D_PP)
ifneq ($(strip $(D_PP)),)
$(V_CMD)$(ECHO) "(VALIDATE.PP) $^"
$(V_CMD)$(VALIDATE.PP) $^
endif
%.pp.validate: %.pp
$(V_CMD)$(ECHO) "(VALIDATE.PP) $<" ; \
$(VALIDATE.PP) $<
validate.pp.iterate: $(D_PP_VALIDATE_TARGETS)
%.rb.validate: %.rb
$(V_CMD)$(ECHO) "(VALIDATE.RB) $<" ; \
ruby -c $< >/dev/null
validate.rb: $(D_RB_TARGETS)
%.erb.validate: %.erb
$(V_CMD)$(ECHO) "(VALIDATE.ERB) $<" ; \
erb -P -x -T - $< | ruby -c >/dev/null
validate.erb: $(D_ERB_TARGETS)
%.tmp-yaml.validate: %.tmp-yaml
$(V_CMD)$(ECHO) "(VALIDATE.TMP-YAML) $<" ; \
ruby -e "require 'yaml'; YAML.load_file('$<')"
%.yaml.validate: %.yaml
$(V_CMD)$(ECHO) "(VALIDATE.YAML) $<" ; \
ruby -e "require 'yaml'; YAML.load_file('$<')"
%.tmp-eyaml.validate: %.tmp-eyaml
$(V_CMD)$(ECHO) "(VALIDATE.TMP-YAML) $<" ; \
ruby -e "require 'yaml'; YAML.load_file('$<')"
%.eyaml.validate: %.eyaml
$(V_CMD)$(ECHO) "(VALIDATE.YAML) $<" ; \
ruby -e "require 'yaml'; YAML.load_file('$<')"
validate.yaml: $(D_YAML_TARGETS)
%.json.validate: %.json
$(V_CMD)$(ECHO) "(VALIDATE.JSON) $<" ; \
ruby -e "require 'json'; JSON.parse((File.new '$<').read)"
validate.json: $(D_JSON_TARGETS)
validate.sudo: $(D_SUDO)
ifneq ($(strip $(D_SUDO)),)
$(V_CMD)for i in $(^); do \
$(ECHO) "(VALIDATE.SUDO) $$i" ; \
/usr/sbin/visudo -c -f $$i >/dev/null ; \
done ;
endif
CORRECT_VIM_FOOTER_PP = check-footer.pp
$(CORRECT_VIM_FOOTER_PP): $(D_PP)
ifneq (,$(CORRECT_VIM_FOOTER))
ifneq ($(strip $(D_PP)),)
ifeq ($(filter $(CORRECT_VIM_FOOTER_PP).all,$(CHECKS)),$(CORRECT_VIM_FOOTER_PP).all)
ifeq ($(filter $(CORRECT_VIM_FOOTER_PP),$(CHECKS)),$(CORRECT_VIM_FOOTER_PP))
$(V_CMD)$(ECHO) "(CHECK-VIM-FOOTER.PP) $^"
$(V_CMD)fgrep -x -L '$(CORRECT_VIM_FOOTER)' $^
endif
endif
endif
endif
$(CORRECT_VIM_FOOTER_PP).all: $(CORRECT_VIM_FOOTER_PP)
#test:
# @echo INCLUDE_SUBMODULE=$(INCLUDE_SUBMODULE)
# @echo SUBMODULE_LIST=$(SUBMODULE_LIST)
# @echo SUBMODULE_LIST_SUFFIX=$(SUBMODULE_LIST_SUFFIX)
# @echo SUBMODULE_TRUE=$(SUBMODULE_TRUE)
# @echo SUBMODULE_FALSE=$(SUBMODULE_FALSE)
# @echo SUBMODULE_PATTERNS=$(SUBMODULE_PATTERNS)
# @echo D_=$(D_)
# @echo D=$(D)
.PRECIOUS: %.tmp-yaml
%.tmp-yaml: %.yaml.erb %.yaml.erb.validate
$(V_CMD)$(ECHO) "(YAML.ERB) $^"
$(V_CMD)erb "$(<)" >"$(@)" || rm -f "$(@).tmp"
%.yaml: %.tmp-yaml %.tmp-yaml.validate
$(V_CMD)$(ECHO) "(TMP.YAML) $^"
$(V_CMD)mv -f "$(<)" "$(@)"
.PHONY: validate lint lint.pp lint.pp.only $(VALIDATE_TARGETS) validate.pp.all validate.pp.iterate check
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment