diff --git a/index.js b/index.js index 1352394..00e1d54 100644 --- a/index.js +++ b/index.js @@ -37,7 +37,7 @@ function parse(str) { // Stash, aka Bitbucket Server. https://www.atlassian.com/software/bitbucket/server // We look for a git@ URL not pointing at bitbucket.org/bitbucket.com, or for a HTTP/HTTPS URL that isn't pointing to - // bitbucket.com/bitbucket.org and that has a path that starts with /projects/ + // bitbucket.com/bitbucket.org and that has a path that contains /projects/ or /scm/ var stashDetected = (str.indexOf('git@') !== -1 && str.indexOf('git@bitbucket.org') === -1 && str.indexOf('git@bitbucket.com') === -1) || @@ -45,35 +45,44 @@ function parse(str) { || (obj.hostname && !(obj.hostname.endsWith('bitbucket.org') || obj.hostname.endsWith('bitbucket.com')) && - pathSegments[0] === 'projects'); + (pathSegments.includes('projects') || pathSegments.includes('scm'))); + + var stashPathOffset = 0; + if (stashDetected) { + stashPathOffset = pathSegments.indexOf('projects'); + if (stashPathOffset == -1) { + stashPathOffset = pathSegments.indexOf('scm'); + } + stashPathOffset = stashPathOffset > 0 ? stashPathOffset : 0; + } // TODO: This is too spaghetti.. rewrite this to be understandable, separate Bitbucket Server/Bitbucket Cloud paths, // SSH/git paths, etc if (stashDetected) { // Stash mode - if (str.indexOf('git@') === -1 && pathSegments[0] !== 'scm') { + if (str.indexOf('git@') === -1 && pathSegments[0 + stashPathOffset] !== 'scm') { if (pathSegments.length > 1) { - obj.owner = owner(pathSegments[1]); + obj.owner = owner(pathSegments[1 + stashPathOffset]); } else { obj.owner = null; } - if (pathSegments.length > 3 && pathSegments[2] === 'repos') { - obj.name = name(pathSegments[3]); + if (pathSegments.length > 3 && pathSegments[2 + stashPathOffset] === 'repos') { + obj.name = name(pathSegments[3 + stashPathOffset]); } else { obj.name = null; } } else { - if (pathSegments.length === 3) { - if (pathSegments[0] !== 'scm') { - obj.host = pathSegments[0].replace('git@', ''); + if (pathSegments.length - stashPathOffset === 3) { + if (pathSegments[0 + stashPathOffset] !== 'scm') { + obj.host = pathSegments[0 + stashPathOffset].replace('git@', ''); } - obj.owner = owner(pathSegments[1]); - obj.name = name(pathSegments[2]); + obj.owner = owner(pathSegments[1 + stashPathOffset]); + obj.name = name(pathSegments[2 + stashPathOffset]); } else { - obj.owner = owner(pathSegments[0]); - obj.name = name(pathSegments[1]); + obj.owner = owner(pathSegments[0 + stashPathOffset]); + obj.name = name(pathSegments[1 + stashPathOffset]); } } } else { @@ -82,7 +91,7 @@ function parse(str) { obj.name = name(pathSegments[1]); } - if (pathSegments.length > 1 && obj.owner && obj.name) { + if (pathSegments.length > 1 + stashPathOffset && obj.owner && obj.name) { obj.repo = obj.owner + '/' + obj.name; } else { var href = obj.href.split(':'); @@ -109,21 +118,21 @@ function parse(str) { } } - if (pathSegments.length >= 3) { + if (pathSegments.length >= 3 + stashPathOffset) { switch(pathSegments[2]){ case 'get': // Look at seg[3] for a file name, which will be the branch/tag name // NOTE: tags and branches are treated alike in Bitbucket and cannot be distinguished by URL. // We'll treat everything like branches. var fileName = null; - if (pathSegments[3].endsWith('.tar.gz')) { - fileName = pathSegments[3].replace('.tar.gz', ''); + if (pathSegments[3 + stashPathOffset].endsWith('.tar.gz')) { + fileName = pathSegments[3+ stashPathOffset].replace('.tar.gz', ''); } - if (pathSegments[3].endsWith('.tar.bz2')) { - fileName = pathSegments[3].replace('.tar.bz2', ''); + if (pathSegments[3+ stashPathOffset].endsWith('.tar.bz2')) { + fileName = pathSegments[3+ stashPathOffset].replace('.tar.bz2', ''); } - if (pathSegments[3].endsWith('.zip')) { - fileName = pathSegments[3].replace('.zip', ''); + if (pathSegments[3+ stashPathOffset].endsWith('.zip')) { + fileName = pathSegments[3+ stashPathOffset].replace('.zip', ''); } obj.branch = fileName; @@ -134,11 +143,11 @@ function parse(str) { break; case 'raw':// support file location. Bitbucket support two file modes:raw and src. This is only for bitbuket and not Bitbucket Server case 'src':// todo: support bitbucket server file location - if(pathSegments.length < 5){ + if(pathSegments.length < 5 + stashPathOffset){ // no file location break; } - var filepath = pathSegments.slice(4); + var filepath = pathSegments.slice(4 + stashPathOffset); if(filepath.length){ var file = filepath[filepath.length - 1]; file = file.split('?')[0]; //remove the query params diff --git a/test.js b/test.js index dc6ef1b..8493814 100644 --- a/test.js +++ b/test.js @@ -274,4 +274,30 @@ describe('parse-bitbucket-url', function() { assert.equal(bb('https://itai@stash-internal.codefresh.io/scm/cod/more-proj.git').host, 'stash-internal.codefresh.io'); assert.equal(bb('https://itai@stash-internal.codefresh.io/scm/cod/more-proj.git').repo, 'cod/more-proj'); }); + + it('should work with sub path Bitbucket Server URLs:', function() { + assert.equal(bb('https://stash.one.two/stashinstance/projects/KEY/repos/name1/browse').owner, 'KEY'); + assert.equal(bb('https://stash.one.two/stashinstance/projects/ONE/repos/name2/browse').owner, 'ONE'); + assert.equal(bb('https://stash.one.two/stashinstance/projects/ABC/repos/name3/commits/a1aa8e5c5b99002396d449c1bdd4d6946303bbc3').name, 'name3'); + assert.equal(bb('https://stash.one.two/stashinstance/projects/DEF/repos/na-me4/commits').name, 'na-me4'); + assert.equal(bb('https://bitbucketserver.one.two/stashinstance/projects/GHI/repos/name5/compare/commits?sourceBranch=refs%2Fheads%2Fmaster&targetBranch=refs%2Fheads%2Fbugfix%2Fdevelop').repo, 'GHI/name5'); + assert.equal(bb('https://stash.one.two/stashinstance/projects/JKL/repos/nam-e6/branches').repo, 'JKL/nam-e6'); + assert.equal(bb('https://internal.one.two:2034/stashinstance/projects/MNOPQ/repos/name7/pull-requests').host, 'internal.one.two:2034'); + assert.equal(bb('https://stash-internal.my.company:3333/stashinstance/projects/KEY/repos/name1/browse/README.md?at=refs%2Fheads%2Fbranch333').host, 'stash-internal.my.company:3333'); + assert.equal(bb('https://advance512@stash-internal.my.company/stashinstance/scm/a-key/a-project.git').branch, 'master'); + assert.equal(bb('https://stash-internal.my.company:3333/stashinstance/projects/KEY/repos/name1/browse/README.md?at=refs%2Fheads%2Fbranch333').branch, 'branch333'); + assert.equal(bb('https://stash.one.two/stashinstance/projects/KEY').owner, 'KEY'); + assert.equal(bb('https://stash.one.two/stashinstance/projects/KEY').name, null); + assert.equal(bb('https://stash.one.two/stashinstance/projects/KEY').repo, null); + assert.equal(bb('https://stash.one.two/stashinstance/projects/KEY/repos').owner, 'KEY'); + assert.equal(bb('https://stash.one.two/stashinstance/projects/KEY/repos/').name, null); + assert.equal(bb('https://stash.one.two/stashinstance/projects/KEY/repos/').repo, null); + + + assert.equal(bb('https://itai@stash-internal.codefresh.io/stashinstance/scm/cod/more-proj.git').owner, 'cod'); + assert.equal(bb('https://itai@stash-internal.codefresh.io/stashinstance/scm/cod/more-proj.git').name, 'more-proj'); + assert.equal(bb('https://itai@stash-internal.codefresh.io/stashinstance/scm/cod/more-proj.git').host, 'stash-internal.codefresh.io'); + assert.equal(bb('https://itai@stash-internal.codefresh.io/stashinstance/scm/cod/more-proj.git').repo, 'cod/more-proj'); + + }); });