bdy 1.16.15-dev → 1.16.17-dev
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/distTs/package.json +2 -1
- package/distTs/src/api/client.js +107 -14
- package/distTs/src/command/login.js +111 -46
- package/distTs/src/command/package/download.js +259 -0
- package/distTs/src/command/package/list.js +35 -0
- package/distTs/src/command/package/publish.js +231 -0
- package/distTs/src/command/package.js +16 -0
- package/distTs/src/command/pipeline/run.js +3 -3
- package/distTs/src/command/project/set.js +1 -1
- package/distTs/src/index.js +2 -0
- package/distTs/src/input.js +24 -2
- package/distTs/src/texts.js +69 -22
- package/distTs/src/tunnel/cfg.js +17 -0
- package/distTs/src/tunnel/server/http1.js +11 -6
- package/distTs/src/tunnel/server/http2.js +14 -6
- package/package.json +2 -1
package/distTs/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bdy",
|
|
3
3
|
"preferGlobal": false,
|
|
4
|
-
"version": "1.16.
|
|
4
|
+
"version": "1.16.17-dev",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"scripts": {
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"eventsource": "4.0.0",
|
|
32
32
|
"fastify": "4.28.1",
|
|
33
33
|
"fdir": "6.5.0",
|
|
34
|
+
"open": "11.0.0",
|
|
34
35
|
"fflate": "0.8.2",
|
|
35
36
|
"human-id": "^4.1.3",
|
|
36
37
|
"isbinaryfile": "5.0.2",
|
package/distTs/src/api/client.js
CHANGED
|
@@ -21,18 +21,24 @@ class ApiClient {
|
|
|
21
21
|
},
|
|
22
22
|
});
|
|
23
23
|
}
|
|
24
|
-
async request(method, path, body, parseResponseBody = false, rawResponseBody = false) {
|
|
25
|
-
const headers = {
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
async request(method, path, body, parseResponseBody = false, rawResponseBody = false, httpUrlEncoded = false) {
|
|
25
|
+
const headers = {};
|
|
26
|
+
if (this.token)
|
|
27
|
+
headers.authorization = `Bearer ${this.token}`;
|
|
28
28
|
let bodyParsed = undefined;
|
|
29
29
|
if (body) {
|
|
30
30
|
if (body instanceof undici_1.FormData) {
|
|
31
31
|
bodyParsed = body;
|
|
32
32
|
}
|
|
33
33
|
else {
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
if (httpUrlEncoded) {
|
|
35
|
+
headers['content-type'] = 'application/x-www-form-urlencoded; charset=utf-8';
|
|
36
|
+
bodyParsed = new URLSearchParams(body).toString();
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
headers['content-type'] = 'application/json; charset=utf-8';
|
|
40
|
+
bodyParsed = JSON.stringify(body);
|
|
41
|
+
}
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
44
|
const opts = {
|
|
@@ -45,7 +51,7 @@ class ApiClient {
|
|
|
45
51
|
let responseBody;
|
|
46
52
|
logger_1.default.debug(`API CLIENT: ${method} ${this.baseUrl.protocol}//${this.baseUrl.host}${path}`);
|
|
47
53
|
logger_1.default.debug(headers);
|
|
48
|
-
logger_1.default.debug(
|
|
54
|
+
logger_1.default.debug(bodyParsed);
|
|
49
55
|
try {
|
|
50
56
|
const r = await this.client.request(opts);
|
|
51
57
|
status = r.statusCode;
|
|
@@ -101,7 +107,7 @@ class ApiClient {
|
|
|
101
107
|
else
|
|
102
108
|
throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
|
|
103
109
|
}
|
|
104
|
-
if (
|
|
110
|
+
if ([200, 201].includes(status)) {
|
|
105
111
|
if (parseResponseBody) {
|
|
106
112
|
try {
|
|
107
113
|
const b = await responseBody.json();
|
|
@@ -132,9 +138,6 @@ class ApiClient {
|
|
|
132
138
|
throw new Error(texts_1.ERR_REST_API_GENERAL_ERROR);
|
|
133
139
|
}
|
|
134
140
|
}
|
|
135
|
-
async getPipelineByIdentifier(workspace, project, identifier) {
|
|
136
|
-
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/identifiers?project=${encodeURIComponent(project)}&pipeline=${encodeURIComponent(identifier)}`, null, true);
|
|
137
|
-
}
|
|
138
141
|
async getPipelineRun(workspace, project, pipelineId, executionId) {
|
|
139
142
|
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/projects/${encodeURIComponent(project)}/pipelines/${encodeURIComponent(pipelineId)}/executions/${encodeURIComponent(executionId)}`, null, true);
|
|
140
143
|
}
|
|
@@ -172,6 +175,28 @@ class ApiClient {
|
|
|
172
175
|
async stopSandbox(workspace, sandboxId) {
|
|
173
176
|
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/stop`, {}, true);
|
|
174
177
|
}
|
|
178
|
+
async registerApp(name, redirectUrl) {
|
|
179
|
+
return await this.request('POST', '/auth/register', {
|
|
180
|
+
redirect_uris: [redirectUrl],
|
|
181
|
+
client_name: name,
|
|
182
|
+
grant_types: ['authorization_code', 'refresh_token'],
|
|
183
|
+
response_types: ['code'],
|
|
184
|
+
token_endpoint_auth_method: "client_secret_basic",
|
|
185
|
+
token_expires_in: 3600
|
|
186
|
+
}, true);
|
|
187
|
+
}
|
|
188
|
+
async getApp(clientId) {
|
|
189
|
+
return await this.request('GET', `/auth/register/${encodeURIComponent(clientId)}`, null, true);
|
|
190
|
+
}
|
|
191
|
+
async exchangeAppToken(code, clientId, clientSecret, redirectUrl) {
|
|
192
|
+
return await this.request('POST', '/oauth2/token', {
|
|
193
|
+
grant_type: 'authorization_code',
|
|
194
|
+
code,
|
|
195
|
+
client_id: clientId,
|
|
196
|
+
client_secret: clientSecret,
|
|
197
|
+
redirect_uri: redirectUrl
|
|
198
|
+
}, true, false, true);
|
|
199
|
+
}
|
|
175
200
|
async restartSandbox(workspace, sandboxId) {
|
|
176
201
|
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/restart`, {}, true);
|
|
177
202
|
}
|
|
@@ -184,9 +209,6 @@ class ApiClient {
|
|
|
184
209
|
async listSandboxCommands(workspace, sandboxId) {
|
|
185
210
|
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands`, null, true);
|
|
186
211
|
}
|
|
187
|
-
async getSandboxCommandLogsUrl(workspace, sandboxId, commandId) {
|
|
188
|
-
return `${this.baseUrl.origin}/workspaces/${encodeURIComponent(workspace)}/sandboxes/${encodeURIComponent(sandboxId)}/commands/${encodeURIComponent(commandId)}/logs`;
|
|
189
|
-
}
|
|
190
212
|
async streamSandboxCommandLogs(workspace, sandboxId, commandId, follow = true) {
|
|
191
213
|
let q = '';
|
|
192
214
|
if (follow)
|
|
@@ -280,8 +302,79 @@ class ApiClient {
|
|
|
280
302
|
async getWorkspaces() {
|
|
281
303
|
return await this.request('GET', '/workspaces', null, true);
|
|
282
304
|
}
|
|
305
|
+
async getPackages(workspace, project) {
|
|
306
|
+
let query = '';
|
|
307
|
+
if (project)
|
|
308
|
+
query += `?project_name=${encodeURIComponent(project)}`;
|
|
309
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages${query}`, null, true);
|
|
310
|
+
}
|
|
283
311
|
async getProjects(workspace) {
|
|
284
312
|
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/projects`, null, true);
|
|
285
313
|
}
|
|
314
|
+
async getResourceByIdentifier(workspace, params) {
|
|
315
|
+
let query = '';
|
|
316
|
+
Object.keys(params).forEach((key) => {
|
|
317
|
+
if (!query)
|
|
318
|
+
query += '?';
|
|
319
|
+
else
|
|
320
|
+
query += '&';
|
|
321
|
+
query += encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
|
|
322
|
+
});
|
|
323
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/identifiers${query}`, null, true);
|
|
324
|
+
}
|
|
325
|
+
async getPipelineByIdentifier(workspace, project, identifier) {
|
|
326
|
+
return await this.getResourceByIdentifier(workspace, { project, pipeline: identifier });
|
|
327
|
+
}
|
|
328
|
+
async getPackageVersionByIdentifier(workspace, project, pkg, version) {
|
|
329
|
+
const opts = {
|
|
330
|
+
package: pkg,
|
|
331
|
+
};
|
|
332
|
+
if (project)
|
|
333
|
+
opts.project = project;
|
|
334
|
+
if (version)
|
|
335
|
+
opts.package_version = version;
|
|
336
|
+
return await this.getResourceByIdentifier(workspace, opts);
|
|
337
|
+
}
|
|
338
|
+
async getPackageVersion(workspace, pkgId, versionId) {
|
|
339
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions/${encodeURIComponent(versionId)}`, null, true);
|
|
340
|
+
}
|
|
341
|
+
async getPackageLatest(workspace, pkgId) {
|
|
342
|
+
const res = await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions?page=1&per_page=1`, null, true);
|
|
343
|
+
if (res && res.versions && res.versions.length > 0) {
|
|
344
|
+
return res.versions[0];
|
|
345
|
+
}
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
async downloadPackageVersion(workspace, pkgId, versionId) {
|
|
349
|
+
return await this.request('GET', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions/${encodeURIComponent(versionId)}/download`, null, false, true);
|
|
350
|
+
}
|
|
351
|
+
async postPackageVersion(workspace, pkgId, version) {
|
|
352
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions`, {
|
|
353
|
+
version
|
|
354
|
+
}, true);
|
|
355
|
+
}
|
|
356
|
+
async postPackageVersionZip(workspace, pkgId, versionId, file) {
|
|
357
|
+
const form = new undici_1.FormData();
|
|
358
|
+
form.append('file', file);
|
|
359
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/packages/${encodeURIComponent(pkgId)}/versions/${versionId}/upload`, form, true);
|
|
360
|
+
}
|
|
361
|
+
async postPackage(workspace, project, identifier) {
|
|
362
|
+
const body = {
|
|
363
|
+
name: identifier,
|
|
364
|
+
identifier,
|
|
365
|
+
type: 'FILE',
|
|
366
|
+
scope: 'WORKSPACE',
|
|
367
|
+
authorization: {
|
|
368
|
+
type: 'BUDDY'
|
|
369
|
+
}
|
|
370
|
+
};
|
|
371
|
+
if (project) {
|
|
372
|
+
body.project = {
|
|
373
|
+
name: project
|
|
374
|
+
};
|
|
375
|
+
body.scope = 'PROJECT';
|
|
376
|
+
}
|
|
377
|
+
return await this.request('POST', `/workspaces/${encodeURIComponent(workspace)}/packages`, body, true);
|
|
378
|
+
}
|
|
286
379
|
}
|
|
287
380
|
exports.default = ApiClient;
|
|
@@ -6,21 +6,15 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const cfg_1 = __importDefault(require("../tunnel/cfg"));
|
|
7
7
|
const output_1 = __importDefault(require("../output"));
|
|
8
8
|
const client_1 = __importDefault(require("../api/client"));
|
|
9
|
+
const node_http_1 = __importDefault(require("node:http"));
|
|
10
|
+
const open_1 = __importDefault(require("open"));
|
|
9
11
|
const texts_1 = require("../texts");
|
|
10
12
|
const utils_1 = require("../utils");
|
|
11
13
|
const input_1 = __importDefault(require("../input"));
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
case utils_1.REST_API_REGION.EU:
|
|
17
|
-
return 'https://eu.buddy.works/security';
|
|
18
|
-
case utils_1.REST_API_REGION.AS:
|
|
19
|
-
return 'https://asia.buddy.works/security';
|
|
20
|
-
default:
|
|
21
|
-
return `https://${baseUrl}/security`;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
14
|
+
const OAUTH_CLIENT_APP_PORT = 7596;
|
|
15
|
+
const OAUTH_CLIENT_APP_HOST = 'localhost';
|
|
16
|
+
const OAUTH_CLIENT_APP_REDIRECT_URL = `http://localhost:${OAUTH_CLIENT_APP_PORT}`;
|
|
17
|
+
const OAUTH_CLIENT_APP_SCOPES = 'WORKSPACE USER_INFO EXECUTION_MANAGE SANDBOX_MANAGE PACKAGE_MANAGE';
|
|
24
18
|
function normalizeBaseUrl(url) {
|
|
25
19
|
let normalized = url.trim();
|
|
26
20
|
normalized = normalized.replace(/^https?:\/\//i, '');
|
|
@@ -52,10 +46,104 @@ async function restApiBaseUrl() {
|
|
|
52
46
|
}
|
|
53
47
|
return `${normalized}/api`;
|
|
54
48
|
}
|
|
55
|
-
async function
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
49
|
+
async function oauthServer(api, clientId, clientSecret) {
|
|
50
|
+
return new Promise((resolve, reject) => {
|
|
51
|
+
const s = node_http_1.default.createServer(async (req, res) => {
|
|
52
|
+
const url = new URL(req.url || '', `http://${OAUTH_CLIENT_APP_HOST}`);
|
|
53
|
+
const urlCode = url.searchParams.get('code');
|
|
54
|
+
if (!urlCode) {
|
|
55
|
+
res.end(texts_1.ERR_LOGIN_HTTP_FAILED);
|
|
56
|
+
s.close();
|
|
57
|
+
reject(new Error(texts_1.ERR_LOGIN_HTTP_FAILED));
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
const client = new client_1.default(new URL(`https://${api}`));
|
|
61
|
+
try {
|
|
62
|
+
const response = await client.exchangeAppToken(urlCode, clientId, clientSecret, OAUTH_CLIENT_APP_REDIRECT_URL);
|
|
63
|
+
res.end(texts_1.ERR_LOGIN_HTTP_SUCCESS);
|
|
64
|
+
s.close();
|
|
65
|
+
resolve(response.access_token);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
res.end(texts_1.ERR_LOGIN_HTTP_FAILED);
|
|
69
|
+
s.close();
|
|
70
|
+
reject(new Error(texts_1.ERR_LOGIN_HTTP_FAILED));
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
s.on('error', () => {
|
|
75
|
+
s.close();
|
|
76
|
+
reject(texts_1.ERR_LOGIN_HTTP_SERVER_PORT_TAKEN);
|
|
77
|
+
});
|
|
78
|
+
s.listen(OAUTH_CLIENT_APP_PORT, OAUTH_CLIENT_APP_HOST);
|
|
79
|
+
const url = `https://${api}/oauth2/authorize?type=web_server&client_id=${encodeURIComponent(clientId)}&redirect_uri=${encodeURIComponent(OAUTH_CLIENT_APP_REDIRECT_URL)}&response_type=code&scope=${encodeURIComponent(OAUTH_CLIENT_APP_SCOPES)}`;
|
|
80
|
+
(0, open_1.default)(url);
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
async function getOrCreateApp(api) {
|
|
84
|
+
const client = new client_1.default(new URL(`https://${api}`));
|
|
85
|
+
let clientId = cfg_1.default.getApiClientId();
|
|
86
|
+
let clientSecret = cfg_1.default.getApiClientSecret();
|
|
87
|
+
if (clientId && clientSecret) {
|
|
88
|
+
let clear = false;
|
|
89
|
+
try {
|
|
90
|
+
const app = await client.getApp(clientId);
|
|
91
|
+
if (!app || !app.redirect_uris || !app.redirect_uris.includes(OAUTH_CLIENT_APP_REDIRECT_URL)) {
|
|
92
|
+
clear = true;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
clear = true;
|
|
97
|
+
}
|
|
98
|
+
if (clear) {
|
|
99
|
+
clientId = null;
|
|
100
|
+
clientSecret = null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (!clientId || !clientSecret) {
|
|
104
|
+
const app = await client.registerApp('bdy cli app', OAUTH_CLIENT_APP_REDIRECT_URL);
|
|
105
|
+
clientId = app.client_id;
|
|
106
|
+
clientSecret = app.client_secret;
|
|
107
|
+
cfg_1.default.setApiClient(clientId, clientSecret);
|
|
108
|
+
}
|
|
109
|
+
return {
|
|
110
|
+
clientId,
|
|
111
|
+
clientSecret,
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
async function authorizeOAuth(api) {
|
|
115
|
+
const { clientId, clientSecret } = await getOrCreateApp(api);
|
|
116
|
+
return await oauthServer(api, clientId, clientSecret);
|
|
117
|
+
}
|
|
118
|
+
async function authorizeToken(api, token, workspace, project) {
|
|
119
|
+
const client = new client_1.default(new URL(`https://${api}`), token);
|
|
120
|
+
const w = await client.getWorkspaces();
|
|
121
|
+
if (!w.workspaces?.length) {
|
|
122
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
|
|
123
|
+
}
|
|
124
|
+
if (workspace) {
|
|
125
|
+
const found = w.workspaces.find((w) => w.domain === workspace);
|
|
126
|
+
if (!found) {
|
|
127
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACE_FOUND);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
workspace = await output_1.default.selectWorkspace(w.workspaces);
|
|
132
|
+
}
|
|
133
|
+
cfg_1.default.setApiToken(token);
|
|
134
|
+
cfg_1.default.setWorkspace(workspace);
|
|
135
|
+
const p = await client.getProjects(workspace);
|
|
136
|
+
if (project) {
|
|
137
|
+
const found = p.projects.find((p) => p.name === project);
|
|
138
|
+
if (!found) {
|
|
139
|
+
output_1.default.exitError(texts_1.ERR_LOGIN_NO_PROJECT_FOUND);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
project = await output_1.default.selectProject(p.projects);
|
|
144
|
+
}
|
|
145
|
+
cfg_1.default.setProject(project);
|
|
146
|
+
output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
|
|
59
147
|
}
|
|
60
148
|
const commandLogin = (0, utils_1.newCommand)('login', texts_1.DESC_COMMAND_LOGIN);
|
|
61
149
|
commandLogin.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
|
|
@@ -68,9 +156,9 @@ commandLogin.action(async (options) => {
|
|
|
68
156
|
cfg_1.default.clearLogin();
|
|
69
157
|
let api = options.api || process.env.BUDDY_API_ENDPOINT;
|
|
70
158
|
let region = options.region || process.env.BUDDY_REGION;
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
159
|
+
const token = options.token || process.env.BUDDY_TOKEN;
|
|
160
|
+
const workspace = options.workspace || process.env.BUDDY_WORKSPACE;
|
|
161
|
+
const project = options.project || process.env.BUDDY_PROJECT;
|
|
74
162
|
if (api) {
|
|
75
163
|
region = utils_1.REST_API_REGION.ONPREM;
|
|
76
164
|
}
|
|
@@ -96,35 +184,12 @@ commandLogin.action(async (options) => {
|
|
|
96
184
|
}
|
|
97
185
|
cfg_1.default.setBaseUrl(api);
|
|
98
186
|
if (!token) {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
const w = await client.getWorkspaces();
|
|
103
|
-
if (!w.workspaces?.length) {
|
|
104
|
-
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACES);
|
|
105
|
-
}
|
|
106
|
-
if (workspace) {
|
|
107
|
-
const found = w.workspaces.find((w) => w.domain === workspace);
|
|
108
|
-
if (!found) {
|
|
109
|
-
output_1.default.exitError(texts_1.ERR_LOGIN_NO_WORKSPACE_FOUND);
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
workspace = await output_1.default.selectWorkspace(w.workspaces);
|
|
114
|
-
}
|
|
115
|
-
cfg_1.default.setApiToken(token);
|
|
116
|
-
cfg_1.default.setWorkspace(workspace);
|
|
117
|
-
const p = await client.getProjects(workspace);
|
|
118
|
-
if (project) {
|
|
119
|
-
const found = p.projects.find((p) => p.name === project);
|
|
120
|
-
if (!found) {
|
|
121
|
-
output_1.default.exitError(texts_1.ERR_LOGIN_NO_PROJECT_FOUND);
|
|
122
|
-
}
|
|
187
|
+
output_1.default.normal(texts_1.TXT_LOGIN_OAUTH);
|
|
188
|
+
const token = await authorizeOAuth(api);
|
|
189
|
+
await authorizeToken(api, token, workspace, project);
|
|
123
190
|
}
|
|
124
191
|
else {
|
|
125
|
-
|
|
192
|
+
await authorizeToken(api, token, workspace, project);
|
|
126
193
|
}
|
|
127
|
-
cfg_1.default.setProject(project);
|
|
128
|
-
output_1.default.exitSuccess(texts_1.TXT_LOGIN_SUCCESS);
|
|
129
194
|
});
|
|
130
195
|
exports.default = commandLogin;
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const utils_1 = require("../../utils");
|
|
7
|
+
const texts_1 = require("../../texts");
|
|
8
|
+
const input_1 = __importDefault(require("../../input"));
|
|
9
|
+
const client_1 = __importDefault(require("../../api/client"));
|
|
10
|
+
const output_1 = __importDefault(require("../../output"));
|
|
11
|
+
const logger_1 = __importDefault(require("../../logger"));
|
|
12
|
+
const path_1 = require("path");
|
|
13
|
+
const uuid_1 = require("uuid");
|
|
14
|
+
const fs_1 = __importDefault(require("fs"));
|
|
15
|
+
const promises_1 = __importDefault(require("stream/promises"));
|
|
16
|
+
const fflate_1 = require("fflate");
|
|
17
|
+
const commandPackageDownload = (0, utils_1.newCommand)('download', texts_1.DESC_COMMAND_PACKAGE_DOWNLOAD);
|
|
18
|
+
commandPackageDownload.alias('dd');
|
|
19
|
+
commandPackageDownload.option('-t, --token <token>', texts_1.OPTION_REST_API_TOKEN);
|
|
20
|
+
commandPackageDownload.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
|
|
21
|
+
commandPackageDownload.option('--region <region>', texts_1.OPTION_REST_API_REGION);
|
|
22
|
+
commandPackageDownload.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
23
|
+
commandPackageDownload.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
|
|
24
|
+
commandPackageDownload.option('-m, --merge', texts_1.OPTION_PACKAGE_DOWNLOAD_MERGE);
|
|
25
|
+
commandPackageDownload.option('-r, --replace', texts_1.OPTION_PACKAGE_DOWNLOAD_REPLACE);
|
|
26
|
+
commandPackageDownload.argument('<identifier>', texts_1.OPTION_PACKAGE_ID);
|
|
27
|
+
commandPackageDownload.argument('<directory>', texts_1.OPTION_PACKAGE_DOWNLOAD_PATH);
|
|
28
|
+
commandPackageDownload.action(async (id, path, options) => {
|
|
29
|
+
const token = input_1.default.restApiToken(options.token);
|
|
30
|
+
const baseUrl = input_1.default.restApiBaseUrl(options.api, options.region);
|
|
31
|
+
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
32
|
+
const project = input_1.default.restApiProject(options.project, true);
|
|
33
|
+
const client = new client_1.default(baseUrl, token);
|
|
34
|
+
// eslint-disable-next-line prefer-const
|
|
35
|
+
let { identifier, version } = input_1.default.packageSplitIdentifier(id);
|
|
36
|
+
const data = await client.getPackageVersionByIdentifier(workspace, project, identifier, version);
|
|
37
|
+
if (!data || !data.domain) {
|
|
38
|
+
output_1.default.exitError(texts_1.ERR_WORKSPACE_NOT_FOUND);
|
|
39
|
+
}
|
|
40
|
+
if (project && !data.project_identifier) {
|
|
41
|
+
output_1.default.exitError(texts_1.ERR_PROJECT_NOT_FOUND);
|
|
42
|
+
}
|
|
43
|
+
const packageId = data.pkg_id;
|
|
44
|
+
if (!packageId) {
|
|
45
|
+
output_1.default.exitError(texts_1.ERR_PACKAGE_DOWNLOAD_NOT_FOUND);
|
|
46
|
+
}
|
|
47
|
+
let versionId = data.pkg_version_id;
|
|
48
|
+
if (version && !versionId) {
|
|
49
|
+
output_1.default.exitError(texts_1.ERR_PACKAGE_VERSION_NOT_FOUND);
|
|
50
|
+
}
|
|
51
|
+
if (!version || !versionId) {
|
|
52
|
+
const v = await client.getPackageLatest(workspace, packageId);
|
|
53
|
+
if (!v) {
|
|
54
|
+
output_1.default.exitError(texts_1.ERR_PACKAGE_VERSION_NOT_FOUND);
|
|
55
|
+
}
|
|
56
|
+
version = v.version;
|
|
57
|
+
versionId = v.id;
|
|
58
|
+
}
|
|
59
|
+
const dirPath = (0, path_1.resolve)(path);
|
|
60
|
+
const exists = fs_1.default.existsSync(dirPath);
|
|
61
|
+
if (!exists) {
|
|
62
|
+
try {
|
|
63
|
+
fs_1.default.mkdirSync(dirPath, {
|
|
64
|
+
recursive: true,
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
catch (err) {
|
|
68
|
+
logger_1.default.error(err);
|
|
69
|
+
output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_MKDIR)(dirPath));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
else if (options.replace) {
|
|
73
|
+
try {
|
|
74
|
+
fs_1.default.rmSync(dirPath, {
|
|
75
|
+
recursive: true,
|
|
76
|
+
force: true,
|
|
77
|
+
});
|
|
78
|
+
fs_1.default.mkdirSync(dirPath, {
|
|
79
|
+
recursive: true,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
logger_1.default.error(err);
|
|
84
|
+
output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_REPLACE)(dirPath));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
const stat = fs_1.default.statSync(dirPath);
|
|
89
|
+
if (!stat.isDirectory()) {
|
|
90
|
+
output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_IS_FILE)(dirPath));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (err) {
|
|
94
|
+
logger_1.default.error(err);
|
|
95
|
+
output_1.default.exitError(texts_1.ERR_SWW);
|
|
96
|
+
}
|
|
97
|
+
let empty = true;
|
|
98
|
+
try {
|
|
99
|
+
const entries = fs_1.default.readdirSync(dirPath);
|
|
100
|
+
empty = !entries.length;
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
logger_1.default.error(err);
|
|
104
|
+
output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_READDIR)(dirPath));
|
|
105
|
+
}
|
|
106
|
+
if (!empty && !options.merge) {
|
|
107
|
+
output_1.default.exitError((0, texts_1.ERR_PACKAGE_DOWNLOAD_NOT_EMPTY_DIR)(dirPath));
|
|
108
|
+
}
|
|
109
|
+
const zipPath = (0, path_1.join)((0, utils_1.getHomeDirectory)(), `${(0, uuid_1.v4)()}.zip`);
|
|
110
|
+
const clearZip = () => {
|
|
111
|
+
try {
|
|
112
|
+
fs_1.default.rmSync(zipPath);
|
|
113
|
+
}
|
|
114
|
+
catch {
|
|
115
|
+
// do nothing
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
output_1.default.normal(texts_1.TXT_PACKAGE_DOWNLOADING_ZIP);
|
|
119
|
+
const body = await client.downloadPackageVersion(workspace, packageId, versionId);
|
|
120
|
+
try {
|
|
121
|
+
await promises_1.default.pipeline(body, fs_1.default.createWriteStream(zipPath));
|
|
122
|
+
output_1.default.clearPreviousLine();
|
|
123
|
+
output_1.default.normal(texts_1.TXT_PACKAGE_DOWNLOADED_ZIP);
|
|
124
|
+
output_1.default.normal(texts_1.TXT_PACKAGE_UNZIPPING);
|
|
125
|
+
let count = 0;
|
|
126
|
+
await unzip(dirPath, zipPath, () => {
|
|
127
|
+
count += 1;
|
|
128
|
+
output_1.default.clearPreviousLine();
|
|
129
|
+
output_1.default.normal((0, texts_1.TXT_PACKAGE_UNZIPPING_COUNT)(count));
|
|
130
|
+
});
|
|
131
|
+
clearZip();
|
|
132
|
+
output_1.default.clearPreviousLine();
|
|
133
|
+
output_1.default.normal(texts_1.TXT_PACKAGE_UNZIPPED);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
logger_1.default.error(err);
|
|
137
|
+
clearZip();
|
|
138
|
+
output_1.default.exitError(texts_1.ERR_SWW);
|
|
139
|
+
}
|
|
140
|
+
output_1.default.exitSuccess((0, texts_1.TXT_PACKAGE_DOWNLOADED)(version, dirPath));
|
|
141
|
+
});
|
|
142
|
+
const unzip = (dirPath, zipPath, onFile) => {
|
|
143
|
+
return new Promise((resolve, reject) => {
|
|
144
|
+
let _startedFiles = 0;
|
|
145
|
+
let _finishedFiles = 0;
|
|
146
|
+
let _finishedStream = false;
|
|
147
|
+
let _finishedError = null;
|
|
148
|
+
let _calledResolve = false;
|
|
149
|
+
const rs = fs_1.default.createReadStream(zipPath);
|
|
150
|
+
const _finish = () => {
|
|
151
|
+
if (_finishedError || _finishedStream) {
|
|
152
|
+
try {
|
|
153
|
+
rs.removeAllListeners();
|
|
154
|
+
rs.close();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// do nothing
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (_calledResolve)
|
|
161
|
+
return;
|
|
162
|
+
if (_finishedError) {
|
|
163
|
+
_calledResolve = true;
|
|
164
|
+
reject(_finishedError);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (_finishedStream && _startedFiles === _finishedFiles) {
|
|
168
|
+
_calledResolve = true;
|
|
169
|
+
resolve();
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
const finishFile = (err, fws) => {
|
|
173
|
+
if (!_finishedError && err)
|
|
174
|
+
_finishedError = err;
|
|
175
|
+
_finishedFiles += 1;
|
|
176
|
+
if (fws) {
|
|
177
|
+
try {
|
|
178
|
+
fws.removeAllListeners();
|
|
179
|
+
fws.close();
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
// do nothing
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
onFile();
|
|
186
|
+
_finish();
|
|
187
|
+
};
|
|
188
|
+
const finishStream = (err) => {
|
|
189
|
+
if (!_finishedError && err)
|
|
190
|
+
_finishedError = err;
|
|
191
|
+
_finishedStream = true;
|
|
192
|
+
_finish();
|
|
193
|
+
};
|
|
194
|
+
const unzip = new fflate_1.Unzip(async (file) => {
|
|
195
|
+
if (_finishedError)
|
|
196
|
+
return;
|
|
197
|
+
_startedFiles += 1;
|
|
198
|
+
const fullPath = (0, path_1.join)(dirPath, file.name);
|
|
199
|
+
const parentPath = (0, path_1.dirname)(fullPath);
|
|
200
|
+
let fws;
|
|
201
|
+
try {
|
|
202
|
+
await fs_1.default.promises.rm(fullPath, {
|
|
203
|
+
recursive: true,
|
|
204
|
+
force: true,
|
|
205
|
+
});
|
|
206
|
+
}
|
|
207
|
+
catch {
|
|
208
|
+
// do nothing
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
if (fullPath.endsWith('/')) {
|
|
212
|
+
await fs_1.default.promises.mkdir(fullPath, {
|
|
213
|
+
recursive: true,
|
|
214
|
+
});
|
|
215
|
+
finishFile();
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
await fs_1.default.promises.mkdir(parentPath, {
|
|
219
|
+
recursive: true,
|
|
220
|
+
});
|
|
221
|
+
fws = fs_1.default.createWriteStream(fullPath, {
|
|
222
|
+
flags: 'w',
|
|
223
|
+
});
|
|
224
|
+
fws.on('error', (err) => {
|
|
225
|
+
finishFile(err, fws);
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
finishFile(err, fws);
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
file.ondata = (err, data, final) => {
|
|
233
|
+
if (_finishedError)
|
|
234
|
+
return;
|
|
235
|
+
if (err)
|
|
236
|
+
finishFile(err, fws);
|
|
237
|
+
else {
|
|
238
|
+
if (fws)
|
|
239
|
+
fws.write(data);
|
|
240
|
+
if (final)
|
|
241
|
+
finishFile(null, fws);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
file.start();
|
|
245
|
+
});
|
|
246
|
+
unzip.register(fflate_1.AsyncUnzipInflate);
|
|
247
|
+
rs.on('data', (chunk) => {
|
|
248
|
+
unzip.push(chunk, false);
|
|
249
|
+
});
|
|
250
|
+
rs.on('error', (err) => {
|
|
251
|
+
finishStream(err);
|
|
252
|
+
});
|
|
253
|
+
rs.on('end', () => {
|
|
254
|
+
unzip.push(new Uint8Array(0), true);
|
|
255
|
+
finishStream();
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
};
|
|
259
|
+
exports.default = commandPackageDownload;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const output_1 = __importDefault(require("../../output"));
|
|
7
|
+
const client_1 = __importDefault(require("../../api/client"));
|
|
8
|
+
const texts_1 = require("../../texts");
|
|
9
|
+
const utils_1 = require("../../utils");
|
|
10
|
+
const input_1 = __importDefault(require("../../input"));
|
|
11
|
+
const commandPackageList = (0, utils_1.newCommand)('list', texts_1.DESC_COMMAND_PACKAGE_LIST);
|
|
12
|
+
commandPackageList.option('--token <token>', texts_1.OPTION_REST_API_TOKEN);
|
|
13
|
+
commandPackageList.option('--api <url>', texts_1.OPTION_REST_API_ENDPOINT);
|
|
14
|
+
commandPackageList.option('--region <region>', texts_1.OPTION_REST_API_REGION);
|
|
15
|
+
commandPackageList.option('-w, --workspace <domain>', texts_1.OPTION_REST_API_WORKSPACE);
|
|
16
|
+
commandPackageList.option('-p, --project <name>', texts_1.OPTION_REST_API_PROJECT);
|
|
17
|
+
commandPackageList.alias('ls');
|
|
18
|
+
commandPackageList.action(async (options) => {
|
|
19
|
+
const token = input_1.default.restApiToken(options.token);
|
|
20
|
+
const baseUrl = input_1.default.restApiBaseUrl(options.api, options.region);
|
|
21
|
+
const workspace = input_1.default.restApiWorkspace(options.workspace);
|
|
22
|
+
const project = input_1.default.restApiProject(options.project, true);
|
|
23
|
+
const client = new client_1.default(baseUrl, token);
|
|
24
|
+
const response = await client.getPackages(workspace, project);
|
|
25
|
+
if (!response.packages || response.packages.length === 0) {
|
|
26
|
+
output_1.default.exitError(texts_1.ERR_COMMAND_PACKAGE_NO_PROJECTS);
|
|
27
|
+
}
|
|
28
|
+
const data = [['NAME', 'IDENTIFIER']];
|
|
29
|
+
for (const pkg of response.packages) {
|
|
30
|
+
data.push([pkg.name, pkg.identifier]);
|
|
31
|
+
}
|
|
32
|
+
output_1.default.table(data);
|
|
33
|
+
output_1.default.exitNormal();
|
|
34
|
+
});
|
|
35
|
+
exports.default = commandPackageList;
|