Skip to content

Commit

Permalink
Merge branch 'trunk' into docs/update-curate-editor-filter-hooks-doc
Browse files Browse the repository at this point in the history
  • Loading branch information
ndiego committed May 15, 2024
2 parents 4706bd2 + 5b2454b commit ff035cd
Show file tree
Hide file tree
Showing 179 changed files with 3,302 additions and 2,089 deletions.
3 changes: 3 additions & 0 deletions .github/workflows/performance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ jobs:
run: |
./bin/plugin/cli.js perf $(echo $BRANCHES | tr ',' ' ') --tests-branch $GITHUB_SHA --wp-version "$WP_VERSION"
- name: Add workflow summary
run: cat ${{ env.WP_ARTIFACTS_PATH }}/summary.md >> $GITHUB_STEP_SUMMARY

- name: Archive performance results
if: success()
uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/php-changes-detection.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@ jobs:

- name: Get changed PHP files
id: changed-files-php
uses: tj-actions/changed-files@0874344d6ebbaa00a27da73276ae7162fadcaf69 # v44.3.0
uses: tj-actions/changed-files@a29e8b565651ce417abb5db7164b4a2ad8b6155c # v44.4.0
with:
files: |
**.{php}
lib/**
packages/**/*.php
phpunit/**
- name: List all changed files
if: steps.changed-files-php.outputs.any_changed == 'true'
Expand Down
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
save-exact = true
engine-strict = true
legacy-peer-deps = true
prefer-dedupe = true
9 changes: 8 additions & 1 deletion .stylelintrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
"font-weight-notation": null,
"max-line-length": null,
"no-descending-specificity": null,
"property-disallowed-list": [
[ "order" ],
{
"message": "Avoid the order property. For accessibility reasons, visual, reading, and DOM order must match. Only use the order property when it does not affect reading order, meaning, and interaction"
}
],
"rule-empty-line-before": null,
"selector-class-pattern": null,
"value-keyword-case": null,
Expand All @@ -29,5 +35,6 @@
"scss/at-else-empty-line-before": null,
"scss/at-if-closing-brace-space-after": null,
"no-invalid-position-at-import-rule": null
}
},
"reportDescriptionlessDisables": true
}
4 changes: 2 additions & 2 deletions bin/log-performance-results.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const data = new TextEncoder().encode(
performanceResults[ index ][ hash ] ?? {}
).map( ( [ key, value ] ) => [
metricsPrefix + key,
value,
typeof value === 'object' ? value.q50 : value,
] )
),
};
Expand All @@ -64,7 +64,7 @@ const data = new TextEncoder().encode(
performanceResults[ index ][ baseHash ] ?? {}
).map( ( [ key, value ] ) => [
metricsPrefix + key,
value,
typeof value === 'object' ? value.q50 : value,
] )
),
};
Expand Down
233 changes: 202 additions & 31 deletions bin/plugin/commands/performance.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const config = require( '../config' );

const ARTIFACTS_PATH =
process.env.WP_ARTIFACTS_PATH || path.join( process.cwd(), 'artifacts' );
const RESULTS_FILE_SUFFIX = '.performance-results.json';
const RESULTS_FILE_SUFFIX = '.performance-results.raw.json';

/**
* @typedef WPPerformanceCommandOptions
Expand Down Expand Up @@ -56,24 +56,97 @@ function sanitizeBranchName( branch ) {
}

/**
* Computes the median number from an array numbers.
*
* @param {number} number
*/
function fixed( number ) {
return Math.round( number * 100 ) / 100;
}

/**
* @param {number[]} array
*
* @return {number|undefined} Median value or undefined if array empty.
*/
function median( array ) {
if ( ! array || ! array.length ) {
return undefined;
function quartiles( array ) {
const numbers = array.slice().sort( ( a, b ) => a - b );

/**
* @param {number} offset
* @param {number} length
*/
function med( offset, length ) {
if ( length % 2 === 0 ) {
// even length, average of two middle numbers
return (
( numbers[ offset + length / 2 - 1 ] +
numbers[ offset + length / 2 ] ) /
2
);
}

// odd length, exact middle point
return numbers[ offset + ( length - 1 ) / 2 ];
}

const numbers = [ ...array ].sort( ( a, b ) => a - b );
const middleIndex = Math.floor( numbers.length / 2 );
const q50 = med( 0, numbers.length );

let q25, q75;
if ( numbers.length % 2 === 0 ) {
return ( numbers[ middleIndex - 1 ] + numbers[ middleIndex ] ) / 2;
// medians of two exact halves
const mid = numbers.length / 2;
q25 = med( 0, mid );
q75 = med( mid, mid );
} else {
// quartiles are average of medians of the smaller and bigger slice
const midl = ( numbers.length - 1 ) / 2;
const midh = ( numbers.length + 1 ) / 2;
q25 = ( med( 0, midl ) + med( 0, midh ) ) / 2;
q75 = ( med( midl, midh ) + med( midh, midl ) ) / 2;
}
return numbers[ middleIndex ];
return { q25, q50, q75 };
}

/**
* @param {number[]|undefined} values
*/
function stats( values ) {
if ( ! values || values.length === 0 ) {
return undefined;
}
const { q25, q50, q75 } = quartiles( values );
const cnt = values.length;
return {
q25: fixed( q25 ),
q50: fixed( q50 ),
q75: fixed( q75 ),
cnt,
};
}

/**
* Nicely formats a given value.
*
* @param {string} metric Metric.
* @param {number} value
*/
function formatValue( metric, value ) {
if ( 'wpMemoryUsage' === metric ) {
return `${ ( value / Math.pow( 10, 6 ) ).toFixed( 2 ) } MB`;
}

if ( 'wpDbQueries' === metric ) {
return value.toString();
}

return `${ value } ms`;
}

/**
* @param {string} m
* @param {Record<string, number>} s
*/
function printStats( m, s ) {
const pp = fixed( ( 100 * ( s.q75 - s.q50 ) ) / s.q50 );
const mp = fixed( ( 100 * ( s.q50 - s.q25 ) ) / s.q50 );
return `${ formatValue( m, s.q50 ) } +${ pp }% -${ mp }%`;
}

/**
Expand All @@ -96,6 +169,61 @@ async function runTestSuite( testSuite, testRunnerDir, runKey ) {
);
}

/**
* Formats an array of objects as a Markdown table.
*
* For example, this array:
*
* [
* {
* foo: 123,
* bar: 456,
* baz: 'Yes',
* },
* {
* foo: 777,
* bar: 999,
* baz: 'No',
* }
* ]
*
* Will result in the following table:
*
* | foo | bar | baz |
* |-----|-----|-----|
* | 123 | 456 | Yes |
* | 777 | 999 | No |
*
* @param {Array<Object>} rows Table rows.
* @return {string} Markdown table content.
*/
function formatAsMarkdownTable( rows ) {
let result = '';

if ( ! rows.length ) {
return result;
}

const headers = Object.keys( rows[ 0 ] );
for ( const header of headers ) {
result += `| ${ header } `;
}
result += '|\n';
for ( let i = 0; i < headers.length; i++ ) {
result += '| ------ ';
}
result += '|\n';

for ( const row of rows ) {
for ( const value of Object.values( row ) ) {
result += `| ${ value } `;
}
result += '|\n';
}

return result;
}

/**
* Runs the performances tests on an array of branches and output the result.
*
Expand Down Expand Up @@ -366,7 +494,7 @@ async function runPerformanceTests( branches, options ) {
const resultFiles = getFilesFromDir( ARTIFACTS_PATH ).filter( ( file ) =>
file.endsWith( RESULTS_FILE_SUFFIX )
);
/** @type {Record<string,Record<string, Record<string, number>>>} */
/** @type {Record<string,Record<string, Record<string, Record<string, number>>>>} */
const results = {};

// Calculate medians from all rounds.
Expand All @@ -387,20 +515,21 @@ async function runPerformanceTests( branches, options ) {
return readJSONFile( file );
} );

const metrics = Object.keys( resultsRounds[ 0 ] );
const metrics = Object.keys( resultsRounds[ 0 ] ?? {} );
results[ testSuite ][ branch ] = {};

for ( const metric of metrics ) {
const values = resultsRounds
.map( ( round ) => round[ metric ] )
.filter( ( value ) => typeof value === 'number' );
const values = resultsRounds.flatMap(
( round ) => round[ metric ] ?? []
);

const value = median( values );
const value = stats( values );
if ( value !== undefined ) {
results[ testSuite ][ branch ][ metric ] = value;
}
}
}

const calculatedResultsPath = path.join(
ARTIFACTS_PATH,
testSuite + RESULTS_FILE_SUFFIX
Expand All @@ -424,40 +553,82 @@ async function runPerformanceTests( branches, options ) {
)
);

let summaryMarkdown = `## Performance Test Results\n\n`;

summaryMarkdown += `Please note that client side metrics **exclude** the server response time.\n\n`;

for ( const testSuite of testSuites ) {
logAtIndent( 0, formats.success( testSuite ) );

// Invert the results so we can display them in a table.
/** @type {Record<string, Record<string, string>>} */
/** @type {Record<string, Record<string, Record<string, number>>>} */
const invertedResult = {};
for ( const [ branch, metrics ] of Object.entries(
results[ testSuite ]
) ) {
for ( const [ metric, value ] of Object.entries( metrics ) ) {
invertedResult[ metric ] = invertedResult[ metric ] || {};
invertedResult[ metric ][ branch ] = `${ value } ms`;
invertedResult[ metric ][ branch ] = value;
}
}

if ( branches.length === 2 ) {
const [ branch1, branch2 ] = branches;
for ( const metric in invertedResult ) {
const value1 = parseFloat(
invertedResult[ metric ][ branch1 ]
/** @type {Record<string, Record<string, string>>} */
const printedResult = {};
for ( const [ metric, branch ] of Object.entries( invertedResult ) ) {
printedResult[ metric ] = {};
for ( const [ branchName, data ] of Object.entries( branch ) ) {
printedResult[ metric ][ branchName ] = printStats(
metric,
data
);
const value2 = parseFloat(
invertedResult[ metric ][ branch2 ]
}

if ( branches.length === 2 ) {
const [ branch1, branch2 ] = branches;
const value1 = branch[ branch1 ].q50;
const value2 = branch[ branch2 ].q50;
const percentageChange = fixed(
( ( value1 - value2 ) / value2 ) * 100
);
const percentageChange = ( ( value1 - value2 ) / value2 ) * 100;
invertedResult[ metric ][
printedResult[ metric ][
'% Change'
] = `${ percentageChange.toFixed( 2 ) }%`;
] = `${ percentageChange }%`;
}
}

// Print the results.
console.table( invertedResult );
console.table( printedResult );

// Use yet another structure to generate a Markdown table.

const rows = [];

for ( const [ metric, resultBranches ] of Object.entries(
printedResult
) ) {
/**
* @type {Record< string, string >}
*/
const row = {
Metric: metric,
};

for ( const [ branch, value ] of Object.entries(
resultBranches
) ) {
row[ branch ] = value;
}
rows.push( row );
}

summaryMarkdown += `**${ testSuite }**\n\n`;
summaryMarkdown += `${ formatAsMarkdownTable( rows ) }\n`;
}

fs.writeFileSync(
path.join( ARTIFACTS_PATH, 'summary.md' ),
summaryMarkdown
);
}

module.exports = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Port: {MYSQL_PORT_NUMBER}

**Please note**: the MySQL port number will change each time `wp-env` restarts. If you find you can no longer access your database, simply repeat the steps above to find the new port number and restore your connection.

**Tip**: [Sequel Ace](https://sequel-ace.com/) is a useful GUI tool for accessing a MySQL database. Other tools are available and documented in this [article on accessing the WordPress database](https://wordpress.org/documentation/article/creating-database-for-wordpress/).
**Tip**: [Sequel Ace](https://sequel-ace.com/) is a useful GUI tool for accessing a MySQL database. Other tools are available and documented in this [article on accessing the WordPress database](https://developer.wordpress.org/advanced-administration/before-install/creating-database/).

#### Troubleshooting

Expand Down
2 changes: 1 addition & 1 deletion docs/how-to-guides/themes/global-settings-and-styles.md
Original file line number Diff line number Diff line change
Expand Up @@ -1337,4 +1337,4 @@ The value defined for the root `styles.spacing.blockGap` style is also output as

### Why does it take so long to update the styles in the browser?

When you are actively developing with theme.json you may notice it takes 30+ seconds for your changes to show up in the browser, this is because `theme.json` is cached. To remove this caching issue, set either [`WP_DEBUG`](https://wordpress.org/documentation/article/debugging-in-wordpress/#wp_debug) or [`SCRIPT_DEBUG`](https://wordpress.org/documentation/article/debugging-in-wordpress/#script_debug) to 'true' in your [`wp-config.php`](https://wordpress.org/documentation/article/editing-wp-config-php/). This tells WordPress to skip the cache and always use fresh data.
When you are actively developing with theme.json you may notice it takes 30+ seconds for your changes to show up in the browser, this is because `theme.json` is cached. To remove this caching issue, set either [`WP_DEBUG`](https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/#wp_debug) or [`SCRIPT_DEBUG`](https://developer.wordpress.org/advanced-administration/debug/debug-wordpress/#script_debug) to 'true' in your [`wp-config.php`](https://developer.wordpress.org/advanced-administration/wordpress/wp-config/). This tells WordPress to skip the cache and always use fresh data.
Loading

0 comments on commit ff035cd

Please sign in to comment.