Exercises for use in the GitStream interactive Git tutor.
src/exercises
.
This will be the name of the repository that users clone.N-exerciseName
where N is a number used to order
the exercises.
Omitting the N-
will cause the exercise to be ignored by GitStream.conf.js
.resources
subdirectory.Great! Now you're ready to configure the exercise!
Add any necessary resources to the resources/
folder and then continue on to
populating the conf file.
When you are finished designing an exercise, build them by running
$ ./createx.js
Remember to either link your gitstream-exercises
directory into GitStream's or edit the
GitStream package.json
to point gitstream-exercises
to your own repo!
conf.js
templateThe following is a minimal template for the conf.js
file.
'use strict'
// place constants and static functions here
module.exports = {
// conf that applies to exercise (in general)
global: {
},
// description of server-side state machine
machine: {
startState: 'aDoneState', // name of the start state
aDoneState: null // null means done
},
// description of what the user sees in-browser
viewer: {
title: 'The title of the exercise',
steps: {
// HTML descriptions of the goal of each step
},
feedback: {
// HTML shown beneath the step when
// transitioning from one state to another
}
},
// optional: conf for custom generation of exercise repo
repo: {
// description of the commits to be made
}
}
global
timeLimited
constant was previously required but
has since been deprecated [January 2024].machine
startState:String
-
The name of the state (step) on which the exercise starts.
This state must be present in the machine
object.
Other than the startState
, keys are the names of states and their values can be one of the following:
String
- Steps into the named state.
loopyState: 'loopyState'
is probably a bad idea.null
- Denotes a halt state. Stepping into a halt state causes the "Done!" step
to be highlighted.Object
- The most common (and useful) option is an object mapping event names to
callback functions performed when the event is triggered.onReceive: function( repo, action, info, done )
For every event (except 404
and receive
), there are two options for registering callbacks.
The first and most common mode is as a listener and the second is as a handler.
The difference is that the handler is called synchronously (i.e. the exercise will not continue until the handler calls the provided callbacks or times out).
The key name in the state object and callback function signature is as follows:
onEventName: function( repo, action, info, done )
repo:String
- the name of the repo (e.g. nhynes/gitstream)action:String
- the name of the event that triggered this callback
(which is usually known in advance)info:Object
- additional information associated with the action (see below)done:Function
- call with a state name or null to step into that state or with no
arguments to remain in the current state without triggering a stephandleEventName: function( repo, action, info, gitDone, stepDone )
repo:String
- the name of the repoaction:String
- the name of the event that triggered this callbackinfo:Object
- additional information associated with the action (see below)gitDone:Function
- call with no arguments to allow the in-progress Git operation to
complete or call with exitCode:Number
and optional feedback
to be displayed in the terminal.
Depending on the operation, a non-zero exit code will prevent
its completion (see githooks)stepDone:Function
- accepts the same arguments as done
, above, with a final
positional argument passed to the viewer as stepOutput
.Event | Description | info |
---|---|---|
Clone | Happens when a user clones the already-created repository. | |
PostCheckout* | Happens when a user checks out a ref |
prevHead:String - the ref of the prevous HEADnewHead:String - the ref of the new HEADchBranch:Boolean - whether the branche changed |
(Pre|Post)Commit* | Happens after the user enters a commit message but before the commit is recorded or after the commit. PreCommit works well as a handler since cancelling the event prevents the commit from being recorded. |
msg:String - the full text of the log message (may contain comments inserted by Git)
|
(Pre)Info | Happens when Git requests information about a remote repo. Notably, this occurs before a pull. | |
Merge | Happens after a non-conflicting merge | wasSquash:Boolean - whether the merge was a squash |
(Pre)Pull |
Happens before or after a pull (and before Merge).
This is another good place to use a handler.
Note that local Git may display unexpected error messages when the remote
changes between an info and the actual operation.
|
head:String - the requested HEAD |
(Pre)Push | Happens before or after a push (and before PreReceive). A handler here can stop a push from ever reaching the remote. |
last:String - The oldest commit in the pushhead:String - The newest commit in the pushbranch:String - The name of the pushed-to branch
|
(Pre)Rebase | Occurs before a rebase | (TODO: this should forward along Git-provided data) |
(Pre)Receive | Happens before or after the remote repo receives a push (and after the PrePush). This is another good place to use a handler, except if trying to make a commit that changes the location of the requested HEAD, which causes an "unable to lock" error. |
name:String - name of the updated refold:String - old SHA pointed to by the refnew:String - new SHA pointed to by the ref
|
* Updates the Shadowbranch, a ref containing the contents of the repository.
Note: tag events can also be detected, but it requires a fix that is in a seperate PR branch (let me know if you want it merged into master).
The this
of an event callback contains several helpful methods for interacting with
the repo and automating common tasks (see the docs).
viewer
title:String
- The title of the exercise visible on the main page and at the top
of the exercise page.steps:Object
- An object mapping from step names (the same ones as in the
machine
section).
The halt states should not be included here.feedback:Object
- An object with keys that are the names states or onEnter
.
The value is a function with the following signature:function( stepOutput, cb )
where
stepOutput:Object
has keys prev
and new
that contain
the data provided to the callbacks of the previous and new
(current) statescb:Function
can optionally be called with a string that is
displayed under the newly-entered staterepo
commits:Array
- an array of commit specsNote: templating is done using Mustache syntax.
machine
and repo
sections are run on the server and can include require
calls,
but the viewer
section can only contain environment-agnostic JS.viewer
file.viewer
section, restart the GitStream server and view your changes via make run