Skip to content

Commit 740c1cf

Browse files
committed
build/parse refactor
Signed-off-by: shmck <[email protected]>
1 parent 1b47da5 commit 740c1cf

File tree

3 files changed

+130
-180
lines changed

3 files changed

+130
-180
lines changed

src/build.ts

+4-66
Original file line numberDiff line numberDiff line change
@@ -5,80 +5,18 @@ import * as fs from "fs";
55
import * as util from "util";
66
import { parse } from "./utils/parse";
77
import { getArg } from "./utils/args";
8-
import { getCommits } from "./utils/commits";
8+
import { getCommits, CommitLogObject } from "./utils/commits";
99
import * as T from "../typings/tutorial";
1010

1111
const write = util.promisify(fs.writeFile);
1212
const read = util.promisify(fs.readFile);
1313

14-
// import not working
15-
16-
const workingDir = "tmp";
17-
18-
function rmDir(dir: string, rmSelf = false) {
19-
try {
20-
let files;
21-
rmSelf = rmSelf === undefined ? true : rmSelf;
22-
23-
try {
24-
files = fs.readdirSync(dir);
25-
} catch (e) {
26-
console.log(`Sorry, directory '${dir}' doesn't exist.`);
27-
return;
28-
}
29-
30-
if (files.length > 0) {
31-
files.forEach(function (filePath: string) {
32-
if (fs.statSync(path.join(dir, filePath)).isDirectory()) {
33-
rmDir(path.join(dir, filePath));
34-
} else {
35-
fs.unlinkSync(path.join(dir, filePath));
36-
}
37-
});
38-
}
39-
40-
if (rmSelf) {
41-
// check if user want to delete the directory ir just the files in this directory
42-
fs.rmdirSync(dir);
43-
}
44-
} catch (error) {
45-
return error;
46-
}
47-
}
48-
49-
async function cleanupFiles(workingDir: string) {
50-
try {
51-
const gitModule = simpleGit(process.cwd());
52-
53-
await gitModule.subModule(["deinit", "-f", workingDir]);
54-
await gitModule.rm(workingDir);
55-
await gitModule.reset(["HEAD"]);
56-
rmDir(path.join(process.cwd(), ".git", "modules", workingDir));
57-
rmDir(workingDir);
58-
} catch (error) {
59-
return error;
60-
}
61-
}
62-
6314
export type BuildConfigOptions = {
6415
text: string; // text document from markdown
6516
config: T.Tutorial; // yaml config file converted to json
66-
commits: { [key: string]: string[] };
17+
commits: CommitLogObject; // an object of tutorial positions with a list of commit hashes
6718
};
6819

69-
async function generateConfig({ text, config, commits }: BuildConfigOptions) {
70-
const tutorial = parse(text, config);
71-
72-
// const isValid = validate(tutorial);
73-
74-
// if (!isValid) {
75-
// console.log(JSON.stringify(validate.errors, null, 2));
76-
// return;
77-
// }
78-
79-
return tutorial;
80-
}
81-
8220
type BuildArgs = {
8321
dir: string;
8422
markdown: string;
@@ -122,10 +60,10 @@ async function build(args: string[]) {
12260

12361
const config = yamlParser.load(_yaml);
12462

125-
const commits = getCommits(config.config.repo.branch);
63+
const commits: CommitLogObject = await getCommits(config.config.repo.branch);
12664

12765
// Otherwise, continue with the other options
128-
const tutorial: T.Tutorial = await generateConfig({
66+
const tutorial: T.Tutorial = await parse({
12967
text: _markdown,
13068
config,
13169
commits,

src/utils/commits.ts

+58-105
Original file line numberDiff line numberDiff line change
@@ -1,116 +1,69 @@
1+
import * as fs from "fs";
2+
import util from "util";
13
import * as path from "path";
2-
import gitP, { SimpleGit, StatusResult } from "simple-git/promise";
4+
import gitP, { SimpleGit } from "simple-git/promise";
5+
import * as T from "../../typings/tutorial";
36

4-
export async function getCommits() {
5-
const git: SimpleGit = gitP(process.cwd());
7+
const mkdir = util.promisify(fs.mkdir);
8+
const exists = util.promisify(fs.exists);
9+
const rmdir = util.promisify(fs.rmdir);
610

7-
const isRepo = await git.checkIsRepo();
11+
type GetCommitOptions = {
12+
localDir: string;
13+
codeBranch: string;
14+
};
15+
16+
export type CommitLogObject = { [position: string]: string[] };
817

9-
const tmpDirectory = "tmp";
10-
const localPath = path.join(process.cwd(), tmpDirectory);
18+
export async function getCommits({
19+
localDir,
20+
codeBranch,
21+
}: GetCommitOptions): Promise<CommitLogObject> {
22+
const git: SimpleGit = gitP(localDir);
23+
24+
const isRepo = await git.checkIsRepo();
1125

1226
if (!isRepo) {
1327
throw new Error("No git repo provided");
1428
}
1529

16-
// if (isRepo) {
17-
// await gitTest.submoduleAdd(repo, workingDir);
18-
19-
// isSubModule = true;
20-
// } else {
21-
// await gitTest.clone(repo, localPath);
22-
// }
23-
24-
// await git.fetch();
25-
26-
// // checkout the branch to load tutorialuration and content branch
27-
// await git.checkout(setupBranch);
28-
29-
// // Checkout the code branches
30-
// await git.checkout(codeBranch);
31-
32-
// // Load all logs
33-
// const logs = await git.log();
34-
35-
// // Filter relevant logs
36-
// const parts = new Set();
30+
const tmpDir = path.join(localDir, ".tmp");
3731

38-
// for (const commit of logs.all) {
39-
// const matches = commit.message.match(
40-
// /^(?<stepId>(?<levelId>L\d+)S\d+)(?<stepType>[QA])?/
41-
// );
42-
43-
// if (matches && !parts.has(matches[0])) {
44-
// // Uses a set to make sure only the latest commit is proccessed
45-
// parts.add(matches[0]);
46-
47-
// // Add the content and git hash to the tutorial
48-
// if (matches.groups.stepId) {
49-
// // If it's a step: add the content and the setup/solution hashes depending on the type
50-
// const level: T.Level | null =
51-
// tutorial.levels.find(
52-
// (level: T.Level) => level.id === matches.groups.levelId
53-
// ) || null;
54-
// if (!level) {
55-
// console.log(`Level ${matches.groups.levelId} not found`);
56-
// } else {
57-
// const theStep: T.Step | null =
58-
// level.steps.find(
59-
// (step: T.Step) => step.id === matches.groups.stepId
60-
// ) || null;
61-
62-
// if (!theStep) {
63-
// console.log(`Step ${matches.groups.stepId} not found`);
64-
// } else {
65-
// if (matches.groups.stepType === "Q") {
66-
// theStep.setup.commits.push(commit.hash.substr(0, 7));
67-
// } else if (
68-
// matches.groups.stepType === "A" &&
69-
// theStep.solution &&
70-
// theStep.solution.commits
71-
// ) {
72-
// theStep.solution.commits.push(commit.hash.substr(0, 7));
73-
// }
74-
// }
75-
// }
76-
// } else {
77-
// // If it's level: add the commit hash (if the level has the commit key) and the content to the tutorial
78-
// const theLevel: T.Level | null =
79-
// tutorial.levels.find(
80-
// (level: T.Level) => level.id === matches.groups.levelId
81-
// ) || null;
82-
83-
// if (!theLevel) {
84-
// console.log(`Level ${matches.groups.levelId} not found`);
85-
// } else {
86-
// if (_.has(theLevel, "tutorial.commits")) {
87-
// if (theLevel.setup) {
88-
// theLevel.setup.commits.push(commit.hash.substr(0, 7));
89-
// }
90-
// }
91-
// }
92-
// }
93-
// }
94-
// }
95-
96-
// // cleanup the submodules
97-
// if (!isLocal) {
98-
// let cleanupErr;
99-
100-
// if (isSubModule) {
101-
// cleanupErr = await cleanupFiles(workingDir);
102-
// } else {
103-
// cleanupErr = rmDir(path.join(process.cwd(), workingDir));
104-
// }
105-
106-
// if (cleanupErr) {
107-
// console.log(
108-
// `Error when deleting temporary files on ${
109-
// isSubModule ? "module" : "folder"
110-
// } ${workingDir}.`
111-
// );
112-
// }
113-
// }
32+
const tmpDirExists = await exists(tmpDir);
33+
if (tmpDirExists) {
34+
await rmdir(tmpDir, { recursive: true });
35+
}
36+
await mkdir(tmpDir);
37+
const tempGit = gitP(tmpDir);
38+
await tempGit.clone(localDir, tmpDir);
39+
40+
// Checkout the code branches
41+
await git.checkout(codeBranch);
42+
43+
// Load all logs
44+
const logs = await git.log();
45+
46+
// Filter relevant logs
47+
const commits: CommitLogObject = {};
48+
49+
for (const commit of logs.all) {
50+
const matches = commit.message.match(
51+
/^(?<stepId>(?<levelId>L\d+)(S\d+))(?<stepType>[QA])?/
52+
);
53+
54+
if (matches && matches.length) {
55+
// Use an object of commit arrays to collect all commits
56+
const position = matches[0];
57+
if (!commits[position]) {
58+
// does not exist, create the list
59+
commits[position] = [commit.hash];
60+
} else {
61+
// add to the list
62+
commits[position].push(commit.hash);
63+
}
64+
}
65+
}
66+
// cleanup the tmp directory
67+
await rmdir(tmpDir, { recursive: true });
68+
return commits;
11469
}
115-
116-
getCommits();

src/utils/parse.ts

+68-9
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as _ from "lodash";
2+
import { CommitLogObject } from "./commits";
23
import * as T from "../../typings/tutorial";
34

45
type TutorialFrame = {
@@ -91,17 +92,23 @@ export function parseMdContent(md: string): TutorialFrame | never {
9192
return sections;
9293
}
9394

94-
export function parse(_content: string, _config: string): T.Tutorial {
95-
const mdContent: TutorialFrame = parseMdContent(_content);
96-
// Parse tutorial to JSON
97-
const tutorial: T.Tutorial = yamlParser.load(_config);
95+
type ParseParams = {
96+
text: string;
97+
config: T.Tutorial;
98+
commits: CommitLogObject;
99+
};
100+
101+
export function parse(params: ParseParams): T.Tutorial {
102+
const parsed = { ...params.config };
103+
104+
const mdContent: TutorialFrame = parseMdContent(params.text);
98105

99106
// Add the summary to the tutorial file
100-
tutorial["summary"] = mdContent.summary;
107+
parsed["summary"] = mdContent.summary;
101108

102109
// merge content and tutorial
103-
if (tutorial.levels) {
104-
tutorial.levels.forEach((level: T.Level) => {
110+
if (parsed.levels) {
111+
parsed.levels.forEach((level: T.Level, levelIndex: number) => {
105112
const levelContent = mdContent[level.id];
106113
if (!levelContent) {
107114
console.log(`Markdown content not found for ${level.id}`);
@@ -110,12 +117,64 @@ export function parse(_content: string, _config: string): T.Tutorial {
110117
const { steps, ...content } = levelContent;
111118

112119
if (steps) {
113-
steps.forEach((step: T.Step) => _.merge(step, steps[step.id]));
120+
steps.forEach((step: T.Step, stepIndex: number) => {
121+
return _.merge(step, steps[step.id]);
122+
});
114123
}
115124

116125
_.merge(level, content);
117126
});
118127
}
119128

120-
return tutorial;
129+
return parsed;
121130
}
131+
132+
/*
133+
// Add the content and git hash to the tutorial
134+
if (matches.groups.stepId) {
135+
// If it's a step: add the content and the setup/solution hashes depending on the type
136+
const level: T.Level | null =
137+
tutorial.levels.find(
138+
(level: T.Level) => level.id === matches.groups.levelId
139+
) || null;
140+
if (!level) {
141+
console.log(`Level ${matches.groups.levelId} not found`);
142+
} else {
143+
const theStep: T.Step | null =
144+
level.steps.find(
145+
(step: T.Step) => step.id === matches.groups.stepId
146+
) || null;
147+
148+
if (!theStep) {
149+
console.log(`Step ${matches.groups.stepId} not found`);
150+
} else {
151+
if (matches.groups.stepType === "Q") {
152+
theStep.setup.commits.push(commit.hash.substr(0, 7));
153+
} else if (
154+
matches.groups.stepType === "A" &&
155+
theStep.solution &&
156+
theStep.solution.commits
157+
) {
158+
theStep.solution.commits.push(commit.hash.substr(0, 7));
159+
}
160+
}
161+
}
162+
} else {
163+
// If it's level: add the commit hash (if the level has the commit key) and the content to the tutorial
164+
const theLevel: T.Level | null =
165+
tutorial.levels.find(
166+
(level: T.Level) => level.id === matches.groups.levelId
167+
) || null;
168+
169+
if (!theLevel) {
170+
console.log(`Level ${matches.groups.levelId} not found`);
171+
} else {
172+
if (_.has(theLevel, "tutorial.commits")) {
173+
if (theLevel.setup) {
174+
theLevel.setup.commits.push(commit.hash.substr(0, 7));
175+
}
176+
}
177+
}
178+
}
179+
}
180+
*/

0 commit comments

Comments
 (0)