@gravityforms/gulp-tasks
Version:
Configurable Gulp tasks for use in Gravity Forms projects.
191 lines (165 loc) • 6.64 kB
JavaScript
import { exec } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { createRequire } from 'node:module';
import getConfig from '../../config.js';
import { moduleExists, trailingSlashIt } from './util.js';
const cjsRequire = createRequire( import.meta.url );
const simpleGit = cjsRequire( 'simple-git' );
const { config } = getConfig();
const rootPath = config?.paths?.root || '';
let packagesCloned = false;
const clonePath = path.resolve( rootPath, '../gravitypackages-clone' );
const lintDependencies = [
'@babel/cli',
'@babel/core',
'@babel/eslint-parser',
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-decorators',
'@babel/plugin-proposal-object-rest-spread',
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-syntax-dynamic-import',
'@babel/plugin-transform-object-assign',
'@babel/plugin-transform-regenerator',
'@babel/plugin-transform-runtime',
'@babel/preset-env',
'@babel/preset-react',
'babel-loader',
'babel-plugin-istanbul',
'babel-plugin-module-resolver',
'eslint',
'eslint-import-resolver-webpack',
'eslint-plugin-jsdoc',
'eslint-plugin-jsx-a11y',
'eslint-plugin-react',
'eslint-plugin-react-hooks',
'stylelint',
];
function execShellCommand( cmd, printOutput = false ) {
return new Promise( ( resolve, reject ) => {
exec( cmd, ( error, stdout, stderr ) => {
if ( error ) {
console.error( `exec error: ${ error }` );
reject( error );
return;
}
if ( stderr ) {
console.error( `stderr: ${ stderr }` );
}
if ( stdout && printOutput ) {
console.log( `stdout: ${ stdout }` );
}
resolve( stdout );
} );
} );
}
const readJson = ( filePath ) => JSON.parse( fs.readFileSync( filePath, 'utf8' ) );
const updatePeerDependencies = async ( projectPackageJsonPath, monorepoPackageJsonPath ) => {
const monorepoPackageJson = readJson( monorepoPackageJsonPath );
const projectPackageJson = readJson( projectPackageJsonPath );
const dependenciesToAdd = Object.fromEntries(
Object.entries( monorepoPackageJson.dependencies || {} )
.filter( ( [ key ] ) => lintDependencies.includes( key ) ),
);
console.log( 'Adding the following peer dependencies to package.json:', dependenciesToAdd );
projectPackageJson.dependencies = projectPackageJson.dependencies || {};
Object.assign( projectPackageJson.dependencies, dependenciesToAdd );
projectPackageJson.scripts = projectPackageJson.scripts || {};
fs.writeFileSync( projectPackageJsonPath, JSON.stringify( projectPackageJson, null, 2 ) );
};
async function getCurrentBranch( localPath ) {
const git = simpleGit( localPath );
const branchSummary = await git.branchLocal();
return branchSummary.current;
}
async function fetchRemotePackagesBranches() {
const git = simpleGit();
try {
const remoteInfo = await git.listRemote( [
'--heads',
`https://x-access-token:${ process.env.GITHUB_TOKEN }@github.com/gravityforms/gravitypackages.git`,
] );
return remoteInfo.split( '\n' )
.filter( ( line ) => !! line.trim() )
.map( ( line ) => {
const parts = line.split( '\t' );
const ref = parts[ 1 ];
return ref.replace( 'refs/heads/', '' );
} );
} catch ( error ) {
console.error( 'Failed to fetch branches:', error );
throw error;
}
}
async function cloneIfBranchMatches() {
const localBranchName = await getCurrentBranch( rootPath );
if ( localBranchName === 'master' || localBranchName === 'main' ) {
console.log( `Current branch is ${ localBranchName }, skipping monorepo link checking.` );
return;
}
const remoteBranches = await fetchRemotePackagesBranches();
if ( remoteBranches.includes( localBranchName ) ) {
console.log( `Cloning gravitypackages repo on branch ${ localBranchName } to ${ clonePath }` );
if ( ! fs.existsSync( clonePath ) ) {
packagesCloned = true;
fs.mkdirSync( clonePath, { recursive: true } );
const git = simpleGit( clonePath );
const repoUrl = `https://x-access-token:${ process.env.GITHUB_TOKEN }@github.com/gravityforms/gravitypackages.git`;
await git.clone( repoUrl, clonePath, [ '--branch', localBranchName ] );
console.log( `Cloned gravitypackages repo on branch ${ localBranchName } into ${ clonePath }` );
} else {
console.log( `Target directory ${ clonePath } already exists.` );
}
} else {
console.log( 'No matching branch found in Gravity Packages during monorepo linking.' );
}
}
async function linkPackages() {
const packageJsonSrc = path.join( rootPath, 'package.json' );
const packageJson = readJson( packageJsonSrc );
if ( ! packageJson?.dependencies ) {
console.log( 'Package.json not found during linking, exiting.' );
return;
}
const gulpTasksPackageJsonSrc = trailingSlashIt( clonePath ) + 'packages/npm/gulp-tasks/package.json';
const gulpTasksPackageJson = moduleExists( gulpTasksPackageJsonSrc ) ? readJson( gulpTasksPackageJsonSrc ) : {};
const hasGenerateDistScript = gulpTasksPackageJson?.scripts?.[ 'generate:dist' ];
const targets = Object.keys( packageJson.dependencies )
.filter( ( dep ) => dep.startsWith( '@gravityforms/' ) )
.map( ( dep ) => `${ trailingSlashIt( clonePath ) }packages/npm/${ dep.slice( 14 ) }` );
if ( targets.length === 0 ) {
console.log( 'No packages to link, exiting.' );
return;
}
console.log( 'Updating peer dependencies...' );
await updatePeerDependencies( packageJsonSrc, gulpTasksPackageJsonSrc );
console.log( 'Installing packages root...' );
await execShellCommand( `cd '${ trailingSlashIt( clonePath ) }' && npm ci`, true );
console.log( 'Installing gulp tasks...' );
await execShellCommand( `cd '${ trailingSlashIt( clonePath ) }packages/npm/gulp-tasks' && npm ci`, true );
if ( ! hasGenerateDistScript ) {
console.log( 'Exporting components...' );
await execShellCommand( `cd '${ trailingSlashIt( clonePath ) }' && npm run export:components`, true );
} else {
console.log( 'Generating packages dist and exporting components...' );
await execShellCommand( `cd '${ trailingSlashIt( clonePath ) }' && npm run packages:dist`, true );
}
const cmd = `cd ${ rootPath } && npm link ${ targets.map( ( target ) => `'${ target }'` ).join( ' ' ) }`;
console.log( 'Executing link command: ', cmd );
await execShellCommand( cmd, true );
}
( async () => {
try {
if ( process.env.GULP_PRODUCTION_MODE !== 'true' ) {
console.log( 'Skipping linking packages repo because GULP_PRODUCTION_MODE is not set to true.' );
return;
}
await cloneIfBranchMatches();
if ( packagesCloned ) {
await linkPackages();
}
} catch ( err ) {
console.error( 'An error occurred during linking:', err );
}
} )();