diff --git a/.github/workflows/matomo-tests.yml b/.github/workflows/matomo-tests.yml index 7105559a4..8cd8aa7b6 100644 --- a/.github/workflows/matomo-tests.yml +++ b/.github/workflows/matomo-tests.yml @@ -1,7 +1,7 @@ # Action for running tests # This file has been automatically created. # To recreate it you can run this command -# ./console generate:test-action --plugin="GoogleAnalyticsImporter" --php-versions="matomo5_min_php,matomo5_max_php" --dependent-plugins="matomo-org/plugin-MarketingCampaignsReporting innocraft/plugin-Funnels" --schedule-cron="10 3 * * 6" +# ./console generate:test-action --plugin="GoogleAnalyticsImporter" --php-versions="matomo6_min_php,matomo6_max_php" --dependent-plugins="matomo-org/plugin-MarketingCampaignsReporting innocraft/plugin-Funnels" --schedule-cron="10 3 * * 6" name: Plugin GoogleAnalyticsImporter Tests @@ -37,8 +37,11 @@ jobs: strategy: fail-fast: false matrix: - php: [ 'matomo5_min_php', 'matomo5_max_php' ] + php: [ 'matomo6_min_php', 'matomo6_max_php' ] target: ['minimum_required_matomo', 'maximum_supported_matomo'] + database: + - { engine: 'Mysql', version: '8.0' } + - { engine: 'Mariadb', version: '10.6' } steps: - uses: actions/checkout@v3 with: @@ -53,8 +56,10 @@ jobs: php-version: ${{ matrix.php }} test-type: 'PluginTests' matomo-test-branch: ${{ matrix.target }} + mysql-engine: ${{ matrix.database.engine }} + mysql-version: ${{ matrix.database.version }} artifacts-pass: ${{ secrets.ARTIFACTS_PASS }} - upload-artifacts: ${{ matrix.php == 'matomo5_min_php' && matrix.target == 'maximum_supported_matomo' }} + upload-artifacts: ${{ matrix.php == 'matomo6_min_php' && matrix.target == 'maximum_supported_matomo' && matrix.database.engine == 'Mysql' }} dependent-plugins: 'matomo-org/plugin-MarketingCampaignsReporting innocraft/plugin-Funnels' github-token: ${{ secrets.TESTS_ACCESS_TOKEN || secrets.GITHUB_TOKEN }} UI: @@ -70,8 +75,10 @@ jobs: plugin-name: 'GoogleAnalyticsImporter' matomo-test-branch: 'maximum_supported_matomo' test-type: 'UI' - php-version: 'matomo5_min_php' - node-version: '16' + mysql-engine: 'Mysql' + mysql-version: '8.0' + php-version: 'matomo6_min_php' + node-version: '24' artifacts-pass: ${{ secrets.ARTIFACTS_PASS }} upload-artifacts: true dependent-plugins: 'matomo-org/plugin-MarketingCampaignsReporting innocraft/plugin-Funnels' diff --git a/.gitignore b/.gitignore index 5cc826997..6847cfb42 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ vendor/**/composer.lock /vue/dist/*.common.js /vue/dist/*.map /vue/dist/*.development.* +/vue/dist/*.umd.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 826e8c049..12255f483 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ ## Changelog +# 6.0.0 - 2026-08-11 + +- Compatibility with Matomo 6 + # 5.2.1 - 2026-08-03 - Added PHPStan static analysis (CI check and pre-push hook) - Fixed an error that could hide the real failure reason when starting a GA4 import fails diff --git a/Logger/LogToSingleFileProcessor.php b/Logger/LogToSingleFileProcessor.php index 0a04db30b..7776decda 100644 --- a/Logger/LogToSingleFileProcessor.php +++ b/Logger/LogToSingleFileProcessor.php @@ -9,6 +9,7 @@ namespace Piwik\Plugins\GoogleAnalyticsImporter\Logger; +use Monolog\LogRecord; use Piwik\Log\Logger; use Piwik\Container\StaticContainer; @@ -25,11 +26,11 @@ public function __construct($idSite) { $this->idSite = (int) $idSite; } - public function __invoke(array $record) + public function __invoke(LogRecord $record): LogRecord { $message = $record['message']; if (is_string($message)) { - $record['message'] = '(idSite: ' . $this->idSite . ') ' . $record['message']; + $record = $record->with(message: '(idSite: ' . $this->idSite . ') ' . $message); } return $record; } diff --git a/composer.json b/composer.json index 9b23bf7b9..8bfc4e8f8 100644 --- a/composer.json +++ b/composer.json @@ -1,6 +1,6 @@ { "require": { - "php": ">=7.2.5", + "php": ">=8.1.0", "google/apiclient": "^2.15.3", "google/apiclient-services": "^0.224.1", "guzzlehttp\/guzzle": "7.10.1", diff --git a/phpstan.neon b/phpstan.neon index 30b3140b2..d7cae3721 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -1,13 +1,13 @@ parameters: level: 1 - phpVersion: 70200 + phpVersion: 80100 tmpDir: /tmp/phpstan/GoogleAnalyticsImporter/main paths: - . excludePaths: analyseAndScan: - tests/* - - github-action-tests/ + - github-action-tests/ (?) - scoper.inc.php # still scanned so the prefixed Google classes are discovered even # when the Matomo bootstrap cannot load plugin autoloaders (e.g. CI) diff --git a/plugin.json b/plugin.json index fda5b861e..f6e4fafa1 100644 --- a/plugin.json +++ b/plugin.json @@ -1,10 +1,10 @@ { "name": "GoogleAnalyticsImporter", "description": "Import reports from a Google Analytics account into Matomo.", - "version": "5.2.1", + "version": "6.0.0", "theme": false, "require": { - "matomo": ">=5.0.0-rc5,<6.0.0-b1" + "matomo": ">=6.0.0-b1,<7.0.0-b1" }, "authors": [ { diff --git a/stylesheets/styles.less b/stylesheets/styles.less index b0737621c..5757071c0 100644 --- a/stylesheets/styles.less +++ b/stylesheets/styles.less @@ -27,15 +27,6 @@ } } - .ga-import-warning { - background: @color-orange-brand; - color: white; - - &::before { - color: unset; - } - } - .radio { margin-left: 1rem; } diff --git a/tests/System/CheckDirectDependencyUseCommandTest.php b/tests/System/CheckDirectDependencyUseCommandTest.php index abac270d3..6592e2d83 100644 --- a/tests/System/CheckDirectDependencyUseCommandTest.php +++ b/tests/System/CheckDirectDependencyUseCommandTest.php @@ -45,6 +45,7 @@ public function testCommand() 'GoogleAnalyticsImporter/Importers/DevicesDetection/RecordImporterGA4.php' ], 'Monolog' => [ + 'GoogleAnalyticsImporter/Logger/LogToSingleFileProcessor.php', 'GoogleAnalyticsImporter/Monolog/Handler/GASystemLogHandler.php' ], 'Symfony\Component\Console' => [ diff --git a/tests/UI/GoogleAnalyticsImporterGA4_spec.js b/tests/UI/GoogleAnalyticsImporterGA4_spec.js index 27d585b22..4c7a51037 100644 --- a/tests/UI/GoogleAnalyticsImporterGA4_spec.js +++ b/tests/UI/GoogleAnalyticsImporterGA4_spec.js @@ -14,6 +14,47 @@ describe("GoogleAnalyticsImporterGA4", function () { var url = "?module=GoogleAnalyticsImporter&action=index&idSite=1&period=day&date=yesterday"; + // type into a field with real keyboard events and verify the value arrived + // (a freshly rendered field sometimes swallows the first characters); + // values set programmatically do not reach the Vue model + async function typeFieldValue(selector, text) { + let actual; + for (let attempt = 0; attempt < 3; attempt++) { + await (await page.$(selector)).type(text); + await page.waitForTimeout(100); + actual = await page.evaluate( + (selector) => document.querySelector(selector).value, + selector + ); + if (actual === text) { + return; + } + await page.evaluate((selector) => { + document.querySelector(selector).value = ''; + }, selector); + } + + throw new Error(`Could not type "${text}" into ${selector}, last value was "${actual}"`); + } + + // selects bind v-model to the real