@@ -11,6 +11,7 @@ const frontmatter = require('../../lib/frontmatter')
1111const languages = require ( '../../lib/languages' )
1212const { tags } = require ( '../../lib/liquid-tags/extended-markdown' )
1313const ghesReleaseNotesSchema = require ( '../helpers/schemas/release-notes-schema' )
14+ const learningTracksSchema = require ( '../helpers/schemas/learning-tracks-schema' )
1415const renderContent = require ( '../../lib/render-content' )
1516const { execSync } = require ( 'child_process' )
1617
@@ -20,6 +21,7 @@ const reusablesDir = path.join(rootDir, 'data/reusables')
2021const variablesDir = path . join ( rootDir , 'data/variables' )
2122const glossariesDir = path . join ( rootDir , 'data/glossaries' )
2223const ghesReleaseNotesDir = path . join ( rootDir , 'data/release-notes' )
24+ const learningTracks = path . join ( rootDir , 'data/learning-tracks' )
2325
2426const languageCodes = Object . keys ( languages )
2527
@@ -167,7 +169,7 @@ const yamlWalkOptions = {
167169}
168170
169171// different lint rules apply to different content types
170- let mdToLint , ymlToLint , releaseNotesToLint
172+ let mdToLint , ymlToLint , releaseNotesToLint , learningTracksToLint
171173
172174if ( ! process . env . TEST_TRANSLATION ) {
173175 // compile lists of all the files we want to lint
@@ -196,8 +198,13 @@ if (!process.env.TEST_TRANSLATION) {
196198
197199 // GHES release notes
198200 const ghesReleaseNotesYamlAbsPaths = walk ( ghesReleaseNotesDir , yamlWalkOptions ) . sort ( )
199- const ghesReleaseNotesYamlRelPaths = ghesReleaseNotesYamlAbsPaths . map ( p => path . relative ( rootDir , p ) )
201+ const ghesReleaseNotesYamlRelPaths = ghesReleaseNotesYamlAbsPaths . map ( p => slash ( path . relative ( rootDir , p ) ) )
200202 releaseNotesToLint = zip ( ghesReleaseNotesYamlRelPaths , ghesReleaseNotesYamlAbsPaths )
203+
204+ // Learning tracks
205+ const learningTracksYamlAbsPaths = walk ( learningTracks , yamlWalkOptions ) . sort ( )
206+ const learningTracksYamlRelPaths = learningTracksYamlAbsPaths . map ( p => slash ( path . relative ( rootDir , p ) ) )
207+ learningTracksToLint = zip ( learningTracksYamlRelPaths , learningTracksYamlAbsPaths )
201208} else {
202209 // get all translated markdown or yaml files by comparing files changed to main branch
203210 const changedFilesRelPaths = execSync ( 'git diff --name-only origin/main | egrep "^translations/.*/.+.(yml|md)$"' , { maxBuffer : 1024 * 1024 * 100 } ) . toString ( ) . split ( '\n' )
@@ -207,7 +214,7 @@ if (!process.env.TEST_TRANSLATION) {
207214
208215 console . log ( `Found ${ changedFilesRelPaths . length } translated files.` )
209216
210- const { mdRelPaths = [ ] , ymlRelPaths = [ ] , releaseNotesRelPaths = [ ] } = groupBy ( changedFilesRelPaths , ( path ) => {
217+ const { mdRelPaths = [ ] , ymlRelPaths = [ ] , releaseNotesRelPaths = [ ] , learningTracksRelPaths = [ ] } = groupBy ( changedFilesRelPaths , ( path ) => {
211218 // separate the changed files to different groups
212219 if ( path . endsWith ( 'README.md' ) ) {
213220 return 'throwAway'
@@ -217,20 +224,23 @@ if (!process.env.TEST_TRANSLATION) {
217224 return 'ymlRelPaths'
218225 } else if ( path . match ( / \/ d a t a \/ r e l e a s e - n o t e s \/ / i) ) {
219226 return 'releaseNotesRelPaths'
227+ } else if ( path . match ( / \d a t a \/ l e a r n i n g - t r a c k s / ) ) {
228+ return 'learningTracksRelPaths'
220229 } else {
221230 // we aren't linting the rest
222231 return 'throwAway'
223232 }
224233 } )
225234
226- const [ mdTuples , ymlTuples , releaseNotesTuples ] = [ mdRelPaths , ymlRelPaths , releaseNotesRelPaths ] . map ( relPaths => {
235+ const [ mdTuples , ymlTuples , releaseNotesTuples , learningTracksTuples ] = [ mdRelPaths , ymlRelPaths , releaseNotesRelPaths , learningTracksRelPaths ] . map ( relPaths => {
227236 const absPaths = relPaths . map ( p => path . join ( rootDir , p ) )
228237 return zip ( relPaths , absPaths )
229238 } )
230239
231240 mdToLint = mdTuples
232241 ymlToLint = ymlTuples
233242 releaseNotesToLint = releaseNotesTuples
243+ learningTracksToLint = learningTracksTuples
234244}
235245
236246function formatLinkError ( message , links ) {
@@ -682,3 +692,42 @@ describe('lint release notes', () => {
682692 }
683693 )
684694} )
695+
696+ describe ( 'lint learning tracks' , ( ) => {
697+ if ( learningTracksToLint . length < 1 ) return
698+ describe . each ( learningTracksToLint ) (
699+ '%s' ,
700+ ( yamlRelPath , yamlAbsPath ) => {
701+ let dictionary
702+
703+ beforeAll ( async ( ) => {
704+ const fileContents = await readFileAsync ( yamlAbsPath , 'utf8' )
705+ dictionary = yaml . safeLoad ( fileContents , { filename : yamlRelPath } )
706+ } )
707+
708+ it ( 'matches the schema' , ( ) => {
709+ const { errors } = revalidator . validate ( dictionary , learningTracksSchema )
710+ const errorMessage = errors . map ( error => `- [${ error . property } ]: ${ error . actual } , ${ error . message } ` ) . join ( '\n' )
711+ expect ( errors . length , errorMessage ) . toBe ( 0 )
712+ } )
713+
714+ it ( 'has at least one featured track' , ( ) => {
715+ expect ( Object . values ( dictionary ) . some ( entry => entry . featured_track ) ) . toBe ( true )
716+ } )
717+
718+ it ( 'contains valid liquid' , ( ) => {
719+ const toLint = [ ]
720+ Object . values ( dictionary ) . forEach ( ( { title, description } ) => {
721+ toLint . push ( title )
722+ toLint . push ( description )
723+ } )
724+
725+ toLint . forEach ( element => {
726+ expect ( ( ) => renderContent . liquid . parse ( element ) , `${ element } contains invalid liquid` )
727+ . not
728+ . toThrow ( )
729+ } )
730+ } )
731+ }
732+ )
733+ } )
0 commit comments