diff --git a/tools/code-analyzer/src/commands/analyzer/index.ts b/tools/code-analyzer/src/commands/analyzer/index.ts index 34f1788d90e..b42cc9b59dc 100644 --- a/tools/code-analyzer/src/commands/analyzer/index.ts +++ b/tools/code-analyzer/src/commands/analyzer/index.ts @@ -21,6 +21,8 @@ import { getPatches, getHookName, areSchemasEqual, + getHookDescription, + getHookChangeType, } from '../../utils'; import { generatePatch, generateSchemaDiff } from '../../git'; @@ -368,18 +370,25 @@ export default class Analyzer extends Command { const matchPatches = /^a\/(.+).php/g; const patches = getPatches( content, matchPatches ); const verRegEx = getVersionRegex( version ); - const matchHooks = `@since\\s+(${ verRegEx })(.*?)(apply_filters|do_action)\\((\\s+)?(\\'|\\")(.*?)(\\'|\\")`; + const matchHooks = `\/\\*\\*(.*?)@since\\s+(${ verRegEx })(.*?)(apply_filters|do_action)\\((\\s+)?(\\'|\\")(.*?)(\\'|\\")`; const newRegEx = new RegExp( matchHooks, 'gs' ); for ( const p in patches ) { const patch = patches[ p ]; const results = patch.match( newRegEx ); + const hasHookRegex = /apply_filters|do_action/g; + const hasHook = patch.match( hasHookRegex ); const hooksList: Map< string, string[] > = new Map< string, string[] >(); if ( ! results ) { + if ( hasHook ) { + this.error( + 'A hook has been introduced or updated without a docBlock. Please add a docBlock.' + ); + } continue; } @@ -396,17 +405,32 @@ export default class Analyzer extends Command { continue; } + const description = getHookDescription( raw ); + const name = getHookName( hookName[ 3 ] ); + + if ( ! description ) { + this.error( + `Hook ${ name } has no description. Please add a description.` + ); + } + const kind = hookName[ 2 ] === 'do_action' ? 'action' : 'filter'; - const CLIMessage = `\'${ name }\' introduced in ${ version }`; + const CLIMessage = `**${ name }** introduced in ${ version }`; const GithubMessage = `\\'${ name }\\' introduced in ${ version }`; const message = output === 'github' ? GithubMessage : CLIMessage; - const title = `New ${ kind } found`; + const hookChangeType = getHookChangeType( raw ); + const title = `${ hookChangeType } ${ kind } found`; if ( ! hookName[ 2 ].startsWith( '-' ) ) { - hooksList.set( name, [ 'NOTICE', title, message ] ); + hooksList.set( name, [ + 'NOTICE', + title, + message, + description, + ] ); } } diff --git a/tools/code-analyzer/src/print.ts b/tools/code-analyzer/src/print.ts index 2e4aac89425..5972b4ae610 100644 --- a/tools/code-analyzer/src/print.ts +++ b/tools/code-analyzer/src/print.ts @@ -58,7 +58,9 @@ export const printHookResults = ( if ( value.size ) { opt += `\\n* **file:** ${ key }`; for ( const [ k, v ] of value ) { - opt += `\\n * ${ v[ 0 ].toUpperCase() }: ${ v[ 2 ] }`; + opt += `\\n * ${ v[ 0 ].toUpperCase() } - ${ v[ 2 ] }: ${ + v[ 3 ] + }`; log( `::${ v[ 0 ] } file=${ key },line=1,title=${ v[ 1 ] } - ${ k }::${ v[ 2 ] }` ); @@ -75,7 +77,7 @@ export const printHookResults = ( log( 'FILE: ' + key ); log( '---------------------------------------------------' ); for ( const [ k, v ] of value ) { - log( 'HOOK: ' + k ); + log( `HOOK: ${ k }: ${ v[ 3 ] }` ); log( '---------------------------------------------------' ); diff --git a/tools/code-analyzer/src/utils.ts b/tools/code-analyzer/src/utils.ts index 908cf2512b7..019c09fcd0e 100644 --- a/tools/code-analyzer/src/utils.ts +++ b/tools/code-analyzer/src/utils.ts @@ -193,3 +193,42 @@ export const isValidCommitHash = ( branch: string ): boolean => { return false; } }; + +/** + * Extrace hook description from a raw diff. + * + * @param {string} diff raw diff. + * @return {string|false} hook description or false if none exists. + */ +export const getHookDescription = ( diff: string ): string | false => { + const diffWithoutDeletions = diff.replace( /-.*\n/g, '' ); + + // Extract hook description. + const description = diffWithoutDeletions.match( /\/\*\*([\s\S]*) @since/ ); + + if ( ! description ) { + return false; + } + + return description[ 1 ] + .replace( / \* /g, '' ) + .replace( /\*/g, '' ) + .replace( /\+/g, '' ) + .replace( /-/g, '' ) + .replace( /\t/g, '' ) + .replace( /\n/g, '' ) + .trim(); +}; + +/** + * Determine hook change type: New or Updated. + * + * @param {string} diff raw diff. + * @return {'Updated' | 'New'} change type. + */ +export const getHookChangeType = ( diff: string ): 'Updated' | 'New' => { + const sincesRegex = /@since/g; + const sinces = diff.match( sincesRegex ) || []; + // If there is more than one 'since' in the diff, it means that line was updated meaning the hook already exists. + return sinces.length > 1 ? 'Updated' : 'New'; +};