Describe the user story
Yarn has the awesome deferred version strategy built-in into version plugin, but currently, it doesn't support changelogs. I want to understand what changes were introduced in specific version of package.
Describe the solution you'd like
It could be part of version plugin or separate plugin too. I expect to work it in a similar way as changesets. So a user will add changelog entry when bumping version. And later, when we apply versions, we should generate a markdown file with these entries.
Describe the drawbacks of your solution
If it will be part of the version plugin, we need some options to enable/disable changelogs because not everyone needs it. Is it doable at all without breaking change?
Describe alternatives you've considered
Btw there is the issue about yarn integration with changesets. Maybe we can enhance changesets a bit so it will work like standalone cli.
Additional context
Maybe there is some other tools (like lerna)?
@arcanis maybe we should add case study label to research problems with current usage of changesets?
Changelog would be awesome - even for this very repository we would love this feature! So far however time has been short to implement it, so if someone could help us on that, it would be amazing ๐
The way I see it, we cannot resort on conventional commits. They are fine when managing a single project, but they don't compose very well with the model used by version check - we'd need to find out the original commit that led to a particular release file, and that can be tricky and error-prone.
Instead, I'd like to add an input box (nothing fancy, just a single line, maybe?) that would be stored within the release file along with the rest of the data. Then, when applying the versions, the stored changelog lines would be each applied to all related workspaces and aggregated into a markdown output (which would be obtained with yarn changeset changelog?).
Note that we would treat direct releases pretty much the same way as transitive releases for the purpose of the changelog generation. So for example, if we make a change into plugin-git that require to re-release the CLI as well, here's what could be generated:
yarnpkg/cli
- Add support for foo
By usernameyarnpkg/plugin-git
- Add support for foo
By username
So this is how I imagined this working:
version commandWe add a --changelog flag.
When you call the command with that flag, you are prompted to enter a short description of the bump. That description is then be added to changelogs of all the workspaces where the version has been bumped.
version check commandWe add a --changelog flag.
When you call the non-interactive command with that flag, it not only checks that versions were bumped, but it also checks that all workspaces that were bumped contain a short description of the bump.
When you call the interactive command with that flag, you are not only be prompted to bump versions, but there is also a text input present, where you enter a short description.
The text input is only be present for direct releases, the workspaces that depend on the direct releases just copy the descriptions of the corresponding direct releases. How @arcanis described it above.
The descriptions are then added to the release files.
version apply commandThe command works the same as before, except now, it also appends the short descriptions to the corresponding changelogs.
There is a changelogs field added, that contains the short descriptions for all bumped workspaces.
So for example, if you change something in the yarnpkg-libui, bump its version, add a short description, and then also bump the versions of plugin-version and plugin-interactive-tools, since they depend on yarnpkg-libui, the release file would look something like this.
releases:
"@yarnpkg/libui": prerelease
"@yarnpkg/plugin-interactive-tools": prerelease
"@yarnpkg/plugin-version": prerelease
changelogs:
"@yarnpkg/libui": "Increased spacing in the item's component."
"@yarnpkg/plugin-interactive-tools": "Increased spacing in the item's component."
"@yarnpkg/plugin-version": "Increased spacing in the item's component."
This then results in all of the three packages getting the description added to their changelogs.
An example of how an entry into the changelog would look like, very simple for now:
Do we also want to keep a root changelog, that would keep track of all of the version bumps in all of the workspaces? I'm not sure about this one, maybe it can wait until the next iteration of this feature.
What do you guys think?
Let's take a look at changesets.
One of the main ideas that you can read changelog entries easily and edit it later. So I believe that markdown is better than YAML it this case. Also, changelog entry can contain many text and code blocks for example.
Note that changelog entries have some human-readable names like rich-melons-press.md so it's easier to navigate between them and review changes or edit it.
As input, I would expect that command will open my preferable editor/IDE via $EDITOR variable because maybe I would write several paragraphs of text and also I want to see a preview for written markdown. Maybe it could be toggle via option?
Also it will be great (and important?) to not break backward compatibility. Can we support both markdown and yaml formats? Or maybe as workaround we can link markdown files in yaml? Something like that (but I don't really like it):
releases:
"@yarnpkg/libui": prerelease
"@yarnpkg/plugin-interactive-tools": prerelease
"@yarnpkg/plugin-version": prerelease
changelogs:
"@yarnpkg/libui": "./some-file.md"
"@yarnpkg/plugin-interactive-tools": "./some-file.md"
"@yarnpkg/plugin-version": "./some-file.md"
Also there are could be more that one changelog entries for one PR.
More details here: https://github.com/atlassian/changesets/blob/master/docs/detailed-explanation.md
I think we should have different changelog drivers: we have github, bitbucket, gitlab at least.
To be honest I feel weird that we are discussing features that already implemented in changesets so maybe better to find a way how we can integrate it?
versioncommand
The --changelog option would only be applied when using --deferred, right? Otherwise where would we keep it, since there would be no YAML file?
version applycommand
I think it might be interesting to ignore version apply for this iteration. Instead, I'd like to introduce a new command, yarn changeset changelog, that would generate a Markdown output based on the content (but without changing anything to the repo - it would be a side-effect-free command. So for example, the typical release workflow would do this:
yarn changeset changelog >> CHANGELOG.md
yarn changeset apply
Doing this would be quite handy, because it would become possible to generate the changelog at any given point without mutating the repository. For example, let's say I want to quickly look at what's going to be released, I can just run yarn changeset changlog and everything is here.
Do we also want to keep a root changelog, that would keep track of all of the version bumps in all of the workspaces? I'm not sure about this one, maybe it can wait until the next iteration of this feature.
With the yarn changeset changelog, the responsibility of actually generating the changelog would fall to the user, so this problem wouldn't be there.
Example changelog
I suggest to also find the merge commit that added version files, and to link to it (we can grep the trailing (#XXX) from the merge commit message to derive the PR number) + their authors. For example, an entry could be:
@yarnpkg/monorepo
One of the main ideas that you can read changelog entries easily and edit it later. So I believe that markdown is better than YAML it this case. Also, changelog entry can contain many text and code blocks for example.
There's no reason why Markdown cannot be stored within a YAML file:
changelog: |
Fixes our repository constraints *(warning: experimental)*
As input, I would expect that command will open my preferable editor/IDE via $EDITOR variable because maybe I would write several paragraphs of text and also I want to see a preview for written markdown. Maybe it could be toggle via option?
That's a good point - perhaps we could follow the Git model and make yarn version --deferred open the EDITOR, and yarn version --deferred -m "Foobar" add the changelog entry from the command line without opening the editor?
Also there are could be more that one changelog entries for one PR.
Perhaps in a followup, but it may make the UI confusing. I prefer the initial version to simply cover all the workspaces, and we can go from here to figure out whether this model should be refined.
I think we should have different changelog drivers: we have github, bitbucket, gitlab at least.
Too complex for the first iteration. We don't need driver for now, at best we only need to find the PR number and generate a hashlink from it (all providers are assumed to follow this standard), with perhaps a fallback to instead print the short commit id when there's no PR number to be found in the merge message.
To be honest I feel weird that we are discussing features that already implemented in changesets
The version workflow was designed without being aware of the Changeset project. While there's certainly value in taking a look at what exists elsewhere, I think ultimately we're in a unique position of implementing a workflow that's integrated deeper than what third-party projects could do. At the very least, it's worth considering alternatives ๐
Another way to do this would be to export proper hooks from the version plugin so that someone else can write the plugin that handles change logs properly.
Please also see the issue logged for changesets to properly work with yarn v2 at: https://github.com/atlassian/changesets/issues/432 for reference
To be honest I feel weird that we are discussing features that already implemented in changesets
The version workflow was designed without being aware of the Changeset project. While there's certainly value in taking a look at what exists elsewhere, I think ultimately we're in a unique position of implementing a workflow that's integrated deeper than what third-party projects could do. At the very least, it's worth considering alternatives ๐
I think that the statement that 'integrated deeper' means better than third-party is a bit extreme and dangerous. One of the best features of berry is the introduction of plugins and hooks so that integration with yarn does not mean a new release of yarn. It's actually pretty desirable that an endorsed plugin by yarn (i.e. version) also follows that direction and exports the proper hooks for a third-party project to integrate deeper with yarn. If that is deemed too much, then would you please consider enhancing the workflow advocated by version to also include pre-release like changesets, generating CHANGELOG.md like changesets or better, etc...?
Hi there ๐ I'm one of the maintainers of Changesets, so I thought I would pitch in here as @abdes has pointed me to this thread.
Let's start with a few comments.
The text input is only be present for direct releases, the workspaces that depend on the direct releases just copy the descriptions of the corresponding direct releases. How @arcanis described it above.
This IMHO is not enough. Changelogs are supposed to be consumed primarily by humans - they are informative. Even in simple setups, this could easily create confusing entries. There are two scenarios to consider here:
node_modules when upgrading your dependencies in a consuming project.Release Files format
&
There's no reason why Markdown cannot be stored within a YAML file
Yes, technically you could store Markdown in YAML but I would consider this to be less user-friendly overall. You won't get the same support from editors in editing this. If you keep everything in a single YAML then it would also probably be more prone to git conflicts.
As @7rulnik has mentioned, this is vastly important for Changesets:
One of the main ideas that you can read changelog entries easily and edit it later. So I believe that markdown is better than YAML it this case. Also, changelog entry can contain many text and code blocks for example.
And I believe is one of the reasons behind Changesets getting traction and love from their users.
Do we also want to keep a root changelog, that would keep track of all of the version bumps in all of the workspaces? I'm not sure about this one, maybe it can wait until the next iteration of this feature.
This has been requested at Changesets, but so far we haven't implemented support for this. There are many workflows that people are using right now and it's hard to satisfy them all, we also try to not overcomplicate stuff in the long run, so additional features like this are considered carefully. We don't want to rush into implementing them right way.
Also there are could be more that one changelog entries for one PR.
This is also an important "feature" of Changesets. Support for this enabled user-friendly changelogs from PRs that touch multiple packages - which are not rare in monorepos.
Perhaps in a followup, but it may make the UI confusing. I prefer the initial version to simply cover all the workspaces, and we can go from here to figure out whether this model should be refined.
@arcanis has commented this about the former thing - multiple changelog entries for a single PR. I'm not sure exactly how do you envision this to work in Yarn - but in Changesets this works already and I haven't heard any DX complaints about it. We have an interactive CLI command, with autocomplete and all that jazz that guides users through the process.
Doing this would be quite handy, because it would become possible to generate the changelog at any given point without mutating the repository. For example, let's say I want to quickly look at what's going to be released, I can just run yarn changeset changlog and everything is here.
This I don't quite understand. Could you sum up the complete workflow that has been discussed so far? How could you not mutate the repository and implement deferred publishes at the same time? ๐ค
The version workflow was designed without being aware of the Changeset project. While there's certainly value in taking a look at what exists elsewhere, I think ultimately we're in a unique position of implementing a workflow that's integrated deeper than what third-party projects could do. At the very least, it's worth considering alternatives ๐
You are, of course, allowed to implementing your own workflow - but as people have already said: the overlap between this and Changesets is just huge. As @abdes said, given your plugins architecture, it really sounds like you should offload this to 3rd party tooling. Maybe provide some dedicated wrappers for them in here. Giving away some of the maintenance to others wouldn't also hurt Yarn - it already has a huge and important responsibility, I don't particularly think that packing even more into Berry would be that beneficial to you. Yes - you would gain control, so maybe that's important enough for you to do the hard work on your own. We could cooperate more closely to work out a shared solution though, setting up integration tests and all.
Changesets - while working and serving its purpose - still have some minor gaps, there are hard answers with no ideal answers. We have already figured out a lot though and it would be a shame to reinvent this workflow again.
Hey @Andarist! Thanks for shimming here with such a detailed comment! One thing that's important enough to be answered first:
You are, of course, allowed to implementing your own workflow - but as people have already said: the overlap between this and Changesets is just huge. As @abdes said, given your plugins architecture, it really sounds like you should offload this to 3rd party tooling.
I actually really agree - when I started working on the changeset feature I didn't look enough at existing solutions, and missed your project until @zkochan pointed it to me ๐ Had I noticed it, there's a good chance I'd have at least tried to integrate both tools. If you're open to start a discussion to discuss what that would look like, I'd be very interested!
Could you sum up the complete workflow that has been discussed so far? How could you not mutate the repository and implement deferred publishes at the same time?
Updates can be applied "in memory". For example, our current plugin mutates all the workspace instance in memory, and only during the following install are they persisted on the disk. It would be easy to completely skip the install, and instead print a summary of the changes that would have been applied.
Yes, technically you could store Markdown in YAML but I would consider this to be less user-friendly overall. You won't get the same support from editors in editing this. If you keep everything in a single YAML then it would also probably be more prone to git conflicts.
I see you're using Frontmatter - that's a nice solution indeed ๐ How does that work however when you wish to provide upgrade information on multiple packages, like you mentioned before? Do you detect which workspace a particular paragraph applies to per the section title and aggregate them all?
If you wish, perhaps we can make a "meeting" on Discord this week to discuss this in a more interactive way?
I love OpenSource :-), Thanks @arcanis and @Andarist ๐ .
Please include me in your future discussions as well. We use changesets+pnpm in my company of 200+ devs. Also, I recommend everyone who uses pnpm to use changesets for publishing. So I'd like changesets to be the de facto standard. The only issue with it is the crazy lack of documentation.
If you're open to start a discussion to discuss what that would look like, I'd be very interested!
I would be interested in that ๐ Feel free to reach out to me any time, I'm not sure if you have time to work on this right now. I might also not give this 100% of my attention this week - but I will do my best to answer any potential questions and brainstorm a little bit in the asynchronous fashion.
If you wish, perhaps we can make a "meeting" on Discord this week to discuss this in a more interactive way?
I possibly could do this next week or later.
I see you're using Frontmatter - that's a nice solution indeed ๐ How does that work however when you wish to provide upgrade information on multiple packages, like you mentioned before? Do you detect which workspace a particular paragraph applies to per the section title and aggregate them all?
When running a CLI command we list all "changed" packages at the top and the rest below them, one can select packages for which they'd like to create a changeset file (that will become a changelog entry later), after that, we ask for bump types for each package (or rather - we ask which should be major bumped, which minor bumped and leftovers are considered as patch, so u get at most 2 questions at this step of the flow, from what I recall). And as a final step, we ask for the actual message describing the change.
So such a single yarn changeset run results in a single changeset file containing release intents for N packages (they can have different bump types as described above) but with a single message. If you want to create different messages you just have to run this multiple times. CLI is nicely guiding a user through the process, but changeset files can be created manually when one gets accustomed to the flow and would like to speed things up for themselves - they are just simple markdown files with a frontmatter after all.
I love OpenSource :-), Thanks @arcanis and @Andarist ๐ .
Me too! โค๏ธ
So I'd like changesets to be the de facto standard. The only issue with it is the crazy lack of documentation.
We could definitely try to improve this. If you have any particular things that you feel are especially poorly documented - please open issues about them and we'll try to provide docs covering those topics.
So such a single
yarn changesetrun results in a single changeset file containing release intents for N packages (they can have different bump types as described above) but with a single message. If you want to create different messages you just have to run this multiple times.
I see - I think those are the differences with our current workflow:
Calling the command repeatedly will always use the changeset file that's already in the current branch. I find that handy, because you sometimes want to amend the changes you've made.
We only print the dependent packages from those who will get released, rather than all of them (we use Ink to update the display depending on the previously selected options).
We show a tabular interface asking to select a type of release for each row. This way there are more choices (we also handle prereleases, for example).
In particular, at the moment, declining to bump a package is possible (for example if you only changed the README), but it's an explicit choice (like minor, major, etc). It's a bit annoying at the moment, we want to simplify that.
I possibly could do this next week or later.
Great, I'll setup something ๐
Oh and, one problem that we currently have, it's sometimes a bit difficult for external contributors to know what to bump (for example that modifying the plugins require to mark the CLI package for release). I'd like to eventually fix that - perhaps with "presets" in the UI, or with a GH action that would allow us to set those fields from the PR interface.
Oh and, one problem that we currently have, it's sometimes a bit difficult for external contributors to know what to bump (for example that modifying the plugins require to mark the CLI package for release). I'd like to eventually fix that - perhaps with "presets" in the UI, or with a GH action that would allow us to set those fields from the PR interface.
@arcanis, that actually may be more general than just during the version bump. Today yarn does a good job in identifying inter-workspace dependencies, so we can definitely implement a command in the plugins to for example identify all affected packages by a change. This is similar to what Nx does with nx affected command or to what rush does with --from or --to options to select a package and its dependents or its dependencies. Nx solves the implicit or manual dependencies through the workspaces config. You can specify that a certain workspace depends on another although that dependency is not detected by yarn. If you do so, then the affected algorithm will take it into account.
Actually such feature is very useful to for example:
run yarn npm publish on a workspace and its dependents instead of today run on all workspaces and silently fail on the non-bumped ones,
run tests on affected workspaces,
set an implicit dependency on tsconfig.base.json and if that file changes all TS workspaces get rebuilt,
...
Calling the command repeatedly will always use the changeset file that's already in the current branch. I find that handy, because you sometimes want to amend the changes you've made.
You can amend changes just fine using our workflow - changeset files are physically written to disk so it's super easy to add more, remove some or edit some. I might still fundamentally misunderstand how your workflow looks like though and maybe that's why there is a small misunderstanding in this area between us.
Using full Changesets workflow you create changesets at any time (even after your PR get gets merged into the base branch). When changesets land on a base branch our github action (that consumers should have configured for their repo) creates a versioning PR like this: https://github.com/emotion-js/emotion/pull/1963 . And only when this gets merged to the base branch actual releasing happens - so releases are not 100% automated, but it's specifically designed for people to have control over the releasing. It's mostly automated in this regard. So to rephrase this a little bit - changeset files sit in the repo, written to disk, waiting for the release to happen.
Could you give a brief overview of how this works right now in your case? Or point me to some docs?
We only print the dependent packages from those who will get released, rather than all of them (we use Ink to update the display depending on the previously selected options).
Hm, this doesn't sound much different from us. Maybe just in some details - but the basic idea sounds the same, show people what we think should be shown to them to minimize the cognitive load and speed up things for them.
We show a tabular interface asking to select a type of release for each row. This way there are more choices (we also handle prereleases, for example).
Would have to take a look at this, but the tabular interface sounds like a cosmetic difference. It should be possible to build any interactive CLI one could imagine for this - given building blocks we provide (or which we could provide, not sure if everything is exposed right now for public usage).
As to prereleases - we handle this as well, but probably in a different way than you do. Prereleases are a complex topic of its own so we can postpone discussing this until later.
In particular, at the moment, declining to bump a package is possible (for example if you only changed the README), but it's an explicit choice (like minor, major, etc). It's a bit annoying at the moment, we want to simplify that.
We also support "none" bump type that can be used for this. I don't think though that there is any way to enforce changesets for all affected packages right now - one would have to build this as a custom GitHub action (and I think people have already done that because I recall reading about such workflows in the issues).
Oh and, one problem that we currently have, it's sometimes a bit difficult for external contributors to know what to bump (for example that modifying the plugins require to mark the CLI package for release). I'd like to eventually fix that - perhaps with "presets" in the UI, or with a GH action that would allow us to set those fields from the PR interface.
In changesets if CLI depends on plugins and you add a changeset for the plugins package then CLI will be bumped at least with a patch bump and the updated dependencies will be listed in its changelog. There is no way to enforce (right now) that one has to write a changelog entry for CLI though.
We also have a "linked" packages concept - in this case, the CLI would be bumped to the same version as plugins package. This is similar - but not the same (!) - to Lerna's fixed versioning. The difference is that if you have 2 linked packages that do not depend on each other (let's say [email protected] and [email protected]) and you minor version B then you will end up with [email protected] and [email protected], but if you now patch version A then you will end up with [email protected] and [email protected] - whereas with fixed versioning you would get 1.1.0 for both the first time and 1.1.1 for both the second time.
As to the PR interface - we provide a bot which makes it easier for maintainers to add changesets directly from GitHub (assuming PR author has allowed maintainers to commit to their fork). It is done by preparing a URL such as this:
https://github.com/hudecsamuel/xstate/new/state-value-type?filename=.changeset/smooth-feet-learn.md&value=---%0A%22%40xstate%2Ffsm%22%3A%20patch%0A---%0A%0Aupdated%20State%20interface%20value%20type%0A
Not to be that person, but any updates on this? Lerna doesn't seem like it's actively maintained anymore, so I'd love to remove the dependency and just rely on yarn for publishing ๐
We discussed with @Andarist and I think the takeaway was that we would want to uniformize the syntax used by Yarn and Changesets so that we'd still be able to keep the UI interface we currently have (in particular where multiple workspaces can be affected to different release strategies, or none at all), but would also be able to leverage the Changesets tools.
At the moment however it hasn't yet been acted upon, so the best approach would be to use the regular release workflow, although it's not exactly a 1:1 mapping with Lerna. For what it's worth, Babel has removed Lerna at the same time they migrated to Yarn 2, in part by implementing a plugin to customize the behavior to exactly what they were after - perhaps that would be an option?
Thanks for the update @arcanis! Writing a custom plugin sounds a bit much for evening hacking, but I'll take a look. Maybe @nicolo-ribaudo wants to share his thoughts in this issue as well? ๐
Most helpful comment
Please include me in your future discussions as well. We use changesets+pnpm in my company of 200+ devs. Also, I recommend everyone who uses pnpm to use changesets for publishing. So I'd like changesets to be the de facto standard. The only issue with it is the crazy lack of documentation.