Compiling a tutorial from a Git repository

Structure of git repo

Each tutorial is in its own branch of the repo, and has its own top-level directory within the repo. We imagine such branches will very often have their history re-written as we think of clearer ways of structuring the development of the code.

The structure of the development of the code (its decomposition into sections etc.) is provided by the tutorial.md document.

To identify particular commits touching the code.py file, the author adds a slug to the commit message by starting the subject with a string like:

{#fire-alien-missile}

To refer to such a commit in the tutorial text, and bring in an interactive patch element to the presentation, the author writes a paragraph consisting of just a particular shortcode into the tutorial.md file like:

{{< commit fire-alien-missile >}}

(These shortcodes are modelled on Hugo’s.)

Creating a new tutorial

There is an experimental tool for creating the necessary file and repo structures for a new tutorial. Within the pytch-tutorials repo, and assuming the pytch-build repo is a sibling to the pytch-tutorials repo, run something like:

poetry run -P ../pytch-build \
  pytchbuild-new-tutorial \
  --tutorial-name="Collect the diamonds" \
  --tutorial-branch=bn/collect-diamonds-01 \
  --tutorial-slug=collect-diamonds

Where the three inputs give the short human-readable name, the branch name to be created, and the name of the directory to be created.

Structure of tutorial markdown file

Consists of front matter followed by chapters.

Front matter

Start with level-1 heading naming the project. Then whatever you like, then a horizonal rule. The rule marks the end of the front matter and does not appear in the rendered tutorial.

Typically the rendered front matter will include a try the project button, which is generated by the shortcode:

{{< run-finished-project >}}

It will also typically include credits, including perhaps by use of the shortcode:

{{< asset-credits >}}

which brings in the credit information from the messages of commits adding assets.

Chapters

After the horizontal rule, the markdown file should contain the chapters of the tutorial. Each chapter starts with a level-2 heading and continues until either the next level-2 heading or the end of the file. Within each chapter, level-3 or lower-level headings can be used, as can any other markdown features.

Showing patches

At a point where the tutorial wants to show the exact change to the code required to do the next step of the project, the author can write a paragraph consisting of a commit shortcode:

{{< commit fire-alien-missile >}}

The compiler transforms this into a <div> with a particular structure which can be picked up by the front end, to add interactivity features.

(Currently the complete text of the code.py file as of that commit is included as a data attribute. This was used for an experimental make mine like this feature, but currently is unused. It bloats the HTML fragment considerably. Remove it? Recover it from the sequence of patches?)

Generating commit shortcodes for all code commits

The tool pytchbuild-emit-commit-slugs-markdown will emit, to stdout, markdown text consisting of a sequence of commit shortcodes, one per code commit in the history. This can be copied into the tutorial.md file as a basis for writing the tutorial text.

Project assets

The project will require graphics and maybe sound assets. These files should be added in standard git commits. More than one asset can be added in a single commit, but such commits should not include any other changes.

The commit message should include copyright and licence information, for example creative commons, source attribution, etc. This is free-form markdown, and the text is gathered by the tutorial-compiler and made available via the asset-credits shortcode.

Current thinking is that assets will be added and then left unchanged. Is there a use-case for modifying the graphics as part of the tutorial? If so, how to encode version information in the code?

Tutorial assets

Assets for use in the tutorial itself, for example screenshots, can be included in a tutorial-assets directory. Commits adding such assets should have credits/licence information along the same lines as the information given for project assets.

Tutorial summary file

The tutorial directory should also include a summary.md file at top-level (so next to the tutorial.md file). It should start with a screenshot image, created along the lines of:

![Screenshot](summary-screenshot.png)

and after that should have a H1 line, such as:

# Boing — a Pong-like game

and after that is free-form, but should be kept fairly short. One paragraph of a few lines is enough.

Output from compiler

Zipfile containing a single directory at top level, whose name is taken from the sole directoy at top-level in the repo (as of the tip of the branch containing that particular tutorial). Within that directory, the contents are:

  • tutorial.html — HTML fragment suitable for loading by interactive tutorial mechanism in webapp.

  • project-assets/ — Directory containing images and/or sounds as required by project which the tutorial explains. Within the tutorial Python, the URL is taken to refer to an object under project-assets/.

TODO: This information is independent of the fact that the zipfile came from a git repo. Move it to the general tutorial-structure.rst file?

Internals

The following is cut/paste from an earlier version of the tool and needs revising:

We collect the tutorial into chapters; each chapter is a list of elements. An ‘interactive patch’ element gets turned into a DIV with the relevant patch as a table, as well as extra metadata. Each chapter starts with an H2 and continues until either the next H2 or the end of the whole document.

Outline design

Major pieces are:

class Asset

Graphics or sound asset belonging to project

Distinction is (or will be) against tutorial asset, e.g., a screenshot to be included in the presentation.

Contains path (QN: relative to what?) and data-bytes. Relative to git root?

class ProjectCommit

Individual commit from history

Construct from repo and commit-OID.

Different types of commit:

  • Identified commit belonging to project being developed: Expect this to be used in tutorial.

  • Addition of asset/s: E.g., adding a graphics file.

  • The unique base commit: How much code should there be in this? Just the import stuff at the top?

  • Updates just to the raw markdown of the tutorial text: Ignored when generating tutorial.

  • TODO: Addition of tutorial assets, e.g., screenshots.

added_assets

A list of Asset instances.

QN: A given ProjectCommit might add more than one asset. We also have an explicit (but possibly redundant) tag in the commit message to flag a commit as adding assets. What if the tag and the actual commit disagree? Should it be possible to do added_assets on any ProjectCommit? Should this return an empty list if there are no added assets? Emit a warning if it adds assets but doesn’t include the add-project-assets tag (or vice versa)? TODO: That tag is no longer used I think?

maybe_identifying_slug

The text of the identifying slug, if one present, otherwise None.

is_base: bool

Whether the commit message contains the magic ‘this is the base’ tag.

modified_tutorial_text

Whether the commit updates just the TOP-LEVEL-DIRECTORY/tutorial.md file, and is not otherwise tagged.

class ProjectHistory

Chain of git commits developing project from scratch.

Read in repo, starting at some commit and tracing back through first parent until a given end commit. Really just a list of ProjectCommit objects.

Ctor inputs:

  • Repo directory. Branch name with latest commit in history to process. (QN: Might one day want to support more than one ‘final’ branch, to support ‘now you try this’, or ‘alternatively we could have implemented this feature like this.)

  • Tip revision.

  • Which source to use for the tutorial text.

class TutorialRawText

Document with tutorial text and DIVs for rich content

Read in tutorial text, break down into sections, identify pieces where augmentation from the git repo is required.

Ctor inputs:

  • Filename of markdown file.

Representation:

Soup? Whose job is it to manipulate the soup to add the attributes etc. to the DIVs for interactive commits? And who owns the soup? Probably OK for it to live in the TutorialRawText, but for the convention to be that when that TutorialRawText is handed over to the TutorialBundle ctor, the contained soup is available for the TutorialBundle to mutate.

class TutorialBundle

Filesystem fragment (tutorial.html, assets/ directory)

Representation of everything needed to emit the tutorial bundle:

  • Raw text (TutorialRawText)

  • Git repo / project history (ProjectHistory)

Constructed from the above two things.

write_new_zipfile(file_or_filename)
write_to_zipfile(existing_open_zipfile)

TODOs

Validation and/or warnings would be nice, including:

  • each project asset has a path within the ‘project-assets/’ directory

  • exactly those commits tagged as adding project assets do in fact add project assets

  • all changes to the code file are tagged with identifier-slugs

  • all untagged commits are changes to the tutorial.md file

  • there is exactly one base in the history

  • the history has no merges