Skip to content

Commit e22b1f8

Browse files
Merge pull request #8219 from BitGo/BTC-3073.add-beta-tools
docs: document beta release process and add @bitgo/beta-tools
2 parents 0ebabf2 + 043aee2 commit e22b1f8

23 files changed

Lines changed: 1433 additions & 1 deletion

docs/beta-release.md

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
# Beta Release Process (`@bitgo-beta/*`)
2+
3+
## Overview
4+
5+
BitGoJS publishes beta releases under the `@bitgo-beta` scope on npm. The `scripts/prepare-release.ts`
6+
script transforms the entire monorepo — re-scoping all `@bitgo/*` packages to `@bitgo-beta/*`, computing
7+
prerelease versions, and pinning all inter-module dependency versions. This enables publishing beta/alpha
8+
releases without conflicting with stable releases.
9+
10+
## How `prepare-release.ts` Works
11+
12+
```
13+
CLI: npx tsx scripts/prepare-release.ts [preid] --scope [scope] --root-dir [dir]
14+
Defaults: preid=beta, scope=@bitgo-beta, root-dir=<repo-root>
15+
```
16+
17+
### Step 1: Scope Replacement
18+
19+
The script walks all `.ts`, `.tsx`, `.js`, `.json` files in `modules/` and `webpack/` (skipping
20+
`node_modules/`), performing a global regex replacement of every `@bitgo/X` reference with
21+
`@bitgo-beta/X`. This covers:
22+
23+
- `package.json` dependency entries
24+
- TypeScript/JavaScript import statements
25+
- Any other string references to `@bitgo/` scoped packages
26+
27+
**Special case**: The `modules/bitgo` package is the only one published without an `@bitgo/` prefix.
28+
Its `package.json` name is explicitly set to `@bitgo-beta/bitgo`.
29+
30+
Implementation: `scripts/prepareRelease/changeScopeInFile.ts`
31+
32+
### Step 2: Version Computation
33+
34+
For each module, the script:
35+
36+
1. Fetches dist-tags from npm (`https://registry.npmjs.org/-/package/<name>/dist-tags`)
37+
2. Determines the previous prerelease version:
38+
- If a beta tag exists and its base version >= latest, use the beta tag as base
39+
- If the beta tag's base version < latest, start a new prerelease from latest
40+
- If no beta tag exists, create one from latest
41+
3. Computes the next version via `semver.inc(prevTag, 'prerelease', preid)`
42+
43+
Example: `8.2.1-beta.1009``8.2.1-beta.1010`
44+
45+
The dist-tag fetch can be cached via `BITGO_PREPARE_RELEASE_CACHE_DIST_TAGS` env var pointing to a
46+
JSON file, avoiding repeated npm registry calls.
47+
48+
Implementation: `scripts/prepareRelease/distTags.ts`
49+
50+
### Step 3: Cross-Module Version Pinning
51+
52+
After each module's version is bumped, all other modules that depend on it have their dependency
53+
version updated to the exact new version. This **removes semver ranges** (`^`, `~`), resulting in
54+
pinned versions:
55+
56+
```
57+
Before: "@bitgo/sdk-core": "^31.2.1"
58+
After: "@bitgo-beta/sdk-core": "8.2.1-beta.1010"
59+
```
60+
61+
Implementation: `scripts/prepareRelease/changePackageJson.ts`
62+
63+
## Side Effects for Consumers
64+
65+
Because all dependency versions are pinned (no ranges), consumers of `@bitgo-beta/*` packages must
66+
**explicitly bump** to new versions when they are published. The `@bitgo/beta-tools` package provides
67+
a canonical CLI and library for this — see its README for usage.
68+
69+
Key behaviors to understand:
70+
71+
- Each `@bitgo-beta` package has its own **independent prerelease counter** (e.g.,
72+
`sdk-core@8.2.1-beta.788`, `statics@15.1.1-beta.791`). There is no shared suffix —
73+
what ties a release together is the CI publish run.
74+
- The `beta` dist-tag on npm always points to the latest published prerelease for each package.
75+
- Fetching dist-tags individually during a multi-package publish can yield inconsistent versions
76+
(a race condition): some packages may have the new version while others still show the old one.
77+
Use `--versions-file` with a CI-generated manifest to avoid this.
78+
79+
## Helper Modules (`scripts/prepareRelease/`)
80+
81+
| File | Purpose |
82+
|------|---------|
83+
| `changeScopeInFile.ts` | Regex replacement of `@bitgo/*` → target scope in file contents |
84+
| `changePackageJson.ts` | Updates dependency versions in `package.json` objects |
85+
| `distTags.ts` | Fetches/caches npm dist-tags for all modules |
86+
| `getLernaModules.ts` | Runs `lerna list --json --all` to discover all modules |
87+
| `walk.ts` | Recursively walks directories, filtering by file extension |
88+
| `index.ts` | Barrel export |
89+
90+
## Known Limitations
91+
92+
- `setDependencyVersion` in `changePackageJson.ts` only updates `dependencies` and `devDependencies`.
93+
It does **not** update `peerDependencies` or `buildDependencies` (marked with a FIXME).
94+
- Three packages are skipped during dist-tag fetch: `@bitgo-beta/express`, `@bitgo-beta/web-demo`,
95+
`@bitgo-beta/sdk-test` (not published to npm).
96+
97+
## Related Scripts
98+
99+
| Script | Purpose |
100+
|--------|---------|
101+
| `scripts/prepare-release.ts` | Main transformation script (this document) |
102+
| `@bitgo/beta-tools` (`modules/beta-tools`) | Canonical tool for consumers to bump `@bitgo-beta/*` versions |

modules/beta-tools/.eslintignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
dist/

modules/beta-tools/.eslintrc.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"extends": "../../.eslintrc.json"
3+
}

modules/beta-tools/.mocharc.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
require: 'tsx',
3+
extension: ['.js', '.ts'],
4+
};

modules/beta-tools/README.md

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
# @bitgo/beta-tools
2+
3+
CLI and library for bumping `@bitgo-beta/*` dependency versions in consumer projects.
4+
5+
## Problem
6+
7+
BitGoJS publishes beta packages under the `@bitgo-beta` scope with pinned (non-range) inter-module
8+
dependency versions. Consumer repos must explicitly bump these versions. This tool replaces the
9+
divergent bespoke scripts that existed in individual consumer repos.
10+
11+
## How version resolution works
12+
13+
Strategies are tried in order — the first available one wins:
14+
15+
1. **Manifest file (`--versions-file`):** Reads an explicit JSON map of package→version. Most
16+
deterministic — useful for CI pipelines that generate a manifest during publish.
17+
18+
2. **GitHub Actions API** (when `GITHUB_TOKEN` is set): Fetches the logs of the latest successful
19+
"Publish @bitgo-beta" workflow run and parses the verify-release output. This gives the complete
20+
version set (~106 packages) from a single CI run — race-free, no gaps.
21+
22+
3. **npm registry (default fallback):** Fetches `@bitgo-beta/bitgo` at the requested dist-tag. Its
23+
`dependencies` field contains pinned versions for ~92 packages from the same CI publish run.
24+
Packages not covered by the megapackage (typically 5-6 per consumer) fall back to individual
25+
dist-tag lookups — these are racy during active publishes.
26+
27+
## CLI usage
28+
29+
```bash
30+
# Via npx
31+
npx @bitgo-beta/beta-tools --tag beta
32+
33+
# Or install as devDependency
34+
npm install -D @bitgo-beta/beta-tools
35+
bump-bitgo-beta --tag beta
36+
```
37+
38+
### Options
39+
40+
| Option | Default | Description |
41+
|---|---|---|
42+
| `--tag <tag>` | `beta` | Dist tag to resolve |
43+
| `--versions-file <path>` || JSON manifest of package→version mappings |
44+
| `--scope <scope>` | `@bitgo-beta` | Package scope to match in `package.json` |
45+
| `--pm <npm\|yarn\|pnpm>` | auto-detected | Package manager to use |
46+
| `--ignore <pkg...>` | `[]` | Packages to skip |
47+
| `--only-utxo` | `false` | Only bump UTXO-related packages |
48+
| `--ignore-utxo` | `true` (when `--only-utxo` not set) | Skip UTXO-related packages |
49+
| `--utxo-patterns <patterns...>` | `utxo, unspents, abstract-lightning, babylonlabs-io-btc-staking-ts` | Patterns for UTXO package detection |
50+
| `--check-duplicates` | `true` | Check lockfile for duplicate versions after install (npm only) |
51+
| `--check-duplicate-packages <pkg...>` | `@bitgo-beta/utxo-lib, @bitgo/wasm-utxo` | Packages to check for duplicates |
52+
| `--dry-run` | `false` | Show what would be installed without installing |
53+
54+
### Examples
55+
56+
```bash
57+
# Bump all non-UTXO beta deps (default behavior)
58+
bump-bitgo-beta
59+
60+
# Bump only UTXO packages
61+
bump-bitgo-beta --only-utxo
62+
63+
# Bump everything, skip duplicate check
64+
bump-bitgo-beta --ignore-utxo=false --check-duplicates=false
65+
66+
# Use a CI-generated manifest
67+
bump-bitgo-beta --versions-file ./beta-versions.json
68+
69+
# Preview without installing
70+
bump-bitgo-beta --dry-run
71+
```
72+
73+
## Library API
74+
75+
```typescript
76+
import {
77+
resolveVersions,
78+
filterDependencies,
79+
detectPackageManager,
80+
createPackageManager,
81+
checkDuplicates,
82+
} from '@bitgo-beta/beta-tools';
83+
84+
const resolved = await resolveVersions({
85+
packages: ['@bitgo-beta/sdk-core', '@bitgo-beta/statics'],
86+
tag: 'beta',
87+
scope: '@bitgo-beta',
88+
});
89+
90+
for (const [pkg, version] of resolved.versions) {
91+
console.log(`${pkg}@${version}`);
92+
}
93+
```
94+
95+
## Development
96+
97+
```bash
98+
yarn build
99+
yarn lint
100+
yarn unit-test
101+
```

modules/beta-tools/package.json

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
{
2+
"name": "@bitgo/beta-tools",
3+
"version": "1.0.0",
4+
"description": "CLI and library for bumping @bitgo-beta dependency versions",
5+
"main": "./dist/src/index.js",
6+
"types": "./dist/src/index.d.ts",
7+
"bin": {
8+
"bump-bitgo-beta": "./dist/src/cli.js"
9+
},
10+
"files": [
11+
"dist/src/**/*"
12+
],
13+
"scripts": {
14+
"prepare": "npm run build",
15+
"build": "yarn tsc --build --incremental --verbose .",
16+
"lint": "eslint --quiet .",
17+
"unit-test": "mocha --recursive test",
18+
"fmt": "prettier --write '{src,test}/**/*.{ts,js}'"
19+
},
20+
"repository": {
21+
"type": "git",
22+
"url": "https://github.com/BitGo/BitGoJS.git",
23+
"directory": "modules/beta-tools"
24+
},
25+
"dependencies": {
26+
"yargs": "^17.7.2"
27+
},
28+
"devDependencies": {
29+
"@types/yargs": "^17.0.0",
30+
"sinon": "^13.0.1",
31+
"@types/sinon": "^10.0.0"
32+
},
33+
"lint-staged": {
34+
"*.{js,ts}": [
35+
"yarn prettier --write",
36+
"yarn eslint --fix"
37+
]
38+
},
39+
"publishConfig": {
40+
"access": "public"
41+
},
42+
"license": "MIT"
43+
}

0 commit comments

Comments
 (0)