Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implemented root repository feature #162

Merged
merged 9 commits into from
Aug 25, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ CLI options:
Default: null

--preset Uses an alternative set of dependencies defined in the config file.

--skip-root Allows skipping root repository when executing command,
if "$rootRepository" is defined in the config file.
```

All these options can also be specified in `mrgit.json` (options passed through CLI takes precedence):
Expand Down Expand Up @@ -187,6 +190,39 @@ Example:
}
```

### The `$rootRepository` option

`mrgit` allows for handling of the root repository as well. If such behavior is desired, `$rootRepository` option can be used in the config. When configured, using eg. the `pull` command will affect the root repository in addition to the usual dependencies. If required, this behavior can be disabled with the `--skip-root` CLI option. Additionally, the `$rootRepository` key can be included in any preset, and will work accordingly to presets logic.
przemyslaw-zan marked this conversation as resolved.
Show resolved Hide resolved

Not all commands are support execution in the root repository. If a command does not support this feature, it is executed normally, without affecting the root repository. Currently supported commands are:
przemyslaw-zan marked this conversation as resolved.
Show resolved Hide resolved

- `checkout`
- `commit`
- `diff`
- `exec`
- `fetch`
- `pull`
- `push`
- `status`
- `sync`

Example config:

```json
{
"packages": "/workspace/modules",
"$rootRepository": "cksource/root-repository",
"dependencies": {
"foo": "bar"
},
"presets": {
"dev": {
"$rootRepository": "cksource/root-repository#dev"
}
}
}
```

### Recursive cloning

When the `--recursive` option is used `mrgit` will clone repositories recursively. First, it will clone the `dependencies` specified in `mrgit.json` and, then, their `dependencies` and `devDependencies` specified in `package.json` files located in cloned repositories.
Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ function handleCli() {

${ y( '--preset' ) } Uses an alternative set of dependencies defined in the config file.

${ y( '--skip-root' ) } Allows skipping root repository when executing command,
if "${ u( '$rootRepository' ) }" is defined in the config file.

${ u( 'Git Options:' ) }
Git options are supported by the following commands: commit, diff, fetch, push.
Type "mrgit [command] -h" in order to see which options are supported.
Expand Down
2 changes: 2 additions & 0 deletions lib/commands/close.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const buildOptions = require( 'minimist-options' );
const minimist = require( 'minimist' );

module.exports = {
name: 'close',

get helpMessage() {
const {
italic: i,
Expand Down
2 changes: 2 additions & 0 deletions lib/commands/diff.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
const chalk = require( 'chalk' );

module.exports = {
name: 'diff',

skipCounter: true,

get helpMessage() {
Expand Down
18 changes: 11 additions & 7 deletions lib/commands/exec.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const chalk = require( 'chalk' );
const shell = require( '../utils/shell' );

module.exports = {
name: 'exec',

get helpMessage() {
const {
italic: i,
Expand Down Expand Up @@ -43,16 +45,18 @@ module.exports = {
const log = require( '../utils/log' )();

return new Promise( ( resolve, reject ) => {
const newCwd = path.join( data.toolOptions.packages, data.repository.directory );
if ( !data.isRootRepository ) {
const newCwd = path.join( data.toolOptions.packages, data.repository.directory );

// Package does not exist.
if ( !fs.existsSync( newCwd ) ) {
log.error( `Package "${ data.packageName }" is not available. Run "mrgit sync" in order to download the package.` );
// Package does not exist.
if ( !fs.existsSync( newCwd ) ) {
log.error( `Package "${ data.packageName }" is not available. Run "mrgit sync" in order to download the package.` );

return reject( { logs: log.all() } );
}
return reject( { logs: log.all() } );
}

process.chdir( newCwd );
process.chdir( newCwd );
}

shell( data.arguments[ 0 ] )
.then( stdout => {
Expand Down
12 changes: 8 additions & 4 deletions lib/commands/fetch.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ const buildOptions = require( 'minimist-options' );
const minimist = require( 'minimist' );

module.exports = {
name: 'fetch',

skipCounter: true,

get helpMessage() {
Expand Down Expand Up @@ -42,11 +44,13 @@ module.exports = {
const log = require( '../utils/log' )();
const execCommand = require( './exec' );

const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );
if ( !data.isRootRepository ) {
const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );

// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
return Promise.resolve( {} );
// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
return Promise.resolve( {} );
}
}

const options = this._parseArguments( data.arguments );
Expand Down
12 changes: 8 additions & 4 deletions lib/commands/pull.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const path = require( 'upath' );
const chalk = require( 'chalk' );

module.exports = {
name: 'pull',

skipCounter: true,

get helpMessage() {
Expand All @@ -32,11 +34,13 @@ module.exports = {
async execute( data ) {
const execCommand = require( './exec' );

const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );
if ( !data.isRootRepository ) {
const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );

// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
return Promise.resolve( {} );
// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
return Promise.resolve( {} );
}
}

const commandResponse = await execCommand.execute( getExecData( 'git branch --show-current' ) );
Expand Down
12 changes: 8 additions & 4 deletions lib/commands/push.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ const path = require( 'upath' );
const chalk = require( 'chalk' );

module.exports = {
name: 'push',

skipCounter: true,

get helpMessage() {
Expand Down Expand Up @@ -39,11 +41,13 @@ module.exports = {
async execute( data ) {
const execCommand = require( './exec' );

const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );
if ( !data.isRootRepository ) {
const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );

// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
return Promise.resolve( {} );
// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
return Promise.resolve( {} );
}
}

const commandResponse = await execCommand.execute( getExecData( 'git branch --show-current' ) );
Expand Down
2 changes: 2 additions & 0 deletions lib/commands/save.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const updateJsonFile = require( '../utils/updatejsonfile' );
const gitStatusParser = require( '../utils/gitstatusparser' );

module.exports = {
name: 'save',

get helpMessage() {
const {
gray: g,
Expand Down
20 changes: 9 additions & 11 deletions lib/commands/status.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
const chalk = require( 'chalk' );
const Table = require( 'cli-table' );
const gitStatusParser = require( '../utils/gitstatusparser' );
const { addRootRepositorySuffix } = require( '../utils/rootrepositoryutils' );

module.exports = {
name: 'status',
Expand Down Expand Up @@ -59,8 +60,13 @@ module.exports = {
packageName = packageName.replace( new RegExp( '^' + packagePrefix ), '' );
}

if ( data.isRootRepository ) {
packageName = addRootRepositorySuffix( packageName, { bold: true } );
}

const commandResponse = {
packageName,
isRootRepository: data.isRootRepository,
status: gitStatusParser( currentBranchStatusResponse.logs.info[ 0 ], currentTag ),
commit: hashResponse.logs.info[ 0 ].slice( 0, 7 ), // Short version of the commit hash.
mrgitBranch: data.repository.branch,
Expand Down Expand Up @@ -99,17 +105,9 @@ module.exports = {
} );

const packagesResponses = Array.from( commandResponses.values() )
.sort( ( a, b ) => {
/* istanbul ignore else */
if ( a.packageName < b.packageName ) {
return -1;
} else if ( a.packageName > b.packageName ) {
return 1;
}

/* istanbul ignore next */
return 0;
} );
.sort( ( a, b ) => a.packageName.localeCompare( b.packageName ) )
// The root package should be at the top.
.sort( ( a, b ) => b.isRootRepository - a.isRootRepository );

for ( const singleResponse of packagesResponses ) {
table.push( createSingleRow( singleResponse ) );
Expand Down
30 changes: 17 additions & 13 deletions lib/commands/sync.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const chalk = require( 'chalk' );
const shell = require( '../utils/shell' );

module.exports = {
name: 'sync',

get helpMessage() {
const {
gray: g,
Expand Down Expand Up @@ -46,19 +48,21 @@ module.exports = {
const log = require( '../utils/log' )();
const execCommand = require( './exec' );

const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );

// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
log.info( `Package "${ data.packageName }" was not found. Cloning...` );

return this._clonePackage( {
path: destinationPath,
name: data.packageName,
url: data.repository.url,
branch: data.repository.branch,
tag: data.repository.tag
}, data.toolOptions, { log } );
if ( !data.isRootRepository ) {
const destinationPath = path.join( data.toolOptions.packages, data.repository.directory );

// Package is not cloned.
if ( !fs.existsSync( destinationPath ) ) {
log.info( `Package "${ data.packageName }" was not found. Cloning...` );

return this._clonePackage( {
path: destinationPath,
name: data.packageName,
url: data.repository.url,
branch: data.repository.branch,
tag: data.repository.tag
}, data.toolOptions, { log } );
}
}

return execCommand.execute( getExecData( 'git status -s' ) )
Expand Down
7 changes: 5 additions & 2 deletions lib/default-resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ const parseRepositoryUrl = require( './utils/parserepositoryurl' );
*
* @param {String} packageName Package name.
* @param {Options} options The options object.
* @param {Boolean} isRootRepository
* @returns {Repository|null}
*/
module.exports = function resolver( packageName, options ) {
const repositoryUrl = options.dependencies[ packageName ];
module.exports = function resolver( packageName, options, isRootRepository ) {
const repositoryUrl = isRootRepository ?
options.$rootRepository :
options.dependencies[ packageName ];

if ( !repositoryUrl ) {
return null;
Expand Down
13 changes: 11 additions & 2 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const getOptions = require( './utils/getoptions' );
const getPackageNames = require( './utils/getpackagenames' );
const getCommandInstance = require( './utils/getcommandinstance' );
const getCwd = require( './utils/getcwd' );
const { addRootRepositorySuffix } = require( './utils/rootrepositoryutils' );

const CHILD_PROCESS_PATH = require.resolve( './utils/child-process' );

Expand Down Expand Up @@ -48,7 +49,7 @@ module.exports = function( args, options ) {
const processedPackages = new Set();
const commandResponses = new Set();
const packagesWithError = new Set();
const packageNames = getPackageNames( toolOptions );
const packageNames = getPackageNames( toolOptions, command );

let allPackagesNumber = packageNames.length;
let donePackagesNumber = 0;
Expand All @@ -73,14 +74,18 @@ module.exports = function( args, options ) {
return;
}

const isRootRepository = packageName.startsWith( '$' );
packageName = packageName.replace( /^\$/, '' );

processedPackages.add( packageName );

const data = {
packageName,
isRootRepository,
toolOptions,
commandPath: command.path,
arguments: args.slice( 1 ),
repository: repositoryResolver( packageName, toolOptions )
repository: repositoryResolver( packageName, toolOptions, isRootRepository )
};

forkPool.enqueue( data )
Expand All @@ -103,6 +108,10 @@ module.exports = function( args, options ) {
}

if ( returnedData.logs ) {
if ( data.isRootRepository ) {
packageName = addRootRepositorySuffix( packageName );
}

if ( returnedData.logs.error.length ) {
packagesWithError.add( packageName );
}
Expand Down
4 changes: 2 additions & 2 deletions lib/utils/getcommandinstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ module.exports = function getCommandInstance( commandName ) {
* @property {Boolean} [skipCounter=false] A flag that allows hiding the progress bar (number of package and number of all
* packages to process) on the screen.
*
* @property {String} [name] A name of the command. It's useful if specified command has defined an alias.
* @property {String} name A name of the command. Used for aliases and handling root package logic.
*
* @property {Function} [beforeExecute] A function that is called by mrgit automatically before executing the main command's method.
* This function is called once. It receives two parameters:
Expand All @@ -79,7 +79,7 @@ module.exports = function getCommandInstance( commandName ) {
*
* @property {String} packageName A name of package.
*
* @propery {Options} toolOptions Options resolved by mrgit.
* @property {Options} toolOptions Options resolved by mrgit.
*
* @property {String} commandPath An absolute path to the file that keeps the command.
*
Expand Down
Loading