@uipath/data-fabric-tool 1.0.4 → 1.195.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/browser.json +3 -0
- package/dist/index.js +20 -43167
- package/dist/tool.js +29174 -28399
- package/package.json +16 -32
- package/src/commands/choice-sets.spec.ts +849 -0
- package/src/commands/choice-sets.ts +690 -0
- package/src/commands/entities.spec.ts +411 -137
- package/src/commands/entities.ts +189 -368
- package/src/commands/files.spec.ts +18 -32
- package/src/commands/files.ts +43 -92
- package/src/commands/records.spec.ts +171 -207
- package/src/commands/records.ts +150 -342
- package/src/index.ts +5 -10
- package/src/tool.ts +6 -0
- package/src/utils/output.spec.ts +78 -0
- package/src/utils/output.ts +51 -0
- package/src/utils/sdk-client.spec.ts +59 -0
- package/src/utils/sdk-client.ts +23 -0
package/src/index.ts
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import
|
|
4
|
-
import { registerEntitiesCommand } from "./commands/entities";
|
|
5
|
-
import { registerFilesCommand } from "./commands/files";
|
|
6
|
-
import { registerRecordsCommand } from "./commands/records";
|
|
3
|
+
import { metadata, registerCommands } from "./tool.js";
|
|
7
4
|
|
|
8
5
|
const program = new Command();
|
|
9
6
|
program
|
|
10
|
-
.name(
|
|
11
|
-
.description(
|
|
12
|
-
.version(
|
|
7
|
+
.name(metadata.name)
|
|
8
|
+
.description(metadata.description)
|
|
9
|
+
.version(metadata.version);
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
registerRecordsCommand(program);
|
|
16
|
-
registerFilesCommand(program);
|
|
11
|
+
await registerCommands(program);
|
|
17
12
|
await program.parseAsync(process.argv);
|
package/src/tool.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import pkg from "../package.json" with { type: "json" };
|
|
3
|
+
import {
|
|
4
|
+
registerChoiceSetsCommand,
|
|
5
|
+
registerChoiceSetValuesCommand,
|
|
6
|
+
} from "./commands/choice-sets";
|
|
3
7
|
import { registerEntitiesCommand } from "./commands/entities";
|
|
4
8
|
import { registerFilesCommand } from "./commands/files";
|
|
5
9
|
import { registerRecordsCommand } from "./commands/records";
|
|
@@ -16,4 +20,6 @@ export const registerCommands = async (program: Command): Promise<void> => {
|
|
|
16
20
|
registerEntitiesCommand(program);
|
|
17
21
|
registerRecordsCommand(program);
|
|
18
22
|
registerFilesCommand(program);
|
|
23
|
+
registerChoiceSetsCommand(program);
|
|
24
|
+
registerChoiceSetValuesCommand(program);
|
|
19
25
|
};
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
vi.mock("@uipath/common", async (importOriginal) => {
|
|
4
|
+
const actual = await importOriginal<typeof import("@uipath/common")>();
|
|
5
|
+
return {
|
|
6
|
+
...actual,
|
|
7
|
+
OutputFormatter: { success: vi.fn(), error: vi.fn() },
|
|
8
|
+
};
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
import { OutputFormatter } from "@uipath/common";
|
|
12
|
+
import { fail, requireDestructiveConfirmation } from "./output";
|
|
13
|
+
|
|
14
|
+
describe("fail", () => {
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
vi.resetAllMocks();
|
|
17
|
+
process.exitCode = undefined;
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("emits a failure result and sets a non-zero exit code", () => {
|
|
21
|
+
fail("Something broke", "Try again.");
|
|
22
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
23
|
+
expect.objectContaining({
|
|
24
|
+
Result: "Failure",
|
|
25
|
+
Message: "Something broke",
|
|
26
|
+
Instructions: "Try again.",
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
expect(process.exitCode).toBe(1);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("requireDestructiveConfirmation", () => {
|
|
34
|
+
const reasonInstruction = "Pass --reason to explain.";
|
|
35
|
+
|
|
36
|
+
beforeEach(() => {
|
|
37
|
+
vi.resetAllMocks();
|
|
38
|
+
process.exitCode = undefined;
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("returns the trimmed reason when --confirm and --reason are present", () => {
|
|
42
|
+
const result = requireDestructiveConfirmation(
|
|
43
|
+
{ confirm: true, reason: " cleanup " },
|
|
44
|
+
reasonInstruction,
|
|
45
|
+
);
|
|
46
|
+
expect(result).toBe("cleanup");
|
|
47
|
+
expect(OutputFormatter.error).not.toHaveBeenCalled();
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
it("fails and returns null when --confirm is missing", () => {
|
|
51
|
+
const result = requireDestructiveConfirmation(
|
|
52
|
+
{ reason: "cleanup" },
|
|
53
|
+
reasonInstruction,
|
|
54
|
+
);
|
|
55
|
+
expect(result).toBeNull();
|
|
56
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
57
|
+
expect.objectContaining({
|
|
58
|
+
Message: "Confirmation required for destructive operation",
|
|
59
|
+
}),
|
|
60
|
+
);
|
|
61
|
+
expect(process.exitCode).toBe(1);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("fails and returns null when --reason is missing or blank", () => {
|
|
65
|
+
const result = requireDestructiveConfirmation(
|
|
66
|
+
{ confirm: true, reason: " " },
|
|
67
|
+
reasonInstruction,
|
|
68
|
+
);
|
|
69
|
+
expect(result).toBeNull();
|
|
70
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
71
|
+
expect.objectContaining({
|
|
72
|
+
Message: "Reason required for destructive operation",
|
|
73
|
+
Instructions: reasonInstruction,
|
|
74
|
+
}),
|
|
75
|
+
);
|
|
76
|
+
expect(process.exitCode).toBe(1);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { OutputFormatter, processContext, RESULTS } from "@uipath/common";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Emit a standard failure result and set a non-zero exit code.
|
|
5
|
+
*
|
|
6
|
+
* Returns `void` so a handler can halt in one line: `return fail(msg, instr);`
|
|
7
|
+
* (`processContext.exit` only sets `process.exitCode`, so the caller must still
|
|
8
|
+
* return to stop execution).
|
|
9
|
+
*/
|
|
10
|
+
export function fail(message: string, instructions: string): void {
|
|
11
|
+
OutputFormatter.error({
|
|
12
|
+
Result: RESULTS.Failure,
|
|
13
|
+
Message: message,
|
|
14
|
+
Instructions: instructions,
|
|
15
|
+
});
|
|
16
|
+
processContext.exit(1);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface DestructiveOptions {
|
|
20
|
+
confirm?: boolean;
|
|
21
|
+
reason?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validate the `--confirm`/`--reason` flags required for a destructive
|
|
26
|
+
* operation. On failure, emits the appropriate error, sets the exit code, and
|
|
27
|
+
* returns `null`. On success, returns the trimmed reason.
|
|
28
|
+
*
|
|
29
|
+
* @param reasonInstruction - Instruction text shown when `--reason` is missing,
|
|
30
|
+
* e.g. `'Pass --reason "<text>" to record why the choice set is being deleted.'`
|
|
31
|
+
*/
|
|
32
|
+
export function requireDestructiveConfirmation(
|
|
33
|
+
options: DestructiveOptions,
|
|
34
|
+
reasonInstruction: string,
|
|
35
|
+
): string | null {
|
|
36
|
+
if (options.confirm !== true) {
|
|
37
|
+
fail(
|
|
38
|
+
"Confirmation required for destructive operation",
|
|
39
|
+
"Pass --confirm to acknowledge this is irreversible.",
|
|
40
|
+
);
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const reason = options.reason?.trim();
|
|
45
|
+
if (reason === undefined || reason === "") {
|
|
46
|
+
fail("Reason required for destructive operation", reasonInstruction);
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return reason;
|
|
51
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
vi.mock("@uipath/auth", () => ({
|
|
4
|
+
getLoginStatusAsync: vi.fn(),
|
|
5
|
+
}));
|
|
6
|
+
|
|
7
|
+
vi.mock("@uipath/uipath-typescript", () => ({
|
|
8
|
+
UiPath: class {},
|
|
9
|
+
}));
|
|
10
|
+
|
|
11
|
+
vi.mock("@uipath/common", async (importOriginal) => {
|
|
12
|
+
const actual = await importOriginal<typeof import("@uipath/common")>();
|
|
13
|
+
return {
|
|
14
|
+
...actual,
|
|
15
|
+
OutputFormatter: { success: vi.fn(), error: vi.fn() },
|
|
16
|
+
};
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
import { getLoginStatusAsync } from "@uipath/auth";
|
|
20
|
+
import { OutputFormatter } from "@uipath/common";
|
|
21
|
+
import { connectOrFail } from "./sdk-client";
|
|
22
|
+
|
|
23
|
+
describe("connectOrFail", () => {
|
|
24
|
+
beforeEach(() => {
|
|
25
|
+
vi.resetAllMocks();
|
|
26
|
+
process.exitCode = undefined;
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("returns a client when logged in", async () => {
|
|
30
|
+
vi.mocked(getLoginStatusAsync).mockResolvedValue({
|
|
31
|
+
loginStatus: "Logged in",
|
|
32
|
+
accessToken: "token",
|
|
33
|
+
baseUrl: "https://cloud.uipath.com",
|
|
34
|
+
organizationName: "org",
|
|
35
|
+
tenantName: "tenant",
|
|
36
|
+
} as never);
|
|
37
|
+
|
|
38
|
+
const sdk = await connectOrFail();
|
|
39
|
+
expect(sdk).toBeDefined();
|
|
40
|
+
expect(OutputFormatter.error).not.toHaveBeenCalled();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("emits a connection error and returns undefined when not logged in", async () => {
|
|
44
|
+
vi.mocked(getLoginStatusAsync).mockResolvedValue({
|
|
45
|
+
loginStatus: "LoggedOut",
|
|
46
|
+
hint: "Run 'uip login' first.",
|
|
47
|
+
} as never);
|
|
48
|
+
|
|
49
|
+
const sdk = await connectOrFail();
|
|
50
|
+
expect(sdk).toBeUndefined();
|
|
51
|
+
expect(OutputFormatter.error).toHaveBeenCalledWith(
|
|
52
|
+
expect.objectContaining({
|
|
53
|
+
Result: "Failure",
|
|
54
|
+
Message: "Error connecting to Data Fabric",
|
|
55
|
+
}),
|
|
56
|
+
);
|
|
57
|
+
expect(process.exitCode).toBe(1);
|
|
58
|
+
});
|
|
59
|
+
});
|
package/src/utils/sdk-client.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { getLoginStatusAsync } from "@uipath/auth";
|
|
2
|
+
import { catchError, extractErrorMessage } from "@uipath/common";
|
|
2
3
|
import { UiPath } from "@uipath/uipath-typescript";
|
|
4
|
+
import { fail } from "./output";
|
|
3
5
|
|
|
4
6
|
export const createDataFabricClient = async (
|
|
5
7
|
tenantOverride?: string,
|
|
@@ -21,3 +23,24 @@ export const createDataFabricClient = async (
|
|
|
21
23
|
tenantName: tenantOverride ?? status.tenantName,
|
|
22
24
|
});
|
|
23
25
|
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create a Data Fabric client, or emit a standard connection error and return
|
|
29
|
+
* `undefined`. Lets a handler open with: `const sdk = await connectOrFail(t);
|
|
30
|
+
* if (!sdk) return;`
|
|
31
|
+
*/
|
|
32
|
+
export const connectOrFail = async (
|
|
33
|
+
tenantOverride?: string,
|
|
34
|
+
): Promise<UiPath | undefined> => {
|
|
35
|
+
const [clientError, sdk] = await catchError(
|
|
36
|
+
createDataFabricClient(tenantOverride),
|
|
37
|
+
);
|
|
38
|
+
if (clientError) {
|
|
39
|
+
fail(
|
|
40
|
+
"Error connecting to Data Fabric",
|
|
41
|
+
await extractErrorMessage(clientError),
|
|
42
|
+
);
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
return sdk;
|
|
46
|
+
};
|