# All Configurations

# monorepo

default: undefined

// example
module.exports = {
  monorepo: {
    mainVersionFile: 'package.json',
    packagesToBump: ['packages/*', 'examples/*'],
    packagesToPublish: ['packages/*'],
    updateDependencies: true // optional, default: true
  },
};

If monorepo is defined, Ship.js will treat the project as a monorepo.

NOTICE

Ship.js currently does not provide independent versioning. It means all the packages in the monorepo must have the same version.

# shipjs prepare

  1. Ship.js reads version from mainVersionFile.
  2. When next version is decided, Ship.js will update the version at mainVersionFile.
  3. Ship.js will update all the versions in packagesToBump.
  4. When updateDependencies: true, it updates the dependencies, too.

For example,

// ship.config.js
packagesToBump: ['packages/my-package-core', 'packages/my-package-js']
// packages/my-package-js/package.json
{
  ...
  "dependencies": {
    "my-package-core": "^x.y.z"
  }
}

Ship.js will check dependencies, devDependencies and peerDependencies and update the version to the latest. If you don't want this behavior, put updateDependencies: false in the config.

# shipjs trigger

  1. Ship.js will only publish the packages from packagesToPublish.

# shouldPrepare

used at: shipjs prepare

default: undefined

// example
shouldPrepare: ({
  commits,
  nextVersion,
  releaseType,
  releaseTag,
  commitNumbersPerType,
}) => {
  /* ... */
};

This is a lifecycle hook where you can decide whether or not to proceed with the preparation.

  • commits: string of commit titles. Be aware that it's not an array of strings. It comes from git log --pretty=format:%s.
  • nextVersion: x.y.z
  • releaseType: 'major' | 'minor' | 'patch' | 'prerelease'
  • releaseTag: 'latest' | 'alpha' | 'beta' | ...
  • commitNumbersPerType: an object with keys of conventional commit type, and with values of number of commits of the type. { feat: 2, fix: 4, chore: 8 }
// example
shouldPrepare: ({ releaseType, commitNumbersPerType }) => {
  const { fix = 0 } = commitNumbersPerType;
  if (releaseType === 'patch' && fix === 0) {
    return false;
  }
  return true;
};

With the config above, you can skip if it's going to be a patch release but without any fix commits.

# updateChangelog

used at: shipjs prepare

default: true

If false, Ship.js won't run conventional-changelog during shipjs prepare.

# conventionalChangelogArgs

used at: shipjs prepare

default: '-p angular -i CHANGELOG.md -s'

This is passed to conventional-changelog CLI to update CHANGELOG.md.

# installCommand

used at: shipjs prepare

default:

installCommand: ({ isYarn }) =>
    isYarn ? 'yarn install --silent' : 'npm install'`

# getNextVersion

used at: shipjs prepare

default: undefined

This hook determines what the next version should be. It returns the next version as string. If not given, by default, Ship.js follows conventional commits.

  • revisionRange: for example, v0.1.0..HEAD
  • commitTitles: string of commit titles. Be aware that it's not an array of strings. It comes from git log --pretty=format:%s.
  • commitBodies: string of commit bodies. Be aware that it's not an array of strings. It comes from git log --pretty=format:%b.
  • currentVersion: for example, 0.1.0
  • dir: current working dir
// example
getNextVersion: ({ revisionRange, commitTitles, commitBodies, currentVersion, dir }) => {
  // do something
  return nextVersion; // for example, `"0.2.0"`
}

# versionUpdated

used at: shipjs prepare

default: undefined

// example
versionUpdated: ({ version, releaseType, dir, exec }) => {
  /* ... */
};

This is a lifecycle hook where you can put additional code after version is updated. You can read an example here.

  • version: x.y.z
  • releaseType: 'major' | 'minor' | 'patch' | 'prerelease'
  • dir: current working dir
  • exec: shelljs.exec bound with the dir.
    • For example, exec('yarn some-command')
    • This is a synchronous function.

# beforeCommitChanges

used at: shipjs prepare

default: undefined

// example
beforeCommitChanges: ({ nextVersion, releaseType, exec, dir }) => {
  /* ... */
};

This is a lifecycle hook which is executed right before git commit happens. You can put additional code like modifying some other files.

# pullRequestReviewers

used at: shipjs prepare

default: undefined

You can put an array of strings.

pullRequestReviewers: ['user1', 'user2', 'user3'];

One thing you need to be aware of is, you cannot assign yourself as a reviewer. You can put github username of your team or colleagues.

# pullRequestTeamReviewers

used at: shipjs prepare

default: undefined

You can put an array of strings.

pullRequestTeamReviewers: ['team-username1'];

# buildCommand

used at: shipjs trigger

default:

buildCommand: ({ isYarn, version }) =>
  isYarn ? 'yarn build' : 'npm run build';

If there's nothing to build before publishing, you can skip this step:

buildCommand: () => null;

# beforePublish

used at: shipjs trigger

default: undefined

// example
beforePublish: ({ exec, dir }) => {
  /* do something */
};

# publishCommand

used at: shipjs trigger

default:

publishCommand: ({ isYarn, tag, defaultCommand, dir }) => defaultCommand;

defaultCommand:

isYarn
  ? `npm_config_registry=https://registry.npmjs.org/ npm publish --tag ${tag}`
  : `npm publish --tag ${tag}`;

By default, publishCommand will return npm publish ....

# Scoped Package

If your project is a scoped package and you want it to be public, you need to add --access public to the publish command. To do so,

publishCommand: ({ isYarn, tag, defaultCommand, dir }) =>
  `${defaultCommand} --access public`;

# Monorepo

If your project is a monorepo and if you want to use different publish command per package,

publishCommand: ({ isYarn, tag, defaultCommand, dir }) => {
  if (dir.endsWith('/website')) {
    return 'npx now';
  } else {
    return defaultCommand;
  }
};

# afterPublish

used at: shipjs trigger

default: undefined

// example
afterPublish: ({ exec, dir, version, releaseTag }) => {
  /* do something */
};

# testCommandBeforeRelease

used at: shipjs trigger

default: undefined

Ship.js runs this command at shipjs trigger before publishing the package to make sure if it works correctly.

By default, it's undefined because you may already have a CI service running tests on your GitHub PR.

If you want to run something right before release, you can do so like the following:

testCommandBeforeRelease: ({ isYarn }) =>
  isYarn ? 'yarn test' : 'npm run test';

# releases

used at: shipjs trigger

default: undefined

By default, Ship.js will create a release on "releases" tab at GitHub.

By defining releases, you can optionally attach assets or customize content of release.

// example
releases: {
  assetsToUpload, // optional
  extractChangelog, // optional
}
  • assetsToUpload: String | String[] | Function
    • archive.zip
    • archive.*.zip
    • ['package.json', 'dist/*.zip']
    • ({dir, version, tagName}) => [...]
  • extractChangelog: ({ version, dir }) => 'some specific changelog to that version'

# appName

used at: shipjs trigger

default: undefined

// example
appName: 'My Awesome Package';

This is used when Ship.js sends message to your Slack channel. If it's undefined, Ship.js will take name from your package.json by default.

# Messaging to Slack

used at: shipjs trigger

If you configure an environment variable SLACK_INCOMING_HOOK, Ship.js will send messages

  • when shipjs prepare is finished (prepare)
  • when shipjs trigger is finished (releaseSuccess)

You can specify sender's username:

slack: {
  default: {
    username: 'My Release Bot',
  }
}

As described above, there are three phases of Slack messages: prepare and releaseSuccess.

You can customize the messages. The following is the default value. You can read this documentation from Slack to learn how to format messages.

slack: {
  prepared: ({ appName, version, pullRequestUrl }) => ({
    pretext: `:writing_hand: The release for *${appName}@${version}* is prepared!`,
    fields: [
      {
        title: 'Branch',
        value: 'master',
        short: true,
      },
      {
        title: 'Version',
        value: version,
        short: true,
      },
      {
        title: 'Pull Request',
        value: pullRequestUrl,
        short: false,
      },
    ],
  }),
  releaseSuccess: ({
    appName,
    version,
    latestCommitHash,
    latestCommitUrl,
    repoURL,
  }) => ({
    pretext: `:tada: Successfully released *${appName}@${version}*`,
    fields: [
      {
        title: 'Branch',
        value: 'master',
        short: true,
      },
      {
        title: 'Commit',
        value: `*<${latestCommitUrl}|${latestCommitHash}>*`,
        short: true,
      },
      {
        title: 'Version',
        value: version,
        short: true,
      },
      {
        title: 'CHANGELOG',
        value: `${repoURL}/blob/master/CHANGELOG.md`,
      },
    ],
  }),
}

If you don't want, you can skip some of the messages:

slack: {
  prepared: null,
}

In this way, Ship.js won't send a message when a pull request is prepared.

When Ship.js loads your ship.config.js, it deep-merges slack object.

defaultConfig = {
  slack: {
    default: {
      username: 'Ship.js',
    },
    prepared: () => {
      /* ... */
    },
    releaseSuccess: () => {
      /* ... */
    },
  },
};

yourConfig = {
  slack: {
    prepared: null,
  },
};

finalConfig = {
  slack: {
    default: {
      username: 'Ship.js',
    },
    prepared: null, // <- only this is affected
    releaseSuccess: () => {
      /* ... */
    },
  },
};