Skip to content

Changesets

Benny Powers edited this page Nov 3, 2022 · 3 revisions

Writing Helpful Changesets

A changeset is a GitHub-Flavoured Markdown file with YAML frontmatter which describes the changes made to a project in user-friendly terms. A good changeset provides a succinct, minimally complete description of what's changed in the package version.

Changesets produce two outputs:

  1. New package versions
  2. Package changelogs

Writing Effective Changelogs

Changesets should be written in terse, past-tense prose. They should contain a minimally complete description of the fixes, features, and changes made to the package, along with examples. For major releases, they should provide a mini migration guide in the form of before and after snippets. In single package repos, changesets should always refer to the components they change.

Style

Follow these conventions to maintain a consistent voice in design system changelogs

  • Use the past tense
  • Refer to elements by tag name, with angle brackets, wrapped in a code element
  • Be specific about how changes affect users, but not about how they were implemented
  • Avoid use of headings
  • Refer to elements inline or at the start of a line followed by a colon.
  • Refer to elements by their tagname, unless specifically referring to the class constuctor

Bad:

### Changes In New Version
Fixing accessibility
### Other changes
makes RhCircle circumference twice it's radius times pi

Good:

Fixed `<rh-alert>` screen reader text to describe the state of the alert
Corrected the geometry in `<rh-circle>`

Breaking Changes

❌ Bad: Which component changed? How does the user opt in to the close button back? Use of present tense

---
"@rhds/elements": major
---
Removes close button by default

✅ Good: User knows which element changed, and how to update their existing code. Links to further docs help, too.

---
"@rhds/elements": major
---

Removed close button from `<rh-alert>` by default. Users can opt-back in either
with the `dismissable` attribute or by using the `header-actions` slot:

Before:

```html
<rh-alert></rh-alert>
```

After:

```html
<rh-alert dismissable>
  Click the close button to remove this alert
</rh-alert>

<rh-alert id="update-alert">
  <rh-button slot="header-actions" plain icon="close">x</rh-button>
  Click the close button to hide this alert.
</rh-alert>

<script type="module">
  const alert = document.getElementById('update-alert')
  alert.addEventListener('click', () => alert.hidden = true);
</script>
```

For more information, read the [alert docs](https://ux.redhat.com/components/alert).

Relevant Information

The audience for changelogs are package consumers i.e. web developers using our web components to build pages, patterns, and apps, or designers using our kits to build designs. As such, information about internal private technological changes to components should be omitted from changesets.

❌ Bad: Unnecessary detail about private APIs

Changes private methods from typescript `private` modifier to ecmascript
`#private` and removes `@bound` decorator.

✅ Good: Describes user-facing benefits; uses past tense

Improved performance and maintainability of `<rh-icon>` and `<rh-button>`.

Certain internal changes, like which web component library to use, do have user-facing consequences, so those need to be explained:

---
"@rhds/elements": major
---

Migrated all elements from `LitElement` to `FASTElement`. Several common
component APIs have changed as a result.
Before:

```js
await rhButton.updateComplete;
// async updates to rhButton are now complete
if (rhButton.diabled) {...}
```

After:

```js
import { DOM } from '@fast/element';
await DOM.nextUpdate();
// async updates to all FASTElements are now complete
if (rhButton.disabled) {...}
```

Read more about [FAST](https://fast.design) on their docs.

Semantic Versions

Each changeset represents a potentially new version of a package, although in practise, several changesets may combine into a single version. A changeset always indicates a version bump, though: there is no such thing as a changeset which doesn't indicate a release. There are three levels of releases that a changeset can describe, which are described by semantic versioning:

  • Patch releases increment the last number of a version. They represent fixes or non-breaking, non-feature changes
  • Minor releases increment the second (middle) number of a version. They represent new features which do not break existing usage of the previous version
  • Major releases increment the first number of a version, representing breaking changes. Some (or all) uses of the previous version will need to be updated in order to work with this version

In single-package repositories, there will only be one package listed in the front-matter, monorepos should include each relevant package in the frontmatter.

Monorepos

Be careful when drafting changesets in monorepos. A single commit might add a feature to package @a/b, but make a bugfix in package @a/c. In that case, you'll most likely want to write two changesets, one which describes the new feature in @a/b and another which describes the fix in @a/c. That way, the changelog for @a/c will not contain the irrelevant information about the new features in @a/b. This pattern is common when updating a sibling dependent.

Examples

@ds/button depends on @ds/icon. A new feature is added to @ds/icon, which is not reflected in the API for @ds/button. The author of these changes should prepare two changesets:

---
"@ds/icon": minor
---

Added `--ds-icon-opacity` CSS Custom Property:

```css
ds-card.ambiguous {
  --ds-icon-opacity: 0.5;
}
```
---
"@ds/button": patch
---

Updated `@ds/icon` version. See [icon docs](https://design.system/icon) for
more info.

This way, the changelog for button will not include the extraneous snippet for icon, but does include a docs link for more info.

Merging the release PR will bump the versions according to the following table:

Package Initial Version Changeset Type New Version
@ds/icon 1.0.0 minor 1.1.0
@ds/button 1.0.0 patch 1.0.1