feat: throw an Error if package.json has duplicate "repository" key (#1656)
This commit is contained in:
		
							parent
							
								
									18e35b28ad
								
							
						
					
					
						commit
						b8fb35c7e1
					
				| @ -229,7 +229,7 @@ Before pushing your code changes make sure there are no linting errors with `npm | |||||||
| 
 | 
 | ||||||
| ### Tests | ### Tests | ||||||
| 
 | 
 | ||||||
| Running the integration test requires you to install [Docker](https://docs.docker.com/engine/installation) on your machine. | Running the integration test requires you to install [Docker](https://docs.docker.com/engine/installation) on your machine. Note: the tests assume that running `git init` will create a `master` branch by default. If your local `git` is configured differently (see [`init.defaultBranch`](https://github.blog/2020-07-27-highlights-from-git-2-28/#introducing-init-defaultbranch)), change it temporarily when running the tests. | ||||||
| 
 | 
 | ||||||
| All the [semantic-release](https://github.com/semantic-release) repositories use [AVA](https://github.com/avajs/ava) for writing and running tests. | All the [semantic-release](https://github.com/semantic-release) repositories use [AVA](https://github.com/avajs/ava) for writing and running tests. | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -29,6 +29,10 @@ Please make sure to add the \`repositoryUrl\` to the [semantic-release configura | |||||||
|       'docs/usage/configuration.md' |       'docs/usage/configuration.md' | ||||||
|     )}).`,
 |     )}).`,
 | ||||||
|   }), |   }), | ||||||
|  |   EDUPLICATEREPOSITORYKEY: ({packageJsonPath}) => ({ | ||||||
|  |     message: 'Duplicate `"repository"` key in package.json.', | ||||||
|  |     details: `Your package.json file at ${packageJsonPath} has more than one "repository" keys.`, | ||||||
|  |   }), | ||||||
|   EGITNOPERMISSION: ({options: {repositoryUrl}, branch: {name}}) => ({ |   EGITNOPERMISSION: ({options: {repositoryUrl}, branch: {name}}) => ({ | ||||||
|     message: 'Cannot push to the Git repository.', |     message: 'Cannot push to the Git repository.', | ||||||
|     details: `**semantic-release** cannot push the version tag to the branch \`${name}\` on the remote Git repository with URL \`${repositoryUrl}\`.
 |     details: `**semantic-release** cannot push the version tag to the branch \`${name}\` on the remote Git repository with URL \`${repositoryUrl}\`.
 | ||||||
|  | |||||||
| @ -1,12 +1,15 @@ | |||||||
|  | const {readFile} = require('fs').promises; | ||||||
| const {castArray, pickBy, isNil, isString, isPlainObject} = require('lodash'); | const {castArray, pickBy, isNil, isString, isPlainObject} = require('lodash'); | ||||||
| const readPkgUp = require('read-pkg-up'); | const findPkgUp = require('pkg-up'); | ||||||
| const {cosmiconfig} = require('cosmiconfig'); | const {cosmiconfig} = require('cosmiconfig'); | ||||||
| const resolveFrom = require('resolve-from'); | const resolveFrom = require('resolve-from'); | ||||||
|  | const findDuplicatedPropertyKeys = require('find-duplicated-property-keys'); | ||||||
| const debug = require('debug')('semantic-release:config'); | const debug = require('debug')('semantic-release:config'); | ||||||
| const {repoUrl} = require('./git'); | const {repoUrl} = require('./git'); | ||||||
| const PLUGINS_DEFINITIONS = require('./definitions/plugins'); | const PLUGINS_DEFINITIONS = require('./definitions/plugins'); | ||||||
| const plugins = require('./plugins'); | const plugins = require('./plugins'); | ||||||
| const {validatePlugin, parseConfig} = require('./plugins/utils'); | const {validatePlugin, parseConfig} = require('./plugins/utils'); | ||||||
|  | const getError = require('./get-error'); | ||||||
| 
 | 
 | ||||||
| const CONFIG_NAME = 'release'; | const CONFIG_NAME = 'release'; | ||||||
| const CONFIG_FILES = [ | const CONFIG_FILES = [ | ||||||
| @ -74,7 +77,7 @@ module.exports = async (context, cliOptions) => { | |||||||
|       {name: 'beta', prerelease: true}, |       {name: 'beta', prerelease: true}, | ||||||
|       {name: 'alpha', prerelease: true}, |       {name: 'alpha', prerelease: true}, | ||||||
|     ], |     ], | ||||||
|     repositoryUrl: (await pkgRepoUrl({normalize: false, cwd})) || (await repoUrl({cwd, env})), |     repositoryUrl: (await pkgRepoUrl({cwd})) || (await repoUrl({cwd, env})), | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|     plugins: [ |     plugins: [ | ||||||
|       '@semantic-release/commit-analyzer', |       '@semantic-release/commit-analyzer', | ||||||
| @ -93,6 +96,18 @@ module.exports = async (context, cliOptions) => { | |||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| async function pkgRepoUrl(options) { | async function pkgRepoUrl(options) { | ||||||
|   const {packageJson} = (await readPkgUp(options)) || {}; |   const packageJsonPath = await findPkgUp(options); | ||||||
|   return packageJson && (isPlainObject(packageJson.repository) ? packageJson.repository.url : packageJson.repository); |   if (!packageJsonPath) return; | ||||||
|  | 
 | ||||||
|  |   const packageJsonString = await readFile(packageJsonPath, 'utf-8'); | ||||||
|  |   const result = findDuplicatedPropertyKeys(packageJsonString); | ||||||
|  | 
 | ||||||
|  |   if (result.length > 0) { | ||||||
|  |     throw getError('EDUPLICATEREPOSITORYKEY', {packageJsonPath}); | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   const {repository} = require(packageJsonPath); | ||||||
|  |   if (!repository) return; | ||||||
|  | 
 | ||||||
|  |   return isPlainObject(repository) ? repository.url : repository; | ||||||
| } | } | ||||||
|  | |||||||
| @ -31,6 +31,7 @@ | |||||||
|     "env-ci": "^5.0.0", |     "env-ci": "^5.0.0", | ||||||
|     "execa": "^4.0.0", |     "execa": "^4.0.0", | ||||||
|     "figures": "^3.0.0", |     "figures": "^3.0.0", | ||||||
|  |     "find-duplicated-property-keys": "^1.2.2", | ||||||
|     "find-versions": "^3.0.0", |     "find-versions": "^3.0.0", | ||||||
|     "get-stream": "^5.0.0", |     "get-stream": "^5.0.0", | ||||||
|     "git-log-parser": "^1.2.0", |     "git-log-parser": "^1.2.0", | ||||||
| @ -42,7 +43,7 @@ | |||||||
|     "micromatch": "^4.0.2", |     "micromatch": "^4.0.2", | ||||||
|     "p-each-series": "^2.1.0", |     "p-each-series": "^2.1.0", | ||||||
|     "p-reduce": "^2.0.0", |     "p-reduce": "^2.0.0", | ||||||
|     "read-pkg-up": "^7.0.0", |     "pkg-up": "^3.1.0", | ||||||
|     "resolve-from": "^5.0.0", |     "resolve-from": "^5.0.0", | ||||||
|     "semver": "^7.3.2", |     "semver": "^7.3.2", | ||||||
|     "semver-diff": "^3.1.1", |     "semver-diff": "^3.1.1", | ||||||
| @ -128,7 +129,8 @@ | |||||||
|     "prettier": true, |     "prettier": true, | ||||||
|     "space": true, |     "space": true, | ||||||
|     "rules": { |     "rules": { | ||||||
|       "unicorn/string-content": "off" |       "unicorn/string-content": "off", | ||||||
|  |       "node/no-unsupported-features/node-builtins": "off" | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | |||||||
| @ -516,3 +516,21 @@ test('Throw an Error if one of the shareable config cannot be found', async (t) | |||||||
|     code: 'MODULE_NOT_FOUND', |     code: 'MODULE_NOT_FOUND', | ||||||
|   }); |   }); | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
|  | test('Throw an Error if package.json has duplicate "repository" key', async (t) => { | ||||||
|  |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|  |   const {cwd} = await gitRepo(); | ||||||
|  | 
 | ||||||
|  |   // Create package.json with duplicate "repository" key
 | ||||||
|  |   await writeFile( | ||||||
|  |     path.resolve(cwd, 'package.json'), | ||||||
|  |     `{
 | ||||||
|  |     "repository": "https://github.com/octocat/repository", | ||||||
|  |     "repository": "https://github.com/octocat/repository" | ||||||
|  |   }` | ||||||
|  |   ); | ||||||
|  | 
 | ||||||
|  |   const error = await t.throwsAsync(t.context.getConfig({cwd})); | ||||||
|  |   t.is(error.code, 'EDUPLICATEREPOSITORYKEY'); | ||||||
|  |   t.is(error.message, 'Duplicate `"repository"` key in package.json.'); | ||||||
|  | }); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user