From 164b9af5131108fe0691b715f89c00a201306a83 Mon Sep 17 00:00:00 2001 From: Ayoub Kaanich <kayoub5@live.com> Date: Thu, 8 Nov 2018 13:21:36 +0100 Subject: [PATCH] feat: gitFs over SSH (#2768) Support setting git clone protocol `http`, `https` or `ssh`. Config name: `gitFsProtocol`. Platform independent. Closes #2708 --- lib/config/definitions.js | 5 ++-- lib/config/migration.js | 9 +++++++ lib/platform/git/storage.js | 18 +++++++++++++ lib/platform/github/index.js | 9 +++---- lib/platform/gitlab/index.js | 17 ++++++------- .../__snapshots__/migration.spec.js.snap | 2 ++ test/config/migration.spec.js | 2 ++ test/platform/git/storage.spec.js | 25 +++++++++++++++++++ website/docs/self-hosted-configuration.md | 1 + 9 files changed, 72 insertions(+), 16 deletions(-) diff --git a/lib/config/definitions.js b/lib/config/definitions.js index 8ba309ae7f..f0f0f9c68e 100644 --- a/lib/config/definitions.js +++ b/lib/config/definitions.js @@ -182,9 +182,10 @@ const options = [ name: 'gitFs', description: 'Use git for FS operations instead of API. GitHub only.', stage: 'repository', - type: 'boolean', + type: 'string', + allowedValues: ['https', 'http', 'ssh'], admin: true, - default: false, + default: null, }, { name: 'exposeEnv', diff --git a/lib/config/migration.js b/lib/config/migration.js index 6ed9b61d28..e58dcefa19 100644 --- a/lib/config/migration.js +++ b/lib/config/migration.js @@ -56,6 +56,15 @@ function migrateConfig(config) { ); } delete migratedConfig.pathRules; + } else if (key === 'gitFs') { + if (val === false) { + isMigrated = true; + migratedConfig.gitFs = null; + } + if (val === true) { + isMigrated = true; + migratedConfig.gitFs = 'https'; + } } else if (key === 'packageFiles' && is.array(val)) { isMigrated = true; const fileList = []; diff --git a/lib/platform/git/storage.js b/lib/platform/git/storage.js index 7bdb4af241..12558edd89 100644 --- a/lib/platform/git/storage.js +++ b/lib/platform/git/storage.js @@ -1,6 +1,7 @@ const fs = require('fs-extra'); const { join } = require('path'); const path = require('path'); +const URL = require('url'); const Git = require('simple-git/promise'); const convertHrtime = require('convert-hrtime'); @@ -279,4 +280,21 @@ function localName(branchName) { return branchName.replace(/^origin\//, ''); } +Storage.getUrl = ({ gitFs, auth, hostname, repository }) => { + let protocol = gitFs || 'https'; + // istanbul ignore if + if (protocol.toString() === 'true') { + protocol = 'https'; + } + if (protocol === 'ssh') { + return `git@${hostname}:${repository}.git`; + } + return URL.format({ + protocol, + auth, + hostname, + pathname: repository + '.git', + }); +}; + module.exports = Storage; diff --git a/lib/platform/github/index.js b/lib/platform/github/index.js index 322105cfbb..adb110e859 100644 --- a/lib/platform/github/index.js +++ b/lib/platform/github/index.js @@ -307,19 +307,18 @@ async function initRepo({ // istanbul ignore if if (gitFs) { logger.debug('Enabling Git FS'); - let { protocol, host } = URL.parse(opts.endpoint); + let { host } = URL.parse(opts.endpoint); if (host === 'api.github.com') { host = null; } host = host || 'github.com'; - protocol = protocol || 'https:'; - const url = URL.format({ - protocol, + const url = GitStorage.getUrl({ + gitFs, auth: config.forkToken || (global.appMode ? `x-access-token:${opts.token}` : opts.token), hostname: host, - pathname: repository + '.git', + repository, }); config.storage = new GitStorage(); await config.storage.initRepo({ diff --git a/lib/platform/gitlab/index.js b/lib/platform/gitlab/index.js index 6c7f6022fa..18d844b4c8 100644 --- a/lib/platform/gitlab/index.js +++ b/lib/platform/gitlab/index.js @@ -145,14 +145,12 @@ async function initRepo({ // istanbul ignore if if (config.gitFs) { logger.debug('Enabling Git FS'); - let { protocol, host } = URL.parse(opts.endpoint); - host = host || 'gitlab.com'; - protocol = protocol || 'https:'; - const url = URL.format({ - protocol, + const { host } = URL.parse(opts.endpoint); + const url = GitStorage.getUrl({ + gitFs, auth: 'oauth2:' + (config.forkToken || opts.token), - hostname: host, - pathname: repository + '.git', + hostname: host || 'gitlab.com', + repository, }); config.storage = new GitStorage(); await config.storage.initRepo({ @@ -241,10 +239,11 @@ async function commitFilesToBranch( message, parentBranch = config.baseBranch ) { - // GitLab does not support push with GitFs + // GitLab does not support push with GitFs token + // See https://gitlab.com/gitlab-org/gitlab-ce/issues/18106 let storage = config.storage; // istanbul ignore if - if (config.gitFs) { + if (config.gitFs === 'http' || config.gitFs === 'https') { storage = new Storage(); storage.initRepo(config); } diff --git a/test/config/__snapshots__/migration.spec.js.snap b/test/config/__snapshots__/migration.spec.js.snap index 917a9d2b9f..d71effdf69 100644 --- a/test/config/__snapshots__/migration.spec.js.snap +++ b/test/config/__snapshots__/migration.spec.js.snap @@ -21,6 +21,7 @@ Object { "config:js-app", "config:js-lib", ], + "gitFs": null, "hostRules": Array [ Object {}, ], @@ -29,6 +30,7 @@ Object { ], "lockFileMaintenance": Object { "automerge": true, + "gitFs": "https", "schedule": "before 5am", }, "major": Object { diff --git a/test/config/migration.spec.js b/test/config/migration.spec.js index 265092f30a..d3e695e18d 100644 --- a/test/config/migration.spec.js +++ b/test/config/migration.spec.js @@ -11,6 +11,7 @@ describe('config/migration', () => { maintainYarnLock: true, onboarding: 'false', multipleMajorPrs: true, + gitFs: false, separateMajorReleases: true, separatePatchReleases: true, automerge: 'none', @@ -57,6 +58,7 @@ describe('config/migration', () => { }, ], lockFileMaintenance: { + gitFs: true, automerge: 'any', schedule: 'before 5am every day', }, diff --git a/test/platform/git/storage.spec.js b/test/platform/git/storage.spec.js index 1cdbc061c3..f4e56d9fd0 100644 --- a/test/platform/git/storage.spec.js +++ b/test/platform/git/storage.spec.js @@ -212,4 +212,29 @@ describe('platform/git/storage', () => { expect(await git.getCommitMessages()).toMatchSnapshot(); }); }); + + describe('Storage.getUrl()', () => { + const getUrl = GitStorage.getUrl; + it('returns https url', () => { + expect( + getUrl({ + gitFs: 'https', + auth: 'user:pass', + hostname: 'host', + repository: 'some/repo', + }) + ).toEqual('https://user:pass@host/some/repo.git'); + }); + + it('returns ssh url', () => { + expect( + getUrl({ + gitFs: 'ssh', + auth: 'user:pass', + hostname: 'host', + repository: 'some/repo', + }) + ).toEqual('git@host:some/repo.git'); + }); + }); }); diff --git a/website/docs/self-hosted-configuration.md b/website/docs/self-hosted-configuration.md index b9a0eee7f7..996d197b65 100644 --- a/website/docs/self-hosted-configuration.md +++ b/website/docs/self-hosted-configuration.md @@ -42,6 +42,7 @@ RFC5322-compliant string if you wish to customise the git author for commits. ## gitFs This setting is experimental, and works for GitHub repositories only. If enabled, Renovate will `git clone` repos and use `git` for file operations such as creating branches and committing files. +Set it to a string specifing the transport used by Git (`https`, `http` or `ssh`). ## gitPrivateKey -- GitLab