@programinglive/commiter 1.0.11 โ†’ 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/SECURITY.md CHANGED
@@ -1,30 +1,30 @@
1
- # Security Policy
2
-
3
- ## Reporting a Vulnerability
4
-
5
- If you discover a security vulnerability in `@programinglive/commiter`, please report it responsibly.
6
-
7
- Send your report to: [security@programinglive.com](mailto:security@programinglive.com).
8
-
9
- Please include:
10
- - A detailed description of the vulnerability
11
- - Steps to reproduce the issue
12
- - Any potential impact
13
- - Optional: Suggested mitigation or patch
14
-
15
- We aim to respond within **48 hours** and will keep you informed of our progress.
16
-
17
- ## Supported Versions
18
-
19
- We support the latest released version of the package. Please ensure you are running the most recent version before reporting issues.
20
-
21
- ## Disclosure Policy
22
-
23
- We follow a coordinated disclosure process:
24
- 1. Acknowledge receipt of your report within 48 hours
25
- 2. Assess the vulnerability and determine severity
26
- 3. Fix the issue and prepare a release
27
- 4. Credit the reporter (if desired)
28
- 5. Publish a security advisory detailing the fix
29
-
30
- Thank you for helping keep our project secure!
1
+ # Security Policy
2
+
3
+ ## Reporting a Vulnerability
4
+
5
+ If you discover a security vulnerability in `@programinglive/commiter`, please report it responsibly.
6
+
7
+ Send your report to: [security@programinglive.com](mailto:security@programinglive.com).
8
+
9
+ Please include:
10
+ - A detailed description of the vulnerability
11
+ - Steps to reproduce the issue
12
+ - Any potential impact
13
+ - Optional: Suggested mitigation or patch
14
+
15
+ We aim to respond within **48 hours** and will keep you informed of our progress.
16
+
17
+ ## Supported Versions
18
+
19
+ We support the latest released version of the package. Please ensure you are running the most recent version before reporting issues.
20
+
21
+ ## Disclosure Policy
22
+
23
+ We follow a coordinated disclosure process:
24
+ 1. Acknowledge receipt of your report within 48 hours
25
+ 2. Assess the vulnerability and determine severity
26
+ 3. Fix the issue and prepare a release
27
+ 4. Credit the reporter (if desired)
28
+ 5. Publish a security advisory detailing the fix
29
+
30
+ Thank you for helping keep our project secure!
@@ -1,4 +1,4 @@
1
- module.exports = {
2
- extends: ['@commitlint/config-conventional'],
3
- ignores: [(message) => message.startsWith('chore(release):')]
4
- };
1
+ module.exports = {
2
+ extends: ['@commitlint/config-conventional'],
3
+ ignores: [(message) => message.startsWith('chore(release):')]
4
+ };
package/index.js CHANGED
@@ -1,148 +1,148 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Commiter - Commit convention tooling for standard-version releases
5
- *
6
- * This package helps enforce conventional commits and automate releases
7
- * with beautiful changelogs featuring icons for each commit type.
8
- */
9
-
10
- const { execSync } = require('child_process');
11
- const fs = require('fs');
12
- const path = require('path');
13
-
14
- function ensureSafeTestScript(scripts = {}) {
15
- const defaultFailingTestScript = 'echo "Error: no test specified" && exit 1';
16
- if (!scripts.test || scripts.test === defaultFailingTestScript) {
17
- scripts.test = 'echo "No tests specified"';
18
- }
19
- return scripts;
20
- }
21
-
22
- function setupCommiter() {
23
- console.log('๐Ÿš€ Setting up Commiter...\n');
24
-
25
- // Check if package.json exists
26
- if (!fs.existsSync('package.json')) {
27
- console.error('โŒ Error: package.json not found. Please run this in a Node.js project directory.');
28
- process.exit(1);
29
- }
30
-
31
- try {
32
- // Install dependencies
33
- console.log('๐Ÿ“ฆ Installing dependencies...');
34
- execSync('npm install --save-dev standard-version @commitlint/cli @commitlint/config-conventional husky', {
35
- stdio: 'inherit'
36
- });
37
-
38
- // Read package.json
39
- const packageJsonPath = path.join(process.cwd(), 'package.json');
40
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
41
-
42
- packageJson.scripts = ensureSafeTestScript(packageJson.scripts || {});
43
- // Add scripts
44
- packageJson.scripts.prepare = 'husky';
45
- packageJson.scripts.release = 'node scripts/release.js';
46
- packageJson.scripts['release:major'] = 'node scripts/release.js major';
47
- packageJson.scripts['release:minor'] = 'node scripts/release.js minor';
48
- packageJson.scripts['release:patch'] = 'node scripts/release.js patch';
49
-
50
- // Add standard-version config
51
- packageJson['standard-version'] = {
52
- releaseCommitMessageFormat: 'chore(release): {{currentTag}} ๐Ÿš€',
53
- types: [
54
- { type: 'feat', section: 'โœจ Features' },
55
- { type: 'fix', section: '๐Ÿ› Bug Fixes' },
56
- { type: 'perf', section: 'โšก Performance' },
57
- { type: 'refactor', section: 'โ™ป๏ธ Refactors' },
58
- { type: 'docs', section: '๐Ÿ“ Documentation' },
59
- { type: 'style', section: '๐Ÿ’„ Styles' },
60
- { type: 'test', section: 'โœ… Tests' },
61
- { type: 'build', section: '๐Ÿ—๏ธ Build System' },
62
- { type: 'ci', section: '๐Ÿ‘ท Continuous Integration' },
63
- { type: 'chore', section: '๐Ÿงน Chores' },
64
- { type: 'revert', section: 'โช Reverts' }
65
- ]
66
- };
67
-
68
- // Write updated package.json
69
- fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
70
-
71
- // Create release helper script
72
- console.log('๐Ÿ› ๏ธ Creating release helper script...');
73
- const releaseScriptDir = path.join(process.cwd(), 'scripts');
74
- if (!fs.existsSync(releaseScriptDir)) {
75
- fs.mkdirSync(releaseScriptDir, { recursive: true });
76
- }
77
-
78
- const releaseScriptPath = path.join(releaseScriptDir, 'release.js');
79
- const releaseScriptSource = path.join(__dirname, 'scripts', 'release.js');
80
- const releaseScriptContent = fs.readFileSync(releaseScriptSource, 'utf8');
81
-
82
- fs.writeFileSync(releaseScriptPath, releaseScriptContent + '\n');
83
- try {
84
- fs.chmodSync(releaseScriptPath, 0o755);
85
- } catch (error) {
86
- // Ignore chmod errors on non-POSIX systems
87
- }
88
-
89
- // Determine commitlint config format based on project module type
90
- const isEsmProject = packageJson.type === 'module';
91
- const commitlintConfigFile = isEsmProject ? 'commitlint.config.js' : 'commitlint.config.cjs';
92
- const commitlintConfigContent = isEsmProject
93
- ? `export default {
94
- extends: ['@commitlint/config-conventional'],
95
- ignores: [(message) => message.startsWith('chore(release):')]
96
- }\n`
97
- : `module.exports = {
98
- extends: ['@commitlint/config-conventional'],
99
- ignores: [(message) => message.startsWith('chore(release):')]
100
- }\n`;
101
-
102
- const legacyCommitlintConfigFile = isEsmProject ? 'commitlint.config.cjs' : 'commitlint.config.js';
103
- if (fs.existsSync(legacyCommitlintConfigFile)) {
104
- fs.rmSync(legacyCommitlintConfigFile);
105
- }
106
-
107
- console.log(`โš™๏ธ Creating commitlint config (${commitlintConfigFile})...`);
108
- fs.writeFileSync(commitlintConfigFile, commitlintConfigContent);
109
-
110
- // Initialize Husky
111
- console.log('๐Ÿถ Setting up Husky...');
112
- execSync('npx husky init', { stdio: 'inherit' });
113
-
114
- // Create commit-msg hook
115
- const huskyDir = path.join(process.cwd(), '.husky');
116
- if (!fs.existsSync(huskyDir)) {
117
- fs.mkdirSync(huskyDir, { recursive: true });
118
- }
119
-
120
- const commitMsgHook = `#!/usr/bin/env sh
121
-
122
- npx --no -- commitlint --edit "$1"
123
- `;
124
- fs.writeFileSync(path.join(huskyDir, 'commit-msg'), commitMsgHook);
125
- fs.chmodSync(path.join(huskyDir, 'commit-msg'), 0o755);
126
-
127
- console.log('\nโœ… Commiter setup complete!\n');
128
- console.log('๐Ÿ“š Available commands:');
129
- console.log(' npm run release major - Create a major release (1.0.0 โ†’ 2.0.0)');
130
- console.log(' npm run release minor - Create a minor release (1.0.0 โ†’ 1.1.0)');
131
- console.log(' npm run release patch - Create a patch release (1.0.0 โ†’ 1.0.1)');
132
- console.log(' npm run release - Auto-detect version bump');
133
- console.log(' npm run release -- --prerelease beta - Create a beta prerelease\n');
134
- console.log('๐ŸŽฏ Commit format: type(scope): subject');
135
- console.log(' Example: feat(auth): add user login\n');
136
-
137
- } catch (error) {
138
- console.error('โŒ Error during setup:', error.message);
139
- process.exit(1);
140
- }
141
- }
142
-
143
- // Run setup if called directly
144
- if (require.main === module) {
145
- setupCommiter();
146
- }
147
-
148
- module.exports = { setupCommiter, ensureSafeTestScript };
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Commiter - Commit convention tooling for standard-version releases
5
+ *
6
+ * This package helps enforce conventional commits and automate releases
7
+ * with beautiful changelogs featuring icons for each commit type.
8
+ */
9
+
10
+ const { execSync } = require('child_process');
11
+ const fs = require('fs');
12
+ const path = require('path');
13
+
14
+ function ensureSafeTestScript(scripts = {}) {
15
+ const defaultFailingTestScript = 'echo "Error: no test specified" && exit 1';
16
+ if (!scripts.test || scripts.test === defaultFailingTestScript) {
17
+ scripts.test = 'echo "No tests specified"';
18
+ }
19
+ return scripts;
20
+ }
21
+
22
+ function setupCommiter() {
23
+ console.log('๐Ÿš€ Setting up Commiter...\n');
24
+
25
+ // Check if package.json exists
26
+ if (!fs.existsSync('package.json')) {
27
+ console.error('โŒ Error: package.json not found. Please run this in a Node.js project directory.');
28
+ process.exit(1);
29
+ }
30
+
31
+ try {
32
+ // Install dependencies
33
+ console.log('๐Ÿ“ฆ Installing dependencies...');
34
+ execSync('npm install --save-dev standard-version @commitlint/cli @commitlint/config-conventional husky', {
35
+ stdio: 'inherit'
36
+ });
37
+
38
+ // Read package.json
39
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
40
+ const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
41
+
42
+ packageJson.scripts = ensureSafeTestScript(packageJson.scripts || {});
43
+ // Add scripts
44
+ packageJson.scripts.prepare = 'husky';
45
+ packageJson.scripts.release = 'node scripts/release.js';
46
+ packageJson.scripts['release:major'] = 'node scripts/release.js major';
47
+ packageJson.scripts['release:minor'] = 'node scripts/release.js minor';
48
+ packageJson.scripts['release:patch'] = 'node scripts/release.js patch';
49
+
50
+ // Add standard-version config
51
+ packageJson['standard-version'] = {
52
+ releaseCommitMessageFormat: 'chore(release): {{currentTag}} ๐Ÿš€',
53
+ types: [
54
+ { type: 'feat', section: 'โœจ Features' },
55
+ { type: 'fix', section: '๐Ÿ› Bug Fixes' },
56
+ { type: 'perf', section: 'โšก Performance' },
57
+ { type: 'refactor', section: 'โ™ป๏ธ Refactors' },
58
+ { type: 'docs', section: '๐Ÿ“ Documentation' },
59
+ { type: 'style', section: '๐Ÿ’„ Styles' },
60
+ { type: 'test', section: 'โœ… Tests' },
61
+ { type: 'build', section: '๐Ÿ—๏ธ Build System' },
62
+ { type: 'ci', section: '๐Ÿ‘ท Continuous Integration' },
63
+ { type: 'chore', section: '๐Ÿงน Chores' },
64
+ { type: 'revert', section: 'โช Reverts' }
65
+ ]
66
+ };
67
+
68
+ // Write updated package.json
69
+ fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
70
+
71
+ // Create release helper script
72
+ console.log('๐Ÿ› ๏ธ Creating release helper script...');
73
+ const releaseScriptDir = path.join(process.cwd(), 'scripts');
74
+ if (!fs.existsSync(releaseScriptDir)) {
75
+ fs.mkdirSync(releaseScriptDir, { recursive: true });
76
+ }
77
+
78
+ const releaseScriptPath = path.join(releaseScriptDir, 'release.js');
79
+ const releaseScriptSource = path.join(__dirname, 'scripts', 'release.js');
80
+ const releaseScriptContent = fs.readFileSync(releaseScriptSource, 'utf8');
81
+
82
+ fs.writeFileSync(releaseScriptPath, releaseScriptContent + '\n');
83
+ try {
84
+ fs.chmodSync(releaseScriptPath, 0o755);
85
+ } catch (error) {
86
+ // Ignore chmod errors on non-POSIX systems
87
+ }
88
+
89
+ // Determine commitlint config format based on project module type
90
+ const isEsmProject = packageJson.type === 'module';
91
+ const commitlintConfigFile = isEsmProject ? 'commitlint.config.js' : 'commitlint.config.cjs';
92
+ const commitlintConfigContent = isEsmProject
93
+ ? `export default {
94
+ extends: ['@commitlint/config-conventional'],
95
+ ignores: [(message) => message.startsWith('chore(release):')]
96
+ }\n`
97
+ : `module.exports = {
98
+ extends: ['@commitlint/config-conventional'],
99
+ ignores: [(message) => message.startsWith('chore(release):')]
100
+ }\n`;
101
+
102
+ const legacyCommitlintConfigFile = isEsmProject ? 'commitlint.config.cjs' : 'commitlint.config.js';
103
+ if (fs.existsSync(legacyCommitlintConfigFile)) {
104
+ fs.rmSync(legacyCommitlintConfigFile);
105
+ }
106
+
107
+ console.log(`โš™๏ธ Creating commitlint config (${commitlintConfigFile})...`);
108
+ fs.writeFileSync(commitlintConfigFile, commitlintConfigContent);
109
+
110
+ // Initialize Husky
111
+ console.log('๐Ÿถ Setting up Husky...');
112
+ execSync('npx husky init', { stdio: 'inherit' });
113
+
114
+ // Create commit-msg hook
115
+ const huskyDir = path.join(process.cwd(), '.husky');
116
+ if (!fs.existsSync(huskyDir)) {
117
+ fs.mkdirSync(huskyDir, { recursive: true });
118
+ }
119
+
120
+ const commitMsgHook = `#!/usr/bin/env sh
121
+
122
+ npx --no -- commitlint --edit "$1"
123
+ `;
124
+ fs.writeFileSync(path.join(huskyDir, 'commit-msg'), commitMsgHook);
125
+ fs.chmodSync(path.join(huskyDir, 'commit-msg'), 0o755);
126
+
127
+ console.log('\nโœ… Commiter setup complete!\n');
128
+ console.log('๐Ÿ“š Available commands:');
129
+ console.log(' npm run release major - Create a major release (1.0.0 โ†’ 2.0.0)');
130
+ console.log(' npm run release minor - Create a minor release (1.0.0 โ†’ 1.1.0)');
131
+ console.log(' npm run release patch - Create a patch release (1.0.0 โ†’ 1.0.1)');
132
+ console.log(' npm run release - Auto-detect version bump');
133
+ console.log(' npm run release -- --prerelease beta - Create a beta prerelease\n');
134
+ console.log('๐ŸŽฏ Commit format: type(scope): subject');
135
+ console.log(' Example: feat(auth): add user login\n');
136
+
137
+ } catch (error) {
138
+ console.error('โŒ Error during setup:', error.message);
139
+ process.exit(1);
140
+ }
141
+ }
142
+
143
+ // Run setup if called directly
144
+ if (require.main === module) {
145
+ setupCommiter();
146
+ }
147
+
148
+ module.exports = { setupCommiter, ensureSafeTestScript };
package/package.json CHANGED
@@ -1,94 +1,94 @@
1
- {
2
- "name": "@programinglive/commiter",
3
- "version": "1.0.11",
4
- "description": "Commit convention tooling for standard-version releases with beautiful changelogs",
5
- "main": "index.js",
6
- "bin": {
7
- "commiter": "./index.js"
8
- },
9
- "scripts": {
10
- "test": "node test/ensureSafeTestScript.test.js",
11
- "prepare": "husky",
12
- "release": "node scripts/release.js",
13
- "release:major": "node scripts/release.js major",
14
- "release:minor": "node scripts/release.js minor",
15
- "release:patch": "node scripts/release.js patch"
16
- },
17
- "keywords": [
18
- "commit",
19
- "conventional-commits",
20
- "standard-version",
21
- "changelog",
22
- "versioning",
23
- "semantic-release",
24
- "git-hooks",
25
- "husky",
26
- "commitlint"
27
- ],
28
- "author": "Programming Live",
29
- "license": "MIT",
30
- "repository": {
31
- "type": "git",
32
- "url": "git+https://github.com/programinglive/commiter.git"
33
- },
34
- "bugs": {
35
- "url": "https://github.com/programinglive/commiter/issues"
36
- },
37
- "homepage": "https://github.com/programinglive/commiter#readme",
38
- "type": "commonjs",
39
- "standard-version": {
40
- "releaseCommitMessageFormat": "chore(release): {{currentTag}} ๐Ÿš€",
41
- "types": [
42
- {
43
- "type": "feat",
44
- "section": "โœจ Features"
45
- },
46
- {
47
- "type": "fix",
48
- "section": "๐Ÿ› Bug Fixes"
49
- },
50
- {
51
- "type": "perf",
52
- "section": "โšก Performance"
53
- },
54
- {
55
- "type": "refactor",
56
- "section": "โ™ป๏ธ Refactors"
57
- },
58
- {
59
- "type": "docs",
60
- "section": "๐Ÿ“ Documentation"
61
- },
62
- {
63
- "type": "style",
64
- "section": "๐Ÿ’„ Styles"
65
- },
66
- {
67
- "type": "test",
68
- "section": "โœ… Tests"
69
- },
70
- {
71
- "type": "build",
72
- "section": "๐Ÿ—๏ธ Build System"
73
- },
74
- {
75
- "type": "ci",
76
- "section": "๐Ÿ‘ท Continuous Integration"
77
- },
78
- {
79
- "type": "chore",
80
- "section": "๐Ÿงน Chores"
81
- },
82
- {
83
- "type": "revert",
84
- "section": "โช Reverts"
85
- }
86
- ]
87
- },
88
- "devDependencies": {
89
- "@commitlint/cli": "^20.1.0",
90
- "@commitlint/config-conventional": "^20.0.0",
91
- "husky": "^9.1.7",
92
- "standard-version": "^9.5.0"
93
- }
94
- }
1
+ {
2
+ "name": "@programinglive/commiter",
3
+ "version": "1.1.0",
4
+ "description": "Commiter keeps repositories release-ready by enforcing conventional commits, generating icon-rich changelog entries, and orchestrating semantic version bumps without manual toil. It bootstraps Husky hooks, commitlint rules, and release scripts that inspect history, detect framework-specific test commands, run them automatically, tag git releases, coordinate npm publishing, surface release metrics, enforce project-specific checks, and give maintainers observability across distributed teams. Plus!",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "commiter": "./index.js"
8
+ },
9
+ "scripts": {
10
+ "test": "node test/ensureSafeTestScript.test.js",
11
+ "prepare": "husky",
12
+ "release": "node scripts/release.js",
13
+ "release:major": "node scripts/release.js major",
14
+ "release:minor": "node scripts/release.js minor",
15
+ "release:patch": "node scripts/release.js patch"
16
+ },
17
+ "keywords": [
18
+ "commit",
19
+ "conventional-commits",
20
+ "standard-version",
21
+ "changelog",
22
+ "versioning",
23
+ "semantic-release",
24
+ "git-hooks",
25
+ "husky",
26
+ "commitlint"
27
+ ],
28
+ "author": "Programming Live",
29
+ "license": "MIT",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/programinglive/commiter.git"
33
+ },
34
+ "bugs": {
35
+ "url": "https://github.com/programinglive/commiter/issues"
36
+ },
37
+ "homepage": "https://github.com/programinglive/commiter#readme",
38
+ "type": "commonjs",
39
+ "standard-version": {
40
+ "releaseCommitMessageFormat": "chore(release): {{currentTag}} ๐Ÿš€",
41
+ "types": [
42
+ {
43
+ "type": "feat",
44
+ "section": "โœจ Features"
45
+ },
46
+ {
47
+ "type": "fix",
48
+ "section": "๐Ÿ› Bug Fixes"
49
+ },
50
+ {
51
+ "type": "perf",
52
+ "section": "โšก Performance"
53
+ },
54
+ {
55
+ "type": "refactor",
56
+ "section": "โ™ป๏ธ Refactors"
57
+ },
58
+ {
59
+ "type": "docs",
60
+ "section": "๐Ÿ“ Documentation"
61
+ },
62
+ {
63
+ "type": "style",
64
+ "section": "๐Ÿ’„ Styles"
65
+ },
66
+ {
67
+ "type": "test",
68
+ "section": "โœ… Tests"
69
+ },
70
+ {
71
+ "type": "build",
72
+ "section": "๐Ÿ—๏ธ Build System"
73
+ },
74
+ {
75
+ "type": "ci",
76
+ "section": "๐Ÿ‘ท Continuous Integration"
77
+ },
78
+ {
79
+ "type": "chore",
80
+ "section": "๐Ÿงน Chores"
81
+ },
82
+ {
83
+ "type": "revert",
84
+ "section": "โช Reverts"
85
+ }
86
+ ]
87
+ },
88
+ "devDependencies": {
89
+ "@commitlint/cli": "^20.1.0",
90
+ "@commitlint/config-conventional": "^20.0.0",
91
+ "husky": "^9.1.7",
92
+ "standard-version": "^9.5.0"
93
+ }
94
+ }
@@ -1,6 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const { spawnSync } = require('child_process');
4
+ const fs = require('fs');
5
+ const path = require('path');
4
6
 
5
7
  const VALID_RELEASE_TYPES = new Set([
6
8
  'major',
@@ -14,6 +16,13 @@ const VALID_RELEASE_TYPES = new Set([
14
16
 
15
17
  const SEMVER_REGEX = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
16
18
 
19
+ const LOCKFILE_PREFERENCES = [
20
+ { manager: 'pnpm', file: 'pnpm-lock.yaml' },
21
+ { manager: 'yarn', file: 'yarn.lock' },
22
+ { manager: 'bun', file: 'bun.lockb' },
23
+ { manager: 'npm', file: 'package-lock.json' }
24
+ ];
25
+
17
26
  function getCliArguments(argv = process.argv) {
18
27
  const rawArgs = argv.slice(2);
19
28
  if (rawArgs.length === 0) {
@@ -61,6 +70,63 @@ function buildStandardVersionArgs({ releaseType, extraArgs }) {
61
70
  return args;
62
71
  }
63
72
 
73
+ function loadPackageJson(cwd = process.cwd()) {
74
+ try {
75
+ const packageJsonPath = path.join(cwd, 'package.json');
76
+ const contents = fs.readFileSync(packageJsonPath, 'utf8');
77
+ return JSON.parse(contents);
78
+ } catch (error) {
79
+ return null;
80
+ }
81
+ }
82
+
83
+ function detectPackageManager({ env = process.env, cwd = process.cwd() } = {}) {
84
+ const userAgent = env.npm_config_user_agent || '';
85
+ if (userAgent.startsWith('pnpm/')) return 'pnpm';
86
+ if (userAgent.startsWith('yarn/')) return 'yarn';
87
+ if (userAgent.startsWith('bun/')) return 'bun';
88
+
89
+ for (const { manager, file } of LOCKFILE_PREFERENCES) {
90
+ if (fs.existsSync(path.join(cwd, file))) {
91
+ return manager;
92
+ }
93
+ }
94
+
95
+ return 'npm';
96
+ }
97
+
98
+ function buildTestCommand(packageManager) {
99
+ switch (packageManager) {
100
+ case 'pnpm':
101
+ return { command: 'pnpm', args: ['test'] };
102
+ case 'yarn':
103
+ return { command: 'yarn', args: ['test'] };
104
+ case 'bun':
105
+ return { command: 'bun', args: ['test'] };
106
+ default:
107
+ return { command: 'npm', args: ['test'] };
108
+ }
109
+ }
110
+
111
+ function runProjectTests({ spawn = spawnSync, env = process.env, cwd = process.cwd() } = {}) {
112
+ const packageJson = loadPackageJson(cwd);
113
+ const scripts = packageJson && packageJson.scripts ? packageJson.scripts : {};
114
+
115
+ if (!scripts.test) {
116
+ console.log('โ„น๏ธ Skipping tests: no "test" script detected in package.json');
117
+ return { status: 0 };
118
+ }
119
+
120
+ const packageManager = detectPackageManager({ env, cwd });
121
+ const { command, args } = buildTestCommand(packageManager);
122
+
123
+ console.log(`๐Ÿงช Running tests with ${packageManager} ${args.join(' ')}`.trim());
124
+ return spawn(command, args, {
125
+ stdio: 'inherit',
126
+ env
127
+ });
128
+ }
129
+
64
130
  function runRelease({ argv = process.argv, env = process.env, spawn = spawnSync } = {}) {
65
131
  const { releaseType: cliReleaseType, extraArgs } = getCliArguments(argv);
66
132
  const inferredReleaseType = cliReleaseType || getNpmRunArgument(env);
@@ -69,6 +135,11 @@ function runRelease({ argv = process.argv, env = process.env, spawn = spawnSync
69
135
  extraArgs
70
136
  });
71
137
 
138
+ const testResult = runProjectTests({ spawn, env });
139
+ if (testResult && typeof testResult.status === 'number' && testResult.status !== 0) {
140
+ return testResult;
141
+ }
142
+
72
143
  const standardVersionBin = require.resolve('standard-version/bin/cli.js');
73
144
  return spawn(process.execPath, [standardVersionBin, ...standardVersionArgs], {
74
145
  stdio: 'inherit'
@@ -93,5 +164,8 @@ module.exports = {
93
164
  getCliArguments,
94
165
  getNpmRunArgument,
95
166
  buildStandardVersionArgs,
167
+ loadPackageJson,
168
+ detectPackageManager,
169
+ runProjectTests,
96
170
  runRelease
97
171
  };