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

[rush] Add defaultCommand command-line parameter #4236

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "add defaultCommand",
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
1 change: 1 addition & 0 deletions common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ export interface IPackageManagerOptionsJsonBase {
export interface IPhase {
allowWarningsOnSuccess: boolean;
associatedParameters: Set<CommandLineParameter>;
defaultCommand?: string;
dependencies: {
self: Set<IPhase>;
upstream: Set<IPhase>;
Expand Down
13 changes: 12 additions & 1 deletion libraries/rush-lib/src/api/CommandLineConfiguration.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@ export interface IPhase {
* values will be appended to the end of this string.
*/
shellCommand?: string;

/**
* (Optional) If the `defaultCommand` field is set for a bulk command, when Rush can't find the package.json `"scripts"` entry
* matching Rush command/phase name, it will fall back to this command.
*
* This string is the path to a script that will be invoked using the OS shell. The working directory will be
* the folder that contains rush.json. If custom parameters are associated with this command, their
* values will be appended to the end of this string.
*/
defaultCommand?: string;
}

export interface ICommandWithParameters {
Expand Down Expand Up @@ -695,7 +705,8 @@ export class CommandLineConfiguration {
},
missingScriptBehavior: command.ignoreMissingScript ? 'log' : 'error',
allowWarningsOnSuccess: !!command.allowWarningsInSuccessfulBuild,
shellCommand: command.shellCommand
shellCommand: command.shellCommand,
defaultCommand: command.defaultCommand
};

if (!command.ignoreDependencyOrder) {
Expand Down
2 changes: 2 additions & 0 deletions libraries/rush-lib/src/api/CommandLineJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export interface IBulkCommandJson extends IBaseCommandJson {
allowWarningsInSuccessfulBuild?: boolean;
watchForChanges?: boolean;
disableBuildCache?: boolean;
defaultCommand?: string;
}

/**
Expand All @@ -39,6 +40,7 @@ export interface IPhasedCommandWithoutPhasesJson extends IBaseCommandJson {
commandKind: 'phased';
enableParallelism: boolean;
incremental?: boolean;
defaultCommand?: string;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,30 @@ describe(CommandLineConfiguration.name, () => {
expect(phase.shellCommand).toEqual('echo');
});
});

describe('defaultCommand in bulk command', () => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please include a unit test of having it in a phase definition as well.

it('get "custom-shell-command-echo" command', () => {
const commandLineConfiguration: CommandLineConfiguration = new CommandLineConfiguration({
commands: [
{
commandKind: 'bulk',
name: 'custom-shell-command-echo',
summary: 'custom define bulk defaultCommand echo',
enableParallelism: true,
safeForSimultaneousRushProcesses: false,
defaultCommand: 'echo'
}
]
});

const command: IPhasedCommandConfig | undefined = commandLineConfiguration.commands.get(
'custom-shell-command-echo'
) as IPhasedCommandConfig;
expect(command).toBeDefined();
expect(command?.phases).toBeDefined();
const phase = [...command?.phases][0];
expect(phase.name).toEqual('custom-shell-command-echo');
expect(phase.defaultCommand).toEqual('echo');
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ function createShellOperations(
project,
phase.name,
customParameterValues,
phase.shellCommand
phase.shellCommand,
phase.defaultCommand
);

if (commandToRun === undefined && phase.missingScriptBehavior === 'error') {
Expand Down Expand Up @@ -106,11 +107,12 @@ function getScriptToRun(
rushProject: RushConfigurationProject,
commandToRun: string,
customParameterValues: ReadonlyArray<string>,
shellCommand: string | undefined
shellCommand: string | undefined,
defaultCommand: string | undefined
): string | undefined {
const { scripts } = rushProject.packageJson;

const rawCommand: string | undefined | null = shellCommand ?? scripts?.[commandToRun];
const rawCommand: string | undefined | null = shellCommand ?? scripts?.[commandToRun] ?? defaultCommand;

if (rawCommand === undefined || rawCommand === null) {
return undefined;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,4 +109,91 @@ describe(ShellOperationRunnerPlugin.name, () => {
// All projects
expect(Array.from(operations, serializeOperation)).toMatchSnapshot();
});

it('defaultCommand "echo custom defaultCommand" should be set to commandToRun', async () => {
const rushJsonFile: string = path.resolve(
__dirname,
`../../test/customDefaultCommandinBulkRepo/rush.json`
);
const commandLineJsonFile: string = path.resolve(
__dirname,
`../../test/customDefaultCommandinBulkRepo/common/config/rush/command-line.json`
);

const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile);
const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile);

const commandLineConfiguration = new CommandLineConfiguration(commandLineJson);

const echoCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get(
'echo'
)! as IPhasedCommandConfig;

const fakeCreateOperationsContext: Pick<
ICreateOperationsContext,
'phaseOriginal' | 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
> = {
phaseOriginal: echoCommand.phases,
phaseSelection: echoCommand.phases,
projectSelection: new Set(rushConfiguration.projects),
projectsInUnknownState: new Set(rushConfiguration.projects)
};

const hooks: PhasedCommandHooks = new PhasedCommandHooks();

// Generates the default operation graph
new PhasedOperationPlugin().apply(hooks);
// Applies the Shell Operation Runner to selected operations
new ShellOperationRunnerPlugin().apply(hooks);

const operations: Set<Operation> = await hooks.createOperations.promise(
new Set(),
fakeCreateOperationsContext as ICreateOperationsContext
);
// All projects
expect(Array.from(operations, serializeOperation)).toMatchSnapshot();
});

it('defaultCommand priority should be lower than script name', async () => {
const rushJsonFile: string = path.resolve(
__dirname,
`../../test/customDefaultCommandinBulkOverrideScriptsRepo/rush.json`
);
const commandLineJsonFile: string = path.resolve(
__dirname,
`../../test/customDefaultCommandinBulkOverrideScriptsRepo/common/config/rush/command-line.json`
);

const rushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonFile);
const commandLineJson: ICommandLineJson = JsonFile.load(commandLineJsonFile);

const commandLineConfiguration = new CommandLineConfiguration(commandLineJson);
const echoCommand: IPhasedCommandConfig = commandLineConfiguration.commands.get(
'echo'
)! as IPhasedCommandConfig;

const fakeCreateOperationsContext: Pick<
ICreateOperationsContext,
'phaseOriginal' | 'phaseSelection' | 'projectSelection' | 'projectsInUnknownState'
> = {
phaseOriginal: echoCommand.phases,
phaseSelection: echoCommand.phases,
projectSelection: new Set(rushConfiguration.projects),
projectsInUnknownState: new Set(rushConfiguration.projects)
};

const hooks: PhasedCommandHooks = new PhasedCommandHooks();

// Generates the default operation graph
new PhasedOperationPlugin().apply(hooks);
// Applies the Shell Operation Runner to selected operations
new ShellOperationRunnerPlugin().apply(hooks);

const operations: Set<Operation> = await hooks.createOperations.promise(
new Set(),
fakeCreateOperationsContext as ICreateOperationsContext
);
// All projects
expect(Array.from(operations, serializeOperation)).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,31 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ShellOperationRunnerPlugin defaultCommand "echo custom defaultCommand" should be set to commandToRun 1`] = `
Array [
Object {
"commandToRun": "echo custom defaultCommand ",
"name": "a",
},
Object {
"commandToRun": "echo custom defaultCommand ",
"name": "b",
},
]
`;

exports[`ShellOperationRunnerPlugin defaultCommand priority should be lower than script name 1`] = `
Array [
Object {
"commandToRun": "echo custom defaultCommand ",
"name": "a",
},
Object {
"commandToRun": "fake_echo_task_but_works_with_mock ",
"name": "b",
},
]
`;

exports[`ShellOperationRunnerPlugin shellCommand "echo custom shellCommand" should be set to commandToRun 1`] = `
Array [
Object {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "a",
"version": "1.0.0",
"description": "Test package a",
"scripts": {
"build": "fake_build_task_but_works_with_mock",
"rebuild": "fake_REbuild_task_but_works_with_mock"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"name": "b",
"version": "1.0.0",
"description": "Test package b",
"scripts": {
"build": "fake_build_task_but_works_with_mock",
"rebuild": "fake_REbuild_task_but_works_with_mock",
"echo": "fake_echo_task_but_works_with_mock"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json",
"commands": [
{
"commandKind": "bulk",
"name": "echo",
"summary": "execute 'echo' command",
"description": "execute 'echo' command for selected project",
"enableParallelism": true,
"defaultCommand": "echo custom defaultCommand"
}
],
"parameters": [
{
"longName": "--flag-for-echo",
"description": "This flag should be usable for build and rebuild commands.",
"parameterKind": "flag",
"associatedCommands": ["echo"]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"npmVersion": "6.4.1",
"rushVersion": "5.5.2",
"projectFolderMinDepth": 1,
"projectFolderMaxDepth": 99,

"projects": [
{
"packageName": "a",
"projectFolder": "a"
},
{
"packageName": "b",
"projectFolder": "b"
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "a",
"version": "1.0.0",
"description": "Test package a",
"scripts": {
"build": "fake_build_task_but_works_with_mock",
"rebuild": "fake_REbuild_task_but_works_with_mock"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "b",
"version": "1.0.0",
"description": "Test package b",
"scripts": {
"build": "fake_build_task_but_works_with_mock",
"rebuild": "fake_REbuild_task_but_works_with_mock"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/command-line.schema.json",
"commands": [
{
"commandKind": "bulk",
"name": "echo",
"summary": "execute 'echo' command",
"description": "execute 'echo' command for selected project",
"enableParallelism": true,
"defaultCommand": "echo custom defaultCommand"
}
],
"parameters": [
{
"longName": "--flag-for-echo",
"description": "This flag should be usable for build and rebuild commands.",
"parameterKind": "flag",
"associatedCommands": ["echo"]
}
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"npmVersion": "6.4.1",
"rushVersion": "5.5.2",
"projectFolderMinDepth": 1,
"projectFolderMaxDepth": 99,

"projects": [
{
"packageName": "a",
"projectFolder": "a"
},
{
"packageName": "b",
"projectFolder": "b"
}
]
}