track-cli 3.1.0-rc1 → 4.0.0-rc0
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/esm/_dnt.shims.d.ts +1 -1
- package/esm/_dnt.shims.js +1 -0
- package/esm/src/action/add.js +8 -8
- package/esm/src/action/clone.js +46 -76
- package/esm/src/action/lang.js +11 -16
- package/esm/src/action/pull.js +8 -8
- package/esm/src/action/remove.js +8 -6
- package/esm/src/action/reset.js +9 -10
- package/esm/src/action/run.js +13 -16
- package/esm/src/action/status.js +6 -3
- package/esm/src/meta.d.ts +1 -1
- package/esm/src/meta.js +1 -1
- package/esm/src/shared/config.d.ts +16 -9
- package/esm/src/shared/config.js +0 -3
- package/esm/src/shared/errors.d.ts +1 -1
- package/esm/src/shared/errors.js +4 -3
- package/esm/src/shared/mod.d.ts +10 -10
- package/esm/src/shared/mod.js +73 -93
- package/esm/src/shared/types.d.ts +141 -11
- package/esm/src/shared/types.js +100 -1
- package/esm/src/track/client.d.ts +35 -38
- package/esm/src/track/client.js +31 -122
- package/esm/src/track/test.d.ts +32 -0
- package/esm/src/track/test.js +184 -0
- package/esm/src/track/training.d.ts +29 -0
- package/esm/src/track/training.js +149 -0
- package/package.json +1 -1
- package/esm/src/track/types.d.ts +0 -211
- package/esm/src/track/types.js +0 -40
package/esm/_dnt.shims.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ import { fetch, File, FormData, Headers, Request, Response } from "undici";
|
|
|
5
5
|
export { fetch, File, FormData, Headers, Request, Response, type BodyInit, type HeadersInit, type RequestInit, type ResponseInit } from "undici";
|
|
6
6
|
import { alert, confirm, prompt } from "./shim/prompts.js";
|
|
7
7
|
export { alert, confirm, prompt } from "./shim/prompts.js";
|
|
8
|
-
export declare const dntGlobalThis: Omit<typeof globalThis, "
|
|
8
|
+
export declare const dntGlobalThis: Omit<typeof globalThis, "fetch" | "Request" | "Response" | "FormData" | "Headers" | "Deno" | "crypto" | "File" | "alert" | "confirm" | "prompt"> & {
|
|
9
9
|
Deno: typeof Deno;
|
|
10
10
|
crypto: import("@deno/shim-crypto").Crypto;
|
|
11
11
|
fetch: typeof fetch;
|
package/esm/_dnt.shims.js
CHANGED
package/esm/src/action/add.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
-
import { CONFIG_FILE_PATH } from "../shared/config.js";
|
|
2
|
+
import { CONFIG_FILE_PATH, load as loadConfig } from "../shared/config.js";
|
|
3
3
|
import { CantReadFile, NewFilesNotAllowed } from "../shared/errors.js";
|
|
4
4
|
import { pathsToFilenameSet, toNativeStyle } from "../shared/file.js";
|
|
5
|
-
import { getCommonChallengeContext, listFileNames, printWorkingFileSet, } from "../shared/mod.js";
|
|
6
|
-
import { FileListType } from "../
|
|
5
|
+
import { getCommonChallengeContext, listFileNames, printWorkingFileSet, trackClientFromConfig, } from "../shared/mod.js";
|
|
6
|
+
import { FileListType } from "../shared/types.js";
|
|
7
7
|
import * as colors from "../../deps/deno.land/std@0.195.0/fmt/colors.js";
|
|
8
8
|
export async function add(filePaths) {
|
|
9
|
-
|
|
10
|
-
const
|
|
11
|
-
const
|
|
9
|
+
const config = await loadConfig();
|
|
10
|
+
const api = trackClientFromConfig(config);
|
|
11
|
+
const [codingContext, _challenge] = await getCommonChallengeContext(config, api);
|
|
12
12
|
if (!codingContext.settings.allowNewFile) {
|
|
13
13
|
throw new NewFilesNotAllowed();
|
|
14
14
|
}
|
|
@@ -45,8 +45,8 @@ export async function add(filePaths) {
|
|
|
45
45
|
console.log(`\t${toNativeStyle(path)}`);
|
|
46
46
|
}
|
|
47
47
|
console.log();
|
|
48
|
-
await api.saveFiles(
|
|
49
|
-
const newCodingContext = await api.
|
|
48
|
+
await api.saveFiles(saveFilesRequest);
|
|
49
|
+
const newCodingContext = await api.context();
|
|
50
50
|
printWorkingFileSet(newCodingContext);
|
|
51
51
|
}
|
|
52
52
|
else {
|
package/esm/src/action/clone.js
CHANGED
|
@@ -1,108 +1,78 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
2
|
import * as config from "../shared/config.js";
|
|
3
|
-
import {
|
|
4
|
-
import { downloadChallengeFilesTo,
|
|
5
|
-
import {
|
|
3
|
+
import { LocalCodingNotAllowed, OtherError } from "../shared/errors.js";
|
|
4
|
+
import { downloadChallengeFilesTo, printTimeLeft, tryStartingChallenge, } from "../shared/mod.js";
|
|
5
|
+
import { CloneUrl, TrackApp } from "../shared/types.js";
|
|
6
|
+
import { TestClient } from "../track/test.js";
|
|
7
|
+
import { TrainingClient } from "../track/training.js";
|
|
6
8
|
import { exists } from "../../deps/deno.land/std@0.195.0/fs/mod.js";
|
|
7
9
|
export async function clone(url, options) {
|
|
8
10
|
// console.log(`url: ${url}`);
|
|
9
11
|
// console.log(`target_dir: ${targetDir}`);
|
|
10
12
|
// console.log(`basicAuthUser: ${basicAuthUser}`);
|
|
11
13
|
// console.log(`basicAuthPassword: ${basicAuthPassword}`);
|
|
12
|
-
const
|
|
14
|
+
const cloneUrl = new CloneUrl(url);
|
|
13
15
|
const basicAuth = options?.basicAuthUser
|
|
14
16
|
? {
|
|
15
17
|
username: options?.basicAuthUser,
|
|
16
18
|
password: options?.basicAuthPassword,
|
|
17
19
|
}
|
|
18
20
|
: undefined;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
ensureExamInProgress(applicantExam, webUrl);
|
|
28
|
-
const examSession = await api.getExamSession(applicantExam.id);
|
|
29
|
-
// Determine challenge directory
|
|
30
|
-
const challengePosition = examSession.challengesSets
|
|
31
|
-
.flatMap((set) => set.challenges)
|
|
32
|
-
.findIndex((challenge) => challenge.id === cloneData.challengeId) +
|
|
33
|
-
1;
|
|
34
|
-
const challengeDir = options?.targetDir ||
|
|
35
|
-
`${cloneData.orgName}-challenge-${challengePosition}`;
|
|
36
|
-
const configDir = `${challengeDir}/.track`;
|
|
37
|
-
const configFile = `${configDir}/config.json`;
|
|
38
|
-
const pathExists = await exists(challengeDir);
|
|
39
|
-
if (pathExists) {
|
|
40
|
-
// オリジナルの Track CLI では空ディレクトリなら OK だったが、そのケースで特に便利にならないので、ファイル・ディレクトリが存在したら無条件でエラーに
|
|
41
|
-
throw new ChallengeDirectoryExists(challengeDir);
|
|
21
|
+
let api;
|
|
22
|
+
switch (cloneUrl.app) {
|
|
23
|
+
case TrackApp.Test:
|
|
24
|
+
api = new TestClient(cloneUrl.baseUrl, cloneUrl.orgName, cloneUrl.token, cloneUrl.id, basicAuth);
|
|
25
|
+
break;
|
|
26
|
+
case TrackApp.Training:
|
|
27
|
+
api = new TrainingClient(cloneUrl.baseUrl, cloneUrl.orgName, cloneUrl.token, cloneUrl.id, 0, 0, basicAuth);
|
|
28
|
+
break;
|
|
42
29
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
throw new LocalExamNotAllowed(webUrl);
|
|
30
|
+
await api.authenticate();
|
|
31
|
+
const challenge = await api.startChallengeSession();
|
|
32
|
+
if (!challenge.localCodingAllowed) {
|
|
33
|
+
const webUrl = cloneUrl.toString(); // TODO: Test の場合は clone URL がそのまま受験画面だったけど、Training の場合は?
|
|
34
|
+
throw new LocalCodingNotAllowed(webUrl);
|
|
49
35
|
}
|
|
50
|
-
//
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
// - Change language
|
|
55
|
-
// - Start Challenge
|
|
56
|
-
// - TimeLeft
|
|
57
|
-
// - Context
|
|
58
|
-
// - Presigned
|
|
59
|
-
// - Download files
|
|
60
|
-
// TODO - Print warnings about challenge time limit, having
|
|
61
|
-
// a stable internet connection, and what to do next
|
|
62
|
-
// in the challenge solving process.
|
|
63
|
-
const result = await tryStartingChallenge(challenge, api, applicantExam, resultOpt);
|
|
36
|
+
// Determine challenge directory
|
|
37
|
+
const challengeDir = await createChallengeDir(options?.targetDir ||
|
|
38
|
+
`${cloneUrl.orgName}-challenge-${challenge.challengeId}`);
|
|
39
|
+
const result = await tryStartingChallenge(api, challenge);
|
|
64
40
|
if (!result) {
|
|
65
41
|
throw new OtherError("Expected to have a challenge result after preparing and starting");
|
|
66
42
|
}
|
|
67
|
-
const timeLeft = await api.timeLeft(
|
|
43
|
+
const timeLeft = await api.timeLeft();
|
|
68
44
|
printTimeLeft(timeLeft);
|
|
69
|
-
const codingContext = await api.
|
|
45
|
+
const codingContext = await api.context();
|
|
70
46
|
await dntShim.Deno.mkdir(challengeDir, { recursive: true });
|
|
71
47
|
const showFileDiff = false;
|
|
72
48
|
const includeTarball = true;
|
|
73
|
-
await downloadChallengeFilesTo(codingContext, challengeDir, api,
|
|
74
|
-
const trackConfig = {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
orgName:
|
|
49
|
+
await downloadChallengeFilesTo(codingContext, challengeDir, api, showFileDiff, includeTarball);
|
|
50
|
+
const trackConfig = Object.assign(api.config(), {
|
|
51
|
+
app: cloneUrl.app,
|
|
52
|
+
baseUrl: cloneUrl.baseUrl,
|
|
53
|
+
orgName: cloneUrl.orgName,
|
|
78
54
|
basicAuth: basicAuth,
|
|
79
|
-
|
|
80
|
-
applicantExamId: applicantExam.id,
|
|
81
|
-
challengeId: cloneData.challengeId,
|
|
82
|
-
challengeResultId: result.id,
|
|
55
|
+
token: cloneUrl.token,
|
|
83
56
|
cookies: api.getCookies(),
|
|
84
57
|
programmingLanguage: result.programmingLanguage,
|
|
85
|
-
};
|
|
86
|
-
await config.save(trackConfig, {
|
|
58
|
+
});
|
|
59
|
+
await config.save(trackConfig, {
|
|
60
|
+
path: `${challengeDir}/.track/config.json`,
|
|
61
|
+
});
|
|
87
62
|
console.log();
|
|
88
63
|
console.log(`Challenge downloaded to ${challengeDir}`);
|
|
89
64
|
console.log(`Run 'cd ${challengeDir} && track status' to begin!`);
|
|
90
65
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
66
|
+
async function createChallengeDir(base) {
|
|
67
|
+
let i = 1;
|
|
68
|
+
while (true) {
|
|
69
|
+
const challengeDir = i == 1 ? base : `${base}-${i}`;
|
|
70
|
+
const pathExists = await exists(challengeDir);
|
|
71
|
+
if (pathExists) {
|
|
72
|
+
i++;
|
|
73
|
+
continue;
|
|
74
|
+
}
|
|
75
|
+
await dntShim.Deno.mkdir(challengeDir, { recursive: true });
|
|
76
|
+
return challengeDir;
|
|
97
77
|
}
|
|
98
|
-
return {
|
|
99
|
-
scheme: urlObj.protocol.slice(0, -1),
|
|
100
|
-
host: urlObj.host + (urlObj.port ? ":" + urlObj.port : ""),
|
|
101
|
-
orgName: caps[1],
|
|
102
|
-
examToken: caps[2],
|
|
103
|
-
challengeId: parseInt(caps[3]),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
function getResultFromExamSession(examSession, challengeId) {
|
|
107
|
-
return examSession.results.find((r) => r.challengeId === challengeId);
|
|
108
78
|
}
|
package/esm/src/action/lang.js
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
-
import { save as saveConfig } from "../shared/config.js";
|
|
3
|
-
import { CantChooseLanguage
|
|
4
|
-
import { archiveExistingChallengeFiles, chooseProgrammingLanguage, downloadChallengeFilesTo,
|
|
2
|
+
import { load as loadConfig, save as saveConfig, } from "../shared/config.js";
|
|
3
|
+
import { CantChooseLanguage } from "../shared/errors.js";
|
|
4
|
+
import { archiveExistingChallengeFiles, chooseProgrammingLanguage, downloadChallengeFilesTo, getCommonChallengeContext, trackClientFromConfig, } from "../shared/mod.js";
|
|
5
5
|
export async function lang() {
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const challenge = getChallengeFromExamSession(examSession, codingContext.challengeId) ??
|
|
10
|
-
(() => {
|
|
11
|
-
throw new InvalidChallengeId(codingContext.challengeId);
|
|
12
|
-
})();
|
|
6
|
+
const config = await loadConfig();
|
|
7
|
+
const api = trackClientFromConfig(config);
|
|
8
|
+
const [codingContext, challenge] = await getCommonChallengeContext(config, api);
|
|
13
9
|
if (challenge.programmingLanguages.length === 0) {
|
|
14
10
|
throw new CantChooseLanguage();
|
|
15
11
|
}
|
|
16
|
-
const availableLanguages = (await api.
|
|
12
|
+
const availableLanguages = (await api.languages())
|
|
17
13
|
.filter((pl) => codingContext.programmingLanguages.find((n) => n === pl.value));
|
|
18
14
|
console.log("Your existing code will be archived in this directory and the original challenge code for the new language will be downloaded");
|
|
19
15
|
const shouldContinue = dntShim.confirm("Are you sure you want to continue?");
|
|
@@ -25,14 +21,13 @@ export async function lang() {
|
|
|
25
21
|
console.log("You are already using this language");
|
|
26
22
|
return;
|
|
27
23
|
}
|
|
28
|
-
await api.
|
|
24
|
+
await api.updateLanguage(desiredLanguage.value);
|
|
29
25
|
const currentDir = dntShim.Deno.cwd();
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const newCodingContext = await api.getChallengeCodingContext(config.applicantExamId, config.challengeResultId);
|
|
26
|
+
await archiveExistingChallengeFiles(config.orgName);
|
|
27
|
+
const newCodingContext = await api.context();
|
|
33
28
|
const showFileDiff = false;
|
|
34
29
|
const includeTarball = true;
|
|
35
|
-
await downloadChallengeFilesTo(newCodingContext, currentDir, api,
|
|
30
|
+
await downloadChallengeFilesTo(newCodingContext, currentDir, api, showFileDiff, includeTarball);
|
|
36
31
|
const updatedConfig = Object.assign({}, config, {
|
|
37
32
|
programmingLanguage: desiredLanguage.value,
|
|
38
33
|
});
|
package/esm/src/action/pull.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
-
import { save as saveConfig } from "../shared/config.js";
|
|
3
|
-
import { archiveExistingChallengeFiles, downloadChallengeFilesTo, getCommonChallengeContext, } from "../shared/mod.js";
|
|
2
|
+
import { load as loadConfig, save as saveConfig, } from "../shared/config.js";
|
|
3
|
+
import { archiveExistingChallengeFiles, downloadChallengeFilesTo, getCommonChallengeContext, trackClientFromConfig, } from "../shared/mod.js";
|
|
4
4
|
export async function pull() {
|
|
5
|
-
const
|
|
6
|
-
const
|
|
5
|
+
const config = await loadConfig();
|
|
6
|
+
const api = trackClientFromConfig(config);
|
|
7
|
+
const [codingContext, _challenge] = await getCommonChallengeContext(config, api);
|
|
7
8
|
const configLang = config.programmingLanguage;
|
|
8
|
-
const currentLang =
|
|
9
|
+
const currentLang = codingContext.selectedLanguage;
|
|
9
10
|
const currentDir = dntShim.Deno.cwd();
|
|
10
11
|
if (configLang && currentLang && configLang !== currentLang) {
|
|
11
12
|
console.log("Your programming language has changed elsewhere since you last ran this challenge");
|
|
12
|
-
|
|
13
|
-
await archiveExistingChallengeFiles(config.orgName, challengePosition, { selectedLanguage, challengeDir: currentDir });
|
|
13
|
+
await archiveExistingChallengeFiles(config.orgName);
|
|
14
14
|
const updatedConfig = Object.assign({}, config, {
|
|
15
15
|
programmingLanguage: currentLang,
|
|
16
16
|
});
|
|
@@ -18,5 +18,5 @@ export async function pull() {
|
|
|
18
18
|
}
|
|
19
19
|
const showFileDiff = true;
|
|
20
20
|
const includeTarball = false;
|
|
21
|
-
await downloadChallengeFilesTo(codingContext, currentDir, api,
|
|
21
|
+
await downloadChallengeFilesTo(codingContext, currentDir, api, showFileDiff, includeTarball);
|
|
22
22
|
}
|
package/esm/src/action/remove.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
+
import { load as loadConfig } from "../shared/config.js";
|
|
2
3
|
import { DeleteFilesNotAllowed, OtherError } from "../shared/errors.js";
|
|
3
4
|
import { isEmptyDirectory, pathsToFilenameSet, toNativeStyle, } from "../shared/file.js";
|
|
4
|
-
import { getCommonChallengeContext, listFileNames, printWorkingFileSet, } from "../shared/mod.js";
|
|
5
|
-
import { FileListType } from "../
|
|
5
|
+
import { getCommonChallengeContext, listFileNames, printWorkingFileSet, trackClientFromConfig, } from "../shared/mod.js";
|
|
6
|
+
import { FileListType } from "../shared/types.js";
|
|
6
7
|
import * as colors from "../../deps/deno.land/std@0.195.0/fmt/colors.js";
|
|
7
8
|
export async function remove(filePaths, options) {
|
|
8
|
-
const
|
|
9
|
-
const
|
|
9
|
+
const config = await loadConfig();
|
|
10
|
+
const api = trackClientFromConfig(config);
|
|
11
|
+
const [codingContext, _challenge] = await getCommonChallengeContext(config, api);
|
|
10
12
|
if (!codingContext.settings.allowNewFile) {
|
|
11
13
|
throw new DeleteFilesNotAllowed();
|
|
12
14
|
}
|
|
@@ -35,7 +37,7 @@ export async function remove(filePaths, options) {
|
|
|
35
37
|
addedFiles: filesToKeep,
|
|
36
38
|
updatedFiles: {},
|
|
37
39
|
};
|
|
38
|
-
await api.saveFiles(
|
|
40
|
+
await api.saveFiles(saveFilesRequest);
|
|
39
41
|
await Promise.all(filesToDelete.map((file) => dntShim.Deno.remove(file)))
|
|
40
42
|
.catch((e) => Promise.reject(new OtherError(`An error occurred while deleting files: ${e}`)));
|
|
41
43
|
// For each file to delete, walk the file's parents and delete directories
|
|
@@ -55,7 +57,7 @@ export async function remove(filePaths, options) {
|
|
|
55
57
|
current = parent;
|
|
56
58
|
}
|
|
57
59
|
}
|
|
58
|
-
const newCodingContext = await api.
|
|
60
|
+
const newCodingContext = await api.context();
|
|
59
61
|
printWorkingFileSet(newCodingContext);
|
|
60
62
|
}
|
|
61
63
|
else {
|
package/esm/src/action/reset.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
-
import {
|
|
2
|
+
import { load as loadConfig } from "../shared/config.js";
|
|
3
|
+
import { archiveExistingChallengeFiles, downloadChallengeFilesTo, getCommonChallengeContext, trackClientFromConfig, } from "../shared/mod.js";
|
|
3
4
|
export async function reset() {
|
|
4
|
-
const
|
|
5
|
-
const
|
|
5
|
+
const config = await loadConfig();
|
|
6
|
+
const api = trackClientFromConfig(config);
|
|
7
|
+
const [_codingContext, _challenge] = await getCommonChallengeContext(config, api);
|
|
6
8
|
console.log("Your existing code will be archived in this directory and the original challenge code will be downloaded");
|
|
7
9
|
const shouldContinue = dntShim.confirm("Are you sure you want to reset this challenge?");
|
|
8
10
|
if (!shouldContinue) {
|
|
9
11
|
return;
|
|
10
12
|
}
|
|
11
13
|
const currentDir = dntShim.Deno.cwd();
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
await archiveExistingChallengeFiles(config.orgName, challengePosition, { selectedLanguage, challengeDir: currentDir });
|
|
16
|
-
await api.reset(config.applicantExamId, config.challengeResultId);
|
|
17
|
-
const newCodingContext = await api.getChallengeCodingContext(config.applicantExamId, config.challengeResultId);
|
|
14
|
+
await archiveExistingChallengeFiles(config.orgName);
|
|
15
|
+
await api.reset();
|
|
16
|
+
const newCodingContext = await api.context();
|
|
18
17
|
const showFileDiff = false;
|
|
19
18
|
const includeTarball = true;
|
|
20
|
-
await downloadChallengeFilesTo(newCodingContext, currentDir, api,
|
|
19
|
+
await downloadChallengeFilesTo(newCodingContext, currentDir, api, showFileDiff, includeTarball);
|
|
21
20
|
}
|
package/esm/src/action/run.js
CHANGED
|
@@ -1,21 +1,20 @@
|
|
|
1
1
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
-
import {
|
|
2
|
+
import { load as loadConfig } from "../shared/config.js";
|
|
3
3
|
import { CantReadFile } from "../shared/errors.js";
|
|
4
|
-
import { getCommonChallengeContext, listFileNames, printTimeLeft, } from "../shared/mod.js";
|
|
5
|
-
import { EnvSettings, FileListType, } from "../
|
|
4
|
+
import { getCommonChallengeContext, listFileNames, printTimeLeft, trackClientFromConfig, } from "../shared/mod.js";
|
|
5
|
+
import { EnvSettings, FileListType, } from "../shared/types.js";
|
|
6
6
|
import { OrcaClient } from "../orca/client.js";
|
|
7
7
|
import { FileType } from "../orca/types.js";
|
|
8
8
|
import * as colors from "../../deps/deno.land/std@0.195.0/fmt/colors.js";
|
|
9
9
|
const MAX_MEMORY_FOR_TEST = 512 * 1024 * 1024; // 512 MB
|
|
10
10
|
export async function run(options) {
|
|
11
|
-
const
|
|
12
|
-
const api =
|
|
13
|
-
const
|
|
14
|
-
const codingContext = trackContext.codingContext;
|
|
11
|
+
const config = await loadConfig();
|
|
12
|
+
const api = trackClientFromConfig(config);
|
|
13
|
+
const [codingContext, challenge] = await getCommonChallengeContext(config, api);
|
|
15
14
|
// const orcaHost = Deno.env.get("ORCA_HOST") || "track-prod-frontend.orca.run";
|
|
16
15
|
// Temporary code to retrieve the Orca host. Will be able to get from CodingContext in the future.
|
|
17
16
|
const orcaHost = codingContext.orcaHost || await api.orcaHost();
|
|
18
|
-
const token = await api.orcaToken(codingContext
|
|
17
|
+
const token = await api.orcaToken(codingContext);
|
|
19
18
|
const orca = new OrcaClient(orcaHost, token);
|
|
20
19
|
await orca.connect();
|
|
21
20
|
const envConfig = codingContext.answers.envConfig || EnvSettings.default;
|
|
@@ -47,7 +46,7 @@ export async function run(options) {
|
|
|
47
46
|
updatedFiles: updatedFiles,
|
|
48
47
|
};
|
|
49
48
|
console.log("Saving challenge files");
|
|
50
|
-
await api.saveFiles(
|
|
49
|
+
await api.saveFiles(saveFilesRequest);
|
|
51
50
|
console.log(colors.green("Challenge files saved"));
|
|
52
51
|
}
|
|
53
52
|
console.log();
|
|
@@ -97,13 +96,13 @@ export async function run(options) {
|
|
|
97
96
|
console.log("Test Results");
|
|
98
97
|
console.log("-".repeat(50));
|
|
99
98
|
console.log();
|
|
100
|
-
if (
|
|
99
|
+
if (challenge.openTestcases) {
|
|
101
100
|
const totalPassed = scoreCounter.totalPassed();
|
|
102
|
-
const scoreStr = `${totalPassed}/${
|
|
101
|
+
const scoreStr = `${totalPassed}/${challenge.openTestcases}`;
|
|
103
102
|
console.log(`Score: ${colors.green(scoreStr)}`);
|
|
104
|
-
await api.updateEditorScore(
|
|
103
|
+
await api.updateEditorScore(totalPassed);
|
|
105
104
|
}
|
|
106
|
-
const timeLeft = await api.timeLeft(
|
|
105
|
+
const timeLeft = await api.timeLeft();
|
|
107
106
|
printTimeLeft(timeLeft);
|
|
108
107
|
}
|
|
109
108
|
else {
|
|
@@ -121,9 +120,7 @@ export async function run(options) {
|
|
|
121
120
|
for (const file of updatedDisplayFiles) {
|
|
122
121
|
console.log(colors.green(`\t${file}`));
|
|
123
122
|
}
|
|
124
|
-
|
|
125
|
-
console.log();
|
|
126
|
-
console.log(`Files uploaded successfully to ${url}`);
|
|
123
|
+
console.log(`Files uploaded successfully.`);
|
|
127
124
|
}
|
|
128
125
|
}
|
|
129
126
|
async function getAllEditableFileContent(context) {
|
package/esm/src/action/status.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { load as loadConfig } from "../shared/config.js";
|
|
2
|
+
import { getCommonChallengeContext, printChallengeInfo, trackClientFromConfig, } from "../shared/mod.js";
|
|
2
3
|
export async function status() {
|
|
3
|
-
const
|
|
4
|
-
|
|
4
|
+
const config = await loadConfig();
|
|
5
|
+
const api = trackClientFromConfig(config);
|
|
6
|
+
const [codingContext, challenge] = await getCommonChallengeContext(config, api);
|
|
7
|
+
await printChallengeInfo(api, codingContext, challenge);
|
|
5
8
|
}
|
package/esm/src/meta.d.ts
CHANGED
package/esm/src/meta.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as colors from "../deps/deno.land/std@0.195.0/fmt/colors.js";
|
|
2
2
|
// @ts-ignore: has no exported member
|
|
3
3
|
import { CookieJar, fetch } from "node-fetch-cookies";
|
|
4
|
-
export const VERSION = "
|
|
4
|
+
export const VERSION = "4.0.0-rc0";
|
|
5
5
|
export const DESCRIPTION = "A CLI for interacting with tracks.run and running code tests on track's servers";
|
|
6
6
|
const VERSION_RE = /^(\d+)\.(\d+)\.(\d+)(?:-?(.*))$/;
|
|
7
7
|
function parseSemver(s) {
|
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
import { BasicAuth } from "../track/client.js";
|
|
2
|
-
import { ProgrammingLanguage } from "
|
|
2
|
+
import { ProgrammingLanguage, TrackApp } from "./types.js";
|
|
3
3
|
export declare const CONFIG_FILE_PATH = ".track/config.json";
|
|
4
|
-
export interface
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export interface TrackConfigCore {
|
|
5
|
+
app: TrackApp;
|
|
6
|
+
baseUrl: string;
|
|
7
7
|
orgName: string;
|
|
8
8
|
basicAuth?: BasicAuth;
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
token: string;
|
|
10
|
+
programmingLanguage?: ProgrammingLanguage;
|
|
11
|
+
cookies: Record<string, string>;
|
|
12
|
+
}
|
|
13
|
+
export interface TrackTestConfigPart {
|
|
11
14
|
challengeId: number;
|
|
15
|
+
applicantExamId: number;
|
|
12
16
|
challengeResultId: number;
|
|
13
|
-
cookies: Record<string, string>;
|
|
14
|
-
programmingLanguage?: ProgrammingLanguage;
|
|
15
17
|
}
|
|
18
|
+
export interface TrackTrainingConfigPart {
|
|
19
|
+
courseMaterialId: number;
|
|
20
|
+
klassId: number;
|
|
21
|
+
klassResultId: number;
|
|
22
|
+
}
|
|
23
|
+
export type TrackConfig = TrackConfigCore & (TrackTestConfigPart | TrackTrainingConfigPart);
|
|
16
24
|
export type SaveConfigOptions = {
|
|
17
25
|
path?: string;
|
|
18
26
|
};
|
|
@@ -21,4 +29,3 @@ export type LoadConfigOptions = {
|
|
|
21
29
|
path?: string;
|
|
22
30
|
};
|
|
23
31
|
export declare function load(options?: LoadConfigOptions): Promise<TrackConfig>;
|
|
24
|
-
export declare function webUrl(config: TrackConfig): string;
|
package/esm/src/shared/config.js
CHANGED
|
@@ -72,7 +72,7 @@ export declare class NewFilesNotAllowed extends TrackError {
|
|
|
72
72
|
export declare class DeleteFilesNotAllowed extends TrackError {
|
|
73
73
|
constructor();
|
|
74
74
|
}
|
|
75
|
-
export declare class
|
|
75
|
+
export declare class LocalCodingNotAllowed extends TrackError {
|
|
76
76
|
url: string;
|
|
77
77
|
constructor(url: string);
|
|
78
78
|
}
|
package/esm/src/shared/errors.js
CHANGED
|
@@ -11,6 +11,7 @@ export class APIError extends TrackError {
|
|
|
11
11
|
this.name = "APIError";
|
|
12
12
|
}
|
|
13
13
|
static async fromResponse(res) {
|
|
14
|
+
console.log(res.url);
|
|
14
15
|
const body = await res.text();
|
|
15
16
|
if (HttpStatus.isClientError(res)) {
|
|
16
17
|
return new APIError(`A client error occurred (${res.status}): ${body}`);
|
|
@@ -202,16 +203,16 @@ export class DeleteFilesNotAllowed extends TrackError {
|
|
|
202
203
|
this.name = "DeleteFilesNotAllowed";
|
|
203
204
|
}
|
|
204
205
|
}
|
|
205
|
-
export class
|
|
206
|
+
export class LocalCodingNotAllowed extends TrackError {
|
|
206
207
|
constructor(url) {
|
|
207
|
-
super(`You are not allowed to take this challenge in your local CLI.\nPlease continue your
|
|
208
|
+
super(`You are not allowed to take this challenge in your local CLI.\nPlease continue your challenge on web:\n\n${url}`);
|
|
208
209
|
Object.defineProperty(this, "url", {
|
|
209
210
|
enumerable: true,
|
|
210
211
|
configurable: true,
|
|
211
212
|
writable: true,
|
|
212
213
|
value: url
|
|
213
214
|
});
|
|
214
|
-
this.name = "
|
|
215
|
+
this.name = "LocalCodingNotAllowed";
|
|
215
216
|
}
|
|
216
217
|
}
|
|
217
218
|
export class OtherError extends TrackError {
|
package/esm/src/shared/mod.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
1
2
|
import * as dntShim from "../../_dnt.shims.js";
|
|
2
|
-
import {
|
|
3
|
+
import { TrackConfig } from "./config.js";
|
|
4
|
+
import { ChallengeResult, ChallengeSession, ChallengeSettings, CodingAnswers, CodingContext, FileListType, ProgrammingLanguageInfo } from "./types.js";
|
|
3
5
|
import { TrackClient } from "../track/client.js";
|
|
4
|
-
import { ApplicantExamForNoAuth, ChallengeResult, ChallengeSettings, CodingContext, ExamSession, ExamSessionChallenge, FileListType, ProgrammingLanguageInfo } from "../track/types.js";
|
|
5
|
-
import { CodingAnswers } from "../track/types.js";
|
|
6
6
|
export declare const _internals: {
|
|
7
7
|
prompt: typeof dntShim.prompt;
|
|
8
8
|
scoreRatio: typeof scoreRatio;
|
|
@@ -11,6 +11,7 @@ export declare const HttpStatus: {
|
|
|
11
11
|
readonly OK: 200;
|
|
12
12
|
readonly Unauthorized: 401;
|
|
13
13
|
readonly isSuccess: (r: number | dntShim.Response) => boolean;
|
|
14
|
+
readonly isRedirect: (r: number | dntShim.Response) => boolean;
|
|
14
15
|
readonly isClientError: (r: number | dntShim.Response) => boolean;
|
|
15
16
|
readonly isServerError: (r: number | dntShim.Response) => boolean;
|
|
16
17
|
};
|
|
@@ -18,9 +19,7 @@ export declare const Prompt: {
|
|
|
18
19
|
select(message: string, items: string[]): number | undefined;
|
|
19
20
|
};
|
|
20
21
|
export declare function printTimeLeft(timeLeftSeconds: number): void;
|
|
21
|
-
export declare function
|
|
22
|
-
export declare function getChallengeFromExamSession(examSession: ExamSession, challengeId: number): ExamSessionChallenge | undefined;
|
|
23
|
-
export declare function tryStartingChallenge(challenge: ExamSessionChallenge, api: TrackClient, applicantExam: ApplicantExamForNoAuth, resultOpt?: ChallengeResult): Promise<ChallengeResult | undefined>;
|
|
22
|
+
export declare function tryStartingChallenge(api: TrackClient, challenge: ChallengeSession): Promise<ChallengeResult | undefined>;
|
|
24
23
|
export declare function chooseProgrammingLanguage(languages: ProgrammingLanguageInfo[]): ProgrammingLanguageInfo;
|
|
25
24
|
export declare function listFileNames(context: {
|
|
26
25
|
settings: ChallengeSettings;
|
|
@@ -30,14 +29,15 @@ export declare const SnakeCase: {
|
|
|
30
29
|
to<T>(obj: T): T;
|
|
31
30
|
from<T_1>(obj: T_1): T_1;
|
|
32
31
|
};
|
|
33
|
-
export declare function getCommonChallengeContext(): Promise<
|
|
32
|
+
export declare function getCommonChallengeContext(config: TrackConfig, api: TrackClient): Promise<[CodingContext, ChallengeSession]>;
|
|
34
33
|
declare function scoreRatio(editorScore: number | undefined, openTestcases: number | undefined): string;
|
|
35
|
-
export declare function printChallengeInfo(
|
|
34
|
+
export declare function printChallengeInfo(api: TrackClient, codingContext: CodingContext, challenge: ChallengeSession): Promise<void>;
|
|
36
35
|
export declare function printWorkingFileSet(codingContext: CodingContext): void;
|
|
37
|
-
export declare function downloadChallengeFilesTo(codingContext: CodingContext, dest: string, api: TrackClient,
|
|
36
|
+
export declare function downloadChallengeFilesTo(codingContext: CodingContext, dest: string, api: TrackClient, showFileDiff: boolean, includeTarball: boolean): Promise<void>;
|
|
38
37
|
export type ArchiveExistingChallengeFilesOptions = {
|
|
39
38
|
challengeDir?: string;
|
|
40
39
|
selectedLanguage?: ProgrammingLanguageInfo;
|
|
41
40
|
};
|
|
42
|
-
export declare function archiveExistingChallengeFiles(orgName: string
|
|
41
|
+
export declare function archiveExistingChallengeFiles(orgName: string): Promise<void>;
|
|
42
|
+
export declare function trackClientFromConfig(config: TrackConfig): TrackClient;
|
|
43
43
|
export {};
|