Skip to content

Commit 568626e

Browse files
Add automated CHANGELOG release preparation script
Created scripts/prepare-changelog-release.cjs to automate CHANGELOG updates during releases: - Replaces "Unreleased" with version number and date - Adds new empty "Unreleased" section at top - Validates version format and CHANGELOG structure - Added as npm script: changelog:prepare-release Updated CLAUDE.md with release process documentation showing how to use the new script. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
1 parent 33d653f commit 568626e

7 files changed

Lines changed: 247 additions & 1 deletion

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,14 @@
77
- Document what changed, why, and any breaking changes
88
- Add entry under "Unreleased" section with PR number
99

10+
### Developer Experience
11+
12+
- **Release Process**: Added automated CHANGELOG preparation script (#112)
13+
- New `npm run changelog:prepare-release <version>` command
14+
- Automatically replaces "Unreleased" with version and date
15+
- Adds new empty "Unreleased" section for next changes
16+
- Includes validation for version format and CHANGELOG structure
17+
1018
## 0.8.3
1119

1220
### Security

CLAUDE.md

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,27 @@ When creating pull requests:
9191
- Add your entry under the "Unreleased" section at the top
9292
- Include the PR number and a brief description of the change
9393

94+
### Release Process
95+
96+
When preparing a new release:
97+
98+
```bash
99+
# Prepare CHANGELOG for release (replaces "Unreleased" with version and date)
100+
npm run changelog:prepare-release 1.0.0
101+
102+
# Review changes, then commit and tag
103+
git add CHANGELOG.md
104+
git commit -m "Release v1.0.0"
105+
git tag v1.0.0
106+
git push && git push --tags
107+
```
108+
109+
The `changelog:prepare-release` script automatically:
110+
111+
- Replaces "## Unreleased" with "## {version} - {date}"
112+
- Adds a new empty "## Unreleased" section at the top
113+
- Validates version format and CHANGELOG structure
114+
94115
## Important Constraints
95116

96117
- **Dependency Injection**: Tools must accept `httpRequest` parameter for testability

PR_DESCRIPTION.md

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
# Add explicit subpath exports (alternative to #110)
2+
3+
## Summary
4+
5+
This PR provides a better alternative to #110's wildcard export approach. Instead of `"./*": "./*"` which exposes the entire internal structure, this implements explicit, well-documented subpath exports.
6+
7+
## Motivation
8+
9+
Addresses the need from #110 where users want to import parts of this package without the entire server. The wildcard approach in #110 has several drawbacks:
10+
11+
- Exposes all internal implementation details
12+
- No control over public API surface
13+
- Makes it harder to refactor internals without breaking users
14+
- Not clear what's intended to be public vs private
15+
16+
## Solution
17+
18+
Explicit subpath exports via tshy:
19+
20+
- **`@mapbox/mcp-server/tools`** - Tool classes and pre-configured instances
21+
- **`@mapbox/mcp-server/resources`** - Resource classes and instances
22+
- **`@mapbox/mcp-server/prompts`** - Prompt classes and instances
23+
- **`@mapbox/mcp-server/utils`** - HTTP pipeline utilities
24+
25+
All exports support both ESM and CommonJS automatically via tshy dual builds.
26+
27+
## Usage Examples
28+
29+
### Simple: Pre-configured instances
30+
31+
```typescript
32+
import {
33+
directions,
34+
searchAndGeocode,
35+
isochrone
36+
} from '@mapbox/mcp-server/tools';
37+
38+
// Ready to use - no configuration needed
39+
const server = new McpServer({ name: 'my-server', version: '1.0.0' });
40+
directions.installTo(server);
41+
```
42+
43+
### Advanced: Custom HTTP pipeline
44+
45+
```typescript
46+
import { DirectionsTool } from '@mapbox/mcp-server/tools';
47+
import { httpRequest } from '@mapbox/mcp-server/utils';
48+
49+
const tool = new DirectionsTool({ httpRequest });
50+
```
51+
52+
### Expert: Full customization
53+
54+
```typescript
55+
import {
56+
HttpPipeline,
57+
UserAgentPolicy,
58+
RetryPolicy
59+
} from '@mapbox/mcp-server/utils';
60+
import { DirectionsTool } from '@mapbox/mcp-server/tools';
61+
62+
const pipeline = new HttpPipeline();
63+
pipeline.usePolicy(new UserAgentPolicy('MyApp/2.0.0'));
64+
pipeline.usePolicy(new RetryPolicy(5, 300, 5000));
65+
66+
const tool = new DirectionsTool({
67+
httpRequest: pipeline.execute.bind(pipeline)
68+
});
69+
```
70+
71+
## Changes
72+
73+
### New Files
74+
75+
- **Barrel exports** (`src/{tools,resources,prompts,utils}/index.ts`) - Clean public APIs
76+
- **Documentation** (`docs/importing-tools.md`) - Comprehensive usage guide with examples
77+
- **Examples** (`examples/import-example.ts`) - Working code demonstrating all patterns
78+
- **Tests** (`test/exports.test.ts`) - Validates all subpath exports work correctly
79+
- **Config** (`tsconfig.examples.json`) - Type checking for examples
80+
81+
### Updated Files
82+
83+
- `package.json` - Added tshy exports config, updated lint/format scripts to include examples
84+
- `README.md` - Added link to importing guide
85+
- `CLAUDE.md` - Documented package exports
86+
87+
## Benefits Over Wildcard Approach
88+
89+
1.**Explicit API surface** - Only exports what's intended to be public
90+
2.**Better discoverability** - Clear, documented entry points
91+
3.**Type safety** - Full TypeScript support
92+
4.**Tree-shaking friendly** - Bundlers can optimize imports better
93+
5.**Future-proof** - Can evolve internals without breaking users
94+
6.**Clean names** - Instance exports use short names (e.g., `directions` instead of `directionsTool`)
95+
7.**Flexible** - Three levels of usage (simple, advanced, expert)
96+
97+
## Testing
98+
99+
- ✅ All 611 existing tests pass
100+
- ✅ New test suite (`test/exports.test.ts`) validates all subpath exports
101+
- ✅ Examples included in linting, formatting, and type checking
102+
- ✅ Documentation includes working, type-checked examples
103+
- ✅ Both ESM and CommonJS exports verified
104+
105+
## Documentation
106+
107+
Comprehensive documentation added in `docs/importing-tools.md` covering:
108+
109+
- All usage patterns (simple to expert)
110+
- Complete API reference
111+
- Working examples for common scenarios
112+
- Best practices
113+
114+
## Compatibility
115+
116+
- ✅ Backward compatible - doesn't affect existing usage
117+
- ✅ Supports both ESM and CommonJS
118+
- ✅ Works with all bundlers (webpack, rollup, esbuild, vite, etc.)
119+
- ✅ Full TypeScript support with type definitions
120+
121+
## Related
122+
123+
Closes #110 (provides better alternative to wildcard exports)
124+
125+
---
126+
127+
@vincent-lecrubier-skydio This provides what you need from #110 but with a cleaner, more maintainable approach. You can now import just the tools you need:
128+
129+
```typescript
130+
import { getCoreTools } from '@mapbox/mcp-server/tools';
131+
import { httpRequest } from '@mapbox/mcp-server/utils';
132+
```
133+
134+
Let me know if this works for your use case!

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"scripts": {
1313
"build": "npm run prepare && tshy && npm run generate-version && node scripts/add-shebang.cjs",
14+
"changelog:prepare-release": "node scripts/prepare-changelog-release.cjs",
1415
"format": "prettier --check \"./src/**/*.{ts,tsx,js,json,md}\" \"./test/**/*.{ts,tsx,js,json,md}\"",
1516
"format:fix": "prettier --write \"./src/**/*.{ts,tsx,js,json,md}\" \"./test/**/*.{ts,tsx,js,json,md}\"",
1617
"generate-version": "node scripts/build-helpers.cjs generate-version",
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env node
2+
// Copyright (c) Mapbox, Inc.
3+
// Licensed under the MIT License.
4+
5+
/**
6+
* Prepares CHANGELOG.md for a new release by:
7+
* 1. Replacing "## Unreleased" with "## {version}"
8+
* 2. Adding current date to the version heading
9+
* 3. Adding a new empty "## Unreleased" section at the top
10+
*
11+
* Usage:
12+
* node scripts/prepare-changelog-release.cjs <version>
13+
* npm run changelog:prepare-release <version>
14+
*
15+
* Example:
16+
* node scripts/prepare-changelog-release.cjs 1.0.0
17+
*/
18+
19+
const fs = require('node:fs');
20+
const path = require('node:path');
21+
const process = require('node:process');
22+
23+
function prepareChangelogRelease(version) {
24+
if (!version) {
25+
console.error('Error: Version number is required');
26+
console.error('Usage: node scripts/prepare-changelog-release.cjs <version>');
27+
process.exit(1);
28+
}
29+
30+
// Validate version format (basic semver check)
31+
if (!/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/.test(version)) {
32+
console.error(`Error: Invalid version format: ${version}`);
33+
console.error('Expected format: X.Y.Z or X.Y.Z-prerelease');
34+
process.exit(1);
35+
}
36+
37+
const changelogPath = path.join(process.cwd(), 'CHANGELOG.md');
38+
39+
// Check if CHANGELOG.md exists
40+
if (!fs.existsSync(changelogPath)) {
41+
console.error('Error: CHANGELOG.md not found');
42+
process.exit(1);
43+
}
44+
45+
// Read CHANGELOG.md
46+
const content = fs.readFileSync(changelogPath, 'utf8');
47+
48+
// Check if "## Unreleased" exists
49+
if (!content.includes('## Unreleased')) {
50+
console.error('Error: No "## Unreleased" section found in CHANGELOG.md');
51+
console.error('Nothing to release - add changes under "## Unreleased" first');
52+
process.exit(1);
53+
}
54+
55+
// Get current date in YYYY-MM-DD format
56+
const date = new Date().toISOString().split('T')[0];
57+
58+
// Replace "## Unreleased" with "## {version} - {date}"
59+
// and add a new "## Unreleased" section at the top
60+
const updatedContent = content.replace(
61+
'## Unreleased',
62+
`## Unreleased\n\n## ${version} - ${date}`
63+
);
64+
65+
// Write updated content back to CHANGELOG.md
66+
fs.writeFileSync(changelogPath, updatedContent, 'utf8');
67+
68+
console.log(`✓ CHANGELOG.md updated successfully`);
69+
console.log(` - Released version ${version} (${date})`);
70+
console.log(` - Added new "Unreleased" section`);
71+
console.log('');
72+
console.log('Next steps:');
73+
console.log(' 1. Review CHANGELOG.md');
74+
console.log(' 2. Commit changes: git add CHANGELOG.md && git commit -m "Release v' + version + '"');
75+
console.log(' 3. Create tag: git tag v' + version);
76+
console.log(' 4. Push: git push && git push --tags');
77+
}
78+
79+
// Process command line arguments
80+
const version = process.argv[2];
81+
prepareChangelogRelease(version);

tsconfig.examples.tsbuildinfo

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tsconfig.src.tsbuildinfo

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)