<Meta title="Guides/Maintaining" parameters={{ viewMode: 'docs', previewTabs: { canvas: {hidden: true}, }, }} />
If you're a Canvas Kit core maintainer, this doc is for you! Consider this a field guide to help you maintain Canvas Kit with confidence. If you see some information that's unclear, incomplete, or incorrect, please update this doc to help your future self and others. Thanks for maintaining Canvas Kit!
We maintain three major versions of Canvas Kit at any given time: the previous major, the current major, and the next major version. These versions live in four branches:
support
- the previous major version - patches only, no new features or breaking changesmaster
- the current major version - patches and small updates onlyprerelease/minor
- the current major version - new features are added hereprerelease/major
- the next major version - patches, new features, and major breaking changes
We use GitHub Actions to automate our workflows and CI / CD processes. You can view all our workflows here.
Forward merges ensure that changes made in lower-versioned branches are forwarded to
higher-versioned branches. So for example, if a bug is patched in the support
branch, forward
merging propogates the fix so it's available in master
, prerelease/minor
and prerelease/major
branches. This workflow is fully automated, which reduces opportunities for error.
The
forward merge workflow
runs on support
, master
, and prerelease/minor
branches. Forward merges for support
and
master
run automatically when a release commit is merged to that branch. Every release commit
starts with chore: Release
, and that's how the forward merge workflow identifies them. Forward
merges will run on every merge to prerelease/minor
regardless of the commit message.
Run Forward Merge? | Branch | Commit Message |
---|---|---|
✅ | support |
chore: Release v6.8.14 [skip release] |
⛔️ | support |
fix: Remove unused props |
✅ | master |
chore: Release v7.3.0 [skip release] |
⛔️ | master |
fix: Update Popup types |
✅ | prerelease/minor |
feat: Add new Layout components |
If the forward merge workflow fails and cannot automatically merge the update to the next branch, it will generate a PR with instructions on how to handle the forward merge manually. For a more in-depth review, view the workflow source code.
The
release minor workflow
is initated manually and begins the process for minor releases. It checks out the
prerelease/minor
branch and pushes any commits not in master
to the master branch. It does not
run any tests or validations as all the commits have been verified by the previous workflows. Once
prerelease/minor
is merged to master
, it will trigger the release workflow
which will publish a new version of Canvas Kit.
This workflow will only fail if there are commits in master
that are not included in
prerelease/minor
. You can verify that
here. In that case,
you'll need to foward merge any commits in master
to
prerelease/minor
. For a more in-depth review of the workflow,
view the source code.
The
release workflow
is initiated automatically and runs the release process for all Canvas Kit releases (major, minor,
and patch) on the master
and support
branches. This workflow will only run if:
- The commit message does not contain
[skip release]
- OR the workflow was manually triggered and has a
version
string
At a high-level, this workflow will:
- checkout the repository
- install dependencies (if they are not already cached)
- run
yarn bump
to craete a commit and a git tag - bump package versions
- generate a changeset
- update the changelog
- build Storybook
- publish to npm
- create a GitHub release
- publish Storybook
- update Chromatic baseline
- notify Slack
For a more in-depth review of the workflow, view the source code
The
canary workflow
are initiated automatically when a commit is merged to prerelease/minor
or prerelease/major
. For
a more in-depth review of the workflow,
view the source code.
Patch releases in the support
and master
branches go out automatically once the pull request is
merged. These releases use the release workflow to publish updates
automatically.
Canvas Kit minor releases occur every three weeks. They are initiated manually by a maintainer with
the release minor workflow. Before you initiate a minor release, all
branches up to prerelease/minor
need to be forward merged. Check all of
the following to make sure there are no commits listed:
If there are any commits listed, run the
forward merge for the
branch that isn't merged forward (support
, master
, or prerelease/minor
). It is safe to run
this job even if there are no changes since the job will recognize no change and bail.
Canvas Kit major releases occur every six months. They are manual and performed by a maintainer. The process is similar to minor releases, except the addition of the support branch. All branches have to be forward merged. Check all of the following to make sure there are no commits listed:
- Compare
master
withsupport
- Compare
prerelease/minor
withmaster
- Compare
prerelease/major
withprerelease/minor
If there are any commits listed, run the
forward merge for the
branch that isn't merged forward (support
, master
, or prerelease/minor
). It is safe to run
this job even if there are no changes since the job will recognize no change and bail.
We'll be using the terms previous major
, current major
, and next major
in the context of
versions before the release process is complete. For example, if support
is pointing to v4,
master
to v5 and prerelease/major
to v6, we need to update these pointers. After these steps are
completed, the following will happen:
support
: v4 -> v5master
: v5 -> v6prerelease/minor
: v5 -> v6prerelease/major
: v6 -> v7
Before starting the next steps, we need to disable some CI jobs (Disabling Workflow Docs).
These jobs will only cause problems during the release cycle. We will enable them when we're done.
Locally, make sure to fetch upstream.
git fetch upstream
-
Update
support
to point to the current major versionmaster
is currently pointing to. This effectively moves theHEAD
pointer of thesupport
branch to the sameHEAD
ofmaster
git checkout master git pull upstream master git push upstream master:support
Normally, this would trigger a release job, but we've disabled the job and there's nothing to release anyway.
-
Re-enable the Release job (Enable Workflow Docs)
-
Update
master
to point to the next major releaseprerelease/major
is currently pointing to. This step produces the actual release, including a Slack message.git checkout prerelease/major git pull upstream prerelease/major git push upstream prerelease/major:master
This will trigger the release workflow. Up to this point,
prerelease/major
has been creating canary jobs. This will trigger the actual release. We must wait for this job to finish. The job will be running againstmaster
. The CI job will runlerna bump
and push that commit back onto themaster
branch which will include the update tolerna.json
that we need in the next step.Note: If something went wrong and a version is incorrect, you can cancel this release workflow run and manually run it with a version override. For example, for the
v8.0.0
release, alerna bump
command chosev8.0.0
for a release version on a patch update and we had to remove this release from npm. According to npm's release policy, they take down the release from npm, but the version string can never be used again, so we the actual v8 release was8.0.1
-
We need to wait for the release workflow job to finish and the slack message be announced. Once the previous step is completed, we need to update
prerelease/minor
andprerelease/major
to point to the currentHEAD
of master (which should now contain the next major version release commit).git checkout master git pull upstream master git push upstream master:prerelease/minor git push upstream master:prerelease/major
-
Re-enable the Canary and forward-merge workflows (Enable Workflow Docs)
-
🎉
Canary releases use the canary workflow to automatically publish test versions
of Canvas Kit. While these releases can be unstable, they are useful for external testing or
allowing teams to experiment with new features or fixes before a stable release is available. These
releases only run on prerelease/minor
and prerelease/major
branches.
Canary releases on the prerelease/minor
branch go out automatically once the pull request is
merged. The major version will be appended with -next.{commit-count}
, where commit-count
is the
number of commits since the last release tag. So for example, a V7 canary would look something like
this: 7.3.0-next.3
.
Canary releases on the prerelease/major
branch go out automatically once the pull request is
merged. The major version will be appended with -alpha.{build-number}-next.{commit-count}
, where
build-number
is the GitHub build identifier, and commit-count
is the number of commits since the
last release tag. So for example, a V8 canary would look something like this:
8.0.0-alpha.127-next.4
.
We use codemods to reduce friction for consumers as they make changes and do upgrades. Codemods are accompany major version releases since v5, and can also be released in minor releases if users want to apply some changes sooner.
Adding a new codemod is pretty straightforward, but this guide will make sure you don't miss any steps along the way.
First, you need to add a new command to the root CLI. For this example, we'll pretend you're adding a new v10 codemod.
// modules/codemod/lib/index.js
.command('v10 [path]', chalk.gray('Canvas Kit v9 > v10 upgrade transform'), yargs => {
yargs.positional('path', {
type: 'string',
default: '.',
describe: chalk.gray('The path to execute the transform in (recursively).'),
});
})
Next, you'll want to add new v10 files and directories.
# add code and spec directories
mkdir modules/codemod/v10 modules/codemod/spec
# add code files
touch modules/codemod/v10/index.ts modules/codemod/v10/__example__.ts
## add spec files
touch modules/codemod/v10/spec/__example__.spec.ts modules/codemod/v10/spec/expectTransformFactory.spec.ts
Now you can add your first (placeholder) codemod.
// modules/codemod/v10/__example__.ts
import {Transform} from 'jscodeshift';
// placeholder codemod
const transform: Transform = (file, api) => {
const j = api.jscodeshift;
const root = j(file.source);
return root.toSource();
};
export default transform;
And add a codemod runner:
// modules/codemod/v10/index.ts
import {Transform} from 'jscodeshift';
// TODO: Remove this
import placeholderCodemod from './__example__';
const transform: Transform = (file, api, options) => {
// These will run in order. If your transform depends on others, place yours after dependent transforms
const fixes = [
// TODO: Remove this
placeholderCodemod,
// add codemods here
];
return fixes.reduce((source, fix) => fix({...file, source}, api, options) as string, file.source);
};
export default transform;
Now you're ready to add your tests. First, we'll add this test factory to make your tests easier to write.
// modules/codemod/v10/spec/expectTransformFactory.spec.ts
import {runInlineTest} from 'jscodeshift/dist/testUtils';
export const expectTransformFactory = (fn: Function) => (
input: string,
expected: string,
options?: Record<string, any>
) => {
return runInlineTest(fn, options, {source: input}, expected, {parser: 'tsx'});
};
// modules/codemod/v10/spec/__example__.spec.ts
import {expectTransformFactory} from './expectTransformFactory';
import transform from '../__remove_this__';
const expectTransform = expectTransformFactory(transform);
describe('Example Codemod', () => {
it('should not modify the code', () => {
const input = "const foo = 'bar';";
const expected = "const foo = 'bar';";
expectTransform(input, expected);
});
});
And that's it! You're done. Stage your changes, commit, and push up a PR.