Download releases, generate documentation, build website, deploy, relax.
The GitHub Release Manager
automates the process of building a website and documenting APIs
for any GitHub
project. With a single command, you can run any or all of the following:
- Download all recent releases (tags) by fetching them via the GitHub API.
- Parse the JSDoc documentation of all latest releases and generate a customizable template for navigating any or all available releases.
- Run a code quality check using ESLint, by simply creating an
ESLint
configuration file. - Run any custom defined
test
routine by running npm test. - Use Metalsmith to build a full-fledged website from markdown files, handlebars templates, libSass, and more.
- Deploy to GitHub Pages.
Much of this is done through a single vinyl file stream (built on top of Gulp, for maximum peformance. It also provides an interface for running custom build operations and/or validating/preventing the build.
Additionally, GRM
allows you to serve the website for debugging / development using Browsersync.
GitHub Release Manager
(GRM
) can be installed locally or globally, and includes both a node interface and a command-line interface (CLI). It also includes a CLI adapter to easily integrate the node interface into any existing node
-based command-line program.
$ npm install --global gh-release-manager # avalable everywhere
$ npm install --save gh-release-manager
# optionally link the script to node_modules/gh-release-manager
# (does NOT install the module globally)
$ cd node_modules/gh-release-manager && npm link
There are three ways to interface with the GitHub Release Manager
:
- Using the command-line interface
- Using the node interface
- Using the CLI adapter
There is also a long list of options that can be used to customize the behavior.
The package name (gh-release-manager
) is also the command when using the CLI
. However, GRM
also uses node-alias to set up a short command, grm
.
Additionally, each option has a short option format that is compatible with the CLI
.
Display the contents of the manual:
$ grm help
Do it all in one go:
$ grm
Or, run one of the sub commands.
Although it is often most convenient to do it all in one go, there may be a use case that involves running the steps individually (i.e. debugging, serving, etc). For that reason, GRM
is a collection of sub commands (or just simply "commands"
). By default, if no [command]
is specified, grm-release(1) is run.
Every command has a help
file. Simply run:
$ grm help [command]
This will display the information about the command, including all of the available options for that command.
Use Metalsmith to build a full-fledged website from markdown files, handlebars templates, libSass, and more.
$ grm build
available options: opts, build, quiet, urlBase, verbose
GRM
includes a bundle of tools for dynamically building a website; similar to popular tools like Jekyll. However, the toolset provided in GRM
is much more powerful, as it is built on top of Metalsmith. It runs purely in node
, so there is no extra Ruby
dependency. It also integrates seamlessly with the vinyl
pipeline for exceptional performance.
To take advantage of this toolset, get familiar with Handlebars which is used as the templating engine, and Sass which is the included CSS
preprocessor.
Then, all you need to do is to start creating files according to the expected directory structure:
- node_modules
- gh-release-manager # this module
- source # any .md files can be placed in source/**
- css # all scss files go here
- layouts # all handlebars templates go here
- partials # all handlebars partials go here
- .eslintrc.js # see grm-lint(1)
- grm.opts # see grm.opts()
- grm.metadata.json # global template metadata (see below)
The markdown
files will also be parsed for YAML Front Matter, and the data is passed to the template and made available to handlebars
. Additionally, the following Front Matter
attribute(s) have special meaning:
---
layout: page.html # from source/layouts - defaults to page.html
---
Finally, the following data is made available to all Handlebars
templates:
-
content
- Contains the marked-generatedHTML
. Should use triple-brackets (i.e.{{{content}}}
) to escape HTML. -
site
- A merged object containing:- All global template metadata read from the
grm.metadata.json
file in the project root. urlBase
, if set by options.urlBase. Useful for generating url prefixes, i.e.{{site.urlBase}}/images.png
If the
grm.metadata.json
file does not exist, and options.urlBase is not set,site
will beundefined
. - All global template metadata read from the
Example grm.metadata.json
:
{
"title": "Lodash.com"
}
...and an example usage, in a custom head.html
:
<!-- If 'title' is set in the 'Front Matter' for the page,
use it and the global 'site.title' from 'grm.metadata.json' -->
<title>{{#if title}}{{title}} | {{site.title}}{{else}}{{site.title}}{{/if}}</title>
Also, custom build tasks can be automated and included in the pipeline when build
is run.
Additionally, all markdown
files are parsed for code blocks using highlight.js. There are over 65 themes to choose from. The import path for all highlight.js
styles is included in the build
process, so simply import the theme you want by name in your SCSS/CSS
file, i.e.:
@import 'github-gist';
See the lodash.github.io project for an example implementation of gh-release-manager
.
Deploy the build directory to
gh-pages
.
$ grm deploy
available options: opts, quiet, verbose
The final step of the release routine. Uses GitHub Pages for deployment. Pushes the build/
folder to gh-pages
. Assumes the current working directory is a Git
repository, and uses its remote url.
Download recent releases via the GitHub Tags API.
$ grm download
available options: opts, keep, lib, quiet, repo, top, verbose
- The [top] most recent releases are fetched from [repo].
- The full set of releases is filtered to only include "stable" releases (in the format
/^[vV]?\d+\.\d+\.\d+$/
, i.e.v1.0.0
or1.0.0
). - The files located at [lib] (relative to the repo) are stored in [keep] (if provided), each in a subdirectory named after the release (i.e.
[keep]/1.0.0
).
- If
[keep]
is not provided,GRM
will store the downloaded files in a temporary directory that is deleted after success or failure. - If
[lib]
is not provided,GRM
will assume the file to be stored is located at[project root]/index.js
. - If
[repo]
is not provided,GRM
will prompt for input in the format[org/repo]
. - If
[top]
is not provided,GRM
will fetch the top (most recent) release.
When specifying the [top] option, be sure to consider that it identifies the total number of releases to download, which are then filtered to only include stable releases.
Parse JSDoc headers for locally-downloaded releases.
$ grm jsdoc
available options: opts, keep, quiet, verbose
The JavaScript
files located at [keep] are parsed for JSDoc comment blocks.
When running release, if
[keep]
is not set, files are stored in atmp
directory and parsed from there.
Supports all JSDoc
JSON configuration. GRM
will look in the current working directory for a file called jsdoc.conf.json
and inherit the provided configuration. By default, the following options are set:
configure
- Points to the project root as the location of jsdoc.conf.json.destination
- Points tobuild/docs/[release]
.encoding
- UTF8.recurse
- Generates documentation recursively through the releases ([keep]
) directory.template
- DocStrap (highly customizable).
Any of the default options can be overridden using config.opts.
Run code quality check using ESLint.
$ grm lint
available options: opts, quiet, verbose
When this command is run, the GRM
will look for an ESLint configuration file in the current working directory. It will accept any valid ESLint
configuration file:
- .eslintrc.js
- .eslintrc.yaml
- .eslintrc.yml
- .eslintrc.json
- .eslintrc
If the file does not exist, a warning will be displayed (if verbosity is high enough), but the task will not exit with an error.
It then runs ESLint
with the supplied configuration against all JavaScript
files with the exception of the node_modules/
folder.
Do it all in one go.
$ grm release
$ grm # alias
all common options, plus deploy.
As mentioned earlier, grm-release(1)
is the default command run when no sub command is specified. This will run all of the sub commands, with the exception of grm-serve(1) in the following order:
- grm-download(1)
- grm-jsdoc(1)
- grm-test(1)
- grm-lint(1)
- grm-build(1)
- grm-deploy(1) can be skipped using the deploy option
Serve the website for debugging / development using Browsersync.
$ grm serve
available options: opts, port, quiet, urlBase, verbose
Launchs a static server with Browsersync, and re-builds/re-loads when necessary by using gaze to observe file changes. Additionally uses opn to automatically launch a browser to the base url.
If only making changes to .scss
files, the new styles will be injected automatically and the browser will not refresh; the changes will be seen immediately. If making changes to HTML
/ markdown
files, the browser will automatically refresh once the full build of the website completes.
- If
[port]
is not provided, the website will be served on port3000
. - If
[urlBase]
is set, the server will alias all requests by removing urlBase when doing a static file lookup. Also opens the browser to the base URL.
Run a custom
test
routine usingnpm test
, if it exists
$ grm test
available options: opts, quiet, verbose
Simply runs npm test
with run-script. The one main difference is that grm test
captures any errors that result from the test
script not existing in package.json
.
Useful when run as a part of a larger pipeline, i.e. when running the release command.
GRM
also includes a node
interface, which works the same way as the CLI. All of the available options are the same, and the interface can run any of the commands. For example:
const grm = require('gh-release-manager');
grm('download', {
keep: 'releases',
lib 'lib/module.js'
repo: 'justinhelmer/gh-release-manager'
top: 5,
verbose 2
});
It returns a Bluebird promise, for easy async
support and error handling, i.e.:
const grm = require('gh-release-manager');
const options = {
keep: 'releases',
lib 'lib/module.js'
repo: 'justinhelmer/gh-release-manager'
top: 5,
verbose 2
};
grm('download', options)
.then(function() {
console.log('success!');
})
.catch(function(err) {
console.error(err);
})
.done();
GRM
also includes a CLI adapter to easily integrate the node interface into any exiting node
-based command-line program. It uses commander.js to create a command-line program that integrates with the GRM
node interface and exposes only the desired options.
{string} The GRM
command to run.
{string} The description of the interface, which is displayed with the help documentation, i.e. foo help [command]
.
{object} An array of {string} values representing which options to expose. Should use the short option format, with the dash (-
) omitted. By default, o
, q
, and v
(for --opts, --quiet, and --verbose) are always exposed, so there is no need to supply them.
For example:
#!/usr/bin/env node
(function() {
'use strict';
const grm = require('gh-release-manager');
const desc = 'Download the top <t> recent releases for "foo/bar" project and store them in [k]';
grm.cli('download', desc, ['t', 'k']);
})();
When using the CLI adapter
, GRM
will always check for a grm.opts file. This way, a custom command-line program can specify project-level defaults for options, and expose only the options that should be configurable by the program consumer.
Options can be specified via the CLI
or through the node
interface. In either case, the options are the same.
The only exception is that CLI
args (as well as grm.opts) use kebab-case
while the node
interface accepts args in camelCase
format (i.e. url-base
for the CLI
vs. urlBase
for the node
interface). This is to match the conventions of the respective constructs.
Several of the options are common
across the sub commands.
{string} The path to an optional grm.opts file. CLI
args take precedence.
used by: all sub commands
{string} The path to a module that runs custom build
operations before running the build operations included by GRM
. The module should return false
to prevent the remaining build
operations from running, without throwing an error or stopping the pipeline.
Alternatively, a promise can be returned that if fulfilled with the boolean value false
will prevent the remaining build operations from running.
Can use vinyl-tasks for running streaming operations easily.
{boolean} Skip the deploy step during release (i.e. perform a "dry run") by setting this to false
. Defaults to true
.
used by: release
Since the default behavior of release is to deploy, the
CLI
accepts a--no-deploy
flag instead of using--deploy false
.
{boolean} Force push to gh-pages
during deployment.
By default, the deploy
command will not force push to GitHub Pages. Set this option to true
to reverse that behavior.
{string} The path to where releases should be stored. If this option is not set, downloaded files will be deleted when the process exits, whether it succeeds or fails.
used by: download, jsdoc, release
{string} The relative path to the file to parse for JSDoc
headers; assumes the same relative path for all releases. If not set, [project root]/index.js
is assumed.
used by: download, jsdoc, release
{string} The port number to launch a development server using Browsersync. If not set, [project root]/index.js
is assumed.
used by: serve
{boolean} Suppress all output (STDOUT
and STDERR
). Defaults to false
.
used by: all sub commands
{string} The repository to fetch releases for (in the format org/repo
) via the GitHub Tags API. If not set, will be prompted to enter it.
used by: deploy, download, release
{number} The number of recent releases to fetch. Without specifying, will grab the most recent release (top=1
).
When specifying the [top] option, be sure to consider that it identifies the total number of releases to download, which are then filtered to only include stable releases.
{string} The base used to serve the website. Also passed as metadata
to the Handlebars
templates during build.
used by: build, release, serve
{mixed} Show more output. Can be true
, false
, or a number to specify the verbosity level. Defaults to false
.
used by: all sub commands
Additionally, a path can be provided using opts
to point to a configuration file for parsing.
If opts
is not provided, GRM
will look in the current working directory for a file called grm.opts
.
The grm.opts
file should be in the following format (example grm.opts
file):
--build lib/build.js
--force true
--keep releases
--lib lib/module.js
--port 8000
--quiet false
--repo justinhelmer/gh-release-manager
--top 5
--url-base /gh-release-manager.github.io
--verbose 2
The
grm.opts
file must use the long format of the option, not the short format (i.e.-d
,-k
, etc. will be igored).
For less typing. Only works with the CLI interface and for exposing options using the CLI adapter.
Long | Short |
---|---|
--opts | -o |
--build | -b |
--no-deploy | -n |
--force | -f |
--keep | -k |
--lib | -l |
--port | -p |
--quiet | -q |
--repo | -r |
--top | -t |
--urlBase | -u |
--verbose | -v |
If there are additional build
steps that need to happen outside of what GRM
provides out-of-the-box, or any pre-conditions that need to be run before executing the build, use options.build.
This will allow the execution of any arbitrary functionality, such as running additional operations using vinyl-tasks. It also provides the ability to stop the build from running.
The MIT License (MIT)
Copyright (c) 2016 Justin Helmer
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.