@learnpack/learnpack 5.0.7 → 5.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. package/README.md +17 -17
  2. package/bin/run +17 -17
  3. package/bin/run.cmd +3 -3
  4. package/lib/commands/audit.js +34 -22
  5. package/lib/commands/clean.js +3 -3
  6. package/lib/commands/download.js +3 -3
  7. package/lib/commands/login.js +3 -3
  8. package/lib/commands/logout.js +3 -3
  9. package/lib/managers/config/index.d.ts +10 -0
  10. package/lib/managers/config/index.js +3 -1
  11. package/oclif.manifest.json +1 -1
  12. package/package.json +152 -152
  13. package/src/commands/audit.ts +449 -443
  14. package/src/commands/clean.ts +29 -29
  15. package/src/commands/download.ts +61 -61
  16. package/src/commands/login.ts +42 -42
  17. package/src/commands/logout.ts +43 -43
  18. package/src/commands/publish.ts +249 -249
  19. package/src/commands/test.ts +85 -85
  20. package/src/index.ts +1 -1
  21. package/src/managers/config/allowed_files.ts +29 -29
  22. package/src/managers/config/index.ts +6 -4
  23. package/src/managers/gitpod.ts +84 -84
  24. package/src/managers/server/index.ts +78 -78
  25. package/src/managers/telemetry.ts +353 -353
  26. package/src/managers/test.ts +83 -83
  27. package/src/models/audit.ts +16 -16
  28. package/src/models/config-manager.ts +23 -23
  29. package/src/models/counter.ts +11 -11
  30. package/src/models/errors.ts +22 -22
  31. package/src/models/exercise-obj.ts +29 -29
  32. package/src/models/file.ts +5 -5
  33. package/src/models/findings.ts +18 -18
  34. package/src/models/flags.ts +10 -10
  35. package/src/models/front-matter.ts +11 -11
  36. package/src/models/gitpod-data.ts +19 -19
  37. package/src/models/language.ts +4 -4
  38. package/src/models/package.ts +7 -7
  39. package/src/models/plugin-config.ts +17 -17
  40. package/src/models/success-types.ts +1 -1
  41. package/src/plugin/command/compile.ts +17 -17
  42. package/src/plugin/command/test.ts +30 -30
  43. package/src/plugin/index.ts +6 -6
  44. package/src/plugin/plugin.ts +94 -94
  45. package/src/plugin/utils.ts +87 -87
  46. package/src/types/node-fetch.d.ts +1 -1
  47. package/src/ui/download.ts +71 -71
  48. package/src/utils/BaseCommand.ts +48 -48
  49. package/src/utils/SessionCommand.ts +43 -43
  50. package/src/utils/audit.ts +393 -393
  51. package/src/utils/errors.ts +117 -117
  52. package/src/utils/exercisesQueue.ts +51 -51
  53. package/src/utils/fileQueue.ts +199 -199
  54. package/src/utils/misc.ts +23 -23
  55. package/src/utils/osOperations.ts +79 -79
  56. package/src/utils/templates/gitignore.txt +19 -19
  57. package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.es.md +24 -24
  58. package/src/utils/templates/incremental/.learn/exercises/01-hello-world/README.md +24 -24
  59. package/src/utils/templates/incremental/.vscode/schema.json +121 -121
  60. package/src/utils/templates/incremental/.vscode/settings.json +13 -13
  61. package/src/utils/templates/incremental/README.ejs +4 -4
  62. package/src/utils/templates/incremental/README.es.ejs +4 -4
  63. package/src/utils/templates/isolated/.vscode/schema.json +121 -121
  64. package/src/utils/templates/isolated/.vscode/settings.json +13 -13
  65. package/src/utils/templates/isolated/README.ejs +4 -4
  66. package/src/utils/templates/isolated/README.es.ejs +4 -4
  67. package/src/utils/templates/no-grading/README.ejs +4 -4
  68. package/src/utils/templates/no-grading/README.es.ejs +4 -4
  69. package/src/utils/validators.ts +18 -18
  70. package/src/utils/watcher.ts +27 -27
@@ -1,249 +1,249 @@
1
- /* eslint-disable arrow-parens */
2
- /* eslint-disable unicorn/no-array-for-each */
3
- import { flags } from "@oclif/command"
4
- import SessionCommand from "../utils/SessionCommand"
5
- import SessionManager from "../managers/session"
6
- import * as fs from "fs"
7
- import * as path from "path"
8
- import * as archiver from "archiver"
9
- import axios from "axios"
10
- import FormData = require("form-data")
11
- import Console from "../utils/console"
12
- import {
13
- decompress,
14
- downloadEditor,
15
- checkIfDirectoryExists,
16
- } from "../managers/file"
17
-
18
- const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
19
- // const RIGOBOT_HOST =
20
- // "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
21
- const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
22
-
23
- export default class BuildCommand extends SessionCommand {
24
- static description =
25
- "Builds the project by copying necessary files and directories into a zip file"
26
-
27
- static flags = {
28
- help: flags.help({ char: "h" }),
29
- }
30
-
31
- async init() {
32
- const { flags } = this.parse(BuildCommand)
33
- await this.initSession(flags)
34
- }
35
-
36
- async run() {
37
- const buildDir = path.join(process.cwd(), "build")
38
- // this.configManager?.clean()
39
-
40
- const configObject = this.configManager?.get()
41
- // Console.success("Package cleaned successfully, ready to publish")
42
-
43
- if (configObject) {
44
- // build exerises
45
- Console.debug("Building exercises")
46
- this.configManager?.buildIndex()
47
- }
48
-
49
- let sessionPayload = await SessionManager.getPayload()
50
- if (!sessionPayload || !sessionPayload.rigobot) {
51
- Console.error("You must be logged in to upload a LearnPack package")
52
- try {
53
- sessionPayload = await SessionManager.login()
54
- } catch (error) {
55
- Console.error("Error trying to authenticate")
56
- Console.error((error as TypeError).message || (error as string))
57
- }
58
- }
59
-
60
- const rigoToken = sessionPayload.rigobot.key
61
- // const rigoToken = "417d612d226a1606ad3a4e94b1881a9f0124b667"
62
-
63
- // Read learn.json to get the slug
64
- const learnJsonPath = path.join(process.cwd(), "learn.json")
65
- if (!fs.existsSync(learnJsonPath)) {
66
- this.error("learn.json not found")
67
- }
68
-
69
- const learnJson = JSON.parse(fs.readFileSync(learnJsonPath, "utf-8"))
70
-
71
- const zipFilePath = path.join(process.cwd(), `${learnJson.slug}.zip`)
72
-
73
- // Ensure build directory exists
74
- if (!fs.existsSync(buildDir)) {
75
- fs.mkdirSync(buildDir)
76
- }
77
-
78
- if (configObject) {
79
- const { config } = configObject
80
- const appAlreadyExists = checkIfDirectoryExists(`${config?.dirPath}/_app`)
81
-
82
- if (!appAlreadyExists) {
83
- // download app and decompress
84
- await downloadEditor(
85
- config?.editor.version,
86
- `${config?.dirPath}/app.tar.gz`
87
- )
88
-
89
- Console.info("Decompressing LearnPack UI, this may take a minute...")
90
- await decompress(
91
- `${config?.dirPath}/app.tar.gz`,
92
- `${config?.dirPath}/_app/`
93
- )
94
- }
95
- }
96
-
97
- // Copy config.json
98
- const configPath = path.join(process.cwd(), ".learn", "config.json")
99
- if (fs.existsSync(configPath)) {
100
- fs.copyFileSync(configPath, path.join(buildDir, "config.json"))
101
- } else {
102
- this.error("config.json not found")
103
- }
104
-
105
- // Copy .learn/assets directory, if it exists else create it
106
- const assetsDir = path.join(process.cwd(), ".learn", "assets")
107
- if (fs.existsSync(assetsDir)) {
108
- this.copyDirectory(assetsDir, path.join(buildDir, ".learn", "assets"))
109
- } else {
110
- fs.mkdirSync(path.join(buildDir, ".learn", "assets"), { recursive: true })
111
- }
112
-
113
- // Copy .learn/_app directory files to the same level as config.json
114
- const appDir = path.join(process.cwd(), ".learn", "_app")
115
- if (fs.existsSync(appDir)) {
116
- this.copyDirectory(appDir, buildDir)
117
- } else {
118
- this.error(".learn/_app directory not found")
119
- }
120
-
121
- // After copying the _app directory
122
- const indexHtmlPath = path.join(appDir, "index.html")
123
- const buildIndexHtmlPath = path.join(buildDir, "index.html")
124
-
125
- if (fs.existsSync(indexHtmlPath)) {
126
- let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8")
127
-
128
- const description = learnJson.description.us || "LearnPack is awesome!"
129
- const title =
130
- learnJson.title.us || "LearnPack: Interactive Learning as a Service"
131
-
132
- const previewUrl =
133
- learnJson.preview ||
134
- "https://raw.githubusercontent.com/learnpack/ide/refs/heads/master/public/learnpack.svg"
135
- // Replace placeholders and the <title>Old title </title> tag for a new tag with the title
136
- indexHtmlContent = indexHtmlContent
137
- .replace(/{{description}}/g, description)
138
- .replace(/<title>.*<\/title>/, `<title>${title}</title>`)
139
- .replace(/{{title}}/g, title)
140
- .replace(/{{preview}}/g, previewUrl)
141
-
142
- // Write the modified content to the build directory
143
- fs.writeFileSync(buildIndexHtmlPath, indexHtmlContent)
144
- } else {
145
- this.error("index.html not found in _app directory")
146
- }
147
-
148
- // Copy exercises directory
149
- const exercisesDir = path.join(process.cwd(), "exercises")
150
- const learnExercisesDir = path.join(process.cwd(), ".learn", "exercises")
151
-
152
- if (fs.existsSync(exercisesDir)) {
153
- this.copyDirectory(exercisesDir, path.join(buildDir, "exercises"))
154
- } else if (fs.existsSync(learnExercisesDir)) {
155
- this.copyDirectory(learnExercisesDir, path.join(buildDir, "exercises"))
156
- } else {
157
- this.error("exercises directory not found in either location")
158
- }
159
-
160
- // Copy learn.json
161
- fs.copyFileSync(learnJsonPath, path.join(buildDir, "learn.json"))
162
-
163
- // Create zip file
164
- const output = fs.createWriteStream(zipFilePath)
165
- const archive = archiver("zip", {
166
- zlib: { level: 9 },
167
- })
168
-
169
- output.on("close", async () => {
170
- this.log(
171
- `Build completed: ${zipFilePath} (${archive.pointer()} total bytes)`
172
- )
173
- // Remove build directory after zip is created
174
- // this.removeDirectory(buildDir)
175
- Console.debug("Zip file saved in project root")
176
-
177
- const formData = new FormData()
178
- formData.append("file", fs.createReadStream(zipFilePath))
179
- formData.append("config", JSON.stringify(learnJson))
180
-
181
- try {
182
- const res = await axios.post(uploadZipEndpont, formData, {
183
- headers: {
184
- ...formData.getHeaders(),
185
- Authorization: `Token ${rigoToken}`,
186
- },
187
- })
188
- console.log(res.data)
189
- // Remove the zip file after uploading
190
- fs.unlinkSync(zipFilePath)
191
- } catch (error) {
192
- if (axios.isAxiosError(error)) {
193
- if (error.response && error.response.status === 403) {
194
- console.error("Error 403:", error.response.data.error)
195
- } else if (error.response && error.response.status === 400) {
196
- console.error(error.response.data.error)
197
- } else {
198
- console.error("Error uploading file:", error)
199
- }
200
- } else {
201
- console.error("Error uploading file:", error)
202
- }
203
-
204
- fs.unlinkSync(zipFilePath)
205
- }
206
- })
207
-
208
- archive.on("error", (err: any) => {
209
- throw err
210
- })
211
-
212
- archive.pipe(output)
213
- archive.directory(buildDir, false)
214
- await archive.finalize()
215
- }
216
-
217
- copyDirectory(src: string, dest: string) {
218
- if (!fs.existsSync(dest)) {
219
- fs.mkdirSync(dest, { recursive: true })
220
- }
221
-
222
- const entries = fs.readdirSync(src, { withFileTypes: true })
223
-
224
- for (const entry of entries) {
225
- const srcPath = path.join(src, entry.name)
226
- const destPath = path.join(dest, entry.name)
227
-
228
- if (entry.isDirectory()) {
229
- this.copyDirectory(srcPath, destPath)
230
- } else {
231
- fs.copyFileSync(srcPath, destPath)
232
- }
233
- }
234
- }
235
-
236
- removeDirectory(dir: string) {
237
- if (fs.existsSync(dir)) {
238
- fs.readdirSync(dir).forEach((file) => {
239
- const currentPath = path.join(dir, file)
240
- if (fs.lstatSync(currentPath).isDirectory()) {
241
- this.removeDirectory(currentPath)
242
- } else {
243
- fs.unlinkSync(currentPath)
244
- }
245
- })
246
- fs.rmdirSync(dir)
247
- }
248
- }
249
- }
1
+ /* eslint-disable arrow-parens */
2
+ /* eslint-disable unicorn/no-array-for-each */
3
+ import { flags } from "@oclif/command"
4
+ import SessionCommand from "../utils/SessionCommand"
5
+ import SessionManager from "../managers/session"
6
+ import * as fs from "fs"
7
+ import * as path from "path"
8
+ import * as archiver from "archiver"
9
+ import axios from "axios"
10
+ import FormData = require("form-data")
11
+ import Console from "../utils/console"
12
+ import {
13
+ decompress,
14
+ downloadEditor,
15
+ checkIfDirectoryExists,
16
+ } from "../managers/file"
17
+
18
+ const RIGOBOT_HOST = "https://rigobot.herokuapp.com"
19
+ // const RIGOBOT_HOST =
20
+ // "https://8000-charlytoc-rigobot-bmwdeam7cev.ws-us116.gitpod.io"
21
+ const uploadZipEndpont = RIGOBOT_HOST + "/v1/learnpack/upload"
22
+
23
+ export default class BuildCommand extends SessionCommand {
24
+ static description =
25
+ "Builds the project by copying necessary files and directories into a zip file"
26
+
27
+ static flags = {
28
+ help: flags.help({ char: "h" }),
29
+ }
30
+
31
+ async init() {
32
+ const { flags } = this.parse(BuildCommand)
33
+ await this.initSession(flags)
34
+ }
35
+
36
+ async run() {
37
+ const buildDir = path.join(process.cwd(), "build")
38
+ // this.configManager?.clean()
39
+
40
+ const configObject = this.configManager?.get()
41
+ // Console.success("Package cleaned successfully, ready to publish")
42
+
43
+ if (configObject) {
44
+ // build exerises
45
+ Console.debug("Building exercises")
46
+ this.configManager?.buildIndex()
47
+ }
48
+
49
+ let sessionPayload = await SessionManager.getPayload()
50
+ if (!sessionPayload || !sessionPayload.rigobot) {
51
+ Console.error("You must be logged in to upload a LearnPack package")
52
+ try {
53
+ sessionPayload = await SessionManager.login()
54
+ } catch (error) {
55
+ Console.error("Error trying to authenticate")
56
+ Console.error((error as TypeError).message || (error as string))
57
+ }
58
+ }
59
+
60
+ const rigoToken = sessionPayload.rigobot.key
61
+ // const rigoToken = "417d612d226a1606ad3a4e94b1881a9f0124b667"
62
+
63
+ // Read learn.json to get the slug
64
+ const learnJsonPath = path.join(process.cwd(), "learn.json")
65
+ if (!fs.existsSync(learnJsonPath)) {
66
+ this.error("learn.json not found")
67
+ }
68
+
69
+ const learnJson = JSON.parse(fs.readFileSync(learnJsonPath, "utf-8"))
70
+
71
+ const zipFilePath = path.join(process.cwd(), `${learnJson.slug}.zip`)
72
+
73
+ // Ensure build directory exists
74
+ if (!fs.existsSync(buildDir)) {
75
+ fs.mkdirSync(buildDir)
76
+ }
77
+
78
+ if (configObject) {
79
+ const { config } = configObject
80
+ const appAlreadyExists = checkIfDirectoryExists(`${config?.dirPath}/_app`)
81
+
82
+ if (!appAlreadyExists) {
83
+ // download app and decompress
84
+ await downloadEditor(
85
+ config?.editor.version,
86
+ `${config?.dirPath}/app.tar.gz`
87
+ )
88
+
89
+ Console.info("Decompressing LearnPack UI, this may take a minute...")
90
+ await decompress(
91
+ `${config?.dirPath}/app.tar.gz`,
92
+ `${config?.dirPath}/_app/`
93
+ )
94
+ }
95
+ }
96
+
97
+ // Copy config.json
98
+ const configPath = path.join(process.cwd(), ".learn", "config.json")
99
+ if (fs.existsSync(configPath)) {
100
+ fs.copyFileSync(configPath, path.join(buildDir, "config.json"))
101
+ } else {
102
+ this.error("config.json not found")
103
+ }
104
+
105
+ // Copy .learn/assets directory, if it exists else create it
106
+ const assetsDir = path.join(process.cwd(), ".learn", "assets")
107
+ if (fs.existsSync(assetsDir)) {
108
+ this.copyDirectory(assetsDir, path.join(buildDir, ".learn", "assets"))
109
+ } else {
110
+ fs.mkdirSync(path.join(buildDir, ".learn", "assets"), { recursive: true })
111
+ }
112
+
113
+ // Copy .learn/_app directory files to the same level as config.json
114
+ const appDir = path.join(process.cwd(), ".learn", "_app")
115
+ if (fs.existsSync(appDir)) {
116
+ this.copyDirectory(appDir, buildDir)
117
+ } else {
118
+ this.error(".learn/_app directory not found")
119
+ }
120
+
121
+ // After copying the _app directory
122
+ const indexHtmlPath = path.join(appDir, "index.html")
123
+ const buildIndexHtmlPath = path.join(buildDir, "index.html")
124
+
125
+ if (fs.existsSync(indexHtmlPath)) {
126
+ let indexHtmlContent = fs.readFileSync(indexHtmlPath, "utf-8")
127
+
128
+ const description = learnJson.description.us || "LearnPack is awesome!"
129
+ const title =
130
+ learnJson.title.us || "LearnPack: Interactive Learning as a Service"
131
+
132
+ const previewUrl =
133
+ learnJson.preview ||
134
+ "https://raw.githubusercontent.com/learnpack/ide/refs/heads/master/public/learnpack.svg"
135
+ // Replace placeholders and the <title>Old title </title> tag for a new tag with the title
136
+ indexHtmlContent = indexHtmlContent
137
+ .replace(/{{description}}/g, description)
138
+ .replace(/<title>.*<\/title>/, `<title>${title}</title>`)
139
+ .replace(/{{title}}/g, title)
140
+ .replace(/{{preview}}/g, previewUrl)
141
+
142
+ // Write the modified content to the build directory
143
+ fs.writeFileSync(buildIndexHtmlPath, indexHtmlContent)
144
+ } else {
145
+ this.error("index.html not found in _app directory")
146
+ }
147
+
148
+ // Copy exercises directory
149
+ const exercisesDir = path.join(process.cwd(), "exercises")
150
+ const learnExercisesDir = path.join(process.cwd(), ".learn", "exercises")
151
+
152
+ if (fs.existsSync(exercisesDir)) {
153
+ this.copyDirectory(exercisesDir, path.join(buildDir, "exercises"))
154
+ } else if (fs.existsSync(learnExercisesDir)) {
155
+ this.copyDirectory(learnExercisesDir, path.join(buildDir, "exercises"))
156
+ } else {
157
+ this.error("exercises directory not found in either location")
158
+ }
159
+
160
+ // Copy learn.json
161
+ fs.copyFileSync(learnJsonPath, path.join(buildDir, "learn.json"))
162
+
163
+ // Create zip file
164
+ const output = fs.createWriteStream(zipFilePath)
165
+ const archive = archiver("zip", {
166
+ zlib: { level: 9 },
167
+ })
168
+
169
+ output.on("close", async () => {
170
+ this.log(
171
+ `Build completed: ${zipFilePath} (${archive.pointer()} total bytes)`
172
+ )
173
+ // Remove build directory after zip is created
174
+ // this.removeDirectory(buildDir)
175
+ Console.debug("Zip file saved in project root")
176
+
177
+ const formData = new FormData()
178
+ formData.append("file", fs.createReadStream(zipFilePath))
179
+ formData.append("config", JSON.stringify(learnJson))
180
+
181
+ try {
182
+ const res = await axios.post(uploadZipEndpont, formData, {
183
+ headers: {
184
+ ...formData.getHeaders(),
185
+ Authorization: `Token ${rigoToken}`,
186
+ },
187
+ })
188
+ console.log(res.data)
189
+ // Remove the zip file after uploading
190
+ fs.unlinkSync(zipFilePath)
191
+ } catch (error) {
192
+ if (axios.isAxiosError(error)) {
193
+ if (error.response && error.response.status === 403) {
194
+ console.error("Error 403:", error.response.data.error)
195
+ } else if (error.response && error.response.status === 400) {
196
+ console.error(error.response.data.error)
197
+ } else {
198
+ console.error("Error uploading file:", error)
199
+ }
200
+ } else {
201
+ console.error("Error uploading file:", error)
202
+ }
203
+
204
+ fs.unlinkSync(zipFilePath)
205
+ }
206
+ })
207
+
208
+ archive.on("error", (err: any) => {
209
+ throw err
210
+ })
211
+
212
+ archive.pipe(output)
213
+ archive.directory(buildDir, false)
214
+ await archive.finalize()
215
+ }
216
+
217
+ copyDirectory(src: string, dest: string) {
218
+ if (!fs.existsSync(dest)) {
219
+ fs.mkdirSync(dest, { recursive: true })
220
+ }
221
+
222
+ const entries = fs.readdirSync(src, { withFileTypes: true })
223
+
224
+ for (const entry of entries) {
225
+ const srcPath = path.join(src, entry.name)
226
+ const destPath = path.join(dest, entry.name)
227
+
228
+ if (entry.isDirectory()) {
229
+ this.copyDirectory(srcPath, destPath)
230
+ } else {
231
+ fs.copyFileSync(srcPath, destPath)
232
+ }
233
+ }
234
+ }
235
+
236
+ removeDirectory(dir: string) {
237
+ if (fs.existsSync(dir)) {
238
+ fs.readdirSync(dir).forEach((file) => {
239
+ const currentPath = path.join(dir, file)
240
+ if (fs.lstatSync(currentPath).isDirectory()) {
241
+ this.removeDirectory(currentPath)
242
+ } else {
243
+ fs.unlinkSync(currentPath)
244
+ }
245
+ })
246
+ fs.rmdirSync(dir)
247
+ }
248
+ }
249
+ }
@@ -1,85 +1,85 @@
1
- import Console from "../utils/console"
2
- import SessionCommand from "../utils/SessionCommand"
3
- import socket from "../managers/socket"
4
-
5
- import createServer from "../managers/server"
6
- import ExercisesQueue from "../utils/exercisesQueue"
7
- import { IExercise } from "../models/exercise-obj"
8
-
9
- class TestCommand extends SessionCommand {
10
- async init() {
11
- const { flags } = this.parse(TestCommand)
12
- await this.initSession(flags)
13
- }
14
-
15
- async run() {
16
- const {
17
- args: { exerciseSlug },
18
- } = this.parse(TestCommand)
19
-
20
- // Build exercises index
21
- this.configManager?.buildIndex()
22
-
23
- let exercises: IExercise[] | undefined = []
24
-
25
- // test all exercises
26
- !exerciseSlug ?
27
- (exercises = this.configManager?.getAllExercises()) :
28
- (exercises = [this.configManager!.getExercise(exerciseSlug)])
29
-
30
- const exercisesQueue = new ExercisesQueue(exercises)
31
-
32
- const configObject = this.configManager?.get()
33
-
34
- let hasFailed = false
35
- let failedTestsCount = 0
36
- let successTestsCount = 0
37
- const testsToRunCount = exercisesQueue.size()
38
-
39
- configObject!.config!.testingFinishedCallback = ({ result }) => {
40
- if (result === "failed") {
41
- hasFailed = true
42
- failedTestsCount++
43
- } else {
44
- successTestsCount++
45
- }
46
-
47
- if (exercisesQueue.isEmpty()) {
48
- Console.info(
49
- `${testsToRunCount} test${testsToRunCount > 1 ? "s" : ""} runned`
50
- )
51
- Console.success(
52
- `${successTestsCount} test${successTestsCount > 1 ? "s" : ""} passed`
53
- )
54
- Console.error(
55
- `${failedTestsCount} test${failedTestsCount > 1 ? "s" : ""} failed`
56
- )
57
-
58
- process.exit(hasFailed ? 1 : 0)
59
- } else {
60
- exercisesQueue.pop()!.test!(this.config, config!, socket)
61
- }
62
- }
63
-
64
- const config = configObject?.config
65
-
66
- const server = await createServer(configObject!, this.configManager!, true)
67
-
68
- socket.start(config!, server, true)
69
-
70
- exercisesQueue.pop()!.test!(this.config, config!, socket)
71
- }
72
- }
73
-
74
- TestCommand.description = `Test exercises`
75
-
76
- TestCommand.args = [
77
- {
78
- name: "exerciseSlug",
79
- required: false,
80
- description: "The name of the exercise to test",
81
- hidden: false,
82
- },
83
- ]
84
-
85
- export default TestCommand
1
+ import Console from "../utils/console"
2
+ import SessionCommand from "../utils/SessionCommand"
3
+ import socket from "../managers/socket"
4
+
5
+ import createServer from "../managers/server"
6
+ import ExercisesQueue from "../utils/exercisesQueue"
7
+ import { IExercise } from "../models/exercise-obj"
8
+
9
+ class TestCommand extends SessionCommand {
10
+ async init() {
11
+ const { flags } = this.parse(TestCommand)
12
+ await this.initSession(flags)
13
+ }
14
+
15
+ async run() {
16
+ const {
17
+ args: { exerciseSlug },
18
+ } = this.parse(TestCommand)
19
+
20
+ // Build exercises index
21
+ this.configManager?.buildIndex()
22
+
23
+ let exercises: IExercise[] | undefined = []
24
+
25
+ // test all exercises
26
+ !exerciseSlug ?
27
+ (exercises = this.configManager?.getAllExercises()) :
28
+ (exercises = [this.configManager!.getExercise(exerciseSlug)])
29
+
30
+ const exercisesQueue = new ExercisesQueue(exercises)
31
+
32
+ const configObject = this.configManager?.get()
33
+
34
+ let hasFailed = false
35
+ let failedTestsCount = 0
36
+ let successTestsCount = 0
37
+ const testsToRunCount = exercisesQueue.size()
38
+
39
+ configObject!.config!.testingFinishedCallback = ({ result }) => {
40
+ if (result === "failed") {
41
+ hasFailed = true
42
+ failedTestsCount++
43
+ } else {
44
+ successTestsCount++
45
+ }
46
+
47
+ if (exercisesQueue.isEmpty()) {
48
+ Console.info(
49
+ `${testsToRunCount} test${testsToRunCount > 1 ? "s" : ""} runned`
50
+ )
51
+ Console.success(
52
+ `${successTestsCount} test${successTestsCount > 1 ? "s" : ""} passed`
53
+ )
54
+ Console.error(
55
+ `${failedTestsCount} test${failedTestsCount > 1 ? "s" : ""} failed`
56
+ )
57
+
58
+ process.exit(hasFailed ? 1 : 0)
59
+ } else {
60
+ exercisesQueue.pop()!.test!(this.config, config!, socket)
61
+ }
62
+ }
63
+
64
+ const config = configObject?.config
65
+
66
+ const server = await createServer(configObject!, this.configManager!, true)
67
+
68
+ socket.start(config!, server, true)
69
+
70
+ exercisesQueue.pop()!.test!(this.config, config!, socket)
71
+ }
72
+ }
73
+
74
+ TestCommand.description = `Test exercises`
75
+
76
+ TestCommand.args = [
77
+ {
78
+ name: "exerciseSlug",
79
+ required: false,
80
+ description: "The name of the exercise to test",
81
+ hidden: false,
82
+ },
83
+ ]
84
+
85
+ export default TestCommand
package/src/index.ts CHANGED
@@ -1 +1 @@
1
- export * from '@oclif/command'
1
+ export * from '@oclif/command'