Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support monorepos without synchronized versions #45

Closed
Gudahtt opened this issue Apr 26, 2022 · 4 comments · Fixed by #51
Closed

Support monorepos without synchronized versions #45

Gudahtt opened this issue Apr 26, 2022 · 4 comments · Fixed by #51
Assignees

Comments

@Gudahtt
Copy link
Member

Gudahtt commented Apr 26, 2022

Currently this action only supports monorepos with synchronized versions. We will soon be using monorepos that don't use synchronized versions, so this will need to be updated to support that.

@Gudahtt Gudahtt assigned rickycodes and unassigned mcmire Jun 21, 2022
@mcmire
Copy link
Contributor

mcmire commented Jun 30, 2022

Here are my thoughts on what sort of changes we could make to this action in order to achieve this goal.

Disclaimer

It's important to know up front that right now this action reads the version we want to release (the "release version") from the branch being merged. This is being changed in #46 to read from the version in package.json, so we will assume that.

Current flow

Once we know what the release version is, we follow one of two workflows:

Polyrepo

  • We parse CHANGELOG.md and extract the section of the changelog that matches the release version.
  • We then use the gh command-line utility to create a new GitHub release which is titled the same as the release version and has the content of the section of the changelog as obtained in the previous step.
  • We then create a Git tag which is named v${releaseVersion} (e.g. if the release version is 1.2.3, the tag will be called v1.2.3).

Monorepo

  • Instead of reading CHANGELOG.md in the root, we go through all of the packages that the monorepo holds (as specified via the root package.json's workspaces field), and for each package, we extract the section of its CHANGELOG.md that matches the release version. We stitch these sections into one big changelog, where each section is headered by the package that it belongs to.
  • We then use the gh command-line utility to create a new GitHub release, using the release version for the title and the big changelog as obtained in the previous step as the release notes. This will end up also creating a Git tag which is named v${releaseVersion} (e.g. if the release version is 1.2.3, the tag will be called v1.2.3).

New flow

For polyrepos, everything should work how it works now.

But for monorepos, there's a problem with the existing flow: it assumes that when a release is created, all packages will be bumped to the same version. This may continue to be true for snaps-skunkworks and eslint-config, but will not be true for controllers, because we will be following an independent versioning strategy, where 1) every package can have a different version and 2) not every package may be bumped when a new release is issued.

Therefore, the changes we need to make are as follows:

  • We will want to have the action take a second input, which is the version synchronization strategy. By default, to avoid breaking changes for snaps-skunkworks or eslint-config, we can default this strategy to "fixed", but allow it to be set to "independent".
  • For the "fixed" versioning strategy, we want to continue to follow the same flow as provided above.
  • But for the "independent" strategy, we want to follow this flow:
    • We may want to change the representation of the release version. Again, this is the same as version listed in the root package's package.json. The root package is private, so as it stands, assigning a version like <major>.<minor>.<patch> to this package doesn't make sense. It may make more sense to assign a date, such as <year>.<month>.<day>. To account for the case in which we want to create more than one release in a day, we may want to add a fourth part, so in order to stay SemVer-compatible, the format could be <year>.<month>.<day>-<release number>. (The semver library should be able to handle this, but we can check.) The "release number" here would be a number that would be incremented for each new release. We would probably want to ensure that this number is valid by pulling the latest of the set of Git tags that matches this format, and (assuming that such a tag exists) confirm that the new version increases the number at the end by 1.
    • In the existing workflow, we iterate through all of the workspace packages in order to extract sections of changelogs from each package, but now we only want to iterate through the packages for which we want to release new versions. The easiest way to find this, I think, is to go through each package in the monorepo and compare the version of that package as set in its package.json to its currently published version on NPM. Any packages where these two versions differ we can assume require new releases.
    • Once we have a list of packages to release, we can go through each package and extract a section of its CHANGELOG.md — only instead of using the release version to find the appropriate section, we use the version in package.json for that package. As before, though, we then stitch the sections of the changelogs from each package into one big changelog, where each section is headered by the package that it belongs to.
    • We then use the gh command-line utility to create a new GitHub release, using the big changelog from the previous step as the release notes. For the title, however, we can parse the date from the release version, so for example, 2022.6.30-1234 might turn into "June 30, 2022 (release 1234)". We can also instruct the gh command to create a Git tag named after the release version — although we can drop the v, since it's not a real version.
    • Finally, we will want to create Git tags for each package that we are releasing (so we will have a tag per root release, and a tag per package release). We already have the list of packages from a previous step, so we can simply iterate through all of them and call git tag <new version>, then call git push --tags at the end. (Note that in order to do this, we may want to move the entire of contents of scripts/create-github-release.sh into the TypeScript script. That may make things easier to test.)
    • Of course, we want to make sure this logic is well tested.

Decisions to make

In summary, here are the things we need to decide, in the case of a monorepo with an independent versioning strategy:

  • What should the release version be called?
  • How should we title each GitHub release?
  • Should the content of scripts/create-github-release.sh be folded into the TypeScript code?

Prior art

For inspiration, take a look at Vercel, which more or less follows the same process that we want to follow: https://github.com/vercel/vercel

@mcmire
Copy link
Contributor

mcmire commented Jul 18, 2022

Just an update on this: Instead of having this action take a second input, we should read the value of versionSynchronizationStrategy from some sort of configuration object that is kept in the repo as described here: https://github.com/MetaMask/create-release-branch/blob/88ec7e222c8c8e3fa88534c0ebda331a117911db/docs/setup.md. @rickycodes and I are discussing in Slack whether this configuration object lives in package.json or in a separate file entirely, so until that's resolved we can work around it for now by continuing to have a second action input, and then tweak it in a later PR.

@mcmire
Copy link
Contributor

mcmire commented Jul 21, 2022

Another update: instead of using a version format of <year>.<month>.<day>-<release number> for the root package, we should use <yyyy><mm><dd>.<release number>.0, so that we don't create a prerelease version.

@mcmire
Copy link
Contributor

mcmire commented Jul 21, 2022

Here's the relevant part of the Notion doc which describes how this action fits into the larger workflow. This might be helpful to gain more context: https://www.notion.so/Core-Monorepo-Release-Automation-a65b28ab89a14c9d82dcf9fabc3eb1e1#aa00c0fc1e404448884f41c4998602e6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants