@@ -2,12 +2,16 @@ import * as yamlParser from "js-yaml";
2
2
import * as path from "path" ;
3
3
import * as _ from "lodash" ;
4
4
import * as fs from "fs" ;
5
- import * as T from "../typings/tutorial " ;
5
+ import * as util from "util " ;
6
6
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 ) ;
8
13
9
14
// import not working
10
- const simpleGit = require ( "simple-git/promise" ) ;
11
15
12
16
const workingDir = "tmp" ;
13
17
@@ -56,143 +60,84 @@ async function cleanupFiles(workingDir: string) {
56
60
}
57
61
}
58
62
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 [ ] } ;
65
67
} ;
66
68
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 ) ;
79
71
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);
92
73
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
+ // }
95
78
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
+ }
99
81
100
- const tutorial = parse ( _content , _config ) ;
82
+ type BuildArgs = {
83
+ dir : string ;
84
+ markdown : string ;
85
+ yaml : string ;
86
+ output : string ;
87
+ } ;
101
88
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
+ } ;
104
110
105
- // Load all logs
106
- const logs = await git . log ( ) ;
111
+ async function build ( args : string [ ] ) {
112
+ const options = parseArgs ( args ) ;
107
113
108
- // Filter relevant logs
109
- const parts = new Set ( ) ;
114
+ // path to run build from
115
+ const localPath = path . join ( process . cwd ( ) , options . dir ) ;
110
116
111
- for ( const commit of logs . all ) {
112
- const matches = commit . message . match (
113
- / ^ (?< stepId > (?< levelId > L \d + ) S \d + ) (?< stepType > [ Q A ] ) ? /
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
+ ] ) ;
115
122
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 ) ;
119
124
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 ) ;
168
126
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
+ } ) ;
172
133
173
- if ( isSubModule ) {
174
- cleanupErr = await cleanupFiles ( workingDir ) ;
134
+ if ( tutorial ) {
135
+ if ( options . output ) {
136
+ await write ( options . output , JSON . stringify ( tutorial ) , "utf8" ) ;
175
137
} 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 ) ) ;
185
139
}
186
140
}
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 ;
196
141
}
197
142
198
143
export default build ;
0 commit comments