Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 49 additions & 31 deletions .git-hooks-matomo/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
### Check we're running in the context of a plugin and get helpful dir variables ###

REPO_DIR="$(git rev-parse --show-toplevel)"
echo "Running pre-commit hook in repo: $REPO_DIR"
echo "Running pre-push hook in repo: $REPO_DIR"

if [[ "$REPO_DIR" =~ /plugins/(.*) ]]; then
PLUGIN_PATH="plugins/${BASH_REMATCH[1]}/"
else
echo "Not a plugin, not running any further checks"
exit 1
echo "Not inside a Matomo checkout's plugins/ directory, skipping PHPStan checks"
exit 0
fi
MATOMO_DIR=$(echo "$REPO_DIR" | sed -E 's|/plugins/.*$||')

Expand All @@ -33,11 +33,9 @@ MATOMO_DIR=$(echo "$REPO_DIR" | sed -E 's|/plugins/.*$||')

COMMAND=""
# Use local PHP if setup
if command -v php >/dev/null 2>&1; then
if [ -f "${MATOMO_DIR}/vendor/bin/phpstan" ]; then
COMMAND="${MATOMO_DIR}/vendor/bin/phpstan"
PLUGIN_PATH=''
fi
if command -v php >/dev/null 2>&1 && [ -f "${MATOMO_DIR}/vendor/bin/phpstan" ]; then
COMMAND="${MATOMO_DIR}/vendor/bin/phpstan"
PLUGIN_PATH=''
elif command -v ddev >/dev/null 2>&1; then
# Use ddev if setup (overridding local setup)
if [ -d "$MATOMO_DIR/.ddev" ]; then
Expand All @@ -58,39 +56,59 @@ fi
# Basic setup
cd "$REPO_DIR"
STATUS=0
MAIN_BRANCH='5.x-dev'
ZERO_OID='0000000000000000000000000000000000000000'
PHPSTAN_CREATED_CONFIG=phpstan/phpstan.created.neon
PHPSTAN_MODIFIED_CONFIG=phpstan/phpstan.modified.neon



### Run PHPStan on the files a pushed commit adds or changes. ###

### Run PHPStan on newly created files. ###
# $1 -- the pushed commit
# $2 -- git diff filter (A for created files, CM for modified files)
# $3 -- the phpstan config to use
# $4 -- log label for the file kind
check_pushed_commit() {
local commit="$1" filter="$2" config="$3" label="$4"

PHPSTAN_CREATED_CONFIG=phpstan/phpstan.created.neon
MAIN_BRANCH='5.x-dev'
if [[ -f "$PHPSTAN_CREATED_CONFIG" ]]; then
CHANGED_FILES=$(git diff --name-only ${MAIN_BRANCH} --diff-filter=A | grep '\.php$' || true)
if [ -z "$CHANGED_FILES" ]; then
echo "No created PHP files"
else
echo "Running PHPstan at a very high level on new files"
CHANGED_FILES=`echo "$CHANGED_FILES" | sed -e 's/^\(.*\)$/"\1"/' | xargs -I{} echo "${PLUGIN_PATH}{}"`
echo "$CHANGED_FILES" | xargs $COMMAND analyse -c ${PLUGIN_PATH}${PHPSTAN_CREATED_CONFIG} || STATUS=1
if [[ ! -f "$config" ]]; then
return 0
fi
fi

# Use the merge base with the remote main branch: the local branch can be stale
# or missing, which silently widens the diff to files the push doesn't touch.
local diff_base
diff_base=$(git merge-base "$commit" "origin/${MAIN_BRANCH}" 2>/dev/null)
if [[ -z "$diff_base" ]]; then
echo "Could not resolve the merge base between ${commit} and origin/${MAIN_BRANCH}."
echo "Run 'git fetch origin ${MAIN_BRANCH}' and push again."
return 1
fi

local changed_files
changed_files=$(git diff --name-only "$diff_base" "$commit" --diff-filter="$filter" | grep '\.php$' || true)
if [ -z "$changed_files" ]; then
echo "No ${label} PHP files"
return 0
fi

### Run PHPStan on modified files. ###
PHPSTAN_MODIFIED_CONFIG=phpstan/phpstan.modified.neon
if [[ -f "$PHPSTAN_MODIFIED_CONFIG" ]]; then
CHANGED_FILES=$(git diff --name-only ${MAIN_BRANCH} --diff-filter=CM | grep '\.php$' || true)
if [ -z "$CHANGED_FILES" ]; then
echo "No changed PHP files"
else
echo "Running PHPstan on modified files"
CHANGED_FILES=`echo "$CHANGED_FILES" | sed -e 's/^\(.*\)$/"\1"/' | xargs -I{} echo "${PLUGIN_PATH}{}"`
echo "$CHANGED_FILES" | xargs $COMMAND analyse -c ${PLUGIN_PATH}${PHPSTAN_MODIFIED_CONFIG} || STATUS=1
echo "Running PHPstan on ${label} files"
changed_files=`echo "$changed_files" | sed -e 's/^\(.*\)$/"\1"/' | xargs -I{} echo "${PLUGIN_PATH}{}"`
echo "$changed_files" | xargs $COMMAND analyse -c ${PLUGIN_PATH}${config} || return 1
}

# Check the commits actually being pushed, as supplied on stdin: HEAD is wrong
# when pushing another local branch or several refs at once. The inner commands
# read /dev/null so they cannot consume the remaining stdin lines.
while read -r local_ref local_oid remote_ref remote_oid; do
if [[ "$local_oid" == "$ZERO_OID" ]]; then
continue # deleting the remote ref, nothing is pushed
fi
fi
echo "Checking ${local_ref} (${local_oid})"
check_pushed_commit "$local_oid" A "$PHPSTAN_CREATED_CONFIG" "created" < /dev/null || STATUS=1
check_pushed_commit "$local_oid" CM "$PHPSTAN_MODIFIED_CONFIG" "modified" < /dev/null || STATUS=1
done

# Don't bother running the full check, as we check changes files already, and
# can assume that the unchanged files don't need rechecking.
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ jobs:
repository: matomo-org/github-action-tests
ref: main
path: github-action-tests
persist-credentials: false

- name: checkout matomo for plugin builds
shell: bash
Expand Down
3 changes: 2 additions & 1 deletion phpstan/phpstan.created.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
includes:
- ../phpstan.neon
parameters:
level: 5
# new files carry no pre-existing debt, so hold them to the strictest level
level: 9
tmpDir: /tmp/phpstan/Slack/created
Loading