Monerpo Workflow Foundation changesets open and advanced (Speeches)

background

Changesets is an atlas product of jira company, which has been transferred to the new organization of changesets for special maintenance.

Who's using it?

Presupposition theory

Talk about workflow

workflow consistency problem

How to reach an agreed workflow?

  • Within the company: pull through alignment to form a consistent resultant force
  • Open source: github bot + github actions

Workflow solution of open source project

Officially recommended automated solution: Automating Changesets

github bot
  1. Standardize developer behavior

  2. Automatically generate the release changelog report and control the unified release behavior (example: changesets pull) #718 )

github actions

Therefore, the solution process of Auto workflow of open source project is:

  1. Development stage: the developer develops the code, carries out PR, and the github bot specification ensures the submission of the change set. Here is attached:

    a. changelog of single change
    b. Degree of impact on version

  2. Collection stage: the project owner collects the PR required for approve. At this time, the github bot will accumulate all changed release PR in the form of one pr. It contains:

    a. Project release changelog
    b. version change of each sub package
    c. changelog for each sub package

  3. Release phase: after a period of time and collecting enough pr (change set), the project owner will merge the release PR proposed by github bot, and the release will be automatically released by github actions. Here:

    a. Automatically send version to npm
    b. Each sub packet receives changelog attachment and version change

Practical empowerment

Install changesets

  # Install changesets
  pnpm add -W -D @changesets/cli

  # Initialize changesets folder
  npx changeset init

Configure changestes

to configure. changeset/config.json :

{
  "$schema": "https://unpkg.com/@changesets/config@1.6.1/schema.json",
  
  // changelog generation method
  "changelog": "@changesets/cli/changelog",
  // Open source projects can use the changelog in github format with a commit link
  // "changelog": ["@changesets/changelog-github", { "repo": "changesets/changesets" }]
  
  // Don't let changeset do git add for us when publish ing
  "commit": false,
  
  // Configure which packages to share versions
  // Reference 1: https://github.com/changesets/changesets/blob/main/docs/config-file-options.md#linked-array-of-arrays-of-package-names
  // Reference 2: https://github.com/changesets/changesets/blob/main/docs/linked-packages.md#using-glob-expressions
  "linked": [],
  
  // Public and private security settings are available. restricted is recommended for intranet, and public is used for open source
  "access": "restricted",
  
  // Project main branch
  "baseBranch": "origin/main",
  
  // Ensure that the package that a package depends on is upgraded, and the unit of measurement (magnitude) of version upgrade should also occur for the package
  // https://github.com/changesets/changesets/blob/main/docs/config-file-options.md#updateinternaldependencies
  "updateInternalDependencies": "patch",
  
  // Packages that do not need to change version
  "ignore": [],
  
  // Every time the version changes, there must be no reason for patch to raise the versions of those packages that depend on him, so as to prevent major priority from not updating
  "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
    // https://github.com/changesets/changesets/blob/c68536edf4c04e7fdf5594ec9c69471cd86fd0ce/packages/assemble-release-plan/src/determine-dependents.ts#L88
    "updateInternalDependents": "always"
  }
}

For the introduction of various options, please directly refer to the official document description. Here are two recommended solutions for different scenarios:

Business project

{
  "$schema": "https://unpkg.com/@changesets/config@1.6.1/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "linked": [],
  "access": "restricted",
  "baseBranch": "origin/main",
  "updateInternalDependencies": "patch",
  "ignore": [],
  "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
    "updateInternalDependents": "always"
  }
}

Open source project

{
  "$schema": "https://unpkg.com/@changesets/config@1.6.1/schema.json",
  // ⬇️  This is different from the business configuration~
  "changelog": ["@changesets/changelog-github", { "repo": "owner/repo" }],
  "commit": false,
  "linked": [],
  // ⬇️  This is different from the business configuration~
  "access": "public",
  "baseBranch": "origin/main",
  "updateInternalDependencies": "patch",
  "ignore": [],
  "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": {
    "updateInternalDependents": "always"
  }
}

Modify packages json

Modify the package. In the project root directory json :

// package.json

// newly added
"scripts": {
    // Build the product of the whole project
  	"build": "pnpm -r --filter ./packages run build",
    
    // 1. Start filling in change sets interactively
    "changeset": "changeset",
      
    // 2. Used to uniformly upgrade the version number
    "version-packages": "changeset version",
     
    // 3. Build the post release version of the product
    "release": "pnpm build && pnpm release:only",
    "release:only": "changeset publish --registry=https://registry.npmjs.com/"
}

// newly added
"publishConfig": {
  "access": "public"
}

Here are also two solutions for different scenarios:

Business project

// package.json

"scripts": {
  	"build": "pnpm -r --filter ./packages run build",
  
  	// ⬇️  Due to the need for frequent use, shorter commands are used locally to save costs 🥰
    "change": "changeset",
  
    // ⬇️  Since there is no github bot inside, the cost can be saved locally with shorter commands 🥰
    "vp": "pnpm version-packages",
    "version-packages": "changeset version",
  
    "release": "pnpm build && pnpm release:only",
  
  	// ⬇️  Configure company source
    "release:only": "changeset publish --registry=https://company-registry/"
}

Optional: add npmrc is limited to private sources. If the default configuration is all, this step is unnecessary

# .npmrc
@scope:registry=https://company-registry/

Open source project

// package.json

"scripts": {
  	"build": "pnpm -r --filter ./packages run build",
    "changeset": "changeset",
    "version-packages": "changeset version",
    "release": "pnpm build && pnpm release:only",
    "release:only": "changeset publish --registry=https://registry.npmjs.com/"
}

"publishConfig": {
  "access": "public"
}

Advanced thinking

What is the business project release flow?

  1. Different developers develop first and use pnpm changeset to write a change set when submitting PR
  2. The project owner contracts regularly, uses pnpm version packages to consume all change sets, and changesets automatically promotes the sub package version and generates changelog 😆
  3. Execute pnpm release to build all projects and contract out 🥰

What is the release flow of open source projects?

  1. With the help of github bot, each developer submits a change set before PR
  2. With the help of the github bot, the project owner regularly clicks the release PR proposed by the join bot to join the upgraded version in one click to generate the changelog 😆
  3. With the help of github actions, when the release PR is closed, it will automatically contract to npm 🥰

As you can see, what did the project owner do when publishing? A few mouse clicks 😅 , However, changelog, version upgrade and contract awarding are not few, which is really nice.


How to use changeset publish well?

In fact, changeset publish is just a pure contract issuing command. It will publish all packages once. Therefore, even if you do not upgrade the version through workflow, you can manually upgrade / modify the version and then change set publish.

For example, if you have an urgent test scenario, you can quickly and manually modify it to the version publish test with tag.


How to release with tag (like beta version)?

Method 1: manual debugging method

According to our understanding of changeset publish above, you can manually modify the version number of a package after modifying the code, and then tag and publish it:

// package.json
{
	"name": "@scope/some-package",
    "version": "1.0.1-beta.1"
}
# Be careful not to forget the tag option
pnpm changeset publish --tag beta

Method 2: overall debugging method

Use the official prerelease mode to enter the pre mode first:

# Enter the prerelease mode with beta tag
pnpm changeset pre enter beta

After that, changeset publish in this mode will default to the beta environment. Here is an example:

# 1-1 made some development
# 1-2 submitting change sets
pnpm changeset
# 1-3 upgrade version
pnpm vp # changeset version
# 1-4 contract awarding
pnpm release # pnpm build && pnpm changeset publish --registry=...
# 1-5 to get 1.0.0-beta one

# 2-1 made some development
# 2-2 submitting change sets
pnpm changeset
# 2-3 upgrade version
pnpm vp
# 2-4 contract awarding
pnpm release
# 2-5 to get 1.0.0-beta two

# ......

After complete debugging, exit the prerelease mode:

pnpm changeset pre exit

You can see that this method is more systematic. Of course, in order to facilitate local debugging and pre issuance, you can aggregate commands to run together as much as possible and shorten the command length.

In the business project monorepo, how can the mixed scenario of business applications and basic libraries be opened gracefully?

Problem scenario

Considering a business scenario, we have to put the business application in monorepo and the basic library and Toolkit in monorepo (they may not be a workspace folder, so it won't be very chaotic).
Considering the complexity and agility of the business, the advantage of this is that you can directly use the workspace:version protocol in the warehouse for rapid use without publishing, and there is no need to jump repeatedly between multiple repo s.

Problem disassembly

At this time, we will encounter a problem. Although we specify private: true for the business project, it will not be contracted, because it depends on the tool library in the warehouse, when the tool library is upgraded, the version of the business application will still be upgraded, and a changelog will be generated in the directory of the business project (even if the version field is not filled in), This was unexpected.

How to solve it?

Problem solution

In order to solve this problem, we need to add the name of the business application to the ignore field in the changeset configuration file to represent that no operation should be performed on the project.

But for a monorepo, how to solve the problem when there are more business items? Do you fill in ignore manually every time? Obviously not. We need monkey patch pnpm changeset, such as:

// package.json

"scripts": {
  // This script will help us collect all private packages
  // And add their name s to the ignore list in the changeset configuration file
	"change": "node ./scripts/change.js",
}

In this way, the problem of mixing business projects and tools can be solved automatically.

How to build the optimal pre dependency before each release of a business project?

Consider a common scenario in a business monorepo warehouse:

  1. We have three basic packages @ scope/a, @ scope/b and @ scope/c
  2. We need to build a project @ project/a, which relies on @ scope/a

If it is obviously a waste to build all the basic packages before releasing the project every time, how to solve it?

There are several solutions:

  1. Recursive construction using pnpm's -r native
  2. Use tools such as turborepo to find the best construction path

Let's compare:

Comparison itempnpm -rturborepo
cache😅 None. The secondary build needs to be packaged again🥰 have The local secondary construction can be skipped according to the hash. In cicd, the file cache of the last container can be used to skip the construction
best build path😅 None. All -r base packages are built recursively each time🥰 have turbo will automatically find out which dependencies the project to be built depends on in advance. Only the required ones will be built, and the construction order is the best
flexible exec script🥰 have pnpm exec can flexibly specify the command to be executed each time, and supports attached parameters😅 None. Only the commands contained in each package scripts can be executed

Add another entry-level tutorial on my understanding of turborepo:

Optimal construction of complex topological relationships using turbopo

turborepo is not the only solution. There are also build system organization tools such as nx.

What does the domestic industry do?

Changesets: a popular monorepo scenario contracting tool

What's customized?

  1. Changeset name (default random, non customizable) generation rule
  2. pre release release release command combination

Comparison of similar competitive products?

lerna

  1. High starting cost and need to be installed in advance
  2. yarn does not support monorepo natively, and requires cumbersome configuration
  3. Implicit dependency, ghost dependency
  4. changelog immature
  5. No active maintenance

rush

The idea is similar. Developers need to provide change instructions, but the process is more cumbersome than changesets, and the documents are discouraged 🤬

The basis of effectiveness in my eyes

  • pnpm monorepo

  • changesets

  • turborepo

Keywords: Web Development npm

Added by irkevin on Sun, 09 Jan 2022 03:34:54 +0200