node package manager
Don’t reinvent the wheel. Reuse code within your team. Create a free org »

gh-release-manager

GitHub Release Manager

Download releases, generate documentation, build website, deploy, relax.

npm package node version dependency status contributions welcome devDependency status

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:

  1. Download all recent releases (tags) by fetching them via the GitHub API.
  2. Parse the JSDoc documentation of all latest releases and generate a customizable template for navigating any or all available releases.
  3. Run a code quality check using ESLint, by simply creating an ESLint configuration file.
  4. Run any custom defined test routine by running npm test.
  5. Use Metalsmith to build a full-fledged website from markdown files, handlebars templates, libSass, and more.
  6. 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.

console output

Additionally, GRM allows you to serve the website for debugging / development using Browsersync.

Installation

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.

Install globally

$ npm install --global gh-release-manager   # avalable everywhere 

Install locally

$ 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

Usage

There are three ways to interface with the GitHub Release Manager:

  1. Using the command-line interface
  2. Using the node interface
  3. Using the CLI adapter

There is also a long list of options that can be used to customize the behavior.

CLI

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.

Using the CLI

Display the contents of the manual:

$ grm help

Do it all in one go:

$ grm

Or, run one of the sub commands.

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.

grm-build(1)

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-generated HTML. 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 be undefined.

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.

grm-deploy(1)

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.

grm-download(1)

Download recent releases via the GitHub Tags API.

$ grm download

available options: opts, keep, lib, quiet, repo, top, verbose

  1. The [top] most recent releases are fetched from [repo].
  2. The full set of releases is filtered to only include "stable" releases (in the format /^[vV]?\d+\.\d+\.\d+$/, i.e. v1.0.0 or 1.0.0).
  3. 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.

grm-jsdoc(1)

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 a tmp 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 to build/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.

grm-lint(1)

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.

grm-release(1)

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:

  1. grm-download(1)
  2. grm-jsdoc(1)
  3. grm-test(1)
  4. grm-lint(1)
  5. grm-build(1)
  6. grm-deploy(1) can be skipped using the deploy option

grm-serve(1)

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 port 3000.
  • 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.

grm-test(1)

Run a custom test routine using npm 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.

Node interface

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();

CLI adapter

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.

grm.cli(command, description[, grmOptions])

command

{string} The GRM command to run.

description

{string} The description of the interface, which is displayed with the help documentation, i.e. foo help [command].

grmOptions

{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.

Common options

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.

opts

{string} The path to an optional grm.opts file. CLI args take precedence.

used by: all sub commands

build

{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.

used by: build, release

Can use vinyl-tasks for running streaming operations easily.

deploy

{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.

force

{boolean} Force push to gh-pages during deployment.

used by: deploy, release

By default, the deploy command will not force push to GitHub Pages. Set this option to true to reverse that behavior.

keep

{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

lib

{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

port

{string} The port number to launch a development server using Browsersync. If not set, [project root]/index.js is assumed.

used by: serve

quiet

{boolean} Suppress all output (STDOUT and STDERR). Defaults to false.

used by: all sub commands

repo

{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

top

{number} The number of recent releases to fetch. Without specifying, will grab the most recent release (top=1).

used by: download, 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.

urlBase

{string} The base used to serve the website. Also passed as metadata to the Handlebars templates during build.

used by: build, release, serve

verbose

{mixed} Show more output. Can be true, false, or a number to specify the verbosity level. Defaults to false.

used by: all sub commands

grm.opts

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).

Short option format

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

Custom build tasks

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.

Contributing

contributions welcome devDependency status

License

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.