diff --git a/README.md b/README.md index d5fe11a..00ea62f 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,8 @@ Available options (with default value): phpcs_bin_path: 'phpcs' # Custom PHPCS bin path use_local_config: 'false' # Use local config if available extra_args: '' # Extra arguments passing to the command + only_changed_files: '' # Run the linter only on the changed files. Accepts true|false + only_changed_lines: '' # Run the linter only on the changed lines. Accepts true|false ``` ## Examples @@ -137,6 +139,28 @@ jobs: standard: 'WordPress' # Standard to use. Accepts WordPress|WordPress-Core|WordPress-Docs|WordPress-Extra|WordPress-VIP-Go|WordPressVIPMinimum|10up-Default. use_local_config: 'true' ``` +### Run linter on changed lines + +```yaml +name: WPCS check + +on: pull_request + +jobs: + phpcs: + name: WPCS + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # This is very important. Without this the linting of only the changed lines will not work. + - name: WPCS check + uses: 10up/wpcs-action@stable + with: + standard: 10up-Default + enable_warnings: true + only_changed_lines: true +``` ## Support Level diff --git a/action.yml b/action.yml index e3dc303..7cdf682 100644 --- a/action.yml +++ b/action.yml @@ -38,6 +38,14 @@ inputs: description: 'Passing extra arguments to the phpcs command' required: false default: '' + only_changed_files: + description: 'Run linter on changed files only' + required: false + default: '' + only_changed_lines: + description: 'Report errors only for changed lines' + required: false + default: '' runs: using: 'docker' image: 'Dockerfile' diff --git a/entrypoint.sh b/entrypoint.sh index 2c21f81..4116d7c 100644 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -4,27 +4,126 @@ cp /action/problem-matcher.json /github/workflow/problem-matcher.json git clone --depth 1 -b 2.3.0 https://github.com/WordPress/WordPress-Coding-Standards.git ~/wpcs +git config --global --add safe.directory $(pwd) + +diff_lines() { + path="" + line="" + while IFS= read -r REPLY; do + esc=$(printf '\033') + if echo "$REPLY" | grep -qE '\-\-\- (a/)?.*'; then + continue + elif echo "$REPLY" | grep -qE '\+\+\+ (b/)?([^[:blank:]'"$esc"']+).*'; then + path=$(echo "$REPLY" | sed -E 's/\+\+\+ (b\/)?([^[:blank:]'"$esc"']+).*/\2/') + elif echo "$REPLY" | grep -qE '@@ -[0-9]+(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@.*'; then + line=$(echo "$REPLY" | sed -E 's/@@ -[0-9]+(,[0-9]+)? \+([0-9]+)(,[0-9]+)? @@.*/\2/') + elif echo "$REPLY" | grep -qE '^('"$esc"'\[[0-9;]*m)*([\\ +-])'; then + echo "$path:$line:$REPLY" + if echo "${REPLY}" | grep -qE '^('"$esc"'\[[0-9;]*m)*([\ +-])'; then + line=$((line+1)) + fi + fi + done +} + +filter_by_changed_lines() { + changedLines="$1" + fileName= + fileLine= + exitCode=0 + + while IFS= read -r line; do + if echo "$line" | grep -q -E ' ${COMPARE_TO_REF})" + set +e + CHANGED_FILES=$(git diff --name-only --diff-filter=d "${COMPARE_FROM_REF}" "${COMPARE_TO_REF}" | xargs -rt ls -1d 2>/dev/null) + set -e + echo "Will check files:" + echo "${CHANGED_FILES}" +else + echo "Will check all files" +fi + if [ "${INPUT_STANDARD}" = "WordPress-VIP-Go" ] || [ "${INPUT_STANDARD}" = "WordPressVIPMinimum" ]; then echo "Setting up VIPCS" git clone --depth 1 -b 2.3.3 https://github.com/Automattic/VIP-Coding-Standards.git ${HOME}/vipcs git clone https://github.com/sirbrillig/phpcs-variable-analysis ${HOME}/variable-analysis - ${INPUT_PHPCS_BIN_PATH} --config-set installed_paths "${HOME}/wpcs,${HOME}/vipcs,${HOME}/variable-analysis" + + decide_all_files_or_changed "${HOME}/wpcs,${HOME}/vipcs,${HOME}/variable-analysis" elif [ "${INPUT_STANDARD}" = "10up-Default" ]; then echo "Setting up 10up-Default" git clone https://github.com/10up/phpcs-composer ${HOME}/10up git clone https://github.com/PHPCompatibility/PHPCompatibilityWP ${HOME}/phpcompatwp git clone https://github.com/PHPCompatibility/PHPCompatibility ${HOME}/phpcompat git clone https://github.com/PHPCompatibility/PHPCompatibilityParagonie ${HOME}/phpcompat-paragonie - git clone https://github.com/PHPCSStandards/PHPCSUtils ${HOME}/phpcsutils + git clone --depth 1 --branch 1.0.11 https://github.com/PHPCSStandards/PHPCSUtils ${HOME}/phpcsutils git clone https://github.com/Automattic/VIP-Coding-Standards ${HOME}/vipcs git clone https://github.com/sirbrillig/phpcs-variable-analysis ${HOME}/variable-analysis - ${INPUT_PHPCS_BIN_PATH} --config-set installed_paths "${HOME}/wpcs,${HOME}/10up/10up-Default,${HOME}/phpcompatwp/PHPCompatibilityWP,${HOME}/phpcompat/PHPCompatibility,${HOME}/phpcompat-paragonie/PHPCompatibilityParagonieSodiumCompat,${HOME}/phpcompat-paragonie/PHPCompatibilityParagonieRandomCompat,${HOME}/phpcsutils/PHPCSUtils,${HOME}/vipcs,${HOME}/variable-analysis" + + decide_all_files_or_changed "${HOME}/wpcs,${HOME}/10up/10up-Default,${HOME}/phpcompatwp/PHPCompatibilityWP,${HOME}/phpcompat/PHPCompatibility,${HOME}/phpcompat-paragonie/PHPCompatibilityParagonieSodiumCompat,${HOME}/phpcompat-paragonie/PHPCompatibilityParagonieRandomCompat,${HOME}/phpcsutils/PHPCSUtils,${HOME}/vipcs,${HOME}/variable-analysis" elif [ -z "${INPUT_STANDARD_REPO}" ] || [ "${INPUT_STANDARD_REPO}" = "false" ]; then - ${INPUT_PHPCS_BIN_PATH} --config-set installed_paths ~/wpcs + decide_all_files_or_changed "~/wpcs" else - echo "Standard repository: ${INPUT_STANDARD_REPO}" - git clone -b ${INPUT_REPO_BRANCH} ${INPUT_STANDARD_REPO} ${HOME}/cs - ${INPUT_PHPCS_BIN_PATH} --config-set installed_paths "${HOME}/wpcs,${HOME}/cs" + echo "Standard repository: ${INPUT_STANDARD_REPO}" + git clone -b ${INPUT_REPO_BRANCH} ${INPUT_STANDARD_REPO} ${HOME}/cs + + decide_all_files_or_changed "${HOME}/wpcs,${HOME}/cs" fi if [ -z "${INPUT_EXCLUDES}" ]; then @@ -53,13 +152,37 @@ else fi if [ "${HAS_CONFIG}" = true ] && [ "${INPUT_USE_LOCAL_CONFIG}" = "true" ] ; then - ${INPUT_PHPCS_BIN_PATH} ${WARNING_FLAG} --report=checkstyle ${INPUT_EXTRA_ARGS} + if [ "${INPUT_ONLY_CHANGED_FILES}" = "true" ]; then + if [ "${INPUT_ONLY_CHANGED_LINES}" = "true" ]; then + set +e + echo "${CHANGED_FILES}" | xargs -rt ${INPUT_PHPCS_BIN_PATH} ${WARNING_FLAG} --report=checkstyle ${INPUT_EXTRA_ARGS} | filter_by_changed_lines "${clean_diff_output}" + status=$? + set -e + else + echo "${CHANGED_FILES}" | xargs -rt ${INPUT_PHPCS_BIN_PATH} ${WARNING_FLAG} --report=checkstyle ${INPUT_EXTRA_ARGS} + status=$? + fi + else + ${INPUT_PHPCS_BIN_PATH} ${WARNING_FLAG} --report=checkstyle ${INPUT_EXTRA_ARGS} + status=$? + fi else + if [ "${INPUT_ONLY_CHANGED_FILES}" = "true" ]; then + if [ "${INPUT_ONLY_CHANGED_LINES}" = "true" ]; then + set +e + echo "${CHANGED_FILES}" | xargs -rt ${INPUT_PHPCS_BIN_PATH} ${WARNING_FLAG} --report=checkstyle --standard=${INPUT_STANDARD} --extensions=php ${INPUT_EXTRA_ARGS} | filter_by_changed_lines "$(clean_diff_output)" + status=$? + set -e + else + echo "${CHANGED_FILES}" | xargs -rt ${INPUT_PHPCS_BIN_PATH} ${WARNING_FLAG} --report=checkstyle --standard=${INPUT_STANDARD} --extensions=php ${INPUT_EXTRA_ARGS} + status=$? + fi + else ${INPUT_PHPCS_BIN_PATH} ${WARNING_FLAG} --report=checkstyle --standard=${INPUT_STANDARD} --ignore=${EXCLUDES} --extensions=php ${INPUT_PATHS} ${INPUT_EXTRA_ARGS} + status=$? + fi fi -status=$? - echo "::remove-matcher owner=phpcs::" exit $status