artifact packaging for service builds

Usage no npm install needed!

<script type="module">
  import npmWharfShipwright from 'https://cdn.skypack.dev/@npm-wharf/shipwright';



A simple/consistent way to create build artifacts with calculated tags and then update related repositories (think packages, tarballs, docker builds, etc.).

Build Status Coverage Status

Why Not Bash?

  • copy pasta'd shell script is tough to maintain, "did I copy that change to all 20+ repos?"
  • automated testing is nicer than pushing to CI to see what will happen
  • with an increasing set of integration/features I prefer JS as a way to develop and share these features/ideas


npm i @npm-wharf/shipwright


Right now this mashes a lot of other tools into a promise chain behind a single command.

shipwright build image

Builds a docker image with all default options. Read carefully, there are kindovalot.

  • --repo - the image repository to build for, no default
  • --name - defaults to the package's name
  • --name-prefix - optionally prefix default package name
  • --name-postfix - optionally postfix default package name
  • --working-path - the working directory for the build, defaults to ./
  • --docker-file - the DockerFile to use, defaults to ./Dockerfile
  • --build-arg - used to define an ARG key in the Dockerfile. (example: `--build-arg key=value)
  • --tags - defaults are: (see buildgoggles for tag specifications)
    • lt,v_s,v,miv,ma [ 'latest', '1.2.3_abcdefgh', '1.2.3', '1.2', '1' ] - for tagged builds
    • v_c_s [ '1.2.3_10_abcdefgh' ] - for master commits
    • b_v_c_s [ 'branch_1.2.3_10_abcdefgh' ] - in any other branch when:
      • --always-build is an argument
      • --build-branches contains the current branch
      • the commit message contains [build-image]
  • --registry - defaults to hub.docker.com
  • --lts-only - defaults to true: when true, skips everything for non-LTS Node versions
  • --skip-prs - defaults to true: should anything other than a Docker build is done for PRs
  • --no-push - prevents shipwright from pushing the image to the registry
  • --update-with - specify an instruction file for how to send a PR to another GitHub repository's file
  • --sudo - defaults to true: use sudo with Docker commands
  • --verbose - defaults to false: include Docker build output in console logs
  • --always-build - always produce a build regardless of the branch by providing the default tag specification [ 'b_v_c_s' ] if no other tags have been specified
  • --build-branches - defaults to [ 'staging', 'qa', 'dev' ]: a list of branches to build for (other than master) with the default tag specification [ 'b_v_c_s' ] if no other tags have been specified.
  • --cache-from-latest - will cause shipwright to add a --cache-from argument to Docker with the current image name and the latest tag.
  • --cache-from - will cause shipwright to pass the argument on to docker's --cache-from
  • --flatten - creates a new flattened image with no history and a single layer

Use cases for --always-build and --build-branches

These flags are intended to supply ways to get shipwright to generate build images for development branches without disrupting the useful default tag specs provided for master and tagged builds and without having to constantly rely on filling your commit log with [build-image].

The build-branches defaults effectively guarantee you'll get build images if you push to branches named staging, qa, or dev.

Default Build Behavior

With all the tags, it is a bit unclear what the shipwright's default behavior actually would be if you were to, for example, just add the following lines to travis:

  - docker login -u="$DOCKER_USERNAME" -p="$DOCKER_PASSWORD"
  - shipwright build image --repo=myRepo --name=imageName 

For Builds On Master (With Git Tags On The Commit)

A docker image will get built, tagged and pushed with the following tags:

  • latest
  • 1
  • 1.2
  • 1.2.3
  • 1.2.3_abcdefgh

For Builds On Master (Without Git Tags On The Commit)

A docker image will get built, tagged and pushed with a tag that contains the version, build number and commit sha:

  • 1.2.3_10_abcdefgh

For Builds On A --build-branches (staging, qa, dev)

A docker image will get built, tagged and pushed with a tag that contains the branch name, version, build number, and commit sha:

  • branch-name_1.2.3_10_abcdefgh

For Builds With [build-image] In The Commit Message

Even without adding flags, you can still get a build on any branch with the tag specification that contains the branch, version:

  • branch-name_1.2.3_10_abcdefgh

For PRs and Builds On Non-LTS Versions of Node

shipwright won't do anything at all. This is to avoid drawing out the build times on your CI server. You can change these behaviors with the skip-prs and lts-only flags, of course, but this is about default build behavior.

Caching Support

shipwright has three different caching support options you can use to populate Docker's --cache-from argument.

In the event that any of these flags result in an error from the Docker CLI, shipwright will fall back to making the command without the --cache-from argument. If your build is not getting faster, check your log output and make sure that the image it's trying to cache from actually exists in the target Docker repository.


This flag will append the latest tag to your current image and attempt to use that to populate Docker's --cache-from argument.


This argument allows you to provide your own full specification to shipwright that it will then pass through to Docker.

updateWith - Instruction Files & PR Plugins

The updateWith argument is way to plug in your own transformers after the fact to get shipwright to send a PR to another GitHub repository in order to update a single file.

This uses github-change-remote-file so the limitation here is that it can change 1 file at a time. The transformer plugin you write will get passed a buildInfo hash with all the context of the build and the instruction file with any static arguments you'd like to pass it.

plugin format

The plugin module should export a function that takes the build information and instruction file content and returns a function that transforms the target file's contents (passed as a string) and returns the changed content.

module.exports = function( buildInfo, instructions ) {
    return function( raw ) {
      // do something to the file
      return changedContent;

instruction file

You can provide an instruction file in either JSON or YAML.

The source properties control the repository and branch the pull request will be made from and what file will be changed. The source owner, repo, and file values are required to specify the target GitHub repository and path to the file relative to the repository's root. If the source branch is left out, it will default to master. The module argument is required and should be the name of an installed npm module or the relative path to a JS module in the current repository that satisfies the plugin behavior. The branch name is also optional and if left off, will be calculated based off the current build parameters.

Any other values included in the file itself will be deserialized and passed to your plugin.

  "source": {
    "owner": "me",
    "repo": "test",
    "file": "somefile.txt",
    "branch": "master"
  "module": "myPlugin",
  "branch": "pr"
  owner: me
  repo: test
  file: somefile.txt
  branch: master
module: myPlugin
branch: pr

buildInfo hash

The build information hash will contain the following properties:

  "owner": "npm",
  "repository": "shipwright",
  "branch": "master",
  "version": "0.1.0",
  "build": 10,
  "slug": "a1b2c3d4",
  "tag": "arobson_build-goggles_master_0.1.0_1_a1b2c3d4",
  "isLTS": true,
  "commitMessage": "the commit message used",
  "ci": {
    "inCI": "true",
    "tagged": false,
    "pullRequest": false
  "imageName": "repo/image"

Note: the imageName property will only exist if an artifact (like a Docker image) was produced as part of the build


  • separate command so that build and push are represented as different steps
  • add support for additional artifact types
  • support multiple artifact types per build