feat: allow to use shorthand for repositoryUrl
				
					
				
			- `owner/repo` => `https://github.com/owner/repo.git` - `gitlab:owner/repo` => `https://gitlab.com/owner/repo.git` - `bitbucket:owner/repo` => `https://bitbucket.com/owner/repo.git`
This commit is contained in:
		
							parent
							
								
									f13ec6a615
								
							
						
					
					
						commit
						5f1d530e2a
					
				| @ -63,8 +63,6 @@ The git repository URL. | |||||||
| 
 | 
 | ||||||
| Any valid git url format is supported (See [Git protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols)). | Any valid git url format is supported (See [Git protocols](https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols)). | ||||||
| 
 | 
 | ||||||
| **Note**: If the [Github plugin](https://github.com/semantic-release/github) is used the URL must be a valid Github URL that include the `owner`, the `repository` name and the `host`. **The Github shorthand URL is not supported.** |  | ||||||
| 
 |  | ||||||
| ### tagFormat | ### tagFormat | ||||||
| 
 | 
 | ||||||
| Type: `String` | Type: `String` | ||||||
|  | |||||||
| @ -2,9 +2,8 @@ const {castArray, pickBy, isUndefined, isNull, isString, isPlainObject} = requir | |||||||
| const readPkgUp = require('read-pkg-up'); | const readPkgUp = require('read-pkg-up'); | ||||||
| const cosmiconfig = require('cosmiconfig'); | const cosmiconfig = require('cosmiconfig'); | ||||||
| const resolveFrom = require('resolve-from'); | const resolveFrom = require('resolve-from'); | ||||||
| const gitUrlParse = require('git-url-parse'); |  | ||||||
| const debug = require('debug')('semantic-release:config'); | const debug = require('debug')('semantic-release:config'); | ||||||
| const {repoUrl, verifyAuth} = 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 getGitAuthUrl = require('./get-git-auth-url'); | const getGitAuthUrl = require('./get-git-auth-url'); | ||||||
| @ -52,9 +51,7 @@ module.exports = async (opts, logger) => { | |||||||
|     ...pickBy(options, option => !isUndefined(option) && !isNull(option)), |     ...pickBy(options, option => !isUndefined(option) && !isNull(option)), | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   if (!await verifyAuth(options.repositoryUrl, options.branch)) { |   options.repositoryUrl = await getGitAuthUrl(options); | ||||||
|     options.repositoryUrl = options.repositoryUrl ? getGitAuthUrl(options.repositoryUrl) : options.repositoryUrl; |  | ||||||
|   } |  | ||||||
| 
 | 
 | ||||||
|   debug('options values: %O', options); |   debug('options values: %O', options); | ||||||
| 
 | 
 | ||||||
| @ -63,12 +60,5 @@ module.exports = async (opts, logger) => { | |||||||
| 
 | 
 | ||||||
| async function pkgRepoUrl() { | async function pkgRepoUrl() { | ||||||
|   const {pkg} = await readPkgUp({normalize: false}); |   const {pkg} = await readPkgUp({normalize: false}); | ||||||
|   const repositoryUrl = pkg && (isPlainObject(pkg.repository) ? pkg.repository.url : pkg.repository); |   return pkg && (isPlainObject(pkg.repository) ? pkg.repository.url : pkg.repository); | ||||||
| 
 |  | ||||||
|   if (repositoryUrl) { |  | ||||||
|     const {protocols} = gitUrlParse(repositoryUrl); |  | ||||||
|     return `${gitUrlParse(repositoryUrl).toString( |  | ||||||
|       protocols.includes('https') ? 'https' : protocols.includes('http') ? 'http' : undefined |  | ||||||
|     )}${protocols.includes('https') || protocols.includes('http') ? '.git' : ''}`;
 |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,30 +1,54 @@ | |||||||
| const {parse, format} = require('url'); | const {parse, format} = require('url'); | ||||||
| const {isUndefined} = require('lodash'); | const {isUndefined} = require('lodash'); | ||||||
| const gitUrlParse = require('git-url-parse'); | const gitUrlParse = require('git-url-parse'); | ||||||
|  | const hostedGitInfo = require('hosted-git-info'); | ||||||
|  | const {verifyAuth} = require('./git'); | ||||||
| 
 | 
 | ||||||
| const GIT_TOKENS = ['GIT_CREDENTIALS', 'GH_TOKEN', 'GITHUB_TOKEN', 'GL_TOKEN', 'GITLAB_TOKEN']; | const GIT_TOKENS = ['GIT_CREDENTIALS', 'GH_TOKEN', 'GITHUB_TOKEN', 'GL_TOKEN', 'GITLAB_TOKEN']; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Generate the git repository URL with creadentials. |  * Determine the the git repository URL to use to push, either: | ||||||
|  * If the `gitCredentials` is defined, returns a http or https URL with Basic Authentication (`https://username:passowrd@hostname:port/path.git`). |  * - The `repositoryUrl` as is if allowed to push | ||||||
|  * If the `gitCredentials` is undefined, returns the `repositoryUrl`. In that case it's expected for the user to have setup the Git authentication on the CI (for example via SSH keys). |  * - The `repositoryUrl` converted to `https` or `http` with Basic Authentication | ||||||
|  * |  * | ||||||
|  * @param {String} gitCredentials Basic HTTP Authentication credentials, can be `username:password` or a token for certain Git providers. |  * In addition, expand shortcut URLs (`owner/repo` => `https://github.com/owner/repo.git`) and transform `git+https` / `git+http` URLs to `https` / `http`. | ||||||
|  * @param {String}  repositoryUrl The git repository URL. |  * | ||||||
|  |  * @param {String}  repositoryUrl The user provided Git repository URL. | ||||||
|  * @return {String} The formatted Git repository URL. |  * @return {String} The formatted Git repository URL. | ||||||
|  */ |  */ | ||||||
| module.exports = repositoryUrl => { | module.exports = async ({repositoryUrl, branch}) => { | ||||||
|  |   if (repositoryUrl) { | ||||||
|  |     const info = hostedGitInfo.fromUrl(repositoryUrl, {noGitPlus: true}); | ||||||
|  | 
 | ||||||
|  |     if (info && info.getDefaultRepresentation() === 'shortcut') { | ||||||
|  |       // Expand shorthand URLs (such as `owner/repo` or `gitlab:owner/repo`)
 | ||||||
|  |       repositoryUrl = info.https(); | ||||||
|  |     } else { | ||||||
|  |       const {protocols} = gitUrlParse(repositoryUrl); | ||||||
|  | 
 | ||||||
|  |       // Replace `git+https` and `git+http` with `https` or `http`
 | ||||||
|  |       if (protocols.includes('http') || protocols.includes('https')) { | ||||||
|  |         repositoryUrl = format({ | ||||||
|  |           ...parse(repositoryUrl), | ||||||
|  |           ...{protocol: protocols.includes('https') ? 'https' : 'http'}, | ||||||
|  |         }); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     // Test if push is allowed without transforming the URL (e.g. is ssh keys are set up)
 | ||||||
|  |     if (!await verifyAuth(repositoryUrl, branch)) { | ||||||
|       const envVar = GIT_TOKENS.find(envVar => !isUndefined(process.env[envVar])); |       const envVar = GIT_TOKENS.find(envVar => !isUndefined(process.env[envVar])); | ||||||
|       const gitCredentials = ['GL_TOKEN', 'GITLAB_TOKEN'].includes(envVar) |       const gitCredentials = ['GL_TOKEN', 'GITLAB_TOKEN'].includes(envVar) | ||||||
|         ? `gitlab-ci-token:${process.env[envVar]}` |         ? `gitlab-ci-token:${process.env[envVar]}` | ||||||
|         : process.env[envVar]; |         : process.env[envVar]; | ||||||
| 
 |  | ||||||
|       const {protocols} = gitUrlParse(repositoryUrl); |       const {protocols} = gitUrlParse(repositoryUrl); | ||||||
|       const protocol = protocols.includes('https') ? 'https' : protocols.includes('http') ? 'http' : 'https'; |       const protocol = protocols.includes('https') ? 'https' : protocols.includes('http') ? 'http' : 'https'; | ||||||
| 
 | 
 | ||||||
|   if (!gitCredentials) { |       // If credentials are set via anvironment variables, convert the URL to http/https and add basic auth, otherwise return `repositoryUrl` as is
 | ||||||
|     return protocols.includes('https') ? `${gitUrlParse(repositoryUrl).toString(protocol)}.git` : repositoryUrl; |       return gitCredentials | ||||||
|  |         ? format({...parse(`${gitUrlParse(repositoryUrl).toString(protocol)}.git`), ...{auth: gitCredentials}}) | ||||||
|  |         : repositoryUrl; | ||||||
|     } |     } | ||||||
| 
 |   } | ||||||
|   return format({...parse(`${gitUrlParse(repositoryUrl).toString(protocol)}.git`), ...{auth: gitCredentials}}); |   return repositoryUrl; | ||||||
| }; | }; | ||||||
|  | |||||||
| @ -35,6 +35,7 @@ | |||||||
|     "git-log-parser": "^1.2.0", |     "git-log-parser": "^1.2.0", | ||||||
|     "git-url-parse": "^8.1.0", |     "git-url-parse": "^8.1.0", | ||||||
|     "hook-std": "^0.4.0", |     "hook-std": "^0.4.0", | ||||||
|  |     "hosted-git-info": "^2.6.0", | ||||||
|     "lodash": "^4.17.4", |     "lodash": "^4.17.4", | ||||||
|     "marked": "^0.3.9", |     "marked": "^0.3.9", | ||||||
|     "marked-terminal": "^2.0.0", |     "marked-terminal": "^2.0.0", | ||||||
|  | |||||||
| @ -32,12 +32,12 @@ test.afterEach.always(() => { | |||||||
| 
 | 
 | ||||||
| test.serial('Default values, reading repositoryUrl from package.json', async t => { | test.serial('Default values, reading repositoryUrl from package.json', async t => { | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |   process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|   const pkg = {repository: 'https://package.com/owner/module.git'}; |   const pkg = {repository: 'https://host.null/owner/package.git'}; | ||||||
|   // Create a git repository, set the current working directory at the root of the repo
 |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|   await gitRepo(); |   await gitRepo(); | ||||||
|   await gitCommits(['First']); |   await gitCommits(['First']); | ||||||
|   // Add remote.origin.url config
 |   // Add remote.origin.url config
 | ||||||
|   await gitAddConfig('remote.origin.url', 'git@repo.com:owner/module.git'); |   await gitAddConfig('remote.origin.url', 'git@host.null:owner/repo.git'); | ||||||
|   // Create package.json in repository root
 |   // Create package.json in repository root
 | ||||||
|   await outputJson('./package.json', pkg); |   await outputJson('./package.json', pkg); | ||||||
| 
 | 
 | ||||||
| @ -45,7 +45,7 @@ test.serial('Default values, reading repositoryUrl from package.json', async t = | |||||||
| 
 | 
 | ||||||
|   // Verify the default options are set
 |   // Verify the default options are set
 | ||||||
|   t.is(options.branch, 'master'); |   t.is(options.branch, 'master'); | ||||||
|   t.is(options.repositoryUrl, 'https://user:pass@package.com/owner/module.git'); |   t.is(options.repositoryUrl, 'https://user:pass@host.null/owner/package.git'); | ||||||
|   t.is(options.tagFormat, `v\${version}`); |   t.is(options.tagFormat, `v\${version}`); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| @ -54,19 +54,19 @@ test.serial('Default values, reading repositoryUrl from repo if not set in packa | |||||||
|   // Create a git repository, set the current working directory at the root of the repo
 |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|   await gitRepo(); |   await gitRepo(); | ||||||
|   // Add remote.origin.url config
 |   // Add remote.origin.url config
 | ||||||
|   await gitAddConfig('remote.origin.url', 'https://hostname.com/owner/module.git'); |   await gitAddConfig('remote.origin.url', 'https://host.null/owner/module.git'); | ||||||
| 
 | 
 | ||||||
|   const {options} = await t.context.getConfig(); |   const {options} = await t.context.getConfig(); | ||||||
| 
 | 
 | ||||||
|   // Verify the default options are set
 |   // Verify the default options are set
 | ||||||
|   t.is(options.branch, 'master'); |   t.is(options.branch, 'master'); | ||||||
|   t.is(options.repositoryUrl, 'https://user:pass@hostname.com/owner/module.git'); |   t.is(options.repositoryUrl, 'https://user:pass@host.null/owner/module.git'); | ||||||
|   t.is(options.tagFormat, `v\${version}`); |   t.is(options.tagFormat, `v\${version}`); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Default values, reading repositoryUrl (http url) from package.json if not set in repo', async t => { | test.serial('Default values, reading repositoryUrl (http url) from package.json if not set in repo', async t => { | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |   process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|   const pkg = {repository: 'https://hostname.com/owner/module.git'}; |   const pkg = {repository: 'https://host.null/owner/module.git'}; | ||||||
|   // Create a git repository, set the current working directory at the root of the repo
 |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|   await gitRepo(); |   await gitRepo(); | ||||||
|   // Create package.json in repository root
 |   // Create package.json in repository root
 | ||||||
| @ -76,10 +76,45 @@ test.serial('Default values, reading repositoryUrl (http url) from package.json | |||||||
| 
 | 
 | ||||||
|   // Verify the default options are set
 |   // Verify the default options are set
 | ||||||
|   t.is(options.branch, 'master'); |   t.is(options.branch, 'master'); | ||||||
|   t.is(options.repositoryUrl, 'https://user:pass@hostname.com/owner/module.git'); |   t.is(options.repositoryUrl, 'https://user:pass@host.null/owner/module.git'); | ||||||
|   t.is(options.tagFormat, `v\${version}`); |   t.is(options.tagFormat, `v\${version}`); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
|  | test.serial('Default values, reading repositoryUrl (shorthand url) from package.json if not set in repo', async t => { | ||||||
|  |   process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|  |   const pkg = {repository: 'owner/module'}; | ||||||
|  |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|  |   await gitRepo(); | ||||||
|  |   // Create package.json in repository root
 | ||||||
|  |   await outputJson('./package.json', pkg); | ||||||
|  | 
 | ||||||
|  |   const {options} = await t.context.getConfig(); | ||||||
|  | 
 | ||||||
|  |   // Verify the default options are set
 | ||||||
|  |   t.is(options.branch, 'master'); | ||||||
|  |   t.is(options.repositoryUrl, 'https://user:pass@github.com/owner/module.git'); | ||||||
|  |   t.is(options.tagFormat, `v\${version}`); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test.serial( | ||||||
|  |   'Default values, reading repositoryUrl (gitlab shorthand url) from package.json if not set in repo', | ||||||
|  |   async t => { | ||||||
|  |     process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|  |     const pkg = {repository: 'gitlab:owner/module'}; | ||||||
|  |     // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|  |     await gitRepo(); | ||||||
|  |     // Create package.json in repository root
 | ||||||
|  |     await outputJson('./package.json', pkg); | ||||||
|  | 
 | ||||||
|  |     const {options} = await t.context.getConfig(); | ||||||
|  | 
 | ||||||
|  |     // Verify the default options are set
 | ||||||
|  |     t.is(options.branch, 'master'); | ||||||
|  |     t.is(options.repositoryUrl, 'https://user:pass@gitlab.com/owner/module.git'); | ||||||
|  |     t.is(options.tagFormat, `v\${version}`); | ||||||
|  |   } | ||||||
|  | ); | ||||||
|  | 
 | ||||||
| test.serial('Do not add git credential to repositoryUrl if push is allowed', async t => { | test.serial('Do not add git credential to repositoryUrl if push is allowed', async t => { | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |   process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|   // Create a git repository, set the current working directory at the root of the repo
 |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
| @ -98,7 +133,7 @@ test.serial('Read options from package.json', async t => { | |||||||
|     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, |     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, | ||||||
|     generateNotes: 'generateNotes', |     generateNotes: 'generateNotes', | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -119,7 +154,7 @@ test.serial('Read options from .releaserc.yml', async t => { | |||||||
|   const release = { |   const release = { | ||||||
|     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, |     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -140,7 +175,7 @@ test.serial('Read options from .releaserc.json', async t => { | |||||||
|   const release = { |   const release = { | ||||||
|     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, |     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -161,7 +196,7 @@ test.serial('Read options from .releaserc.js', async t => { | |||||||
|   const release = { |   const release = { | ||||||
|     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, |     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -182,7 +217,7 @@ test.serial('Read options from release.config.js', async t => { | |||||||
|   const release = { |   const release = { | ||||||
|     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, |     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -210,7 +245,7 @@ test.serial('Prioritise CLI/API parameters over file configuration and git repo' | |||||||
|     repositoryUrl: 'http://cli-url.com/owner/package', |     repositoryUrl: 'http://cli-url.com/owner/package', | ||||||
|     tagFormat: `cli\${version}`, |     tagFormat: `cli\${version}`, | ||||||
|   }; |   }; | ||||||
|   const pkg = {release, repository: 'git@hostname.com:owner/module.git'}; |   const pkg = {release, repository: 'git@host.null:owner/module.git'}; | ||||||
|   // Create a git repository, set the current working directory at the root of the repo
 |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|   const repo = await gitRepo(); |   const repo = await gitRepo(); | ||||||
|   await gitCommits(['First']); |   await gitCommits(['First']); | ||||||
| @ -233,7 +268,7 @@ test.serial('Read configuration from file path in "extends"', async t => { | |||||||
|     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, |     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, | ||||||
|     generateNotes: 'generateNotes', |     generateNotes: 'generateNotes', | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -261,7 +296,7 @@ test.serial('Read configuration from module path in "extends"', async t => { | |||||||
|     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, |     analyzeCommits: {path: 'analyzeCommits', param: 'analyzeCommits_param'}, | ||||||
|     generateNotes: 'generateNotes', |     generateNotes: 'generateNotes', | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -289,7 +324,7 @@ test.serial('Read configuration from an array of paths in "extends"', async t => | |||||||
|     verifyRelease: 'verifyRelease1', |     verifyRelease: 'verifyRelease1', | ||||||
|     analyzeCommits: {path: 'analyzeCommits1', param: 'analyzeCommits_param1'}, |     analyzeCommits: {path: 'analyzeCommits1', param: 'analyzeCommits_param1'}, | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|   const shareable2 = { |   const shareable2 = { | ||||||
| @ -334,7 +369,7 @@ test.serial('Prioritize configuration from config file over "extends"', async t | |||||||
|     generateNotes: 'generateNotesShareable', |     generateNotes: 'generateNotesShareable', | ||||||
|     publish: [{path: 'publishShareable', param: 'publishShareable_param'}], |     publish: [{path: 'publishShareable', param: 'publishShareable_param'}], | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|     tagFormat: `v\${version}`, |     tagFormat: `v\${version}`, | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
| @ -362,7 +397,7 @@ test.serial('Prioritize configuration from cli/API options over "extends"', asyn | |||||||
|     extends: './shareable2.json', |     extends: './shareable2.json', | ||||||
|     branch: 'branch_opts', |     branch: 'branch_opts', | ||||||
|     publish: [{path: 'publishOpts', param: 'publishOpts_param'}], |     publish: [{path: 'publishOpts', param: 'publishOpts_param'}], | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|   }; |   }; | ||||||
|   const release = { |   const release = { | ||||||
|     extends: './shareable1.json', |     extends: './shareable1.json', | ||||||
| @ -375,7 +410,7 @@ test.serial('Prioritize configuration from cli/API options over "extends"', asyn | |||||||
|     generateNotes: 'generateNotesShareable1', |     generateNotes: 'generateNotesShareable1', | ||||||
|     publish: [{path: 'publishShareable', param: 'publishShareable_param1'}], |     publish: [{path: 'publishShareable', param: 'publishShareable_param1'}], | ||||||
|     branch: 'test_branch1', |     branch: 'test_branch1', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|   }; |   }; | ||||||
|   const shareable2 = { |   const shareable2 = { | ||||||
|     analyzeCommits: 'analyzeCommits2', |     analyzeCommits: 'analyzeCommits2', | ||||||
| @ -404,7 +439,7 @@ test.serial('Allow to unset properties defined in shareable config with "null"', | |||||||
|     extends: './shareable.json', |     extends: './shareable.json', | ||||||
|     analyzeCommits: null, |     analyzeCommits: null, | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|   }; |   }; | ||||||
|   const shareable = { |   const shareable = { | ||||||
|     generateNotes: 'generateNotes', |     generateNotes: 'generateNotes', | ||||||
| @ -438,7 +473,7 @@ test.serial('Allow to unset properties defined in shareable config with "undefin | |||||||
|     extends: './shareable.json', |     extends: './shareable.json', | ||||||
|     analyzeCommits: undefined, |     analyzeCommits: undefined, | ||||||
|     branch: 'test_branch', |     branch: 'test_branch', | ||||||
|     repositoryUrl: 'https://hostname.com/owner/module.git', |     repositoryUrl: 'https://host.null/owner/module.git', | ||||||
|   }; |   }; | ||||||
|   const shareable = { |   const shareable = { | ||||||
|     generateNotes: 'generateNotes', |     generateNotes: 'generateNotes', | ||||||
|  | |||||||
| @ -1,105 +1,157 @@ | |||||||
| import test from 'ava'; | import test from 'ava'; | ||||||
| import getAuthUrl from '../lib/get-git-auth-url'; | import getAuthUrl from '../lib/get-git-auth-url'; | ||||||
|  | import {gitRepo} from './helpers/git-utils'; | ||||||
| 
 | 
 | ||||||
| // Save the current process.env
 | // Save the current process.env
 | ||||||
| const envBackup = Object.assign({}, process.env); | const envBackup = Object.assign({}, process.env); | ||||||
|  | // Save the current working diretory
 | ||||||
|  | const cwd = process.cwd(); | ||||||
| 
 | 
 | ||||||
| test.beforeEach(() => { | test.beforeEach(() => { | ||||||
|   // Restore process.env
 |   delete process.env.GIT_CREDENTIALS; | ||||||
|   process.env = {}; |   delete process.env.GH_TOKEN; | ||||||
|  |   delete process.env.GITHUB_TOKEN; | ||||||
|  |   delete process.env.GL_TOKEN; | ||||||
|  |   delete process.env.GITLAB_TOKEN; | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.afterEach.always(() => { | test.afterEach.always(() => { | ||||||
|   // Restore process.env
 |   // Restore process.env
 | ||||||
|   process.env = envBackup; |   process.env = envBackup; | ||||||
|  |   // Restore the current working directory
 | ||||||
|  |   process.chdir(cwd); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Return the same "git" formatted URL if "gitCredentials" is not defined', t => { | test.serial('Return the same "git" formatted URL if "gitCredentials" is not defined', async t => { | ||||||
|   t.is(getAuthUrl('git@host.com:owner/repo.git'), 'git@host.com:owner/repo.git'); |   t.is(await getAuthUrl({repositoryUrl: 'git@host.null:owner/repo.git'}), 'git@host.null:owner/repo.git'); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Return the same "https" formatted URL if "gitCredentials" is not defined', t => { | test.serial('Return the same "https" formatted URL if "gitCredentials" is not defined', async t => { | ||||||
|   t.is(getAuthUrl('https://host.com/owner/repo.git'), 'https://host.com/owner/repo.git'); |   t.is(await getAuthUrl({repositoryUrl: 'https://host.null/owner/repo.git'}), 'https://host.null/owner/repo.git'); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial( | test.serial( | ||||||
|   'Return the "https" formatted URL if "gitCredentials" is not defined and repositoryUrl is a "git+https" URL', |   'Return the "https" formatted URL if "gitCredentials" is not defined and repositoryUrl is a "git+https" URL', | ||||||
|   t => { |   async t => { | ||||||
|     t.is(getAuthUrl('git+https://host.com/owner/repo.git'), 'https://host.com/owner/repo.git'); |     t.is(await getAuthUrl({repositoryUrl: 'git+https://host.null/owner/repo.git'}), 'https://host.null/owner/repo.git'); | ||||||
|   } |   } | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| test.serial('Handle "https" URL with group and subgroup', t => { | test.serial('Handle "https" URL with group and subgroup', async t => { | ||||||
|   t.is(getAuthUrl('https://host.com/group/subgroup/owner/repo.git'), 'https://host.com/group/subgroup/owner/repo.git'); |   t.is( | ||||||
|  |     await getAuthUrl({repositoryUrl: 'https://host.null/group/subgroup/owner/repo.git'}), | ||||||
|  |     'https://host.null/group/subgroup/owner/repo.git' | ||||||
|  |   ); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Handle "git" URL with group and subgroup', t => { | test.serial('Handle "git" URL with group and subgroup', async t => { | ||||||
|   t.is(getAuthUrl('git@host.com:group/subgroup/owner/repo.git'), 'git@host.com:group/subgroup/owner/repo.git'); |   t.is( | ||||||
| }); |     await getAuthUrl({repositoryUrl: 'git@host.null:group/subgroup/owner/repo.git'}), | ||||||
| 
 |     'git@host.null:group/subgroup/owner/repo.git' | ||||||
| test.serial('Return the "https" formatted URL if "gitCredentials" is defined and repositoryUrl is a "git" URL', t => { |   ); | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |  | ||||||
|   t.is(getAuthUrl('git@host.com:owner/repo.git'), 'https://user:pass@host.com/owner/repo.git'); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| test.serial('Return the "https" formatted URL if "gitCredentials" is defined and repositoryUrl is a "https" URL', t => { |  | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |  | ||||||
|   t.is(getAuthUrl('https://host.com/owner/repo.git'), 'https://user:pass@host.com/owner/repo.git'); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| test.serial('Return the "http" formatted URL if "gitCredentials" is defined and repositoryUrl is a "http" URL', t => { |  | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |  | ||||||
|   t.is(getAuthUrl('http://host.com/owner/repo.git'), 'http://user:pass@host.com/owner/repo.git'); |  | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial( | test.serial( | ||||||
|   'Return the "https" formatted URL if "gitCredentials" is defined and repositoryUrl is a "git+https" URL', |   'Return the "https" formatted URL if "gitCredentials" is defined and repositoryUrl is a "git" URL', | ||||||
|   t => { |   async t => { | ||||||
|     process.env.GIT_CREDENTIALS = 'user:pass'; |     process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|     t.is(getAuthUrl('git+https://host.com/owner/repo.git'), 'https://user:pass@host.com/owner/repo.git'); |     t.is( | ||||||
|  |       await getAuthUrl({repositoryUrl: 'git@host.null:owner/repo.git'}), | ||||||
|  |       'https://user:pass@host.null/owner/repo.git' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | test.serial( | ||||||
|  |   'Return the "https" formatted URL if "gitCredentials" is defined and repositoryUrl is a "https" URL', | ||||||
|  |   async t => { | ||||||
|  |     process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|  |     t.is( | ||||||
|  |       await getAuthUrl({repositoryUrl: 'https://host.null/owner/repo.git'}), | ||||||
|  |       'https://user:pass@host.null/owner/repo.git' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | test.serial( | ||||||
|  |   'Return the "http" formatted URL if "gitCredentials" is defined and repositoryUrl is a "http" URL', | ||||||
|  |   async t => { | ||||||
|  |     process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|  |     t.is( | ||||||
|  |       await getAuthUrl({repositoryUrl: 'http://host.null/owner/repo.git'}), | ||||||
|  |       'http://user:pass@host.null/owner/repo.git' | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | ); | ||||||
|  | 
 | ||||||
|  | test.serial( | ||||||
|  |   'Return the "https" formatted URL if "gitCredentials" is defined and repositoryUrl is a "git+https" URL', | ||||||
|  |   async t => { | ||||||
|  |     process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|  |     t.is( | ||||||
|  |       await getAuthUrl({repositoryUrl: 'git+https://host.null/owner/repo.git'}), | ||||||
|  |       'https://user:pass@host.null/owner/repo.git' | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| test.serial( | test.serial( | ||||||
|   'Return the "http" formatted URL if "gitCredentials" is defined and repositoryUrl is a "git+http" URL', |   'Return the "http" formatted URL if "gitCredentials" is defined and repositoryUrl is a "git+http" URL', | ||||||
|   t => { |   async t => { | ||||||
|     process.env.GIT_CREDENTIALS = 'user:pass'; |     process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|     t.is(getAuthUrl('git+http://host.com/owner/repo.git'), 'http://user:pass@host.com/owner/repo.git'); |     t.is( | ||||||
|  |       await getAuthUrl({repositoryUrl: 'git+http://host.null/owner/repo.git'}), | ||||||
|  |       'http://user:pass@host.null/owner/repo.git' | ||||||
|  |     ); | ||||||
|   } |   } | ||||||
| ); | ); | ||||||
| 
 | 
 | ||||||
| test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GH_TOKEN"', t => { | test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GH_TOKEN"', async t => { | ||||||
|   process.env.GH_TOKEN = 'token'; |   process.env.GH_TOKEN = 'token'; | ||||||
|   t.is(getAuthUrl('git@host.com:owner/repo.git'), 'https://token@host.com/owner/repo.git'); |   t.is(await getAuthUrl({repositoryUrl: 'git@host.null:owner/repo.git'}), 'https://token@host.null/owner/repo.git'); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GITHUB_TOKEN"', t => { | test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GITHUB_TOKEN"', async t => { | ||||||
|   process.env.GITHUB_TOKEN = 'token'; |   process.env.GITHUB_TOKEN = 'token'; | ||||||
|   t.is(getAuthUrl('git@host.com:owner/repo.git'), 'https://token@host.com/owner/repo.git'); |   t.is(await getAuthUrl({repositoryUrl: 'git@host.null:owner/repo.git'}), 'https://token@host.null/owner/repo.git'); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GL_TOKEN"', t => { | test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GL_TOKEN"', async t => { | ||||||
|   process.env.GL_TOKEN = 'token'; |   process.env.GL_TOKEN = 'token'; | ||||||
|   t.is(getAuthUrl('git@host.com:owner/repo.git'), 'https://gitlab-ci-token:token@host.com/owner/repo.git'); |   t.is( | ||||||
|  |     await getAuthUrl({repositoryUrl: 'git@host.null:owner/repo.git'}), | ||||||
|  |     'https://gitlab-ci-token:token@host.null/owner/repo.git' | ||||||
|  |   ); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GITLAB_TOKEN"', t => { | test.serial('Return the "https" formatted URL if "gitCredentials" is defined with "GITLAB_TOKEN"', async t => { | ||||||
|   process.env.GITLAB_TOKEN = 'token'; |   process.env.GITLAB_TOKEN = 'token'; | ||||||
|   t.is(getAuthUrl('git@host.com:owner/repo.git'), 'https://gitlab-ci-token:token@host.com/owner/repo.git'); |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| test.serial('Handle "https" URL with group and subgroup, with "GIT_CREDENTIALS"', t => { |  | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |  | ||||||
|   t.is( |   t.is( | ||||||
|     getAuthUrl('https://host.com/group/subgroup/owner/repo.git'), |     await getAuthUrl({repositoryUrl: 'git@host.null:owner/repo.git'}), | ||||||
|     'https://user:pass@host.com/group/subgroup/owner/repo.git' |     'https://gitlab-ci-token:token@host.null/owner/repo.git' | ||||||
|   ); |   ); | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| test.serial('Handle "git" URL with group and subgroup, with "GIT_CREDENTIALS', t => { | test.serial('Handle "https" URL with group and subgroup, with "GIT_CREDENTIALS"', async t => { | ||||||
|   process.env.GIT_CREDENTIALS = 'user:pass'; |   process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|   t.is( |   t.is( | ||||||
|     getAuthUrl('git@host.com:group/subgroup/owner/repo.git'), |     await getAuthUrl({repositoryUrl: 'https://host.null/group/subgroup/owner/repo.git'}), | ||||||
|     'https://user:pass@host.com/group/subgroup/owner/repo.git' |     'https://user:pass@host.null/group/subgroup/owner/repo.git' | ||||||
|   ); |   ); | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
|  | test.serial('Handle "git" URL with group and subgroup, with "GIT_CREDENTIALS', async t => { | ||||||
|  |   process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|  |   t.is( | ||||||
|  |     await getAuthUrl({repositoryUrl: 'git@host.null:group/subgroup/owner/repo.git'}), | ||||||
|  |     'https://user:pass@host.null/group/subgroup/owner/repo.git' | ||||||
|  |   ); | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | test.serial('Do not add git credential to repositoryUrl if push is allowed', async t => { | ||||||
|  |   process.env.GIT_CREDENTIALS = 'user:pass'; | ||||||
|  |   // Create a git repository, set the current working directory at the root of the repo
 | ||||||
|  |   const repositoryUrl = await gitRepo(true); | ||||||
|  | 
 | ||||||
|  |   t.is(await getAuthUrl({repositoryUrl}), repositoryUrl); | ||||||
|  | }); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user