microsoft / rushstack

Monorepo for tools developed by the Rush Stack community
https://rushstack.io/
Other
5.94k stars 598 forks source link

[rush] automatically generate changelog #1659

Open dbartholomae opened 4 years ago

dbartholomae commented 4 years ago

Please prefix the issue title with the project name i.e. [rush], [api-extractor] etc.

Is this a feature or a bug?

Please describe the actual behavior. I use conventional commit messages to signify any changes directly in the commit message. Currently when using rush I have to manually write changelog entries, copying over what I already wrote in the commit messages.

What is the expected behavior? It would be great if rush could extract changes from commit messages and use them to create changelogs. The semantic release project is based around this idea but currently does not support monorepos. I am not sure where this kind of functionality should live and would like to use this issue to open up the discussion. I would also be willing to contribute to this effort :)

ghost commented 4 years ago

This hasn't gone anywhere in half a year. Is this considered important or should I use semantic-release-monorepo with lerna instead?

octogonz commented 4 years ago

I'm not sure Git commits are the best way to author a changelog for a monorepo with lots of projects and teams.

Git commits document steps of work. For example, when I create a PR, I might break it into 5 separate commits that are easier to review one by one, rather than reading the entire PR diff. And then during the code review, people may suggest various improvements, which may lead to 10 more commits before I finally merge my PR. Some of these commits will be pure bookkeeping (ran "rush update", merged from master, etc). Git commits are written for the audience of people who work on the code. Whereas...

Change logs inform consumers what's new. Consumers need to know which bugs got fixed, which new features were added, or alert consumers about possible breaking changes. This audience often doesn't know anything about the underlying implementation, so a different style of writing is needed. In a monorepo, one Git commit might impact many different projects, and perhaps in a way that needs to be explained differently for each project. For certain important projects, the change log may serve as a public announcement to customers. The release team may have a step where they manually revise the changelog before publishing a release.

I see "semantic release" used mainly in smaller repos where this distinction between commits vs changelogs isn't too important. But it might not work so well as you scale up with multiple teams and projects coexisting.

If someone is willing to propose a design and help implement this for Rush, we would support you. But given Rush's goal of enabling solutions that can scale up, it doesn't seem like this would make sense as a default model that replaces rush change. And I'm not sure that it would be the right fit for the Rush Stack repo. (?)

ghost commented 4 years ago

@octogonz I disagree. Semantic-release is strongly tied to commit conventions like conventional-commit which allows it to make assumptions about the reliability of your commit message.
If rush would integrate support for conventional-commit messages (which I autogenerate with commitizen), it could easily extract changelog messages from these commits. This is a common practice by now as it helps maintaining a consistent changelog on EVERY change, without a developer having to remember certain steps and adding hassle. I'm still in strong support of adding this feature and, ideally, stronger integration with such commit message standards.

dbartholomae commented 4 years ago

Just to clear two things up:

  1. With conventional-commit not all commit messages are used for change logs. E. g. refactorings and style changes are not used. Also a lot of people I know (me included) rebase and clean up commits, so I didn't have problems with conventional-commits even for larger projects.
  2. I don't think this should be forced upon everyone. It should be optional, so if someone feels their project is too big for this, they don't need to use it.

Concerning the design what I would envision based on my understanding of RushJS architecture would be:

ghost commented 4 years ago

@dbartholomae Couldn't have expressed it better!
In addition to publishing the packages with optional, automatic semantic versioning at npm, it would be cool if we could publish to different distribution channels (/npm tags) like with semantic-release. I can't wait to switch to rush after this!

octogonz commented 4 years ago

This sounds pretty reasonable. Is anyone available to work on it?

ghost commented 4 years ago

I'm looking into the rush codebase - its the first time I'm working in it. Lets see if I'll be able to start anything in a pr. If anyone else has time, please go ahead :)

anonrig commented 4 years ago

Would love to see this feature on Rush, any progress or update on it?

dbartholomae commented 4 years ago

This is becoming more and more relevant for me. I might look into this soon. Most likely it would take the form of a separate tool that can create the change files that are usually created by rush change automatically based on conventional commits. @octogonz How stable is the JSON format used to save these changes? Does my idea make sense? I would also be willing to contribute the tool into this monorepo but might need some help how to best get this started.

anonrig commented 4 years ago

I'm willing to do the same @dbartholomae, happy to do this together if you need any help

dbartholomae commented 4 years ago

@anonrig I'm currently still on a different hobby project that will hopefully be finished in a couple days. Would love to work on this together pair programming style if you are interested and we can coordinate the time :)

kamontat commented 3 years ago

Any person working on this right now? I interesting on contribute to this story.

m1heng commented 2 years ago

Is it possible to implement this through plugin?

kkazala commented 2 years ago

In case somebody is still interested, I wrote a script creating change files based on commits, respecting conventional commits. It's described here + here. The code is on GitHub

I hope it will fit into the process described by @octogonz because I only generate change files for fix/feat/breaking changes. I would assume that developers may make more user-friendly descriptions for these cases. And there's still a possibility of either editing the change files/change log afterwards.

icy0307 commented 2 years ago

FYI, conventional commits can point to an issue directly. And the issue could be closed via CI later.

For change log, is it possible to add another prompt message? like Does this change affect any open issues? Then add issue id in the json that generated by rush, which shows on changelog.md eventually? @octogonz

{
  "changes": [
    {
      "packageName": "foo",
      "comment": "some comment",
      "type": "patch"
      "issue": 56 // issue id
    }
  ],
  "packageName": "foo"
}

I'm not sure Git commits are the best way to author a changelog for a monorepo with lots of projects and teams.

Git commits document steps of work. For example, when I create a PR, I might break it into 5 separate commits that are easier to review one by one, rather than reading the entire PR diff. And then during the code review, people may suggest various improvements, which may lead to 10 more commits before I finally merge my PR. Some of these commits will be pure bookkeeping (ran "rush update", merged from master, etc). Git commits are written for the audience of people who work on the code. Whereas...

Change logs inform consumers what's new. Consumers need to know which bugs got fixed, which new features were added, or alert consumers about possible breaking changes. This audience often doesn't know anything about the underlying implementation, so a different style of writing is needed. In a monorepo, one Git commit might impact many different projects, and perhaps in a way that needs to be explained differently for each project. For certain important projects, the change log may serve as a public announcement to customers. The release team may have a step where they manually revise the changelog before publishing a release.

I see "semantic release" used mainly in smaller repos where this distinction between commits vs changelogs isn't too important. But it might not work so well as you scale up with multiple teams and projects coexisting.

If someone is willing to propose a design and help implement this for Rush, we would support you. But given Rush's goal of enabling solutions that can scale up, it doesn't seem like this would make sense as a default model that replaces rush change. And I'm not sure that it would be the right fit for the Rush Stack repo. (?)

octogonz commented 2 years ago

For change log, is it possible to add another prompt message? like Does this change affect any open issues? Then add issue id in the json that generated by rush, which shows on changelog.md eventually? @octogonz

@icy0307 This is a good idea. Let's open a separate GitHub issue to discuss the design. It is somewhat unrelated to "conventional commits" syntax.

octogonz commented 2 years ago

In case somebody is still interested, I wrote a script creating change files based on commits, respecting conventional commits. It's described here + here. The code is on GitHub

I hope it will fit into the process described by @octogonz because I only generate change files for fix/feat/breaking changes. I would assume that developers may make more user-friendly descriptions for these cases. And there's still a possibility of either editing the change files/change log afterwards.

@kkazala Interesting! How do you handle this type of scenario:

  1. I make a PR whose branch has 20 different commits. These consist of initial work, followed by incremental fixes based on feedback from coworkers during the code review discussions.
  2. The individual commits are meaningful to GitHub (or whatever system we use for reviewing code), so I don't want to overwrite them by force-pushing the branch. (However, I'm fine with the commits getting squashed when my PR is finally merged.)
  3. This PR makes changes to 5 different Rush projects. These projects have different change logs. For example, my change log for example-app may say Added ability to search by title, whereas my change log for example-lib may say Fixed bug with searchInsensitive() API.
  4. The changes in step 3 are introduced by a single git commit -- it does not makes sense to split the example-app and example-lib fixes into two commits, because if we separate them, the branch doesn't compile.
  5. After my PR is merged, the owners of the example-lib project need to revise the change log prior to release, because their library is an SDK for customers. For example, a later PR renamed the API to searchCaseInsensitive() and so they want to rename the change log to be consistent. (The owners of example-app project don't care about this sort of cleanups, because their change log is for an internal audience only.)

The big challenge for "conventional commits" is: How to handle these sorts of requirements using git commit strings? All these problems seem to require a JSON file.

kkazala commented 2 years ago

@octogonz Thank you for taking time considering this idea.

I totally see the difference between commits and change files, your comment very clearly explains the characteristics of each of them. And I admit that my "workaround" is just that- a workaround. The generated change log has to be updated and yes, it would very quickly become a mess.

On the other hand, I very often find myself scratching my head, when it comes to generating change files. I think it would be useful to know which commits triggered the requirement for a change file. I imagine I'm not alone when I say- work can get crazy sometimes. It may be difficult and time consuming to recall the commits and to decide what should be included in the change file. And obviously I can check my commits history but… from which point of time? And as you say- what if one commit impacts multiple projects? All this takes valuable time.

And of top of that, if I'm using conventional commits, the information on change type is already "there". So a suggestion, based on the commits, would go a long way.

What do you think about the following approach

This would be a massive help, and I think wouldn't impact the flow currently defined by rush. What's your opinion?

octogonz commented 2 years ago

This is the best idea I've heard yet for adapting the spirit of conventional commits to the rush change workflow. 👌 Could you give a little more detail about the design? Like examples of the console outputs/prompts and how the parsing might work? It does not sound like a lot of work to implement.

kkazala commented 2 years ago

@octogonz I was thinking about sth like that

We add two parameters: --show-commits and --recommend-changetype

In _askQuestions we follow the usual sequence until the user confirms they wish to create a change file. image

In such case we call _parseCommits method

_parseCommits()
      if (showCommits) {
        this._git.getShortLog(mergeCommitHash, projectInfo.projectRelativeFolder);
      }
      if (recommendChangeType) {
        const ccHelper: ConventionalCommits = new ConventionalCommits(this.rushConfiguration);
        const changeType: string = ccHelper.getRecommendedChangeType(
          mergeCommitHash,
          projectInfo.projectRelativeFolder
        );
        console.log(
          `Based on conventional commits convention, we recommend the following change type: ` +
            colors.green(changeType)
        );

If --show-commits, we display commits history, I'm currently using git shortlog but if there are many commits, this will have to be approached differently. It's not use-friendly to display it in the console. So I was thinking.... separate file, that gets deleted after change file is created? image

If --recommend-changetype, we filter commits and suggest the change type image

To check if there are any commits requiring major/minor/patch, I'm calling git rev-list --extended-regexp --grep

kkazala commented 2 years ago

@octogonz Did you have a chance to consider my proposal? In the meantime, I had an idea that maybe this new capabilities could be more tightly connected to the rush change and rush change -v. It would basically display the same info, along what rush change / rush change -v already do.

Also.... I looked into the ChangeAction._verifyAsync() and from what I understand, if I:

Is that correct? Maybe it would be helpful to detect if there are any new commits after the newest change file has been created?

octogonz commented 2 years ago

If --show-commits, we display commits history, I'm currently using git shortlog but if there are many commits, this will have to be approached differently. It's not use-friendly to display it in the console. So I was thinking.... separate file, that gets deleted after change file is created?

Maybe this is not necessary. If there are too many commits, we could simply say so, and the person can just as easily use git log to inspect them.

octogonz commented 2 years ago

Maybe it would be helpful to detect if there are any new commits after the newest change file has been created?

Our typical workflow goes like this:

  1. You make 10 commits to implement a new feature
  2. You create a PR
  3. The PR build failed because you didn't run rush change. Go write change logs for your new feature, now the build succeeds. 👍
  4. Other people review your PR. This produces another 10 commits to address all their feedback.
  5. Now we're ready to merge. A few tests are failing, we need to merge master a couple times to fix merge conflicts.
  6. Finally it's green and gets merged. 🎉

In my experience additional rush change prompting/breaks would be a big nuisance during steps 4-6 (unless it's about a new project that I didn't already write a change log for).

kkazala commented 2 years ago

@octogonz

What I had in mind by "more tightly connected to the rush change" is that this new logic would not be executed by default, but instead:

"if there are too many commits, we could simply say so," The big question when running the git log is - what is the mergebase? It is not difficult to find it but it takes time, and also some understanding of what rush is actually doing. When asking user to run use git log I would at least display the command to invoke. Alternatively, the --show-commits could accept format: --show-commits shortlog --show-commits full. Something like this

kkazala commented 2 years ago

@octogonz

I made a small improvement in the meantime, to retrieve the creation date&time of the newest change file, and only parse/return commits after this date.

So for example, after running rush change --recommend-changetype --show-commits long: image If the change file will be generated/changes appended to the existing one, I'm checking for any new commits AFTER the creation date/time of the newest change file. If there we re no commits, appropriate information is displayed.

On the other hand, if commits are found, they are either displayed in the terminal (--show-commits short) or saved to a file (--show-commits long). The change type recommendation is displayed, and also, if user choses to describe the changes, the recommended change type is preselected in the "select the type of change" options: image

The gitlog folder is then deleted, along with all its contents

I would be happy to contribute a PR, but at the same time I don't want to force it on the rush team. Could you have a look at the logic and the code and let me know if it makes sense? I imagine I should also write tests, but I don't want to start if the idea dies ;)