diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..68bc17f --- /dev/null +++ b/.gitignore @@ -0,0 +1,160 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ diff --git a/.pre-commit-hooks.yaml b/.pre-commit-hooks.yaml new file mode 100644 index 0000000..764e9b0 --- /dev/null +++ b/.pre-commit-hooks.yaml @@ -0,0 +1,6 @@ + - id: checkstyle-java + name: checkstyle-java + description: '' + entry: ./.scripts/checkstyle-pre-commit.sh + language: script + require_serial: false \ No newline at end of file diff --git a/.scripts/checkstyle-pre-commit.sh b/.scripts/checkstyle-pre-commit.sh new file mode 100755 index 0000000..acb389f --- /dev/null +++ b/.scripts/checkstyle-pre-commit.sh @@ -0,0 +1,138 @@ +#!/bin/bash + +# Checkstyle jar artifact +CHECKSTYLE_VERSION="https://github.com/checkstyle/checkstyle/releases/download/checkstyle-10.12.0/checkstyle-10.12.0-all.jar" + +# File locations +PRE_COMMIT_DIR=~/.cache/pre-commit/checkstyle +CHECKSTYLE_JAR="checkstyle.jar" +GOOGLE_CHECKS="google_checks.xml" +SUN_CHECKS="sun_checks.xml" +OUTPUT_CACHE="${PRE_COMMIT_DIR}/output_cache.txt" +OUTPUT_FILE="${PRE_COMMIT_DIR}/output.txt" + +# script flags and codes +STRICT=false +EXIT_CODE=0 + +while getopts c:s flag +do + case "${flag}" in + c) CONFIG_ARG=${OPTARG};; + s) STRICT=true;; + *) EXIT_CODE=1;; + esac +done + +# if error on script call. +if [ $EXIT_CODE != 0 ] +then + echo "exit" + exit $EXIT_CODE +fi + +# make checkstyle dir in pre commit if does not exist +if [ ! -d "${PRE_COMMIT_DIR}" ] +then + echo "caching directory under: ${PRE_COMMIT_DIR}" + mkdir "${PRE_COMMIT_DIR}" +fi + +# download checkstyle jar if not found +if [ ! -f "${PRE_COMMIT_DIR}/${CHECKSTYLE_JAR}" ] +then + echo "downloading checkstyle" + curl -o "${PRE_COMMIT_DIR}/${CHECKSTYLE_JAR}" -LJO "${CHECKSTYLE_VERSION}" +fi + +# download google checks config if not found +if [ ! -f "${PRE_COMMIT_DIR}/${GOOGLE_CHECKS}" ] +then + echo "downloading google_checks config" + curl -o "${PRE_COMMIT_DIR}/${GOOGLE_CHECKS}" https://raw.githubusercontent.com/checkstyle/checkstyle/master/src/main/resources/google_checks.xml +fi + +# download sun checks config if not found +if [ ! -f "${PRE_COMMIT_DIR}/${SUN_CHECKS}" ] +then + echo "downloading sun_checks config" + curl -o "${PRE_COMMIT_DIR}/${SUN_CHECKS}" https://raw.githubusercontent.com/checkstyle/checkstyle/master/src/main/resources/sun_checks.xml + +fi + +# switch to specify config to use. +# default to sun_checks.xml +case "${CONFIG_ARG}" in + "google") CONFIG_ARG="${GOOGLE_CHECKS}";; + "sun") CONFIG_ARG="${SUN_CHECKS}";; + *) CONFIG_ARG="${SUN_CHECKS}";; + +esac + +# determine config path +CHECKSTYLE_CONFIG="${PRE_COMMIT_DIR}/${CONFIG_ARG}" +echo "running checkstyle using ${CONFIG_ARG} config" + +# HERE +# clear old output file. +if [ -f "${OUTPUT_FILE}" ] +then + rm "${OUTPUT_FILE}" +fi + +# iterate through checked in java files. +ALL_FILES=$(git diff --cached --name-status) +FILE_STATUS=false +for FILE in $ALL_FILES +do + if [[ "${FILE}" == *.java && $FILE_STATUS = true ]] + then + # HERE + # run checkstyle command on specific file. + echo "linting ${FILE}" + LINT_RESULT=$(java -jar "${PRE_COMMIT_DIR}/${CHECKSTYLE_JAR}" -o "${OUTPUT_CACHE}" -c "${CHECKSTYLE_CONFIG}" "${FILE}" ) + + cat "${OUTPUT_CACHE}" >> "${OUTPUT_FILE}" + fi + + # set status to true if positive change on file. + if [[ "${FILE}" = "D" || "${FILE}" = 'R'* ]] + then + FILE_STATUS=false + else + FILE_STATUS=true + fi +done + +# HERE +# cleanup output cache +if [ -f "${OUTPUT_CACHE}" ] +then + rm "${OUTPUT_CACHE}" +fi + +# Filter all checkstyle output +ERRORS=0 +while read line; do + # parse output lines + if [[ "${line}" == '[ERROR]'* ]] + then + ERRORS=$((ERRORS + 1)) + echo "${line}" + fi + + # if STRICT set WARN as error + if [[ "${line}" == '[WARN]'* && $STRICT = true ]] + then + ERRORS=$((ERRORS + 1)) + echo "${line}" + fi +done < "${OUTPUT_FILE}" + +# if any errors set exit code to failing +if [ $ERRORS -gt 0 ] +then + EXIT_CODE=1 +fi + +exit $EXIT_CODE \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..be10c47 --- /dev/null +++ b/README.md @@ -0,0 +1,26 @@ +# pre-commit-mirror-checkstyle + +A mirror of the checkstyle linting tool for use in pre-commit hooks + +## Usage + +Add the following code to your repo's `.pre-commit-config.yaml` + +> `- hooks:` +`- id: checkstyle-java` +`repo: https://github.com/rgraue/pre-commit-mirror-checkstyle` +`rev: v0.1.15` + +## Options + +**Config** `-c` + +- Specify the config to be used by checkstyle. `google` or `sun` only. Points to [google_checks](https://raw.githubusercontent.com/checkstyle/checkstyle/master/src/main/resources/google_checks.xml) and [sun_checks](https://raw.githubusercontent.com/checkstyle/checkstyle/master/src/main/resources/sun_checks.xml) respectively. + +**Strict** `-s` + +- Specify whether to fail on `[WARN]` (warnings) as well during linting. *Default False* + +## Notes + +`pre-commit` does not officially support **java** hooks. Java must be installed locally, and checkstyle jar and subsequent files will be saved under `~/.cache/pre-commit/checkstyle`. Files and configs will be installed during first run of hook.