@chimp-stack/release-chimp
Advanced tools
+164
-46
@@ -49,9 +49,15 @@ #!/usr/bin/env node | ||
| const tag = options?.tagFormat && name ? applyTagFormat(options.tagFormat, name, version2) : `v${version2}`; | ||
| execSync("git add CHANGELOG.md", { stdio: "inherit" }); | ||
| execSync(`git commit -m "chore(release): ${version2}"`, { | ||
| const changelogFile = options?.changelogPath ?? "CHANGELOG.md"; | ||
| if (fs.existsSync(path.join(cwd, changelogFile))) { | ||
| execSync(`git add ${changelogFile}`, { stdio: "inherit" }); | ||
| } | ||
| const message = options?.commitMessage ?? `chore(release): ${version2}`; | ||
| execSync(`git commit -m "${message}"`, { | ||
| stdio: "inherit" | ||
| }); | ||
| execSync(`git tag ${tag}`, { stdio: "inherit" }); | ||
| execSync("git push", { stdio: "inherit" }); | ||
| execSync("git push --tags", { stdio: "inherit" }); | ||
| if (!options?.skipPush) { | ||
| execSync("git push", { stdio: "inherit" }); | ||
| execSync("git push --tags", { stdio: "inherit" }); | ||
| } | ||
| } catch (err) { | ||
@@ -65,2 +71,3 @@ console.error("\u274C Git operation failed. Releasing is canceled."); | ||
| import { | ||
| applyTagFormat as applyTagFormat2, | ||
| detectCurrentVersion, | ||
@@ -70,22 +77,86 @@ extractVersionFromTag | ||
| import { | ||
| loadChimpConfig as loadChimpConfig2 | ||
| } from "@chimp-stack/core"; | ||
| // src/utils/detectRecommendedBump.ts | ||
| import { | ||
| getSemanticCommits, | ||
| loadChimpConfig | ||
| } from "@chimp-stack/core"; | ||
| async function handleBump(cliPart, cliOptions) { | ||
| async function detectRecommendedBump() { | ||
| const config = loadChimpConfig( | ||
| "releaseChimp" | ||
| ); | ||
| const scoped = config.bump?.scoped ?? false; | ||
| const commits = await getSemanticCommits({ | ||
| scoped, | ||
| configDir: process.cwd() | ||
| }); | ||
| let hasBreaking = false; | ||
| let hasFeature = false; | ||
| let hasFix = false; | ||
| for (const c of commits) { | ||
| if (c.isBreaking) { | ||
| hasBreaking = true; | ||
| } | ||
| if (c.type === "feat") { | ||
| hasFeature = true; | ||
| } | ||
| if (c.type === "fix") { | ||
| hasFix = true; | ||
| } | ||
| } | ||
| if (hasBreaking) { | ||
| return "major"; | ||
| } | ||
| if (hasFeature) { | ||
| return "minor"; | ||
| } | ||
| if (hasFix) { | ||
| return "patch"; | ||
| } | ||
| console.warn("\u26A0\uFE0F No semantic commits found for bump detection."); | ||
| return null; | ||
| } | ||
| // src/commands/bump.ts | ||
| async function handleBump(cliPart, cliOptions) { | ||
| if (cliOptions.cwd) { | ||
| try { | ||
| process.chdir(cliOptions.cwd); | ||
| console.log( | ||
| `\u{1F9ED} Changed working directory to ${cliOptions.cwd}` | ||
| ); | ||
| } catch (err) { | ||
| console.error( | ||
| `\u274C Failed to change directory: ${cliOptions.cwd}`, | ||
| err | ||
| ); | ||
| process.exit(1); | ||
| } | ||
| } | ||
| const config = loadChimpConfig2( | ||
| "releaseChimp" | ||
| ); | ||
| const dryRun = cliOptions.dryRun ?? config.dryRun ?? false; | ||
| const part = cliPart || config.bumpType || "patch"; | ||
| const inferVersionOnly = cliPart === void 0 && !dryRun; | ||
| const isCI = cliOptions.ci ?? false; | ||
| if (isCI) { | ||
| console.log( | ||
| "\u{1F916} CI mode enabled: Skipping package.json, changelog, and git." | ||
| ); | ||
| let part = cliPart || config.bumpType || null; | ||
| let inferredFromCommits = false; | ||
| if (!part) { | ||
| part = await detectRecommendedBump(); | ||
| if (part) { | ||
| console.log(`\u{1F4E6} Bump type auto-detected as: ${part}`); | ||
| inferredFromCommits = true; | ||
| } else { | ||
| if (isCI) { | ||
| console.log( | ||
| "\u26A0\uFE0F No semantic commits found. CI mode: skipping bump." | ||
| ); | ||
| process.exit(0); | ||
| } else { | ||
| console.log("\u{1F4E6} Falling back to patch version bump"); | ||
| part = "patch"; | ||
| } | ||
| } | ||
| } | ||
| const noPackageJson = cliOptions.noPackageJson ?? config.noPackageJson ?? false; | ||
| const noChangelog = isCI || (cliOptions.noChangelog ?? config.noChangelog ?? false); | ||
| const noGit = isCI || (cliOptions.noGit ?? config.noGit ?? false); | ||
| const useAI = cliOptions.ai ?? config.changelog?.useAI ?? false; | ||
| const outputFormat = cliOptions.output ?? "text"; | ||
| const validParts = ["major", "minor", "patch"]; | ||
@@ -98,2 +169,13 @@ if (!validParts.includes(part)) { | ||
| } | ||
| const inferVersionOnly = cliPart === void 0 && !dryRun; | ||
| if (isCI) { | ||
| console.log( | ||
| "\u{1F916} CI mode enabled. Commit messages will include [skip ci]. Use --no-xyz flags to control what gets skipped." | ||
| ); | ||
| } | ||
| const noPackageJson = cliOptions.noPackageJson ?? config.noPackageJson ?? false; | ||
| const noChangelog = cliOptions.noChangelog ?? config.noChangelog ?? false; | ||
| const noGit = cliOptions.noGit ?? config.noGit ?? false; | ||
| const useAI = cliOptions.ai ?? config.changelog?.useAI ?? false; | ||
| const outputFormat = cliOptions.output ?? "text"; | ||
| const { version: current, isGitRef } = await detectCurrentVersion({ | ||
@@ -106,21 +188,54 @@ tagFormat: config.tagFormat | ||
| console.log(`\u{1F34C} Next version: ${next}`); | ||
| console.log("\u{1F4E6} Bump type: %s", part); | ||
| if (inferredFromCommits) { | ||
| console.log("\u{1F50D} Bump type auto-detected from commit history"); | ||
| } | ||
| if (next === rawVersion) { | ||
| console.log( | ||
| `\u26A0\uFE0F Version '${next}' is already published or no bump needed. Exiting.` | ||
| ); | ||
| process.exit(0); | ||
| } | ||
| if (inferVersionOnly) { | ||
| console.log(`\u{1F504} Inferring version from latest tag`); | ||
| console.log( | ||
| `\u{1F504} No bump type specified. Inferring version from latest tag.` | ||
| ); | ||
| } | ||
| const pkgPath = path2.resolve(process.cwd(), "package.json"); | ||
| const hasPkg = fs2.existsSync(pkgPath); | ||
| const pkg = hasPkg ? JSON.parse(fs2.readFileSync(pkgPath, "utf-8")) : {}; | ||
| const name = pkg.name; | ||
| const tag = config?.tagFormat && name ? applyTagFormat2(config.tagFormat, name, next) : `v${next}`; | ||
| const includeNameInCommit = config.includeNameInCommit ?? true; | ||
| const commitMessage = isCI ? `chore(release): ${includeNameInCommit && name ? `${name} ` : ""}${next} [skip ci]` : `chore(release): ${includeNameInCommit && name ? `${name} ` : ""}${next}`; | ||
| const changelog = noChangelog ? "_Changelog generation skipped._" : await generateSemanticChangelog({ | ||
| from: isGitRef ? current : void 0, | ||
| to: "HEAD", | ||
| toolName: "releaseChimp", | ||
| useAI | ||
| }); | ||
| if (dryRun) { | ||
| const changelog = noChangelog ? "_Changelog generation skipped (dry run)._" : await generateSemanticChangelog({ | ||
| from: isGitRef ? current : void 0, | ||
| to: "HEAD", | ||
| toolName: "releaseChimp", | ||
| useAI | ||
| }); | ||
| console.log("\n\u{1F50D} [Dry Run] Preview:\n"); | ||
| if (!noPackageJson) { | ||
| if (!noPackageJson) | ||
| console.log(`\u{1F4E6} Would update package.json version to ${next}`); | ||
| else console.log("\u{1F4E6} Skipping package.json update"); | ||
| if (!noChangelog) { | ||
| console.log( | ||
| `\u{1F4DD} Would write changelog to ${config.changelog?.path ?? "CHANGELOG.md"}` | ||
| ); | ||
| console.log("\u{1F4DD} Changelog preview:"); | ||
| console.log(changelog); | ||
| } else { | ||
| console.log("\u{1F4E6} Skipping package.json update"); | ||
| console.log("\u{1F4DD} Skipping changelog update"); | ||
| } | ||
| console.log(changelog); | ||
| if (!noGit) { | ||
| console.log(`\u{1F527} Would commit, tag, and push version ${next}`); | ||
| console.log(`\u{1F527} Would stage:`); | ||
| if (!noPackageJson) console.log(" - package.json"); | ||
| if (!noChangelog) | ||
| console.log( | ||
| ` - ${config.changelog?.path ?? "CHANGELOG.md"}` | ||
| ); | ||
| console.log(`\u{1F527} Would commit with message: "${commitMessage}"`); | ||
| console.log(`\u{1F3F7}\uFE0F Would tag: ${tag}`); | ||
| console.log("\u{1F680} Would push to remote"); | ||
| } else { | ||
@@ -135,7 +250,3 @@ console.log("\u{1F527} Skipping git commit/tag/push"); | ||
| if (!noPackageJson) { | ||
| const packageJsonPath = path2.resolve( | ||
| process.cwd(), | ||
| "package.json" | ||
| ); | ||
| if (!fs2.existsSync(packageJsonPath)) { | ||
| if (!hasPkg) { | ||
| console.warn( | ||
@@ -145,8 +256,5 @@ "\u26A0\uFE0F package.json not found, skipping version update." | ||
| } else { | ||
| const pkg = JSON.parse( | ||
| fs2.readFileSync(packageJsonPath, "utf-8") | ||
| ); | ||
| pkg.version = next; | ||
| fs2.writeFileSync( | ||
| packageJsonPath, | ||
| pkgPath, | ||
| JSON.stringify(pkg, null, 2) + "\n", | ||
@@ -161,13 +269,7 @@ "utf-8" | ||
| if (!noChangelog) { | ||
| const changelog = await generateSemanticChangelog({ | ||
| from: isGitRef ? current : void 0, | ||
| to: "HEAD", | ||
| toolName: "releaseChimp", | ||
| useAI | ||
| }); | ||
| try { | ||
| writeChangelogToFile(changelog); | ||
| writeChangelogToFile(changelog, config.changelog?.path); | ||
| console.log("\u{1F4DD} Changelog updated"); | ||
| } catch (error) { | ||
| console.error(`\u274C Failed to write changelog`); | ||
| } catch { | ||
| console.error("\u274C Failed to write changelog"); | ||
| process.exit(1); | ||
@@ -179,3 +281,7 @@ } | ||
| if (!noGit) { | ||
| gitCommitTagPush(next, { tagFormat: config.tagFormat }); | ||
| gitCommitTagPush(next, { | ||
| tagFormat: config.tagFormat, | ||
| commitMessage, | ||
| changelogPath: config.changelog?.path ?? "CHANGELOG.md" | ||
| }); | ||
| console.log(`\u{1F680} Released version ${next} and pushed to remote.`); | ||
@@ -192,2 +298,8 @@ } else { | ||
| // src/commands/detect-bump.ts | ||
| async function handleDetectBump() { | ||
| const type = await detectRecommendedBump(); | ||
| console.log(type); | ||
| } | ||
| // src/commands/index.ts | ||
@@ -210,3 +322,9 @@ var version = "0.1.0"; | ||
| "text" | ||
| ).option( | ||
| "--cwd <path>", | ||
| "Change working directory before running command" | ||
| ).action(handleBump); | ||
| program.command("detect-bump").description( | ||
| "Detect recommended bump type (major, minor, patch) based on commit history" | ||
| ).action(handleDetectBump); | ||
| program.parse(process.argv); | ||
@@ -213,0 +331,0 @@ } |
+2
-2
| { | ||
| "name": "@chimp-stack/release-chimp", | ||
| "version": "0.2.0", | ||
| "version": "0.3.0", | ||
| "type": "module", | ||
@@ -36,2 +36,3 @@ "bin": { | ||
| "globby": "^14.1.0", | ||
| "parse-commit-message": "^5.0.4", | ||
| "simple-git": "^3.27.0", | ||
@@ -43,3 +44,2 @@ "ts-node": "^10.9.2", | ||
| "@types/jest": "^29.5.14", | ||
| "conventional-changelog-conventionalcommits": "^9.0.0", | ||
| "jest": "^29.7.0", | ||
@@ -46,0 +46,0 @@ "ts-jest": "^29.4.0", |
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
17663
25.59%4
-20%313
58.08%11
10%+ Added
+ Added
+ Added
+ Added
+ Added