diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index bb920942a..d17b4fcc5 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -23,7 +23,7 @@ jobs: OS: ${{ matrix.os }} NODE_VERSION: ${{ matrix.node }} steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 - run: git fetch --prune --unshallow - run: git config --global user.name 'Actions' - run: git config --global user.email 'dummy@example.org' diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml index 9fdbbe7b8..c3ffddc2b 100644 --- a/.github/workflows/release-please.yml +++ b/.github/workflows/release-please.yml @@ -15,7 +15,7 @@ jobs: release-type: node package-name: commit-and-tag-version # The logic below handles the npm publication: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v4 # these if statements ensure that a publication only occurs when # a new release is created: if: ${{ steps.release.outputs.release_created }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 770201d3b..79efe5bc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines. +## [12.6.0](https://github.com/absolute-version/commit-and-tag-version/compare/v12.5.2...v12.6.0) (2025-08-27) + + +### Features + +* add --config option to allow custom config file path ([#237](https://github.com/absolute-version/commit-and-tag-version/issues/237)) ([3958e68](https://github.com/absolute-version/commit-and-tag-version/commit/3958e688a60df4f1ba46137d1f4147a65817c8d7)) + ## [12.5.2](https://github.com/absolute-version/commit-and-tag-version/compare/v12.5.1...v12.5.2) (2025-07-30) diff --git a/README.md b/README.md index 85a850241..b466a5e13 100644 --- a/README.md +++ b/README.md @@ -38,6 +38,7 @@ _Having problems? Want to contribute? Join us on the [node-tooling community Sla - [Release as a Pre-Release](#release-as-a-pre-release) - [Release as a Target Type Imperatively (`npm version`-like)](#release-as-a-target-type-imperatively-npm-version-like) - [Prevent Git Hooks](#prevent-git-hooks) + - [Custom Config Path](#custom-config-path) - [Signing Commits and Tags](#signing-commits-and-tags) - [Lifecycle Scripts](#lifecycle-scripts) - [Skipping Lifecycle Steps](#skipping-lifecycle-steps) @@ -312,6 +313,23 @@ npm run release -- --no-verify commit-and-tag-version --no-verify ``` +### Custom Config Path + +Specify a custom path to the configuration file using the `--config` option + +```sh +commit-and-tag-version --config ./path/to/.versionrc.js + +# or using alias +commit-and-tag-version -c ./path/to/.versionrc.js +``` + +All config file formats can be used: + +```sh +commit-and-tag-version -c ./path/to/.versionrc[.js|.cjs|.json] +``` + ### Signing Commits and Tags If you have your GPG key set up, add the `--sign` or `-s` flag to your `commit-and-tag-version` command. diff --git a/command.js b/command.js index c5d98480e..8d04da3d6 100755 --- a/command.js +++ b/command.js @@ -132,6 +132,12 @@ const yargs = require('yargs') default: defaults.npmPublishHint, describe: 'Customized publishing hint', }) + .option('config', { + type: 'string', + default: defaults.config, + alias: 'c', + describe: 'Path to a custom configuration file', + }) .check((argv) => { if (typeof argv.scripts !== 'object' || Array.isArray(argv.scripts)) { throw Error('scripts must be an object'); @@ -150,9 +156,10 @@ const yargs = require('yargs') ) .pkgConf('standard-version') .pkgConf('commit-and-tag-version') - .config(getConfiguration()) .wrap(97); +yargs.config(getConfiguration(yargs.argv.config)); + Object.keys(spec.properties).forEach((propertyKey) => { const property = spec.properties[propertyKey]; yargs.option(propertyKey, { diff --git a/defaults.js b/defaults.js index 9cf40e034..83d69d225 100644 --- a/defaults.js +++ b/defaults.js @@ -17,6 +17,7 @@ const defaults = { gitTagFallback: true, preset: require.resolve('conventional-changelog-conventionalcommits'), npmPublishHint: undefined, + config: undefined, }; /** diff --git a/lib/configuration.js b/lib/configuration.js index f169631ea..be8c634ef 100644 --- a/lib/configuration.js +++ b/lib/configuration.js @@ -9,9 +9,13 @@ const CONFIGURATION_FILES = [ '.versionrc.js', ]; -module.exports.getConfiguration = function () { +module.exports.getConfiguration = function (configFile) { let config = {}; - const configPath = findUp.sync(CONFIGURATION_FILES); + + // If the user has provided a configuration file via the `--config` argument, we use that. + const configurationFiles = configFile ?? CONFIGURATION_FILES; + + const configPath = findUp.sync(configurationFiles); if (!configPath) { return config; } diff --git a/package-lock.json b/package-lock.json index f46c12f94..90489549a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "commit-and-tag-version", - "version": "12.5.2", + "version": "12.6.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "commit-and-tag-version", - "version": "12.5.2", + "version": "12.6.0", "license": "ISC", "dependencies": { "chalk": "^2.4.2", @@ -30,17 +30,17 @@ "commit-and-tag-version": "bin/cli.js" }, "devDependencies": { - "@eslint/js": "^9.13.0", + "@eslint/js": "^9.36.0", "eslint": "^9.13.0", - "eslint-config-prettier": "^9.1.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^28.8.3", - "eslint-plugin-n": "^17.11.1", + "eslint-plugin-n": "^17.21.3", "eslint-plugin-promise": "^7.1.0", "jest": "^29.7.0", "jest-serial-runner": "^1.2.1", "prettier": "^3.3.3", - "shelljs": "^0.8.5", + "shelljs": "^0.10.0", "strip-ansi": "^6.0.1" }, "engines": { @@ -547,15 +547,20 @@ "license": "MIT" }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz", + "integrity": "sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==", "dev": true, "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } @@ -634,12 +639,16 @@ } }, "node_modules/@eslint/js": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", - "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", + "version": "9.36.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.36.0.tgz", + "integrity": "sha512-uhCbYtYynH30iZErszX78U+nR3pJU3RHGQ57NXy5QupD4SBVwDeU8TNBy+MjMngc1UyIW9noKqsRqfjQTBU2dw==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { @@ -3321,13 +3330,17 @@ } }, "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "version": "10.1.8", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz", + "integrity": "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==", "dev": true, + "license": "MIT", "bin": { "eslint-config-prettier": "bin/cli.js" }, + "funding": { + "url": "https://opencollective.com/eslint-config-prettier" + }, "peerDependencies": { "eslint": ">=7.0.0" } @@ -3483,19 +3496,21 @@ } }, "node_modules/eslint-plugin-n": { - "version": "17.11.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.11.1.tgz", - "integrity": "sha512-93IUD82N6tIEgjztVI/l3ElHtC2wTa9boJHrD8iN+NyDxjxz/daZUZKfkedjBZNdg6EqDk4irybUsiPwDqXAEA==", + "version": "17.21.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.21.3.tgz", + "integrity": "sha512-MtxYjDZhMQgsWRm/4xYLL0i2EhusWT7itDxlJ80l1NND2AL2Vi5Mvneqv/ikG9+zpran0VsVRXTEHrpLmUZRNw==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "enhanced-resolve": "^5.17.0", - "eslint-plugin-es-x": "^7.5.0", - "get-tsconfig": "^4.7.0", - "globals": "^15.8.0", - "ignore": "^5.2.4", - "minimatch": "^9.0.5", - "semver": "^7.5.3" + "@eslint-community/eslint-utils": "^4.5.0", + "enhanced-resolve": "^5.17.1", + "eslint-plugin-es-x": "^7.8.0", + "get-tsconfig": "^4.8.1", + "globals": "^15.11.0", + "globrex": "^0.1.2", + "ignore": "^5.3.2", + "semver": "^7.6.3", + "ts-declaration-location": "^1.0.6" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -3507,15 +3522,6 @@ "eslint": ">=8.23.0" } }, - "node_modules/eslint-plugin-n/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/eslint-plugin-n/node_modules/globals": { "version": "15.11.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", @@ -3528,21 +3534,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-plugin-n/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/eslint-plugin-promise": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.1.0.tgz", @@ -3585,6 +3576,16 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/@eslint/js": { + "version": "9.13.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", + "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/eslint/node_modules/ansi-styles": { "version": "4.3.0", "dev": true, @@ -4225,6 +4226,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globrex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", + "integrity": "sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==", + "dev": true, + "license": "MIT" + }, "node_modules/gopd": { "version": "1.0.1", "dev": true, @@ -4504,14 +4512,6 @@ "node": ">= 0.4" } }, - "node_modules/interpret": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } - }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -7531,16 +7531,6 @@ "node": ">= 6" } }, - "node_modules/rechoir": { - "version": "0.6.2", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, "node_modules/redent": { "version": "3.0.0", "license": "MIT", @@ -7798,19 +7788,17 @@ } }, "node_modules/shelljs": { - "version": "0.8.5", + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.10.0.tgz", + "integrity": "sha512-Jex+xw5Mg2qMZL3qnzXIfaxEtBaC4n7xifqaqtrZDdlheR70OGkydrPJWT0V1cA1k3nanC86x9FwAmQl6w3Klw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "glob": "^7.0.0", - "interpret": "^1.0.0", - "rechoir": "^0.6.2" - }, - "bin": { - "shjs": "bin/shjs" + "execa": "^5.1.1", + "fast-glob": "^3.3.2" }, "engines": { - "node": ">=4" + "node": ">=18" } }, "node_modules/side-channel": { @@ -8257,6 +8245,42 @@ "typescript": ">=4.2.0" } }, + "node_modules/ts-declaration-location": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", + "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", + "dev": true, + "funding": [ + { + "type": "ko-fi", + "url": "https://ko-fi.com/rebeccastevens" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" + } + ], + "license": "BSD-3-Clause", + "dependencies": { + "picomatch": "^4.0.2" + }, + "peerDependencies": { + "typescript": ">=4.0.0" + } + }, + "node_modules/ts-declaration-location/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", diff --git a/package.json b/package.json index 466aad691..ac7463ef2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "commit-and-tag-version", - "version": "12.5.2", + "version": "12.6.0", "description": "replacement for `npm version` with automatic CHANGELOG generation", "bin": "bin/cli.js", "scripts": { @@ -57,17 +57,17 @@ "yargs": "^17.7.2" }, "devDependencies": { - "@eslint/js": "^9.13.0", + "@eslint/js": "^9.36.0", "eslint": "^9.13.0", - "eslint-config-prettier": "^9.1.0", + "eslint-config-prettier": "^10.1.8", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jest": "^28.8.3", - "eslint-plugin-n": "^17.11.1", + "eslint-plugin-n": "^17.21.3", "eslint-plugin-promise": "^7.1.0", "jest": "^29.7.0", "jest-serial-runner": "^1.2.1", "prettier": "^3.3.3", - "shelljs": "^0.8.5", + "shelljs": "^0.10.0", "strip-ansi": "^6.0.1" } } diff --git a/test/config-files.integration-test.js b/test/config-files.integration-test.js index e1c54f3c9..dba07a780 100644 --- a/test/config-files.integration-test.js +++ b/test/config-files.integration-test.js @@ -86,6 +86,30 @@ describe('config files', function () { expect(content).toContain(issueUrlFormat); }); + it('reads config from custom path', async function () { + const issueUrlFormat = 'http://www.foo.com/{{id}}'; + const changelog = ({ preset }) => preset.issueUrlFormat; + mock({ bump: 'minor', changelog }); + fs.mkdirSync('custom-folder'); + fs.writeFileSync( + 'custom-folder/.versionrc.json', + JSON.stringify({ issueUrlFormat }), + 'utf-8', + ); + + // Override process.argv to simulate CLI arguments before `exec`. + // This ensures yargs parses the custom config argument. + const originalArgv = process.argv; + process.argv = ['node', 'script.js', '-c', 'custom-folder/.versionrc.json']; + + await exec(['-c', 'custom-folder/.versionrc.json']); + const content = fs.readFileSync('CHANGELOG.md', 'utf-8'); + expect(content).toContain(issueUrlFormat); + + // Restore original process.argv + process.argv = originalArgv; + }); + it('evaluates a config-function from .versionrc.js', async function () { const issueUrlFormat = 'http://www.foo.com/{{id}}'; const src = `module.exports = function() { return ${JSON.stringify({