Skip to content

Commit ab357b1

Browse files
Really Himclaude
andcommitted
feat: add automated release system
Implement comprehensive release automation to streamline version management and publishing workflow. Changes: - Add release scripts (patch/minor/major) to package.json - Create automated release script (scripts/release.js) that handles: - Version bumping in package.json and src/server.ts - Running tests and builds - Creating git commits and tags - Pushing to GitHub - Creating GitHub releases (when gh CLI available) - Triggering npm publish via GitHub Actions - Add RELEASING.md documentation with complete release guide - Support semantic versioning with single-command releases This eliminates manual steps and potential errors in the release process, ensuring consistent releases every time. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 4b098dc commit ab357b1

File tree

3 files changed

+294
-1
lines changed

3 files changed

+294
-1
lines changed

RELEASING.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Release Process
2+
3+
This project uses automated release scripts to streamline the publishing process.
4+
5+
## 🚀 Quick Release Commands
6+
7+
```bash
8+
# For bug fixes and patches (1.2.3 -> 1.2.4)
9+
npm run release:patch
10+
11+
# For new features (1.2.3 -> 1.3.0)
12+
npm run release:minor
13+
14+
# For breaking changes (1.2.3 -> 2.0.0)
15+
npm run release:major
16+
```
17+
18+
## 📋 What Happens During Release
19+
20+
When you run a release command, the following steps occur automatically:
21+
22+
1. **Version Bump**: Updates version in `package.json` and `src/server.ts`
23+
2. **Tests**: Runs the full test suite to ensure everything works
24+
3. **Build**: Compiles TypeScript and prepares distribution files
25+
4. **Git Commit**: Commits the version changes
26+
5. **Git Tag**: Creates an annotated git tag (e.g., `v1.2.3`)
27+
6. **Push**: Pushes commits and tags to GitHub
28+
7. **GitHub Release**: Creates a GitHub release (if `gh` CLI is installed)
29+
8. **NPM Publish**: GitHub Actions automatically publishes to npm
30+
31+
## 🔧 Prerequisites
32+
33+
### Required Setup
34+
35+
1. **NPM Token in GitHub Secrets**
36+
- Go to npmjs.com → Account Settings → Access Tokens
37+
- Create an "Automation" token
38+
- Add to GitHub: Settings → Secrets → Actions → `NPM_TOKEN`
39+
40+
2. **GitHub CLI (Optional but Recommended)**
41+
```bash
42+
# macOS
43+
brew install gh
44+
45+
# Or download from: https://cli.github.com/
46+
```
47+
48+
3. **Clean Working Directory**
49+
- Commit or stash all changes before releasing
50+
- The release script will check this automatically
51+
52+
## 📝 Manual Release Process
53+
54+
If you prefer to release manually:
55+
56+
```bash
57+
# 1. Update version in package.json
58+
npm version patch # or minor/major
59+
60+
# 2. Update src/server.ts version to match
61+
62+
# 3. Run tests
63+
npm test
64+
65+
# 4. Commit changes
66+
git add -A
67+
git commit -m "chore: release v1.2.3"
68+
69+
# 5. Create and push tag
70+
git tag -a v1.2.3 -m "Release v1.2.3"
71+
git push origin main
72+
git push origin v1.2.3
73+
74+
# 6. Create GitHub release
75+
# Go to: https://github.com/hesreallyhim/diy-tools-mcp/releases/new
76+
# Select the tag and publish
77+
```
78+
79+
## 🎯 Semantic Versioning Guide
80+
81+
- **Patch** (`1.2.3``1.2.4`): Bug fixes, typos, small improvements
82+
- **Minor** (`1.2.3``1.3.0`): New features, backwards compatible
83+
- **Major** (`1.2.3``2.0.0`): Breaking changes, API changes
84+
85+
## 🔍 Troubleshooting
86+
87+
### NPM Publish Fails in GitHub Actions
88+
89+
- Check that `NPM_TOKEN` secret is set correctly
90+
- Ensure the version doesn't already exist on npm
91+
- View action logs at: https://github.com/hesreallyhim/diy-tools-mcp/actions
92+
93+
### Release Script Fails
94+
95+
- Ensure you have a clean git working directory
96+
- Check that you're on the main branch
97+
- Verify you have push permissions to GitHub
98+
99+
### Version Mismatch
100+
101+
The release script automatically keeps `package.json` and `src/server.ts` in sync.
102+
103+
## 📊 Monitoring Releases
104+
105+
- **NPM Package**: https://www.npmjs.com/package/diy-tools-mcp
106+
- **GitHub Releases**: https://github.com/hesreallyhim/diy-tools-mcp/releases
107+
- **GitHub Actions**: https://github.com/hesreallyhim/diy-tools-mcp/actions
108+
109+
## 🔄 Rollback Process
110+
111+
If you need to rollback a release:
112+
113+
1. **Unpublish from npm** (within 72 hours):
114+
```bash
115+
npm unpublish diy-tools-mcp@1.2.3
116+
```
117+
118+
2. **Delete git tag**:
119+
```bash
120+
git tag -d v1.2.3
121+
git push origin --delete v1.2.3
122+
```
123+
124+
3. **Delete GitHub release**: Via GitHub UI
125+
126+
⚠️ **Note**: Once a version is published to npm for >72 hours, it cannot be unpublished.

package.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,14 @@
3131
"format": "prettier --write 'src/**/*.ts' 'demo.ts'",
3232
"format:check": "prettier --check 'src/**/*.ts' 'demo.ts'",
3333
"prepublishOnly": "npm run clean && npm run build && npm test",
34-
"prepare": "husky"
34+
"prepare": "husky",
35+
"version:patch": "npm version patch --no-git-tag-version",
36+
"version:minor": "npm version minor --no-git-tag-version",
37+
"version:major": "npm version major --no-git-tag-version",
38+
"release:patch": "npm run version:patch && npm run release:do",
39+
"release:minor": "npm run version:minor && npm run release:do",
40+
"release:major": "npm run version:major && npm run release:do",
41+
"release:do": "node scripts/release.js"
3542
},
3643
"repository": {
3744
"type": "git",

scripts/release.js

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
#!/usr/bin/env node
2+
3+
import { execSync } from 'child_process';
4+
import { readFileSync, writeFileSync } from 'fs';
5+
import { join, dirname } from 'path';
6+
import { fileURLToPath } from 'url';
7+
8+
const __dirname = dirname(fileURLToPath(import.meta.url));
9+
const rootDir = join(__dirname, '..');
10+
11+
// Colors for console output
12+
const colors = {
13+
reset: '\x1b[0m',
14+
bright: '\x1b[1m',
15+
green: '\x1b[32m',
16+
yellow: '\x1b[33m',
17+
blue: '\x1b[34m',
18+
red: '\x1b[31m',
19+
};
20+
21+
function log(message, color = 'reset') {
22+
console.log(`${colors[color]}${message}${colors.reset}`);
23+
}
24+
25+
function exec(command, options = {}) {
26+
try {
27+
return execSync(command, { encoding: 'utf-8', cwd: rootDir, ...options });
28+
} catch (error) {
29+
log(`Error executing: ${command}`, 'red');
30+
log(error.message, 'red');
31+
process.exit(1);
32+
}
33+
}
34+
35+
function getPackageVersion() {
36+
const packageJson = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf-8'));
37+
return packageJson.version;
38+
}
39+
40+
function updateServerVersion(version) {
41+
const serverPath = join(rootDir, 'src', 'server.ts');
42+
let serverContent = readFileSync(serverPath, 'utf-8');
43+
serverContent = serverContent.replace(/version:\s*['"][\d.]+['"]/, `version: '${version}'`);
44+
writeFileSync(serverPath, serverContent);
45+
}
46+
47+
async function main() {
48+
log('\n🚀 Starting automated release process...', 'bright');
49+
50+
// 1. Check git status
51+
log('\n📋 Checking git status...', 'blue');
52+
const gitStatus = exec('git status --porcelain');
53+
const uncommittedFiles = gitStatus
54+
.split('\n')
55+
.filter(
56+
(line) => line.trim() && !line.includes('package.json') && !line.includes('src/server.ts')
57+
);
58+
59+
if (uncommittedFiles.length > 0) {
60+
log('Error: You have uncommitted changes:', 'red');
61+
console.log(uncommittedFiles.join('\n'));
62+
log('\nPlease commit or stash your changes before releasing.', 'yellow');
63+
process.exit(1);
64+
}
65+
66+
// 2. Get current version
67+
const version = getPackageVersion();
68+
log(`\n📦 Preparing to release version: ${version}`, 'green');
69+
70+
// 3. Update server.ts version
71+
log('\n🔧 Updating server.ts version...', 'blue');
72+
updateServerVersion(version);
73+
74+
// 4. Run tests
75+
log('\n🧪 Running tests...', 'blue');
76+
exec('npm test', { stdio: 'inherit' });
77+
78+
// 5. Build the project
79+
log('\n🔨 Building project...', 'blue');
80+
exec('npm run build');
81+
82+
// 6. Commit version changes
83+
log('\n💾 Committing version changes...', 'blue');
84+
exec('git add package.json package-lock.json src/server.ts');
85+
86+
const commitMessage = `chore: release v${version}
87+
88+
🤖 Generated with [Claude Code](https://claude.ai/code)
89+
90+
Co-Authored-By: Claude <noreply@anthropic.com>`;
91+
92+
exec(`git commit -m "${commitMessage}"`);
93+
94+
// 7. Create git tag
95+
log('\n🏷️ Creating git tag...', 'blue');
96+
const tagMessage = `Release v${version}
97+
98+
Published to npm registry`;
99+
exec(`git tag -a v${version} -m "${tagMessage}"`);
100+
101+
// 8. Push to GitHub
102+
log('\n📤 Pushing to GitHub...', 'blue');
103+
exec('git push origin main');
104+
exec(`git push origin v${version}`);
105+
106+
// 9. Create GitHub release
107+
log('\n📝 Creating GitHub release...', 'blue');
108+
try {
109+
// Check if gh CLI is installed
110+
exec('gh --version', { stdio: 'pipe' });
111+
112+
const releaseNotes = `## Release v${version}
113+
114+
### 📦 Installation
115+
\`\`\`bash
116+
npm install -g diy-tools-mcp@${version}
117+
\`\`\`
118+
119+
### 🚀 What's Changed
120+
- See commit history for details
121+
122+
### 📝 Full Changelog
123+
https://github.com/hesreallyhim/diy-tools-mcp/compare/v${getPreviousVersion()}...v${version}`;
124+
125+
exec(`gh release create v${version} --title "v${version}" --notes "${releaseNotes}"`);
126+
log('✅ GitHub release created!', 'green');
127+
} catch (error) {
128+
log('⚠️ GitHub CLI not found. Please create release manually at:', 'yellow');
129+
log(`https://github.com/hesreallyhim/diy-tools-mcp/releases/new?tag=v${version}`, 'blue');
130+
}
131+
132+
// Success message
133+
log('\n✨ Release process complete!', 'green');
134+
log(`\n📊 Version ${version} has been:`, 'bright');
135+
log(' ✅ Committed to git', 'green');
136+
log(' ✅ Tagged in git', 'green');
137+
log(' ✅ Pushed to GitHub', 'green');
138+
log(' ✅ Will be published to npm via GitHub Actions', 'green');
139+
140+
log('\n📈 Monitor the publish action at:', 'blue');
141+
log('https://github.com/hesreallyhim/diy-tools-mcp/actions', 'blue');
142+
}
143+
144+
function getPreviousVersion() {
145+
try {
146+
const tags = exec('git tag -l --sort=-version:refname')
147+
.split('\n')
148+
.filter((t) => t.startsWith('v'));
149+
return tags[1] || 'v1.0.0';
150+
} catch {
151+
return 'v1.0.0';
152+
}
153+
}
154+
155+
// Run the release
156+
main().catch((error) => {
157+
log('\n❌ Release failed:', 'red');
158+
console.error(error);
159+
process.exit(1);
160+
});

0 commit comments

Comments
 (0)