diff --git a/.github/files/coverage-munger/process-coverage.sh b/.github/files/coverage-munger/process-coverage.sh index 0c15eb5cfdf2e..c95ff9809e5c8 100755 --- a/.github/files/coverage-munger/process-coverage.sh +++ b/.github/files/coverage-munger/process-coverage.sh @@ -17,27 +17,39 @@ echo '::endgroup::' TMP_DIR=$( mktemp -d ) trap 'rm -rf "$TMP_DIR"' exit -echo "::group::Combining PHP coverage" -composer --working-dir="$BASE" update -"$BASE"/vendor/bin/phpcov merge --php artifacts/php-combined.cov coverage -perl -i -pwe 'BEGIN { $prefix = shift; $prefix=~s!/*$!/!; $re = qr/\Q$prefix\E/; $l = length( $prefix ); } s!s:(\d+):"$re! sprintf( qq(s:%d:"), $1 - $l ) !ge' "$GITHUB_WORKSPACE" artifacts/php-combined.cov -echo '::endgroup::' - -echo "::group::Combining JS coverage" -pnpm --filter=jetpack-gh-config-munger exec istanbul-merge --out "$PWD"/artifacts/js-combined.json $( find "$PWD/coverage" -name '*.json' ) -perl -i -pwe 'BEGIN { $prefix = shift; $prefix=~s!/*$!/!; $re = qr/\Q$prefix\E/; } s!"$re!"!g' "$GITHUB_WORKSPACE" artifacts/js-combined.json -echo '::endgroup::' - -echo "::group::Creating PHP coverage summary" -"$BASE"/extract-php-summary-data.php artifacts/php-combined.cov > "$TMP_DIR/php-summary.tsv" -echo '::endgroup::' +TMP=$( find "$PWD/coverage" -name '*.cov' ) +if [[ -n "$TMP" ]]; then + echo "::group::Combining PHP coverage" + composer --working-dir="$BASE" update + "$BASE"/vendor/bin/phpcov merge --php artifacts/php-combined.cov coverage + perl -i -pwe 'BEGIN { $prefix = shift; $prefix=~s!/*$!/!; $re = qr/\Q$prefix\E/; $l = length( $prefix ); } s!s:(\d+):"$re! sprintf( qq(s:%d:"), $1 - $l ) !ge' "$GITHUB_WORKSPACE" artifacts/php-combined.cov + echo '::endgroup::' + + echo "::group::Creating PHP coverage summary" + "$BASE"/extract-php-summary-data.php artifacts/php-combined.cov > "$TMP_DIR/php-summary.tsv" + echo '::endgroup::' +else + echo "No PHP coverage files found!" + touch "$TMP_DIR/php-summary.tsv" +fi -echo "::group::Creating JS coverage summary" -mkdir "$TMP_DIR/js" -cp artifacts/js-combined.json "$TMP_DIR/js" -pnpm --filter=jetpack-gh-config-munger exec nyc report --no-exclude-after-remap --report-dir="$TMP_DIR" --temp-dir="$TMP_DIR/js" --reporter=json-summary -jq -r 'to_entries[] | select( .key != "total" ) | [ .key, .value.lines.total, .value.lines.covered ] | @tsv' "$TMP_DIR/coverage-summary.json" > "$TMP_DIR/js-summary.tsv" -echo '::endgroup::' +TMP=$( find "$PWD/coverage" -name '*.json' ) +if [[ -n "$TMP" ]]; then + echo "::group::Combining JS coverage" + pnpm --filter=jetpack-gh-config-munger exec istanbul-merge --out "$PWD"/artifacts/js-combined.json $TMP + perl -i -pwe 'BEGIN { $prefix = shift; $prefix=~s!/*$!/!; $re = qr/\Q$prefix\E/; } s!"$re!"!g' "$GITHUB_WORKSPACE" artifacts/js-combined.json + echo '::endgroup::' + + echo "::group::Creating JS coverage summary" + mkdir "$TMP_DIR/js" + cp artifacts/js-combined.json "$TMP_DIR/js" + pnpm --filter=jetpack-gh-config-munger exec nyc report --no-exclude-after-remap --report-dir="$TMP_DIR" --temp-dir="$TMP_DIR/js" --reporter=json-summary + jq -r 'to_entries[] | select( .key != "total" ) | [ .key, .value.lines.total, .value.lines.covered ] | @tsv' "$TMP_DIR/coverage-summary.json" > "$TMP_DIR/js-summary.tsv" + echo '::endgroup::' +else + echo "No JS coverage files found!" + touch "$TMP_DIR/js-summary.tsv" +fi echo "::group::Combining coverage summaries" sort "$TMP_DIR/php-summary.tsv" "$TMP_DIR/js-summary.tsv" > artifacts/summary.tsv diff --git a/.github/files/generate-ci-matrix.php b/.github/files/generate-ci-matrix.php index 4fa03fb9c8d48..78b7074022c0d 100755 --- a/.github/files/generate-ci-matrix.php +++ b/.github/files/generate-ci-matrix.php @@ -65,21 +65,10 @@ 'script' => 'test-php', 'php' => $php, 'wp' => 'latest', - 'timeout' => 20, // 2023-08-17: Successful runs seem to take up to ~12 minutes. + 'timeout' => 20, // 2024-11-12: Successful runs seem to take up to ~7 minutes. ); } -// TODO: When WordPress 6.5 is no longer supported, this can be removed. Runs too slow on ubuntu-24.04 (ubuntu-latest). -$matrix[] = array( - 'name' => 'PHP tests: PHP 7.0 WP previous', - 'runner' => 'ubuntu-22.04', - 'script' => 'test-php', - 'php' => '7.0', - 'wp' => 'previous', - 'timeout' => 20, // 2023-08-17: Successful runs seem to take up to ~12 minutes. - 'force-package-tests' => true, -); - foreach ( array( 'previous', 'trunk' ) as $wp ) { $phpver = $versions['PHP_VERSION']; $matrix[] = array( @@ -87,7 +76,7 @@ 'script' => 'test-php', 'php' => $phpver, 'wp' => $wp, - 'timeout' => 15, // 2021-01-18: Successful runs seem to take ~8 minutes for the 7.4 trunk run, ~5.5-6 for 7.x and 8.0. + 'timeout' => 15, // 2024-11-12: Successful runs seem to take ~7 minutes with PHP 8.2. ); } @@ -115,7 +104,7 @@ $matrix[] = array( 'name' => 'JS tests', 'script' => 'test-js', - 'timeout' => 15, // 2021-01-18: Successful runs seem to take ~5 minutes. + 'timeout' => 15, // 2024-11-12: Successful runs seem to take ~5 minutes. ); // Add Coverage tests. @@ -123,7 +112,7 @@ 'name' => 'Code coverage', 'script' => 'test-coverage', 'wp' => 'latest', - 'timeout' => 40, // 2024-10-30: Successful runs seem to take ~30 minutes. We'll need to improve that. + 'timeout' => 40, // 2024-11-12: Successful runs seem to take ~14 minutes. ); // END matrix definitions. diff --git a/.github/files/phpcompatibility-dev-phpcs.xml b/.github/files/phpcompatibility-dev-phpcs.xml index 300dc543d04cb..59c6bab7d92c8 100644 --- a/.github/files/phpcompatibility-dev-phpcs.xml +++ b/.github/files/phpcompatibility-dev-phpcs.xml @@ -8,8 +8,5 @@ - - - diff --git a/.github/files/select-wordpress-tag.sh b/.github/files/select-wordpress-tag.sh index 920d628f4e2e0..3e7bbe766242d 100755 --- a/.github/files/select-wordpress-tag.sh +++ b/.github/files/select-wordpress-tag.sh @@ -20,7 +20,7 @@ case "$WP_BRANCH" in previous) # We hard-code the version here because there's a time near WP releases where # we've dropped the old 'previous' but WP hasn't actually released the new 'latest' - WORDPRESS_TAG=6.5 + WORDPRESS_TAG=6.6 ;; *) echo "Unrecognized value for WP_BRANCH: $WP_BRANCH" >&2 diff --git a/.github/versions.sh b/.github/versions.sh index 0064576962d11..839057a1c8579 100644 --- a/.github/versions.sh +++ b/.github/versions.sh @@ -5,5 +5,5 @@ NODE_VERSION=22.9.0 PNPM_VERSION=9.3.0 # Other useful version numbers. -MIN_PHP_VERSION=7.0 +MIN_PHP_VERSION=7.2 MAX_PHP_VERSION=8.3 diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml index dce7a5cd5d839..df0f263673272 100644 --- a/.github/workflows/linting.yml +++ b/.github/workflows/linting.yml @@ -171,7 +171,7 @@ jobs: strategy: fail-fast: false matrix: - php-versions: [ '7.0', '7.2', '7.4', '8.0', '8.1', '8.2', '8.3' ] + php-versions: [ '7.2', '7.4', '8.0', '8.1', '8.2', '8.3' ] experimental: [ false ] steps: diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index cfd8b156fc24a..a18c812be4b0d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -251,7 +251,7 @@ jobs: - name: Process coverage results env: CHANGED: ${{ steps.changed.outputs.projects }} - if: matrix.script == 'test-coverage' + if: matrix.script == 'test-coverage' && always() run: .github/files/coverage-munger/process-coverage.sh - name: Check for artifacts diff --git a/.phan/config.base.php b/.phan/config.base.php index 9ffd5b166aa90..97c272c219115 100644 --- a/.phan/config.base.php +++ b/.phan/config.base.php @@ -268,11 +268,5 @@ function make_phan_config( $dir, $options = array() ) { $config['minimum_target_php_version'] = $m[1]; } - // Disable PhanDeprecatedImplicitNullableParam if still supporting PHP 7.0 - // @todo Remove this once we drop PHP 7.0 support everywhere. - if ( isset( $config['minimum_target_php_version'] ) && version_compare( $config['minimum_target_php_version'], '7.1.0', '<' ) ) { - $config['suppress_issue_types'][] = 'PhanDeprecatedImplicitNullableParam'; - } - return $config; } diff --git a/.phpcs.config.xml b/.phpcs.config.xml index 4bb9600a8e194..3b2916e6d59b4 100644 --- a/.phpcs.config.xml +++ b/.phpcs.config.xml @@ -2,8 +2,8 @@ - - + + diff --git a/composer.json b/composer.json index 2d5f3a9e63855..7e5fc35127c0e 100644 --- a/composer.json +++ b/composer.json @@ -15,8 +15,8 @@ "phan/phan": "^5.4", "php-parallel-lint/php-parallel-lint": "^1.4.0", "php-stubs/woocommerce-stubs": ">=8.7", - "php-stubs/wordpress-stubs": ">=6.5", - "php-stubs/wordpress-tests-stubs": ">=6.5", + "php-stubs/wordpress-stubs": ">=6.6", + "php-stubs/wordpress-tests-stubs": ">=6.6", "php-stubs/wp-cli-stubs": "^2.10", "sirbrillig/phpcs-changed": "^2.11.5", "squizlabs/php_codesniffer": "^3.6.2" diff --git a/composer.lock b/composer.lock index 6913f73b280a7..827ca54d3572c 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c9fc8342729e916410c963d050a22782", + "content-hash": "4e5d0ab379d2df5496c6454eccaeff2b", "packages": [], "packages-dev": [ { @@ -13,10 +13,10 @@ "dist": { "type": "path", "url": "projects/packages/ignorefile", - "reference": "f50f9c9e55fbcb3cb0e8bbdcce950bf8fec6b107" + "reference": "8f2d11d1b20847517f10a70eef2e362084bdffdc" }, "require": { - "php": ">=7.0" + "php": ">=7.2" }, "require-dev": { "automattic/jetpack-changelogger": "@dev", @@ -187,11 +187,11 @@ "dist": { "type": "path", "url": "projects/packages/phpcs-filter", - "reference": "dbe1ec842434405b5f5e1805bcfddb851b821199" + "reference": "0425b29cbd8e6ee012478f89f605f593f3beda54" }, "require": { "automattic/ignorefile": "@dev", - "php": ">=7.0", + "php": ">=7.2", "squizlabs/php_codesniffer": "^3.6.1" }, "require-dev": { @@ -1059,16 +1059,16 @@ }, { "name": "php-stubs/woocommerce-stubs", - "version": "v9.3.3", + "version": "v9.4.0", "source": { "type": "git", "url": "https://github.com/php-stubs/woocommerce-stubs.git", - "reference": "1995245b3ebfd82eeaf3a8e9d3ec962f00ab3b73" + "reference": "008a5e9dfee9488bd2f063337e29078c0e8df65d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-stubs/woocommerce-stubs/zipball/1995245b3ebfd82eeaf3a8e9d3ec962f00ab3b73", - "reference": "1995245b3ebfd82eeaf3a8e9d3ec962f00ab3b73", + "url": "https://api.github.com/repos/php-stubs/woocommerce-stubs/zipball/008a5e9dfee9488bd2f063337e29078c0e8df65d", + "reference": "008a5e9dfee9488bd2f063337e29078c0e8df65d", "shasum": "" }, "require": { @@ -1097,9 +1097,9 @@ ], "support": { "issues": "https://github.com/php-stubs/woocommerce-stubs/issues", - "source": "https://github.com/php-stubs/woocommerce-stubs/tree/v9.3.3" + "source": "https://github.com/php-stubs/woocommerce-stubs/tree/v9.4.0" }, - "time": "2024-09-25T17:38:08+00:00" + "time": "2024-11-11T22:34:03+00:00" }, { "name": "php-stubs/wordpress-stubs", @@ -3126,6 +3126,6 @@ "platform": { "ext-json": "*" }, - "platform-dev": {}, + "platform-dev": [], "plugin-api-version": "2.6.0" } diff --git a/docs/development-environment.md b/docs/development-environment.md index 79a541d12811c..bb939ef5d6f02 100644 --- a/docs/development-environment.md +++ b/docs/development-environment.md @@ -384,9 +384,9 @@ We strongly recommend that you install tools to review your code in your IDE. It composer phpcs:lint ``` -* ### Checking Jetpack's PHP for compatibility with different versions of PHP since 7.0 +* ### Checking Jetpack's PHP for compatibility with different versions of PHP - We have a handy `composer` script that will just run the PHP CodeSniffer `PHPCompatibilityWP` ruleset checking for code not compatible with PHP 7.0 + We have a handy `composer` script that will just run the PHP CodeSniffer `PHPCompatibilityWP` ruleset checking for code not compatible with supported PHP versions: ```sh composer phpcs:compatibility diff --git a/docs/monorepo.md b/docs/monorepo.md index ca7b1c57f019c..c2b2e150bfb47 100644 --- a/docs/monorepo.md +++ b/docs/monorepo.md @@ -41,7 +41,7 @@ All GitHub Actions configuration for the monorepo, including CI, lives in `.gith ## Compatibility -All projects should be compatible with PHP versions WordPress supports. That's currently PHP 7.0 to 8.3. +All projects should be compatible with PHP versions WordPress supports. That's currently PHP 7.2 to 8.3. ## First Time @@ -266,7 +266,7 @@ If a project contains PHP tests (typically PHPUnit), it must define `.scripts.te A MySQL database is available if needed; credentials may be found in `~/.my.cnf`. Note that the host must be specified as `127.0.0.1`, as when passed `localhost` PHP will try to connect via a Unix domain socket which is not available in the Actions environment. -Tests are run with a variety of supported PHP versions from 7.0 to 8.3. If you have tests that only need to be run once, run them when `PHP_VERSION` matches that in `.github/versions.sh`. +Tests are run with a variety of supported PHP versions from 7.2 to 8.3. If you have tests that only need to be run once, run them when `PHP_VERSION` matches that in `.github/versions.sh`. #### PHP tests for non-plugins @@ -274,7 +274,7 @@ For all project types other than WordPress plugins, the necessary version of PHP We currently make use of the following packages in testing; it's encouraged to use these rather than introducing other tools that serve the same purpose. -* [yoast/phpunit-polyfills](https://packagist.org/packages/yoast/phpunit-polyfills) supplies polyfills for compatibility with PHPUnit 6.5 to 9.0, to support PHP 7.0 to 8.3. +* [yoast/phpunit-polyfills](https://packagist.org/packages/yoast/phpunit-polyfills) supplies polyfills for compatibility with PHPUnit 8.5 to 9.6, to support PHP 7.2 to 8.3. * Do not use `Yoast\PHPUnitPolyfills\TestCases\TestCase` or `Yoast\PHPUnitPolyfills\TestCases\XTestCase`. Just use the `@before`, `@after`, `@beforeClass`, and `@afterClass` annotations directly. * PHPUnit's built-in mocking is used for class mocks. * [brain/monkey](https://packagist.org/packages/brain/monkey) is used for mocking functions, and can also provide some functions for minimal WordPress compatibility. @@ -315,6 +315,53 @@ For JS tests, you'll probably have a `test` script in package.json that runs `je There's no need to be concerned about collisions with other projects' coverage files, a separate directory is used per project. The coverage files are also automatically copied to `ARTIFACTS_DIR`. +If you want to generate coverage locally, e.g. with `jetpack test coverage`, note that generating PHP coverage requires the [pcov](https://pecl.php.net/package/pcov) or [xdebug](https://pecl.php.net/package/xdebug) extensions. We use `pcov` for the CI runs; results from `xdebug` may be slightly different. + +
Installing the PHP pcov extension on Linux + +On most Linux distributions, you can install the PHP pcov extension using your package manager: + +- For Ubuntu/Debian-based systems: + ``` + sudo apt-get install php8.2-pcov + ``` +- For Arch Linux: + Install the AUR package "php-pcov" from https://aur.archlinux.org/packages/php-pcov + +For other Linux distributions, consult your package manager's documentation or consider compiling from source. + +
+ +Mac users have reported having trouble installing the PHP pcov extension. See the dropdown below for Mac-specific instructions. + +
Installing the PHP pcov extension on Mac + +This assumes you have PHP installed via Homebrew, e.g. you've done `brew install php@8.2`. + +1. First, check whether pcov is already installed by running `php --ri pcov`. If it prints something like this, you should already be good: + ``` + pcov + + PCOV support => Enabled + PCOV version => 1.0.11 + pcov.directory => /some/path/ + pcov.exclude => none + pcov.initial.memory => 65336 bytes + pcov.initial.files => 64 + ``` +2. You may need to `brew install pkg-config zlib` to install some necessary dependencies. +3. Update the list of available extensions: `pecl channel-update pecl.php.net` +4. Build the extension: `pecl install pcov` + - If the build process fails due to mkdir errors with the pecl directory, you might try `mkdir -p /opt/homebrew/lib/php/pecl` and running the install again. +5. You may also need to tell PHP where to find the newly-installed extension. + 1. Run `pecl config-get ext_dir` to find where pecl installs extensions. + 2. Run `php -r 'echo ini_get( "extension_dir" ) . "\n";'` to find where PHP currently expects extensions to live. + 3. If those are the same, great! If not, you have two options: + * If PHP's current directory is empty, you could find your `php.ini` file (`php --ini`) and change `extension_dir` to pecl's location. + * Or else, pecl probably added `extension=pcov.so` to an ini file somewhere. You could change the `pcov.so` value to be the full path inside pecl's directory. + +
+ ## Mirror repositories Most projects in the monorepo should have a mirror repository holding a built version of the project, ready for deployment. Follow these steps to create the mirror repo and configure the monorepo tooling to push to it. diff --git a/docs/testing/regression-checklist/regression-checklist.md b/docs/testing/regression-checklist/regression-checklist.md index 73ac25801ec83..f1daf606aee41 100644 --- a/docs/testing/regression-checklist/regression-checklist.md +++ b/docs/testing/regression-checklist/regression-checklist.md @@ -21,7 +21,7 @@ NOTE: it might become outdated, so it could be a good idea to generate this file ### PHP versions(Low) -- 7.0 - current +- 7.2 - current ### Hosting providers(High) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 06138f17aa57a..d5467c22fe6d4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1695,6 +1695,9 @@ importers: '@wordpress/browserslist-config': specifier: 6.11.0 version: 6.11.0 + concurrently: + specifier: 7.6.0 + version: 7.6.0 jest: specifier: 29.7.0 version: 29.7.0 @@ -1725,12 +1728,15 @@ importers: '@automattic/jetpack-connection': specifier: workspace:* version: link:../../js-packages/connection + '@tanstack/react-query': + specifier: 5.20.5 + version: 5.20.5(react@18.3.1) '@wordpress/api-fetch': specifier: 7.11.0 version: 7.11.0 '@wordpress/components': specifier: 28.11.0 - version: 28.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 28.11.0(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@wordpress/data': specifier: 10.11.0 version: 10.11.0(react@18.3.1) @@ -1743,6 +1749,9 @@ importers: '@wordpress/i18n': specifier: 5.11.0 version: 5.11.0 + moment: + specifier: 2.29.4 + version: 2.29.4 prop-types: specifier: ^15.8.1 version: 15.8.1 @@ -1773,10 +1782,13 @@ importers: version: 10.4.0 '@testing-library/react': specifier: 16.0.1 - version: 16.0.1(@testing-library/dom@10.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + version: 16.0.1(@testing-library/dom@10.4.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@testing-library/user-event': specifier: 14.5.2 version: 14.5.2(@testing-library/dom@10.4.0) + '@types/react': + specifier: 18.3.3 + version: 18.3.3 '@wordpress/browserslist-config': specifier: 6.11.0 version: 6.11.0 @@ -1795,6 +1807,9 @@ importers: sass-loader: specifier: 12.4.0 version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) + typescript: + specifier: 5.0.4 + version: 5.0.4 webpack: specifier: 5.94.0 version: 5.94.0(webpack-cli@4.9.1) @@ -2031,6 +2046,9 @@ importers: '@types/qs': specifier: 6.9.16 version: 6.9.16 + concurrently: + specifier: 7.6.0 + version: 7.6.0 jest: specifier: 29.7.0 version: 29.7.0(@types/node@20.17.6) @@ -2539,6 +2557,9 @@ importers: '@types/react': specifier: 18.3.12 version: 18.3.12 + concurrently: + specifier: 7.6.0 + version: 7.6.0 jest: specifier: 29.7.0 version: 29.7.0 @@ -2954,6 +2975,9 @@ importers: autoprefixer: specifier: 10.4.14 version: 10.4.14(postcss@8.4.47) + concurrently: + specifier: 7.6.0 + version: 7.6.0 copy-webpack-plugin: specifier: 11.0.0 version: 11.0.0(webpack@5.94.0(webpack-cli@4.9.1)) @@ -4112,97 +4136,6 @@ importers: specifier: workspace:* version: link:../../../../../tools/e2e-commons - projects/plugins/migration: - dependencies: - '@automattic/jetpack-analytics': - specifier: workspace:* - version: link:../../js-packages/analytics - '@automattic/jetpack-api': - specifier: workspace:* - version: link:../../js-packages/api - '@automattic/jetpack-base-styles': - specifier: workspace:* - version: link:../../js-packages/base-styles - '@automattic/jetpack-components': - specifier: workspace:* - version: link:../../js-packages/components - '@automattic/jetpack-connection': - specifier: workspace:* - version: link:../../js-packages/connection - '@automattic/jetpack-shared-extension-utils': - specifier: workspace:* - version: link:../../js-packages/shared-extension-utils - '@automattic/typography': - specifier: 1.0.0 - version: 1.0.0 - '@wordpress/components': - specifier: 28.11.0 - version: 28.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@wordpress/data': - specifier: 10.11.0 - version: 10.11.0(react@18.3.1) - '@wordpress/date': - specifier: 5.11.0 - version: 5.11.0 - '@wordpress/element': - specifier: 6.11.0 - version: 6.11.0 - '@wordpress/i18n': - specifier: 5.11.0 - version: 5.11.0 - react: - specifier: 18.3.1 - version: 18.3.1 - react-dom: - specifier: 18.3.1 - version: 18.3.1(react@18.3.1) - devDependencies: - '@automattic/jetpack-webpack-config': - specifier: workspace:* - version: link:../../js-packages/webpack-config - '@babel/core': - specifier: 7.26.0 - version: 7.26.0 - '@babel/preset-env': - specifier: 7.26.0 - version: 7.26.0(@babel/core@7.26.0) - '@babel/runtime': - specifier: 7.26.0 - version: 7.26.0 - '@wordpress/browserslist-config': - specifier: 6.11.0 - version: 6.11.0 - concurrently: - specifier: 7.6.0 - version: 7.6.0 - sass: - specifier: 1.64.1 - version: 1.64.1 - sass-loader: - specifier: 12.4.0 - version: 12.4.0(sass@1.64.1)(webpack@5.94.0(webpack-cli@4.9.1)) - webpack: - specifier: 5.94.0 - version: 5.94.0(webpack-cli@4.9.1) - webpack-cli: - specifier: 4.9.1 - version: 4.9.1(webpack@5.94.0) - - projects/plugins/migration/tests/e2e: - devDependencies: - '@playwright/test': - specifier: 1.45.1 - version: 1.45.1 - allure-playwright: - specifier: 2.9.2 - version: 2.9.2 - config: - specifier: 3.3.7 - version: 3.3.7 - jetpack-e2e-commons: - specifier: workspace:* - version: link:../../../../../tools/e2e-commons - projects/plugins/mu-wpcom-plugin: {} projects/plugins/protect: @@ -7455,6 +7388,9 @@ packages: '@types/react@18.3.12': resolution: {integrity: sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==} + '@types/react@18.3.3': + resolution: {integrity: sha512-hti/R0pS0q1/xx+TsI73XIqk26eBsISZ2R0wUijXIngRK9R/e7Xw/cXVxQK7R5JjW+SV4zGcn5hXjudkN/pLIw==} + '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} @@ -15285,6 +15221,22 @@ snapshots: transitivePeerDependencies: - supports-color + '@emotion/react@11.13.3(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.0 + '@emotion/babel-plugin': 11.12.0 + '@emotion/cache': 11.13.1 + '@emotion/serialize': 1.3.2 + '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) + '@emotion/utils': 1.4.1 + '@emotion/weak-memoize': 0.4.0 + hoist-non-react-statics: 3.3.2 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + transitivePeerDependencies: + - supports-color + '@emotion/react@11.13.3(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 @@ -15324,6 +15276,21 @@ snapshots: transitivePeerDependencies: - supports-color + '@emotion/styled@11.13.0(@emotion/react@11.13.3(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.0 + '@emotion/babel-plugin': 11.12.0 + '@emotion/is-prop-valid': 1.3.1 + '@emotion/react': 11.13.3(@types/react@18.3.3)(react@18.3.1) + '@emotion/serialize': 1.3.2 + '@emotion/use-insertion-effect-with-fallbacks': 1.1.0(react@18.3.1) + '@emotion/utils': 1.4.1 + react: 18.3.1 + optionalDependencies: + '@types/react': 18.3.3 + transitivePeerDependencies: + - supports-color + '@emotion/styled@11.13.0(@emotion/react@11.13.3(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 @@ -17148,6 +17115,15 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 + '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@babel/runtime': 7.26.0 + '@testing-library/dom': 10.4.0 + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.3 + '@testing-library/react@16.0.1(@testing-library/dom@10.4.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@babel/runtime': 7.26.0 @@ -17378,6 +17354,11 @@ snapshots: '@types/prop-types': 15.7.13 csstype: 3.1.3 + '@types/react@18.3.3': + dependencies: + '@types/prop-types': 15.7.13 + csstype: 3.1.3 + '@types/resolve@1.20.2': {} '@types/resolve@1.20.6': {} @@ -18206,6 +18187,60 @@ snapshots: - '@types/react' - supports-color + '@wordpress/components@28.11.0(@types/react@18.3.3)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@ariakit/react': 0.4.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@babel/runtime': 7.25.7 + '@emotion/cache': 11.13.1 + '@emotion/css': 11.13.4 + '@emotion/react': 11.13.3(@types/react@18.3.3)(react@18.3.1) + '@emotion/serialize': 1.3.2 + '@emotion/styled': 11.13.0(@emotion/react@11.13.3(@types/react@18.3.3)(react@18.3.1))(@types/react@18.3.3)(react@18.3.1) + '@emotion/utils': 1.4.1 + '@floating-ui/react-dom': 2.1.2(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@types/gradient-parser': 0.1.3 + '@types/highlight-words-core': 1.2.1 + '@use-gesture/react': 10.3.1(react@18.3.1) + '@wordpress/a11y': 4.11.0 + '@wordpress/compose': 7.11.0(react@18.3.1) + '@wordpress/date': 5.11.0 + '@wordpress/deprecated': 4.11.0 + '@wordpress/dom': 4.11.0 + '@wordpress/element': 6.11.0 + '@wordpress/escape-html': 3.11.0 + '@wordpress/hooks': 4.11.0 + '@wordpress/html-entities': 4.11.0 + '@wordpress/i18n': 5.11.0 + '@wordpress/icons': 10.11.0(react@18.3.1) + '@wordpress/is-shallow-equal': 5.11.0 + '@wordpress/keycodes': 4.11.0 + '@wordpress/primitives': 4.11.0(react@18.3.1) + '@wordpress/private-apis': 1.11.0 + '@wordpress/rich-text': 7.11.0(react@18.3.1) + '@wordpress/warning': 3.11.0 + change-case: 4.1.2 + clsx: 2.1.1 + colord: 2.9.3 + date-fns: 3.6.0 + deepmerge: 4.3.1 + fast-deep-equal: 3.1.3 + framer-motion: 11.4.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + gradient-parser: 0.1.5 + highlight-words-core: 1.2.3 + is-plain-object: 5.0.0 + memize: 2.1.0 + path-to-regexp: 6.3.0 + re-resizable: 6.10.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react: 18.3.1 + react-colorful: 5.6.1(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + react-dom: 18.3.1(react@18.3.1) + remove-accents: 0.5.0 + uuid: 9.0.1 + transitivePeerDependencies: + - '@emotion/is-prop-valid' + - '@types/react' + - supports-color + '@wordpress/components@28.11.0(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@ariakit/react': 0.4.13(react-dom@18.3.1(react@18.3.1))(react@18.3.1) diff --git a/projects/plugins/migration/changelog/update-my-jetpack-protect-card-waf-dependency b/projects/github-actions/pr-is-up-to-date/changelog/force-a-release similarity index 57% rename from projects/plugins/migration/changelog/update-my-jetpack-protect-card-waf-dependency rename to projects/github-actions/pr-is-up-to-date/changelog/force-a-release index 59c80f69574e5..d4ad6c7cc3379 100644 --- a/projects/plugins/migration/changelog/update-my-jetpack-protect-card-waf-dependency +++ b/projects/github-actions/pr-is-up-to-date/changelog/force-a-release @@ -1,4 +1,4 @@ Significance: patch Type: changed -Update composer lock file +Update dependencies. diff --git a/projects/plugins/migration/changelog/add-mj-protect-card-auto-firewall-status b/projects/github-actions/push-to-mirrors/changelog/force-a-release similarity index 56% rename from projects/plugins/migration/changelog/add-mj-protect-card-auto-firewall-status rename to projects/github-actions/push-to-mirrors/changelog/force-a-release index 66603f18e7ca1..d4ad6c7cc3379 100644 --- a/projects/plugins/migration/changelog/add-mj-protect-card-auto-firewall-status +++ b/projects/github-actions/push-to-mirrors/changelog/force-a-release @@ -1,5 +1,4 @@ Significance: patch Type: changed -Comment: update lock file - +Update dependencies. diff --git a/projects/github-actions/repo-gardening/README.md b/projects/github-actions/repo-gardening/README.md index 8b4369ae04c85..194b9f640b30c 100644 --- a/projects/github-actions/repo-gardening/README.md +++ b/projects/github-actions/repo-gardening/README.md @@ -18,7 +18,6 @@ Here is the current list of tasks handled by this action: - Triage Issues (`triageIssues`): Adds labels to issues based on issue content, and send Slack notifications depending on Priority. - Gather support references (`gatherSupportReferences`): Adds a new comment with a list of all support references on the issue, and escalates that issue via a Slack message if needed. - Reply to customers Reminder ( `replyToCustomersReminder` ): sends a Slack message about closed issues to remind Automatticians to update customers. -- Update Board (`updateBoard`): this task updates specific columns in a GitHub Project board, based on labels applied to an issue. Some of the tasks are may not satisfy your needs. If that's the case, you can use the `tasks` option to limit the action to the list of tasks you need in your repo. See the example below to find out more. @@ -84,9 +83,9 @@ The action relies on the following parameters. - (Optional) `slack_he_triage_channel` is the Slack public channel ID where messages for the HE Triage team will be posted. The value should be stored in a secret. - (Optional) `slack_quality_channel` is the Slack public channel ID where issues needing extra triage / escalation will be sent. The value should be stored in a secret. - (Optional) `reply_to_customers_threshold`. It is optional, and defaults to 10. It is the minimum number of support references needed to trigger an alert that we need to reply to customers. -- (Optional) `triage_projects_token` is a [personal access token](https://github.com/settings/tokens/new) with `repo` and `project` scopes. The token should be stored in a secret. This is required if you want to use the `updateBoard` task. -- (Optional) `project_board_url` is the URL of a GitHub Project Board. We'll automate some of the work on that board in the `updateBoard` task. -- (Optional) `labels_team_assignments` is a list of features you can provide, with matching team names, as specified in the "Team" field of your GitHub Project Board used for the `updateBoard` task, and lists of labels in use in your repository. +- (Optional) `triage_projects_token` is a [personal access token](https://github.com/settings/tokens/new) with `repo` and `project` scopes. The token should be stored in a secret. This is required if you want to use the `triageIssues` task. +- (Optional) `project_board_url` is the URL of a GitHub Project Board. We'll automate some of the work on that board in the `triageIssues` task. +- (Optional) `labels_team_assignments` is a list of features you can provide, with matching team names, as specified in the "Team" field of your GitHub Project Board used for the `triageIssues` task, and lists of labels in use in your repository. - (Optional) `openai_api_key` is the API key for OpenAI. This is required if you want to use the `triageIssues` task to automatically add labels to your issues. **Note**: this option is only available for Automattic-hosted repositories. #### How to create a Slack bot and get your SLACK_TOKEN diff --git a/projects/github-actions/repo-gardening/changelog/fix-repo-gardening-root-changelog b/projects/github-actions/repo-gardening/changelog/fix-repo-gardening-root-changelog new file mode 100644 index 0000000000000..f94a169a2abaf --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/fix-repo-gardening-root-changelog @@ -0,0 +1,4 @@ +Significance: patch +Type: fixed + +Auto-labeling: do not add a "Docs" label when a changelog.md file is modified on the root of the repo. diff --git a/projects/github-actions/repo-gardening/changelog/rm-update-board-task b/projects/github-actions/repo-gardening/changelog/rm-update-board-task new file mode 100644 index 0000000000000..e0738bc8e32a5 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/rm-update-board-task @@ -0,0 +1,4 @@ +Significance: major +Type: changed + +Board Triage: remove updateBoard task. It will now be part of the existing triageIssues task. diff --git a/projects/github-actions/repo-gardening/changelog/update-ai-labeling-conditions b/projects/github-actions/repo-gardening/changelog/update-ai-labeling-conditions new file mode 100644 index 0000000000000..1cde7d9a93879 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/update-ai-labeling-conditions @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +AI Labeling: update conditions when labeling is triggered. diff --git a/projects/github-actions/repo-gardening/changelog/update-board-triage-issue-type-management b/projects/github-actions/repo-gardening/changelog/update-board-triage-issue-type-management new file mode 100644 index 0000000000000..c086215eea4e5 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/update-board-triage-issue-type-management @@ -0,0 +1,4 @@ +Significance: minor +Type: added + +Board Triage: automatically add the issue type to our project board when a Type label can be found in the issue. diff --git a/projects/github-actions/repo-gardening/changelog/update-escalate-issue-multiple b/projects/github-actions/repo-gardening/changelog/update-escalate-issue-multiple new file mode 100644 index 0000000000000..de823de98b339 --- /dev/null +++ b/projects/github-actions/repo-gardening/changelog/update-escalate-issue-multiple @@ -0,0 +1,4 @@ +Significance: patch +Type: changed + +Issue escalation: allow escalating the issue to multiple teams. diff --git a/projects/github-actions/repo-gardening/src/index.js b/projects/github-actions/repo-gardening/src/index.js index 69b89af4c98bc..7c60a9ad74a83 100644 --- a/projects/github-actions/repo-gardening/src/index.js +++ b/projects/github-actions/repo-gardening/src/index.js @@ -11,18 +11,12 @@ const notifyDesign = require( './tasks/notify-design' ); const notifyEditorial = require( './tasks/notify-editorial' ); const replyToCustomersReminder = require( './tasks/reply-to-customers-reminder' ); const triageIssues = require( './tasks/triage-issues' ); -const updateBoard = require( './tasks/update-board' ); const wpcomCommitReminder = require( './tasks/wpcom-commit-reminder' ); const debug = require( './utils/debug' ); const ifNotClosed = require( './utils/if-not-closed' ); const ifNotFork = require( './utils/if-not-fork' ); const automations = [ - { - event: 'issues', - action: [ 'labeled', 'opened' ], - task: updateBoard, - }, { event: 'pull_request_target', action: [ 'opened', 'synchronize', 'edited' ], diff --git a/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js b/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js index 442b50f19ef25..6a6c66817a1ec 100644 --- a/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js +++ b/projects/github-actions/repo-gardening/src/tasks/add-labels/index.js @@ -184,8 +184,8 @@ async function getLabelsToAdd( octokit, owner, repo, number, isDraft, isRevert ) keywords.add( '[Tools] Development CLI' ); } - const docs = file.match( /^docs\/|\.md$/ ) && ! file.match( /\/CHANGELOG\.md$/ ); - if ( docs !== null ) { + const docs = file.match( /^docs\/|\.md$/ ) && ! file.match( /CHANGELOG\.md$/i ); + if ( docs ) { keywords.add( 'Docs' ); } diff --git a/projects/github-actions/repo-gardening/src/tasks/triage-issues/ai-labeling.js b/projects/github-actions/repo-gardening/src/tasks/triage-issues/ai-labeling.js new file mode 100644 index 0000000000000..411de1d846779 --- /dev/null +++ b/projects/github-actions/repo-gardening/src/tasks/triage-issues/ai-labeling.js @@ -0,0 +1,176 @@ +const { getInput } = require( '@actions/core' ); +const debug = require( '../../utils/debug' ); +const getAvailableLabels = require( '../../utils/labels/get-available-labels' ); +const getLabels = require( '../../utils/labels/get-labels' ); +const sendOpenAiRequest = require( '../../utils/openai/send-request' ); + +/* global GitHub, WebhookPayloadIssue */ + +/** + * Request a list of matching labels from Open AI that can be applied to the issue, + * based on the issue contents. + * + * @param {GitHub} octokit - Initialized Octokit REST client. + * @param {string} owner - Repository owner. + * @param {string} repo - Repository name. + * @param {string} title - Issue title. + * @param {string} body - Issue body. + * + * @return {Promise} Promise resolving to an object of labels to apply to the issue, and their explanations. + */ +async function fetchOpenAiLabelsSuggestions( octokit, owner, repo, title, body ) { + const suggestions = { labels: [], explanations: {} }; + + // Get all the Feature and Feature Group labels in the repo. + const pattern = /^(\[Feature\]|\[Feature Group\])/; + const repoLabels = await getAvailableLabels( octokit, owner, repo, pattern ); + + // If no labels are found, bail. + if ( repoLabels.length === 0 ) { + debug( + 'triage-issues > auto-label: No labels found in the repository. Aborting OpenAI request.' + ); + return suggestions; + } + + const prompt = `You must analyse the content below, composed of 2 data points pulled from a GitHub issue: + +- a title +- the issue body + +Here is the issue title. It is the most important part of the text you must analyse: + +- ${ title } + +Here is the issue body: + +********************** + +${ body } + +********************** + +You must analyze this content, and suggest labels related to the content. +The labels you will suggest must all come from the list below. +Each item on the list of labels below follows the following format: -