eitri-cli 1.8.0 → 1.9.0-beta.2

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.
Files changed (53) hide show
  1. package/.vscode/settings.json +2 -1
  2. package/bitbucket-pipelines.yml +35 -1
  3. package/config/dev.js +1 -1
  4. package/config/k8s-eitri.js +1 -1
  5. package/config/loc-eitri.js +1 -1
  6. package/eitri-cli-v2/Cargo.lock +2500 -0
  7. package/eitri-cli-v2/Cargo.toml +21 -0
  8. package/eitri-cli-v2/README.md +119 -0
  9. package/eitri-cli-v2/index.js +2 -0
  10. package/eitri-cli-v2/index.unix.node +0 -0
  11. package/eitri-cli-v2/index.win32.node +0 -0
  12. package/eitri-cli-v2/node_modules/.yarn-integrity +16 -0
  13. package/eitri-cli-v2/node_modules/cargo-cp-artifact/LICENSE +21 -0
  14. package/eitri-cli-v2/node_modules/cargo-cp-artifact/README.md +93 -0
  15. package/eitri-cli-v2/node_modules/cargo-cp-artifact/bin/cargo-cp-artifact.js +6 -0
  16. package/eitri-cli-v2/node_modules/cargo-cp-artifact/package.json +34 -0
  17. package/eitri-cli-v2/node_modules/cargo-cp-artifact/src/args.js +131 -0
  18. package/eitri-cli-v2/node_modules/cargo-cp-artifact/src/index.js +164 -0
  19. package/eitri-cli-v2/package-lock.json +26 -0
  20. package/eitri-cli-v2/package.json +21 -0
  21. package/eitri-cli-v2/src/commands/mod.rs +1 -0
  22. package/eitri-cli-v2/src/commands/publish.rs +67 -0
  23. package/eitri-cli-v2/src/config/mod.rs +1 -0
  24. package/eitri-cli-v2/src/config/user_credentials.rs +38 -0
  25. package/eitri-cli-v2/src/infra/async_runtime.rs +9 -0
  26. package/eitri-cli-v2/src/infra/http_client.rs +484 -0
  27. package/eitri-cli-v2/src/infra/mod.rs +2 -0
  28. package/eitri-cli-v2/src/lib.rs +41 -0
  29. package/eitri-cli-v2/src/model/auth_response.rs +8 -0
  30. package/eitri-cli-v2/src/model/credentials.rs +8 -0
  31. package/eitri-cli-v2/src/model/eitri_conf.rs +43 -0
  32. package/eitri-cli-v2/src/model/mod.rs +4 -0
  33. package/eitri-cli-v2/src/model/revision.rs +14 -0
  34. package/eitri-cli-v2/src/services/blind_guardian.rs +87 -0
  35. package/eitri-cli-v2/src/services/eitri_manager.rs +78 -0
  36. package/eitri-cli-v2/src/services/mod.rs +3 -0
  37. package/eitri-cli-v2/src/services/workspace.rs +46 -0
  38. package/eitri-cli-v2/src/utils/convert_eitri_conf.rs +98 -0
  39. package/eitri-cli-v2/src/utils/mod.rs +1 -0
  40. package/eitri-cli-v2/yarn.lock +8 -0
  41. package/index.js +16 -0
  42. package/install-dev.bat +1 -1
  43. package/install-dev.sh +1 -1
  44. package/package.json +1 -1
  45. package/src/cmd/push-version.js +20 -9
  46. package/src/cmd/start.js +5 -2
  47. package/src/cmd/validate.js +1 -1
  48. package/src/modules/vegvisir/VegvisirService.js +2 -2
  49. package/src/service/MiniLog.js +1 -1
  50. package/src/service/QRCodeFactory.js +1 -1
  51. package/src/service/Workspace.js +9 -8
  52. package/src/util/LogUtil.js +14 -0
  53. package/test/e2e/cli.test.js +54 -0
@@ -0,0 +1,67 @@
1
+ use std::process::exit;
2
+
3
+ use neon::{
4
+ context::{Context, FunctionContext},
5
+ result::JsResult,
6
+ types::JsPromise,
7
+ };
8
+
9
+ use crate::{
10
+ infra::async_runtime::runtime,
11
+ services::{eitri_manager, workspace},
12
+ };
13
+
14
+ const DIVISOR: &str = "========================================================";
15
+
16
+ pub fn execute(
17
+ mut cx: FunctionContext,
18
+ environment: String,
19
+ message: String,
20
+ ) -> JsResult<JsPromise> {
21
+ let init_message = format!("Iniciando publicação de Eitri-App",);
22
+ println!("{DIVISOR}");
23
+ println!("\t{init_message}");
24
+ println!("{DIVISOR}");
25
+
26
+ let rt = match runtime(&mut cx) {
27
+ Ok(rt) => rt,
28
+ Err(_err) => {
29
+ eprintln!("Houve um erro ao criar runtime");
30
+ exit(1);
31
+ }
32
+ };
33
+
34
+ let channel = cx.channel();
35
+
36
+ let (deferred, promise) = cx.promise();
37
+
38
+ rt.spawn(async move {
39
+ let eitri_conf = workspace::read_eitri_conf().await;
40
+ let version = eitri_conf.version;
41
+ println!("Versão a ser publicada: {}", version);
42
+ println!("Environment: {}", environment);
43
+ println!("Mensagem: {}", message);
44
+
45
+ let revision = match eitri_manager::get_revision(&eitri_conf.id, &version).await {
46
+ Ok(revision) => revision,
47
+ Err(_err) => {
48
+ eprintln!("Houve um erro ao buscar revisão.");
49
+ exit(1)
50
+ }
51
+ };
52
+ match eitri_manager::publish_revision(&revision.id, &environment, &message).await {
53
+ Ok(_) => {
54
+ println!("Eitri-App publicado com sucesso!")
55
+ }
56
+ Err(err) => {
57
+ eprintln!("Houve um erro. Error: {:?}", err);
58
+ exit(1)
59
+ }
60
+ }
61
+ deferred.settle_with(&channel, move |mut cx| {
62
+ Ok(cx.string("Eitri-App publicado com sucesso!"))
63
+ });
64
+ });
65
+
66
+ Ok(promise)
67
+ }
@@ -0,0 +1 @@
1
+ pub mod user_credentials;
@@ -0,0 +1,38 @@
1
+ use std::{fs, process::exit};
2
+
3
+ use homedir::get_my_home;
4
+
5
+ use crate::model::credentials::Credentials;
6
+
7
+ pub fn get_credentials() -> Result<Credentials, serde_json::Error> {
8
+ let home_dir = match get_my_home() {
9
+ Ok(dir) => dir,
10
+ Err(_) => {
11
+ eprintln!("Houve um erro ao ler a home do usuário");
12
+ exit(1)
13
+ }
14
+ };
15
+
16
+ let home_dir = match home_dir {
17
+ Some(dir) => dir,
18
+ _ => exit(1),
19
+ };
20
+
21
+ let credentials_file_path = home_dir.join(".eitri").join("prod-eitri.conf.js");
22
+
23
+ let content = match fs::read_to_string(credentials_file_path.to_owned()) {
24
+ Ok(c) => c,
25
+ Err(_) => {
26
+ eprintln!(
27
+ "Houve um erro ao ler credenciais do usuário, certifique-se de ter feito login"
28
+ );
29
+ exit(1)
30
+ }
31
+ };
32
+
33
+ let content = content.replace("module.exports = ", "");
34
+
35
+ let credentials: Credentials = serde_json::from_str(&content)?;
36
+
37
+ Ok(credentials)
38
+ }
@@ -0,0 +1,9 @@
1
+ use neon::{context::Context, result::NeonResult};
2
+ use once_cell::sync::OnceCell;
3
+ use tokio::runtime::Runtime;
4
+
5
+ pub fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> {
6
+ static RUNTIME: OnceCell<Runtime> = OnceCell::new();
7
+
8
+ RUNTIME.get_or_try_init(|| Runtime::new().or_else(|err| cx.throw_error(err.to_string())))
9
+ }
@@ -0,0 +1,484 @@
1
+ // use std::sync::Arc;
2
+
3
+ use reqwest::{header::HeaderMap, multipart::Form, Client};
4
+ use serde::de::DeserializeOwned;
5
+ use serde::Serialize;
6
+ use serde_derive::Deserialize;
7
+
8
+ // use crate::services::vegvisir::get_workspace;
9
+
10
+ // use super::cookie::{get_cookie, write_cookie};
11
+
12
+ #[allow(dead_code)]
13
+ #[derive(Debug, Deserialize)]
14
+ pub struct ApiError {
15
+ pub message: String,
16
+ }
17
+
18
+ #[allow(dead_code)]
19
+ #[derive(Debug)]
20
+ pub enum HttpError {
21
+ HttpError(reqwest::StatusCode, ApiError),
22
+ Deserialize(reqwest::Error),
23
+ }
24
+
25
+ #[allow(dead_code)]
26
+ pub async fn post<T, U>(url: &str, data: U, headers: HeaderMap) -> Result<T, HttpError>
27
+ where
28
+ T: DeserializeOwned,
29
+ U: Serialize,
30
+ {
31
+ let client = get_client(url);
32
+
33
+ let response = client
34
+ .post(url)
35
+ .headers(headers)
36
+ .json(&data)
37
+ .send()
38
+ .await
39
+ .map_err(HttpError::Deserialize)?;
40
+
41
+ if response.status().is_success() {
42
+ // write_cookie(&response.headers(), &url);
43
+ return response.json().await.map_err(HttpError::Deserialize);
44
+ }
45
+ let status = response.status();
46
+ let mensagem = response
47
+ .text()
48
+ .await
49
+ .unwrap_or_else(|_| String::from("Erro desconhecido"));
50
+ let api_error: ApiError = serde_json::from_str(&mensagem).unwrap_or_else(|_| ApiError {
51
+ message: String::from("Erro ao relizar parse do JSON"),
52
+ });
53
+ Err(HttpError::HttpError(status, api_error))
54
+ }
55
+
56
+ #[allow(dead_code)]
57
+ pub async fn post_form_data<T>(url: &str, data: Form, headers: HeaderMap) -> Result<T, HttpError>
58
+ where
59
+ T: DeserializeOwned,
60
+ {
61
+ let client = get_client(url);
62
+
63
+ let response = client
64
+ .post(url)
65
+ .headers(headers)
66
+ .multipart(data)
67
+ .send()
68
+ .await
69
+ .map_err(HttpError::Deserialize)?;
70
+
71
+ if response.status().is_success() {
72
+ // write_cookie(&response.headers(), &url);
73
+ return response.json().await.map_err(HttpError::Deserialize);
74
+ }
75
+ let status = response.status();
76
+ let mensagem = response
77
+ .text()
78
+ .await
79
+ .unwrap_or_else(|_| String::from("Erro desconhecido"));
80
+ let api_error: ApiError = serde_json::from_str(&mensagem).unwrap_or_else(|_| ApiError {
81
+ message: String::from("Erro ao relizar parse do JSON"),
82
+ });
83
+ Err(HttpError::HttpError(status, api_error))
84
+ }
85
+
86
+ #[allow(dead_code)]
87
+ pub async fn get<T>(url: &str, headers: HeaderMap) -> Result<T, HttpError>
88
+ where
89
+ T: DeserializeOwned,
90
+ {
91
+ let client = get_client(url);
92
+
93
+ let response = client
94
+ .get(url)
95
+ .headers(headers)
96
+ .send()
97
+ .await
98
+ .map_err(HttpError::Deserialize)?;
99
+
100
+ if response.status().is_success() {
101
+ // write_cookie(&response.headers(), &url);
102
+ return response.json().await.map_err(HttpError::Deserialize);
103
+ }
104
+ let status = response.status();
105
+ let mensagem = response
106
+ .text()
107
+ .await
108
+ .unwrap_or_else(|_| String::from("Erro desconhecido"));
109
+ let api_error: ApiError = serde_json::from_str(&mensagem).unwrap_or_else(|_| ApiError {
110
+ message: String::from("Erro ao relizar parse do JSON"),
111
+ });
112
+ Err(HttpError::HttpError(status, api_error))
113
+ }
114
+
115
+ #[allow(dead_code)]
116
+ pub async fn put<U>(url: &str, data: U, headers: HeaderMap) -> Result<String, HttpError>
117
+ where
118
+ U: Serialize,
119
+ {
120
+ let client = get_client(url);
121
+
122
+ let response = client
123
+ .put(url)
124
+ .headers(headers)
125
+ .json(&data)
126
+ .send()
127
+ .await
128
+ .map_err(HttpError::Deserialize)?;
129
+
130
+ if response.status().is_success() {
131
+ // write_cookie(&response.headers(), &url);
132
+ return response.text().await.map_err(HttpError::Deserialize);
133
+ }
134
+
135
+ let status = response.status();
136
+ let mensagem = response
137
+ .text()
138
+ .await
139
+ .unwrap_or_else(|_| String::from("Erro desconhecido"));
140
+ let api_error: ApiError = serde_json::from_str(&mensagem).unwrap_or_else(|_| ApiError {
141
+ message: String::from("Erro ao relizar parse do JSON"),
142
+ });
143
+ Err(HttpError::HttpError(status, api_error))
144
+ }
145
+
146
+ #[allow(dead_code)]
147
+ pub async fn delete(url: &str, headers: HeaderMap) -> Result<(), HttpError> {
148
+ let client = get_client(url);
149
+
150
+ let response = client
151
+ .delete(url)
152
+ .headers(headers)
153
+ .send()
154
+ .await
155
+ .map_err(HttpError::Deserialize)?;
156
+
157
+ if response.status().is_success() {
158
+ // write_cookie(&response.headers(), &url);
159
+ return Ok(());
160
+ }
161
+
162
+ let status = response.status();
163
+ let mensagem = response
164
+ .text()
165
+ .await
166
+ .unwrap_or_else(|_| String::from("Erro desconhecido"));
167
+ let api_error: ApiError = serde_json::from_str(&mensagem).unwrap_or_else(|_| ApiError {
168
+ message: String::from("Erro ao relizar parse do JSON"),
169
+ });
170
+ Err(HttpError::HttpError(status, api_error))
171
+ }
172
+
173
+ #[allow(dead_code)]
174
+ pub async fn get_default_headers(token: String) -> HeaderMap {
175
+ let mut headers = HeaderMap::new();
176
+
177
+ // let workspace = get_workspace().await;
178
+
179
+ headers.append("Authorization", token.parse().unwrap());
180
+ // headers.append("Workspace-Id", workspace.id.parse().unwrap());
181
+
182
+ headers
183
+ }
184
+
185
+ #[allow(dead_code, unused_variables)]
186
+ fn get_client(request_url: &str) -> Client {
187
+ // let jar = get_cookie(request_url).unwrap_or_else(|| panic!("Error ao ler cookie"));
188
+ Client::builder()
189
+ .cookie_store(true)
190
+ // .cookie_provider(Arc::from(jar))
191
+ .build()
192
+ .unwrap()
193
+ }
194
+
195
+ #[cfg(test)]
196
+ mod tests {
197
+ use std::env;
198
+
199
+ use super::*;
200
+ use httpmock::prelude::*;
201
+ use reqwest::multipart;
202
+ use serde_derive::{Deserialize, Serialize};
203
+ use serde_json::json;
204
+
205
+ #[derive(Deserialize)]
206
+ struct Response {
207
+ #[serde(rename = "resultCount")]
208
+ result_count: i32,
209
+ }
210
+
211
+ #[derive(Deserialize)]
212
+ #[serde(rename_all = "camelCase")]
213
+ struct AuthResponse {
214
+ status: String,
215
+ }
216
+
217
+ #[derive(Deserialize, Serialize)]
218
+ struct UpdateData {
219
+ status: String,
220
+ email: String,
221
+ }
222
+
223
+ #[derive(Deserialize)]
224
+ struct FileUploadResponse {
225
+ ok: bool,
226
+ }
227
+
228
+ #[derive(Serialize, Deserialize)]
229
+ struct FakeAuth {
230
+ client_id: String,
231
+ client_secret: String,
232
+ grant_type: String,
233
+ }
234
+
235
+ #[derive(Deserialize)]
236
+ struct VoidResult {}
237
+
238
+ #[tokio::test]
239
+ async fn test_http_post_success() {
240
+ let mut headers = HeaderMap::new();
241
+ headers.append("user-agent", "eitri".parse().unwrap());
242
+
243
+ let client_id = env::var("EITRI_CLI_CLIENT_ID").unwrap();
244
+ let client_secret = env::var("EITRI_CLI_CLIENT_SECRET").unwrap();
245
+
246
+ let data = FakeAuth {
247
+ client_id,
248
+ client_secret,
249
+ grant_type: String::from("client_credentials"),
250
+ };
251
+
252
+ match post::<AuthResponse, FakeAuth>(
253
+ "https://api.eitri.tech/blind-guardian-api/v1/o/auth",
254
+ data,
255
+ headers,
256
+ )
257
+ .await
258
+ {
259
+ Ok(result) => {
260
+ assert_eq!(result.status, "ACTIVE");
261
+ }
262
+ Err(error) => match error {
263
+ HttpError::HttpError(_, error) => {
264
+ panic!("{}", error.message)
265
+ }
266
+ HttpError::Deserialize(error) => {
267
+ panic!("{:?}", error)
268
+ }
269
+ },
270
+ }
271
+ }
272
+
273
+ #[tokio::test]
274
+ async fn test_http_post_form_data_success() {
275
+ let mut headers = HeaderMap::new();
276
+ headers.append("user-agent", "eitri".parse().unwrap());
277
+ headers.append(
278
+ "Workspace-Id",
279
+ "3c42595c-3da6-475f-a843-5f65cd1982e6".parse().unwrap(),
280
+ );
281
+
282
+ let form = multipart::Form::new();
283
+
284
+ let form = form.text("filepath", "src/views/Home.jsx");
285
+
286
+ let part = multipart::Part::bytes("export default function Home {}".as_bytes())
287
+ .file_name("Home")
288
+ .mime_str("text/plain");
289
+
290
+ let part_result = match part {
291
+ Ok(result) => result,
292
+ Err(_) => {
293
+ panic!("Erro ao construir part")
294
+ }
295
+ };
296
+ let form = form.part("file", part_result);
297
+
298
+ let server = MockServer::start();
299
+
300
+ server.mock(|when, then| {
301
+ when.method(POST).path("/runes-foundry/fileupload");
302
+ then.status(200)
303
+ .header("content-type", "application/json; charset=UTF-8")
304
+ .body(
305
+ json!({
306
+ "ok": true
307
+ })
308
+ .to_string()
309
+ .as_bytes(),
310
+ );
311
+ });
312
+
313
+ match post_form_data::<FileUploadResponse>(
314
+ &server.url("/runes-foundry/fileupload"),
315
+ form,
316
+ headers,
317
+ )
318
+ .await
319
+ {
320
+ Ok(result) => {
321
+ assert!(result.ok);
322
+ }
323
+ Err(error) => match error {
324
+ HttpError::HttpError(_, error) => {
325
+ panic!("{}", error.message)
326
+ }
327
+ HttpError::Deserialize(error) => {
328
+ panic!("{:?}", error)
329
+ }
330
+ },
331
+ }
332
+ }
333
+
334
+ #[tokio::test]
335
+ async fn test_http_get_success() {
336
+ let mut headers = HeaderMap::new();
337
+ headers.append("user-agent", "eitri".parse().unwrap());
338
+ let result: Result<Response, HttpError> =
339
+ get("https://calindra.tech/eitri/product_list.json", headers).await;
340
+ assert!(result.is_ok());
341
+ let data = result.unwrap();
342
+ assert_eq!(6, data.result_count);
343
+ }
344
+
345
+ #[tokio::test]
346
+ async fn test_http_get_error_unauthorized() {
347
+ let mut headers = HeaderMap::new();
348
+ headers.append("user-agent", "eitri".parse().unwrap());
349
+
350
+ match get::<Response>(
351
+ "https://api.eitri.tech/eitri-manager-api/eitri-apps",
352
+ headers,
353
+ )
354
+ .await
355
+ {
356
+ Ok(_) => {}
357
+ Err(erro) => match erro {
358
+ HttpError::HttpError(status, error) => {
359
+ assert_eq!(status, 401);
360
+ assert_eq!(error.message, "JWT missing.")
361
+ }
362
+ HttpError::Deserialize(error) => {
363
+ panic!("{:?}", error)
364
+ }
365
+ },
366
+ }
367
+ }
368
+
369
+ #[tokio::test]
370
+ async fn test_http_get_error_forbidden_with_xml_response() {
371
+ let mut headers = HeaderMap::new();
372
+ headers.append("user-agent", "eitri".parse().unwrap());
373
+ match get::<Response>("https://calindra.tech/eitri/product_listx.json", headers).await {
374
+ Ok(_) => {}
375
+ Err(erro) => match erro {
376
+ HttpError::HttpError(status, _) => {
377
+ assert_eq!(status, 403)
378
+ }
379
+ HttpError::Deserialize(error) => {
380
+ panic!("{:?}", error)
381
+ }
382
+ },
383
+ }
384
+ }
385
+
386
+ #[tokio::test]
387
+ async fn test_http_put_success() {
388
+ let mut headers = HeaderMap::new();
389
+ headers.append("user-agent", "eitri".parse().unwrap());
390
+
391
+ let email = String::from("foobar@mail.com");
392
+
393
+ let data = UpdateData {
394
+ status: String::from("ACTIVE"),
395
+ email,
396
+ };
397
+
398
+ let server = MockServer::start();
399
+
400
+ server.mock(|when, then| {
401
+ when.method(PUT).path("/blind-guardian-api/v1/p/users/self");
402
+ then.status(200)
403
+ .header("content-type", "application/json; charset=UTF-8")
404
+ .body(
405
+ json!({
406
+ "status": "ACTIVE",
407
+ "email": "foobar@gmail.com"
408
+ })
409
+ .to_string()
410
+ .as_bytes(),
411
+ );
412
+ });
413
+ match put::<UpdateData>(
414
+ &format!("{}/blind-guardian-api/v1/p/users/self", server.url("")),
415
+ data,
416
+ headers,
417
+ )
418
+ .await
419
+ {
420
+ Ok(_) => {}
421
+ Err(error) => match error {
422
+ HttpError::HttpError(_, error) => {
423
+ panic!("{}", error.message)
424
+ }
425
+ HttpError::Deserialize(error) => {
426
+ panic!("{:?}", error)
427
+ }
428
+ },
429
+ }
430
+ }
431
+
432
+ #[tokio::test]
433
+ async fn test_http_delete_success() {
434
+ let mut headers = HeaderMap::new();
435
+ headers.append("user-agent", "eitri".parse().unwrap());
436
+ headers.append(
437
+ "Workspace-Id",
438
+ "3c42595c-3da6-475f-a843-5f65cd1982e6".parse().unwrap(),
439
+ );
440
+ headers.append(
441
+ "Authorization",
442
+ "3c42595c-3da6-475f-a843-5f65cd1982e6".parse().unwrap(),
443
+ );
444
+
445
+ let server = MockServer::start();
446
+
447
+ server.mock(|when, then| {
448
+ when.method(DELETE).path("/runes-foundry/sources");
449
+ then.status(200)
450
+ .header("content-type", "application/json; charset=UTF-8")
451
+ .body(json!({}).to_string().as_bytes());
452
+ });
453
+
454
+ match delete(&server.url("/runes-foundry/sources"), headers).await {
455
+ Ok(_) => {}
456
+ Err(error) => match error {
457
+ HttpError::HttpError(_, error) => {
458
+ panic!("{}", error.message)
459
+ }
460
+ HttpError::Deserialize(error) => {
461
+ panic!("{:?}", error)
462
+ }
463
+ },
464
+ }
465
+ }
466
+
467
+ #[tokio::test]
468
+ async fn test_http_client_should_receive_cookies() {
469
+ let url = "https://api.eitri.tech/runes-foundry/health";
470
+ let client = get_client(url);
471
+
472
+ let response = client
473
+ .get(url)
474
+ .send()
475
+ .await
476
+ .unwrap_or_else(|_| panic!("Erro inesperado"));
477
+
478
+ let mut cookies = response.cookies();
479
+
480
+ let stick_cookie = cookies.find(|c| c.name() == "stick_runes_foundry").unwrap();
481
+
482
+ assert_eq!(stick_cookie.name(), "stick_runes_foundry");
483
+ }
484
+ }
@@ -0,0 +1,2 @@
1
+ pub mod async_runtime;
2
+ pub mod http_client;
@@ -0,0 +1,41 @@
1
+ use std::process::exit;
2
+
3
+ use neon::prelude::*;
4
+ mod commands;
5
+ mod config;
6
+ mod infra;
7
+ mod model;
8
+ mod services;
9
+ mod utils;
10
+ fn publish(mut cx: FunctionContext) -> JsResult<JsPromise> {
11
+ let environment = match cx.argument::<JsString>(0) {
12
+ Ok(v) => v.value(&mut cx),
13
+ Err(_err) => {
14
+ eprintln!(
15
+ "É necessário passar como parâmetro o ID do environment para publicar a versão.",
16
+ );
17
+ exit(1);
18
+ }
19
+ };
20
+
21
+ let message = match cx.argument::<JsString>(1) {
22
+ Ok(v) => v.value(&mut cx),
23
+ Err(_err) => String::from(""),
24
+ };
25
+
26
+ let promise = commands::publish::execute(cx, environment, message);
27
+
28
+ match promise {
29
+ Ok(promise) => Ok(promise),
30
+ Err(_err) => {
31
+ eprintln!("Houve um erro inesperado ao executar o comando publish, por favor, tente novamente.");
32
+ exit(1)
33
+ }
34
+ }
35
+ }
36
+
37
+ #[neon::main]
38
+ fn main(mut cx: ModuleContext) -> NeonResult<()> {
39
+ cx.export_function("publish", publish)?;
40
+ Ok(())
41
+ }
@@ -0,0 +1,8 @@
1
+ use serde::Deserialize;
2
+
3
+ #[allow(dead_code)]
4
+ #[derive(Deserialize)]
5
+ #[serde(rename_all = "camelCase")]
6
+ pub struct AuthResponse {
7
+ pub access_token: String,
8
+ }
@@ -0,0 +1,8 @@
1
+ use serde::{Deserialize, Serialize};
2
+
3
+ #[derive(Debug, Deserialize, Serialize)]
4
+ #[serde(rename_all = "camelCase")]
5
+ pub struct Credentials {
6
+ pub dev_user: String,
7
+ pub dev_key: String,
8
+ }