Skip to content

Commit 90eebfa

Browse files
committed
heft-cargo-test-plugin
1 parent 3e35f5a commit 90eebfa

File tree

9 files changed

+231
-0
lines changed

9 files changed

+231
-0
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# @rushstack/heft-cargo-test-plugin
2+
3+
This is a Heft plugin for using the cargo test runner.
4+
5+
## Links
6+
7+
- [CHANGELOG.md](
8+
https://github.com/microsoft/rushstack/blob/main/heft-plugins/heft-cargo-test-plugin/CHANGELOG.md) - Find
9+
out what's new in the latest version
10+
- [@rushstack/heft](https://www.npmjs.com/package/@rushstack/heft) - Heft is a config-driven toolchain that invokes popular tools such as TypeScript, ESLint, Jest, Webpack, and API Extractor.
11+
12+
Heft is part of the [Rush Stack](https://rushstack.io/) family of projects.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3+
4+
"mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",
5+
"apiReport": {
6+
"enabled": true,
7+
"reportFolder": "../../../common/reviews/api"
8+
},
9+
"docModel": {
10+
"enabled": false
11+
},
12+
"dtsRollup": {
13+
"enabled": true,
14+
"betaTrimmedFilePath": "<projectFolder>/dist/<unscopedPackageName>.d.ts"
15+
}
16+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
// The "rig.json" file directs tools to look for their config files in an external package.
3+
// Documentation for this system: https://www.npmjs.com/package/@rushstack/rig-package
4+
"$schema": "https://developer.microsoft.com/json-schemas/rig-package/rig.schema.json",
5+
6+
"rigPackageName": "@rushstack/heft-node-rig"
7+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "https://developer.microsoft.com/json-schemas/heft/v0/heft-plugin.schema.json",
3+
4+
"taskPlugins": [
5+
{
6+
"pluginName": "cargo-test-plugin",
7+
"entryPoint": "./lib/CargoTestPlugin",
8+
"optionsSchema": "./lib/schemas/cargo-test.schema.json",
9+
10+
"parameterScope": "cargo-test",
11+
"parameters": [
12+
{
13+
"longName": "--release",
14+
"parameterKind": "flag",
15+
"description": "Run cargo test in release mode."
16+
}
17+
]
18+
}
19+
]
20+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
{
2+
"name": "@rushstack/heft-cargo-test-plugin",
3+
"version": "0.0.0",
4+
"description": "Heft plugin for running Cargo tests",
5+
"repository": {
6+
"type": "git",
7+
"url": "https://github.com/microsoft/rushstack.git",
8+
"directory": "heft-plugins/heft-cargo-test-plugin"
9+
},
10+
"homepage": "https://rushstack.io/pages/heft/overview/",
11+
"main": "lib/index.js",
12+
"types": "dist/heft-cargo-test-plugin.d.ts",
13+
"license": "MIT",
14+
"scripts": {
15+
"build": "heft build --clean",
16+
"_phase:build": "heft run --only build -- --clean",
17+
"_phase:test": "heft run --only test -- --clean"
18+
},
19+
"peerDependencies": {
20+
"@rushstack/heft": "^0.75.0"
21+
},
22+
"dependencies": {
23+
"@rushstack/node-core-library": "5.17.0"
24+
},
25+
"devDependencies": {
26+
"@rushstack/heft": "1.1.1",
27+
"@rushstack/heft-node-rig": "2.10.2",
28+
"@types/node": "24.0.12"
29+
}
30+
}
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
import child_process from 'node:child_process';
5+
import type {
6+
HeftConfiguration,
7+
IHeftTaskPlugin,
8+
IHeftTaskRunHookOptions,
9+
IHeftTaskSession
10+
} from '@rushstack/heft';
11+
12+
/** @alpha */
13+
export interface ICargoTestPluginOptions {
14+
release?: boolean | undefined;
15+
}
16+
17+
const PLUGIN_NAME: 'cargo-test-plugin' = 'cargo-test-plugin';
18+
const RELEASE_PARAMETER_LONG_NAME: '--release' = '--release';
19+
20+
/**
21+
* @internal
22+
*/
23+
export default class CargoTestPlugin implements IHeftTaskPlugin<ICargoTestPluginOptions> {
24+
private _releaseMode: boolean = false;
25+
26+
public apply(
27+
taskSession: IHeftTaskSession,
28+
heftConfiguration: HeftConfiguration,
29+
options: ICargoTestPluginOptions = {}
30+
): void {
31+
// Check for CLI parameter first, then fall back to options
32+
this._releaseMode =
33+
taskSession.parameters.getFlagParameter(RELEASE_PARAMETER_LONG_NAME).value ||
34+
options.release ||
35+
false;
36+
37+
taskSession.hooks.run.tapPromise(PLUGIN_NAME, async (runOptions: IHeftTaskRunHookOptions) => {
38+
await this._runCargoTestAsync(taskSession, heftConfiguration, runOptions.abortSignal);
39+
});
40+
}
41+
42+
private async _runCargoTestAsync(
43+
taskSession: IHeftTaskSession,
44+
heftConfiguration: HeftConfiguration,
45+
abortSignal: AbortSignal
46+
): Promise<void> {
47+
taskSession.logger.terminal.writeLine('Running Cargo tests...');
48+
49+
if (this._releaseMode) {
50+
taskSession.logger.terminal.writeLine('Using release mode');
51+
}
52+
53+
await this._executeCargoTest(
54+
heftConfiguration.buildFolderPath,
55+
this._releaseMode,
56+
abortSignal,
57+
taskSession
58+
);
59+
}
60+
61+
private async _executeCargoTest(
62+
buildFolderPath: string,
63+
releaseMode: boolean,
64+
abortSignal: AbortSignal,
65+
taskSession: IHeftTaskSession
66+
): Promise<void> {
67+
return new Promise<void>((resolve, reject) => {
68+
const args: string[] = ['test'];
69+
70+
if (releaseMode) {
71+
args.push('--release');
72+
}
73+
74+
taskSession.logger.terminal.writeDebugLine(`Executing: cargo ${args.join(' ')}`);
75+
76+
const child = child_process.spawn('cargo', args, {
77+
stdio: ['inherit', 'inherit', 1], // Redirect stderr to stdout
78+
cwd: buildFolderPath,
79+
env: process.env
80+
});
81+
82+
// Handle abort signal
83+
const abortHandler = (): void => {
84+
child.kill('SIGTERM');
85+
};
86+
87+
if (abortSignal.aborted) {
88+
child.kill('SIGTERM');
89+
reject(new Error('Operation aborted'));
90+
return;
91+
}
92+
93+
abortSignal.addEventListener('abort', abortHandler);
94+
95+
child.on('error', (error) => {
96+
abortSignal.removeEventListener('abort', abortHandler);
97+
reject(new Error(`Failed to spawn Cargo test process: ${error.message}`));
98+
});
99+
100+
child.on('exit', (code, signal) => {
101+
abortSignal.removeEventListener('abort', abortHandler);
102+
if (signal === 'SIGTERM' && abortSignal.aborted) {
103+
reject(new Error('Operation aborted'));
104+
} else if (code === 0) {
105+
taskSession.logger.terminal.writeLine('Cargo tests completed successfully.');
106+
resolve();
107+
} else {
108+
reject(new Error(`Cargo test process exited with code ${code}`));
109+
}
110+
});
111+
});
112+
}
113+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
2+
// See LICENSE in the project root for license information.
3+
4+
export { default as CargoTestPlugin } from './CargoTestPlugin';
5+
export type { ICargoTestPluginOptions } from './CargoTestPlugin';
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "http://json-schema.org/draft-04/schema#",
3+
"title": "Cargo Test Plugin Configuration",
4+
"description": "Defines options for Cargo test plugin execution.",
5+
"type": "object",
6+
7+
"additionalProperties": false,
8+
9+
"properties": {
10+
"$schema": {
11+
"description": "Part of the JSON Schema standard, this optional keyword declares the URL of the schema that the file conforms to. Editors may download the schema and use it to perform syntax highlighting.",
12+
"type": "string"
13+
},
14+
15+
"release": {
16+
"description": "Whether to run cargo test in release mode. Default is false.",
17+
"type": "boolean"
18+
}
19+
}
20+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"extends": "./node_modules/@rushstack/heft-node-rig/profiles/default/tsconfig-base.json",
3+
"compilerOptions": {
4+
"skipLibCheck": true,
5+
"resolveJsonModule": true,
6+
"types": ["node"]
7+
}
8+
}

0 commit comments

Comments
 (0)