zephyr-agent
Version:
Zephyr plugin agent
105 lines (104 loc) • 4.23 kB
JavaScript
import "node:module";
import { ZeErrors, ZephyrError } from "../errors/index.mjs";
const STANDARD_DOMAINS = {
'github.com': 'github',
'gitlab.com': 'gitlab',
'bitbucket.org': 'bitbucket',
'dev.azure.com': 'azure',
'ssh.dev.azure.com': 'azure',
'vs-ssh.visualstudio.com': 'azure'
};
function getGitProviderInfo(gitUrl) {
if (!gitUrl) throw new ZephyrError(ZeErrors.ERR_GIT_REMOTE_ORIGIN);
const parsed = parseGitUrl(gitUrl);
const resource = parsed.resource.toLowerCase();
const provider = detectProvider(parsed, resource);
const isEnterprise = 'custom' === provider;
const owner = isEnterprise ? extractEnterpriseOwner(parsed) : extractStandardOwner(parsed, provider);
const project = extractProjectName(parsed, provider, isEnterprise);
return {
provider,
owner,
project,
isEnterprise
};
}
function parseGitUrl(gitUrl) {
let resource;
let pathname;
if (/^[a-z][a-z\d+.-]*:\/\//i.test(gitUrl)) try {
const url = new URL(gitUrl);
resource = url.hostname;
pathname = url.pathname;
} catch {
throw new ZephyrError(ZeErrors.ERR_GIT_REMOTE_ORIGIN);
}
else {
const scpRemote = /^(?:[^@/:]+@)?([^/:]+):(.+)$/.exec(gitUrl);
if (!scpRemote) throw new ZephyrError(ZeErrors.ERR_GIT_REMOTE_ORIGIN);
resource = scpRemote[1];
pathname = scpRemote[2];
}
const pathParts = pathname.split('/').filter(Boolean);
const name = pathParts.at(-1)?.replace(/\.git$/, '') ?? '';
if (!resource || !name) throw new ZephyrError(ZeErrors.ERR_GIT_REMOTE_ORIGIN);
return {
resource,
owner: pathParts.slice(0, -1).join('/'),
name,
pathname
};
}
function detectProvider(parsed, resource) {
const standardProvider = STANDARD_DOMAINS[resource];
if (standardProvider) return standardProvider;
if (resource.endsWith('.visualstudio.com')) return 'azure';
const pathParts = getPathParts(parsed);
if ('v3' === pathParts[0] && pathParts.length >= 4) return 'azure';
return 'custom';
}
function extractEnterpriseOwner(parsed) {
const domainParts = parsed.resource.split('.');
const baseDomain = domainParts.length > 2 ? domainParts.slice(1).join('.') : parsed.resource;
return baseDomain.replace(/\./g, '-').toLowerCase();
}
function extractStandardOwner(parsed, provider) {
if ('azure' === provider) return extractAzureOrganization(parsed);
const rawOwner = parsed.owner.toLowerCase();
if (('gitlab' === provider || 'bitbucket' === provider) && rawOwner.includes('/')) return rawOwner.split('/')[0];
return rawOwner;
}
function extractProjectName(parsed, provider, isEnterprise) {
if ('azure' === provider) return extractAzureRepoName(parsed);
if (isEnterprise && 'gitlab' === provider && parsed.pathname) {
const pathParts = parsed.pathname.split('/').filter(Boolean);
if (pathParts.length > 2) return pathParts[pathParts.length - 1].replace('.git', '').toLowerCase();
}
return parsed.name.toLowerCase();
}
function extractAzureOrganization(parsed) {
const pathParts = getPathParts(parsed);
if ('v3' === pathParts[0] && pathParts[1]) return pathParts[1].toLowerCase();
const resource = parsed.resource.toLowerCase();
if (resource.endsWith('.visualstudio.com')) return resource.replace(/\.visualstudio\.com$/, '').toLowerCase();
const organization = pathParts[0];
return (organization || parsed.owner).toLowerCase();
}
function extractAzureRepoName(parsed) {
const pathParts = getPathParts(parsed);
const gitSegmentIndex = pathParts.findIndex((part)=>'_git' === part.toLowerCase());
const repoName = gitSegmentIndex >= 0 ? pathParts[gitSegmentIndex + 1] : pathParts[pathParts.length - 1];
return sanitizeGitName(repoName || parsed.name);
}
function getPathParts(parsed) {
return parsed.pathname.split('/').filter(Boolean);
}
function sanitizeGitName(name) {
try {
return decodeURIComponent(name).replace(/\.git$/, '').toLowerCase();
} catch {
return name.replace(/\.git$/, '').toLowerCase();
}
}
export { getGitProviderInfo };
//# sourceMappingURL=git-provider-utils.mjs.map