Skip to content

Commit

Permalink
Description yaml#177479156 (#94)
Browse files Browse the repository at this point in the history
* tests, begun standard builder method

* description yaml file read to supply standard name

* markdown for description yaml

* can use description file without a units directory

* updates go version

Co-authored-by: ToriK17 <[email protected]>
  • Loading branch information
pgrunde and ToriK17 authored Sep 9, 2021
1 parent 06c1380 commit 838191b
Show file tree
Hide file tree
Showing 7 changed files with 156 additions and 61 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ jobs:
test:
strategy:
matrix:
go-version: [1.13.x]
go-version: [1.17.x]
platform: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.platform }}
steps:
Expand Down
63 changes: 50 additions & 13 deletions app/cmd/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,18 +229,15 @@ func newConfigYaml(target, blockRoot, requestedUnitsDir string, excludePaths []s
continue
}

formattedUnitName := formattedName(unit)
if formattedUnitName == "" {
formattedUnitName = formattedTargetName
unitsDirectoryFile, err := os.Stat(unitsDir)

whereToLookForUnits := blockRoot
if err == nil && unitsDirectoryFile.IsDir() {
whereToLookForUnits = fmt.Sprintf("%s%s", blockRoot, unitsRootDirName)
}
unitUID := []byte(formattedUnitName)
md5unitUID := md5.Sum(unitUID)

standard := Standard{
Title: formattedUnitName,
UID: hex.EncodeToString(md5unitUID[:]),
Description: formattedUnitName,
SuccessCriteria: []string{"success criteria"},
standard := newStandard(whereToLookForUnits, unit)
if standard.Title == "" {
standard.Title = formattedTargetName
}

for _, contentFile := range unitToContentFileMap[unit] {
Expand All @@ -267,7 +264,7 @@ func newConfigYaml(target, blockRoot, requestedUnitsDir string, excludePaths []s
}
// when it came from the header but UID is not set, fall back to detecting from path
if contentFile.UID == "" {
cfUID := []byte(formattedUnitName + contentFile.Path)
cfUID := []byte(standard.Title + contentFile.Path)
md5cfUID := md5.Sum(cfUID)
contentFile.UID = hex.EncodeToString(md5cfUID[:])
}
Expand All @@ -277,7 +274,7 @@ func newConfigYaml(target, blockRoot, requestedUnitsDir string, excludePaths []s
}
standard.ContentFiles = append(standard.ContentFiles, contentFile)
} else {
cfUID := []byte(formattedUnitName + contentFile.Path)
cfUID := []byte(standard.Title + contentFile.Path)
md5cfUID := md5.Sum(cfUID)

contentFile.Type = detectContentType(contentFile.Path)
Expand Down Expand Up @@ -483,6 +480,11 @@ func printExtras(yamlText, path string) error {
}

// buildUnitToContentFileMap reads contents from the unit directory and includes md files. It returns attributes from the header for each file
// TODO refactor inputs, should be simplified like unitsDir is just the first and last inputs put together; example from test
// bockRoot ../../fixtures/test-block-no-config/
// unitsDir ../../fixtures/test-block-no-config/units
// unitsDirName Unit 1
// unitsRootDirName units
func buildUnitToContentFileMap(blockRoot, unitsDir, unitsDirName, unitsRootDirName string) (map[string][]ContentFileAttrs, error) {
unitToContentFileMap := map[string][]ContentFileAttrs{}

Expand Down Expand Up @@ -576,6 +578,41 @@ func GitTopLevelDir() (string, error) {
return strings.TrimSpace(string(out)), err
}

// newStandard returns a standard from tne unitDir and unit name combination
// unitDir is the location of the individual unit, with unit the directory beneath it
// Either a description yaml file is read from, or the unit name is used to build a standard
//func standardAttributes(unitDir, unit string) (title, UID, description string, successCriteria []string) {
func newStandard(unitDir, unit string) Standard {
yamlLocation := fmt.Sprintf("%s/%s/%s", unitDir, unit, "description.yaml")
yamlBytes, err := os.ReadFile(yamlLocation)
if err != nil {
// no description yaml found,
return standardFromUnit(unit)
} else {
// read yaml contents of file
standard := Standard{}
if err = yaml.NewDecoder(bytes.NewReader(yamlBytes)).Decode(&standard); err != nil {
return standardFromUnit(unit)
}
return standard
}
}

func standardFromUnit(unit string) Standard {
title := formattedName(unit)
unitUID := []byte(title)
md5unitUID := md5.Sum(unitUID)
UID := hex.EncodeToString(md5unitUID[:])
description := title
successCriteria := []string{"success criteria"}
return Standard{
Title: title,
UID: UID,
Description: description,
SuccessCriteria: successCriteria,
}
}

// split is the bufio Scanner Split interface implementation for fetching content file header attributes
func split(data []byte, atEOF bool) (advance int, token []byte, err error) {
if atEOF && len(data) == 0 {
Expand Down
111 changes: 66 additions & 45 deletions app/cmd/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ func Test_PublishBuildsAutoConfig(t *testing.T) {
if err != nil {
t.Errorf("File created could not unmarshal into ConfigYaml struct: %s", err)
}
if len(configMade.Standards) != 3 {
t.Errorf("test-block-with-config fixture should have made 3 standards but made %d", len(configMade.Standards))
if len(configMade.Standards) != 4 {
t.Errorf("test-block-with-config fixture should have made 4 standards but made %d", len(configMade.Standards))
}
// standard 1
standardOne := configMade.Standards[0]
Expand Down Expand Up @@ -75,67 +75,88 @@ func Test_PublishBuildsAutoConfig(t *testing.T) {

// standard 3
standardThree := configMade.Standards[2]
if standardThree.Title != "Unit 1" {
t.Errorf("test-block-with-config fixture third standard should have title Unit 1, but had '%s'", standardThree.Title)
if standardThree.Title != "Title From Yaml" {
t.Errorf("test-block-with-config fixture third standard should have yaml supplied title 'Title From Yaml', but had '%s'", standardThree.Title)
}
if len(standardThree.ContentFiles) != 5 {
t.Errorf("test-block-with-config fixture third standard should have 5 content files but had %d", len(standardThree.ContentFiles))
if standardThree.Description != "My description here" {
t.Errorf("test-block-with-config fixture third standard should have yaml supplied description 'My description here', but had '%s'", standardThree.Description)
}
// standard 3 file 1
if standardThree.ContentFiles[0].Type != "Lesson" {
t.Errorf("test-block-with-config fixture third standard first content file should be of type Lesson but was '%s'", standardThree.ContentFiles[0].Type)
if standardThree.UID != "02210548f12da09aa7a0bd1f1308c423" {
t.Errorf("test-block-with-config fixture third standard should have yaml supplied UID '02210548f12da09aa7a0bd1f1308c423', but had '%s'", standardThree.UID)
}
if standardThree.ContentFiles[0].Path != "/units/file.hidden.file.md" {
t.Errorf("test-block-with-config fixture third standard first content file path should be '/units/file.hidden.file.md' but was '%s'", standardThree.ContentFiles[0].Path)
if len(standardThree.SuccessCriteria) != 2 {
t.Errorf("test-block-with-config fixture third standard should have 2 SuccessCriteria but had %d", len(standardThree.SuccessCriteria))
}
if standardThree.ContentFiles[0].DefaultVisibility != "hidden" {
t.Errorf("test-block-with-config fixture third standard first content file DefaultVisibility should be 'hidden' but was '%s'", standardThree.ContentFiles[0].DefaultVisibility)
if standardThree.SuccessCriteria[0] != "success" {
t.Errorf("test-block-with-config fixture third standard first success criteria should be 'success' but was %s", standardThree.SuccessCriteria[0])
}
// standard 3 file 2
if standardThree.ContentFiles[1].Type != "Survey" {
t.Errorf("test-block-with-config fixture third standard second content file should be of type Survey but was '%s'", standardThree.ContentFiles[1].Type)
if standardThree.SuccessCriteria[1] != "criteria" {
t.Errorf("test-block-with-config fixture third standard first success criteria should be 'criteria' but was %s", standardThree.SuccessCriteria[1])
}
if standardThree.ContentFiles[1].Path != "/units/file.survey.md" {
t.Errorf("test-block-with-config fixture third standard second content file path should be '/units/file.survey.md' but was '%s'", standardThree.ContentFiles[1].Path)

// standard 4
standardFour := configMade.Standards[3]
if standardFour.Title != "Unit 1" {
t.Errorf("test-block-with-config fixture fourth standard should have title Unit 1, but had '%s'", standardFour.Title)
}
if len(standardFour.ContentFiles) != 5 {
t.Errorf("test-block-with-config fixture fourth standard should have 5 content files but had %d", len(standardFour.ContentFiles))
}
// standard 4 file 1
if standardFour.ContentFiles[0].Type != "Lesson" {
t.Errorf("test-block-with-config fixture fourth standard first content file should be of type Lesson but was '%s'", standardFour.ContentFiles[0].Type)
}
if standardFour.ContentFiles[0].Path != "/units/file.hidden.file.md" {
t.Errorf("test-block-with-config fixture fourth standard first content file path should be '/units/file.hidden.file.md' but was '%s'", standardFour.ContentFiles[0].Path)
}
if standardFour.ContentFiles[0].DefaultVisibility != "hidden" {
t.Errorf("test-block-with-config fixture fourth standard first content file DefaultVisibility should be 'hidden' but was '%s'", standardFour.ContentFiles[0].DefaultVisibility)
}
// standard 4 file 2
if standardFour.ContentFiles[1].Type != "Survey" {
t.Errorf("test-block-with-config fixture fourth standard second content file should be of type Survey but was '%s'", standardFour.ContentFiles[1].Type)
}
if standardFour.ContentFiles[1].Path != "/units/file.survey.md" {
t.Errorf("test-block-with-config fixture fourth standard second content file path should be '/units/file.survey.md' but was '%s'", standardFour.ContentFiles[1].Path)
}
// standard 3 file 3
if standardThree.ContentFiles[2].Type != "Resource" {
t.Errorf("test-block-with-config fixture third standard third content file should be of type Resource but was '%s'", standardThree.ContentFiles[2].Type)
// standard 4 file 3
if standardFour.ContentFiles[2].Type != "Resource" {
t.Errorf("test-block-with-config fixture fourth standard third content file should be of type Resource but was '%s'", standardFour.ContentFiles[2].Type)
}
if standardThree.ContentFiles[2].Path != "/units/hidden.resource.md" {
t.Errorf("test-block-with-config fixture third standard third content file path should be '/units/hidden.resource.md' but was '%s'", standardThree.ContentFiles[2].Path)
if standardFour.ContentFiles[2].Path != "/units/hidden.resource.md" {
t.Errorf("test-block-with-config fixture fourth standard third content file path should be '/units/hidden.resource.md' but was '%s'", standardFour.ContentFiles[2].Path)
}
if standardThree.ContentFiles[2].DefaultVisibility != "hidden" {
t.Errorf("test-block-with-config fixture third standard third content file DefaultVisibility should be 'hidden' but was '%s'", standardThree.ContentFiles[2].DefaultVisibility)
if standardFour.ContentFiles[2].DefaultVisibility != "hidden" {
t.Errorf("test-block-with-config fixture fourth standard third content file DefaultVisibility should be 'hidden' but was '%s'", standardFour.ContentFiles[2].DefaultVisibility)
}
// standard 3 file 4
if standardThree.ContentFiles[3].Type != "Instructor" {
t.Errorf("test-block-with-config fixture third standard fourth content file should be of type Instructor but was '%s'", standardThree.ContentFiles[3].Type)
// standard 4 file 4
if standardFour.ContentFiles[3].Type != "Instructor" {
t.Errorf("test-block-with-config fixture fourth standard fourth content file should be of type Instructor but was '%s'", standardFour.ContentFiles[3].Type)
}
if standardThree.ContentFiles[3].Path != "/units/teacher-instructor.md" {
t.Errorf("test-block-with-config fixture third standard fourth content file path should be '/units/teacher-instructor.md' but was '%s'", standardThree.ContentFiles[3].Path)
if standardFour.ContentFiles[3].Path != "/units/teacher-instructor.md" {
t.Errorf("test-block-with-config fixture fourth standard fourth content file path should be '/units/teacher-instructor.md' but was '%s'", standardFour.ContentFiles[3].Path)
}
// standard 3 file 5 values set from header
if standardThree.ContentFiles[4].Type != "Checkpoint" {
t.Errorf("test-block-with-config fixture third standard fifth content file should be of type Instructor but was '%s'", standardThree.ContentFiles[4].Type)
// standard 4 file 5 values set from header
if standardFour.ContentFiles[4].Type != "Checkpoint" {
t.Errorf("test-block-with-config fixture fourth standard fifth content file should be of type Instructor but was '%s'", standardFour.ContentFiles[4].Type)
}
if standardThree.ContentFiles[4].Path != "/units/test.md" {
t.Errorf("test-block-with-config fixture third standard fifth content file path should be '/units/test.md' but was '%s'", standardThree.ContentFiles[4].Path)
if standardFour.ContentFiles[4].Path != "/units/test.md" {
t.Errorf("test-block-with-config fixture fourth standard fifth content file path should be '/units/test.md' but was '%s'", standardFour.ContentFiles[4].Path)
}
if standardThree.ContentFiles[4].DefaultVisibility != "hidden" {
t.Errorf("test-block-with-config fixture third standard fifth content file DefaultVisibility should be 'hidden' but was '%s'", standardThree.ContentFiles[4].DefaultVisibility)
if standardFour.ContentFiles[4].DefaultVisibility != "hidden" {
t.Errorf("test-block-with-config fixture fourth standard fifth content file DefaultVisibility should be 'hidden' but was '%s'", standardFour.ContentFiles[4].DefaultVisibility)
}
if standardThree.ContentFiles[4].UID != "abc123" {
t.Errorf("test-block-with-config fixture third standard fifth content file UID should be 'abc123' but was '%s'", standardThree.ContentFiles[4].UID)
if standardFour.ContentFiles[4].UID != "abc123" {
t.Errorf("test-block-with-config fixture fourth standard fifth content file UID should be 'abc123' but was '%s'", standardFour.ContentFiles[4].UID)
}
if standardThree.ContentFiles[4].MaxCheckpointSubmissions != 1 {
t.Errorf("test-block-with-config fixture third standard fifth content file MaxCheckpointSubmissions should be 1 but was %d", standardThree.ContentFiles[4].MaxCheckpointSubmissions)
if standardFour.ContentFiles[4].MaxCheckpointSubmissions != 1 {
t.Errorf("test-block-with-config fixture fourth standard fifth content file MaxCheckpointSubmissions should be 1 but was %d", standardFour.ContentFiles[4].MaxCheckpointSubmissions)
}
if standardThree.ContentFiles[4].TimeLimit != 45 {
t.Errorf("test-block-with-config fixture third standard fifth content file TimeLimit should be 45 but was %d", standardThree.ContentFiles[4].TimeLimit)
if standardFour.ContentFiles[4].TimeLimit != 45 {
t.Errorf("test-block-with-config fixture fourth standard fifth content file TimeLimit should be 45 but was %d", standardFour.ContentFiles[4].TimeLimit)
}
if !standardThree.ContentFiles[4].Autoscore {
t.Errorf("test-block-with-config fixture third standard fifth content file Autscore should be true but was false")
if !standardFour.ContentFiles[4].Autoscore {
t.Errorf("test-block-with-config fixture fourth standard fifth content file Autscore should be true but was false")
}
}

Expand Down
24 changes: 22 additions & 2 deletions app/cmd/markdown.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@ var templates = map[string]temp{
"configyaml": {"config.yaml syntax", configyamlTemplate, configyamlTemplateMin, false},
"cry": {"course.yaml syntax", courseyamlTemplate, courseyamlTemplateMin, false},
"courseyaml": {"course.yaml syntax", courseyamlTemplate, courseyamlTemplateMin, false},
"dsy": {"description.yaml syntax", descYamlTemplate, descYamlTemplateMin, true},
"descyaml": {"description.yaml syntax", descYamlTemplate, descYamlTemplateMin, true},
"callout": {"Callout markdown", calloutTemplate, calloutTemplateMin, false},
"co": {"Callout markdown", calloutTemplate, calloutTemplateMin, false},
"upload": {"Upload markdown", uploadTemplate, uploadTemplateMin, true},
Expand Down Expand Up @@ -216,9 +218,10 @@ Questions:
testableproject (tpr)
Other Markdown:
callout (co)
Configuration:
Yaml Configuration:
configyaml (cfy)
courseyaml (cry)`
courseyaml (cry)
descyaml (dsy)`

const fileHeaderTemplate = `---
# BEGIN FILE CONFIGURATION YML HEADER >>>>>
Expand Down Expand Up @@ -1441,6 +1444,23 @@ Course:
- URL:
DefaultUpdates: auto`

const descYamlTemplate = `# description.yaml file template, defines Unit/Standard details when generating an autoconfig.yaml
# Populates a file called 'description.yaml'. When placed in a unit directory, autoconfig.yaml generation will read this file
# and apply these settings to the block's autoconfig.
---
Title: [Unit Title] (appears when viewing content files or curriculum overview)
Description: [Description] (longer text shown with each Title on curriculum overview)
UID: %s
SuccessCriteria:
- [Success Criteria] (define what success for this Unit means)
`
const descYamlTemplateMin = `---
Title:
Description:
UID: %s
SuccessCriteria:
-`

const calloutTemplate = `<!-- available callout types: info, success, warning, danger, secondary, star -->
### !callout-info
Expand Down
10 changes: 10 additions & 0 deletions fixtures/test-block-no-config/autoconfig.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,16 @@ Standards:
- Type: Resource
Path: /units/03.resource/name.resource.md
UID: 2726a7a33276eaef4a8e143d824d9d1e
- Title: Title From Yaml
UID: 02210548f12da09aa7a0bd1f1308c423
Description: My description here
SuccessCriteria:
- success
- criteria
ContentFiles:
- Type: Lesson
Path: /units/04.description/01-lesson.md
UID: 124943de1a85fe1e147273bd967b2eec
- Title: Unit 1
UID: 02210548f12da09aa7a0bd1f1308c423
Description: Unit 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Lesson
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Title: Title From Yaml
Description: My description here
UID: 02210548f12da09aa7a0bd1f1308c423
SuccessCriteria:
- success
- criteria

0 comments on commit 838191b

Please sign in to comment.