Skip to content
Draft
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
15 changes: 13 additions & 2 deletions .github/workflows/publish-alpha.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,11 @@ jobs:
- run: npx nx run-many --target=publish-build --parallel=3

- name: Publish alpha packages
id: publish-alpha
run: |
SHORT_SHA=${GITHUB_SHA:0:6}
yarn lerna publish --no-verify-access --exact --yes --include-merged-tags --no-push --no-git-reset --conventional-commits --conventional-prerelease --preid=alpha.${SHORT_SHA} --dist-tag=alpha.${SHORT_SHA}
PREID="alpha.${SHORT_SHA}"
node script/release-alpha.mjs --preid="${PREID}"
env:
GH_TOKEN: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
Expand All @@ -62,7 +64,16 @@ jobs:
run: |
{
echo 'result<<EOF'
yarn lerna ll --parseable | grep alpha | awk -F: '{print $2"@"$3}' || true
# List all published packages with alpha version
for pkg in packages/*/package.json; do
if [ -f "$pkg" ]; then
NAME=$(node -p "try { require('./$pkg').name } catch(e) { '' }")
VERSION=$(node -p "try { require('./$pkg').version } catch(e) { '' }")
if [[ "$VERSION" == *"alpha"* ]] && [[ -n "$NAME" ]]; then
echo "${NAME}@${VERSION}"
fi
fi
done
echo 'EOF'
} >> $GITHUB_OUTPUT

Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/publish-production.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,8 @@ jobs:
- name: Build All Packages
run: yarn build

- name: Lerna Publish
run: yarn lerna publish --yes --exact --conventional-commits --changelog-preset conventionalcommits --include-merged-tags --create-release=github
- name: NX Release
run: npx nx release -y
env:
GH_TOKEN: ${{ secrets.ACTIONS_GITHUB_TOKEN }}
NODE_AUTH_TOKEN: ${{ secrets.NODE_AUTH_TOKEN }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ dist/docs
# NX
dist/out-tsc
*.tsbuildinfo
/.nx
/.nx/cache
/.nx/workspace-data
# Keep .nx/version-plans tracked for NX release

packages/gamut-styles/demo-styles

Expand Down
7 changes: 7 additions & 0 deletions .nx/version-plans/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Version Plans

This directory contains version plan files for NX Release.

Version plans are created using `yarn nx release plan` and specify which packages should be versioned and with what semver bump (major, minor, or patch).

See the main README for more information about version plans.
86 changes: 63 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ _The component library & design system for Codecademy._ ✨

[![GitHub Actions](https://github.com/Codecademy/gamut/workflows/Test%20Suite/badge.svg)](https://github.com/Codecademy/gamut/actions)

This repository is a monorepo that we manage using [Lerna](https://lerna.js.org/). That means that we publish several packages to npm from the same codebase, including:
This repository is a monorepo that we manage using [NX](https://nx.dev/). That means that we publish several packages to npm from the same codebase, including:

## Gamut Kit

Expand Down Expand Up @@ -66,11 +66,46 @@ We provide a single package to manage the versions of a few core dependencies: `

### Publishing Modules

This repository uses [NX Release](https://nx.dev/recipes/nx-release) with [Version Plans](https://nx.dev/recipes/nx-release/file-based-versioning-version-plans) for package versioning and publishing.

#### Creating a Version Plan

1. Create a version plan for your changes using `yarn nx release plan`. This interactive command will prompt you to:
- Select which packages are affected by your changes
- Choose the type of version bump (major, minor, or patch)
- Provide a description of the changes for the changelog
1. The version plan will be saved as a markdown file in `.nx/version-plans/`
1. Commit this version plan file along with your code changes
1. The version plan will be applied when your PR is merged to main

#### Version Plan Format

Version plan files are markdown files with YAML front matter. Here's an example:

```markdown
---
gamut: minor
gamut-styles: patch
---

Add new Button variant and fix spacing issues

- Added a new "ghost" variant to the Button component
- Fixed margin spacing in the Card component
```

#### Publishing Process

1. Make your changes in a feature branch, and get another engineer to review your code
1. After your code has been reviewed and tested, you can merge your branch into main.
1. Make sure to update your PR title and add a short description of your changes for the changelog (see the [PR Title Guide](https://github.com/Codecademy/gamut#pr-title-guide))
1. Make sure to update your PR title following the [PR Title Guide](https://github.com/Codecademy/gamut#pr-title-guide)
1. To merge your changes, add the `Ship It` label to your Pull Request.
1. Once your branch is merged into main, it will be published automatically by GitHub Actions.
1. Once your branch is merged into main, it will be published automatically by GitHub Actions using NX Release.
- NX Release will apply all version plans found in `.nx/version-plans/`
- It will bump package versions according to the plans
- It will generate changelog entries from the version plan descriptions
- It will publish the packages to npm
- It will create git tags and GitHub releases
1. You can find the new version number on npmjs.com/package/<package-name>, or find it in that package's `package.json` on the `main` branch

### Publishing an alpha version of a module
Expand All @@ -87,7 +122,7 @@ Every PR that changes files in a package publishes alpha releases that you can u

### Working with pre-published changes

> NOTE: Due to the inconsistencies of symlinks in a lerna repo, _instead_ of using `yarn link`, we recommend using the `npm-link-better` package with the `--copy` flag to copy packages into your local repo's `node_modules` directory.
> NOTE: Due to the inconsistencies of symlinks in a monorepo, _instead_ of using `yarn link`, we recommend using the `npm-link-better` package with the `--copy` flag to copy packages into your local repo's `node_modules` directory.

**Initial Setup:**

Expand Down Expand Up @@ -184,14 +219,15 @@ for more information for why you have to do this.

### Adding a New Package

1. Create a new directory at `packages/<package-name>/package.json`.
1. Use `yarn lerna create` to create the new package, copying values from existing `package.json`s when unsure.
- Also copy the `publishConfig` field to let your published package be public by default
1. Create a minimal amount of source code in the new package
- Example: a simple `tsconfig.json` with a `index.ts` exporting a single object
1. Run `yarn lerna bootstrap` from the repository root
1. Send a `feat` PR adding that package
1. One merged, message out in our #frontend Slack channel to other Gamut developers to re-run `yarn lerna bootstrap` after they merge from `main`
1. Use NX generators to create the new package. For example:
```bash
yarn nx g @nx/react:library <package-name> --buildable --publishable
```
- Make sure to set the `publishConfig` field to `{ "access": "public" }` in the generated package.json to let your published package be public by default
1. Customize the generated source code as needed for your package
1. Run `yarn install` from the repository root
1. Send a `feat` PR adding that package with a version plan (using `yarn nx release plan`)
1. Once merged, message out in our #frontend Slack channel to other Gamut developers to re-run `yarn install` after they merge from `main`

Notes:

Expand All @@ -209,11 +245,9 @@ For new packages, please use an NX generator plugin to create your initial packa

Your PR Title should follow the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) Format.

Because we automatically squash merge Pull Requests, you'll need to format your PR title to match these guidelines since the title will become the commit message.

Your individual commits will affect the `alpha` version number, but not the final version once you merge to main.
Because we automatically squash merge Pull Requests, you'll need to format your PR title to match these guidelines.

This Title format will be linted in the `conventional-pr-title` status check and prevent merging if you do not follow the correct format.
**Note:** With the migration to NX Release and Version Plans, the version bumps are now determined by the version plan files you create using `yarn nx release plan`, rather than commit messages. However, we still recommend following Conventional Commits format for consistency and clarity.

### PR Title Format

Expand Down Expand Up @@ -249,7 +283,7 @@ Check out the [Conventional Commits](https://www.conventionalcommits.org/en/v1.0

**Type**

The `type` determines what kind of version bump is needed. A `fix` will create a `patch` release, while a `feat` will create a `minor` release. Major version updates require a special syntax that is described below.
The `type` describes what kind of change you're making. With NX Release and Version Plans, you'll specify the version bump (major/minor/patch) directly when creating your version plan using `yarn nx release plan`.

`type` must be one of the following options:

Expand All @@ -271,15 +305,21 @@ A scope is optional and consists of a noun describing a section of the codebase

**Breaking Changes**

Adding an exclamation point after your type, before the colon, will indicate that your PR contains a breaking change, and increment the major version number of the modules you changed.
Breaking changes are indicated in version plans by specifying a `major` version bump. When creating a version plan with `yarn nx release plan`, select "major" as the bump type for packages that introduce breaking changes.

Examples:
Examples of version plans with breaking changes:

`feat!: made a breaking change in the Button component`
```markdown
---
gamut: major
---

`feat(Button)!: made a breaking change in the Button component`
Breaking: Removed deprecated Button variants

This removes the previously deprecated "primary-blue" and "secondary-red" variants.
```

You should do this if your changes introduce any incompatibilities with previous versions of the module.
You should create a major version bump if your changes introduce any incompatibilities with previous versions of the module.
This will indicate to package consumers that they need to refactor their usage of the module to upgrade.

#### Breaking Changes Release Process
Expand All @@ -302,7 +342,7 @@ Optional extra description for your changes.

This goes in the description for your PR, between the `<!--- CHANGELOG-DESCRIPTION -->` comment tags in the PR template.

If you include the text `BREAKING CHANGE:` in your description it will trigger a major version bump. We prefer to use the `feat!:` syntax for breaking changes described above.
With NX Release and Version Plans, changelog content is primarily driven by the description in your version plan files, not the PR description. The version plan description will appear in the generated CHANGELOG.md files.

## Publishing Storybook

Expand Down
16 changes: 0 additions & 16 deletions lerna.json

This file was deleted.

18 changes: 17 additions & 1 deletion nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,21 @@
"nxCloudAccessToken": "ZmVjZWYxNzctYTdmZC00ODYzLTg4MzEtZTE1YTVmZDdkZmY1fHJlYWQ=",
"parallel": 3,
"useInferencePlugins": false,
"defaultBase": "main"
"defaultBase": "main",
"release": {
"projects": ["packages/*"],
"projectsRelationship": "independent",
"versionPlans": true,
"changelog": {
"workspaceChangelog": false,
"projectChangelogs": {
"createRelease": "github"
}
},
"git": {
"commit": true,
"commitMessage": "chore(release): publish",
"tag": true
}
}
}
5 changes: 1 addition & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@
"babel-jest": "29.6.4",
"babel-plugin-macros": "3.0.1",
"component-test-setup": "^0.3.1",
"conventional-changelog-cli": "^2.0.34",
"conventional-changelog-conventionalcommits": "^4.3.0",
"cpy-cli": "^4.1.0",
"eslint": "^8.11.0",
"eslint-plugin-gamut": "^2.0.0",
Expand All @@ -76,7 +74,6 @@
"jest-environment-jsdom": "29.6.4",
"jest-environment-jsdom-global": "4.0.0",
"jest-junit": "^16.0.0",
"lerna": "7.2.0",
"lint-staged": "14.0.1",
"micromatch": "^4.0.5",
"mutationobserver-shim": "^0.3.3",
Expand Down Expand Up @@ -126,7 +123,7 @@
"build-storybook": "nx run styleguide:build-storybook",
"build:graph": "nx graph",
"clean-builds": "nx run-many --target=clean --all",
"clear-modules": "yarn clean-builds && lerna clean -y && rm -rf node_modules",
"clear-modules": "yarn clean-builds && rm -rf node_modules",
"deploy": "rm -rf ./dist/docs && mv ./dist/storybook/styleguide ./dist/docs && cp -r ./dist/static/* ./dist/docs && gh-pages -b gh-pages -d dist",
"format": "yarn lint:fix && yarn prettier --write",
"format:verify": "yarn prettier --check",
Expand Down
100 changes: 100 additions & 0 deletions script/release-alpha.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#!/usr/bin/env node

/**
* Alpha Release Script
*
* This script uses the NX Release programmatic API to publish alpha versions
* of packages. It is designed to run in CI for pull requests.
*
* Usage: node script/release-alpha.mjs --preid=alpha.abc123
*/

import { releasePublish, releaseVersion } from 'nx/release/index.js';

// Parse command line arguments
const args = process.argv.slice(2);
const parsedArgs = {};

args.forEach((arg) => {
if (arg.startsWith('--')) {
const [key, value] = arg.substring(2).split('=');
parsedArgs[key] = value || true;
} else if (arg.startsWith('-')) {
parsedArgs[arg.substring(1)] = true;
}
});

const preid = parsedArgs.preid;
const dryRun = parsedArgs.dryRun === true || parsedArgs.d === true;
const verbose = parsedArgs.verbose === true;

if (!preid) {
console.error('❌ Error: --preid argument is required');
console.error('Usage: node script/release-alpha.mjs --preid=alpha.abc123');
process.exit(1);
}

(async () => {
console.log(`📦 Starting alpha release with preid: ${preid}`);
if (dryRun) {
console.log('🔍 DRY RUN MODE - No changes will be made');
}

try {
// Step 1: Version all packages as prerelease
console.log('\n🔢 Running versioning step...');
const { workspaceVersion, projectsVersionData } = await releaseVersion({
specifier: 'prerelease',
preid: preid,
stageChanges: false,
gitCommit: false,
gitTag: false,
dryRun: dryRun,
verbose: verbose,
});

console.log('\n📝 Versioning complete:');
if (workspaceVersion) {
console.log(` Workspace version: ${workspaceVersion}`);
}

// Log versioned projects
const versionedProjects = Object.entries(projectsVersionData);
if (versionedProjects.length > 0) {
console.log(` ${versionedProjects.length} projects versioned:`);
versionedProjects.forEach(([projectName, data]) => {
console.log(` - ${projectName}: ${data.newVersion}`);
});
}

// Step 2: Publish packages with alpha tag
console.log(`\n📤 Publishing packages with tag: ${preid}...`);
const publishStatus = await releasePublish({
tag: preid,
dryRun: dryRun,
verbose: verbose,
});

// Check publish results
console.log('\n✅ Publishing complete:');
const results = Object.entries(publishStatus);
const successful = results.filter(([_, status]) => status.code === 0);
const failed = results.filter(([_, status]) => status.code !== 0);

console.log(` Successful: ${successful.length}`);
if (failed.length > 0) {
console.log(` Failed: ${failed.length}`);
failed.forEach(([project, status]) => {
console.error(` - ${project}: exit code ${status.code}`);
});
}

// Exit with appropriate code
const exitCode = failed.length > 0 ? 1 : 0;
process.exit(exitCode);
} catch (error) {
console.error('\n❌ Alpha release failed:');
console.error(error);
process.exit(1);
}
})();
Loading
Loading