Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
feat: throw an Error if package.json has duplicate "repository" key (#…
  • Loading branch information
gr2m committed Oct 11, 2020
1 parent 18e35b2 commit b8fb35c
Show file tree
Hide file tree
Showing 5 changed files with 46 additions and 7 deletions.
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Expand Up @@ -229,7 +229,7 @@ Before pushing your code changes make sure there are no linting errors with `npm

### 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.

Expand Down
4 changes: 4 additions & 0 deletions lib/definitions/errors.js
Expand Up @@ -29,6 +29,10 @@ Please make sure to add the \`repositoryUrl\` to the [semantic-release configura
'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}}) => ({
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}\`.
Expand Down
23 changes: 19 additions & 4 deletions lib/get-config.js
@@ -1,12 +1,15 @@
const {readFile} = require('fs').promises;
const {castArray, pickBy, isNil, isString, isPlainObject} = require('lodash');
const readPkgUp = require('read-pkg-up');
const findPkgUp = require('pkg-up');
const {cosmiconfig} = require('cosmiconfig');
const resolveFrom = require('resolve-from');
const findDuplicatedPropertyKeys = require('find-duplicated-property-keys');
const debug = require('debug')('semantic-release:config');
const {repoUrl} = require('./git');
const PLUGINS_DEFINITIONS = require('./definitions/plugins');
const plugins = require('./plugins');
const {validatePlugin, parseConfig} = require('./plugins/utils');
const getError = require('./get-error');

const CONFIG_NAME = 'release';
const CONFIG_FILES = [
Expand Down Expand Up @@ -74,7 +77,7 @@ module.exports = async (context, cliOptions) => {
{name: 'beta', 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}`,
plugins: [
'@semantic-release/commit-analyzer',
Expand All @@ -93,6 +96,18 @@ module.exports = async (context, cliOptions) => {
};

async function pkgRepoUrl(options) {
const {packageJson} = (await readPkgUp(options)) || {};
return packageJson && (isPlainObject(packageJson.repository) ? packageJson.repository.url : packageJson.repository);
const packageJsonPath = await findPkgUp(options);
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;
}
6 changes: 4 additions & 2 deletions package.json
Expand Up @@ -31,6 +31,7 @@
"env-ci": "^5.0.0",
"execa": "^4.0.0",
"figures": "^3.0.0",
"find-duplicated-property-keys": "^1.2.2",
"find-versions": "^3.0.0",
"get-stream": "^5.0.0",
"git-log-parser": "^1.2.0",
Expand All @@ -42,7 +43,7 @@
"micromatch": "^4.0.2",
"p-each-series": "^2.1.0",
"p-reduce": "^2.0.0",
"read-pkg-up": "^7.0.0",
"pkg-up": "^3.1.0",
"resolve-from": "^5.0.0",
"semver": "^7.3.2",
"semver-diff": "^3.1.1",
Expand Down Expand Up @@ -128,7 +129,8 @@
"prettier": true,
"space": true,
"rules": {
"unicorn/string-content": "off"
"unicorn/string-content": "off",
"node/no-unsupported-features/node-builtins": "off"
}
}
}
18 changes: 18 additions & 0 deletions test/get-config.test.js
Expand Up @@ -516,3 +516,21 @@ test('Throw an Error if one of the shareable config cannot be found', async (t)
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.');
});

0 comments on commit b8fb35c

Please sign in to comment.