Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor learn markdown subcommands into Cobra Commands with tests #128

Merged
merged 4 commits into from
Mar 9, 2024

Conversation

realistschuckle
Copy link
Contributor

NOTE: This refactor leaves the entire CLI usage exactly the same. The only difference is that the help messages for learn markdown are much more thorough.

This refactor moves all learn markdown commands into their own files and Cobra Commands. The common flags for all markdown commands are put into the PersistentFlags of the markdown command object. Those flags are then accessible to all child commands.

The newly-implemented flags for questions/challenges are now only defined for the markdown subcommands in the "questions" group.

The markdown subcommand-specific help messages now contain the same introductory text that can be found in the Learn Documentation cohort. (https://learn-2.galvanize.com/cohorts/667)

The orthogonal interest of how to write output to a destination (clipboard, stdout, append) has also been refactored into its own package (templates). This allows for independent testing of the methods of writing.

The refactor necessitated the upgrade of the Cobra library to the most recent version.

Because of this refactor, it is now possible to test markdown subcommands in isolation, not only their configuration, but also the way the execute. This has allowed for nearly 100% coverage of all Markdown-related code in the CLI.

Example output

Here's some example output for the markdown command.

learn md

This uses Cobra Command groups to group the different Markdown subcommands into different sections of the help message.

02:58:26 curtis@galvanize glearn-cli ±|command-refactor|→ ./glearn-cli md
Generate markdown for Learn content and YAML for Learn configuration

Usage:
  learn markdown [command]

Aliases:
  markdown, md

File Creation Commands
  checkpoint      (cp) Generate the content of a Checkpoint file
  fileheader      (fh) Generate the content of a File Header file
  instructor      (in) Generate the content of a Instructor file
  lesson          (ls) Generate the content of a Lesson file
  resource        (rs) Generate the content of a Resource file
  survey          (sv) Generate the content of a Survey file

Question Scaffolding Commands
  checkbox        (cb) Generate the content for a Check Box block
  customsnippet   (cs) Generate the content for a Custom Snippet block
  java            (ja) Generate the content for a Java block
  javascript      (js) Generate the content for a JavaScript block
  multiplechoice  (mc) Generate the content for a Multiple Choice block
  number          (nb) Generate the content for a Number block
  ordering        (or) Generate the content for a Ordering block
  paragraph       (pg) Generate the content for a Paragraph block
  project         (pr) Generate the content for a Project block
  python          (py) Generate the content for a Python block
  ruby            (rb) Generate the content for a Ruby block
  shortanswer     (sa) Generate the content for a Short Answer block
  sql             (sq) Generate the content for a SQL block
  tasklist        (tl) Generate the content for a Task List block
  testableproject (tpr) Generate the content for a Testable Project block
  upload          (up) Generate the content for a Upload block

Other Commands
  callout         (co) Generate the content for a Call Out block
  distributecode  (dc) Generate the content for a Distribute Code block

YAML Configuration Scaffolding Commands
  configyaml      (cfy) Generate the content for a config.yaml
  courseyaml      (cry) Generate the content for a course.yaml
  descyaml        (dsy) Generate the content for a description.yaml

Flags:
  -h, --help   help for markdown
  -m, --min    Uses a terse, minimal version of the template
  -o, --out    Prints the template to stdout

Use "learn markdown [command] --help" for more information about a command.

learn md cs --help

Here's the help message for the custom snippet subcommand. You can see a couple of things of interest:

  • The help message comes from the same documentation of the challenge type in Learn
  • Flags for question types are only for question types and not for all markdown/yaml things
02:59:53 curtis@galvanize glearn-cli ±|command-refactor|→ ./glearn-cli md cs --help
The Custom Snippet challenges allow a student to write code directly in Learn
and see the standard output from the test runner. They provide a student
experience similar to the JavaScript and Python Code Snippet Challenges.
However, the Curriculum Developer controls the Dockerfile and has all of the
flexibility of testable-project challenges.

NOTE: All custom-snippet Docker images must have the bash shell available.

Usage:
  learn markdown customsnippet [file-to-append-to] [flags]

Aliases:
  customsnippet, cs

Flags:
  -h, --help               help for customsnippet
  -e, --with-explanation   Include explanation blocks
  -n, --with-hints int     Include n number of hint blocks
  -r, --with-rubric        Include rubric blocks

Global Flags:
  -m, --min   Uses a terse, minimal version of the template
  -o, --out   Prints the template to stdout

NOTE: This refactor leaves the entire CLI usage exactly the same.
      The only difference is that the help messages for learn
      markdown are much more thorough.

This refactor moves all learn markdown commands into their own
files and Cobra Commands. The common flags for all markdown
commands are put into the PersistentFlags of the markdown
command object. Those flags are then accessible to all child
commands.

The newly-implemented flags for questions/challenges are now
only defined for the markdown subcommands in the "questions"
group.

The markdown subcommand-specific help messages now contain the
same introductory text that can be found in the Learn
Documentation cohort. (https://learn-2.galvanize.com/cohorts/667)

The orthogonal interest of how to write output to a destination
(clipboard, stdout, append) has also been refactored into its
own package (templates). This allows for independent testing
of the methods of writing.

The refactor necessitated the upgrade of the Cobra library to
the most recent version.

Because of this refactor, it is now possible to test markdown
subcommands in isolation, not only their configuration, but
also the way the execute. This has allowed for nearly 100%
coverage of all Markdown-related code in the CLI.
@realistschuckle
Copy link
Contributor Author

@pgrunde Looks like the mock framework for testing is only supported by 1.21 and 1.22. So, I'm going to push a new workflow.

@realistschuckle
Copy link
Contributor Author

Also, moving clipboard test to integration test. Can be run locally on a machine with a clipboard with:

go test ./... -tags=integration

@realistschuckle
Copy link
Contributor Author

realistschuckle commented Mar 8, 2024

@pgrunde It's now ready for you to review. Sorry about the test thing. There were no clipboard tests previously, and "it works on my machine" proved sufficient until the push.

@realistschuckle
Copy link
Contributor Author

realistschuckle commented Mar 8, 2024

Here's the coverage report with the integration test included.

$ go clean -testcache && go test ./... -cover -tags=integration | grep ok | sed 's/of statements//' | sed 's/coverage://' | column --table -N "result,path,time,coverage"

result  path                                                      time    coverage
ok      github.com/gSchool/glearn-cli/api/github                  0.009s  63.6%
ok      github.com/gSchool/glearn-cli/api/learn                   0.007s  66.8%
ok      github.com/gSchool/glearn-cli/app/cmd                     0.166s  50.0%
ok      github.com/gSchool/glearn-cli/app/cmd/markdown            0.206s  79.2%
ok      github.com/gSchool/glearn-cli/app/cmd/markdown/files      0.018s  100.0%
ok      github.com/gSchool/glearn-cli/app/cmd/markdown/others     0.032s  100.0%
ok      github.com/gSchool/glearn-cli/app/cmd/markdown/questions  0.018s  100.0%
ok      github.com/gSchool/glearn-cli/app/cmd/markdown/templates  0.006s  100.0%
ok      github.com/gSchool/glearn-cli/app/cmd/markdown/yaml       0.008s  100.0%
ok      github.com/gSchool/glearn-cli/ignorematcher               0.006s  86.7%
ok      github.com/gSchool/glearn-cli/mdresourceparser            0.007s  91.6%

Copy link
Collaborator

@pgrunde pgrunde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has allowed for nearly 100% coverage of all Markdown-related code in the CLI.

This is stellar, thanks! I've always wanted to refactor the markdown generation and add actual test coverage. Really appreciate the work here.

  • QA'd Question creation md commands for equivalent behavior to master ✅
  • QA'd File creation md commands for equivalent behavior ✅
  • QA'd Yaml creation commands for equivalent behavior ❌
  • QA'd Other commands for equivalent behavior ✅

This was performed by comparing output for each md subcommand as a diff, where one is output from glearn-cli installed from this branch command-refactor, and the other ./glearn-cli is a from a build of current master.

Using this technique I discovered that the unit description file is not properly interpolating a UID into both minified and maxified (new word!) template.

diff <(./glearn-cli md dsy -om) <(glearn-cli md dsy -om)

Or simply running the md dsy -m and see that it displays the %s instead of the UID.

I'm guessing this is because the yaml package root.go file is using templates.NewStaticTemplate when the description.yaml generator actually makes use of a generated UID. It doesn't seem appropriate though to use the full-on templates.NewAttributeTemplate here since the dsy subcommand will never have explanations, hints, rubrics, etc. Might be worth a constructor for just the id template? Of course it ruins the elegance of createYamlCommand always getting to use one template type. As with life and code, complexity ruins everything.

If it helps, here is all the commands at once for the minified output. The output for each should only show a diff of the uid fields, and it should show separate uid values on each.

diff <(./glearn-cli md cp -om) <(glearn-cli md cp -om)
diff <(./glearn-cli md fh -om) <(glearn-cli md fh -om)
diff <(./glearn-cli md in -om) <(glearn-cli md in -om)
diff <(./glearn-cli md ls -om) <(glearn-cli md ls -om)
diff <(./glearn-cli md rs -om) <(glearn-cli md rs -om)
diff <(./glearn-cli md sv -om) <(glearn-cli md sv -om)
diff <(./glearn-cli md cb -om) <(glearn-cli md cb -om)
diff <(./glearn-cli md cs -om) <(glearn-cli md cs -om)
diff <(./glearn-cli md ja -om) <(glearn-cli md ja -om)
diff <(./glearn-cli md js -om) <(glearn-cli md js -om)
diff <(./glearn-cli md mc -om) <(glearn-cli md mc -om)
diff <(./glearn-cli md nb -om) <(glearn-cli md nb -om)
diff <(./glearn-cli md or -om) <(glearn-cli md or -om)
diff <(./glearn-cli md pg -om) <(glearn-cli md pg -om)
diff <(./glearn-cli md pr -om) <(glearn-cli md pr -om)
diff <(./glearn-cli md py -om) <(glearn-cli md py -om)
diff <(./glearn-cli md rb -om) <(glearn-cli md rb -om)
diff <(./glearn-cli md sa -om) <(glearn-cli md sa -om)
diff <(./glearn-cli md sq -om) <(glearn-cli md sq -om)
diff <(./glearn-cli md tl -om) <(glearn-cli md tl -om)
diff <(./glearn-cli md up -om) <(glearn-cli md up -om)
diff <(./glearn-cli md co -om) <(glearn-cli md co -om)
diff <(./glearn-cli md dc -om) <(glearn-cli md dc -om)
diff <(./glearn-cli md cfy -om) <(glearn-cli md cfy -om)
diff <(./glearn-cli md cry -om) <(glearn-cli md cry -om)
diff <(./glearn-cli md dsy -om) <(glearn-cli md dsy -om)
diff <(./glearn-cli md tpr -om) <(glearn-cli md tpr -om)

The description.yaml file needs UID replacement. This commit
addresses that.

[x] Unit test created to demonstrate the problem
[x] YAML command parameter added to indicate the need of a UID
[x] `createYamlCommand` updated to use the new flag
[x] New flag explicitly set in all YAML commands
@realistschuckle
Copy link
Contributor Author

realistschuckle commented Mar 9, 2024

@pgrunde Thanks for those commands and your diligence!

Commit 786f5ca address the description.yaml discrepancy.


Address error in descyaml generator

The description.yaml file needs UID replacement. This commit addresses that.

  • Unit test created to demonstrate the problem
  • YAML command parameter added to indicate the need of a UID
  • createYamlCommand updated to use the new flag to create an idTemplate if the flag is true, otherwise it creates a staticTemplate
  • New flag explicitly set in all YAML commands

The test reads like this:

  • The descyaml test case has the hasUID flag set to true
  • When the test runs, if the test case has a positive hasUID, then it checks for the regular expression UID: <GUID>
re := regexp.MustCompile(`UID: [[:alnum:]]{8}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{4}-[[:alnum:]]{12}`)
if tc.hasUID {
	rendered := template.Render()
	if !re.MatchString(rendered) {
		t.Error("Did not find a UID GUID in the rendered file:\n" + rendered)
	}
}

@pgrunde pgrunde merged commit 04602e4 into gSchool:master Mar 9, 2024
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants