Skip to content

Commit 1b47da5

Browse files
committed
git commit check changes in progress
Signed-off-by: shmck <shawn.j.mckay@gmail.com>
1 parent bcd8057 commit 1b47da5

File tree

8 files changed

+341
-263
lines changed

8 files changed

+341
-263
lines changed

Diff for: src/build.ts

+68-123
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,16 @@ 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';
7+
import { getArg } from "./utils/args";
8+
import { getCommits } from "./utils/commits";
9+
import * as T from "../typings/tutorial";
10+
11+
const write = util.promisify(fs.writeFile);
12+
const read = util.promisify(fs.readFile);
813

914
// import not working
10-
const simpleGit = require("simple-git/promise");
1115

1216
const workingDir = "tmp";
1317

@@ -56,143 +60,84 @@ async function cleanupFiles(workingDir: string) {
5660
}
5761
}
5862

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
64-
output: string;
63+
export type BuildConfigOptions = {
64+
text: string; // text document from markdown
65+
config: T.Tutorial; // yaml config file converted to json
66+
commits: { [key: string]: string[] };
6567
};
6668

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);
69+
async function generateConfig({ text, config, commits }: BuildConfigOptions) {
70+
const tutorial = parse(text, config);
7971

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();
72+
// const isValid = validate(tutorial);
9273

93-
// checkout the branch to load tutorialuration and content branch
94-
await git.checkout(setupBranch);
74+
// if (!isValid) {
75+
// console.log(JSON.stringify(validate.errors, null, 2));
76+
// return;
77+
// }
9578

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");
79+
return tutorial;
80+
}
9981

100-
const tutorial = parse(_content, _config);
82+
type BuildArgs = {
83+
dir: string;
84+
markdown: string;
85+
yaml: string;
86+
output: string;
87+
};
10188

102-
// Checkout the code branches
103-
await git.checkout(codeBranch);
89+
const parseArgs = (args: string[]): BuildArgs => {
90+
// default .
91+
const dir = args[0] || ".";
92+
// -o --output - default coderoad.json
93+
const output =
94+
getArg(args, { name: "output", alias: "o" }) || "coderoad.json";
95+
// -m --markdown - default TUTORIAL.md
96+
const markdown =
97+
getArg(args, { name: "markdown", alias: "m" }) || "TUTORIAL.md";
98+
// -y --yaml - default coderoad-config.yml
99+
const yaml =
100+
getArg(args, { name: "coderoad-config.yml", alias: "y" }) ||
101+
"coderoad-config.yml";
102+
103+
return {
104+
dir,
105+
output,
106+
markdown,
107+
yaml,
108+
};
109+
};
104110

105-
// Load all logs
106-
const logs = await git.log();
111+
async function build(args: string[]) {
112+
const options = parseArgs(args);
107113

108-
// Filter relevant logs
109-
const parts = new Set();
114+
// path to run build from
115+
const localPath = path.join(process.cwd(), options.dir);
110116

111-
for (const commit of logs.all) {
112-
const matches = commit.message.match(
113-
/^(?<stepId>(?<levelId>L\d+)S\d+)(?<stepType>[QA])?/
114-
);
117+
// load files
118+
const [_markdown, _yaml] = await Promise.all([
119+
read(path.join(localPath, options.markdown), "utf8"),
120+
read(path.join(localPath, options.yaml), "utf8"),
121+
]);
115122

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]);
123+
const config = yamlParser.load(_yaml);
119124

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;
134-
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;
155-
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-
}
125+
const commits = getCommits(config.config.repo.branch);
168126

169-
// cleanup the submodules
170-
if (!isLocal) {
171-
let cleanupErr;
127+
// Otherwise, continue with the other options
128+
const tutorial: T.Tutorial = await generateConfig({
129+
text: _markdown,
130+
config,
131+
commits,
132+
});
172133

173-
if (isSubModule) {
174-
cleanupErr = await cleanupFiles(workingDir);
134+
if (tutorial) {
135+
if (options.output) {
136+
await write(options.output, JSON.stringify(tutorial), "utf8");
175137
} 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-
);
138+
console.log(JSON.stringify(tutorial, null, 2));
185139
}
186140
}
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;
196141
}
197142

198143
export default build;

Diff for: src/cli.ts

+7-134
Original file line numberDiff line numberDiff line change
@@ -1,152 +1,25 @@
1-
import * as inquirer from "inquirer";
2-
import * as fs from "fs";
3-
import * as T from "../typings/tutorial";
4-
import build, { BuildOptions } from "./build";
1+
import build from "./build";
52
import create from "./create";
63

7-
// import not working
8-
const arg = require("arg");
9-
const simpleGit = require("simple-git/promise");
10-
11-
type Q = inquirer.Question<any> & { choices?: string[] };
12-
13-
type ParsedArgs = {
14-
command: string;
15-
git?: string;
16-
dir?: string;
17-
codeBranch: string;
18-
setupBranch: string;
19-
output?: string;
20-
help: string;
21-
version?: string;
22-
};
23-
24-
type Options = {
25-
repo: string;
26-
setupBranch: string;
27-
codeBranch: string;
28-
output: string;
29-
isLocal: boolean;
30-
};
31-
32-
const localGit = "Local directory";
33-
const remoteGit = "Git remote address";
34-
35-
export async function promptForMissingOptions(
36-
options: ParsedArgs
37-
): Promise<Options> {
38-
const questions: Q[] = [];
39-
40-
// if no git remote addres is provided, assume current folder
41-
if (!options.git && !options.dir) {
42-
// check if the current dir is a valid repo
43-
const git = simpleGit(process.cwd());
44-
const isRepo = await git.checkIsRepo();
45-
46-
if (!isRepo) {
47-
questions.push({
48-
type: "list",
49-
name: "source",
50-
message: `The current directory (${process.cwd()}) is not a valid git repo. Would you like to provide a...`,
51-
choices: [localGit, remoteGit],
52-
default: localGit,
53-
});
54-
55-
questions.push({
56-
type: "input",
57-
name: "localGit",
58-
message:
59-
"Please, provide a local directory of the valid git repository: ",
60-
when: (input: any) => input.source === localGit,
61-
});
62-
63-
questions.push({
64-
type: "input",
65-
name: "remoteGit",
66-
message: "Please, provide the address of a remote git repository: ",
67-
when: (input: any) => input.source === remoteGit,
68-
});
69-
}
70-
}
71-
// if both local dir and remote repos are provided
72-
else if (options.git && options.dir) {
73-
questions.push({
74-
type: "list",
75-
name: "source",
76-
message:
77-
"A local git directory and a remote address were both provided. Please, choose either one or those to parse: ",
78-
choices: [localGit, remoteGit],
79-
default: localGit,
80-
});
81-
}
82-
83-
// if the branch containing the code is not provided
84-
if (!options.codeBranch) {
85-
questions.push({
86-
type: "input",
87-
name: "codeBranch",
88-
message: "Please, provide the branch with the code commits: ",
89-
});
90-
}
91-
92-
// if the branch containing the setup files is not provided
93-
if (!options.setupBranch) {
94-
questions.push({
95-
type: "input",
96-
name: "setupBranch",
97-
message:
98-
"Please, provide the branch with the setup files (coderoad.yaml and tutorial.md): ",
99-
});
100-
}
101-
102-
const answers: any = await inquirer.prompt(questions);
103-
104-
let repo: string;
105-
let isLocal: boolean;
106-
107-
if (answers.source) {
108-
repo = (answers.source === localGit ? options.dir : options.git) || "";
109-
isLocal = answers.source === localGit;
110-
} else {
111-
repo = options.dir || options.git || process.cwd();
112-
isLocal = options.git ? false : true;
113-
}
114-
115-
return {
116-
repo,
117-
setupBranch: options.setupBranch || answers.setupBranch,
118-
codeBranch: options.codeBranch || answers.codeBranch,
119-
output: options.output || ".",
120-
isLocal,
121-
};
122-
}
123-
124-
export async function cli(args: string[]): Promise<void> {
125-
const command: string = args[2];
4+
export async function cli(rawArgs: string[]): Promise<void> {
5+
const command: string = rawArgs[2];
6+
const args = rawArgs.slice(3);
1267

1278
switch (command) {
1289
case "--version":
12910
case "-v":
13011
const version = require("../package.json").version;
13112
console.log(`v${version}`);
13213
return;
133-
case "build":
134-
// Otherwise, continue with the other options
135-
// const options: BuildOptions = await promptForMissingOptions(parsedArgs);
136-
// const tutorial: T.Tutorial = await build(options);
13714

138-
// if (tutorial) {
139-
// if (options.output) {
140-
// fs.writeFileSync(options.output, JSON.stringify(tutorial), "utf8");
141-
// } else {
142-
// console.log(JSON.stringify(tutorial, null, 2));
143-
// }
144-
// }
15+
case "build":
16+
build(args);
14517
break;
14618

14719
case "create":
14820
create(process.cwd());
14921
break;
22+
15023
case "--help":
15124
case "-h":
15225
default:

0 commit comments

Comments
 (0)