@backstage/integration
Advanced tools
Comparing version 0.0.0-nightly-20201132941 to 0.0.0-nightly-202011921610
# @backstage/integration | ||
## 0.0.0-nightly-202011921610 | ||
### Patch Changes | ||
- 8054117: Move the core url and auth logic to integration for the four major providers | ||
- 8054117: Add the basics of cross-integration concerns | ||
## 0.1.2 | ||
@@ -4,0 +11,0 @@ |
@@ -5,2 +5,10 @@ 'use strict'; | ||
var parseGitUrl = require('git-url-parse'); | ||
var fetch = require('cross-fetch'); | ||
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
var parseGitUrl__default = /*#__PURE__*/_interopDefaultLegacy(parseGitUrl); | ||
var fetch__default = /*#__PURE__*/_interopDefaultLegacy(fetch); | ||
const AZURE_HOST = "dev.azure.com"; | ||
@@ -21,2 +29,60 @@ function readAzureIntegrationConfig(config2) { | ||
function getAzureFileFetchUrl(url) { | ||
var _a; | ||
try { | ||
const parsedUrl = new URL(url); | ||
const [ | ||
empty, | ||
userOrOrg, | ||
project, | ||
srcKeyword, | ||
repoName | ||
] = parsedUrl.pathname.split("/"); | ||
const path = parsedUrl.searchParams.get("path") || ""; | ||
const ref = (_a = parsedUrl.searchParams.get("version")) == null ? void 0 : _a.substr(2); | ||
if (parsedUrl.hostname !== "dev.azure.com" || empty !== "" || userOrOrg === "" || project === "" || srcKeyword !== "_git" || repoName === "" || path === "" || ref === "") { | ||
throw new Error("Wrong Azure Devops URL or Invalid file path"); | ||
} | ||
parsedUrl.pathname = [ | ||
empty, | ||
userOrOrg, | ||
project, | ||
"_apis", | ||
"git", | ||
"repositories", | ||
repoName, | ||
"items" | ||
].join("/"); | ||
const queryParams = [`path=${path}`]; | ||
if (ref) { | ||
queryParams.push(`version=${ref}`); | ||
} | ||
parsedUrl.search = queryParams.join("&"); | ||
parsedUrl.protocol = "https"; | ||
return parsedUrl.toString(); | ||
} catch (e) { | ||
throw new Error(`Incorrect URL: ${url}, ${e}`); | ||
} | ||
} | ||
function getAzureDownloadUrl(url) { | ||
const { | ||
name: repoName, | ||
owner: project, | ||
organization, | ||
protocol, | ||
resource, | ||
filepath | ||
} = parseGitUrl__default['default'](url); | ||
const scopePath = filepath ? `&scopePath=${encodeURIComponent(filepath)}` : ""; | ||
return `${protocol}://${resource}/${organization}/${project}/_apis/git/repositories/${repoName}/items?recursionLevel=full&download=true&api-version=6.0${scopePath}`; | ||
} | ||
function getAzureRequestOptions(config2, additionalHeaders) { | ||
const headers = additionalHeaders ? {...additionalHeaders} : {}; | ||
if (config2.token) { | ||
const buffer = Buffer.from(`:${config2.token}`, "utf8"); | ||
headers.Authorization = `Basic ${buffer.toString("base64")}`; | ||
} | ||
return {headers}; | ||
} | ||
const BITBUCKET_HOST = "bitbucket.org"; | ||
@@ -55,2 +121,33 @@ const BITBUCKET_API_BASE_URL = "https://api.bitbucket.org/2.0"; | ||
function getBitbucketFileFetchUrl(url, config2) { | ||
try { | ||
const {owner, name, ref, filepathtype, filepath} = parseGitUrl__default['default'](url); | ||
if (!owner || !name || filepathtype !== "browse" && filepathtype !== "raw" && filepathtype !== "src") { | ||
throw new Error("Invalid Bitbucket URL or file path"); | ||
} | ||
const pathWithoutSlash = filepath.replace(/^\//, ""); | ||
if (config2.host === "bitbucket.org") { | ||
if (!ref) { | ||
throw new Error("Invalid Bitbucket URL or file path"); | ||
} | ||
return `${config2.apiBaseUrl}/repositories/${owner}/${name}/src/${ref}/${pathWithoutSlash}`; | ||
} | ||
return `${config2.apiBaseUrl}/projects/${owner}/repos/${name}/raw/${pathWithoutSlash}?at=${ref}`; | ||
} catch (e) { | ||
throw new Error(`Incorrect URL: ${url}, ${e}`); | ||
} | ||
} | ||
function getBitbucketRequestOptions(config2) { | ||
const headers = {}; | ||
if (config2.token) { | ||
headers.Authorization = `Bearer ${config2.token}`; | ||
} else if (config2.username && config2.appPassword) { | ||
const buffer = Buffer.from(`${config2.username}:${config2.appPassword}`, "utf8"); | ||
headers.Authorization = `Basic ${buffer.toString("base64")}`; | ||
} | ||
return { | ||
headers | ||
}; | ||
} | ||
const GITHUB_HOST = "github.com"; | ||
@@ -89,2 +186,34 @@ const GITHUB_API_BASE_URL = "https://api.github.com"; | ||
function getGitHubFileFetchUrl(url, config2) { | ||
try { | ||
const {owner, name, ref, filepathtype, filepath} = parseGitUrl__default['default'](url); | ||
if (!owner || !name || !ref || filepathtype !== "blob" && filepathtype !== "raw") { | ||
throw new Error("Invalid GitHub URL or file path"); | ||
} | ||
const pathWithoutSlash = filepath.replace(/^\//, ""); | ||
if (chooseEndpoint(config2) === "api") { | ||
return `${config2.apiBaseUrl}/repos/${owner}/${name}/contents/${pathWithoutSlash}?ref=${ref}`; | ||
} | ||
return `${config2.rawBaseUrl}/${owner}/${name}/${ref}/${pathWithoutSlash}`; | ||
} catch (e) { | ||
throw new Error(`Incorrect URL: ${url}, ${e}`); | ||
} | ||
} | ||
function getGitHubRequestOptions(config2) { | ||
const headers = {}; | ||
if (chooseEndpoint(config2) === "api") { | ||
headers.Accept = "application/vnd.github.v3.raw"; | ||
} | ||
if (config2.token) { | ||
headers.Authorization = `token ${config2.token}`; | ||
} | ||
return {headers}; | ||
} | ||
function chooseEndpoint(config2) { | ||
if (config2.apiBaseUrl && (config2.token || !config2.rawBaseUrl)) { | ||
return "api"; | ||
} | ||
return "raw"; | ||
} | ||
const GITLAB_HOST = "gitlab.com"; | ||
@@ -105,2 +234,186 @@ function readGitLabIntegrationConfig(config2) { | ||
async function getGitLabFileFetchUrl(url, config2) { | ||
if (url.includes("/-/blob/")) { | ||
const projectID = await getProjectId(url, config2); | ||
return buildProjectUrl(url, projectID).toString(); | ||
} | ||
return buildRawUrl(url).toString(); | ||
} | ||
function getGitLabRequestOptions(config2) { | ||
const {token = ""} = config2; | ||
return { | ||
headers: { | ||
"PRIVATE-TOKEN": token | ||
} | ||
}; | ||
} | ||
function buildRawUrl(target) { | ||
try { | ||
const url = new URL(target); | ||
const [ | ||
empty, | ||
userOrOrg, | ||
repoName, | ||
blobKeyword, | ||
...restOfPath | ||
] = url.pathname.split("/"); | ||
if (empty !== "" || userOrOrg === "" || repoName === "" || blobKeyword !== "blob" || !restOfPath.join("/").match(/\.yaml$/)) { | ||
throw new Error("Wrong GitLab URL"); | ||
} | ||
url.pathname = [empty, userOrOrg, repoName, "raw", ...restOfPath].join("/"); | ||
return url; | ||
} catch (e) { | ||
throw new Error(`Incorrect url: ${target}, ${e}`); | ||
} | ||
} | ||
function buildProjectUrl(target, projectID) { | ||
try { | ||
const url = new URL(target); | ||
const branchAndFilePath = url.pathname.split("/-/blob/")[1]; | ||
const [branch, ...filePath] = branchAndFilePath.split("/"); | ||
url.pathname = [ | ||
"/api/v4/projects", | ||
projectID, | ||
"repository/files", | ||
encodeURIComponent(filePath.join("/")), | ||
"raw" | ||
].join("/"); | ||
url.search = `?ref=${branch}`; | ||
return url; | ||
} catch (e) { | ||
throw new Error(`Incorrect url: ${target}, ${e}`); | ||
} | ||
} | ||
async function getProjectId(target, config2) { | ||
const url = new URL(target); | ||
if (!url.pathname.includes("/-/blob/")) { | ||
throw new Error("Please provide full path to yaml file from Gitlab"); | ||
} | ||
try { | ||
const repo = url.pathname.split("/-/blob/")[0]; | ||
const repoIDLookup = new URL(`${url.protocol + url.hostname}/api/v4/projects/${encodeURIComponent(repo.replace(/^\//, ""))}`); | ||
const response = await fetch__default['default'](repoIDLookup.toString(), getGitLabRequestOptions(config2)); | ||
const projectIDJson = await response.json(); | ||
const projectID = Number(projectIDJson.id); | ||
return projectID; | ||
} catch (e) { | ||
throw new Error(`Could not get GitLab project ID for: ${target}, ${e}`); | ||
} | ||
} | ||
const AzureIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "azure"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let AzureIntegration = AzureIntegration2; | ||
AzureIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readAzureIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.azure")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new AzureIntegration2(integration) | ||
})); | ||
}; | ||
const BitbucketIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "bitbucket"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let BitbucketIntegration = BitbucketIntegration2; | ||
BitbucketIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readBitbucketIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.bitbucket")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new BitbucketIntegration2(integration) | ||
})); | ||
}; | ||
const GitHubIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "github"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let GitHubIntegration = GitHubIntegration2; | ||
GitHubIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readGitHubIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.github")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new GitHubIntegration2(integration) | ||
})); | ||
}; | ||
const GitLabIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "gitlab"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let GitLabIntegration = GitLabIntegration2; | ||
GitLabIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readGitLabIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.gitlab")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new GitLabIntegration2(integration) | ||
})); | ||
}; | ||
class ScmIntegrations { | ||
constructor(integrations) { | ||
this.integrations = integrations; | ||
} | ||
static fromConfig(config2) { | ||
return new ScmIntegrations([ | ||
...AzureIntegration.factory({config: config2}), | ||
...BitbucketIntegration.factory({config: config2}), | ||
...GitHubIntegration.factory({config: config2}), | ||
...GitLabIntegration.factory({config: config2}) | ||
]); | ||
} | ||
list() { | ||
return this.integrations.map((i) => i.integration); | ||
} | ||
byUrl(url) { | ||
var _a; | ||
return (_a = this.integrations.find((i) => i.predicate(new URL(url)))) == null ? void 0 : _a.integration; | ||
} | ||
} | ||
exports.ScmIntegrations = ScmIntegrations; | ||
exports.getAzureDownloadUrl = getAzureDownloadUrl; | ||
exports.getAzureFileFetchUrl = getAzureFileFetchUrl; | ||
exports.getAzureRequestOptions = getAzureRequestOptions; | ||
exports.getBitbucketFileFetchUrl = getBitbucketFileFetchUrl; | ||
exports.getBitbucketRequestOptions = getBitbucketRequestOptions; | ||
exports.getGitHubFileFetchUrl = getGitHubFileFetchUrl; | ||
exports.getGitHubRequestOptions = getGitHubRequestOptions; | ||
exports.getGitLabFileFetchUrl = getGitLabFileFetchUrl; | ||
exports.getGitLabRequestOptions = getGitLabRequestOptions; | ||
exports.readAzureIntegrationConfig = readAzureIntegrationConfig; | ||
@@ -107,0 +420,0 @@ exports.readAzureIntegrationConfigs = readAzureIntegrationConfigs; |
@@ -35,2 +35,27 @@ import { Config } from '@backstage/config'; | ||
/** | ||
* Given a URL pointing to a file on a provider, returns a URL that is suitable | ||
* for fetching the contents of the data. | ||
* | ||
* Converts | ||
* from: https://dev.azure.com/{organization}/{project}/_git/reponame?path={path}&version=GB{commitOrBranch}&_a=contents | ||
* to: https://dev.azure.com/{organization}/{project}/_apis/git/repositories/reponame/items?path={path}&version={commitOrBranch} | ||
* | ||
* @param url A URL pointing to a file | ||
*/ | ||
declare function getAzureFileFetchUrl(url: string): string; | ||
/** | ||
* Given a URL pointing to a path on a provider, returns a URL that is suitable | ||
* for downloading the subtree. | ||
* | ||
* @param url A URL pointing to a path | ||
*/ | ||
declare function getAzureDownloadUrl(url: string): string; | ||
/** | ||
* Gets the request options necessary to make requests to a given provider. | ||
* | ||
* @param config The relevant provider config | ||
*/ | ||
declare function getAzureRequestOptions(config: AzureIntegrationConfig, additionalHeaders?: Record<string, string>): RequestInit; | ||
/** | ||
* The configuration parameters for a single Bitbucket API provider. | ||
@@ -87,2 +112,21 @@ */ | ||
/** | ||
* Given a URL pointing to a file on a provider, returns a URL that is suitable | ||
* for fetching the contents of the data. | ||
* | ||
* Converts | ||
* from: https://bitbucket.org/orgname/reponame/src/master/file.yaml | ||
* to: https://api.bitbucket.org/2.0/repositories/orgname/reponame/src/master/file.yaml | ||
* | ||
* @param url A URL pointing to a file | ||
* @param config The relevant provider config | ||
*/ | ||
declare function getBitbucketFileFetchUrl(url: string, config: BitbucketIntegrationConfig): string; | ||
/** | ||
* Gets the request options necessary to make requests to a given provider. | ||
* | ||
* @param config The relevant provider config | ||
*/ | ||
declare function getBitbucketRequestOptions(config: BitbucketIntegrationConfig): RequestInit; | ||
/** | ||
* The configuration parameters for a single GitHub integration. | ||
@@ -137,2 +181,22 @@ */ | ||
/** | ||
* Given a URL pointing to a file on a provider, returns a URL that is suitable | ||
* for fetching the contents of the data. | ||
* | ||
* Converts | ||
* from: https://github.com/a/b/blob/branchname/path/to/c.yaml | ||
* to: https://api.github.com/repos/a/b/contents/path/to/c.yaml?ref=branchname | ||
* or: https://raw.githubusercontent.com/a/b/branchname/c.yaml | ||
* | ||
* @param url A URL pointing to a file | ||
* @param config The relevant provider config | ||
*/ | ||
declare function getGitHubFileFetchUrl(url: string, config: GitHubIntegrationConfig): string; | ||
/** | ||
* Gets the request options necessary to make requests to a given provider. | ||
* | ||
* @param config The relevant provider config | ||
*/ | ||
declare function getGitHubRequestOptions(config: GitHubIntegrationConfig): RequestInit; | ||
/** | ||
* The configuration parameters for a single GitLab integration. | ||
@@ -166,2 +230,66 @@ */ | ||
export { AzureIntegrationConfig, BitbucketIntegrationConfig, GitHubIntegrationConfig, GitLabIntegrationConfig, readAzureIntegrationConfig, readAzureIntegrationConfigs, readBitbucketIntegrationConfig, readBitbucketIntegrationConfigs, readGitHubIntegrationConfig, readGitHubIntegrationConfigs, readGitLabIntegrationConfig, readGitLabIntegrationConfigs }; | ||
/** | ||
* Given a URL pointing to a file on a provider, returns a URL that is suitable | ||
* for fetching the contents of the data. | ||
* | ||
* Converts | ||
* from: https://gitlab.example.com/a/b/blob/master/c.yaml | ||
* to: https://gitlab.example.com/a/b/raw/master/c.yaml | ||
* -or- | ||
* from: https://gitlab.com/groupA/teams/teamA/subgroupA/repoA/-/blob/branch/filepath | ||
* to: https://gitlab.com/api/v4/projects/projectId/repository/files/filepath?ref=branch | ||
* | ||
* @param url A URL pointing to a file | ||
* @param config The relevant provider config | ||
*/ | ||
declare function getGitLabFileFetchUrl(url: string, config: GitLabIntegrationConfig): Promise<string>; | ||
/** | ||
* Gets the request options necessary to make requests to a given provider. | ||
* | ||
* @param config The relevant provider config | ||
*/ | ||
declare function getGitLabRequestOptions(config: GitLabIntegrationConfig): RequestInit; | ||
/** | ||
* Encapsulates a single SCM integration. | ||
*/ | ||
declare type ScmIntegration = { | ||
/** | ||
* The type of integration, e.g. "github". | ||
*/ | ||
type: string; | ||
/** | ||
* A human readable title for the integration, that can be shown to users to | ||
* differentiate between different integrations. | ||
*/ | ||
title: string; | ||
}; | ||
/** | ||
* Holds all registered SCM integrations. | ||
*/ | ||
declare type ScmIntegrationRegistry = { | ||
/** | ||
* Lists all registered integrations. | ||
*/ | ||
list(): ScmIntegration[]; | ||
/** | ||
* Fetches an integration by URL. | ||
* | ||
* @param url A URL that matches a registered integration | ||
*/ | ||
byUrl(url: string): ScmIntegration | undefined; | ||
}; | ||
declare type ScmIntegrationPredicateTuple = { | ||
predicate: (url: URL) => boolean; | ||
integration: ScmIntegration; | ||
}; | ||
declare class ScmIntegrations implements ScmIntegrationRegistry { | ||
private readonly integrations; | ||
static fromConfig(config: Config): ScmIntegrations; | ||
constructor(integrations: ScmIntegrationPredicateTuple[]); | ||
list(): ScmIntegration[]; | ||
byUrl(url: string): ScmIntegration | undefined; | ||
} | ||
export { AzureIntegrationConfig, BitbucketIntegrationConfig, GitHubIntegrationConfig, GitLabIntegrationConfig, ScmIntegration, ScmIntegrationRegistry, ScmIntegrations, getAzureDownloadUrl, getAzureFileFetchUrl, getAzureRequestOptions, getBitbucketFileFetchUrl, getBitbucketRequestOptions, getGitHubFileFetchUrl, getGitHubRequestOptions, getGitLabFileFetchUrl, getGitLabRequestOptions, readAzureIntegrationConfig, readAzureIntegrationConfigs, readBitbucketIntegrationConfig, readBitbucketIntegrationConfigs, readGitHubIntegrationConfig, readGitHubIntegrationConfigs, readGitLabIntegrationConfig, readGitLabIntegrationConfigs }; |
@@ -0,1 +1,4 @@ | ||
import parseGitUrl from 'git-url-parse'; | ||
import fetch from 'cross-fetch'; | ||
const AZURE_HOST = "dev.azure.com"; | ||
@@ -16,2 +19,60 @@ function readAzureIntegrationConfig(config2) { | ||
function getAzureFileFetchUrl(url) { | ||
var _a; | ||
try { | ||
const parsedUrl = new URL(url); | ||
const [ | ||
empty, | ||
userOrOrg, | ||
project, | ||
srcKeyword, | ||
repoName | ||
] = parsedUrl.pathname.split("/"); | ||
const path = parsedUrl.searchParams.get("path") || ""; | ||
const ref = (_a = parsedUrl.searchParams.get("version")) == null ? void 0 : _a.substr(2); | ||
if (parsedUrl.hostname !== "dev.azure.com" || empty !== "" || userOrOrg === "" || project === "" || srcKeyword !== "_git" || repoName === "" || path === "" || ref === "") { | ||
throw new Error("Wrong Azure Devops URL or Invalid file path"); | ||
} | ||
parsedUrl.pathname = [ | ||
empty, | ||
userOrOrg, | ||
project, | ||
"_apis", | ||
"git", | ||
"repositories", | ||
repoName, | ||
"items" | ||
].join("/"); | ||
const queryParams = [`path=${path}`]; | ||
if (ref) { | ||
queryParams.push(`version=${ref}`); | ||
} | ||
parsedUrl.search = queryParams.join("&"); | ||
parsedUrl.protocol = "https"; | ||
return parsedUrl.toString(); | ||
} catch (e) { | ||
throw new Error(`Incorrect URL: ${url}, ${e}`); | ||
} | ||
} | ||
function getAzureDownloadUrl(url) { | ||
const { | ||
name: repoName, | ||
owner: project, | ||
organization, | ||
protocol, | ||
resource, | ||
filepath | ||
} = parseGitUrl(url); | ||
const scopePath = filepath ? `&scopePath=${encodeURIComponent(filepath)}` : ""; | ||
return `${protocol}://${resource}/${organization}/${project}/_apis/git/repositories/${repoName}/items?recursionLevel=full&download=true&api-version=6.0${scopePath}`; | ||
} | ||
function getAzureRequestOptions(config2, additionalHeaders) { | ||
const headers = additionalHeaders ? {...additionalHeaders} : {}; | ||
if (config2.token) { | ||
const buffer = Buffer.from(`:${config2.token}`, "utf8"); | ||
headers.Authorization = `Basic ${buffer.toString("base64")}`; | ||
} | ||
return {headers}; | ||
} | ||
const BITBUCKET_HOST = "bitbucket.org"; | ||
@@ -50,2 +111,33 @@ const BITBUCKET_API_BASE_URL = "https://api.bitbucket.org/2.0"; | ||
function getBitbucketFileFetchUrl(url, config2) { | ||
try { | ||
const {owner, name, ref, filepathtype, filepath} = parseGitUrl(url); | ||
if (!owner || !name || filepathtype !== "browse" && filepathtype !== "raw" && filepathtype !== "src") { | ||
throw new Error("Invalid Bitbucket URL or file path"); | ||
} | ||
const pathWithoutSlash = filepath.replace(/^\//, ""); | ||
if (config2.host === "bitbucket.org") { | ||
if (!ref) { | ||
throw new Error("Invalid Bitbucket URL or file path"); | ||
} | ||
return `${config2.apiBaseUrl}/repositories/${owner}/${name}/src/${ref}/${pathWithoutSlash}`; | ||
} | ||
return `${config2.apiBaseUrl}/projects/${owner}/repos/${name}/raw/${pathWithoutSlash}?at=${ref}`; | ||
} catch (e) { | ||
throw new Error(`Incorrect URL: ${url}, ${e}`); | ||
} | ||
} | ||
function getBitbucketRequestOptions(config2) { | ||
const headers = {}; | ||
if (config2.token) { | ||
headers.Authorization = `Bearer ${config2.token}`; | ||
} else if (config2.username && config2.appPassword) { | ||
const buffer = Buffer.from(`${config2.username}:${config2.appPassword}`, "utf8"); | ||
headers.Authorization = `Basic ${buffer.toString("base64")}`; | ||
} | ||
return { | ||
headers | ||
}; | ||
} | ||
const GITHUB_HOST = "github.com"; | ||
@@ -84,2 +176,34 @@ const GITHUB_API_BASE_URL = "https://api.github.com"; | ||
function getGitHubFileFetchUrl(url, config2) { | ||
try { | ||
const {owner, name, ref, filepathtype, filepath} = parseGitUrl(url); | ||
if (!owner || !name || !ref || filepathtype !== "blob" && filepathtype !== "raw") { | ||
throw new Error("Invalid GitHub URL or file path"); | ||
} | ||
const pathWithoutSlash = filepath.replace(/^\//, ""); | ||
if (chooseEndpoint(config2) === "api") { | ||
return `${config2.apiBaseUrl}/repos/${owner}/${name}/contents/${pathWithoutSlash}?ref=${ref}`; | ||
} | ||
return `${config2.rawBaseUrl}/${owner}/${name}/${ref}/${pathWithoutSlash}`; | ||
} catch (e) { | ||
throw new Error(`Incorrect URL: ${url}, ${e}`); | ||
} | ||
} | ||
function getGitHubRequestOptions(config2) { | ||
const headers = {}; | ||
if (chooseEndpoint(config2) === "api") { | ||
headers.Accept = "application/vnd.github.v3.raw"; | ||
} | ||
if (config2.token) { | ||
headers.Authorization = `token ${config2.token}`; | ||
} | ||
return {headers}; | ||
} | ||
function chooseEndpoint(config2) { | ||
if (config2.apiBaseUrl && (config2.token || !config2.rawBaseUrl)) { | ||
return "api"; | ||
} | ||
return "raw"; | ||
} | ||
const GITLAB_HOST = "gitlab.com"; | ||
@@ -100,3 +224,177 @@ function readGitLabIntegrationConfig(config2) { | ||
export { readAzureIntegrationConfig, readAzureIntegrationConfigs, readBitbucketIntegrationConfig, readBitbucketIntegrationConfigs, readGitHubIntegrationConfig, readGitHubIntegrationConfigs, readGitLabIntegrationConfig, readGitLabIntegrationConfigs }; | ||
async function getGitLabFileFetchUrl(url, config2) { | ||
if (url.includes("/-/blob/")) { | ||
const projectID = await getProjectId(url, config2); | ||
return buildProjectUrl(url, projectID).toString(); | ||
} | ||
return buildRawUrl(url).toString(); | ||
} | ||
function getGitLabRequestOptions(config2) { | ||
const {token = ""} = config2; | ||
return { | ||
headers: { | ||
"PRIVATE-TOKEN": token | ||
} | ||
}; | ||
} | ||
function buildRawUrl(target) { | ||
try { | ||
const url = new URL(target); | ||
const [ | ||
empty, | ||
userOrOrg, | ||
repoName, | ||
blobKeyword, | ||
...restOfPath | ||
] = url.pathname.split("/"); | ||
if (empty !== "" || userOrOrg === "" || repoName === "" || blobKeyword !== "blob" || !restOfPath.join("/").match(/\.yaml$/)) { | ||
throw new Error("Wrong GitLab URL"); | ||
} | ||
url.pathname = [empty, userOrOrg, repoName, "raw", ...restOfPath].join("/"); | ||
return url; | ||
} catch (e) { | ||
throw new Error(`Incorrect url: ${target}, ${e}`); | ||
} | ||
} | ||
function buildProjectUrl(target, projectID) { | ||
try { | ||
const url = new URL(target); | ||
const branchAndFilePath = url.pathname.split("/-/blob/")[1]; | ||
const [branch, ...filePath] = branchAndFilePath.split("/"); | ||
url.pathname = [ | ||
"/api/v4/projects", | ||
projectID, | ||
"repository/files", | ||
encodeURIComponent(filePath.join("/")), | ||
"raw" | ||
].join("/"); | ||
url.search = `?ref=${branch}`; | ||
return url; | ||
} catch (e) { | ||
throw new Error(`Incorrect url: ${target}, ${e}`); | ||
} | ||
} | ||
async function getProjectId(target, config2) { | ||
const url = new URL(target); | ||
if (!url.pathname.includes("/-/blob/")) { | ||
throw new Error("Please provide full path to yaml file from Gitlab"); | ||
} | ||
try { | ||
const repo = url.pathname.split("/-/blob/")[0]; | ||
const repoIDLookup = new URL(`${url.protocol + url.hostname}/api/v4/projects/${encodeURIComponent(repo.replace(/^\//, ""))}`); | ||
const response = await fetch(repoIDLookup.toString(), getGitLabRequestOptions(config2)); | ||
const projectIDJson = await response.json(); | ||
const projectID = Number(projectIDJson.id); | ||
return projectID; | ||
} catch (e) { | ||
throw new Error(`Could not get GitLab project ID for: ${target}, ${e}`); | ||
} | ||
} | ||
const AzureIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "azure"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let AzureIntegration = AzureIntegration2; | ||
AzureIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readAzureIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.azure")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new AzureIntegration2(integration) | ||
})); | ||
}; | ||
const BitbucketIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "bitbucket"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let BitbucketIntegration = BitbucketIntegration2; | ||
BitbucketIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readBitbucketIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.bitbucket")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new BitbucketIntegration2(integration) | ||
})); | ||
}; | ||
const GitHubIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "github"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let GitHubIntegration = GitHubIntegration2; | ||
GitHubIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readGitHubIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.github")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new GitHubIntegration2(integration) | ||
})); | ||
}; | ||
const GitLabIntegration2 = class { | ||
constructor(config2) { | ||
this.config = config2; | ||
} | ||
get type() { | ||
return "gitlab"; | ||
} | ||
get title() { | ||
return this.config.host; | ||
} | ||
}; | ||
let GitLabIntegration = GitLabIntegration2; | ||
GitLabIntegration.factory = ({config: config2}) => { | ||
var _a; | ||
const configs = readGitLabIntegrationConfigs((_a = config2.getOptionalConfigArray("integrations.gitlab")) != null ? _a : []); | ||
return configs.map((integration) => ({ | ||
predicate: (url) => url.host === integration.host, | ||
integration: new GitLabIntegration2(integration) | ||
})); | ||
}; | ||
class ScmIntegrations { | ||
constructor(integrations) { | ||
this.integrations = integrations; | ||
} | ||
static fromConfig(config2) { | ||
return new ScmIntegrations([ | ||
...AzureIntegration.factory({config: config2}), | ||
...BitbucketIntegration.factory({config: config2}), | ||
...GitHubIntegration.factory({config: config2}), | ||
...GitLabIntegration.factory({config: config2}) | ||
]); | ||
} | ||
list() { | ||
return this.integrations.map((i) => i.integration); | ||
} | ||
byUrl(url) { | ||
var _a; | ||
return (_a = this.integrations.find((i) => i.predicate(new URL(url)))) == null ? void 0 : _a.integration; | ||
} | ||
} | ||
export { ScmIntegrations, getAzureDownloadUrl, getAzureFileFetchUrl, getAzureRequestOptions, getBitbucketFileFetchUrl, getBitbucketRequestOptions, getGitHubFileFetchUrl, getGitHubRequestOptions, getGitLabFileFetchUrl, getGitLabRequestOptions, readAzureIntegrationConfig, readAzureIntegrationConfigs, readBitbucketIntegrationConfig, readBitbucketIntegrationConfigs, readGitHubIntegrationConfig, readGitHubIntegrationConfigs, readGitLabIntegrationConfig, readGitLabIntegrationConfigs }; | ||
//# sourceMappingURL=index.esm.js.map |
{ | ||
"name": "@backstage/integration", | ||
"version": "0.0.0-nightly-20201132941", | ||
"version": "0.0.0-nightly-202011921610", | ||
"main": "dist/index.cjs.js", | ||
@@ -14,2 +14,11 @@ "types": "dist/index.d.ts", | ||
}, | ||
"homepage": "https://backstage.io", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/backstage/backstage", | ||
"directory": "packages/integration" | ||
}, | ||
"keywords": [ | ||
"backstage" | ||
], | ||
"scripts": { | ||
@@ -25,7 +34,9 @@ "build": "backstage-cli build", | ||
"@backstage/config": "^0.1.1", | ||
"cross-fetch": "^3.0.6", | ||
"git-url-parse": "^11.4.0" | ||
}, | ||
"devDependencies": { | ||
"@backstage/cli": "^0.0.0-nightly-20201132941", | ||
"@types/jest": "^26.0.7" | ||
"@backstage/cli": "^0.0.0-nightly-202011921610", | ||
"@types/jest": "^26.0.7", | ||
"msw": "^0.21.2" | ||
}, | ||
@@ -32,0 +43,0 @@ "files": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
117114
1110
1
0
3
3
2
+ Addedcross-fetch@^3.0.6
+ Addedcross-fetch@3.2.0(transitive)
+ Addednode-fetch@2.7.0(transitive)
+ Addedtr46@0.0.3(transitive)
+ Addedwebidl-conversions@3.0.1(transitive)
+ Addedwhatwg-url@5.0.0(transitive)