UNPKG

git-documentdb

Version:

Offline-first database that syncs with Git

454 lines 19.1 kB
"use strict"; /** * GitDocumentDB * Copyright (c) Hidekazu Kubota * * This source code is licensed under the Mozilla Public License Version 2.0 * found in the LICENSE file in the root directory of this source tree. */ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.push = exports.fetch = exports.checkFetch = exports.clone = exports.createCredentialCallback = exports.name = exports.type = void 0; const fs_1 = __importDefault(require("fs")); const isomorphic_git_1 = __importDefault(require("isomorphic-git")); const tslog_1 = require("tslog"); const git_documentdb_remote_errors_1 = require("git-documentdb-remote-errors"); const node_1 = __importDefault(require("isomorphic-git/http/node")); const const_1 = require("../const"); const utils_1 = require("../utils"); /** * @public */ // eslint-disable-next-line @typescript-eslint/naming-convention exports.type = 'remote'; /** * @public */ // eslint-disable-next-line @typescript-eslint/naming-convention exports.name = 'isomorphic-git'; /** * Insert credential options for GitHub * * @throws {@link InvalidURLFormatError} * @throws {@link InvalidRepositoryURLError} * * @internal */ function createCredentialForGitHub(options) { if (!options.remoteUrl.match(/^https?:\/\//)) { throw new git_documentdb_remote_errors_1.InvalidURLFormatError('http protocol required in createCredentialForGitHub'); } const connection = options.connection; if (!connection.personalAccessToken) { return undefined; } const urlArray = options.remoteUrl.replace(/^https?:\/\//, '').split('/'); // github.com/account_name/repository_name if (urlArray.length !== 3) { throw new git_documentdb_remote_errors_1.InvalidRepositoryURLError(options.remoteUrl); } const credentials = connection.personalAccessToken !== undefined ? () => ({ username: connection.personalAccessToken }) : undefined; return credentials; } /** * Create credential options * * @throws {@link InvalidAuthenticationTypeError} * * @throws # Error from createCredentialForGitHub * @throws - {@link InvalidURLFormatError} * @throws - {@link InvalidRepositoryURLError} * * @internal */ function createCredentialCallback(options) { var _a; (_a = options.connection) !== null && _a !== void 0 ? _a : (options.connection = { type: 'none' }); if (options.connection.type === 'github') { return createCredentialForGitHub(options); } else if (options.connection.type === 'none') { return undefined; } // @ts-ignore throw new git_documentdb_remote_errors_1.InvalidAuthenticationTypeError(options.connection.type); } exports.createCredentialCallback = createCredentialCallback; /** * Clone * * @throws {@link InvalidURLFormatError} * @throws {@link NetworkError} * @throws {@link HTTPError401AuthorizationRequired} * @throws {@link HTTPError404NotFound} * @throws {@link CannotConnectError} * * @throws # Errors from createCredentialForGitHub * @throws - {@link HttpProtocolRequiredError} * @throws - {@link InvalidRepositoryURLError} * * @throws # Errors from createCredential * @throws - {@link InvalidAuthenticationTypeError} * * @internal */ // eslint-disable-next-line complexity async function clone(workingDir, remoteOptions, remoteName, logger) { var _a, _b; logger !== null && logger !== void 0 ? logger : (logger = new tslog_1.Logger({ name: 'plugin-nodegit', minLevel: 'trace', displayDateTime: false, displayFunctionName: false, displayFilePath: 'hidden', })); logger.debug(`remote-isomorphic-git: clone: ${remoteOptions.remoteUrl}`); remoteName !== null && remoteName !== void 0 ? remoteName : (remoteName = 'origin'); (_a = remoteOptions.retry) !== null && _a !== void 0 ? _a : (remoteOptions.retry = const_1.NETWORK_RETRY); (_b = remoteOptions.retryInterval) !== null && _b !== void 0 ? _b : (remoteOptions.retryInterval = const_1.NETWORK_RETRY_INTERVAL); const cloneOption = { fs: fs_1.default, dir: workingDir, http: node_1.default, url: remoteOptions.remoteUrl, }; const cred = createCredentialCallback(remoteOptions); if (cred) { cloneOption.onAuth = cred; } for (let i = 0; i < remoteOptions.retry + 1; i++) { // eslint-disable-next-line no-await-in-loop const res = await isomorphic_git_1.default.clone(cloneOption).catch(err => err); let error = ''; if (res instanceof Error) { error = res.toString(); } else { break; } // if (error !== 'undefined') console.warn('connect fetch error: ' + error); switch (true) { case error.startsWith('UrlParseError:'): case error.startsWith('Error: getaddrinfo ENOTFOUND'): throw new git_documentdb_remote_errors_1.InvalidURLFormatError(error); case error.startsWith('Error: connect EACCES'): case error.startsWith('Error: connect ECONNREFUSED'): // isomorphic-git throws this when network is limited. if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.NetworkError(error); } break; case error.startsWith('HttpError: HTTP Error: 401'): throw new git_documentdb_remote_errors_1.HTTPError401AuthorizationRequired(error); case error.startsWith('HttpError: HTTP Error: 404 Not Found'): throw new git_documentdb_remote_errors_1.HTTPError404NotFound(error); default: if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.CannotConnectError(error); } } // eslint-disable-next-line no-await-in-loop await (0, utils_1.sleep)(remoteOptions.retryInterval); } // Add remote // (default is 'origin') if (remoteName !== 'origin') { await isomorphic_git_1.default.addRemote({ fs: fs_1.default, dir: workingDir, remote: 'origin', url: remoteOptions.remoteUrl, }); } await isomorphic_git_1.default.addRemote({ fs: fs_1.default, dir: workingDir, remote: remoteName, url: remoteOptions.remoteUrl, }); } exports.clone = clone; /** * Check connection by FETCH * * @throws {@link InvalidGitRemoteError} * @throws {@link InvalidURLFormatError} * @throws {@link NetworkError} * @throws {@link HTTPError401AuthorizationRequired} * @throws {@link HTTPError404NotFound} * @throws {@link CannotConnectError} * * @throws # Errors from createCredentialForGitHub * @throws - {@link HttpProtocolRequiredError} * @throws - {@link InvalidRepositoryURLError} * * @throws # Errors from createCredential * @throws - {@link InvalidAuthenticationTypeError} * * @internal */ // eslint-disable-next-line complexity async function checkFetch(workingDir, remoteOptions, remoteName, logger) { var _a, _b; logger !== null && logger !== void 0 ? logger : (logger = new tslog_1.Logger({ name: 'plugin-nodegit', minLevel: 'trace', displayDateTime: false, displayFunctionName: false, displayFilePath: 'hidden', })); remoteName !== null && remoteName !== void 0 ? remoteName : (remoteName = 'origin'); const urlOfRemote = await isomorphic_git_1.default.getConfig({ fs: fs_1.default, dir: workingDir, path: `remote.${remoteName}.url`, }); if (urlOfRemote === undefined) { throw new git_documentdb_remote_errors_1.InvalidGitRemoteError(`remote '${remoteName}' does not exist`); } (_a = remoteOptions.retry) !== null && _a !== void 0 ? _a : (remoteOptions.retry = const_1.NETWORK_RETRY); (_b = remoteOptions.retryInterval) !== null && _b !== void 0 ? _b : (remoteOptions.retryInterval = const_1.NETWORK_RETRY_INTERVAL); const checkOption = { http: node_1.default, url: remoteOptions.remoteUrl, }; const cred = createCredentialCallback(remoteOptions); if (cred) { checkOption.onAuth = cred; } for (let i = 0; i < remoteOptions.retry + 1; i++) { // eslint-disable-next-line no-await-in-loop const res = await isomorphic_git_1.default.getRemoteInfo2(checkOption).catch(err => err); let error = ''; if (res instanceof Error) { error = res.toString(); } else { break; } switch (true) { case error.startsWith('UrlParseError:'): case error.startsWith('Error: getaddrinfo ENOTFOUND'): throw new git_documentdb_remote_errors_1.InvalidURLFormatError(error); case error.startsWith('Error: connect EACCES'): case error.startsWith('Error: connect ECONNREFUSED'): // isomorphic-git throws this when network is limited. if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.NetworkError(error); } break; case error.startsWith('HttpError: HTTP Error: 401'): throw new git_documentdb_remote_errors_1.HTTPError401AuthorizationRequired(error); case error.startsWith('HttpError: HTTP Error: 404 Not Found'): throw new git_documentdb_remote_errors_1.HTTPError404NotFound(error); default: if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.CannotConnectError(error); } } // eslint-disable-next-line no-await-in-loop await (0, utils_1.sleep)(remoteOptions.retryInterval); } return true; } exports.checkFetch = checkFetch; /** * git fetch * * @throws {@link InvalidGitRemoteError} * @throws {@link InvalidURLFormatError} * @throws {@link NetworkError} * @throws {@link HTTPError401AuthorizationRequired} * @throws {@link HTTPError404NotFound} * @throws {@link CannotConnectError} * * @throws # Errors from createCredentialForGitHub * @throws - {@link HttpProtocolRequiredError} * @throws - {@link InvalidRepositoryURLError} * * @throws # Errors from createCredential * @throws - {@link InvalidAuthenticationTypeError} * * @internal */ // eslint-disable-next-line complexity async function fetch(workingDir, remoteOptions, remoteName, localBranchName, remoteBranchName, logger) { var _a, _b; logger !== null && logger !== void 0 ? logger : (logger = new tslog_1.Logger({ name: 'plugin-nodegit', minLevel: 'trace', displayDateTime: false, displayFunctionName: false, displayFilePath: 'hidden', })); logger.debug(`remote-isomorphic-git: fetch: ${remoteOptions.remoteUrl}`); remoteName !== null && remoteName !== void 0 ? remoteName : (remoteName = 'origin'); localBranchName !== null && localBranchName !== void 0 ? localBranchName : (localBranchName = 'main'); remoteBranchName !== null && remoteBranchName !== void 0 ? remoteBranchName : (remoteBranchName = 'main'); const urlOfRemote = await isomorphic_git_1.default.getConfig({ fs: fs_1.default, dir: workingDir, path: `remote.${remoteName}.url`, }); if (urlOfRemote === undefined) { throw new git_documentdb_remote_errors_1.InvalidGitRemoteError(`remote '${remoteName}' does not exist`); } (_a = remoteOptions.retry) !== null && _a !== void 0 ? _a : (remoteOptions.retry = const_1.NETWORK_RETRY); (_b = remoteOptions.retryInterval) !== null && _b !== void 0 ? _b : (remoteOptions.retryInterval = const_1.NETWORK_RETRY_INTERVAL); const fetchOption = { fs: fs_1.default, dir: workingDir, http: node_1.default, url: remoteOptions.remoteUrl, remote: remoteName, ref: localBranchName, remoteRef: remoteBranchName, }; const cred = createCredentialCallback(remoteOptions); if (cred) { fetchOption.onAuth = cred; } for (let i = 0; i < remoteOptions.retry + 1; i++) { // eslint-disable-next-line no-await-in-loop const res = await isomorphic_git_1.default.fetch(fetchOption).catch(err => err); let error = ''; if (res instanceof Error) { error = res.toString(); } else { break; } // if (error !== 'undefined') console.warn('connect fetch error: ' + error); switch (true) { case error.startsWith('NoRefspecError'): throw new git_documentdb_remote_errors_1.InvalidGitRemoteError(error); case error.startsWith('UrlParseError:'): case error.startsWith('Error: getaddrinfo ENOTFOUND'): throw new git_documentdb_remote_errors_1.InvalidURLFormatError(error); case error.startsWith('Error: connect EACCES'): case error.startsWith('Error: connect ECONNREFUSED'): // isomorphic-git throws this when network is limited. if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.NetworkError(error); } break; case error.startsWith('HttpError: HTTP Error: 401'): throw new git_documentdb_remote_errors_1.HTTPError401AuthorizationRequired(error); case error.startsWith('HttpError: HTTP Error: 404 Not Found'): throw new git_documentdb_remote_errors_1.HTTPError404NotFound(error); default: if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.CannotConnectError(error); } } // eslint-disable-next-line no-await-in-loop await (0, utils_1.sleep)(remoteOptions.retryInterval); } } exports.fetch = fetch; /** * git push * * @throws {@link InvalidGitRemoteError} * @throws {@link UnfetchedCommitExistsError} * @throws {@link InvalidURLFormatError} * @throws {@link NetworkError} * @throws {@link HTTPError401AuthorizationRequired} * @throws {@link HTTPError404NotFound} * @throws {@link HTTPError403Forbidden} * @throws {@link CannotConnectError} * * @throws # Errors from createCredentialForGitHub * @throws - {@link InvalidURLFormatError} * @throws - {@link InvalidRepositoryURLError} * * @throws # Errors from createCredential * @throws - {@link InvalidAuthenticationTypeError} * * @internal */ // eslint-disable-next-line complexity async function push(workingDir, remoteOptions, remoteName, localBranchName, remoteBranchName, logger) { var _a, _b; logger !== null && logger !== void 0 ? logger : (logger = new tslog_1.Logger({ name: 'plugin-nodegit', minLevel: 'trace', displayDateTime: false, displayFunctionName: false, displayFilePath: 'hidden', })); logger.debug(`remote-isomorphic-git: push: ${remoteOptions.remoteUrl}`); remoteName !== null && remoteName !== void 0 ? remoteName : (remoteName = 'origin'); localBranchName !== null && localBranchName !== void 0 ? localBranchName : (localBranchName = 'main'); remoteBranchName !== null && remoteBranchName !== void 0 ? remoteBranchName : (remoteBranchName = 'main'); const urlOfRemote = await isomorphic_git_1.default.getConfig({ fs: fs_1.default, dir: workingDir, path: `remote.${remoteName}.url`, }); if (urlOfRemote === undefined) { throw new git_documentdb_remote_errors_1.InvalidGitRemoteError(`remote '${remoteName}' does not exist`); } (_a = remoteOptions.retry) !== null && _a !== void 0 ? _a : (remoteOptions.retry = const_1.NETWORK_RETRY); (_b = remoteOptions.retryInterval) !== null && _b !== void 0 ? _b : (remoteOptions.retryInterval = const_1.NETWORK_RETRY_INTERVAL); const pushOption = { fs: fs_1.default, dir: workingDir, http: node_1.default, url: remoteOptions.remoteUrl, remote: remoteName, ref: localBranchName, remoteRef: remoteBranchName, }; const cred = createCredentialCallback(remoteOptions); if (cred) { pushOption.onAuth = cred; } for (let i = 0; i < remoteOptions.retry + 1; i++) { // eslint-disable-next-line no-await-in-loop const res = await isomorphic_git_1.default.push(pushOption).catch(err => err); let error = ''; if (res instanceof Error) { error = res.toString(); } else { break; } // console.log('connect push error: ' + error); switch (true) { // NoRefspecError does not invoke because push does not need Remote when url is specified. // case error.startsWith('NoRefspecError'): // throw new InvalidGitRemoteError(error); case error.startsWith('PushRejectedError:'): throw new git_documentdb_remote_errors_1.UnfetchedCommitExistsError(); case error.startsWith('UrlParseError:'): case error.startsWith('Error: getaddrinfo ENOTFOUND'): throw new git_documentdb_remote_errors_1.InvalidURLFormatError(error); case error.startsWith('Error: connect EACCES'): case error.startsWith('Error: connect ECONNREFUSED'): // isomorphic-git throws this when network is limited. if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.NetworkError(error); } break; case error.startsWith('HttpError: HTTP Error: 401'): throw new git_documentdb_remote_errors_1.HTTPError401AuthorizationRequired(error); case error.startsWith('HttpError: HTTP Error: 404 Not Found'): throw new git_documentdb_remote_errors_1.HTTPError404NotFound(error); case error.startsWith('HttpError: HTTP Error: 403 Forbidden'): throw new git_documentdb_remote_errors_1.HTTPError403Forbidden(error); default: if (i >= remoteOptions.retry) { throw new git_documentdb_remote_errors_1.CannotConnectError(error); } } // eslint-disable-next-line no-await-in-loop await (0, utils_1.sleep)(remoteOptions.retryInterval); } } exports.push = push; //# sourceMappingURL=remote-isomorphic-git.js.map