@credibledata/cred-cli 0.1.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/.eslintrc +33 -0
- package/.github/workflows/build.yml +23 -0
- package/.mocharc.json +10 -0
- package/.prettierignore +1 -0
- package/.prettierrc +4 -0
- package/README.md +40 -0
- package/bun.lock +1259 -0
- package/dist/client/api.js +7022 -0
- package/dist/client/api.js.map +1 -0
- package/dist/client/base.js +69 -0
- package/dist/client/base.js.map +1 -0
- package/dist/client/common.js +162 -0
- package/dist/client/common.js.map +1 -0
- package/dist/client/configuration.js +44 -0
- package/dist/client/configuration.js.map +1 -0
- package/dist/client/index.js +32 -0
- package/dist/client/index.js.map +1 -0
- package/dist/clientconfiguration.js +163 -0
- package/dist/clientconfiguration.js.map +1 -0
- package/dist/clientconfiguration.spec.js +92 -0
- package/dist/clientconfiguration.spec.js.map +1 -0
- package/dist/commands/add.js +61 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/connection/createconnections.js +62 -0
- package/dist/commands/connection/createconnections.js.map +1 -0
- package/dist/commands/connection/deleteconnection.js +52 -0
- package/dist/commands/connection/deleteconnection.js.map +1 -0
- package/dist/commands/connection/listconnections.js +44 -0
- package/dist/commands/connection/listconnections.js.map +1 -0
- package/dist/commands/get.js +28 -0
- package/dist/commands/get.js.map +1 -0
- package/dist/commands/group/addmember.js +73 -0
- package/dist/commands/group/addmember.js.map +1 -0
- package/dist/commands/group/creategroup.js +55 -0
- package/dist/commands/group/creategroup.js.map +1 -0
- package/dist/commands/group/deletegroup.js +48 -0
- package/dist/commands/group/deletegroup.js.map +1 -0
- package/dist/commands/group/getgroup.js +50 -0
- package/dist/commands/group/getgroup.js.map +1 -0
- package/dist/commands/group/listgroups.js +56 -0
- package/dist/commands/group/listgroups.js.map +1 -0
- package/dist/commands/group/removemember.js +68 -0
- package/dist/commands/group/removemember.js.map +1 -0
- package/dist/commands/groupaccesstoken/createToken.js +49 -0
- package/dist/commands/groupaccesstoken/createToken.js.map +1 -0
- package/dist/commands/groupaccesstoken/deleteToken.js +24 -0
- package/dist/commands/groupaccesstoken/deleteToken.js.map +1 -0
- package/dist/commands/groupaccesstoken/groupContainer.js +71 -0
- package/dist/commands/groupaccesstoken/groupContainer.js.map +1 -0
- package/dist/commands/groupaccesstoken/listTokens.js +25 -0
- package/dist/commands/groupaccesstoken/listTokens.js.map +1 -0
- package/dist/commands/list.js +68 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/misc/login.js +166 -0
- package/dist/commands/misc/login.js.map +1 -0
- package/dist/commands/misc/login.spec.js +138 -0
- package/dist/commands/misc/login.spec.js.map +1 -0
- package/dist/commands/misc/logout.js +11 -0
- package/dist/commands/misc/logout.js.map +1 -0
- package/dist/commands/misc/set-access-token.js +27 -0
- package/dist/commands/misc/set-access-token.js.map +1 -0
- package/dist/commands/package/deletepackage.js +54 -0
- package/dist/commands/package/deletepackage.js.map +1 -0
- package/dist/commands/package/listpackages.js +52 -0
- package/dist/commands/package/listpackages.js.map +1 -0
- package/dist/commands/package/publish.js +134 -0
- package/dist/commands/package/publish.js.map +1 -0
- package/dist/commands/package/updatepackage.js +75 -0
- package/dist/commands/package/updatepackage.js.map +1 -0
- package/dist/commands/package/updatepackage.spec.js +139 -0
- package/dist/commands/package/updatepackage.spec.js.map +1 -0
- package/dist/commands/project/createproject.js +65 -0
- package/dist/commands/project/createproject.js.map +1 -0
- package/dist/commands/project/deleteproject.js +49 -0
- package/dist/commands/project/deleteproject.js.map +1 -0
- package/dist/commands/project/getproject.js +44 -0
- package/dist/commands/project/getproject.js.map +1 -0
- package/dist/commands/project/listprojects.js +46 -0
- package/dist/commands/project/listprojects.js.map +1 -0
- package/dist/commands/project/setproject.js +26 -0
- package/dist/commands/project/setproject.js.map +1 -0
- package/dist/commands/rm.js +68 -0
- package/dist/commands/rm.js.map +1 -0
- package/dist/commands/set.js +17 -0
- package/dist/commands/set.js.map +1 -0
- package/dist/commands/update.js +29 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/commands/version/archive-unarchive-version.js +79 -0
- package/dist/commands/version/archive-unarchive-version.js.map +1 -0
- package/dist/commands/version/archive-unarchive-version.spec.js +244 -0
- package/dist/commands/version/archive-unarchive-version.spec.js.map +1 -0
- package/dist/commands/version/listversions.js +46 -0
- package/dist/commands/version/listversions.js.map +1 -0
- package/dist/common/UserGroupId.js +112 -0
- package/dist/common/UserGroupId.js.map +1 -0
- package/dist/constants.js +54 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.js +137 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.js +77 -0
- package/dist/logger.js.map +1 -0
- package/dist/polyfills/file.polyfill.js +6 -0
- package/dist/polyfills/file.polyfill.js.map +1 -0
- package/dist/utils.js +51 -0
- package/dist/utils.js.map +1 -0
- package/dist/validator.js +53 -0
- package/dist/validator.js.map +1 -0
- package/dist/validator.spec.js +41 -0
- package/dist/validator.spec.js.map +1 -0
- package/docker/Dockerfile.ci +10 -0
- package/docker-compose.yml +18 -0
- package/mocha.setup.ts +4 -0
- package/openapitools.json +7 -0
- package/package.json +67 -0
- package/src/client/.openapi-generator/FILES +8 -0
- package/src/client/.openapi-generator/VERSION +1 -0
- package/src/client/.openapi-generator-ignore +23 -0
- package/src/client/api.ts +8408 -0
- package/src/client/base.ts +86 -0
- package/src/client/common.ts +150 -0
- package/src/client/configuration.ts +110 -0
- package/src/client/git_push.sh +57 -0
- package/src/client/index.ts +18 -0
- package/src/clientconfiguration.spec.ts +116 -0
- package/src/clientconfiguration.ts +204 -0
- package/src/commands/add.ts +106 -0
- package/src/commands/connection/createconnections.ts +67 -0
- package/src/commands/connection/deleteconnection.ts +57 -0
- package/src/commands/connection/listconnections.ts +39 -0
- package/src/commands/get.ts +31 -0
- package/src/commands/group/addmember.ts +83 -0
- package/src/commands/group/creategroup.ts +54 -0
- package/src/commands/group/deletegroup.ts +45 -0
- package/src/commands/group/getgroup.ts +47 -0
- package/src/commands/group/listgroups.ts +45 -0
- package/src/commands/group/removemember.ts +74 -0
- package/src/commands/groupaccesstoken/createToken.ts +68 -0
- package/src/commands/groupaccesstoken/deleteToken.ts +24 -0
- package/src/commands/groupaccesstoken/groupContainer.ts +83 -0
- package/src/commands/groupaccesstoken/listTokens.ts +24 -0
- package/src/commands/list.ts +90 -0
- package/src/commands/misc/login.spec.ts +128 -0
- package/src/commands/misc/login.ts +142 -0
- package/src/commands/misc/logout.ts +9 -0
- package/src/commands/misc/set-access-token.ts +32 -0
- package/src/commands/package/deletepackage.ts +58 -0
- package/src/commands/package/listpackages.ts +44 -0
- package/src/commands/package/publish.ts +179 -0
- package/src/commands/package/updatepackage.spec.ts +221 -0
- package/src/commands/package/updatepackage.ts +95 -0
- package/src/commands/project/createproject.ts +59 -0
- package/src/commands/project/deleteproject.ts +48 -0
- package/src/commands/project/getproject.ts +43 -0
- package/src/commands/project/listprojects.ts +36 -0
- package/src/commands/project/setproject.ts +14 -0
- package/src/commands/rm.ts +106 -0
- package/src/commands/set.ts +16 -0
- package/src/commands/update.ts +41 -0
- package/src/commands/version/archive-unarchive-version.spec.ts +456 -0
- package/src/commands/version/archive-unarchive-version.ts +111 -0
- package/src/commands/version/listversions.ts +45 -0
- package/src/common/UserGroupId.ts +137 -0
- package/src/constants.ts +70 -0
- package/src/index.ts +183 -0
- package/src/logger.ts +86 -0
- package/src/polyfills/file.polyfill.ts +5 -0
- package/src/utils.ts +34 -0
- package/src/validator.spec.ts +51 -0
- package/src/validator.ts +44 -0
- package/tsconfig.json +20 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Enum representing the different types of user/group resources.
|
|
3
|
+
*/
|
|
4
|
+
export enum ResourceType {
|
|
5
|
+
USER = "USER",
|
|
6
|
+
GROUP = "GROUP",
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Represents a user or group identifier in the format 'user:userId' or 'group:groupId'.
|
|
11
|
+
* This class parses the input string and provides methods to extract the
|
|
12
|
+
* resource type and name.
|
|
13
|
+
*/
|
|
14
|
+
export class UserGroupId {
|
|
15
|
+
private readonly resourceType: ResourceType;
|
|
16
|
+
private readonly resourceName: string;
|
|
17
|
+
private readonly originalValue: string;
|
|
18
|
+
|
|
19
|
+
static forPublicAccess(): UserGroupId {
|
|
20
|
+
return new UserGroupId(`user:*`);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
static forUser(userName: string | undefined): UserGroupId {
|
|
24
|
+
if (!userName) {
|
|
25
|
+
throw new Error("User name cannot be undefined");
|
|
26
|
+
}
|
|
27
|
+
return new UserGroupId(`user:${userName}`);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static forGroup(groupName: string): UserGroupId {
|
|
31
|
+
return new UserGroupId(`group:${groupName}`);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Creates a UserGroupId from a string in the format 'user:userId' or 'group:groupId'.
|
|
35
|
+
*
|
|
36
|
+
* @param value the string to parse
|
|
37
|
+
* @throws BadRequestException if the format is invalid
|
|
38
|
+
*/
|
|
39
|
+
constructor(value: string) {
|
|
40
|
+
if (!value || value.trim().length === 0) {
|
|
41
|
+
throw new Error("UserGroupId cannot be null or empty");
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
this.originalValue = value.trim();
|
|
45
|
+
|
|
46
|
+
if (!this.originalValue.match(/^(user:[^:]+|group:[^:]+)$/)) {
|
|
47
|
+
throw new Error(
|
|
48
|
+
`Invalid UserGroupId format. Expected 'user:userId' or 'group:groupId', got: ${this.originalValue}`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const parts = this.originalValue.split(":", 2);
|
|
53
|
+
const typeStr = parts[0];
|
|
54
|
+
const name = parts[1];
|
|
55
|
+
|
|
56
|
+
if (!name || name.length === 0) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
`UserGroupId name cannot be empty. Expected 'user:userId' or 'group:groupId', got: ${this.originalValue}`,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
switch (typeStr) {
|
|
63
|
+
case "user":
|
|
64
|
+
this.resourceType = ResourceType.USER;
|
|
65
|
+
break;
|
|
66
|
+
case "group":
|
|
67
|
+
this.resourceType = ResourceType.GROUP;
|
|
68
|
+
break;
|
|
69
|
+
default:
|
|
70
|
+
throw new Error(
|
|
71
|
+
`Invalid UserGroupId type. Expected 'user' or 'group', got: ${typeStr}`,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
this.resourceName = name;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Creates a UserGroupId from resource type and name.
|
|
80
|
+
*
|
|
81
|
+
* @param resourceType the resource type
|
|
82
|
+
* @param userName the user or group name
|
|
83
|
+
*/
|
|
84
|
+
public static create(
|
|
85
|
+
resourceType: ResourceType,
|
|
86
|
+
userName: string,
|
|
87
|
+
): UserGroupId {
|
|
88
|
+
return new UserGroupId(`${resourceType.toLowerCase()}:${userName}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Returns the resource type (USER or GROUP).
|
|
93
|
+
*
|
|
94
|
+
* @return the resource type
|
|
95
|
+
*/
|
|
96
|
+
public getResourceType(): ResourceType {
|
|
97
|
+
return this.resourceType;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Returns the resource name (the part after the colon).
|
|
102
|
+
*
|
|
103
|
+
* @return the resource name
|
|
104
|
+
*/
|
|
105
|
+
public getResourceName(): string {
|
|
106
|
+
return this.resourceName;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Returns the original string value.
|
|
111
|
+
*
|
|
112
|
+
* @return the original string value
|
|
113
|
+
*/
|
|
114
|
+
public getValue(): string {
|
|
115
|
+
return this.originalValue;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
public toString(): string {
|
|
119
|
+
return this.originalValue;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Custom JSON serialization method for axios/openapi.
|
|
124
|
+
* This ensures UserGroupId is serialized as a string (originalValue) instead of an object.
|
|
125
|
+
*
|
|
126
|
+
* @return the original string value for JSON serialization
|
|
127
|
+
*/
|
|
128
|
+
public toJSON(): string {
|
|
129
|
+
return this.originalValue;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public isPublicAccess(): boolean {
|
|
133
|
+
return (
|
|
134
|
+
this.resourceType === ResourceType.USER && this.originalValue === "*"
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
package/src/constants.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export type Environment =
|
|
2
|
+
| "production"
|
|
3
|
+
| "staging"
|
|
4
|
+
| "dev"
|
|
5
|
+
| "localhost"
|
|
6
|
+
| "e2e-test";
|
|
7
|
+
|
|
8
|
+
export const controlPlanesByEnv: Record<Environment, string> = {
|
|
9
|
+
production: "https://admin.ms2.co/api/v0",
|
|
10
|
+
dev: "https://dev-admin.ms2.co/api/v0",
|
|
11
|
+
staging: "https://staging-admin.ms2.co/api/v0",
|
|
12
|
+
localhost: "http://admin.ms2.localhost/api/v0",
|
|
13
|
+
"e2e-test": "http://admin.ms2.localhost/api/v0",
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const auth0ConfigsByEnv: Record<
|
|
17
|
+
Environment,
|
|
18
|
+
{
|
|
19
|
+
domain: string;
|
|
20
|
+
clientId: string;
|
|
21
|
+
clientSecret?: string;
|
|
22
|
+
audience: string;
|
|
23
|
+
}
|
|
24
|
+
> = {
|
|
25
|
+
production: {
|
|
26
|
+
domain: "https://ms2data.us.auth0.com",
|
|
27
|
+
clientId: "ge8JL5TJNwqy7bygAaJkD92KdluqEZgO",
|
|
28
|
+
audience: "https://ms2data.us.auth0.com/api/v2/",
|
|
29
|
+
},
|
|
30
|
+
dev: {
|
|
31
|
+
domain: "https://dev-ohaafogw5p8uyx1m.us.auth0.com",
|
|
32
|
+
clientId: "rr6mzJNj9b104MjCc9xWKPPehq1MJx0L",
|
|
33
|
+
audience: "https://dev-ohaafogw5p8uyx1m.us.auth0.com/api/v2/",
|
|
34
|
+
},
|
|
35
|
+
staging: {
|
|
36
|
+
domain: "https://dev-ohaafogw5p8uyx1m.us.auth0.com",
|
|
37
|
+
clientId: "rr6mzJNj9b104MjCc9xWKPPehq1MJx0L",
|
|
38
|
+
audience: "https://dev-ohaafogw5p8uyx1m.us.auth0.com/api/v2/",
|
|
39
|
+
},
|
|
40
|
+
localhost: {
|
|
41
|
+
domain: "https://dev-ohaafogw5p8uyx1m.us.auth0.com",
|
|
42
|
+
clientId: "rr6mzJNj9b104MjCc9xWKPPehq1MJx0L",
|
|
43
|
+
audience: "https://dev-ohaafogw5p8uyx1m.us.auth0.com/api/v2/",
|
|
44
|
+
},
|
|
45
|
+
"e2e-test": {
|
|
46
|
+
domain: "https://dev-ohaafogw5p8uyx1m.us.auth0.com",
|
|
47
|
+
clientId: "atd8n8dEiGUiNRM7Geuvg41fi5s8ZKqY",
|
|
48
|
+
clientSecret:
|
|
49
|
+
"ZrEvs86WLqKO9EPp4y_cOvUn3NQT1qc3XC8111f6DBt9oyaclV5sWHz6Nkyo_bEF",
|
|
50
|
+
audience: "https://dev-ohaafogw5p8uyx1m.us.auth0.com/api/v2/",
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// Time constants in ms
|
|
55
|
+
export const SECOND = 1000;
|
|
56
|
+
export const MINUTE = SECOND * 60;
|
|
57
|
+
export const HOUR = MINUTE * 60;
|
|
58
|
+
export const DAY = HOUR * 24;
|
|
59
|
+
|
|
60
|
+
// Login related
|
|
61
|
+
export const LOGIN_TIMEOUT_MS = MINUTE * 5;
|
|
62
|
+
|
|
63
|
+
export const ASCII_TITLE = `
|
|
64
|
+
_____ _ _ _ _ _____ _ _____
|
|
65
|
+
/ ____| | (_) | | | / ____| | |_ _|
|
|
66
|
+
| | _ __ ___ __| |_| |__ | | ___ | | | | | |
|
|
67
|
+
| | | '__/ _ \\/ _\` | | '_ \\| |/ _ \\ | | | | | |
|
|
68
|
+
| |____| | | __/ (_| | | |_) | | __/ | |____| |____ _| |_
|
|
69
|
+
\\_____|_| \\___|\\__,_|_|_.__/|_|\\___| \\_____|______|_____|
|
|
70
|
+
`;
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
import { program } from "commander";
|
|
4
|
+
import kleur from "kleur";
|
|
5
|
+
import omelette from "omelette";
|
|
6
|
+
import cliPackage from "../package.json";
|
|
7
|
+
import { ClientConfiguration } from "./clientconfiguration";
|
|
8
|
+
import { registerAddCommands } from "./commands/add";
|
|
9
|
+
import { registerGetCommands } from "./commands/get";
|
|
10
|
+
import { registerListCommands } from "./commands/list";
|
|
11
|
+
import { login } from "./commands/misc/login";
|
|
12
|
+
import { logout } from "./commands/misc/logout";
|
|
13
|
+
import { setAccessToken } from "./commands/misc/set-access-token";
|
|
14
|
+
import { listPackages } from "./commands/package/listpackages";
|
|
15
|
+
import { publish } from "./commands/package/publish";
|
|
16
|
+
import { listProjects } from "./commands/project/listprojects";
|
|
17
|
+
import { registerRmCommands } from "./commands/rm";
|
|
18
|
+
import { registerSetCommands } from "./commands/set";
|
|
19
|
+
import { registerUpdateCommands } from "./commands/update";
|
|
20
|
+
import {
|
|
21
|
+
archiveVersion,
|
|
22
|
+
unarchiveVersion,
|
|
23
|
+
} from "./commands/version/archive-unarchive-version";
|
|
24
|
+
import { ASCII_TITLE, controlPlanesByEnv } from "./constants";
|
|
25
|
+
|
|
26
|
+
const clientConfig = new ClientConfiguration();
|
|
27
|
+
|
|
28
|
+
const activeEnvironment = clientConfig.getEnvironment();
|
|
29
|
+
axios.defaults.baseURL = controlPlanesByEnv[activeEnvironment];
|
|
30
|
+
|
|
31
|
+
const cli = program
|
|
32
|
+
.version(cliPackage.version)
|
|
33
|
+
.description(kleur.green(ASCII_TITLE));
|
|
34
|
+
|
|
35
|
+
// Nested CRUD commands for resource management
|
|
36
|
+
registerGetCommands(cli, activeEnvironment);
|
|
37
|
+
registerListCommands(cli, activeEnvironment);
|
|
38
|
+
registerUpdateCommands(cli, activeEnvironment);
|
|
39
|
+
registerRmCommands(cli, activeEnvironment);
|
|
40
|
+
registerAddCommands(cli, activeEnvironment);
|
|
41
|
+
registerSetCommands(cli);
|
|
42
|
+
|
|
43
|
+
// Root commands
|
|
44
|
+
cli.command("publish")
|
|
45
|
+
.description("Publish a new version of the package.")
|
|
46
|
+
.option("--debug")
|
|
47
|
+
.option("-y, --yes", "Skip confirmation.")
|
|
48
|
+
.option(
|
|
49
|
+
"--replication <replication_count>",
|
|
50
|
+
"The number of replicas to create.",
|
|
51
|
+
(v) => (v === undefined ? undefined : parseInt(v)),
|
|
52
|
+
undefined,
|
|
53
|
+
)
|
|
54
|
+
.option(
|
|
55
|
+
"--set-latest",
|
|
56
|
+
"Set this version as the latest version of the package.",
|
|
57
|
+
false,
|
|
58
|
+
)
|
|
59
|
+
.action((options) => {
|
|
60
|
+
publish(
|
|
61
|
+
controlPlanesByEnv[activeEnvironment],
|
|
62
|
+
options.replicationCount,
|
|
63
|
+
options.debug,
|
|
64
|
+
options.yes,
|
|
65
|
+
options.setLatest,
|
|
66
|
+
);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
cli.command("archive")
|
|
70
|
+
.description("Archive a version of a package.")
|
|
71
|
+
.argument(
|
|
72
|
+
"<packageName>",
|
|
73
|
+
"The name of the package to archive the version of.",
|
|
74
|
+
)
|
|
75
|
+
.argument("<versionId>", "The id of the version to archive.")
|
|
76
|
+
.option("--debug")
|
|
77
|
+
.option("-y, --yes", "Skip confirmation.")
|
|
78
|
+
.action((packageName, versionId, options) => {
|
|
79
|
+
archiveVersion(
|
|
80
|
+
controlPlanesByEnv[activeEnvironment],
|
|
81
|
+
packageName,
|
|
82
|
+
versionId,
|
|
83
|
+
options.debug,
|
|
84
|
+
options.yes,
|
|
85
|
+
);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
cli.command("unarchive")
|
|
89
|
+
.description("Unarchive a version of a package.")
|
|
90
|
+
.argument(
|
|
91
|
+
"<packageName>",
|
|
92
|
+
"The name of the package to unarchive the version of.",
|
|
93
|
+
)
|
|
94
|
+
.argument("<versionId>", "The id of the version to unarchive.")
|
|
95
|
+
.option("--debug")
|
|
96
|
+
.option("-y, --yes", "Skip confirmation.")
|
|
97
|
+
.action((packageName, versionId, options) => {
|
|
98
|
+
unarchiveVersion(
|
|
99
|
+
controlPlanesByEnv[activeEnvironment],
|
|
100
|
+
packageName,
|
|
101
|
+
versionId,
|
|
102
|
+
options.debug,
|
|
103
|
+
options.yes,
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
cli.command("login")
|
|
108
|
+
.description("Login into Credible service.")
|
|
109
|
+
.argument("<organizationName>", "The organization to login to.")
|
|
110
|
+
.action((organizationName) => {
|
|
111
|
+
login(organizationName);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
cli.command("logout")
|
|
115
|
+
.description("Resets Credible service credentials")
|
|
116
|
+
.action(logout);
|
|
117
|
+
|
|
118
|
+
cli.command("set-access-token")
|
|
119
|
+
.description("Set a service account JWT token for CLI authentication")
|
|
120
|
+
.argument("<jwtToken>", "The JWT token to use for authentication")
|
|
121
|
+
.option("-o, --organization <organizationName>", "Organization name to set")
|
|
122
|
+
.action((jwtToken, options) => {
|
|
123
|
+
setAccessToken(jwtToken, options.organization);
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
cli.command("status")
|
|
127
|
+
.description("Shows the currently active organization and project.")
|
|
128
|
+
.action(() => {
|
|
129
|
+
const config = new ClientConfiguration();
|
|
130
|
+
config.printStatus();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
const complete = omelette("cred").tree({
|
|
134
|
+
// CRUD commands
|
|
135
|
+
get: ["project", "group"],
|
|
136
|
+
ls: ["project", "connection", "package", "version", "group", "group-access-token"],
|
|
137
|
+
update: ["package"],
|
|
138
|
+
rm: ["project", "connection", "package", "group", "member", "group-access-token"],
|
|
139
|
+
add: ["project", "connection", "group", "member", "group-access-token"],
|
|
140
|
+
// Misc commands
|
|
141
|
+
set: ["project"],
|
|
142
|
+
login: [],
|
|
143
|
+
logout: [],
|
|
144
|
+
"set-access-token": [],
|
|
145
|
+
status: [],
|
|
146
|
+
publish: [],
|
|
147
|
+
archive: [],
|
|
148
|
+
unarchive: [],
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
complete.onAsync("$3", async ({ reply, line }) => {
|
|
152
|
+
const projectRelatedCommands = ["set project", "get project", "rm project"];
|
|
153
|
+
if (projectRelatedCommands.some((cmd) => line.includes(cmd))) {
|
|
154
|
+
reply(
|
|
155
|
+
listProjects(controlPlanesByEnv[activeEnvironment], false).then(
|
|
156
|
+
(projects) => projects.map((project) => project.name),
|
|
157
|
+
),
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
const packageRelatedCommands = ["rm package", "ls version"];
|
|
161
|
+
if (packageRelatedCommands.some((cmd) => line.includes(cmd))) {
|
|
162
|
+
reply(
|
|
163
|
+
listPackages(controlPlanesByEnv[activeEnvironment], false).then(
|
|
164
|
+
(packages) => packages.map((_package) => _package.name),
|
|
165
|
+
),
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
complete.next(() => {
|
|
171
|
+
program.parse(process.argv);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
if (~process.argv.indexOf("--cleanup")) {
|
|
175
|
+
complete.cleanupShellInitFile();
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (~process.argv.indexOf("--install")) {
|
|
179
|
+
complete.setupShellInitFile();
|
|
180
|
+
console.log("CLI installed successfully!");
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
complete.init();
|
package/src/logger.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { AxiosError } from "axios";
|
|
2
|
+
import kleur from "kleur";
|
|
3
|
+
import winston from "winston";
|
|
4
|
+
|
|
5
|
+
const logColors = {
|
|
6
|
+
error: kleur.red,
|
|
7
|
+
warn: kleur.yellow,
|
|
8
|
+
info: kleur.cyan,
|
|
9
|
+
http: kleur.magenta,
|
|
10
|
+
debug: kleur.gray,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Custom console log format
|
|
14
|
+
const consoleFormat = winston.format.printf(({ level, message, timestamp }) => {
|
|
15
|
+
const colorFn = logColors[level] || ((text: string) => text);
|
|
16
|
+
return `[${kleur.gray(timestamp as string)}] ${colorFn(level.toUpperCase())}: ${message}`;
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
// Create Winston logger
|
|
20
|
+
export const logger = winston.createLogger({
|
|
21
|
+
level: "debug",
|
|
22
|
+
format: winston.format.combine(
|
|
23
|
+
winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
|
|
24
|
+
winston.format.errors({ stack: true }),
|
|
25
|
+
winston.format.splat(),
|
|
26
|
+
),
|
|
27
|
+
transports: [
|
|
28
|
+
// Console transport with colored logs
|
|
29
|
+
new winston.transports.Console({
|
|
30
|
+
format: consoleFormat,
|
|
31
|
+
}),
|
|
32
|
+
|
|
33
|
+
// NOTE disabled app.log logging
|
|
34
|
+
// File transport (logs without colors)
|
|
35
|
+
// new winston.transports.File({
|
|
36
|
+
// filename: "app.log",
|
|
37
|
+
// level: "info",
|
|
38
|
+
// format: winston.format.json(),
|
|
39
|
+
// }),
|
|
40
|
+
],
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
export const logAxiosError = (error: AxiosError, debug: boolean) => {
|
|
44
|
+
if (error.response) {
|
|
45
|
+
// The request was made and the server responded with a status code
|
|
46
|
+
// that falls out of the range of 2xx
|
|
47
|
+
if (debug) {
|
|
48
|
+
logger.error(
|
|
49
|
+
`Error ${error.response.status} at ${error.request.path}`,
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
switch (error.response.status) {
|
|
53
|
+
case 401:
|
|
54
|
+
logger.error(
|
|
55
|
+
"Unauthorized: Please double check that you are logged in",
|
|
56
|
+
);
|
|
57
|
+
break;
|
|
58
|
+
case 403:
|
|
59
|
+
logger.error(
|
|
60
|
+
"Forbidden: You're not allowed to perform this operation",
|
|
61
|
+
);
|
|
62
|
+
break;
|
|
63
|
+
case 500:
|
|
64
|
+
logger.error("Internal Server Error");
|
|
65
|
+
break;
|
|
66
|
+
default:
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
if (error.response.data) {
|
|
70
|
+
logger.error(error.response.data);
|
|
71
|
+
}
|
|
72
|
+
} else if (error.request) {
|
|
73
|
+
// The request was made but no response was received
|
|
74
|
+
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of
|
|
75
|
+
// http.ClientRequest in node.js
|
|
76
|
+
const requestOptions = error.request._options;
|
|
77
|
+
logger.error(
|
|
78
|
+
`Failed to ${requestOptions.method} resource ${requestOptions.path} on ${requestOptions.hostname}:${requestOptions.port}`,
|
|
79
|
+
);
|
|
80
|
+
|
|
81
|
+
logger.error(error.code, error.message);
|
|
82
|
+
} else {
|
|
83
|
+
// Something happened in setting up the request that triggered an Error
|
|
84
|
+
logger.error("Error", error.message);
|
|
85
|
+
}
|
|
86
|
+
};
|
package/src/utils.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import inquirer from "inquirer";
|
|
3
|
+
import { logAxiosError, logger } from "./logger";
|
|
4
|
+
|
|
5
|
+
export function sleep(time_in_ms: number): Promise<void> {
|
|
6
|
+
return new Promise((resolve) => setTimeout(resolve, time_in_ms));
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function prettifyJson(payload: object): string {
|
|
10
|
+
return JSON.stringify(payload, null, 2);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function printOutError(e: Error, debug: boolean) {
|
|
14
|
+
if (axios.isAxiosError(e)) {
|
|
15
|
+
logAxiosError(e, debug);
|
|
16
|
+
} else {
|
|
17
|
+
logger.error("Unexpected error", e);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
if (debug) {
|
|
21
|
+
logger.debug(e);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function getConfirmation(message: string): Promise<boolean> {
|
|
26
|
+
const answer = await inquirer.prompt([
|
|
27
|
+
{
|
|
28
|
+
type: "confirm",
|
|
29
|
+
name: "confirm",
|
|
30
|
+
message,
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
return answer.confirm;
|
|
34
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { expect } from "chai";
|
|
2
|
+
import { validatePath, PathType, validateManifest } from "./validator";
|
|
3
|
+
|
|
4
|
+
describe("validator", () => {
|
|
5
|
+
describe("validatePath", () => {
|
|
6
|
+
it("should return PathType.Invalid for a path not starting with '/'", () => {
|
|
7
|
+
expect(validatePath("invalidPath")).to.equal(PathType.Invalid);
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("should return PathType.Root for '/'", () => {
|
|
11
|
+
expect(validatePath("/")).to.equal(PathType.Root);
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it("should return PathType.Package for a valid package path", () => {
|
|
15
|
+
expect(validatePath("/package123")).to.equal(PathType.Package);
|
|
16
|
+
expect(validatePath("/abc-def")).to.equal(PathType.Package);
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should return PathType.Invalid for a package path with invalid characters", () => {
|
|
20
|
+
expect(validatePath("/package@123")).to.equal(PathType.Invalid);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it("should return PathType.Version for a valid package and version path", () => {
|
|
24
|
+
expect(validatePath("/package123/1.0.0")).to.equal(PathType.Version);
|
|
25
|
+
expect(validatePath("/abc-def/2.3.4")).to.equal(PathType.Version);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("should return PathType.Invalid for a version path with invalid characters", () => {
|
|
29
|
+
expect(validatePath("/package123/1.0.0-beta")).to.equal(
|
|
30
|
+
PathType.Invalid,
|
|
31
|
+
);
|
|
32
|
+
expect(validatePath("/abc-def/2.3.4!")).to.equal(PathType.Invalid);
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("should return PathType.Invalid for a path with too many segments", () => {
|
|
36
|
+
expect(validatePath("/package123/1.0.0/extra")).to.equal(
|
|
37
|
+
PathType.Invalid,
|
|
38
|
+
);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe("validateManifest", () => {
|
|
43
|
+
it("should return true if manifest validation passes", () => {
|
|
44
|
+
expect(validateManifest()).to.be.true;
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// it("should log an error and return false if manifest validation fails", () => {
|
|
48
|
+
// expect(validateManifest()).to.be.false;
|
|
49
|
+
// });
|
|
50
|
+
});
|
|
51
|
+
});
|
package/src/validator.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { logger } from "./logger";
|
|
2
|
+
|
|
3
|
+
const idRegex = new RegExp("^[a-zA-Z0-9\\-]+$");
|
|
4
|
+
const versionRegex = new RegExp("^[a-zA-Z0-9\\.]+$");
|
|
5
|
+
export enum PathType {
|
|
6
|
+
Root,
|
|
7
|
+
Package,
|
|
8
|
+
Version,
|
|
9
|
+
Invalid,
|
|
10
|
+
}
|
|
11
|
+
export function validatePath(path: string): PathType {
|
|
12
|
+
if (!path.startsWith("/")) {
|
|
13
|
+
return PathType.Invalid;
|
|
14
|
+
}
|
|
15
|
+
const pathParts = path.split("/");
|
|
16
|
+
if (pathParts.length === 2 && !pathParts[1]) {
|
|
17
|
+
return PathType.Root;
|
|
18
|
+
} else if (pathParts.length === 2 && idRegex.test(pathParts[1])) {
|
|
19
|
+
return PathType.Package;
|
|
20
|
+
} else if (
|
|
21
|
+
pathParts.length === 3 &&
|
|
22
|
+
idRegex.test(pathParts[1]) &&
|
|
23
|
+
versionRegex.test(pathParts[2])
|
|
24
|
+
) {
|
|
25
|
+
return PathType.Version;
|
|
26
|
+
} else {
|
|
27
|
+
return PathType.Invalid;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function validateManifest(): boolean {
|
|
32
|
+
try {
|
|
33
|
+
// const packageManifestJson = fs.readFileSync("malloy-package.json");
|
|
34
|
+
// const packageManifest = JSON.parse(packageManifestJson.toString());
|
|
35
|
+
// TODO: Validate packageManigfest.
|
|
36
|
+
return true;
|
|
37
|
+
} catch (error) {
|
|
38
|
+
let message;
|
|
39
|
+
if (error instanceof Error) message = error.message;
|
|
40
|
+
else message = String(error);
|
|
41
|
+
logger.error("Unable to open and parse manifest: " + message);
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"outDir": "dist",
|
|
4
|
+
"rootDir": "src",
|
|
5
|
+
"strict": false,
|
|
6
|
+
"target": "es6",
|
|
7
|
+
"module": "commonjs",
|
|
8
|
+
"sourceMap": true,
|
|
9
|
+
"esModuleInterop": true,
|
|
10
|
+
"moduleResolution": "node",
|
|
11
|
+
"resolveJsonModule": true
|
|
12
|
+
},
|
|
13
|
+
"include": [
|
|
14
|
+
"src/**/*"
|
|
15
|
+
],
|
|
16
|
+
"exclude": [
|
|
17
|
+
"node_modules",
|
|
18
|
+
"dist"
|
|
19
|
+
]
|
|
20
|
+
}
|