From fb48b0e4335f3083db4dc7ea81aa8adb60c059c7 Mon Sep 17 00:00:00 2001 From: SatowTakeshi Date: Tue, 12 Nov 2019 07:38:56 +0900 Subject: [PATCH 1/3] Support Sourcehut --- git-host-info.js | 7 + test/fixtures/sourcehut.js | 99 +++++++++++++ test/sourcehut.js | 278 +++++++++++++++++++++++++++++++++++++ 3 files changed, 384 insertions(+) create mode 100644 test/fixtures/sourcehut.js create mode 100644 test/sourcehut.js diff --git a/git-host-info.js b/git-host-info.js index 8147e33..c15d673 100644 --- a/git-host-info.js +++ b/git-host-info.js @@ -27,6 +27,13 @@ var gitHosts = module.exports = { 'tarballtemplate': 'https://{domain}/{user}/{project}/repository/archive.tar.gz?ref={committish}', 'pathmatch': /^[/]([^/]+)[/]((?!.*(\/-\/|\/repository\/archive\.tar\.gz\?=.*|\/repository\/[^/]+\/archive.tar.gz$)).*?)(?:[.]git|[/])?$/ }, + sourcehut: { + 'protocols': [ 'git+ssh', 'git+https', 'ssh', 'https' ], + 'domain': 'git.sr.ht', + 'treepath': 'tree', + 'tarballtemplate': 'https://{domain}/{user}/{project}/archive/{committish}.tar.gz', + 'filetemplate': 'https://{domain}/{user}/{project}/blob/{committish}/{path}' + }, gist: { 'protocols': [ 'git', 'git+ssh', 'git+https', 'ssh', 'https' ], 'domain': 'gist.github.com', diff --git a/test/fixtures/sourcehut.js b/test/fixtures/sourcehut.js new file mode 100644 index 0000000..79ad561 --- /dev/null +++ b/test/fixtures/sourcehut.js @@ -0,0 +1,99 @@ +'use strcit' + +module.exports = [ + { + host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project }, + label: 'https' + }, + { + host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '.git' }, + label: 'https.git' + }, + { + host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '#' + p.branch }, + label: 'https#branch', + hasBranch: true + }, + { + host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '.git#' + p.branch }, + label: 'https.git#branch', + hasBranch: true + }, + { + host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '/archive' + '/3.3.2.tar.gz' }, + label: 'https.tar', + isUndefined: true + }, + { + host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project }, + label: 'git+https' + }, + { + host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project + '.git' }, + label: 'git+https.git' + }, + { + host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project + '#' + p.branch }, + label: 'git+https#branch', + hasBranch: true + }, + { + host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project + '.git#' + p.branch }, + label: 'git+https.git#branch', + hasBranch: true + }, + { + host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project }, + label: 'ssh' + }, + { + host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project + '.git' }, + label: 'ssh.git' + }, + { + host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project + '#' + p.branch }, + label: 'ssh#branch', + hasBranch: true + }, + { + host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project + '.git#' + p.branch }, + label: 'ssh.git#branch', + hasBranch: true + }, + { + host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project }, + label: 'ssh-url' + }, + { + host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project + '.git' }, + label: 'ssh-url.git' + }, + { + host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project + '#' + p.branch }, + label: 'ssh-url#branch', + hasBranch: true + }, + { + host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project + '.git#' + p.branch }, + label: 'ssh-url.git#branch', + hasBranch: true + }, + { + host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project }, + label: 'shortcut' + }, + { + host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project + '.git' }, + label: 'shortcut.git' + }, + { + host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project + '#' + p.branch }, + label: 'shortcut#branch', + hasBranch: true + }, + { + host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project + '.git#' + p.branch }, + label: 'shortcut.git#branch', + hasBranch: true + } +] diff --git a/test/sourcehut.js b/test/sourcehut.js new file mode 100644 index 0000000..d2ff67c --- /dev/null +++ b/test/sourcehut.js @@ -0,0 +1,278 @@ +'use strict' +var HostedGit = require('../index') +var test = require('tap').test + +var showLabel = function (label, fn) { return label + ' -> ' + fn } + +var testFixtures = function (t, params, fixtures) { + for (var i = 0; i < fixtures.length; ++i) { + var fixture = fixtures[i] + + var host = fixture.host(params) + var hostinfo = HostedGit.fromUrl(host) + + // INFO: fromUrl should return `undefined` from fixture input + if (fixture.isUndefined) { + t.test('input results in undefined', function (tt) { + tt.is(hostinfo, undefined) + tt.end() + }) + break + } + + t.test('hostinfo.https', function (tt) { + var expected = function (url, hasBranch) { + return (hasBranch) + ? url + '#' + params.branch + : url + } + tt.is( + hostinfo.https(), + expected('git+https://git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch, fixture.hasGroup), + showLabel(fixture.label, 'https') + ) + // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same + tt.is( + hostinfo.https({ noCommittish: true }), + 'git+https://git.sr.ht/~some-owner/some-repo.git', + showLabel(fixture.label, 'https({ noCommittish: true })') + ) + tt.is( + hostinfo.https({ noGitPlus: true }), + expected('https://git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch), + showLabel(fixture.label, 'https({ noGitPlus: true })') + ) + tt.end() + }) + t.test('hostinfo.browse', function (tt) { + var expected = function (url, hasBranch) { + if (hasBranch) { + if (url.indexOf('master') === -1) { + return url + '/tree/' + params.branch + } else { + return url.replace(/master/gi, params.branch) + } + } + return url + } + tt.is( + hostinfo.browse(), + expected('https://git.sr.ht/~some-owner/some-repo', fixture.hasBranch), + showLabel(fixture.label, 'browse') + ) + tt.is( + hostinfo.browse(''), + expected('https://git.sr.ht/~some-owner/some-repo/tree/master/', fixture.hasBranch), + showLabel(fixture.label, "browse('')") + ) + tt.is( + hostinfo.browse('C'), + expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C', fixture.hasBranch), + showLabel(fixture.label, "browse('C')") + ) + tt.is( + hostinfo.browse('C/D'), + expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C/D', fixture.hasBranch), + showLabel(fixture.label, "browse('C/D')") + ) + tt.is( + hostinfo.browse('C', 'A'), + expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C#a', fixture.hasBranch), + showLabel(fixture.label, "browse('C', 'A')") + ) + tt.is( + hostinfo.browse('C/D', 'A'), + expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C/D#a', fixture.hasBranch), + showLabel(fixture.label, "browse('C/D', 'A')") + ) + tt.end() + }) + t.test('hostinfo.docs', function (tt) { + var expected = function (url, hasBranch) { + if (hasBranch) { + var splitUrl = url.split('#') + return splitUrl[0] + '/tree/' + params.branch + '#' + splitUrl[1] + } + return url + } + tt.is( + hostinfo.docs(), + expected('https://git.sr.ht/~some-owner/some-repo#readme', fixture.hasBranch), + showLabel(fixture.label, 'docs') + ) + tt.is( + hostinfo.docs({ noCommittish: true }), + // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same + 'https://git.sr.ht/~some-owner/some-repo#readme', + showLabel(fixture.label, 'docs({ noCommittish: true })') + ) + tt.is( + hostinfo.docs({ noGitPlus: true }), + expected('https://git.sr.ht/~some-owner/some-repo#readme', fixture.hasBranch), + showLabel(fixture.label, 'docs({ noGitPlus: true })') + ) + tt.end() + }) + t.test('hostinfo.ssh', function (tt) { + var expected = function (url, hasBranch) { + return (hasBranch) + ? url + '#' + params.branch + : url + } + tt.is( + hostinfo.ssh(), + expected('git@git.sr.ht:~some-owner/some-repo.git', fixture.hasBranch), + showLabel(fixture.label, 'ssh') + ) + tt.is( + hostinfo.ssh({ noCommittish: true }), + // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same + 'git@git.sr.ht:~some-owner/some-repo.git', + showLabel(fixture.label, 'ssh({ noCommittish: true })') + ) + tt.is( + hostinfo.ssh({ noGitPlus: true }), + expected('git@git.sr.ht:~some-owner/some-repo.git', fixture.hasBranch), + showLabel(fixture.label, 'ssh({ noGitPlus: true })') + ) + tt.end() + }) + t.test('hostinfo.sshurl', function (tt) { + var expected = function (url, hasBranch) { + return (hasBranch) + ? url + '#' + params.branch + : url + } + tt.is( + hostinfo.sshurl(), + expected('git+ssh://git@git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch), + showLabel(fixture.label, 'sshurl') + ) + tt.is( + hostinfo.sshurl({ noCommittish: true }), + // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same + 'git+ssh://git@git.sr.ht/~some-owner/some-repo.git', + showLabel(fixture.label, 'sshurl({ noCommittish: true })') + ) + tt.is( + hostinfo.sshurl({ noGitPlus: true }), + expected('ssh://git@git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch), + showLabel(fixture.label, 'sshurl({ noGitPlus: true })') + ) + tt.end() + }) + t.test('hostinfo.shortcut', function (tt) { + var expected = function (url, hasBranch) { + return (hasBranch) + ? url + '#' + params.branch + : url + } + tt.is( + hostinfo.shortcut(), + expected('sourcehut:~some-owner/some-repo', fixture.hasBranch), + showLabel(fixture.label, 'shortcut') + ) + tt.is( + hostinfo.shortcut({ noCommittish: true }), + // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same + 'sourcehut:~some-owner/some-repo', + showLabel(fixture.label, 'shortcut({ noCommittish: true })') + ) + tt.is( + hostinfo.shortcut({ noGitPlus: true }), + expected('sourcehut:~some-owner/some-repo', fixture.hasBranch), + showLabel(fixture.label, 'shortcut({ noGitPlus: true })') + ) + tt.end() + }) + t.test('hostinfo.file', function (tt) { + var expected = function (url, hasBranch) { + return (hasBranch) + ? url.replace(/master/gi, params.branch) + : url + } + tt.is( + hostinfo.file(), + expected('https://git.sr.ht/~some-owner/some-repo/blob/master/', fixture.hasBranch), + showLabel(fixture.label, 'file') + ) + tt.is( + hostinfo.file('C'), + expected('https://git.sr.ht/~some-owner/some-repo/blob/master/C', fixture.hasBranch), + showLabel(fixture.label, "file('C')") + ) + tt.is( + hostinfo.file('C/D'), + expected('https://git.sr.ht/~some-owner/some-repo/blob/master/C/D', fixture.hasBranch), + showLabel(fixture.label, "file('C/D')") + ) + tt.end() + }) + t.test('hostinfo.tarball', function (tt) { + var expected = function (url, hasBranch) { + return (hasBranch) + ? url.replace(/master/gi, params.branch) + : url + } + tt.is( + hostinfo.tarball(), + expected('https://git.sr.ht/~some-owner/some-repo/archive/master.tar.gz', fixture.hasBranch), + showLabel(fixture.label, 'tarball') + ) + tt.is( + hostinfo.tarball({ noCommittish: true }), + expected('https://git.sr.ht/~some-owner/some-repo/archive/master.tar.gz', fixture.hasBranch), + showLabel(fixture.label, 'tarball({ noCommittish: true })') + ) + tt.is( + hostinfo.tarball({ noGitPlus: true }), + expected('https://git.sr.ht/~some-owner/some-repo/archive/master.tar.gz', fixture.hasBranch), + showLabel(fixture.label, 'tarball({ noGitPlus: true })') + ) + tt.end() + }) + } +} + +test('fromUrl(sourcehut url)', function (t) { + var fixtures = require('./fixtures/sourcehut') + + t.test('domain: git.sr.ht', function (tt) { + var params = { + domain: 'git.sr.ht', + shortname: 'sourcehut', + label: 'sourcehut', + owner: '~some-owner', + project: 'some-repo', + branch: 'feature-branch' + } + testFixtures(tt, params, fixtures) + tt.end() + }) + + t.test('Soucehub HTTPS URLs with embedded auth', function (tt) { + tt.is( + HostedGit.fromUrl('https://user:pass@git.sr.ht/user/repo.git').toString(), + 'git+https://user:pass@git.sr.ht/user/repo.git', + 'credentials were included in URL' + ) + tt.is( + HostedGit.fromUrl('https://user:pass@git.sr.ht/user/repo').toString(), + 'git+https://user:pass@git.sr.ht/user/repo.git', + 'credentials were included in URL' + ) + tt.is( + HostedGit.fromUrl('git+https://user:pass@git.sr.ht/user/repo.git').toString(), + 'git+https://user:pass@git.sr.ht/user/repo.git', + 'credentials were included in URL' + ) + tt.is( + HostedGit.fromUrl('git+https://user:pass@git.sr.ht/user/repo').toString(), + 'git+https://user:pass@git.sr.ht/user/repo.git', + 'credentials were included in URL' + ) + tt.end() + }) + + t.end() +}) From 4696acc6954fbf27050df13980e3061c0306344b Mon Sep 17 00:00:00 2001 From: satotake Date: Wed, 27 Oct 2021 00:31:42 +0900 Subject: [PATCH 2/3] rewrite --- git-host-info.js | 28 +++ test/fixtures/sourcehut.js | 99 ---------- test/sourcehut.js | 372 +++++++++++-------------------------- 3 files changed, 135 insertions(+), 364 deletions(-) delete mode 100644 test/fixtures/sourcehut.js diff --git a/git-host-info.js b/git-host-info.js index d491934..bb757a2 100644 --- a/git-host-info.js +++ b/git-host-info.js @@ -139,6 +139,34 @@ gitHosts.gist = Object.assign({}, defaults, { } }) +gitHosts.sourcehut = Object.assign({}, defaults, { + protocols: ['git+ssh:', 'https:'], + domain: 'git.sr.ht', + treepath: 'tree', + browsefiletemplate: ({ domain, user, project, committish, treepath, path, fragment, hashformat }) => `https://${domain}/${user}/${project}/${treepath}/${maybeEncode(committish || 'main')}/${path}${maybeJoin('#', hashformat(fragment || ''))}`, + filetemplate: ({ domain, user, project, committish, path }) => `https://${domain}/${user}/${project}/blob/${maybeEncode(committish) || 'main'}/${path}`, + httpstemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}.git${maybeJoin('#', committish)}`, + tarballtemplate: ({ domain, user, project, committish }) => `https://${domain}/${user}/${project}/archive/${maybeEncode(committish) || 'main'}.tar.gz`, + bugstemplate: ({ domain, user, project }) => `https://todo.sr.ht/${user}/${project}`, + docstemplate: ({ domain, user, project, treepath, committish }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}#readme`, + extract: (url) => { + let [, user, project, aux] = url.pathname.split('/', 4) + if (['get'].includes(aux)) { + return + } + + if (project && project.endsWith('.git')) { + project = project.slice(0, -4) + } + + if (!user || !project) { + return + } + + return { user, project, committish: url.hash.slice(1) } + } +}) + const names = Object.keys(gitHosts) gitHosts.byShortcut = {} gitHosts.byDomain = {} diff --git a/test/fixtures/sourcehut.js b/test/fixtures/sourcehut.js deleted file mode 100644 index 79ad561..0000000 --- a/test/fixtures/sourcehut.js +++ /dev/null @@ -1,99 +0,0 @@ -'use strcit' - -module.exports = [ - { - host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project }, - label: 'https' - }, - { - host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '.git' }, - label: 'https.git' - }, - { - host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '#' + p.branch }, - label: 'https#branch', - hasBranch: true - }, - { - host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '.git#' + p.branch }, - label: 'https.git#branch', - hasBranch: true - }, - { - host: function (p) { return 'https://' + p.domain + '/' + p.owner + '/' + p.project + '/archive' + '/3.3.2.tar.gz' }, - label: 'https.tar', - isUndefined: true - }, - { - host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project }, - label: 'git+https' - }, - { - host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project + '.git' }, - label: 'git+https.git' - }, - { - host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project + '#' + p.branch }, - label: 'git+https#branch', - hasBranch: true - }, - { - host: function (p) { return 'git+https://' + p.domain + '/' + p.owner + '/' + p.project + '.git#' + p.branch }, - label: 'git+https.git#branch', - hasBranch: true - }, - { - host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project }, - label: 'ssh' - }, - { - host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project + '.git' }, - label: 'ssh.git' - }, - { - host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project + '#' + p.branch }, - label: 'ssh#branch', - hasBranch: true - }, - { - host: function (p) { return 'git@' + p.domain + ':' + p.owner + '/' + p.project + '.git#' + p.branch }, - label: 'ssh.git#branch', - hasBranch: true - }, - { - host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project }, - label: 'ssh-url' - }, - { - host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project + '.git' }, - label: 'ssh-url.git' - }, - { - host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project + '#' + p.branch }, - label: 'ssh-url#branch', - hasBranch: true - }, - { - host: function (p) { return 'git+ssh://git@' + p.domain + '/' + p.owner + '/' + p.project + '.git#' + p.branch }, - label: 'ssh-url.git#branch', - hasBranch: true - }, - { - host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project }, - label: 'shortcut' - }, - { - host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project + '.git' }, - label: 'shortcut.git' - }, - { - host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project + '#' + p.branch }, - label: 'shortcut#branch', - hasBranch: true - }, - { - host: function (p) { return p.shortname + ':' + p.owner + '/' + p.project + '.git#' + p.branch }, - label: 'shortcut.git#branch', - hasBranch: true - } -] diff --git a/test/sourcehut.js b/test/sourcehut.js index d2ff67c..c2b9cbd 100644 --- a/test/sourcehut.js +++ b/test/sourcehut.js @@ -1,278 +1,120 @@ 'use strict' -var HostedGit = require('../index') -var test = require('tap').test +const HostedGit = require('../index') +const t = require('tap') -var showLabel = function (label, fn) { return label + ' -> ' + fn } +const invalid = [ + // missing project + 'https://git.sr.ht/~foo', + // invalid protocos + 'git://git@git.sr.ht:~foo/bar', + 'ssh://git.sr.ht:~foo/bar' +] -var testFixtures = function (t, params, fixtures) { - for (var i = 0; i < fixtures.length; ++i) { - var fixture = fixtures[i] +// assigning the constructor here is hacky, but the only way to make assertions that compare +// a subset of properties to a found object pass as you would expect +const GitHost = require('../git-host') +const defaults = { constructor: GitHost, type: 'sourcehut', user: '~foo', project: 'bar' } - var host = fixture.host(params) - var hostinfo = HostedGit.fromUrl(host) +const valid = { + // shortucts + 'sourcehut:~foo/bar': { ...defaults, default: 'shortcut' }, + 'sourcehut:~foo/bar#branch': { ...defaults, default: 'shortcut', committish: 'branch' }, - // INFO: fromUrl should return `undefined` from fixture input - if (fixture.isUndefined) { - t.test('input results in undefined', function (tt) { - tt.is(hostinfo, undefined) - tt.end() - }) - break - } + // shortcuts (.git) + 'sourcehut:~foo/bar.git': { ...defaults, default: 'shortcut' }, + 'sourcehut:~foo/bar.git#branch': { ...defaults, default: 'shortcut', committish: 'branch' }, - t.test('hostinfo.https', function (tt) { - var expected = function (url, hasBranch) { - return (hasBranch) - ? url + '#' + params.branch - : url - } - tt.is( - hostinfo.https(), - expected('git+https://git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch, fixture.hasGroup), - showLabel(fixture.label, 'https') - ) - // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same - tt.is( - hostinfo.https({ noCommittish: true }), - 'git+https://git.sr.ht/~some-owner/some-repo.git', - showLabel(fixture.label, 'https({ noCommittish: true })') - ) - tt.is( - hostinfo.https({ noGitPlus: true }), - expected('https://git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch), - showLabel(fixture.label, 'https({ noGitPlus: true })') - ) - tt.end() - }) - t.test('hostinfo.browse', function (tt) { - var expected = function (url, hasBranch) { - if (hasBranch) { - if (url.indexOf('master') === -1) { - return url + '/tree/' + params.branch - } else { - return url.replace(/master/gi, params.branch) - } - } - return url - } - tt.is( - hostinfo.browse(), - expected('https://git.sr.ht/~some-owner/some-repo', fixture.hasBranch), - showLabel(fixture.label, 'browse') - ) - tt.is( - hostinfo.browse(''), - expected('https://git.sr.ht/~some-owner/some-repo/tree/master/', fixture.hasBranch), - showLabel(fixture.label, "browse('')") - ) - tt.is( - hostinfo.browse('C'), - expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C', fixture.hasBranch), - showLabel(fixture.label, "browse('C')") - ) - tt.is( - hostinfo.browse('C/D'), - expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C/D', fixture.hasBranch), - showLabel(fixture.label, "browse('C/D')") - ) - tt.is( - hostinfo.browse('C', 'A'), - expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C#a', fixture.hasBranch), - showLabel(fixture.label, "browse('C', 'A')") - ) - tt.is( - hostinfo.browse('C/D', 'A'), - expected('https://git.sr.ht/~some-owner/some-repo/tree/master/C/D#a', fixture.hasBranch), - showLabel(fixture.label, "browse('C/D', 'A')") - ) - tt.end() - }) - t.test('hostinfo.docs', function (tt) { - var expected = function (url, hasBranch) { - if (hasBranch) { - var splitUrl = url.split('#') - return splitUrl[0] + '/tree/' + params.branch + '#' + splitUrl[1] - } - return url - } - tt.is( - hostinfo.docs(), - expected('https://git.sr.ht/~some-owner/some-repo#readme', fixture.hasBranch), - showLabel(fixture.label, 'docs') - ) - tt.is( - hostinfo.docs({ noCommittish: true }), - // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same - 'https://git.sr.ht/~some-owner/some-repo#readme', - showLabel(fixture.label, 'docs({ noCommittish: true })') - ) - tt.is( - hostinfo.docs({ noGitPlus: true }), - expected('https://git.sr.ht/~some-owner/some-repo#readme', fixture.hasBranch), - showLabel(fixture.label, 'docs({ noGitPlus: true })') - ) - tt.end() - }) - t.test('hostinfo.ssh', function (tt) { - var expected = function (url, hasBranch) { - return (hasBranch) - ? url + '#' + params.branch - : url - } - tt.is( - hostinfo.ssh(), - expected('git@git.sr.ht:~some-owner/some-repo.git', fixture.hasBranch), - showLabel(fixture.label, 'ssh') - ) - tt.is( - hostinfo.ssh({ noCommittish: true }), - // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same - 'git@git.sr.ht:~some-owner/some-repo.git', - showLabel(fixture.label, 'ssh({ noCommittish: true })') - ) - tt.is( - hostinfo.ssh({ noGitPlus: true }), - expected('git@git.sr.ht:~some-owner/some-repo.git', fixture.hasBranch), - showLabel(fixture.label, 'ssh({ noGitPlus: true })') - ) - tt.end() - }) - t.test('hostinfo.sshurl', function (tt) { - var expected = function (url, hasBranch) { - return (hasBranch) - ? url + '#' + params.branch - : url - } - tt.is( - hostinfo.sshurl(), - expected('git+ssh://git@git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch), - showLabel(fixture.label, 'sshurl') - ) - tt.is( - hostinfo.sshurl({ noCommittish: true }), - // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same - 'git+ssh://git@git.sr.ht/~some-owner/some-repo.git', - showLabel(fixture.label, 'sshurl({ noCommittish: true })') - ) - tt.is( - hostinfo.sshurl({ noGitPlus: true }), - expected('ssh://git@git.sr.ht/~some-owner/some-repo.git', fixture.hasBranch), - showLabel(fixture.label, 'sshurl({ noGitPlus: true })') - ) - tt.end() - }) - t.test('hostinfo.shortcut', function (tt) { - var expected = function (url, hasBranch) { - return (hasBranch) - ? url + '#' + params.branch - : url - } - tt.is( - hostinfo.shortcut(), - expected('sourcehut:~some-owner/some-repo', fixture.hasBranch), - showLabel(fixture.label, 'shortcut') - ) - tt.is( - hostinfo.shortcut({ noCommittish: true }), - // INFO: not using `expected` because with `{noCommittish: true}` the output is always the same - 'sourcehut:~some-owner/some-repo', - showLabel(fixture.label, 'shortcut({ noCommittish: true })') - ) - tt.is( - hostinfo.shortcut({ noGitPlus: true }), - expected('sourcehut:~some-owner/some-repo', fixture.hasBranch), - showLabel(fixture.label, 'shortcut({ noGitPlus: true })') - ) - tt.end() - }) - t.test('hostinfo.file', function (tt) { - var expected = function (url, hasBranch) { - return (hasBranch) - ? url.replace(/master/gi, params.branch) - : url - } - tt.is( - hostinfo.file(), - expected('https://git.sr.ht/~some-owner/some-repo/blob/master/', fixture.hasBranch), - showLabel(fixture.label, 'file') - ) - tt.is( - hostinfo.file('C'), - expected('https://git.sr.ht/~some-owner/some-repo/blob/master/C', fixture.hasBranch), - showLabel(fixture.label, "file('C')") - ) - tt.is( - hostinfo.file('C/D'), - expected('https://git.sr.ht/~some-owner/some-repo/blob/master/C/D', fixture.hasBranch), - showLabel(fixture.label, "file('C/D')") - ) - tt.end() - }) - t.test('hostinfo.tarball', function (tt) { - var expected = function (url, hasBranch) { - return (hasBranch) - ? url.replace(/master/gi, params.branch) - : url - } - tt.is( - hostinfo.tarball(), - expected('https://git.sr.ht/~some-owner/some-repo/archive/master.tar.gz', fixture.hasBranch), - showLabel(fixture.label, 'tarball') - ) - tt.is( - hostinfo.tarball({ noCommittish: true }), - expected('https://git.sr.ht/~some-owner/some-repo/archive/master.tar.gz', fixture.hasBranch), - showLabel(fixture.label, 'tarball({ noCommittish: true })') - ) - tt.is( - hostinfo.tarball({ noGitPlus: true }), - expected('https://git.sr.ht/~some-owner/some-repo/archive/master.tar.gz', fixture.hasBranch), - showLabel(fixture.label, 'tarball({ noGitPlus: true })') - ) - tt.end() - }) - } + // no-protocol git+ssh + 'git@git.sr.ht:~foo/bar': { ...defaults, default: 'sshurl', auth: null }, + 'git@git.sr.ht:~foo/bar#branch': { ...defaults, default: 'sshurl', auth: null, committish: 'branch' }, + + // no-protocol git+ssh (.git) + 'git@git.sr.ht:~foo/bar.git': { ...defaults, default: 'sshurl', auth: null }, + 'git@git.sr.ht:~foo/bar.git#branch': { ...defaults, default: 'sshurl', auth: null, committish: 'branch' }, + + // git+ssh urls + 'git+ssh://git@git.sr.ht:~foo/bar': { ...defaults, default: 'sshurl' }, + 'git+ssh://git@git.sr.ht:~foo/bar#branch': { ...defaults, default: 'sshurl', committish: 'branch' }, + + // git+ssh urls (.git) + 'git+ssh://git@git.sr.ht:~foo/bar.git': { ...defaults, default: 'sshurl' }, + 'git+ssh://git@git.sr.ht:~foo/bar.git#branch': { ...defaults, default: 'sshurl', committish: 'branch' }, + + // https urls + 'https://git.sr.ht/~foo/bar': { ...defaults, default: 'https' }, + 'https://git.sr.ht/~foo/bar#branch': { ...defaults, default: 'https', committish: 'branch' }, + + 'https://git.sr.ht/~foo/bar.git': { ...defaults, default: 'https' }, + 'https://git.sr.ht/~foo/bar.git#branch': { ...defaults, default: 'https', committish: 'branch' } } -test('fromUrl(sourcehut url)', function (t) { - var fixtures = require('./fixtures/sourcehut') +t.test('valid urls parse properly', t => { + t.plan(Object.keys(valid).length) + for (const [url, result] of Object.entries(valid)) { + t.hasStrict(HostedGit.fromUrl(url), result, `${url} parses`) + } +}) + +t.test('invalid urls return undefined', t => { + t.plan(invalid.length) + for (const url of invalid) { + t.equal(HostedGit.fromUrl(url), undefined, `${url} returns undefined`) + } +}) + +t.test('toString respects defaults', t => { + const sshurl = HostedGit.fromUrl('git+ssh://git.sr.ht/~foo/bar') + t.equal(sshurl.default, 'sshurl', 'got the right default') + t.equal(sshurl.toString(), sshurl.sshurl(), 'toString calls sshurl') + + const https = HostedGit.fromUrl('https://git.sr.ht/~foo/bar') + t.equal(https.default, 'https', 'got the right default') + t.equal(https.toString(), https.https(), 'toString calls https') + + const shortcut = HostedGit.fromUrl('sourcehut:~foo/bar') + t.equal(shortcut.default, 'shortcut', 'got the right default') + t.equal(shortcut.toString(), shortcut.shortcut(), 'toString calls shortcut') + + t.end() +}) + +t.test('string methods populate correctly', t => { + const parsed = HostedGit.fromUrl('git+ssh://git.sr.ht/~foo/bar') + t.equal(parsed.getDefaultRepresentation(), parsed.default, 'getDefaultRepresentation()') + t.equal(parsed.hash(), '', 'hash() returns empty string when committish is unset') + t.equal(parsed.ssh(), 'git@git.sr.ht:~foo/bar.git') + t.equal(parsed.sshurl(), 'git+ssh://git@git.sr.ht/~foo/bar.git') + t.equal(parsed.browse(), 'https://git.sr.ht/~foo/bar') + t.equal(parsed.browse('/lib/index.js'), 'https://git.sr.ht/~foo/bar/tree/main/lib/index.js') + t.equal(parsed.browse('/lib/index.js', 'L100'), 'https://git.sr.ht/~foo/bar/tree/main/lib/index.js#l100') + t.equal(parsed.docs(), 'https://git.sr.ht/~foo/bar#readme') + t.equal(parsed.https(), 'https://git.sr.ht/~foo/bar.git') + t.equal(parsed.shortcut(), 'sourcehut:~foo/bar') + t.equal(parsed.path(), '~foo/bar') + t.equal(parsed.tarball(), 'https://git.sr.ht/~foo/bar/archive/main.tar.gz') + t.equal(parsed.file(), 'https://git.sr.ht/~foo/bar/blob/main/') + t.equal(parsed.file('/lib/index.js'), 'https://git.sr.ht/~foo/bar/blob/main/lib/index.js') + t.equal(parsed.bugs(), 'https://todo.sr.ht/~foo/bar') + + t.equal(parsed.docs({ committish: 'fix/bug' }), 'https://git.sr.ht/~foo/bar/tree/fix%2Fbug#readme', 'allows overriding options') + + t.same(parsed.git(), null, 'git() returns null') - t.test('domain: git.sr.ht', function (tt) { - var params = { - domain: 'git.sr.ht', - shortname: 'sourcehut', - label: 'sourcehut', - owner: '~some-owner', - project: 'some-repo', - branch: 'feature-branch' - } - testFixtures(tt, params, fixtures) - tt.end() - }) + const extra = HostedGit.fromUrl('https://@git.sr.ht/~foo/bar#fix/bug') + t.equal(extra.hash(), '#fix/bug') + t.equal(extra.https(), 'https://git.sr.ht/~foo/bar.git#fix/bug') + t.equal(extra.shortcut(), 'sourcehut:~foo/bar#fix/bug') + t.equal(extra.ssh(), 'git@git.sr.ht:~foo/bar.git#fix/bug') + t.equal(extra.sshurl(), 'git+ssh://git@git.sr.ht/~foo/bar.git#fix/bug') + t.equal(extra.browse(), 'https://git.sr.ht/~foo/bar/tree/fix%2Fbug') + t.equal(extra.browse('/lib/index.js'), 'https://git.sr.ht/~foo/bar/tree/fix%2Fbug/lib/index.js') + t.equal(extra.browse('/lib/index.js', 'L200'), 'https://git.sr.ht/~foo/bar/tree/fix%2Fbug/lib/index.js#l200') + t.equal(extra.docs(), 'https://git.sr.ht/~foo/bar/tree/fix%2Fbug#readme') + t.equal(extra.file(), 'https://git.sr.ht/~foo/bar/blob/fix%2Fbug/') + t.equal(extra.file('/lib/index.js'), 'https://git.sr.ht/~foo/bar/blob/fix%2Fbug/lib/index.js') - t.test('Soucehub HTTPS URLs with embedded auth', function (tt) { - tt.is( - HostedGit.fromUrl('https://user:pass@git.sr.ht/user/repo.git').toString(), - 'git+https://user:pass@git.sr.ht/user/repo.git', - 'credentials were included in URL' - ) - tt.is( - HostedGit.fromUrl('https://user:pass@git.sr.ht/user/repo').toString(), - 'git+https://user:pass@git.sr.ht/user/repo.git', - 'credentials were included in URL' - ) - tt.is( - HostedGit.fromUrl('git+https://user:pass@git.sr.ht/user/repo.git').toString(), - 'git+https://user:pass@git.sr.ht/user/repo.git', - 'credentials were included in URL' - ) - tt.is( - HostedGit.fromUrl('git+https://user:pass@git.sr.ht/user/repo').toString(), - 'git+https://user:pass@git.sr.ht/user/repo.git', - 'credentials were included in URL' - ) - tt.end() - }) + t.equal(extra.sshurl({ noCommittish: true }), 'git+ssh://git@git.sr.ht/~foo/bar.git', 'noCommittish drops committish from urls') + t.equal(extra.sshurl({ noGitPlus: true }), 'ssh://git@git.sr.ht/~foo/bar.git#fix/bug', 'noGitPlus drops git+ prefix from urls') t.end() }) From 289d4c93e63cb74f5a3472953cfc2aef57074e01 Mon Sep 17 00:00:00 2001 From: satotake Date: Fri, 7 Jan 2022 00:02:11 +0900 Subject: [PATCH 3/3] cover branch in extract fix tarball url --- git-host-info.js | 4 +++- test/sourcehut.js | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/git-host-info.js b/git-host-info.js index bb757a2..ba55248 100644 --- a/git-host-info.js +++ b/git-host-info.js @@ -151,7 +151,9 @@ gitHosts.sourcehut = Object.assign({}, defaults, { docstemplate: ({ domain, user, project, treepath, committish }) => `https://${domain}/${user}/${project}${maybeJoin('/', treepath, '/', maybeEncode(committish))}#readme`, extract: (url) => { let [, user, project, aux] = url.pathname.split('/', 4) - if (['get'].includes(aux)) { + + // tarball url + if (['archive'].includes(aux)) { return } diff --git a/test/sourcehut.js b/test/sourcehut.js index c2b9cbd..17a9c52 100644 --- a/test/sourcehut.js +++ b/test/sourcehut.js @@ -7,7 +7,9 @@ const invalid = [ 'https://git.sr.ht/~foo', // invalid protocos 'git://git@git.sr.ht:~foo/bar', - 'ssh://git.sr.ht:~foo/bar' + 'ssh://git.sr.ht:~foo/bar', + // tarball url + 'https://git.sr.ht/~foo/bar/archive/main.tar.gz' ] // assigning the constructor here is hacky, but the only way to make assertions that compare