Skip to content

Commit ecb6e5e

Browse files
authored
Merge pull request #8 from coderoad/feature/version
Feature/version
2 parents d53c378 + a7d615b commit ecb6e5e

File tree

11 files changed

+439
-408
lines changed

11 files changed

+439
-408
lines changed

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@coderoad/cli",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"description": "A CLI to build the configuration file for Coderoad Tutorials",
55
"main": "src/main.js",
66
"bin": {

src/build.ts

Lines changed: 57 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -2,197 +2,80 @@ import * as yamlParser from "js-yaml";
22
import * as path from "path";
33
import * as _ from "lodash";
44
import * as fs from "fs";
5-
import * as T from "../typings/tutorial";
5+
import * as util from "util";
66
import { parse } from "./utils/parse";
7-
// import validate from './validator';
8-
9-
// import not working
10-
const simpleGit = require("simple-git/promise");
11-
12-
const workingDir = "tmp";
13-
14-
function rmDir(dir: string, rmSelf = false) {
15-
try {
16-
let files;
17-
rmSelf = rmSelf === undefined ? true : rmSelf;
18-
19-
try {
20-
files = fs.readdirSync(dir);
21-
} catch (e) {
22-
console.log(`Sorry, directory '${dir}' doesn't exist.`);
23-
return;
24-
}
25-
26-
if (files.length > 0) {
27-
files.forEach(function (filePath: string) {
28-
if (fs.statSync(path.join(dir, filePath)).isDirectory()) {
29-
rmDir(path.join(dir, filePath));
30-
} else {
31-
fs.unlinkSync(path.join(dir, filePath));
32-
}
33-
});
34-
}
35-
36-
if (rmSelf) {
37-
// check if user want to delete the directory ir just the files in this directory
38-
fs.rmdirSync(dir);
39-
}
40-
} catch (error) {
41-
return error;
42-
}
43-
}
7+
import { getArg } from "./utils/args";
8+
import { getCommits, CommitLogObject } from "./utils/commits";
9+
import * as T from "../typings/tutorial";
4410

45-
async function cleanupFiles(workingDir: string) {
46-
try {
47-
const gitModule = simpleGit(process.cwd());
11+
const write = util.promisify(fs.writeFile);
12+
const read = util.promisify(fs.readFile);
4813

49-
await gitModule.subModule(["deinit", "-f", workingDir]);
50-
await gitModule.rm(workingDir);
51-
await gitModule.reset(["HEAD"]);
52-
rmDir(path.join(process.cwd(), ".git", "modules", workingDir));
53-
rmDir(workingDir);
54-
} catch (error) {
55-
return error;
56-
}
57-
}
14+
export type BuildConfigOptions = {
15+
text: string; // text document from markdown
16+
config: T.Tutorial; // yaml config file converted to json
17+
commits: CommitLogObject; // an object of tutorial positions with a list of commit hashes
18+
};
5819

59-
export type BuildOptions = {
60-
repo: string; // Git url to the repo. It should finish with .git
61-
codeBranch: string; // The branch containing the tutorial code
62-
setupBranch: string; // The branch containing the tutorialuration files
63-
isLocal: boolean; // define if the repo is local or remote
20+
type BuildArgs = {
21+
dir: string;
22+
markdown: string;
23+
yaml: string;
6424
output: string;
6525
};
6626

67-
async function build({ repo, codeBranch, setupBranch, isLocal }: BuildOptions) {
68-
let git: any;
69-
let isSubModule = false;
70-
let localPath: string;
71-
72-
if (isLocal) {
73-
git = simpleGit(repo);
74-
localPath = repo;
75-
} else {
76-
const gitTest = simpleGit(process.cwd());
77-
const isRepo = await gitTest.checkIsRepo();
78-
localPath = path.join(process.cwd(), workingDir);
79-
80-
if (isRepo) {
81-
await gitTest.submoduleAdd(repo, workingDir);
82-
83-
isSubModule = true;
84-
} else {
85-
await gitTest.clone(repo, localPath);
86-
}
87-
88-
git = simpleGit(localPath);
89-
}
90-
91-
await git.fetch();
92-
93-
// checkout the branch to load tutorialuration and content branch
94-
await git.checkout(setupBranch);
95-
96-
// Load files
97-
const _content = fs.readFileSync(path.join(localPath, "TUTORIAL.md"), "utf8");
98-
let _config = fs.readFileSync(path.join(localPath, "coderoad.yaml"), "utf8");
99-
100-
const tutorial = parse(_content, _config);
101-
102-
// Checkout the code branches
103-
await git.checkout(codeBranch);
104-
105-
// Load all logs
106-
const logs = await git.log();
27+
const parseArgs = (args: string[]): BuildArgs => {
28+
// default .
29+
const dir = args[0] || ".";
30+
// -o --output - default coderoad.json
31+
const output =
32+
getArg(args, { name: "output", alias: "o" }) || "coderoad.json";
33+
// -m --markdown - default TUTORIAL.md
34+
const markdown =
35+
getArg(args, { name: "markdown", alias: "m" }) || "TUTORIAL.md";
36+
// -y --yaml - default coderoad-config.yml
37+
const yaml =
38+
getArg(args, { name: "coderoad-config.yml", alias: "y" }) ||
39+
"coderoad-config.yml";
40+
41+
return {
42+
dir,
43+
output,
44+
markdown,
45+
yaml,
46+
};
47+
};
10748

108-
// Filter relevant logs
109-
const parts = new Set();
49+
async function build(args: string[]) {
50+
const options = parseArgs(args);
11051

111-
for (const commit of logs.all) {
112-
const matches = commit.message.match(
113-
/^(?<stepId>(?<levelId>L\d+)S\d+)(?<stepType>[QA])?/
114-
);
52+
// path to run build from
53+
const localPath = path.join(process.cwd(), options.dir);
11554

116-
if (matches && !parts.has(matches[0])) {
117-
// Uses a set to make sure only the latest commit is proccessed
118-
parts.add(matches[0]);
55+
// load files
56+
const [_markdown, _yaml] = await Promise.all([
57+
read(path.join(localPath, options.markdown), "utf8"),
58+
read(path.join(localPath, options.yaml), "utf8"),
59+
]);
11960

120-
// Add the content and git hash to the tutorial
121-
if (matches.groups.stepId) {
122-
// If it's a step: add the content and the setup/solution hashes depending on the type
123-
const level: T.Level | null =
124-
tutorial.levels.find(
125-
(level: T.Level) => level.id === matches.groups.levelId
126-
) || null;
127-
if (!level) {
128-
console.log(`Level ${matches.groups.levelId} not found`);
129-
} else {
130-
const theStep: T.Step | null =
131-
level.steps.find(
132-
(step: T.Step) => step.id === matches.groups.stepId
133-
) || null;
61+
const config = yamlParser.load(_yaml);
13462

135-
if (!theStep) {
136-
console.log(`Step ${matches.groups.stepId} not found`);
137-
} else {
138-
if (matches.groups.stepType === "Q") {
139-
theStep.setup.commits.push(commit.hash.substr(0, 7));
140-
} else if (
141-
matches.groups.stepType === "A" &&
142-
theStep.solution &&
143-
theStep.solution.commits
144-
) {
145-
theStep.solution.commits.push(commit.hash.substr(0, 7));
146-
}
147-
}
148-
}
149-
} else {
150-
// If it's level: add the commit hash (if the level has the commit key) and the content to the tutorial
151-
const theLevel: T.Level | null =
152-
tutorial.levels.find(
153-
(level: T.Level) => level.id === matches.groups.levelId
154-
) || null;
63+
const commits: CommitLogObject = await getCommits(config.config.repo.branch);
15564

156-
if (!theLevel) {
157-
console.log(`Level ${matches.groups.levelId} not found`);
158-
} else {
159-
if (_.has(theLevel, "tutorial.commits")) {
160-
if (theLevel.setup) {
161-
theLevel.setup.commits.push(commit.hash.substr(0, 7));
162-
}
163-
}
164-
}
165-
}
166-
}
167-
}
65+
// Otherwise, continue with the other options
66+
const tutorial: T.Tutorial = await parse({
67+
text: _markdown,
68+
config,
69+
commits,
70+
});
16871

169-
// cleanup the submodules
170-
if (!isLocal) {
171-
let cleanupErr;
172-
173-
if (isSubModule) {
174-
cleanupErr = await cleanupFiles(workingDir);
72+
if (tutorial) {
73+
if (options.output) {
74+
await write(options.output, JSON.stringify(tutorial), "utf8");
17575
} else {
176-
cleanupErr = rmDir(path.join(process.cwd(), workingDir));
177-
}
178-
179-
if (cleanupErr) {
180-
console.log(
181-
`Error when deleting temporary files on ${
182-
isSubModule ? "module" : "folder"
183-
} ${workingDir}.`
184-
);
76+
console.log(JSON.stringify(tutorial, null, 2));
18577
}
18678
}
187-
188-
// const isValid = validate(tutorial);
189-
190-
// if (!isValid) {
191-
// console.log(JSON.stringify(validate.errors, null, 2));
192-
// return;
193-
// }
194-
195-
return tutorial;
19679
}
19780

19881
export default build;

0 commit comments

Comments
 (0)