teuton 2.9.3 → 2.9.5

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -5
  3. data/docs/changelog/changelog.2.md +9 -0
  4. data/docs/es/README.md +72 -0
  5. data/docs/es/aprender/01-cmd_new.md +27 -0
  6. data/docs/es/aprender/02-target.md +131 -0
  7. data/docs/es/aprender/README.md +36 -0
  8. data/docs/install/README.md +2 -2
  9. data/docs/install/s-node.md +3 -3
  10. data/docs/install/t-node.md +8 -13
  11. data/docs/learn/02-target.md +7 -6
  12. data/lib/teuton/case/config.rb +1 -1
  13. data/lib/teuton/case/dsl/expect.rb +2 -0
  14. data/lib/teuton/case/dsl/expect_sequence.rb +2 -2
  15. data/lib/teuton/case/dsl/run_script.rb +1 -1
  16. data/lib/teuton/case/dsl/unique.rb +1 -1
  17. data/lib/teuton/case/execute/execute_base.rb +8 -4
  18. data/lib/teuton/case/execute/execute_manager.rb +2 -2
  19. data/lib/teuton/case/execute/execute_ssh.rb +10 -11
  20. data/lib/teuton/case/execute/execute_telnet.rb +21 -14
  21. data/lib/teuton/case/host.rb +6 -6
  22. data/lib/teuton/check/dsl/all.rb +1 -1
  23. data/lib/teuton/check/show.rb +4 -4
  24. data/lib/teuton/deprecated/runner.rb +12 -12
  25. data/lib/teuton/readme/dsl/getset.rb +3 -3
  26. data/lib/teuton/readme/dsl/run.rb +3 -3
  27. data/lib/teuton/readme/readme.rb +6 -6
  28. data/lib/teuton/report/formatter/default/array.rb +1 -1
  29. data/lib/teuton/report/formatter/default/html.rb +1 -1
  30. data/lib/teuton/report/formatter/default/json.rb +3 -2
  31. data/lib/teuton/report/formatter/default/xml.rb +1 -1
  32. data/lib/teuton/report/formatter/default/yaml.rb +1 -1
  33. data/lib/teuton/report/formatter/moodle_csv_formatter.rb +1 -1
  34. data/lib/teuton/report/formatter/resume/array.rb +1 -1
  35. data/lib/teuton/report/formatter/resume/html.rb +1 -1
  36. data/lib/teuton/report/formatter/resume/json.rb +3 -2
  37. data/lib/teuton/report/formatter/resume/yaml.rb +1 -1
  38. data/lib/teuton/report/report.rb +2 -2
  39. data/lib/teuton/utils/configfile_reader.rb +2 -1
  40. data/lib/teuton/version.rb +1 -1
  41. data/lib/teuton.rb +0 -1
  42. metadata +14 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b4752e08b15fd862f420e1d48adbd9993d85d195d1b4c4e3a038fd49496c266
4
- data.tar.gz: 35b22222f598310ccb28f208a56a4ae6923585815b41cceea7ed1d3546c6b914
3
+ metadata.gz: 3ce9e5fc4e8a37ff624e2c8dc16440236aed569cf1c6b77a49e9efbb6f2b1894
4
+ data.tar.gz: e2959aef5f909f245c27bf18868ffb7cfd0e7dee376da8f9620b1306f0d8b383
5
5
  SHA512:
6
- metadata.gz: 94c0548eea0557f8974d2f11640aa292cb6beaa446ea11f5b8c8927f0fafd846bf03bdb7d9114c82447e149534bc350521ba3998c441996c95aecc1a07341551
7
- data.tar.gz: e6086e5451d2846bde79419d8cc3cf0c6d8dd332c966e2fee3c19f54c66569cc5f3c62e8aeb108a9c6f2e6cfe63e4190d70491b5aeb99d7dbc75cfe3f07991bc
6
+ metadata.gz: 60567daad6f01a946b227f5eba0c63813bcb9e2d1f466e3d0fbf5407e7e3d1efa120036df6cc29f4e63f627b0e638d3334f34f0182558fb20d66d35bedf113de
7
+ data.tar.gz: ed5569263c61fa81b42c4764793fe4e917d4395c115b2f95c4456813c62b5e0d86e02a68e79354babc9e2bc471678d6566c032e475bd1944563817163b65ee54
data/README.md CHANGED
@@ -8,10 +8,10 @@ _Create Unit Test for your machines. Test your infrastructure as code._
8
8
 
9
9
  ![logo](./docs/images/logo.png)
10
10
 
11
- Infrastructure test, useful for:
11
+ The infrastructure test is useful for:
12
12
  * Sysadmin teachers who want to evaluate students remote machines.
13
- * Sysadmin apprentices who want to evaluate their learning process as a game.
14
- * Professional sysadmin who want to monitor remote machines.
13
+ * Students who want to evaluate their learning process.
14
+ * Professionals who want to monitor their remote machines.
15
15
 
16
16
  # Installation
17
17
 
@@ -28,7 +28,7 @@ gem install teuton
28
28
  Executing `teuton` command to run example test:
29
29
 
30
30
  ```console
31
- teuton run examples/01-target
31
+ > teuton run examples/01-target
32
32
 
33
33
  CASE RESULTS
34
34
  +------+-----------+-------+-------+
@@ -37,6 +37,8 @@ CASE RESULTS
37
37
  +------+-----------+-------+-------+
38
38
  ```
39
39
 
40
+ > More information about [commands](docs/commands/README.md)
41
+
40
42
  # Features
41
43
 
42
44
  * Simple DSL to define your tests: `target`, `run`,`expect` and more.
@@ -67,4 +69,6 @@ CASE RESULTS
67
69
  1. Push to the branch (`git push origin my-new-feature`)
68
70
  1. Create new Pull Request.
69
71
 
70
- You can also [create issues](https://github.com/teuton-software/teuton/issues) with your requests/incidences/suggestions.
72
+ You can also [create issues](https://github.com/teuton-software/teuton/issues) with your requests, incidences or suggestions.
73
+
74
+ > Read [Spanish documentation](docs/es/README.md)
@@ -117,3 +117,12 @@ DSL send:
117
117
  /home/username/example/foo/start.rb
118
118
  or /home/username/example/foo.rb
119
119
  ```
120
+
121
+ ## [2.9.3] 20250402
122
+
123
+ - [FIX] Error with telnet connections.
124
+
125
+ ## [2.9.4] 20250410
126
+
127
+ - [FIX] Improve the markdown output of the readme.
128
+ - [FIX] Telnet exitcode
data/docs/es/README.md ADDED
@@ -0,0 +1,72 @@
1
+
2
+ # TEUTON (ES) - (Documentación en progreso)
3
+
4
+ [![Gem Version](https://badge.fury.io/rb/teuton.svg)](https://badge.fury.io/rb/teuton)
5
+ ![GitHub](https://img.shields.io/github/license/dvarrui/teuton)
6
+
7
+ _Crear test unitarios para tus máquinas y probar tu infraestructura como si fuera código._
8
+
9
+ ![logo](../images/logo.png)
10
+
11
+ El test de infraestructura es útil para:
12
+ * Profesores de administración de sistemas que quieren evaluar a las máquinas remotas de los alumnos.
13
+ * Alumnos que quieren evaluar su proceso de aprendizaje.
14
+ * Profesionales que desean monitorizar sus máquinas remotas.
15
+
16
+ # Instalación
17
+
18
+ Primero es necesario tener instalado `Ruby`y a continuación instalamos Teuton con el siguiente comando:
19
+
20
+ ```console
21
+ gem install teuton
22
+ ```
23
+
24
+ > Para instalar Teuton sin privilegios de root: `gem install --user-install teuton`
25
+
26
+ # Modo de uso
27
+
28
+ Usaremos el comando `teuton` para ejecutar los tests:
29
+
30
+ ```console
31
+ > teuton run examples/01-target
32
+
33
+ CASE RESULTS
34
+ +------+-----------+-------+-------+
35
+ | CASE | MEMBERS | GRADE | STATE |
36
+ | 01 | anonymous | 100.0 | ✔ |
37
+ +------+-----------+-------+-------+
38
+ ```
39
+
40
+ > Más información sobre los [comandos](../commands/README.md)
41
+
42
+ # Características
43
+
44
+ * DSL sencillo para definir los tests: `target`, `run`,`expect`, etc.
45
+ * Se usa conexiones SSH o Telnet para acceder a los dispositivos remotos.
46
+ * Formatos de salida: `txt`, `html`, `json`, `yaml`, etc.
47
+ * Multiplatforma.
48
+ * [Licencia de Software Libre](LICENSE).
49
+
50
+ # Documentación
51
+
52
+ * [Instalación](../install/README.md)
53
+ * [Aprender](../learn/README.md)
54
+ * [Ejemplos](../../examples)
55
+ * [Comandos](../commands/README.md)
56
+ * [DSL](../dsl/README.md)
57
+ * [Blogs y videos](../videos.md)
58
+
59
+ # Contacto
60
+
61
+ * **Email**: `teuton.software@protonmail.com`
62
+
63
+ # Contribuciones
64
+
65
+ 1. Asegúrate de tener `Ruby`instalado.
66
+ 1. Haz un "fork" del proyecto.
67
+ 1. Crear tu rama "feature" (`git checkout -b my-new-feature`)
68
+ 1. Haz "commit" de tus cambios (`git commit -am 'Add some feature'`)
69
+ 1. Haz "push" a la rama (`git push origin my-new-feature`)
70
+ 1. Crear un "pull request" nuevo.
71
+
72
+ También se pueden [crear issues](https://github.com/teuton-software/teuton/issues) con peticiones, incidencias o sugerencias.
@@ -0,0 +1,27 @@
1
+
2
+ [<< back](README.md)
3
+
4
+ # Nuevo test
5
+
6
+ Crear el esquelero para un nuevo proyecto: `teuton create foo`
7
+
8
+ ```
9
+ > teuton new foo
10
+
11
+ [INFO] Creating foo project skeleton
12
+ * Create dir => foo
13
+ * Create file => foo/config.yaml
14
+ * Create file => foo/start.rb
15
+ ```
16
+
17
+ > NOTA: Lo ficheros se pueden crear manualmente.
18
+
19
+ Este comando crea los siguientes ficheros:
20
+
21
+ | Fichero/Directorio | Descripción |
22
+ | ------------------ | ---------------- |
23
+ | foo | Direcotrio base |
24
+ | foo/start.rb | Script principal |
25
+ | foo/config.yaml | Fichero de configuración |
26
+
27
+ Ahora es el momento de personalizar nuestros objetivos (targets).
@@ -0,0 +1,131 @@
1
+ [<< back](README.md)
2
+
3
+ # target
4
+
5
+ Un [target](../../dsl/target.md) es el objetivo que queremos evaluar. Los objetivos se definen dentro de una sección `group`.
6
+
7
+ ## Target definition
8
+
9
+ Cada proceso de evaluación consta de 3 partes:
10
+
11
+ * [target](../../dsl/target.md): Descripción del elemento que va a ser evaluado.
12
+ * [run](../../dsl/run.md): Ejecutar el comando `id obiwan` en la máquina local.
13
+ * [expect](../../dsl/expect.md): Verificar que el resultado del comando devuelve el valor esperado.
14
+
15
+ ```ruby
16
+ group "Aprender sobre los targets" do
17
+
18
+ target "Existe el usuario <obiwan>"
19
+ run "id obiwan"
20
+ expect ["uid=", "(obiwan)", "gid="]
21
+
22
+ target "No existe el usuario <vader>"
23
+ run "id vader"
24
+ expect_fail
25
+ end
26
+ ```
27
+
28
+ > En este ejemplo estamo usando un SO GNU/Linux en la máquina local porque queremos ejecutar el comando `id obiwan`.
29
+
30
+ Cuando el usuario existe, esperamos encontrar estas palabras en la salida del comando: `uid=, (obiwan), gid=`.
31
+
32
+ ```
33
+ > id obiwan
34
+ uid=1000(obiwan) gid=1000(obiwan) grupos=1000(obiwan)
35
+ ```
36
+
37
+ Pero cuando el usuario no existe, se esperan una salida de error.
38
+
39
+ ```
40
+ > id vader
41
+ id: «vader»: no such user
42
+
43
+ > echo $?
44
+ 1
45
+
46
+ ```
47
+
48
+ ## Section de ejecución
49
+
50
+ Cuando se ejecuta el test, se procesa la sección `play`, la cual contiene las siguientes instrucciones:
51
+
52
+ * [show](../../dsl/show.md): mostrar por pantalla información del proceso.
53
+ * [export](../../dsl/export.md): generar informes de salida.
54
+
55
+ ```ruby
56
+ play do
57
+ show
58
+ export
59
+ end
60
+ ```
61
+
62
+ ## Ejemplo
63
+
64
+ Usa este comando para ejecutar el test:
65
+
66
+ ```console
67
+ > teuton run examples/02-target
68
+
69
+ CASE RESULTS
70
+ +------+-----------+-------+-------+
71
+ | CASE | MEMBERS | GRADE | STATE |
72
+ | 01 | anonymous | 100.0 | ✔ |
73
+ +------+-----------+-------+-------+
74
+ ```
75
+
76
+ Los informes de salida se crean en la carpeta `var/02-target/`:
77
+
78
+ ```console
79
+ var
80
+ └── 02-target
81
+ ├── case-01.txt
82
+ ├── moodle.csv
83
+ └── resume.txt
84
+ ```
85
+
86
+ Veamos el contenido:
87
+
88
+ ```
89
+ > cat var/02-target/case-01.txt
90
+
91
+ CONFIGURATION
92
+ +-------------+-----------+
93
+ | tt_members | anonymous |
94
+ | tt_sequence | false |
95
+ | tt_skip | false |
96
+ | tt_testname | 02-target |
97
+ +-------------+-----------+
98
+
99
+ GROUPS
100
+ - Learn about targets
101
+ 01 (0.0/1.0)
102
+ Description : Create user obiwan
103
+ Command : id obiwan
104
+ Output : id: «obiwan»: no existe ese usuario
105
+ Duration : 0.002 (local)
106
+ Alterations : find(uid=) & find((obiwan)) & find(gid=) & count
107
+ Expected : Greater than 0
108
+ Result : 0
109
+ 02 (1.0/1.0)
110
+ Description : Delete user vader
111
+ Command : id vader
112
+ Output : id: «vader»: no existe ese usuario
113
+ Duration : 0.002 (local)
114
+ Alterations : Read exit code
115
+ Expected : Greater than 0
116
+ Result : 1
117
+
118
+ RESULTS
119
+ +--------------+---------------------------+
120
+ | case_id | 01 |
121
+ | start_time | 2023-06-16 08:42:13 +0100 |
122
+ | finish_time | 2023-06-16 08:42:13 +0100 |
123
+ | duration | 0.004527443 |
124
+ | unique_fault | 0 |
125
+ | max_weight | 2.0 |
126
+ | good_weight | 1.0 |
127
+ | fail_weight | 1.0 |
128
+ | fail_counter | 1 |
129
+ | grade | 50 |
130
+ +--------------+---------------------------+
131
+ ```
@@ -0,0 +1,36 @@
1
+ [<< back](../README.md)
2
+
3
+ # Aprender
4
+
5
+ Aprender a escribir tus propios test:
6
+
7
+ 1. [Crear un NUEVO test](01-cmd_new.md)
8
+ 1. [Evaluating TARGET](02-target.md)
9
+ 1. [Checking REMOTE HOSTS](03-remote_hosts.md)
10
+ 1. [Reading CONFIG file](04-config.md)
11
+ 1. [Using several files](05-use.md)
12
+ 1. [CHECK test syntax](06-cmd_check.md)
13
+ 1. [Target WEIGHT](07-target_weight.md)
14
+ 1. [UNIQUE values](08-unique_values.md)
15
+ 1. [SEND report copies to remote hosts](09-send.md)
16
+ 1. [DEBUG results](10-debug.md)
17
+ 1. [Export other FORMATS](11-export.md)
18
+ 1. [PRESERVE old reports](12-preserve.md)
19
+ 1. [Hide FEEDBACK from reports](13-feedback.md)
20
+ 1. [MOODLE](14-moodle_id.md)
21
+ 1. [Build README from test](15-readme.md)
22
+ 1. [INCLUDE more configuration files](16-include.md)
23
+ 1. [ALIAS](17-alias.md)
24
+ 1. [LOG messages](18-log.md)
25
+ 1. [Don't get params, just read vars](19-read_vars.md)
26
+ 1. [MACROS](20-macros.md)
27
+ 1. [Checking exit codes](21-exit_codes.md)
28
+ 1. [RESULT object](22-result.md)
29
+ 1. [Test code](23-test-code.md)
30
+ 1. [Test SQL and database](24-test-sql.md)
31
+ 1. [expect vs result](25-expect-result.md) TODO
32
+ 1. [EXPECT_SEQUENCE](26-expect_sequence.md)
33
+ 1. [RUN_SCRIPT](27-run_script.md)
34
+ 1. [UPLOAD](28-upload.md)
35
+
36
+ Mores examples at [teuton-tests](https://github.com/dvarrui/teuton-tests) GitHub repository.
@@ -2,14 +2,14 @@
2
2
 
3
3
  # Installation
4
4
 
5
- There are 2 types of nodes/hosts, so there are 2 installations:
5
+ There are 2 types of nodes (hosts), so there are 2 installations:
6
6
 
7
7
  | ID | Software | Description |
8
8
  | -- | -------- | ----------- |
9
9
  | **T-node** | [Teuton installation](t-node.md) | T-NODE host monitors one or severals S-NODE hosts |
10
10
  | **S-node** | [SSH server installation](s-node.md) | S-NODE hosts are monitorized by T-NODE host |
11
11
 
12
- Read [modes of use](modes_of_use.md) to know more about differents T-NODE/S-NODE schemes.
12
+ > Read [modes of use](modes_of_use.md) to know more about differents T-NODE/S-NODE schemes.
13
13
 
14
14
  ## Tested OS list
15
15
 
@@ -11,7 +11,7 @@ Install SSH server on every machine with S-NODE role.
11
11
  Run this command as `root` user:
12
12
 
13
13
  ```bash
14
- wget -qO- https://raw.githubusercontent.com/teuton-software/teuton/master/install/linux/linux_s-node_install.sh | bash
14
+ wget -qO- https://raw.githubusercontent.com/teuton-software/teuton/master/install/linux/s-node_install.sh | bash
15
15
  ```
16
16
 
17
17
  **S-node Windows installation**
@@ -23,7 +23,7 @@ Requirements:
23
23
  Run this command on **PowerShell (PS)** as `Administrator` user:
24
24
 
25
25
  ```powershell
26
- Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/teuton-software/teuton/master/install/windows/windows_s-node_install.ps1'))
26
+ Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/teuton-software/teuton/master/install/windows/s-node_install.ps1'))
27
27
  ```
28
28
 
29
29
  **S-node Mac OS X installation**
@@ -31,5 +31,5 @@ Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.We
31
31
  Run this command as `root` user:
32
32
 
33
33
  ```bash
34
- curl -sL https://raw.githubusercontent.com/teuton-software/teuton/master/install/mac/macosx_s-node_install.sh | bash
34
+ curl -sL https://raw.githubusercontent.com/teuton-software/teuton/master/install/mac/s-node_install.sh | bash
35
35
  ```
@@ -4,24 +4,19 @@
4
4
 
5
5
  # 1. Recommended
6
6
 
7
- **Installation**
8
-
7
+ Installation:
9
8
  1. Install Ruby on your system.
10
9
  2. `gem install teuton`
11
10
 
12
11
  Run `teuton version` to check the installed version.
13
12
 
14
- **Update**
15
-
16
- `gem update teuton`.
17
-
18
- **Uninstall**
19
-
20
- `gem uninstall teuton`.
13
+ > NOTE:
14
+ > * Update: `gem update teuton`.
15
+ > * Uninstall: `gem uninstall teuton`.
21
16
 
22
17
  # 2. Problems
23
18
 
24
- Don't find `teuton` command (OpenSUSE distro, for example), try this:
19
+ Sometimes we don't find `teuton` command (OpenSUSE distro, for example), so try this:
25
20
 
26
21
  Option A:
27
22
  * `ruby -v`, display your current ruby version. Suppose it is "2.5".
@@ -40,7 +35,7 @@ If you don't know how to install Ruby on your system, execute this script to run
40
35
  Run this command as `root` user:
41
36
 
42
37
  ```bash
43
- wget -qO- https://raw.githubusercontent.com/teuton-software/teuton/master/install/linux/linux_t-node_install.sh | bash
38
+ wget -qO- https://raw.githubusercontent.com/teuton-software/teuton/master/install/linux/t-node_install.sh | bash
44
39
  ```
45
40
 
46
41
  **T-node Windows installation**
@@ -52,7 +47,7 @@ Requirements:
52
47
  Run this command on **PowerShell (PS)** as `Administrator` user:
53
48
 
54
49
  ```powershell
55
- Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/teuton-software/teuton/master/install/windows/windows_t-node_install.ps1'))
50
+ Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/teuton-software/teuton/master/install/windows/t-node_install.ps1'))
56
51
  ```
57
52
 
58
53
  **T-node Mac OS X installation**
@@ -60,7 +55,7 @@ Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.We
60
55
  Run this command as admin user (member of `admin` group):
61
56
 
62
57
  ```bash
63
- curl -sL https://raw.githubusercontent.com/teuton-software/teuton/master/install/mac/macosx_t-node_install.sh | bash
58
+ curl -sL https://raw.githubusercontent.com/teuton-software/teuton/master/install/mac/t-node_install.sh | bash
64
59
  ```
65
60
 
66
61
  # 4. Vagrant/Docker
@@ -2,13 +2,14 @@
2
2
 
3
3
  # target
4
4
 
5
- A [target](../dsl/target.md) is a feature you want to check. Targets are defined into `group` sections and every evaluation has 3 parts:
5
+ A [target](../dsl/target.md) is a feature you want to check. Targets are defined into `group` sections.
6
6
 
7
7
  ## Target definition
8
8
 
9
+ Every evaluation has 3 parts:
9
10
  * [target](dsl/target.md): Description of the element to be tested.
10
11
  * [run](../dsl/run.md): Execute a command `id obiwan` on localhost.
11
- * [expect](../&dsl/expect.md): Verify that the result contains expected value.
12
+ * [expect](../dsl/expect.md): Verify that the result contains expected value.
12
13
 
13
14
  ```ruby
14
15
  group "Learn about targets" do
@@ -28,17 +29,17 @@ end
28
29
  When the user exists, we expect this words: `uid=, (obiwan), gid=`.
29
30
 
30
31
  ```
31
- id obiwan
32
+ > id obiwan
32
33
  uid=1000(obiwan) gid=1000(obiwan) grupos=1000(obiwan)
33
34
  ```
34
35
 
35
- But when user does not exist, we expect different words: `id:, vader, no exist`.
36
+ But when user does not exist, we expect command fail.
36
37
 
37
38
  ```
38
- id vader
39
+ > id vader
39
40
  id: «vader»: no such user
40
41
 
41
- echo $?
42
+ > echo $?
42
43
  1
43
44
 
44
45
  ```
@@ -55,7 +55,7 @@ class Case
55
55
  key2 = @ialias[words[0].to_sym]
56
56
  return "NODATA" unless key2
57
57
 
58
- get("#{key2}_#{words[1]}".to_sym, level)
58
+ get(:"#{key2}_#{words[1]}", level)
59
59
  end
60
60
 
61
61
  def search_array_alias(keys, level)
@@ -23,6 +23,8 @@ module DSL
23
23
  @action_counter += 1
24
24
  @action[:id] = @action_counter
25
25
  if @result.exitcode < 0
26
+ # When exitcode is less than zero, it is because there has been
27
+ # an error in the remote connection (SSH or Telnet)
26
28
  @action[:check] = false
27
29
  @action[:result] = @action[:output]
28
30
  else
@@ -38,8 +38,8 @@ class ExpectSequence
38
38
 
39
39
  def find_best_state
40
40
  @states.each do |state|
41
- state[:score] = (state[:steps].select { _1 }).size
42
- state[:fails] = (state[:steps].select { !_1 }).size
41
+ state[:score] = (state[:steps].select { it }).size
42
+ state[:fails] = (state[:steps].select { !it }).size
43
43
  state[:ok] = (state[:fails] == 0)
44
44
  end
45
45
  best = @states[0]
@@ -5,7 +5,7 @@ module DSL
5
5
  def run_script(script, args = {})
6
6
  items = script.split(" ")
7
7
  if items.size == 1
8
- shell = args[:shell] || (get(:shell) != "NODATA" ? get(:shell) : nil)
8
+ shell = args[:shell] || ((get(:shell) != "NODATA") ? get(:shell) : nil)
9
9
  script = "#{shell} #{script}" if shell
10
10
  script = "#{script} #{args[:args]} " if args[:args]
11
11
  end
@@ -4,6 +4,6 @@ module DSL
4
4
  def unique(key, value)
5
5
  return if value.nil?
6
6
 
7
- @uniques << "#{key}=#{value}".to_sym
7
+ @uniques << :"#{key}=#{value}"
8
8
  end
9
9
  end
@@ -38,8 +38,12 @@ class ExecuteBase
38
38
  def encode_and_split(encoding, text)
39
39
  # Convert text to UTF-8 deleting unknown chars
40
40
  text ||= "" # Ensure text is not nil
41
- flag = [:default, "UTF-8"].include? encoding
42
- return text.encode("UTF-8", invalid: :replace).split("\n") if flag
41
+
42
+ # TODO: text.gsub!('\r', '')
43
+ if [:default, "UTF-8"].include? encoding
44
+ text.encode!("UTF-8", invalid: :replace, undef: :replace, replace: "")
45
+ return text.split("\n")
46
+ end
43
47
 
44
48
  # Convert text from input ENCODING to UTF-8
45
49
  ec = Encoding::Converter.new(encoding.to_s, "UTF-8")
@@ -47,9 +51,9 @@ class ExecuteBase
47
51
  text = ec.convert(text)
48
52
  rescue => e
49
53
  puts "[ERROR] #{e}: Declare text encoding..."
50
- puts " run 'command', on: :host, :encoding => 'ISO-8859-1'"
54
+ puts " run 'command', on: :host, encoding: 'ISO-8859-1'"
51
55
  end
52
56
 
53
- text.split("\n")
57
+ text.split("\n").compact
54
58
  end
55
59
  end
@@ -31,8 +31,8 @@ class ExecuteManager
31
31
  end
32
32
 
33
33
  def run_on(host)
34
- protocol = config.get("#{host}_protocol".to_sym)
35
- ip = config.get("#{host}_ip".to_sym)
34
+ protocol = config.get(:"#{host}_protocol")
35
+ ip = config.get(:"#{host}_ip")
36
36
 
37
37
  if protocol.to_s.downcase == "local" || host.to_s == "localhost"
38
38
  # Protocol force => local
@@ -9,24 +9,24 @@ class ExecuteSSH < ExecuteBase
9
9
  def call(input_hostname)
10
10
  action[:conn_type] = :ssh
11
11
  hostname = input_hostname.to_s
12
- ip = config.get("#{hostname}_ip".to_sym).to_s
13
- username = config.get("#{hostname}_username".to_sym).to_s
14
- password = config.get("#{hostname}_password".to_sym).to_s
15
- port = config.get("#{hostname}_port".to_sym).to_i
12
+ ip = config.get(:"#{hostname}_ip").to_s
13
+ username = config.get(:"#{hostname}_username").to_s
14
+ password = config.get(:"#{hostname}_password").to_s
15
+ port = config.get(:"#{hostname}_port").to_i
16
16
  port = 22 if port.zero?
17
17
 
18
- unless config.get("#{hostname}_route".to_sym) == "NODATA"
18
+ unless config.get(:"#{hostname}_route") == "NODATA"
19
19
  # Reconfigure command with gateway. Example host1_route: IP.
20
20
  # hostname2 = hostname ¿not used?
21
21
  ip2 = ip
22
22
  username2 = username
23
23
  password2 = password
24
24
  command2 = action[:command]
25
- hostname = config.get("#{hostname}_route".to_sym)
26
- ip = config.get("#{hostname}_ip".to_sym).to_s
27
- username = config.get("#{hostname}_username".to_sym).to_s
28
- password = config.get("#{hostname}_password".to_sym).to_s
29
- ostype = config.get("#{hostname}_ostype".to_sym).to_s
25
+ hostname = config.get(:"#{hostname}_route")
26
+ ip = config.get(:"#{hostname}_ip").to_s
27
+ username = config.get(:"#{hostname}_username").to_s
28
+ password = config.get(:"#{hostname}_password").to_s
29
+ ostype = config.get(:"#{hostname}_ostype").to_s
30
30
 
31
31
  action[:command] = if ostype.downcase.start_with? "win"
32
32
  "echo y | plink #{username2}@#{ip2} -ssh -pw #{password2} \"#{command2}\""
@@ -89,6 +89,5 @@ class ExecuteSSH < ExecuteBase
89
89
  end
90
90
  result.exitcode = exitcode
91
91
  result.content = encode_and_split(action[:encoding], text)
92
- result.content.compact!
93
92
  end
94
93
  end
@@ -1,7 +1,7 @@
1
1
  require "net/telnet"
2
- require "rainbow"
2
+ # require "rainbow"
3
3
  require_relative "../../utils/project"
4
- require_relative "../../utils/verbose"
4
+ # require_relative "../../utils/verbose"
5
5
  require_relative "execute_base"
6
6
 
7
7
  class ExecuteTelnet < ExecuteBase
@@ -9,48 +9,55 @@ class ExecuteTelnet < ExecuteBase
9
9
  action[:conn_type] = :telnet
10
10
  hostname = input_hostname.to_s
11
11
  ip = config.get((hostname + "_ip").to_sym)
12
- username = config.get((hostname + "_username").to_sym).to_s
13
- password = config.get((hostname + "_password").to_sym).to_s
12
+ port = config.get((hostname + "_port").to_sym)
13
+ mode = true
14
+ if port.to_i == 0
15
+ port = "23"
16
+ mode = false
17
+ end
14
18
  text = ""
19
+ exitcode = -1
15
20
  begin
16
21
  if sessions[hostname].nil? || sessions[hostname] == :ok
17
22
  h = Net::Telnet.new(
18
23
  "Host" => ip,
24
+ "Port" => port,
25
+ "Telnetmode" => mode,
19
26
  "Timeout" => 30,
20
- "Prompt" => /login|teuton|[$%#>]|PC1>/
27
+ "Prompt" => /login|teuton|[$%#>]/
21
28
  )
22
29
  # "Prompt" => Regexp.new(username[1, 40]))
23
30
  # "Prompt" => /[$%#>] \z/n)
24
- h.login(username, password)
31
+ unless mode
32
+ username = config.get((hostname + "_username").to_sym).to_s
33
+ password = config.get((hostname + "_password").to_sym).to_s
34
+ h.login(username, password)
35
+ end
25
36
  h.cmd(action[:command]) { |i| text << i }
26
37
  h.close
27
38
  sessions[hostname] = :ok
39
+ exitcode = 0
28
40
  else
29
- text = "TELNET: NO CONNECTION!"
41
+ text = "Telnet: NO CONNECTION!"
30
42
  end
31
43
  rescue Net::OpenTimeout
32
44
  sessions[hostname] = :nosession
33
45
  conn_status[hostname] = :open_timeout
34
- # verbose Rainbow(Application.instance.letter[:error]).red.bright
35
46
  log(" ExceptionType=<Net::OpenTimeout> doing <telnet #{ip}>", :error)
36
47
  log(" └── Revise host IP!", :warn)
37
48
  rescue Net::ReadTimeout
38
49
  sessions[hostname] = :nosession
39
50
  conn_status[hostname] = :read_timeout
40
- # verbose Rainbow(Application.instance.letter[:error]).red.bright
41
51
  log(" ExceptionType=<Net::ReadTimeout> doing <telnet #{ip}>", :error)
42
52
  rescue => e
43
53
  sessions[hostname] = :nosession
44
54
  conn_status[hostname] = :error
45
- # verbose Rainbow(Application.instance.letter[:error]).red.bright
46
55
  log(" ExceptionType=<#{e.class}> doing telnet on <#{username}@#{ip}>" \
47
56
  " exec: #{action[:command]}", :error)
48
57
  log(" └── username=<#{username}>, password=<#{password}>," \
49
58
  " ip=<#{ip}>, HOSTID=<#{hostname}>", :warn)
50
59
  end
51
- output = encode_and_split(action[:encoding], text)
52
- result.exitcode = -1
53
- result.content = output
54
- result.content.compact!
60
+ result.exitcode = exitcode
61
+ result.content = encode_and_split(action[:encoding], text)
55
62
  end
56
63
  end
@@ -34,11 +34,11 @@ class Case
34
34
 
35
35
  def init(id)
36
36
  @id = id.to_sym
37
- @ip = @config.get("#{@id}_ip".to_sym).to_s
38
- @username = @config.get("#{@id}_username".to_sym).to_s
39
- @password = @config.get("#{@id}_password".to_sym).to_s
37
+ @ip = @config.get(:"#{@id}_ip").to_s
38
+ @username = @config.get(:"#{@id}_username").to_s
39
+ @password = @config.get(:"#{@id}_password").to_s
40
40
 
41
- @protocol = @config.get("#{@id}_protocol".to_sym).to_s.downcase
41
+ @protocol = @config.get(:"#{@id}_protocol").to_s.downcase
42
42
  if @protocol == "nodata"
43
43
  @protocol = if @ip == "localhost" || @ip.start_with?("127.0.0.")
44
44
  "local"
@@ -47,12 +47,12 @@ class Case
47
47
  end
48
48
  end
49
49
 
50
- @port = @config.get("#{@id}_port".to_sym).to_i
50
+ @port = @config.get(:"#{@id}_port").to_i
51
51
  if @port.zero?
52
52
  default = {"local" => 0, "ssh" => 22, "telnet" => 23}
53
53
  @port = default[@protocol]
54
54
  end
55
- @route = @config.get("#{@id}_route".to_sym)
55
+ @route = @config.get(:"#{@id}_route")
56
56
  end
57
57
 
58
58
  def init_default
@@ -6,7 +6,7 @@ require_relative "run"
6
6
  module CheckDSL
7
7
  def log(text = "", type = :info)
8
8
  @stats[:logs] += 1
9
- prefix = type == :info ? "" : "#{type.to_s.upcase}: "
9
+ prefix = (type == :info) ? "" : "#{type.to_s.upcase}: "
10
10
  Logger.info " log #{prefix}" + text.to_s
11
11
  end
12
12
 
@@ -61,7 +61,7 @@ class ShowCheck
61
61
  end
62
62
  if Project.value[:macros].size.positive?
63
63
  st.add_row ["Macros", Project.value[:macros].size]
64
- Project.value[:macros].each_key { st.add_row ["", _1] }
64
+ Project.value[:macros].each_key { st.add_row ["", it] }
65
65
  end
66
66
  st.add_row ["Groups", @stats[:groups]]
67
67
  st.add_row ["Targets", @stats[:targets]]
@@ -87,11 +87,11 @@ class ShowCheck
87
87
 
88
88
  if @stats[:sets].size.positive?
89
89
  st.add_row ["Sets", @stats[:sets].size]
90
- @stats[:sets].each { st.add_row ["", _1] }
90
+ @stats[:sets].each { st.add_row ["", it] }
91
91
  end
92
92
  if @stats[:uploads].size.positive?
93
93
  st.add_row ["Uploads", @stats[:uploads].size]
94
- @stats[:uploads].each { st.add_row ["", _1] }
94
+ @stats[:uploads].each { st.add_row ["", it] }
95
95
  end
96
96
  end
97
97
  Logger.info my_screen_table.to_s + "\n"
@@ -114,7 +114,7 @@ class ShowCheck
114
114
  script_vars << k.to_s + "_password"
115
115
  end
116
116
  end
117
- @stats[:gets].keys.each { script_vars << _1 }
117
+ @stats[:gets].keys.each { script_vars << it }
118
118
  script_vars
119
119
  end
120
120
  end
@@ -9,8 +9,8 @@ class Case
9
9
  # READ: @config
10
10
  # WRITE: @action, @result, @session
11
11
  def run_cmd_on(host)
12
- protocol = @config.get("#{host}_protocol".to_sym)
13
- ip = @config.get("#{host}_ip".to_sym)
12
+ protocol = @config.get(:"#{host}_protocol")
13
+ ip = @config.get(:"#{host}_ip")
14
14
 
15
15
  if protocol.to_s.downcase == "local" || host.to_s == "localhost"
16
16
  # Protocol force => local
@@ -59,24 +59,24 @@ class Case
59
59
  def run_cmd_remote_ssh(input_hostname)
60
60
  @action[:conn_type] = :ssh
61
61
  hostname = input_hostname.to_s
62
- ip = @config.get("#{hostname}_ip".to_sym).to_s
63
- username = @config.get("#{hostname}_username".to_sym).to_s
64
- password = @config.get("#{hostname}_password".to_sym).to_s
65
- port = @config.get("#{hostname}_port".to_sym).to_i
62
+ ip = @config.get(:"#{hostname}_ip").to_s
63
+ username = @config.get(:"#{hostname}_username").to_s
64
+ password = @config.get(:"#{hostname}_password").to_s
65
+ port = @config.get(:"#{hostname}_port").to_i
66
66
  port = 22 if port.zero?
67
67
 
68
- unless @config.get("#{hostname}_route".to_sym) == "NODATA"
68
+ unless @config.get(:"#{hostname}_route") == "NODATA"
69
69
  # Reconfigure command with gateway. Example host1_route: IP.
70
70
  # hostname2 = hostname ¿not used?
71
71
  ip2 = ip
72
72
  username2 = username
73
73
  password2 = password
74
74
  command2 = @action[:command]
75
- hostname = @config.get("#{hostname}_route".to_sym)
76
- ip = @config.get("#{hostname}_ip".to_sym).to_s
77
- username = @config.get("#{hostname}_username".to_sym).to_s
78
- password = @config.get("#{hostname}_password".to_sym).to_s
79
- ostype = @config.get("#{hostname}_ostype".to_sym).to_s
75
+ hostname = @config.get(:"#{hostname}_route")
76
+ ip = @config.get(:"#{hostname}_ip").to_s
77
+ username = @config.get(:"#{hostname}_username").to_s
78
+ password = @config.get(:"#{hostname}_password").to_s
79
+ ostype = @config.get(:"#{hostname}_ostype").to_s
80
80
 
81
81
  @action[:command] = if ostype.downcase.start_with? "win"
82
82
  "echo y | plink #{username2}@#{ip2} -ssh -pw #{password2} \"#{command2}\""
@@ -14,11 +14,11 @@ module ReadmeDSL
14
14
  def gett(value)
15
15
  a = get(value)
16
16
  if @cases_params.include? value
17
- "[#{value}](#required-params)"
17
+ "[" + value + "](#required-params)"
18
18
  elsif @setted_params[value]
19
- "[#{value}](#created-params)"
19
+ "[" + value + "](#created-params)"
20
20
  elsif @global_params.include? value
21
- "[#{a}](#global-params)"
21
+ "[" + a + "](#global-params)"
22
22
  end
23
23
  a
24
24
  end
@@ -2,21 +2,21 @@ module ReadmeDSL
2
2
  def goto(host = :localhost, args = {})
3
3
  unless host == :localhost
4
4
  b = {}
5
- a = "#{host}_ip".to_sym
5
+ a = :"#{host}_ip"
6
6
  if @config[:global][a].nil? && !@setted_params.include?(a)
7
7
  @cases_params << a
8
8
  end
9
9
  b[:ip] = @config[:global][a] if @config[:global][a]
10
10
  b[:ip] = @setted_params[a] if @setted_params[a]
11
11
 
12
- a = "#{host}_username".to_sym
12
+ a = :"#{host}_username"
13
13
  if @config[:global][a].nil? && !@setted_params.include?(a)
14
14
  @cases_params << a
15
15
  end
16
16
  b[:username] = @config[:global][a] if @config[:global][a]
17
17
  b[:username] = @setted_params[a] if @setted_params[a]
18
18
 
19
- a = "#{host}_password".to_sym
19
+ a = :"#{host}_password"
20
20
  if @config[:global][a].nil? && !@setted_params.include?(a)
21
21
  @cases_params << a
22
22
  end
@@ -71,8 +71,8 @@ class Readme
71
71
  unless @required_hosts.empty?
72
72
  puts Lang.get(:hosts)
73
73
  puts "\n"
74
- puts "| ID | Host | Configuration |"
75
- puts "| --- | --- | --- |"
74
+ puts "| ID | Host | Configuration |"
75
+ puts "| --- | ---- | ------------- |"
76
76
  @required_hosts.each_pair do |k, v|
77
77
  c = []
78
78
  v.each_pair { |k2, v2| c << "#{k2}=#{v2}" }
@@ -123,15 +123,15 @@ class Readme
123
123
  puts Lang.get(:global_params)
124
124
  puts "\n"
125
125
  puts "| Param | Value |"
126
- puts "| --- | --- |"
126
+ puts "| ----- | ----- |"
127
127
  @global_params.each_pair { |k, v| puts "|#{k}|#{v}|" }
128
128
  end
129
129
  if @setted_params.size.positive?
130
130
  puts Lang.get(:created_params)
131
131
  puts "\n"
132
- puts "| Param | Value |"
133
- puts "| --- | --- |"
134
- @setted_params.each_pair { |k, v| puts "|#{k}|#{v}|" }
132
+ puts "| Param |"
133
+ puts "| ----- |"
134
+ @setted_params.each_pair { |k, v| puts "|#{k}|" }
135
135
  end
136
136
  end
137
137
  end
@@ -3,7 +3,7 @@ require_relative "../../../utils/project"
3
3
 
4
4
  class ArrayFormatter < BaseFormatter
5
5
  def initialize(report)
6
- super(report)
6
+ super
7
7
  @data = {}
8
8
  end
9
9
 
@@ -3,7 +3,7 @@ require_relative "yaml"
3
3
 
4
4
  class HTMLFormatter < YAMLFormatter
5
5
  def initialize(report)
6
- super(report)
6
+ super
7
7
  @ext = "html"
8
8
  @data = {}
9
9
  basedir = File.join(File.dirname(__FILE__), "..", "..", "..")
@@ -1,9 +1,10 @@
1
- require "json/pure"
1
+ # require "json/pure"
2
+ require "json"
2
3
  require_relative "array"
3
4
 
4
5
  class JSONFormatter < ArrayFormatter
5
6
  def initialize(report)
6
- super(report)
7
+ super
7
8
  @ext = "json"
8
9
  end
9
10
 
@@ -3,7 +3,7 @@ require_relative "../../../version"
3
3
 
4
4
  class XMLFormatter < BaseFormatter
5
5
  def initialize(report)
6
- super(report)
6
+ super
7
7
  @ext = "xml"
8
8
  end
9
9
 
@@ -3,7 +3,7 @@ require_relative "array"
3
3
 
4
4
  class YAMLFormatter < ArrayFormatter
5
5
  def initialize(report)
6
- super(report)
6
+ super
7
7
  @ext = "yaml"
8
8
  end
9
9
 
@@ -2,7 +2,7 @@ require_relative "resume/array"
2
2
 
3
3
  class MoodleCSVFormatter < ResumeArrayFormatter
4
4
  def initialize(report)
5
- super(report)
5
+ super
6
6
  @ext = "csv"
7
7
  @data = {}
8
8
  end
@@ -3,7 +3,7 @@ require_relative "../../../utils/project"
3
3
 
4
4
  class ResumeArrayFormatter < BaseFormatter
5
5
  def initialize(report)
6
- super(report)
6
+ super
7
7
  @data = {}
8
8
  end
9
9
 
@@ -4,7 +4,7 @@ require_relative "yaml"
4
4
 
5
5
  class ResumeHTMLFormatter < ResumeYAMLFormatter
6
6
  def initialize(report)
7
- super(report)
7
+ super
8
8
  @ext = "html"
9
9
  @data = {}
10
10
  basedir = File.join(File.dirname(__FILE__), "..", "..", "..")
@@ -1,9 +1,10 @@
1
- require "json/pure"
1
+ # require "json/pure"
2
+ require "json"
2
3
  require_relative "array"
3
4
 
4
5
  class ResumeJSONFormatter < ResumeArrayFormatter
5
6
  def initialize(report)
6
- super(report)
7
+ super
7
8
  @ext = "json"
8
9
  @data = {}
9
10
  end
@@ -2,7 +2,7 @@ require_relative "array"
2
2
 
3
3
  class ResumeYAMLFormatter < ResumeArrayFormatter
4
4
  def initialize(report)
5
- super(report)
5
+ super
6
6
  @ext = "yaml"
7
7
  @data = {}
8
8
  end
@@ -28,7 +28,7 @@ class Report
28
28
  report = Report.new
29
29
  attrs = %i[id filename output_dir head lines tail format]
30
30
  attrs.each do |attr|
31
- attr_set = "#{attr}=".to_sym
31
+ attr_set = :"#{attr}="
32
32
  report.send(attr_set, send(attr).clone)
33
33
  end
34
34
 
@@ -42,7 +42,7 @@ class Report
42
42
 
43
43
  def export_resume(options)
44
44
  format = options[:format]
45
- @format = "resume_#{format}".to_sym
45
+ @format = :"resume_#{format}"
46
46
  options[:format] = @format
47
47
  filepath = File.join(@output_dir, @filename)
48
48
  Formatter.call(self, options, filepath)
@@ -1,5 +1,6 @@
1
+ # require "json/pure"
2
+ require "json"
1
3
  require "yaml"
2
- require "json/pure"
3
4
 
4
5
  ##
5
6
  # Functions that read data from ConfigFile using YAML or JSON formats
@@ -1,5 +1,5 @@
1
1
  module Teuton
2
- VERSION = "2.9.3"
2
+ VERSION = "2.9.5"
3
3
  APPNAME = "teuton"
4
4
  GEMNAME = "teuton"
5
5
  DOCKERNAME = "dvarrui/#{GEMNAME}"
data/lib/teuton.rb CHANGED
@@ -22,7 +22,6 @@ module Teuton
22
22
  end
23
23
 
24
24
  def self.run(projectpath, options = {})
25
- # Application.instance.add_input_params(projectpath, options)
26
25
  Project.add_input_params(projectpath, options)
27
26
  require_dsl_and_script("teuton/case_manager/dsl") # Define DSL
28
27
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: teuton
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.9.3
4
+ version: 2.9.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Vargas Ruiz
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2025-04-02 00:00:00.000000000 Z
10
+ date: 2025-05-14 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rainbow
@@ -43,14 +43,14 @@ dependencies:
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '7.2'
46
+ version: '7.3'
47
47
  type: :runtime
48
48
  prerelease: false
49
49
  version_requirements: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '7.2'
53
+ version: '7.3'
54
54
  - !ruby/object:Gem::Dependency
55
55
  name: net-telnet
56
56
  requirement: !ruby/object:Gem::Requirement
@@ -99,14 +99,14 @@ dependencies:
99
99
  requirements:
100
100
  - - "~>"
101
101
  - !ruby/object:Gem::Version
102
- version: '3.0'
102
+ version: '4.0'
103
103
  type: :runtime
104
104
  prerelease: false
105
105
  version_requirements: !ruby/object:Gem::Requirement
106
106
  requirements:
107
107
  - - "~>"
108
108
  - !ruby/object:Gem::Version
109
- version: '3.0'
109
+ version: '4.0'
110
110
  description: |2
111
111
  Intrastructure test, useful for:
112
112
  (1) Sysadmin teachers to evaluate students remote machines.
@@ -142,6 +142,10 @@ extra_rdoc_files:
142
142
  - docs/dsl/set.md
143
143
  - docs/dsl/show.md
144
144
  - docs/dsl/target.md
145
+ - docs/es/README.md
146
+ - docs/es/aprender/01-cmd_new.md
147
+ - docs/es/aprender/02-target.md
148
+ - docs/es/aprender/README.md
145
149
  - docs/es/exit_code.md
146
150
  - docs/es/guess_os.md
147
151
  - docs/ideas/Challenge-Server-Project.md
@@ -207,6 +211,10 @@ files:
207
211
  - docs/dsl/set.md
208
212
  - docs/dsl/show.md
209
213
  - docs/dsl/target.md
214
+ - docs/es/README.md
215
+ - docs/es/aprender/01-cmd_new.md
216
+ - docs/es/aprender/02-target.md
217
+ - docs/es/aprender/README.md
210
218
  - docs/es/exit_code.md
211
219
  - docs/es/guess_os.md
212
220
  - docs/ideas/Challenge-Server-Project.md