Monrepo Utils code-freeze: Update version bump to modify release branches (#39243)
This commit is contained in:
parent
b57f988044
commit
62f02e36f8
|
@ -83,7 +83,7 @@ jobs:
|
|||
if: steps.check-freeze.outputs.freeze == 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: pnpm run utils code-freeze version-bump -o ${{ github.repository_owner }} -v ${{ steps.milestone.outputs.nextDevelopmentVersion }}.0-dev
|
||||
run: pnpm run utils code-freeze version-bump ${{ steps.milestone.outputs.nextDevelopmentVersion }}.0-dev -o ${{ github.repository_owner }}
|
||||
|
||||
- name: Generate changelog changes
|
||||
id: changelog
|
||||
|
|
|
@ -8,7 +8,10 @@ import simpleGit from 'simple-git';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { Logger } from '../../../core/logger';
|
||||
import { sparseCheckoutRepoShallow } from '../../../core/git';
|
||||
import {
|
||||
sparseCheckoutRepoShallow,
|
||||
checkoutRemoteBranch,
|
||||
} from '../../../core/git';
|
||||
import { createPullRequest } from '../../../core/github/repo';
|
||||
import { getEnvVar } from '../../../core/environment';
|
||||
import { getMajorMinor } from '../../../core/version';
|
||||
|
@ -16,16 +19,9 @@ import { bumpFiles } from './bump';
|
|||
import { validateArgs } from './lib/validate';
|
||||
import { Options } from './types';
|
||||
|
||||
const genericErrorFunction = ( err ) => {
|
||||
if ( err.git ) {
|
||||
return err.git;
|
||||
}
|
||||
throw err;
|
||||
};
|
||||
|
||||
export const versionBumpCommand = new Command( 'version-bump' )
|
||||
.description( 'Bump versions ahead of new development cycle' )
|
||||
.requiredOption( '-v, --version <version>', 'Version to bump to' )
|
||||
.argument( '<version>', 'Version to bump to' )
|
||||
.option(
|
||||
'-o --owner <owner>',
|
||||
'Repository owner. Default: woocommerce',
|
||||
|
@ -41,8 +37,19 @@ export const versionBumpCommand = new Command( 'version-bump' )
|
|||
'Base branch to create the PR against. Default: trunk',
|
||||
'trunk'
|
||||
)
|
||||
.action( async ( options: Options ) => {
|
||||
const { owner, name, version, base } = options;
|
||||
.option(
|
||||
'-d --dry-run',
|
||||
'Prepare the version bump and log a diff. Do not create a PR or push to branch',
|
||||
false
|
||||
)
|
||||
.option(
|
||||
'-c --commit-direct-to-base',
|
||||
'Commit directly to the base branch. Do not create a PR just push directly to base branch',
|
||||
false
|
||||
)
|
||||
.action( async ( version, options: Options ) => {
|
||||
const { owner, name, base, dryRun, commitDirectToBase } = options;
|
||||
|
||||
Logger.startTask(
|
||||
`Making a temporary clone of '${ owner }/${ name }'`
|
||||
);
|
||||
|
@ -67,52 +74,88 @@ export const versionBumpCommand = new Command( 'version-bump' )
|
|||
`Temporary clone of '${ owner }/${ name }' created at ${ tmpRepoPath }`
|
||||
);
|
||||
|
||||
await validateArgs( tmpRepoPath, version );
|
||||
|
||||
const git = simpleGit( {
|
||||
baseDir: tmpRepoPath,
|
||||
config: [ 'core.hooksPath=/dev/null' ],
|
||||
} );
|
||||
const majorMinor = getMajorMinor( version );
|
||||
const branch = `prep/trunk-for-next-dev-cycle-${ majorMinor }`;
|
||||
const exists = await git.raw( 'ls-remote', 'origin', branch );
|
||||
|
||||
if ( exists.trim().length > 0 ) {
|
||||
Logger.error(
|
||||
`Branch ${ branch } already exists. Run \`git push <remote> --delete ${ branch }\` and rerun this command.`
|
||||
);
|
||||
}
|
||||
|
||||
await git.checkoutBranch( branch, base ).catch( genericErrorFunction );
|
||||
|
||||
Logger.notice( `Bumping versions in ${ owner }/${ name }` );
|
||||
bumpFiles( tmpRepoPath, version );
|
||||
|
||||
Logger.notice( 'Adding and committing changes' );
|
||||
await git.add( '.' ).catch( genericErrorFunction );
|
||||
await git
|
||||
.commit( `Prep trunk for ${ majorMinor } cycle` )
|
||||
.catch( genericErrorFunction );
|
||||
|
||||
Logger.notice( 'Pushing to Github' );
|
||||
await git.push( 'origin', branch ).catch( ( e ) => {
|
||||
Logger.error( e );
|
||||
} );
|
||||
const branch = `prep/${ base }-for-next-dev-cycle-${ majorMinor }`;
|
||||
|
||||
try {
|
||||
Logger.startTask( 'Creating a pull request' );
|
||||
if ( commitDirectToBase ) {
|
||||
if ( base === 'trunk' ) {
|
||||
Logger.error(
|
||||
`The --commit-direct-to-base option cannot be used with the trunk branch as a base. A pull request must be created instead.`
|
||||
);
|
||||
}
|
||||
Logger.notice( `Checking out ${ base }` );
|
||||
await checkoutRemoteBranch( tmpRepoPath, base );
|
||||
} else {
|
||||
const exists = await git.raw( 'ls-remote', 'origin', branch );
|
||||
|
||||
const pullRequest = await createPullRequest( {
|
||||
owner,
|
||||
name,
|
||||
title: `Prep trunk for ${ majorMinor } cycle`,
|
||||
body: `This PR updates the versions in trunk to ${ version } for next development cycle.`,
|
||||
head: branch,
|
||||
base,
|
||||
} );
|
||||
Logger.notice( `Pull request created: ${ pullRequest.html_url }` );
|
||||
Logger.endTask();
|
||||
} catch ( e ) {
|
||||
Logger.error( e );
|
||||
if ( ! dryRun && exists.trim().length > 0 ) {
|
||||
Logger.error(
|
||||
`Branch ${ branch } already exists. Run \`git push <remote> --delete ${ branch }\` and rerun this command.`
|
||||
);
|
||||
}
|
||||
|
||||
if ( base !== 'trunk' ) {
|
||||
// if the base is not trunk, we need to checkout the base branch first before creating a new branch.
|
||||
Logger.notice( `Checking out ${ base }` );
|
||||
await checkoutRemoteBranch( tmpRepoPath, base );
|
||||
}
|
||||
Logger.notice( `Creating new branch ${ branch }` );
|
||||
await git.checkoutBranch( branch, base );
|
||||
}
|
||||
|
||||
Logger.notice( 'Validating arguments' );
|
||||
await validateArgs( tmpRepoPath, version, options );
|
||||
|
||||
const workingBranch = commitDirectToBase ? base : branch;
|
||||
|
||||
Logger.notice(
|
||||
`Bumping versions in ${ owner }/${ name } on ${ workingBranch } branch`
|
||||
);
|
||||
bumpFiles( tmpRepoPath, version );
|
||||
|
||||
if ( dryRun ) {
|
||||
const diff = await git.diffSummary();
|
||||
Logger.notice(
|
||||
`The version has been bumped to ${ version } in the following files:`
|
||||
);
|
||||
Logger.warn( diff.files.map( ( f ) => f.file ).join( '\n' ) );
|
||||
Logger.notice(
|
||||
'Dry run complete. No pull was request created nor was a commit made.'
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
Logger.notice( 'Adding and committing changes' );
|
||||
await git.add( '.' );
|
||||
await git.commit(
|
||||
`Prep ${ base } for ${ majorMinor } cycle with version bump to ${ version }`
|
||||
);
|
||||
|
||||
Logger.notice( `Pushing ${ workingBranch } branch to Github` );
|
||||
await git.push( 'origin', workingBranch );
|
||||
|
||||
if ( ! commitDirectToBase ) {
|
||||
Logger.startTask( 'Creating a pull request' );
|
||||
|
||||
const pullRequest = await createPullRequest( {
|
||||
owner,
|
||||
name,
|
||||
title: `Prep ${ base } for ${ majorMinor } cycle`,
|
||||
body: `This PR updates the versions in ${ base } to ${ version }.`,
|
||||
head: branch,
|
||||
base,
|
||||
} );
|
||||
Logger.notice(
|
||||
`Pull request created: ${ pullRequest.html_url }`
|
||||
);
|
||||
Logger.endTask();
|
||||
}
|
||||
} catch ( error ) {
|
||||
Logger.error( error );
|
||||
}
|
||||
} );
|
||||
|
|
|
@ -9,6 +9,7 @@ import { readFile } from 'fs/promises';
|
|||
* Internal dependencies
|
||||
*/
|
||||
import { Logger } from '../../../../core/logger';
|
||||
import { Options } from '../types';
|
||||
/**
|
||||
* Get a plugin's current version.
|
||||
*
|
||||
|
@ -17,10 +18,11 @@ import { Logger } from '../../../../core/logger';
|
|||
export const getCurrentVersion = async (
|
||||
tmpRepoPath: string
|
||||
): Promise< string | void > => {
|
||||
const filePath = join( tmpRepoPath, `plugins/woocommerce/composer.json` );
|
||||
const filePath = join( tmpRepoPath, `plugins/woocommerce/woocommerce.php` );
|
||||
try {
|
||||
const composerJSON = JSON.parse( await readFile( filePath, 'utf8' ) );
|
||||
return composerJSON.version;
|
||||
const data = await readFile( filePath, 'utf8' );
|
||||
const matches = data.match( /Version:\s*(.*)/ );
|
||||
return matches ? matches[ 1 ] : undefined;
|
||||
} catch ( e ) {
|
||||
Logger.error( e );
|
||||
}
|
||||
|
@ -48,11 +50,14 @@ export const stripPrereleaseParameters = (
|
|||
*
|
||||
* @param tmpRepoPath cloned repo path
|
||||
* @param version version to bump to
|
||||
* @param options options passed to the command
|
||||
*/
|
||||
export const validateArgs = async (
|
||||
tmpRepoPath: string,
|
||||
version: string
|
||||
version: string,
|
||||
options: Options
|
||||
): Promise< void > => {
|
||||
const { base } = options;
|
||||
const nextVersion = version;
|
||||
|
||||
if ( ! valid( nextVersion ) ) {
|
||||
|
@ -65,9 +70,9 @@ export const validateArgs = async (
|
|||
const isDevVersionBump =
|
||||
prereleaseParameters && prereleaseParameters[ 0 ] === 'dev';
|
||||
|
||||
if ( ! isDevVersionBump ) {
|
||||
if ( ! isDevVersionBump && base === 'trunk' ) {
|
||||
Logger.error(
|
||||
`Version ${ nextVersion } is not a development version bump. This tool is only intended to bump development versions for the preparation of the next development cycle.`
|
||||
`Version ${ nextVersion } is not a development version bump and cannot be applied to trunk, which only accepts development version bumps.`
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -76,6 +81,13 @@ export const validateArgs = async (
|
|||
if ( ! currentVersion ) {
|
||||
Logger.error( 'Unable to determine current version' );
|
||||
} else if ( versionLessThan( nextVersion, currentVersion ) ) {
|
||||
// Semver thinks -a.1 is less than -dev, but -a.1 from -dev will be a valid version bump.
|
||||
if (
|
||||
nextVersion.includes( 'a.' ) &&
|
||||
currentVersion.includes( 'dev' )
|
||||
) {
|
||||
return;
|
||||
}
|
||||
Logger.error(
|
||||
'The version supplied is less than the current version, please supply a valid version.'
|
||||
);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
export type Options = {
|
||||
owner?: string;
|
||||
name?: string;
|
||||
version?: string;
|
||||
base?: string;
|
||||
dryRun?: boolean;
|
||||
commitDirectToBase?: boolean;
|
||||
};
|
||||
|
|
|
@ -437,12 +437,14 @@ export const generateDiff = async (
|
|||
|
||||
/**
|
||||
*
|
||||
* @param {string} tmpRepoPath path to temporary repo
|
||||
* @param {string} branch remote branch to checkout
|
||||
* @param {string} tmpRepoPath path to temporary repo
|
||||
* @param {string} branch remote branch to checkout
|
||||
* @param {boolean} isShallow whether to do a shallow clone and get only the latest commit
|
||||
*/
|
||||
export const checkoutRemoteBranch = async (
|
||||
tmpRepoPath: string,
|
||||
branch: string
|
||||
branch: string,
|
||||
isShallow = true
|
||||
): Promise< void > => {
|
||||
const git = simpleGit( {
|
||||
baseDir: tmpRepoPath,
|
||||
|
@ -451,6 +453,10 @@ export const checkoutRemoteBranch = async (
|
|||
|
||||
// When the clone is shallow, we need to call this before fetching.
|
||||
await git.raw( [ 'remote', 'set-branches', '--add', 'origin', branch ] );
|
||||
await git.raw( [ 'fetch', 'origin', branch ] );
|
||||
const fetchArgs = [ 'fetch', 'origin', branch ];
|
||||
if ( isShallow ) {
|
||||
fetchArgs.push( '--depth=1' );
|
||||
}
|
||||
await git.raw( fetchArgs );
|
||||
await git.raw( [ 'checkout', '-b', branch, `origin/${ branch }` ] );
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue