diff --git a/.gitignore b/.gitignore index d23b8bd..c9ad93e 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,6 @@ dist/ # Test results test-results.xml + +# Build artifacts +*.tsbuildinfo diff --git a/CHANGELOG.md b/CHANGELOG.md index ad3afea..8d8d818 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,20 @@ +## Unreleased + +### Documentation + +- **PR Guidelines**: Added CHANGELOG requirement to CLAUDE.md (#67) + - All pull requests must now update CHANGELOG.md + - Document what changed, why, and any breaking changes + - Add entry under "Unreleased" section with PR number + +### Developer Experience + +- **Release Process**: Added automated CHANGELOG preparation script (#67) + - New `npm run changelog:prepare-release ` command + - Automatically replaces "Unreleased" with version and date + - Adds new empty "Unreleased" section for next changes + - Includes validation for version format and CHANGELOG structure + ## 0.4.7 ### Security diff --git a/CLAUDE.md b/CLAUDE.md index d8c4ae9..8ea694e 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -77,6 +77,36 @@ Generates three files: `*.input.schema.ts`, `*.output.schema.ts`, and `*.test.ts - Never update snapshots without verifying changes - Tool snapshots capture class names, tool names, and descriptions +**Pull Requests:** + +When creating pull requests: + +- **Always update CHANGELOG.md** - Document what changed, why, and any breaking changes +- Follow the existing changelog format (check recent entries for examples) +- Add your entry under the "Unreleased" section at the top +- Include the PR number and a brief description of the change + +**Release Process:** + +When preparing a new release: + +```bash +# Prepare CHANGELOG for release (replaces "Unreleased" with version and date) +npm run changelog:prepare-release 1.0.0 + +# Review changes, then commit and tag +git add CHANGELOG.md +git commit -m "Release v1.0.0" +git tag v1.0.0 +git push && git push --tags +``` + +The `changelog:prepare-release` script automatically: + +- Replaces "## Unreleased" with "## {version} - {date}" +- Adds a new empty "## Unreleased" section at the top +- Validates version format and CHANGELOG structure + ## Important Constraints - **Tool naming:** Tool names (MCP identifiers) must be `snake_case_tool` (e.g., `list_styles_tool`). TypeScript class names follow `PascalCaseTool` convention (e.g., `ListStylesTool`) diff --git a/package.json b/package.json index 9db4559..24a69dd 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "scripts": { "postinstall": "patch-package || true", "build": "npm run prepare && tshy && npm run generate-version && node scripts/add-shebang.cjs", + "changelog:prepare-release": "node scripts/prepare-changelog-release.cjs", "format": "prettier --check \"./src/**/*.{ts,tsx,js,json,md}\" \"./test/**/*.{ts,tsx,js,json,md}\"", "format:fix": "prettier --write \"./src/**/*.{ts,tsx,js,json,md}\" \"./test/**/*.{ts,tsx,js,json,md}\"", "generate-version": "node scripts/build-helpers.cjs generate-version", diff --git a/scripts/prepare-changelog-release.cjs b/scripts/prepare-changelog-release.cjs new file mode 100755 index 0000000..595254a --- /dev/null +++ b/scripts/prepare-changelog-release.cjs @@ -0,0 +1,81 @@ +#!/usr/bin/env node +// Copyright (c) Mapbox, Inc. +// Licensed under the MIT License. + +/** + * Prepares CHANGELOG.md for a new release by: + * 1. Replacing "## Unreleased" with "## {version}" + * 2. Adding current date to the version heading + * 3. Adding a new empty "## Unreleased" section at the top + * + * Usage: + * node scripts/prepare-changelog-release.cjs + * npm run changelog:prepare-release + * + * Example: + * node scripts/prepare-changelog-release.cjs 1.0.0 + */ + +const fs = require('node:fs'); +const path = require('node:path'); +const process = require('node:process'); + +function prepareChangelogRelease(version) { + if (!version) { + console.error('Error: Version number is required'); + console.error('Usage: node scripts/prepare-changelog-release.cjs '); + process.exit(1); + } + + // Validate version format (basic semver check) + if (!/^\d+\.\d+\.\d+(-[a-zA-Z0-9.-]+)?$/.test(version)) { + console.error(`Error: Invalid version format: ${version}`); + console.error('Expected format: X.Y.Z or X.Y.Z-prerelease'); + process.exit(1); + } + + const changelogPath = path.join(process.cwd(), 'CHANGELOG.md'); + + // Check if CHANGELOG.md exists + if (!fs.existsSync(changelogPath)) { + console.error('Error: CHANGELOG.md not found'); + process.exit(1); + } + + // Read CHANGELOG.md + const content = fs.readFileSync(changelogPath, 'utf8'); + + // Check if "## Unreleased" exists + if (!content.includes('## Unreleased')) { + console.error('Error: No "## Unreleased" section found in CHANGELOG.md'); + console.error('Nothing to release - add changes under "## Unreleased" first'); + process.exit(1); + } + + // Get current date in YYYY-MM-DD format + const date = new Date().toISOString().split('T')[0]; + + // Replace "## Unreleased" with "## {version} - {date}" + // and add a new "## Unreleased" section at the top + const updatedContent = content.replace( + '## Unreleased', + `## Unreleased\n\n## ${version} - ${date}` + ); + + // Write updated content back to CHANGELOG.md + fs.writeFileSync(changelogPath, updatedContent, 'utf8'); + + console.log(`✓ CHANGELOG.md updated successfully`); + console.log(` - Released version ${version} (${date})`); + console.log(` - Added new "Unreleased" section`); + console.log(''); + console.log('Next steps:'); + console.log(' 1. Review CHANGELOG.md'); + console.log(' 2. Commit changes: git add CHANGELOG.md && git commit -m "Release v' + version + '"'); + console.log(' 3. Create tag: git tag v' + version); + console.log(' 4. Push: git push && git push --tags'); +} + +// Process command line arguments +const version = process.argv[2]; +prepareChangelogRelease(version);