@chabokan.net/cli 0.8.9 → 0.8.15
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/README.md +25 -24
- package/dist/base.d.ts +10 -8
- package/dist/base.js +13 -10
- package/dist/commands/account/list.js +24 -15
- package/dist/commands/account/remove.js +12 -8
- package/dist/commands/account/use.js +6 -6
- package/dist/commands/deploy.d.ts +3 -2
- package/dist/commands/deploy.js +115 -70
- package/dist/commands/login.js +51 -31
- package/dist/commands/service/list.js +32 -19
- package/dist/commands/service/logs.d.ts +1 -1
- package/dist/commands/service/logs.js +23 -14
- package/dist/commands/service/resize.d.ts +1 -1
- package/dist/commands/service/resize.js +49 -31
- package/dist/commands/service/restart.d.ts +1 -1
- package/dist/commands/service/restart.js +28 -15
- package/dist/commands/service/start.d.ts +1 -1
- package/dist/commands/service/start.js +28 -15
- package/dist/commands/service/stop.d.ts +1 -1
- package/dist/commands/service/stop.js +28 -15
- package/dist/helper.d.ts +15 -8
- package/dist/helper.js +234 -38
- package/dist/types.d.ts +57 -0
- package/dist/types.js +2 -0
- package/oclif.manifest.json +1 -1
- package/package.json +106 -106
package/dist/commands/deploy.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Flags } from "@oclif/core";
|
|
|
2
2
|
import inquirer from "inquirer";
|
|
3
3
|
import chalk from "chalk";
|
|
4
4
|
import Command from "../base.js";
|
|
5
|
-
import { addIgnorePatterns, isEmptyObject } from "../helper.js";
|
|
5
|
+
import { addIgnorePatterns, isEmptyObject, handleApiError, logErrorDetails } from "../helper.js";
|
|
6
6
|
import ProgressBar from "progress";
|
|
7
7
|
import FormData from "form-data";
|
|
8
8
|
import ignore from "ignore";
|
|
@@ -23,21 +23,25 @@ export default class Deploy extends Command {
|
|
|
23
23
|
service: Flags.string({ char: "s", description: "service name" }),
|
|
24
24
|
};
|
|
25
25
|
async run() {
|
|
26
|
-
const {
|
|
26
|
+
const { flags } = await this.parse(Deploy);
|
|
27
27
|
const cli = this;
|
|
28
28
|
await this.init_run();
|
|
29
29
|
const config_json = await this.read_config();
|
|
30
30
|
let selected_service = flags.service;
|
|
31
|
-
|
|
31
|
+
const project_path = flags.path ? flags.path : process.cwd();
|
|
32
32
|
let chabok_file = { service: "" };
|
|
33
33
|
try {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
34
|
+
const chabokFilePath = path.join(project_path, "chabok.json");
|
|
35
|
+
if (fs.existsSync(chabokFilePath)) {
|
|
36
|
+
chabok_file = JSON.parse(fs.readFileSync(chabokFilePath).toString("utf-8")) || {};
|
|
37
|
+
cli.log("Reading Config from chabok.json ...");
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
catch (error) {
|
|
41
|
+
if (process.env.CHABOK_DEBUG === "true") {
|
|
42
|
+
cli.log(`Error reading chabok.json: ${error}`);
|
|
43
|
+
}
|
|
39
44
|
}
|
|
40
|
-
catch { }
|
|
41
45
|
if (chabok_file.service) {
|
|
42
46
|
selected_service = chabok_file.service;
|
|
43
47
|
}
|
|
@@ -46,12 +50,12 @@ export default class Deploy extends Command {
|
|
|
46
50
|
return;
|
|
47
51
|
}
|
|
48
52
|
if (!selected_service) {
|
|
49
|
-
|
|
53
|
+
const all_services = await this.get_services({
|
|
50
54
|
has_deploy: "true",
|
|
51
55
|
status: "on",
|
|
52
56
|
});
|
|
53
57
|
if (all_services.length > 0) {
|
|
54
|
-
|
|
58
|
+
const { service } = await inquirer.prompt({
|
|
55
59
|
type: "list",
|
|
56
60
|
message: "Please select a service:",
|
|
57
61
|
name: "service",
|
|
@@ -64,72 +68,106 @@ export default class Deploy extends Command {
|
|
|
64
68
|
return;
|
|
65
69
|
}
|
|
66
70
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
cli.log(chalk.green(upload_response.message));
|
|
71
|
+
if (!selected_service) {
|
|
72
|
+
cli.log(`${chalk.red("[Error]")} No service selected.`);
|
|
73
|
+
return;
|
|
71
74
|
}
|
|
72
|
-
|
|
73
|
-
|
|
75
|
+
try {
|
|
76
|
+
const archive_path = await this.prepare_archive(project_path);
|
|
77
|
+
const upload_response = await this.upload(archive_path, selected_service, cli, chabok_file);
|
|
78
|
+
if (upload_response.success) {
|
|
79
|
+
cli.log(chalk.green(upload_response.message));
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
cli.log(chalk.red(`[Error] ${upload_response.message}`));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
const errorInfo = handleApiError(error, 'Deployment failed. Please check your project files and try again.', {
|
|
87
|
+
endpoint: `services/${selected_service}/deploy/`,
|
|
88
|
+
serviceName: selected_service,
|
|
89
|
+
operation: 'Deploy'
|
|
90
|
+
});
|
|
91
|
+
cli.log(chalk.red(`[Error] ${errorInfo.message}`));
|
|
92
|
+
logErrorDetails(errorInfo, cli);
|
|
74
93
|
}
|
|
75
94
|
}
|
|
76
95
|
async prepare_archive(project_path) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
".idea",
|
|
81
|
-
".DS_Store",
|
|
82
|
-
".vscode",
|
|
83
|
-
"__pycache__",
|
|
84
|
-
".next",
|
|
85
|
-
".nuxt",
|
|
86
|
-
"*.*~",
|
|
87
|
-
"node_modules",
|
|
88
|
-
"bower_components",
|
|
89
|
-
"venv",
|
|
90
|
-
"/vendor",
|
|
91
|
-
"*.log",
|
|
92
|
-
];
|
|
93
|
-
const ignoreCache = {};
|
|
94
|
-
const ignoreInstance = ignore.default({ ignorecase: false });
|
|
95
|
-
ignoreInstance.add(defaultIgnores);
|
|
96
|
-
const ignoreFN = (f) => {
|
|
97
|
-
const dir = dirname(f);
|
|
98
|
-
if (!ignoreCache[dir]) {
|
|
99
|
-
addIgnorePatterns(ignoreInstance, project_path, dir);
|
|
100
|
-
ignoreCache[dir] = true;
|
|
96
|
+
try {
|
|
97
|
+
if (!fs.existsSync(project_path)) {
|
|
98
|
+
throw new Error(`Project path does not exist: ${project_path}`);
|
|
101
99
|
}
|
|
102
|
-
if (!
|
|
103
|
-
|
|
100
|
+
if (!fs.statSync(project_path).isDirectory()) {
|
|
101
|
+
throw new Error(`Project path is not a directory: ${project_path}`);
|
|
104
102
|
}
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
103
|
+
const defaultIgnores = [
|
|
104
|
+
".npm",
|
|
105
|
+
".git",
|
|
106
|
+
".idea",
|
|
107
|
+
".DS_Store",
|
|
108
|
+
".vscode",
|
|
109
|
+
"__pycache__",
|
|
110
|
+
".next",
|
|
111
|
+
".nuxt",
|
|
112
|
+
"*.*~",
|
|
113
|
+
"node_modules",
|
|
114
|
+
"bower_components",
|
|
115
|
+
"venv",
|
|
116
|
+
"/vendor",
|
|
117
|
+
"*.log",
|
|
118
|
+
];
|
|
119
|
+
const ignoreCache = {};
|
|
120
|
+
const ignoreInstance = ignore.default({ ignorecase: false });
|
|
121
|
+
ignoreInstance.add(defaultIgnores);
|
|
122
|
+
const ignoreFN = (f) => {
|
|
123
|
+
const dir = dirname(f);
|
|
124
|
+
if (!ignoreCache[dir]) {
|
|
125
|
+
addIgnorePatterns(ignoreInstance, project_path, dir);
|
|
126
|
+
ignoreCache[dir] = true;
|
|
127
|
+
}
|
|
128
|
+
if (!ignoreInstance.ignores(f)) {
|
|
129
|
+
return true;
|
|
130
|
+
}
|
|
131
|
+
if (process.env.CHABOK_DEBUG === "true") {
|
|
132
|
+
console.log(`ignoring ${f}`);
|
|
133
|
+
}
|
|
134
|
+
return false;
|
|
135
|
+
};
|
|
136
|
+
const tmpDir = path.join(os.tmpdir(), "/chabok-cli");
|
|
137
|
+
const archivePath = path.join(tmpDir, `${Date.now()}.tar.gz`);
|
|
138
|
+
fs.ensureDirSync(tmpDir);
|
|
139
|
+
const fileList = fs.readdirSync(project_path).filter(ignoreFN);
|
|
140
|
+
if (fileList.length === 0) {
|
|
141
|
+
throw new Error(`No files to archive in ${project_path}. The directory may be empty or all files are ignored.`);
|
|
142
|
+
}
|
|
143
|
+
tar.c({
|
|
144
|
+
gzip: {
|
|
145
|
+
level: 9,
|
|
146
|
+
},
|
|
147
|
+
sync: true,
|
|
148
|
+
cwd: project_path,
|
|
149
|
+
filter: ignoreFN,
|
|
150
|
+
file: archivePath,
|
|
151
|
+
}, fileList);
|
|
152
|
+
return archivePath;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
if (error instanceof Error) {
|
|
156
|
+
throw new Error(`Failed to prepare archive: ${error.message}`);
|
|
157
|
+
}
|
|
158
|
+
throw new Error('Failed to prepare archive: Unknown error');
|
|
159
|
+
}
|
|
122
160
|
}
|
|
123
161
|
async upload(archive_path, selected_service, cli, chabok_file) {
|
|
124
|
-
|
|
162
|
+
const upload_response = {
|
|
125
163
|
success: false,
|
|
126
164
|
message: "some problem",
|
|
127
165
|
};
|
|
128
166
|
const body = new FormData();
|
|
129
|
-
// @ts-ignore
|
|
130
167
|
body.append("file", fs.createReadStream(archive_path));
|
|
131
168
|
body.append("options", JSON.stringify(chabok_file));
|
|
132
|
-
const
|
|
169
|
+
const stats = fs.statSync(archive_path);
|
|
170
|
+
const sourceSize = stats.size;
|
|
133
171
|
if (sourceSize > MAX_SOURCE_SIZE) {
|
|
134
172
|
upload_response.message = "Source is too large. (max: 100MB)";
|
|
135
173
|
return upload_response;
|
|
@@ -150,24 +188,31 @@ export default class Deploy extends Command {
|
|
|
150
188
|
.json();
|
|
151
189
|
if (response.success) {
|
|
152
190
|
upload_response.success = true;
|
|
153
|
-
upload_response.message =
|
|
191
|
+
upload_response.message = `Deployment to service '${selected_service}' finished successfully.`;
|
|
154
192
|
}
|
|
155
193
|
else {
|
|
156
|
-
|
|
157
|
-
|
|
194
|
+
upload_response.message = `Deployment failed: ${String(response.message || "Unknown error occurred. Please try again.")}`;
|
|
195
|
+
if (process.env.CHABOK_DEBUG === "true") {
|
|
196
|
+
cli.log(JSON.stringify(response, null, 2));
|
|
158
197
|
}
|
|
159
198
|
}
|
|
160
199
|
return upload_response;
|
|
161
200
|
}
|
|
162
201
|
catch (error) {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
202
|
+
const errorInfo = handleApiError(error, 'Deployment failed. Please check your project files and network connection.', {
|
|
203
|
+
endpoint: `services/${selected_service}/deploy/`,
|
|
204
|
+
serviceName: selected_service,
|
|
205
|
+
operation: 'Upload Deployment'
|
|
206
|
+
});
|
|
207
|
+
upload_response.message = errorInfo.message;
|
|
208
|
+
logErrorDetails(errorInfo, cli);
|
|
166
209
|
return upload_response;
|
|
167
210
|
}
|
|
168
211
|
finally {
|
|
169
212
|
// cleanup
|
|
170
|
-
fs.unlink(archive_path).catch(() => {
|
|
213
|
+
fs.unlink(archive_path).catch(() => {
|
|
214
|
+
// Ignore cleanup errors
|
|
215
|
+
});
|
|
171
216
|
}
|
|
172
217
|
}
|
|
173
218
|
}
|
package/dist/commands/login.js
CHANGED
|
@@ -2,7 +2,7 @@ import { Flags } from '@oclif/core';
|
|
|
2
2
|
import inquirer from 'inquirer';
|
|
3
3
|
import axios from "axios";
|
|
4
4
|
import chalk from "chalk";
|
|
5
|
-
import { isObject } from "../helper.js";
|
|
5
|
+
import { isObject, handleApiError, logErrorDetails } from "../helper.js";
|
|
6
6
|
import Command from "../base.js";
|
|
7
7
|
export default class Login extends Command {
|
|
8
8
|
static description = 'login to hub.chabokan.net account';
|
|
@@ -13,20 +13,23 @@ export default class Login extends Command {
|
|
|
13
13
|
token: Flags.string({ char: 't', description: 'login with api token' }),
|
|
14
14
|
};
|
|
15
15
|
async run() {
|
|
16
|
-
const {
|
|
16
|
+
const { flags } = await this.parse(Login);
|
|
17
17
|
const cli = this;
|
|
18
18
|
await this.init_run();
|
|
19
19
|
const config_json = await this.read_config();
|
|
20
|
-
const body = {
|
|
20
|
+
const body = {
|
|
21
|
+
username: flags.username,
|
|
22
|
+
password: flags.password
|
|
23
|
+
};
|
|
21
24
|
if (!flags.token) {
|
|
22
25
|
if (!flags.username) {
|
|
23
|
-
|
|
26
|
+
const { username } = await inquirer.prompt({
|
|
24
27
|
type: 'input',
|
|
25
28
|
message: 'Enter your username:',
|
|
26
29
|
name: 'username',
|
|
27
30
|
validate(input) {
|
|
28
31
|
if (input.length === 0) {
|
|
29
|
-
return
|
|
32
|
+
return 'Username cannot be empty';
|
|
30
33
|
}
|
|
31
34
|
return true;
|
|
32
35
|
}
|
|
@@ -34,57 +37,74 @@ export default class Login extends Command {
|
|
|
34
37
|
body.username = username;
|
|
35
38
|
}
|
|
36
39
|
if (!flags.password) {
|
|
37
|
-
|
|
40
|
+
const { password } = await inquirer.prompt({
|
|
38
41
|
type: 'password',
|
|
39
42
|
name: 'password',
|
|
40
43
|
message: 'Enter your password:',
|
|
41
44
|
validate(input) {
|
|
42
45
|
if (input.length === 0) {
|
|
43
|
-
return
|
|
46
|
+
return 'Password cannot be empty';
|
|
44
47
|
}
|
|
45
48
|
return true;
|
|
46
49
|
}
|
|
47
50
|
});
|
|
48
51
|
body.password = password;
|
|
49
52
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
53
|
+
if (!body.username || !body.password) {
|
|
54
|
+
cli.log(`${chalk.red('[Error]')} Username and password are required!`);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const { data } = await axios.post("accounts/login/", body, this.axiosConfig);
|
|
59
|
+
if (data.success && data.token) {
|
|
60
|
+
if (!isObject(config_json.users)) {
|
|
61
|
+
config_json.users = {};
|
|
62
|
+
}
|
|
63
|
+
config_json.users[body.username] = {
|
|
64
|
+
token: data.token
|
|
65
|
+
};
|
|
66
|
+
config_json.default_user = body.username;
|
|
67
|
+
await this.write_config(config_json);
|
|
68
|
+
cli.log(`${chalk.green('[Success]')} You are logged in successfully as '${body.username}'.`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
cli.log(`${chalk.red('[Error]')} Login failed: Invalid username or password. Please check your credentials and try again.`);
|
|
54
72
|
}
|
|
55
|
-
// @ts-ignore
|
|
56
|
-
config_json.users[body.username] = {
|
|
57
|
-
"token": data.token
|
|
58
|
-
};
|
|
59
|
-
config_json["default_user"] = body.username;
|
|
60
|
-
this.write_config(config_json);
|
|
61
|
-
cli.log(`${chalk.green('[Success]')} you are logged in successfully.`);
|
|
62
73
|
}
|
|
63
|
-
|
|
64
|
-
|
|
74
|
+
catch (error) {
|
|
75
|
+
const errorInfo = handleApiError(error, 'Login failed. Please check your credentials and try again.', {
|
|
76
|
+
endpoint: 'accounts/login/',
|
|
77
|
+
operation: 'Login'
|
|
78
|
+
});
|
|
79
|
+
cli.log(`${chalk.red('[Error]')} ${errorInfo.message}`);
|
|
80
|
+
logErrorDetails(errorInfo, cli);
|
|
65
81
|
}
|
|
66
82
|
}
|
|
67
83
|
else {
|
|
68
84
|
try {
|
|
85
|
+
if (!this.axiosConfig.headers) {
|
|
86
|
+
this.axiosConfig.headers = {};
|
|
87
|
+
}
|
|
69
88
|
this.axiosConfig.headers.Authorization = `Token ${flags.token}`;
|
|
70
89
|
const { data } = await axios.get("accounts/info/", this.axiosConfig);
|
|
71
90
|
if (!isObject(config_json.users)) {
|
|
72
91
|
config_json.users = {};
|
|
73
92
|
}
|
|
74
|
-
|
|
75
|
-
config_json.users[
|
|
76
|
-
|
|
93
|
+
const email = data.user.email;
|
|
94
|
+
config_json.users[email] = {
|
|
95
|
+
token: flags.token
|
|
77
96
|
};
|
|
78
|
-
config_json
|
|
97
|
+
config_json.default_user = email;
|
|
79
98
|
await this.write_config(config_json);
|
|
80
|
-
cli.log(`${chalk.green('[Success]')}
|
|
99
|
+
cli.log(`${chalk.green('[Success]')} You are logged in successfully as '${email}' using API token.`);
|
|
81
100
|
}
|
|
82
|
-
catch (
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
cli.log(`${chalk.red('[Error]')}
|
|
101
|
+
catch (error) {
|
|
102
|
+
const errorInfo = handleApiError(error, 'Invalid API token. Please verify your token and try again.', {
|
|
103
|
+
endpoint: 'accounts/info/',
|
|
104
|
+
operation: 'Token Login'
|
|
105
|
+
});
|
|
106
|
+
cli.log(`${chalk.red('[Error]')} ${errorInfo.message}`);
|
|
107
|
+
logErrorDetails(errorInfo, cli);
|
|
88
108
|
}
|
|
89
109
|
}
|
|
90
110
|
}
|
|
@@ -1,32 +1,45 @@
|
|
|
1
1
|
import Command from "../../base.js";
|
|
2
2
|
import { ux } from "@oclif/core";
|
|
3
|
+
import chalk from "chalk";
|
|
4
|
+
import { isEmptyObject, handleApiError, logErrorDetails } from "../../helper.js";
|
|
3
5
|
export default class ServiceList extends Command {
|
|
4
6
|
static description = "show account services list";
|
|
5
7
|
static flags = {
|
|
6
8
|
...Command.flags,
|
|
7
9
|
};
|
|
8
10
|
async run() {
|
|
9
|
-
const {
|
|
11
|
+
const { flags } = await this.parse(ServiceList);
|
|
10
12
|
const cli = this;
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
13
|
+
try {
|
|
14
|
+
await this.init_run();
|
|
15
|
+
const config_json = await this.read_config();
|
|
16
|
+
if (isEmptyObject(config_json.users)) {
|
|
17
|
+
cli.log(`${chalk.red('[Error]')} Please login first using 'chabok login'.`);
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const all_services = await this.get_services();
|
|
21
|
+
if (all_services.length > 0) {
|
|
22
|
+
const services_data = all_services.map((service) => {
|
|
23
|
+
return {
|
|
24
|
+
Name: service.name,
|
|
25
|
+
};
|
|
26
|
+
});
|
|
27
|
+
ux.table(services_data, {
|
|
28
|
+
Name: {},
|
|
29
|
+
}, flags);
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
cli.log(`${chalk.yellow('[Info]')} No services found. Please create a service first.`);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
26
35
|
}
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
36
|
+
catch (error) {
|
|
37
|
+
const errorInfo = handleApiError(error, 'Failed to fetch services list.', {
|
|
38
|
+
endpoint: 'services/',
|
|
39
|
+
operation: 'List Services'
|
|
40
|
+
});
|
|
41
|
+
cli.log(`${chalk.red('[Error]')} ${errorInfo.message}`);
|
|
42
|
+
logErrorDetails(errorInfo, cli);
|
|
30
43
|
}
|
|
31
44
|
}
|
|
32
45
|
}
|
|
@@ -6,5 +6,5 @@ export default class ServiceLogs extends Command {
|
|
|
6
6
|
help: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<void>;
|
|
7
7
|
};
|
|
8
8
|
run(): Promise<void>;
|
|
9
|
-
send_request(cli:
|
|
9
|
+
send_request(cli: Command, selected_service: string): Promise<void>;
|
|
10
10
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Flags } from '@oclif/core';
|
|
2
2
|
import Command from "../../base.js";
|
|
3
|
-
import { isEmptyObject } from "../../helper.js";
|
|
3
|
+
import { isEmptyObject, handleApiError, logErrorDetails } from "../../helper.js";
|
|
4
4
|
import chalk from "chalk";
|
|
5
5
|
import inquirer from 'inquirer';
|
|
6
6
|
import axios from "axios";
|
|
@@ -11,7 +11,7 @@ export default class ServiceLogs extends Command {
|
|
|
11
11
|
service: Flags.string({ char: 's', description: 'service name' }),
|
|
12
12
|
};
|
|
13
13
|
async run() {
|
|
14
|
-
const {
|
|
14
|
+
const { flags } = await this.parse(ServiceLogs);
|
|
15
15
|
const cli = this;
|
|
16
16
|
await this.init_run();
|
|
17
17
|
const config_json = await this.read_config();
|
|
@@ -21,9 +21,9 @@ export default class ServiceLogs extends Command {
|
|
|
21
21
|
return;
|
|
22
22
|
}
|
|
23
23
|
if (!flags.service) {
|
|
24
|
-
|
|
24
|
+
const all_services = await this.get_services();
|
|
25
25
|
if (all_services.length > 0) {
|
|
26
|
-
|
|
26
|
+
const { service } = await inquirer.prompt({
|
|
27
27
|
type: 'list',
|
|
28
28
|
message: 'Please select a service:',
|
|
29
29
|
name: 'service',
|
|
@@ -36,24 +36,33 @@ export default class ServiceLogs extends Command {
|
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
if (selected_service) {
|
|
40
|
+
await this.send_request(cli, selected_service);
|
|
41
|
+
}
|
|
40
42
|
}
|
|
41
43
|
async send_request(cli, selected_service) {
|
|
42
44
|
try {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
45
|
+
const { data } = await axios.get(`services/${selected_service}/logs/`, this.axiosConfig);
|
|
46
|
+
if (data.success && data.logs) {
|
|
47
|
+
cli.log(data.logs);
|
|
48
|
+
}
|
|
49
|
+
else {
|
|
50
|
+
cli.log(`${chalk.yellow('[Warning]')} No logs available for service '${selected_service}'. The service may not have generated any logs yet.`);
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
|
-
catch (
|
|
51
|
-
|
|
52
|
-
|
|
53
|
+
catch (error) {
|
|
54
|
+
const errorInfo = handleApiError(error, 'Failed to fetch service logs.', {
|
|
55
|
+
endpoint: `services/${selected_service}/logs/`,
|
|
56
|
+
serviceName: selected_service,
|
|
57
|
+
operation: 'Fetch Logs'
|
|
58
|
+
});
|
|
59
|
+
if (errorInfo.status === 404) {
|
|
60
|
+
cli.log(`${chalk.red('[Error]')} Service '${selected_service}' not found. Please verify the service name using 'chabok service list' and try again.`);
|
|
53
61
|
}
|
|
54
62
|
else {
|
|
55
|
-
|
|
63
|
+
cli.log(`${chalk.red('[Error]')} ${errorInfo.message}`);
|
|
56
64
|
}
|
|
65
|
+
logErrorDetails(errorInfo, cli);
|
|
57
66
|
}
|
|
58
67
|
}
|
|
59
68
|
}
|
|
@@ -9,5 +9,5 @@ export default class ServiceResize extends Command {
|
|
|
9
9
|
help: import("@oclif/core/lib/interfaces/parser.js").BooleanFlag<void>;
|
|
10
10
|
};
|
|
11
11
|
run(): Promise<void>;
|
|
12
|
-
send_request(cli:
|
|
12
|
+
send_request(cli: Command, selected_service: string, ram: string, cpu: string, disk: string): Promise<void>;
|
|
13
13
|
}
|