Analyzer CLI: Add Database scanning (#33084)

This commit is contained in:
Paul Sealock 2022-05-27 07:52:39 +12:00 committed by GitHub
parent 66633dfe1a
commit 37905dd178
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 201 additions and 7 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Add script for accessing database schema via CLI

View File

@ -9,14 +9,19 @@ import { readFileSync } from 'fs';
* Internal dependencies
*/
import { MONOREPO_ROOT } from '../../const';
import { printTemplateResults, printHookResults } from '../../print';
import {
printTemplateResults,
printHookResults,
printSchemaChange,
printDatabaseUpdates,
} from '../../print';
import {
getVersionRegex,
getFilename,
getPatches,
getHookName,
} from '../../utils';
import { generatePatch } from '../../git';
import { generatePatch, generateSchemaDiff } from '../../git';
/**
* Analyzer class
@ -85,7 +90,32 @@ export default class Analyzer extends Command {
const pluginData = this.getPluginData( flags.plugin );
this.log( `${ pluginData[ 1 ] } Version: ${ pluginData[ 0 ] }` );
this.scanChanges( patchContent, pluginData[ 0 ], flags.output );
// Avoid running this on CI for now, and only run schema diffs in the monorepo.
if (
flags.output === 'console' &&
flags.source === 'woocommerce/woocommerce'
) {
const schemaDiff = generateSchemaDiff(
flags.source,
args.compare,
flags.base,
( e: string ): void => this.error( e )
);
this.scanChanges(
patchContent,
pluginData[ 0 ],
flags.output,
schemaDiff[ 0 ] === schemaDiff[ 1 ]
);
} else {
this.scanChanges(
patchContent,
pluginData[ 0 ],
flags.output,
true
);
}
}
/**
@ -162,17 +192,20 @@ export default class Analyzer extends Command {
/**
* Scan patches for changes in templates, hooks and database schema
*
* @param {string} content Patch content.
* @param {string} version Current product version.
* @param {string} output Output style.
* @param {string} content Patch content.
* @param {string} version Current product version.
* @param {string} output Output style.
* @param {boolean} schemaEquality if schemas are equal between branches.
*/
private scanChanges(
content: string,
version: string,
output: string
output: string,
schemaEquality: boolean
): void {
const templates = this.scanTemplates( content, version );
const hooks = this.scanHooks( content, version, output );
const databaseUpdates = this.scanDatabases( content );
if ( templates.size ) {
printTemplateResults(
@ -192,6 +225,59 @@ export default class Analyzer extends Command {
} else {
this.log( 'No new hooks found' );
}
if ( ! schemaEquality ) {
printSchemaChange( version, output, ( s: string ): void =>
this.log( s )
);
} else {
this.log( 'No new schema changes found' );
}
if ( databaseUpdates ) {
printDatabaseUpdates(
databaseUpdates,
output,
( s: string ): void => this.log( s )
);
} else {
this.log( 'No database updates found' );
}
}
/**
* Scan patches for changes in the database
*
* @param {string} content Patch content.
* @param {string} version Current product version.
* @param {string} output Output style.
* @return {object|null}
*/
private scanDatabases(
content: string
): { updateFunctionName: string; updateFunctionVersion: string } | null {
CliUx.ux.action.start( 'Scanning database changes' );
const matchPatches = /^a\/(.+).php/g;
const patches = getPatches( content, matchPatches );
const databaseUpdatePatch = patches.find( ( patch ) => {
const lines = patch.split( '\n' );
const filepath = getFilename( lines[ 0 ] );
return filepath.includes( 'class-wc-install.php' );
} );
if ( ! databaseUpdatePatch ) {
return null;
}
const updateFunctionRegex = /\+{1,2}\s*'(\d.\d.\d)' => array\(\n\+{1,2}\s*'(.*)',\n\+{1,2}\s*\),/m;
const match = databaseUpdatePatch.match( updateFunctionRegex );
if ( ! match ) {
return null;
}
const updateFunctionVersion = match[ 1 ];
const updateFunctionName = match[ 2 ];
CliUx.ux.action.stop();
return { updateFunctionName, updateFunctionVersion };
}
/**

View File

@ -84,3 +84,57 @@ export const generatePatch = (
CliUx.ux.action.stop();
return content;
};
export const getSchema = (
branch: string,
error: ( s: string ) => void
): string | undefined => {
try {
// Make sure the branch is available.
fetchBranch( branch, error );
// Start spinner.
CliUx.ux.action.start( `Gathering schema from ${ branch }` );
// Save the current branch for later.
const currentBranch = execSync( 'git rev-parse --abbrev-ref HEAD' );
// Checkout branch to compare
execSync( `git checkout ${ branch }` );
const getSchemaPath =
'wp-content/plugins/woocommerce/bin/wc-get-schema.php';
// Get the schema from wp cli
const schema = execSync(
`wp-env run cli "wp eval-file '${ getSchemaPath }'"`,
{
cwd: 'plugins/woocommerce',
encoding: 'utf-8',
}
);
// Return to the current branch.
execSync( `git checkout ${ currentBranch }` );
CliUx.ux.action.stop();
return schema;
} catch ( e ) {
error( `Unable to get schema for branch ${ branch }. \n${ e }` );
}
};
/**
* Generate a schema for each branch being compared.
*
* @param {string} source The GitHub repository.
* @param {string} compare Branch/commit hash to compare against the base.
* @param {string} base Base branch/commit hash.
* @param {Function} error error print method.
* @return {Array<string|undefined>} patch string.
*/
export const generateSchemaDiff = (
source: string,
compare: string,
base: string,
error: ( s: string ) => void
): Array< string | undefined > => {
const baseSchema = getSchema( base, error );
const compareSchema = getSchema( compare, error );
return [ baseSchema, compareSchema ];
};

View File

@ -89,3 +89,53 @@ export const printHookResults = (
}
}
};
/**
* Print Schema change results.
*
* @param {string} version Version change was introduced.
* @param {string} output Output style.
* @param {Function} log Print method.
*/
export const printSchemaChange = (
version: string,
output: string,
log: ( s: string ) => void
): void => {
if ( output === 'github' ) {
// Add Github output here.
} else {
log( '\n## SCHEMA CHANGES' );
log( '---------------------------------------------------' );
log( ` NOTICE | Schema changes detected in ${ version }` );
log( '---------------------------------------------------' );
}
};
/**
*
* @param {Object} databaseUpdates Database update info.
* @param {string} databaseUpdates.updateFunctionName Database upodate function name.
* @param {string} databaseUpdates.updateFunctionVersion Database update version.
* @param {string} output Output style.
* @param {Function} log Print method.
*/
export const printDatabaseUpdates = (
{
updateFunctionName,
updateFunctionVersion,
}: { updateFunctionName: string; updateFunctionVersion: string },
output: string,
log: ( s: string ) => void
): void => {
if ( output === 'github' ) {
// Add Github output here.
} else {
log( '\n## DATABASE UPDATES' );
log( '---------------------------------------------------' );
log(
` NOTICE | Database update found | ${ updateFunctionName } introduced in ${ updateFunctionVersion }`
);
log( '---------------------------------------------------' );
}
};