Custom rush publishing flow
Tags: rush, publish, node
Published: 2022-10-31 18:38:24

If you are using `rush` for managing your repos, but do not want to publish your packages to NPM registry/pack them into tarballs, then the `rush publish` command is... well... of little use. 

But what if we could execute custom commands, as part of the rush publishing flow?

## Rush publishing flow

Let's have a look at the rush flow first.

> There are two stages in a Rush [publishing flow](https://rushjs.io/pages/maintainer/publishing/). The first stage is during development. Developers are asked to provide change files to track changes that deserve a space in change log. The **second stage** is at publishing time. Rush can be used to **gather all change files to increase version, update change log, and publish new packages to a npm registry**.

### Independent version policies

When [independent version policies](https://rushjs.io/pages/maintainer/publishing/#publishing-process-when-version-policies-are-used) are used in rush monorepo, the publishing process consists of two steps:

- increase version with `rush version --bump [--target-branch BRANCH]`
- publish packages with `rush publish --include-all`

In this case, the publishing step requires executing `rush publish --include-all` which, despite the documentation ("_will publish all the public packages that have version increased_") seems to [publish all](https://github.com/microsoft/rushstack/blob/831d6737547946d6814c33b8d0ce823664936f54/libraries/rush-lib/src/cli/actions/PublishAction.ts#L239) the packages.

#### increase version

`rush version --bump` versions are increased based on the change files, and change files are deleted. If you specify `--target-branch BRANCH`, changes will be committed and merged into the target branch. Neat!

At this point, the CHANGELOG.json and CHANGELOG.md files for each **changed** project are updated, and the change files are deleted.

> The CHANGELOG.md is always generated based on CHANGELOG.json and should not be manually modified, because your changes will be overridden the next time you run `rush version` or `rush publish --regenerate-changelogs`. If you need to update the change log, **edit the CHANGELOG.json** file.

#### publish packages

According to the documentation, `rush publish --include-all` will publish all the public packages that have version increased. According to the [code]((https://github.com/microsoft/rushstack/blob/831d6737547946d6814c33b8d0ce823664936f54/libraries/rush-lib/src/cli/actions/PublishAction.ts#L239)), it publishes all the projects. And quite understandably; to publish only changes, rush [needs change files](https://github.com/microsoft/rushstack/blob/831d6737547946d6814c33b8d0ce823664936f54/libraries/rush-lib/src/logic/PublishUtilities.ts#L36), which... were deleted in the previous step.

## Custom publishing flow

`rush dist:package` mimics the rush publishing flow, but it executes the rush bulk commands defined in `--package-command` and `--copy-command` parameters instead of publishing to NPM.

You probably already have your build/package commands in `package.json` of your projects. Registering them as `rush bulk` commands will allow you to use them in `rush dist:package`

I'm using `rush dist:package` to publish my SPFx projects as part of CI/CD, saving packages to Artifacts of in my Azure pipelines. 

When using `rush dist:package`, publishing process might consist of the following steps:

- increase version with `rush version --bump [--target-branch BRANCH]`
- update the **CHANGELOG.json** files if needed; do  **not edit CHANGELOG.md**, because it's generated automatically based on the CHANGELOG.json
- publish your packages using `rush dist:package --package-command COMMAND`, where `COMMAND` is a rush "bulk" command. The `dist:package` also updates **CHANGELOG.md** based on the changes to **CHANGELOG.json**. 

Since the change files are already deleted, `rush dist:package` uses a workaround: it saves the project's version retrieved from the `package.json` as a **tag** in the `rush.json` file.

When invoked for the first time, the **tag** will be missing, so all the projects will be published. To avoid that, you may manually add `published_v{lastPublishedVersion}` tags, e.g. `published_v1.6.16`

## Installing
Install from npm: 
```bash
npm i generator-rush-publish
```
or check the code on [GitHub](https://github.com/kkazala/generator-rush-publish)