'rush change': what bump and why?
Tags: rush, node, conventionalcommits, monorepo
Published: 2022-07-22 08:04:09

I'm not always sure why `rush change [-v]` does, or does not, list a project. Occasionally, I would also like to see my commits, that caused rush to request a change file. You know, for due diligence :)

## Under the hood

I had a look at the rush code to make sure I understand what's happening. 

### Included in "changed projects"
First, `rush change [-v]` calls `git merge-base` to find the target commit. This would be your last merge with the `targetBranch`. 

[libraries\rush-lib\src\logic\Git.ts](https://github.com/microsoft/rushstack/blob/f1cdfb3164f1bc15cdec113f2c0e8d5bc2605cf5/libraries/rush-lib/src/logic/Git.ts#L227)
```sh
# getMergeBase() 
git --no-optional-locks merge-base -- HEAD ${targetBranch}
```

It then finds all changed files tracked by Git, which includes both, **staged and committed** changes.
[libraries\package-deps-hash\src\getRepoState.ts](https://github.com/microsoft/rushstack/blob/f1cdfb3164f1bc15cdec113f2c0e8d5bc2605cf5/libraries/package-deps-hash/src/getRepoState.ts#L288)
```sh
# getRepoChanges()
# revision: the mergeBase from the previous step
git --no-optional-locks diff-index --no-renames --no-commit-id `
--cached -z ${revision} --
```

>Yes, **staged changes** also cause your project to be listed by `rush change`

### NOT included in "changed projects"

Next, `rush change` _validates if the newly added change files match the changed packages_. It basically means that any project with a change file will be [removed](https://github.com/microsoft/rushstack/blob/f1cdfb3164f1bc15cdec113f2c0e8d5bc2605cf5/libraries/rush-lib/src/logic/ChangeFiles.ts#L42) from the "changed projects" list and in effect, you will NOT be required to create a change file. 

> It does not matter, if you made any commits AFTER a change file was generated. The project will NOT require another change file. 

## rush whatchanged

> `rush whatchanged` is a custom command that you can install using [yeoman generator](https://www.npmjs.com/package/generator-rush-conventionalcommits): `yo rush-conventionalcommits` 

Wouldn't it be useful to see what is actually causing `rush change` to request a change file? Is it staged or committed changes? And if there are commits since the last merge, to easily browse through them?
If you are using conventional commits, a change type could be suggested, to spare you time deciding on something that is already "there"

Maybe it will make it to rush at some point (see [here](https://github.com/microsoft/rushstack/issues/1659#issuecomment-1174995612)) but in the meantime, I'm using a **custom rush command** `rush whatchanged`. 

When ran without parameters, it will display summary information. 
You can see how many commits and staged files you have for each project. You also get a warning in case a change file already exists, because `rush change` will ignore this project.
![rush whatchanged no parameters](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xz7cbnz8t0fuy0tsc8po.png)

### rush whatchanges --showcommits

If a change file exists for a project, `rush whatchanges --showcommits` provides you with a history of commits done AFTER the latest change file was created.

#### shortlog
`rush whatchanges --showcommits shortlog` executes `git shortlog` and displays the output to the terminal. 
#### full
In case you have many commits and it's not comfortable to read though them in a console, use `rush whatchanges --showcommits full`. It saves the commits history to a rush temp folder:
![rush what changes showcommits full](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hevilk7a273014fpvmnv.png)
  
### rush whatchanges --recommend-changetype

This command parses your commits and analyses them, following [convenvtional commits](https://www.conventionalcommits.org/en/v1.0.0/) convention. 
If a change file already exists, only commits AFTER the latest change file are taken into account. 

![rush what changes recommend change type](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0xdnzdgh0w3t5ja9x38y.png)
 
The script invokes `git rev-list --count --grep` with a regular expression to filter and count commit messages.

#### major
To detect and count commits that may require **major** change: 
```powershell
git rev-list --count --extended-regexp --grep "(^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(.*?)?!:.*|^BREAKING CHANGE: )" -- "${projectFolder}"
```
#### minor
If no commits causing **major** change are found, the script searches for **minor** change commits:
```powershell
git rev-list --count --extended-regexp --grep "^feat((.*?))?:" -- "${projectFolder}"
```
#### patch
And finally, if there are no major or minor changes, it will see if there are any commits causing **patch** bump:
```powershell
git rev-list --count --extended-regexp --grep "^fix((.*?))?:" -- "${projectFolder}"
```
#### none
If no major/minor/patch changes are found, `none` change type is recommended. It may mean that you either didn't have changes causing version bump, or you don't use conventional commits =) I'm not differentiating between these two cases becase if the latter is true, you shouldn't be calling `rush whatchanges --recommend-changetype` =)

## Resources
You can install the yeoman generator from [npm](https://www.npmjs.com/package/generator-rush-conventionalcommits)
As always, the code is on [github](https://github.com/kkazala/generator-rush-conventionalcommits)