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

Migrate to changesets #565

Merged
merged 8 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changesets

Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)

We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)
173 changes: 173 additions & 0 deletions .changeset/changelog.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,173 @@
const {
getInfo,
getInfoFromPullRequest,
} = require('@changesets/get-github-info');

/**
* Bold the scope of the changelog entry.
*
* @param {string} firstLine
*/
const boldScope = (firstLine) => firstLine.replace(/^([^:]+): /, '**$1:** ');

/**
* Adapted from `@changesets/cli`.
*
* {@link https://github.com/atlassian/changesets/blob/%40changesets/cli%402.17.0/packages/cli/src/changelog/index.ts}
*
* @type import('@changesets/types').ChangelogFunctions
*/
const defaultChangelogFunctions = {
getDependencyReleaseLine: async (changesets, dependenciesUpdated) => {
if (dependenciesUpdated.length === 0) return '';

const changesetLinks = changesets.map(
(changeset) => `- Updated dependencies [${changeset.commit}]`,
);

const updatedDependenciesList = dependenciesUpdated.map(
(dependency) => ` - ${dependency.name}@${dependency.newVersion}`,
);

return [...changesetLinks, ...updatedDependenciesList].join('\n');
},
getReleaseLine: async (changeset) => {
const [firstLine, ...futureLines] = changeset.summary
.split('\n')
.map((l) => l.trimRight());

const formattedFirstLine = boldScope(firstLine);

const suffix = changeset.commit;

return `\n\n- ${formattedFirstLine}${
suffix ? ` (${suffix})` : ''
}\n${futureLines.map((l) => ` ${l}`).join('\n')}`;
},
};

/**
* Adapted from `@changesets/changelog-github`.
*
* {@link https://github.com/atlassian/changesets/blob/%40changesets/changelog-github%400.4.1/packages/changelog-github/src/index.ts}
*
* @type import('@changesets/types').ChangelogFunctions
*/
const gitHubChangelogFunctions = {
getDependencyReleaseLine: async (
changesets,
dependenciesUpdated,
options,
) => {
if (!options.repo) {
throw new Error(
'Please provide a repo to this changelog generator like this:\n"changelog": ["./changelog.js", { "repo": "org/repo" }]',
);
}
if (dependenciesUpdated.length === 0) return '';

const changesetLink = `- Updated dependencies [${(
await Promise.all(
changesets.map(async (cs) => {
if (cs.commit) {
let { links } = await getInfo({
repo: options.repo,
commit: cs.commit,
});
return links.commit;
}
}),
)
)
.filter((_) => _)
.join(', ')}]:`;

const updatedDependenciesList = dependenciesUpdated.map(
(dependency) => ` - ${dependency.name}@${dependency.newVersion}`,
);

return [changesetLink, ...updatedDependenciesList].join('\n');
},
getReleaseLine: async (changeset, _type, options) => {
if (!options || !options.repo) {
throw new Error(
'Please provide a repo to this changelog generator like this:\n"changelog": ["./changelog.js", { "repo": "org/repo" }]',
);
}

/** @type number | undefined */
let prFromSummary;
/** @type string | undefined */
let commitFromSummary;

const replacedChangelog = changeset.summary
.replace(/^\s*(?:pr|pull|pull\s+request):\s*#?(\d+)/im, (_, pr) => {
let num = Number(pr);
if (!isNaN(num)) prFromSummary = num;
return '';
})
.replace(/^\s*commit:\s*([^\s]+)/im, (_, commit) => {
commitFromSummary = commit;
return '';
})
.replace(/^\s*(?:author|user):\s*@?([^\s]+)/gim, (_, user) => {
usersFromSummary.push(user);
return '';
})
.trim();

const [firstLine, ...futureLines] = replacedChangelog
.split('\n')
.map((l) => l.trimRight());

const links = await (async () => {
if (prFromSummary !== undefined) {
let { links } = await getInfoFromPullRequest({
repo: options.repo,
pull: prFromSummary,
});
if (commitFromSummary) {
links = {
...links,
commit: `[\`${commitFromSummary}\`](https://github.com/${options.repo}/commit/${commitFromSummary})`,
};
}
return links;
}
const commitToFetchFrom = commitFromSummary || changeset.commit;
if (commitToFetchFrom) {
let { links } = await getInfo({
repo: options.repo,
commit: commitToFetchFrom,
});
return links;
}
return {
commit: null,
pull: null,
user: null,
};
})();

const formattedFirstLine = boldScope(firstLine);

const suffix = links.pull ?? links.commit;

return [
`\n- ${formattedFirstLine}${suffix ? ` (${suffix})` : ''}`,
...futureLines.map((l) => ` ${l}`),
].join('\n');
},
};

if (process.env.GITHUB_TOKEN) {
module.exports = gitHubChangelogFunctions;
} else {
console.warn(
`Defaulting to Git-based versioning.
Enable GitHub-based versioning by setting the GITHUB_TOKEN environment variable.
This requires a GitHub personal access token with the \`public_repo\` scope: https://github.com/settings/tokens/new`,
);

module.exports = defaultChangelogFunctions;
}
11 changes: 11 additions & 0 deletions .changeset/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"$schema": "https://unpkg.com/@changesets/[email protected]/schema.json",
"changelog": ["./changelog.js", { "repo": "seek-oss/scoobie" }],
"commit": false,
"fixed": [],
"linked": [],
"access": "public",
"baseBranch": "master",
"updateInternalDependencies": "patch",
"ignore": []
}
10 changes: 7 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ jobs:
with:
fetch-depth: 0
lfs: true
token: ${{ secrets.SEEK_OSS_CI_GITHUB_TOKEN }}

- name: Set up Node.js 18.x
uses: actions/setup-node@v3
Expand All @@ -32,12 +33,15 @@ jobs:
run: yarn install --frozen-lockfile

- name: Publish to npm
run: yarn release
uses: changesets/action@v1
with:
publish: yarn release
version: yarn stage
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ secrets.SEEK_OSS_CI_GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.SEEK_OSS_CI_NPM_TOKEN }}

- name: Publish Storybook
run: yarn storybook:build && yarn storybook:deploy -- --ci --host-token-env-variable=GITHUB_TOKEN
env:
GITHUB_TOKEN: ${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}
GITHUB_TOKEN: ${{ github.actor }}:${{ secrets.GITHUB_TOKEN }}
34 changes: 34 additions & 0 deletions .github/workflows/snapshot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Snapshot

on: workflow_dispatch

permissions: {}

jobs:
publish:
name: Publish Snapshot
permissions:
id-token: write
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.SEEK_OSS_CI_GITHUB_TOKEN }}

- name: Set up Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 18.x

- name: Install dependencies
run: yarn install --frozen-lockfile

- name: Publish to npm
uses: seek-oss/changesets-snapshot@v0
with:
pre-publish: yarn build
env:
GITHUB_TOKEN: ${{ secrets.SEEK_OSS_CI_GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.SEEK_OSS_CI_NPM_TOKEN }}
88 changes: 34 additions & 54 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ If you're on Windows, we recommend the [Windows Subsystem for Linux].

First, some JavaScript tooling:

- Node.js 12+
- Node.js LTS
- Yarn 1.x

Next, install npm dependencies:
Expand Down Expand Up @@ -134,96 +134,76 @@ yarn test

## Releases

### Writing a semantic commit message
### Creating a changeset

Consider whether you are making a visible change to the public Scoobie interface,
We use [Changesets] to manage package releases.
You'll see a 🦋 bot gliding around pull requests.

You should write a changeset if you are changing the public Scoobie interface,
which includes:

- Top-level exports from [src/index.ts](/src/index.ts)
- Top-level exports from [webpack/index.js](/webpack/index.js)
- Bundled configuration files [types.d.ts](/types.d.ts) and [typography.ts](/typography.ts)
- [npm dependencies](/package.json)

A release is not necessary for:
On the other hand,
a changeset is not necessary for:

- Documentation like the [README](/README.md)
- Documentation like the [README](README.md)
- Internal refactoring that preserves the existing interface
- [npm dev dependencies](/package.json)

We use **[semantic-release]** to manage package releases.
Commits should follow the [Conventional Commits] spec for [semantic versioning]:
- [npm dev dependencies](https://github.com/seek-oss/scoobie/blob/master/package.json)

- No release
```shell
yarn changeset
```

```text
chore(scope): Update documentation
```
The Changesets CLI is interactive and follows [semantic versioning]:

- Patch release `0.0.X`: fixes or tweaks to existing functionality

```text
fix(scope): Squash a bug
```

- Minor release `0.X.0`: new, backwards-compatible functionality

```text
feat(scope): Add a feature
```

- Major release `X.0.0`: backwards-incompatible modification

```text
fix(scope): Close security holes

BREAKING CHANGE: We deleted all our code.
```

Note that the `fix` type could be anything;
the `BREAKING CHANGE:` prefix in the commit body is what determines the release as major.

Specifying a scope makes it easy to eyeball which part of Scoobie a change relates to:

```text
chore(docs): Update README

fix(MdxProvider): Adjust heading spacing
```
The Changesets CLI will generate a Markdown file under [.changeset](https://github.com/seek-oss/scoobie/tree/master/.changeset),
which you should include in your pull request.
It doesn't need to be part of the same commit as the rest of your changes.
Feel free to manually edit this file to include more details about your change.

### Publishing a release

When a pull request is merged,
our [release](/.github/workflows/release.yml) GitHub Actions workflow will publish the associated GitHub release and npm package version.

We [squash our commits],
so the merged commit itself needs to have a [semantic commit message](#writing-a-semantic-commit-message).
When a pull request with a changeset is merged,
our CI workflow will create a new `Version Packages` PR.
The changesets are used to infer the next semantic version and to update the [changelog].

Scoobie is packaged as TypeScript source code.
Consumers control the compilation; see [sku.config.js].
This PR may be left open to collate multiple changes into the next version.
A maintainer will merge it once ready,
and our [release](https://github.com/seek-oss/scoobie/blob/master/.github/workflows/release.yml) GitHub Actions workflow will publish the associated GitHub release and npm package version.

### Publishing a prerelease

We currently have limited support for prereleases on the `beta` [dist-tag].
This can only be performed by a maintainer.
Prereleases can be created on demand via [seek-oss/changesets-snapshot].

Simply push changes to the `beta` branch on GitHub.
Run the [Snapshot workflow] in GitHub Actions to publish a new snapshot version to npm.

<https://www.npmjs.com/package/scoobie?activeTab=versions>

[#indirect]: https://seekchat.slack.com/channels/indirect
[conventional commits]: https://www.conventionalcommits.org/en/v1.0.0-beta.2/
[changelog]: CHANGELOG.md
[changesets]: https://github.com/atlassian/changesets
[create a pull request]: https://github.com/seek-oss/scoobie/compare
[design system]: https://github.com/seek-oss/braid-design-system
[development toolkit]: https://github.com/seek-oss/sku
[dist-tag]: https://docs.npmjs.com/cli/dist-tag
[fork the repo]: https://github.com/seek-oss/scoobie/fork
[loki]: https://loki.js.org/
[npm package]: https://www.npmjs.com/package/scoobie
[release notes]: https://github.com/seek-oss/scoobie/releases
[seek-oss/changesets-snapshot]: https://github.com/seek-oss/changesets-snapshot
[semantic versioning]: https://semver.org/
[semantic-release]: https://github.com/semantic-release/semantic-release
[sku]: https://github.com/seek-oss/sku
[sku.config.js]: https://github.com/seek-oss/scoobie#skuconfigjs
[sku]: https://github.com/seek-oss/sku
[snapshot workflow]: https://github.com/seek-oss/scoobie/actions/workflows/snapshot.yml
[squash our commits]: https://github.blog/2016-04-01-squash-your-commits/
[storybook]: https://storybook.js.org/
[storybook site]: https://seek-oss.github.io/scoobie/
[storybook]: https://storybook.js.org/
[submit an issue]: https://github.com/seek-oss/scoobie/issues/new/choose
[windows subsystem for linux]: https://en.wikipedia.org/wiki/Windows_Subsystem_for_Linux
Loading