123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287 |
- "use strict";
- var gitUp = require("git-up");
- /**
- * gitUrlParse
- * Parses a Git url.
- *
- * @name gitUrlParse
- * @function
- * @param {String} url The Git url to parse.
- * @return {GitUrl} The `GitUrl` object containing:
- *
- * - `protocols` (Array): An array with the url protocols (usually it has one element).
- * - `port` (null|Number): The domain port.
- * - `resource` (String): The url domain (including subdomains).
- * - `user` (String): The authentication user (usually for ssh urls).
- * - `pathname` (String): The url pathname.
- * - `hash` (String): The url hash.
- * - `search` (String): The url querystring value.
- * - `href` (String): The input url.
- * - `protocol` (String): The git url protocol.
- * - `token` (String): The oauth token (could appear in the https urls).
- * - `source` (String): The Git provider (e.g. `"github.com"`).
- * - `owner` (String): The repository owner.
- * - `name` (String): The repository name.
- * - `ref` (String): The repository ref (e.g., "master" or "dev").
- * - `filepath` (String): A filepath relative to the repository root.
- * - `filepathtype` (String): The type of filepath in the url ("blob" or "tree").
- * - `full_name` (String): The owner and name values in the `owner/name` format.
- * - `toString` (Function): A function to stringify the parsed url into another url type.
- * - `organization` (String): The organization the owner belongs to. This is CloudForge specific.
- * - `git_suffix` (Boolean): Whether to add the `.git` suffix or not.
- *
- */
- function gitUrlParse(url) {
- if (typeof url !== "string") {
- throw new Error("The url must be a string.");
- }
- var urlInfo = gitUp(url),
- sourceParts = urlInfo.resource.split("."),
- splits = null;
- urlInfo.toString = function (type) {
- return gitUrlParse.stringify(this, type);
- };
- urlInfo.source = sourceParts.length > 2 ? sourceParts.slice(1 - sourceParts.length).join(".") : urlInfo.source = urlInfo.resource;
- // Note: Some hosting services (e.g. Visual Studio Team Services) allow whitespace characters
- // in the repository and owner names so we decode the URL pieces to get the correct result
- urlInfo.git_suffix = /\.git$/.test(urlInfo.pathname);
- urlInfo.name = decodeURIComponent(urlInfo.pathname.replace(/^\//, '').replace(/\.git$/, ""));
- urlInfo.owner = decodeURIComponent(urlInfo.user);
- switch (urlInfo.source) {
- case "git.cloudforge.com":
- urlInfo.owner = urlInfo.user;
- urlInfo.organization = sourceParts[0];
- urlInfo.source = "cloudforge.com";
- break;
- case "visualstudio.com":
- // Handle VSTS SSH URLs
- if (urlInfo.resource === 'vs-ssh.visualstudio.com') {
- splits = urlInfo.name.split("/");
- if (splits.length === 4) {
- urlInfo.organization = splits[1];
- urlInfo.owner = splits[2];
- urlInfo.name = splits[3];
- urlInfo.full_name = splits[2] + '/' + splits[3];
- }
- break;
- } else {
- splits = urlInfo.name.split("/");
- if (splits.length === 2) {
- urlInfo.owner = splits[1];
- urlInfo.name = splits[1];
- urlInfo.full_name = '_git/' + urlInfo.name;
- } else if (splits.length === 3) {
- urlInfo.name = splits[2];
- if (splits[0] === 'DefaultCollection') {
- urlInfo.owner = splits[2];
- urlInfo.organization = splits[0];
- urlInfo.full_name = urlInfo.organization + '/_git/' + urlInfo.name;
- } else {
- urlInfo.owner = splits[0];
- urlInfo.full_name = urlInfo.owner + '/_git/' + urlInfo.name;
- }
- } else if (splits.length === 4) {
- urlInfo.organization = splits[0];
- urlInfo.owner = splits[1];
- urlInfo.name = splits[3];
- urlInfo.full_name = urlInfo.organization + '/' + urlInfo.owner + '/_git/' + urlInfo.name;
- }
- break;
- }
- // Azure DevOps (formerly Visual Studio Team Services)
- case "dev.azure.com":
- case "azure.com":
- if (urlInfo.resource === 'ssh.dev.azure.com') {
- splits = urlInfo.name.split("/");
- if (splits.length === 4) {
- urlInfo.organization = splits[1];
- urlInfo.owner = splits[2];
- urlInfo.name = splits[3];
- }
- break;
- } else {
- splits = urlInfo.name.split("/");
- if (splits.length === 5) {
- urlInfo.organization = splits[0];
- urlInfo.owner = splits[1];
- urlInfo.name = splits[4];
- urlInfo.full_name = '_git/' + urlInfo.name;
- } else if (splits.length === 3) {
- urlInfo.name = splits[2];
- if (splits[0] === 'DefaultCollection') {
- urlInfo.owner = splits[2];
- urlInfo.organization = splits[0];
- urlInfo.full_name = urlInfo.organization + '/_git/' + urlInfo.name;
- } else {
- urlInfo.owner = splits[0];
- urlInfo.full_name = urlInfo.owner + '/_git/' + urlInfo.name;
- }
- } else if (splits.length === 4) {
- urlInfo.organization = splits[0];
- urlInfo.owner = splits[1];
- urlInfo.name = splits[3];
- urlInfo.full_name = urlInfo.organization + '/' + urlInfo.owner + '/_git/' + urlInfo.name;
- }
- if (urlInfo.query && urlInfo.query['path']) {
- urlInfo.filepath = urlInfo.query['path'].replace(/^\/+/g, ''); // Strip leading slash (/)
- }
- if (urlInfo.query && urlInfo.query['version']) {
- // version=GB<branch>
- urlInfo.ref = urlInfo.query['version'].replace(/^GB/, ''); // remove GB
- }
- break;
- }
- default:
- splits = urlInfo.name.split("/");
- var nameIndex = splits.length - 1;
- if (splits.length >= 2) {
- var dashIndex = splits.indexOf("-", 2);
- var blobIndex = splits.indexOf("blob", 2);
- var treeIndex = splits.indexOf("tree", 2);
- var commitIndex = splits.indexOf("commit", 2);
- var srcIndex = splits.indexOf("src", 2);
- var rawIndex = splits.indexOf("raw", 2);
- nameIndex = dashIndex > 0 ? dashIndex - 1 : blobIndex > 0 ? blobIndex - 1 : treeIndex > 0 ? treeIndex - 1 : commitIndex > 0 ? commitIndex - 1 : srcIndex > 0 ? srcIndex - 1 : rawIndex > 0 ? rawIndex - 1 : nameIndex;
- urlInfo.owner = splits.slice(0, nameIndex).join('/');
- urlInfo.name = splits[nameIndex];
- if (commitIndex) {
- urlInfo.commit = splits[nameIndex + 2];
- }
- }
- urlInfo.ref = "";
- urlInfo.filepathtype = "";
- urlInfo.filepath = "";
- var offsetNameIndex = splits.length > nameIndex && splits[nameIndex + 1] === "-" ? nameIndex + 1 : nameIndex;
- if (splits.length > offsetNameIndex + 2 && ["raw", "src", "blob", "tree"].indexOf(splits[offsetNameIndex + 1]) >= 0) {
- urlInfo.filepathtype = splits[offsetNameIndex + 1];
- urlInfo.ref = splits[offsetNameIndex + 2];
- if (splits.length > offsetNameIndex + 3) {
- urlInfo.filepath = splits.slice(offsetNameIndex + 3).join('/');
- }
- }
- urlInfo.organization = urlInfo.owner;
- break;
- }
- if (!urlInfo.full_name) {
- urlInfo.full_name = urlInfo.owner;
- if (urlInfo.name) {
- urlInfo.full_name && (urlInfo.full_name += "/");
- urlInfo.full_name += urlInfo.name;
- }
- }
- // Bitbucket Server
- if (urlInfo.owner.startsWith("scm/")) {
- urlInfo.source = "bitbucket-server";
- urlInfo.owner = urlInfo.owner.replace("scm/", "");
- urlInfo.organization = urlInfo.owner;
- urlInfo.full_name = urlInfo.owner + "/" + urlInfo.name;
- }
- var bitbucket = /(projects|users)\/(.*?)\/repos\/(.*?)((\/.*$)|$)/;
- var matches = bitbucket.exec(urlInfo.pathname);
- if (matches != null) {
- urlInfo.source = "bitbucket-server";
- if (matches[1] === "users") {
- urlInfo.owner = "~" + matches[2];
- } else {
- urlInfo.owner = matches[2];
- }
- urlInfo.organization = urlInfo.owner;
- urlInfo.name = matches[3];
- splits = matches[4].split("/");
- if (splits.length > 1) {
- if (["raw", "browse"].indexOf(splits[1]) >= 0) {
- urlInfo.filepathtype = splits[1];
- if (splits.length > 2) {
- urlInfo.filepath = splits.slice(2).join('/');
- }
- } else if (splits[1] === "commits" && splits.length > 2) {
- urlInfo.commit = splits[2];
- }
- }
- urlInfo.full_name = urlInfo.owner + "/" + urlInfo.name;
- if (urlInfo.query.at) {
- urlInfo.ref = urlInfo.query.at;
- } else {
- urlInfo.ref = "";
- }
- }
- return urlInfo;
- }
- /**
- * stringify
- * Stringifies a `GitUrl` object.
- *
- * @name stringify
- * @function
- * @param {GitUrl} obj The parsed Git url object.
- * @param {String} type The type of the stringified url (default `obj.protocol`).
- * @return {String} The stringified url.
- */
- gitUrlParse.stringify = function (obj, type) {
- type = type || (obj.protocols && obj.protocols.length ? obj.protocols.join('+') : obj.protocol);
- var port = obj.port ? ":" + obj.port : '';
- var user = obj.user || 'git';
- var maybeGitSuffix = obj.git_suffix ? ".git" : "";
- switch (type) {
- case "ssh":
- if (port) return "ssh://" + user + "@" + obj.resource + port + "/" + obj.full_name + maybeGitSuffix;else return user + "@" + obj.resource + ":" + obj.full_name + maybeGitSuffix;
- case "git+ssh":
- case "ssh+git":
- case "ftp":
- case "ftps":
- return type + "://" + user + "@" + obj.resource + port + "/" + obj.full_name + maybeGitSuffix;
- case "http":
- case "https":
- var auth = obj.token ? buildToken(obj) : obj.user && (obj.protocols.includes('http') || obj.protocols.includes('https')) ? obj.user + "@" : "";
- return type + "://" + auth + obj.resource + port + "/" + buildPath(obj) + maybeGitSuffix;
- default:
- return obj.href;
- }
- };
- /*!
- * buildToken
- * Builds OAuth token prefix (helper function)
- *
- * @name buildToken
- * @function
- * @param {GitUrl} obj The parsed Git url object.
- * @return {String} token prefix
- */
- function buildToken(obj) {
- switch (obj.source) {
- case "bitbucket.org":
- return "x-token-auth:" + obj.token + "@";
- default:
- return obj.token + "@";
- }
- }
- function buildPath(obj) {
- switch (obj.source) {
- case "bitbucket-server":
- return "scm/" + obj.full_name;
- default:
- return "" + obj.full_name;
- }
- }
- module.exports = gitUrlParse;
|