Skip to content
Draft
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
72 changes: 46 additions & 26 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 Down Expand Up @@ -56,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
86 changes: 6 additions & 80 deletions .github/workflows/phpstan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,87 +3,13 @@ name: PHPStan check
on: pull_request

permissions:
actions: read
checks: read
contents: read
deployments: none
issues: read
packages: none
pull-requests: read
repository-projects: none
security-events: none
statuses: read

env:
PLUGIN_NAME: GoogleAnalyticsImporter
DEPENDENT_PLUGINS: matomo-org/plugin-MarketingCampaignsReporting innocraft/plugin-Funnels innocraft/plugin-ConnectAccounts

jobs:
phpstan:
name: PHPStan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
lfs: false
persist-credentials: false
- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
# 8.2 rather than 7.2: the ConnectAccounts dependency uses PHP 8
# attribute syntax, which fatals when loaded on 7.2. The analysis
# level stays PHP 7.2 via phpVersion in phpstan.neon.
php-version: '8.2'

- name: Check out github-action-tests repository
uses: actions/checkout@v4
with:
repository: matomo-org/github-action-tests
ref: main
path: github-action-tests
persist-credentials: false

- name: checkout matomo for plugin builds
shell: bash
run: ${{ github.workspace }}/github-action-tests/scripts/bash/checkout_matomo.sh
env:
PLUGIN_NAME: ${{ env.PLUGIN_NAME }}
WORKSPACE: ${{ github.workspace }}
ACTION_PATH: ${{ github.workspace }}/github-action-tests
MATOMO_TEST_TARGET: maximum_supported_matomo

- name: prepare setup
shell: bash
run: |
cd ${{ github.workspace }}/matomo
echo -e "composer install"
composer install --ignore-platform-reqs

- name: checkout additional plugins
if: ${{ env.DEPENDENT_PLUGINS != '' }}
shell: bash
working-directory: ${{ github.workspace }}/matomo
run: ${{ github.workspace }}/github-action-tests/scripts/bash/checkout_dependent_plugins.sh

env:
DEPENDENT_PLUGINS: ${{ env.DEPENDENT_PLUGINS }}
GITHUB_USER_TOKEN: ${{ secrets.TESTS_ACCESS_TOKEN || secrets.GITHUB_TOKEN }}

- name: "Restore result cache"
uses: actions/cache/restore@v4
with:
path: /tmp/phpstan # same as in phpstan.neon
key: "phpstan-result-cache-${{ github.run_id }}"
restore-keys: |
phpstan-result-cache-

- name: PHPStan whole repo
id: phpstan-all
run: cd ${{ github.workspace }}/matomo && composer run phpstan -- -vvv -c plugins/${{ env.PLUGIN_NAME }}/phpstan.neon

- name: "Save result cache"
uses: actions/cache/save@v4
if: ${{ !cancelled() }}
with:
path: /tmp/phpstan # same as in phpstan.neon
key: "phpstan-result-cache-${{ github.run_id }}"
uses: matomo-org/plugin-ci-workflows/.github/workflows/plugin-phpstan.yml@main
with:
plugin-name: GoogleAnalyticsImporter
dependent-plugins: 'matomo-org/plugin-MarketingCampaignsReporting innocraft/plugin-Funnels innocraft/plugin-ConnectAccounts'
secrets:
TESTS_ACCESS_TOKEN: ${{ secrets.TESTS_ACCESS_TOKEN }}
2 changes: 1 addition & 1 deletion phpstan.neon
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ parameters:
# still scanned so the prefixed Google classes are discovered even
# when the Matomo bootstrap cannot load plugin autoloaders (e.g. CI)
analyse:
- vendor/
- vendor/ (?)
ignoreErrors:
# WpMatomo and get_option exist only when running inside Matomo for WordPress
- '#^Instantiated class WpMatomo\\Site not found\.$#'
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/GoogleAnalyticsImporter/created
2 changes: 2 additions & 0 deletions phpstan/phpstan.modified.neon
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
includes:
- ../phpstan.neon
parameters:
# touched files are ratcheted up to the plugin-wide goal of level 5,
# even where the CI base level is lower
level: 5
tmpDir: /tmp/phpstan/GoogleAnalyticsImporter/modified
Loading