refactor: Standardize package import/export flag naming in n8n-cli (#34998)

Co-authored-by: n8n-cat-bot[bot] <n8n-cat-bot[bot]@users.noreply.github.com>
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
n8n-cat-bot[bot]
2026-07-27 09:34:20 +00:00
committed by GitHub
parent 2268149b7c
commit bba48aa8da
4 changed files with 42 additions and 14 deletions
+4 -4
View File
@@ -22,7 +22,7 @@ n8n-cli package export -w abc --include-variable-values=false -o export.n8np
| Flag | Description |
|------|-------------|
| `-w, --workflow-id` | Workflow ID to include. Repeat the flag to export several. |
| `-f, --folder-id` | Folder ID to include with its nested folders. Repeat the flag to export several. |
| `--folder-id` | Folder ID to include with its nested folders. Repeat the flag to export several. |
| `-p, --project-id` | Project ID to include. Repeat the flag to export several. |
| `-o, --output` | File to write the package to. Defaults to `export.n8np`. |
| `--include-variable-values` | `true` (default) or `false`. Whether values of variables referenced by the exported workflows are bundled into the package. When `false`, variables still travel as name/type files (and in the package requirements), just without their values. |
@@ -44,7 +44,7 @@ Import a `.n8np` archive into a project.
```bash
n8n-cli package import --file=export.n8np
n8n-cli package import --file=export.n8np --project=<id> --workflow-conflict-policy=skip
n8n-cli package import --file=export.n8np --project-id=<id> --workflow-conflict-policy=skip
n8n-cli package import --file=export.n8np --workflow-conflict-policy=fail --credential-missing-mode=must-preexist
n8n-cli package import --file=export.n8np --workflow-conflict-policy=fail --bindings='{"credentials":{"<sourceId>":"<targetId>"}}'
```
@@ -53,8 +53,8 @@ n8n-cli package import --file=export.n8np --workflow-conflict-policy=fail --bind
|------|-------------|
| `--file` | Path to the `.n8np` package file. (required) |
| `--workflow-conflict-policy` | What to do when a workflow already exists by source ID: `new-version` (default), `fail`, or `skip`. |
| `--project` | Target project ID. Defaults to your personal project. |
| `--folder` | Target folder ID within the project. Defaults to the project root. |
| `-p, --project-id` | Target project ID. Defaults to your personal project. (alias: `--project`) |
| `--folder-id` | Target folder ID within the project. Defaults to the project root. (alias: `--folder`) |
| `--workflow-publishing-policy` | Whether imported workflows end up published. `preserve-published-state` (instance default) never publishes drafts — an updated workflow is republished only when it was already published and the package workflow is published too; `match-source` follows the package workflow's published flag; `publish-all` publishes every imported workflow; `unpublish-all` leaves new workflows unpublished and unpublishes updated ones. |
| `--workflow-id-policy` | Whether imported workflows keep their source ID (`source`) or receive a new one (`new`). |
| `--missing-node-type-mode` | What to do when a workflow uses a node type — or a version of a node type — this instance does not have. `fail` (instance default) rejects the import before anything is written, listing every missing node type and the workflows that use it; `import-anyway` imports the package, but the affected workflows are never published by the import, regardless of the publishing policy. |
@@ -13,8 +13,8 @@ const packageRoot = process.cwd();
interface ImportFlags {
file: string;
project?: string;
folder?: string;
projectId?: string;
folderId?: string;
workflowConflictPolicy?: string;
workflowPublishingPolicy?: string;
workflowIdPolicy?: string;
@@ -59,8 +59,8 @@ describe('package import command', () => {
it('forwards workflowPublishingPolicy and all sibling options to the import API', async () => {
const { command, importPackage } = stubCommand({
file: '/tmp/export.n8np',
project: 'p-1',
folder: 'f-1',
projectId: 'p-1',
folderId: 'f-1',
workflowConflictPolicy: 'fail',
workflowPublishingPolicy: 'publish-all',
workflowIdPolicy: 'new',
@@ -153,6 +153,32 @@ describe('package import command', () => {
);
});
it('resolves the --project-id and --folder-id flags', async () => {
const importPackage = await runWithArgv([
'--file=/tmp/export.n8np',
'--project-id=p-1',
'--folder-id=f-1',
]);
expect(importPackage).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ projectId: 'p-1', folderId: 'f-1' }),
);
});
it('resolves the backward-compatible --project and --folder aliases', async () => {
const importPackage = await runWithArgv([
'--file=/tmp/export.n8np',
'--project=p-1',
'--folder=f-1',
]);
expect(importPackage).toHaveBeenCalledWith(
expect.anything(),
expect.objectContaining({ projectId: 'p-1', folderId: 'f-1' }),
);
});
it('rejects the removed --conflict-policy flag', async () => {
const config = await Config.load(packageRoot);
const command = new PackageImport(
@@ -25,7 +25,6 @@ export default class PackageExport extends BaseCommand {
aliases: ['workflow-id'],
}),
folderId: Flags.string({
char: 'f',
description: 'Folder ID to include with its nested folders (repeat for multiple)',
multiple: true,
aliases: ['folder-id'],
@@ -10,7 +10,7 @@ export default class PackageImport extends BaseCommand {
static override examples = [
'<%= config.bin %> package import --file=export.n8np',
'<%= config.bin %> package import --file=export.n8np --project=<id> --workflow-conflict-policy=skip',
'<%= config.bin %> package import --file=export.n8np --project-id=<id> --workflow-conflict-policy=skip',
'<%= config.bin %> package import --file=export.n8np --workflow-conflict-policy=fail --credential-missing-mode=must-preexist',
'<%= config.bin %> package import --file=export.n8np --workflow-conflict-policy=fail --bindings=\'{"credentials":{"<sourceId>":"<targetId>"}}\'',
];
@@ -18,11 +18,14 @@ export default class PackageImport extends BaseCommand {
static override flags = {
...BaseCommand.baseFlags,
file: Flags.string({ description: 'Path to the .n8np package file', required: true }),
project: Flags.string({
projectId: Flags.string({
char: 'p',
description: 'Target project ID (defaults to your personal project)',
aliases: ['project-id', 'project'],
}),
folder: Flags.string({
folderId: Flags.string({
description: 'Target folder ID within the project (defaults to the project root)',
aliases: ['folder-id', 'folder'],
}),
workflowConflictPolicy: Flags.string({
description: 'What to do when a workflow already exists in the target project',
@@ -107,8 +110,8 @@ export default class PackageImport extends BaseCommand {
result = await client.importPackage(
{ buffer, filename: path.basename(flags.file) },
{
projectId: flags.project,
folderId: flags.folder,
projectId: flags.projectId,
folderId: flags.folderId,
workflowConflictPolicy: flags.workflowConflictPolicy,
workflowPublishingPolicy: flags.workflowPublishingPolicy,
workflowIdPolicy: flags.workflowIdPolicy,