Skip to content

Commit

Permalink
feat: add executor
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesHenry committed Feb 21, 2024
1 parent fdef71a commit 2fbf4ef
Show file tree
Hide file tree
Showing 6 changed files with 140 additions and 3 deletions.
6 changes: 6 additions & 0 deletions packages/rust/executors.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@
"implementation": "./src/executors/napi/executor",
"schema": "./src/executors/napi/schema.json",
"description": "Wrapper to run the napi-cli"
},
"release-publish": {
"implementation": "./src/executors/release-publish/executor",
"schema": "./src/executors/release-publish/schema.json",
"description": "DO NOT INVOKE DIRECTLY WITH `nx run`. Use `nx release publish` instead.",
"hidden": true
}
}
}
87 changes: 87 additions & 0 deletions packages/rust/src/executors/release-publish/executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import { ExecutorContext, joinPathFragments, output } from '@nx/devkit';
import { execSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { relative } from 'node:path';
import { env as appendLocalEnv } from 'npm-run-path';
import { parseCargoToml } from '../../utils/toml';
import { PublishExecutorSchema } from './schema';
import chalk = require('chalk');

const LARGE_BUFFER = 1024 * 1000000;

function processEnv(color: boolean) {
const env = {
...process.env,
...appendLocalEnv(),
};

if (color) {
env.FORCE_COLOR = `${color}`;
}
return env;
}

export default async function runExecutor(
options: PublishExecutorSchema,
context: ExecutorContext
) {
/**
* We need to check both the env var and the option because the executor may have been triggered
* indirectly via dependsOn, in which case the env var will be set, but the option will not.
*/
const isDryRun = process.env.NX_DRY_RUN === 'true' || options.dryRun || false;

const projectConfig =
context.projectsConfigurations!.projects[context.projectName!]!;

const packageRoot = joinPathFragments(
context.root,
options.packageRoot ?? projectConfig.root
);
const workspaceRelativePackageRoot = relative(context.root, packageRoot);

const cargoTomlPath = joinPathFragments(packageRoot, 'Cargo.toml');
const cargoTomlContents = readFileSync(cargoTomlPath, 'utf-8');
const cargoToml = parseCargoToml(cargoTomlContents);
const crateName = cargoToml.package.name;

const cargoPublishCommandSegments = [
`cargo publish --allow-dirty -p ${crateName} --target-dir ${workspaceRelativePackageRoot}/target`,
];

if (isDryRun) {
cargoPublishCommandSegments.push(`--dry-run`);
}

try {
const command = cargoPublishCommandSegments.join(' ');
output.logSingleLine(`Running "${command}"...`);

execSync(command, {
maxBuffer: LARGE_BUFFER,
env: processEnv(true),
cwd: packageRoot,
stdio: 'inherit',
});

console.log('');

if (isDryRun) {
console.log(
`Would publish to https://crates.io, but ${chalk.keyword('orange')(
'[dry-run]'
)} was set`
);
} else {
console.log(`Published to https://crates.io`);
}

return {
success: true,
};
} catch (err: any) {
return {
success: false,
};
}
}
4 changes: 4 additions & 0 deletions packages/rust/src/executors/release-publish/schema.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export interface PublishExecutorSchema {
packageRoot?: string;
dryRun?: boolean;
}
18 changes: 18 additions & 0 deletions packages/rust/src/executors/release-publish/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "https://json-schema.org/schema",
"version": 2,
"title": "Implementation details of `nx release publish`",
"description": "DO NOT INVOKE DIRECTLY WITH `nx run`. Use `nx release publish` instead.",
"type": "object",
"properties": {
"packageRoot": {
"type": "string",
"description": "The root directory of the directory (containing a manifest file at its root) to publish. Defaults to the project root."
},
"dryRun": {
"type": "boolean",
"description": "Whether to run the command without actually publishing the package to the registry."
}
},
"required": []
}
17 changes: 15 additions & 2 deletions packages/rust/src/graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,24 @@ export const createNodes: CreateNodes = [
const root = normalizePath(
dirname(relative(ctx.workspaceRoot, pkg.manifest_path))
);

// TODO(cammisuli): provide defaults for non-project.json workspaces
const targets: ProjectConfiguration['targets'] = {};

// Apply nx-release-publish target for non-private projects
const isPrivate = pkg.publish?.length === 0;
if (!isPrivate) {
targets['nx-release-publish'] = {
dependsOn: ['^nx-release-publish'],
executor: '@monodon/rust:release-publish',
options: {},
};
}

projects[root] = {
root,
name: pkg.name,
// TODO(cammisuli): provide defaults for non-project.json workspaces
targets: {},
targets,
release: {
version: {
generator: '@monodon/rust:release-version',
Expand Down
11 changes: 10 additions & 1 deletion packages/rust/src/models/cargo-metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,16 @@ export interface Package {
features: Features;
manifest_path: string;
metadata: Metadata;
publish: string[];
/**
* From the docs:
* "List of registries to which this package may be published.
* Publishing is unrestricted if null, and forbidden if an empty array."
*
* Additional observation:
* false can be used by the end user but it will be converted to an empty
* array in the cargo metadata output.
*/
publish: string[] | null;
authors: string[];
categories: string[];
default_run: any;
Expand Down

0 comments on commit 2fbf4ef

Please sign in to comment.