Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ These GitHub repositories provide supplementary resources for Rush Stack:
| [/rush-plugins/rush-buildxl-graph-plugin](./rush-plugins/rush-buildxl-graph-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-buildxl-graph-plugin) | | [@rushstack/rush-buildxl-graph-plugin](https://www.npmjs.com/package/@rushstack/rush-buildxl-graph-plugin) |
| [/rush-plugins/rush-http-build-cache-plugin](./rush-plugins/rush-http-build-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-http-build-cache-plugin) | | [@rushstack/rush-http-build-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-http-build-cache-plugin) |
| [/rush-plugins/rush-mcp-docs-plugin](./rush-plugins/rush-mcp-docs-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-mcp-docs-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-mcp-docs-plugin) | [changelog](./rush-plugins/rush-mcp-docs-plugin/CHANGELOG.md) | [@rushstack/rush-mcp-docs-plugin](https://www.npmjs.com/package/@rushstack/rush-mcp-docs-plugin) |
| [/rush-plugins/rush-published-versions-json-plugin](./rush-plugins/rush-published-versions-json-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-published-versions-json-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-published-versions-json-plugin) | [changelog](./rush-plugins/rush-published-versions-json-plugin/CHANGELOG.md) | [@rushstack/rush-published-versions-json-plugin](https://www.npmjs.com/package/@rushstack/rush-published-versions-json-plugin) |
| [/rush-plugins/rush-redis-cobuild-plugin](./rush-plugins/rush-redis-cobuild-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-redis-cobuild-plugin) | | [@rushstack/rush-redis-cobuild-plugin](https://www.npmjs.com/package/@rushstack/rush-redis-cobuild-plugin) |
| [/rush-plugins/rush-resolver-cache-plugin](./rush-plugins/rush-resolver-cache-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-resolver-cache-plugin) | | [@rushstack/rush-resolver-cache-plugin](https://www.npmjs.com/package/@rushstack/rush-resolver-cache-plugin) |
| [/rush-plugins/rush-serve-plugin](./rush-plugins/rush-serve-plugin/) | [![npm version](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin.svg)](https://badge.fury.io/js/%40rushstack%2Frush-serve-plugin) | | [@rushstack/rush-serve-plugin](https://www.npmjs.com/package/@rushstack/rush-serve-plugin) |
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@microsoft/rush",
"comment": "Add `customParametersByLongName` and `setHandled()` to `IGlobalCommand`, enabling Rush plugins to implement native global commands. Plugins can now define global commands with an empty `shellCommand`, handle execution via the `runGlobalCustomCommand` hook, and access parsed command-line parameters.",
"type": "none"
}
],
"packageName": "@microsoft/rush"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"changes": [
{
"packageName": "@rushstack/rush-published-versions-json-plugin",
"comment": "Initial release.",
"type": "minor"
}
],
"packageName": "@rushstack/rush-published-versions-json-plugin"
}
10 changes: 5 additions & 5 deletions common/config/subspaces/build-tests-subspace/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush.
{
"pnpmShrinkwrapHash": "c395a90b30bd67a31beb1d1b08be9aecb02de265",
"pnpmShrinkwrapHash": "58bd145b905637c52bb733fb9455b6d83e3a890e",
"preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9",
"packageJsonInjectedDependenciesHash": "fa90a0a032a0046e646e8751bbc6d0be86a4dda1"
}
25 changes: 25 additions & 0 deletions common/config/subspaces/default/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion common/reviews/api/rush-lib.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -512,6 +512,8 @@ export interface IGetChangedProjectsOptions {

// @beta
export interface IGlobalCommand extends IRushCommand {
getCustomParametersByLongName<TParameter extends CommandLineParameter>(longName: string): TParameter;
setHandled(): void;
}

// @public
Expand Down Expand Up @@ -1500,7 +1502,7 @@ export class RushLifecycleHooks {
variant: string | undefined
]>;
readonly beforeInstall: AsyncSeriesHook<[
command: IGlobalCommand,
command: IRushCommand,
subspace: Subspace,
variant: string | undefined
]>;
Expand Down
49 changes: 49 additions & 0 deletions libraries/rush-lib/src/cli/scriptActions/GlobalScriptAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as path from 'node:path';

import type { AsyncSeriesHook } from 'tapable';

import type { CommandLineParameter } from '@rushstack/ts-command-line';
import {
FileSystem,
type IPackageJson,
Expand Down Expand Up @@ -45,6 +46,9 @@ export class GlobalScriptAction extends BaseScriptAction<IGlobalCommandConfig> {
private readonly _autoinstallerName: string;
private readonly _autoinstallerFullPath: string;

private _customParametersByLongName: ReadonlyMap<string, CommandLineParameter> | undefined;
private _isHandled: boolean = false;

public constructor(options: IGlobalScriptActionOptions) {
super(options);
this._shellCommand = options.shellCommand;
Expand Down Expand Up @@ -93,6 +97,37 @@ export class GlobalScriptAction extends BaseScriptAction<IGlobalCommandConfig> {
this.defineScriptParameters();
}

/**
* {@inheritDoc IGlobalCommand.setHandled}
*/
public setHandled(): void {
this._isHandled = true;
}

/**
* {@inheritDoc IGlobalCommand.getCustomParametersByLongName}
*/
public getCustomParametersByLongName<TParameter extends CommandLineParameter>(
longName: string
): TParameter {
if (!this._customParametersByLongName) {
const map: Map<string, CommandLineParameter> = new Map();
for (const [parameterJson, parameter] of this.customParameters) {
map.set(parameterJson.longName, parameter);
}
this._customParametersByLongName = map;
}

const parameter: CommandLineParameter | undefined = this._customParametersByLongName.get(longName);
if (!parameter) {
throw new Error(
`The command "${this.actionName}" does not have a custom parameter with long name "${longName}".`
);
}

return parameter as TParameter;
}

private async _prepareAutoinstallerNameAsync(): Promise<void> {
const autoInstaller: Autoinstaller = new Autoinstaller({
autoinstallerName: this._autoinstallerName,
Expand All @@ -117,6 +152,20 @@ export class GlobalScriptAction extends BaseScriptAction<IGlobalCommandConfig> {
await hookForAction.promise(this);
}

// If a plugin hook called setHandled(), the command has been fully handled.
// Skip the default shell command execution.
if (this._isHandled) {
return;
}

if (this._shellCommand === '') {
throw new Error(
`The custom command "${this.actionName}" has an empty "shellCommand" value, but no plugin ` +
'called setHandled() for this command. An empty "shellCommand" is intended for global ' +
'commands whose implementation is provided entirely by a Rush plugin.'
);
}

const additionalPathFolders: string[] =
this.commandLineConfiguration?.additionalPathFolders.slice() || [];

Expand Down
16 changes: 14 additions & 2 deletions libraries/rush-lib/src/pluginFramework/RushLifeCycle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

import { AsyncParallelHook, AsyncSeriesHook, HookMap } from 'tapable';

import type { CommandLineParameter } from '@rushstack/ts-command-line';

import type { ITelemetryData } from '../logic/Telemetry';
import type { PhasedCommandHooks } from './PhasedCommandHooks';
import type { Subspace } from '../api/Subspace';
Expand All @@ -23,7 +25,17 @@ export interface IRushCommand {
* @beta
*/
export interface IGlobalCommand extends IRushCommand {
// Nothing added.
/**
* Get a parameter by its long name (e.g. "--output-path") that was defined in command-line.json for this command.
* If the parameter was not defined or not provided on the command line, this will throw.
*/
getCustomParametersByLongName<TParameter extends CommandLineParameter>(longName: string): TParameter;

/**
* Call this from a plugin hook to indicate that the command has been fully handled
* by the plugin. When set, the default shell command execution will be skipped.
*/
setHandled(): void;
}

/**
Expand Down Expand Up @@ -94,7 +106,7 @@ export class RushLifecycleHooks {
* The hook to run between preparing the common/temp folder and invoking the package manager during "rush install" or "rush update".
*/
public readonly beforeInstall: AsyncSeriesHook<
[command: IGlobalCommand, subspace: Subspace, variant: string | undefined]
[command: IRushCommand, subspace: Subspace, variant: string | undefined]
> = new AsyncSeriesHook(['command', 'subspace', 'variant'], 'beforeInstall');

/**
Expand Down
36 changes: 36 additions & 0 deletions rush-plugins/rush-published-versions-json-plugin/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# THIS IS A STANDARD TEMPLATE FOR .npmignore FILES IN THIS REPO.

# Ignore all files by default, to avoid accidentally publishing unintended files.
*

# Use negative patterns to bring back the specific things we want to publish.
!/bin/**
!/lib/**
!/lib-*/**
!/dist/**
!/includes/**

!CHANGELOG.md
!CHANGELOG.json
!heft-plugin.json
!rush-plugin-manifest.json
!ThirdPartyNotice.txt

# Ignore certain patterns that should not get published.
/dist/*.stats.*
/lib/**/test/
/lib-*/**/test/
*.test.js
*.test.[cm]js
*.test.d.ts
*.test.d.[cm]ts

# NOTE: These don't need to be specified, because NPM includes them automatically.
#
# package.json
# README.md
# LICENSE

# ---------------------------------------------------------------------------
# DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below.
# ---------------------------------------------------------------------------
24 changes: 24 additions & 0 deletions rush-plugins/rush-published-versions-json-plugin/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
@rushstack/rush-published-versions-json-plugin

Copyright (c) Microsoft Corporation. All rights reserved.

MIT License

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
71 changes: 71 additions & 0 deletions rush-plugins/rush-published-versions-json-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# @rushstack/rush-published-versions-json-plugin

A Rush plugin that generates a JSON file recording the version numbers of all published packages in a Rush monorepo.

## Installation

1. Add the plugin package to an autoinstaller (e.g. `common/autoinstallers/rush-plugins/package.json`):

```
rush init-autoinstaller --name rush-plugins
```

```bash
cd common/autoinstallers/rush-plugins
pnpm add @rushstack/rush-published-versions-json-plugin
rush update-autoinstaller --name rush-plugins
```

2. Register the plugin in `common/config/rush/rush-plugins.json`:

```json
{
"$schema": "https://developer.microsoft.com/json-schemas/rush/v5/rush-plugins.schema.json",
"plugins": [
{
"packageName": "@rushstack/rush-published-versions-json-plugin",
"pluginName": "rush-published-versions-json-plugin",
"autoinstallerName": "rush-plugins"
}
]
}
```

3. Run `rush update` to install the plugin.

## Usage

```bash
rush record-published-versions --output-path <FILE_PATH>
```

### Parameters

| Parameter | Short | Required | Description |
| --- | --- | --- | --- |
| `--output-path` | `-o` | Yes | The path to the output JSON file. Relative paths are resolved from the repo root. |

### Example

```bash
rush record-published-versions --output-path common/config/published-versions.json
```

### Output format

The output is a JSON object mapping published package names to their current versions:

```json
{
"@my-scope/my-library": "1.2.3",
"@my-scope/my-app": "0.5.0"
}
```

A package is included if it has `shouldPublish` set to `true` or has a `versionPolicy` assigned in
**rush.json**.

## Links

- [CHANGELOG.md](./CHANGELOG.md)
- [Rush: Using rush plugins](https://rushjs.io/pages/maintainer/using_rush_plugins/)
Loading