feat: Add git-connections commands to the n8n CLI (no-changelog) (#36287)

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Irénée
2026-08-20 08:09:57 +00:00
committed by GitHub
parent 365b7036dc
commit 63e8482c98
10 changed files with 180 additions and 0 deletions
+3
View File
@@ -66,6 +66,9 @@
"source-control": {
"description": "Pull changes from the configured source control provider"
},
"git-connections": {
"description": "Create and manage Git repository connections"
},
"package": {
"description": "Export and import workflows as n8n packages (beta)"
},
+32
View File
@@ -214,6 +214,38 @@ export class N8nClient {
return limit !== undefined ? results.slice(0, limit) : results;
}
// ─── Git connections ───────────────────────────────────────────
async listGitConnections(limit?: number) {
return await this.paginate<Record<string, unknown>>('/git-connections', {}, limit);
}
async getGitConnection(id: string) {
return await this.get<Record<string, unknown>>(`/git-connections/${id}`);
}
async createGitConnection(body: unknown) {
return await this.post<Record<string, unknown>>('/git-connections', body);
}
async updateGitConnection(id: string, body: unknown) {
return await this.put<Record<string, unknown>>(`/git-connections/${id}`, body);
}
async cloneGitConnection(id: string, branchName?: string) {
return await this.post<Record<string, unknown>>(`/git-connections/${id}/clone`, {
...(branchName ? { branchName } : {}),
});
}
async disconnectGitConnection(id: string) {
return await this.post<Record<string, unknown>>(`/git-connections/${id}/disconnect`);
}
async deleteGitConnection(id: string) {
return await this.del<undefined>(`/git-connections/${id}`);
}
// ─── Workflows ─────────────────────────────────────────────────
async listWorkflows(query: Record<string, string> = {}, limit?: number) {
@@ -0,0 +1,19 @@
import { Args, Flags } from '@oclif/core';
import { BaseCommand } from '../../base-command';
export default class GitConnectionsClone extends BaseCommand {
static override description = 'Clone a Git connection';
static override args = { id: Args.string({ description: 'Git connection ID', required: true }) };
static override flags = {
...BaseCommand.baseFlags,
branchName: Flags.string({ description: 'Remote branch to clone', aliases: ['branch-name'] }),
};
async run() {
const { args, flags } = await this.parse(GitConnectionsClone);
await this.execute(async () => {
this.output(await this.getClient(flags).cloneGitConnection(args.id, flags.branchName), flags);
});
}
}
@@ -0,0 +1,20 @@
import { Flags } from '@oclif/core';
import { BaseCommand } from '../../base-command';
export default class GitConnectionsCreate extends BaseCommand {
static override description = 'Create a Git connection from JSON';
static override flags = {
...BaseCommand.baseFlags,
file: Flags.string({ description: 'Path to Git connection JSON file' }),
stdin: Flags.boolean({ description: 'Read Git connection JSON from stdin', default: false }),
};
async run() {
const { flags } = await this.parse(GitConnectionsCreate);
await this.execute(async () => {
const body = JSON.parse(this.readInput(flags)) as unknown;
this.output(await this.getClient(flags).createGitConnection(body), flags);
});
}
}
@@ -0,0 +1,17 @@
import { Args } from '@oclif/core';
import { BaseCommand } from '../../base-command';
export default class GitConnectionsDelete extends BaseCommand {
static override description = 'Delete a Git connection';
static override args = { id: Args.string({ description: 'Git connection ID', required: true }) };
static override flags = { ...BaseCommand.baseFlags };
async run() {
const { args, flags } = await this.parse(GitConnectionsDelete);
await this.execute(async () => {
await this.getClient(flags).deleteGitConnection(args.id);
this.succeed(`Git connection ${args.id} deleted.`, flags, { id: args.id, deleted: true });
});
}
}
@@ -0,0 +1,16 @@
import { Args } from '@oclif/core';
import { BaseCommand } from '../../base-command';
export default class GitConnectionsDisconnect extends BaseCommand {
static override description = 'Disconnect a Git connection';
static override args = { id: Args.string({ description: 'Git connection ID', required: true }) };
static override flags = { ...BaseCommand.baseFlags };
async run() {
const { args, flags } = await this.parse(GitConnectionsDisconnect);
await this.execute(async () => {
this.output(await this.getClient(flags).disconnectGitConnection(args.id), flags);
});
}
}
@@ -0,0 +1,16 @@
import { Args } from '@oclif/core';
import { BaseCommand } from '../../base-command';
export default class GitConnectionsGet extends BaseCommand {
static override description = 'Get a Git connection by ID';
static override args = { id: Args.string({ description: 'Git connection ID', required: true }) };
static override flags = { ...BaseCommand.baseFlags };
async run() {
const { args, flags } = await this.parse(GitConnectionsGet);
await this.execute(async () => {
this.output(await this.getClient(flags).getGitConnection(args.id), flags);
});
}
}
@@ -0,0 +1,21 @@
import { Flags } from '@oclif/core';
import { BaseCommand } from '../../base-command';
export default class GitConnectionsList extends BaseCommand {
static override description = 'List Git connections';
static override flags = {
...BaseCommand.baseFlags,
limit: Flags.integer({ description: 'Maximum number of results' }),
};
async run() {
const { flags } = await this.parse(GitConnectionsList);
await this.execute(async () => {
const data = await this.getClient(flags).listGitConnections(flags.limit);
this.output(data, flags, {
columns: ['id', 'name', 'repositoryUrl', 'branchName', 'connectionType'],
});
});
}
}
@@ -0,0 +1,21 @@
import { Args, Flags } from '@oclif/core';
import { BaseCommand } from '../../base-command';
export default class GitConnectionsUpdate extends BaseCommand {
static override description = 'Update a Git connection from JSON';
static override args = { id: Args.string({ description: 'Git connection ID', required: true }) };
static override flags = {
...BaseCommand.baseFlags,
file: Flags.string({ description: 'Path to Git connection JSON file' }),
stdin: Flags.boolean({ description: 'Read Git connection JSON from stdin', default: false }),
};
async run() {
const { args, flags } = await this.parse(GitConnectionsUpdate);
await this.execute(async () => {
const body = JSON.parse(this.readInput(flags)) as unknown;
this.output(await this.getClient(flags).updateGitConnection(args.id, body), flags);
});
}
}
+15
View File
@@ -22,6 +22,13 @@ import ExecutionGet from './commands/execution/get';
import ExecutionList from './commands/execution/list';
import ExecutionRetry from './commands/execution/retry';
import ExecutionStop from './commands/execution/stop';
import GitConnectionsClone from './commands/git-connections/clone';
import GitConnectionsCreate from './commands/git-connections/create';
import GitConnectionsDelete from './commands/git-connections/delete';
import GitConnectionsDisconnect from './commands/git-connections/disconnect';
import GitConnectionsGet from './commands/git-connections/get';
import GitConnectionsList from './commands/git-connections/list';
import GitConnectionsUpdate from './commands/git-connections/update';
import Login from './commands/login';
import Logout from './commands/logout';
import PackageExport from './commands/package/export';
@@ -80,6 +87,14 @@ export const commands = {
'execution:stop': ExecutionStop,
'execution:delete': ExecutionDelete,
'git-connections:list': GitConnectionsList,
'git-connections:get': GitConnectionsGet,
'git-connections:create': GitConnectionsCreate,
'git-connections:update': GitConnectionsUpdate,
'git-connections:clone': GitConnectionsClone,
'git-connections:disconnect': GitConnectionsDisconnect,
'git-connections:delete': GitConnectionsDelete,
'credential:list': CredentialList,
'credential:get': CredentialGet,
'credential:schema': CredentialSchema,