diff --git a/lib/config/definitions.js b/lib/config/definitions.js index 8ba309ae7f5dbd1b6998a8040423125b5fe053de..f0f0f9c68ec65ec7bfc5dc9cd129f8ce9e41feb1 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 6ed9b61d2802ef41d59e69b385453b5dcfe032b0..e58dcefa1966fb81de3148f87ed139189075497b 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 7bdb4af24123eecd22b50b021c536d02d01d35f9..12558edd89f64065bc850b3cf6d352a0783d8fec 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 322105cfbbeb9fa82697b4f3283954d859a8acd1..adb110e859a2988c02b8f871ccc1c2a040bd2b53 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 6c7f6022facba24e5c7adddfbf6c9e38441d9ac7..18d844b4c871ecf2b5c81a816608813277ca7ccd 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 917a9d2b9f91da3b2d19289b36f1464150e0ec02..d71effdf6914340033d195e5b3603a7a07aceefb 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 265092f30aa4dfd8f2d5fbda68691ff5f227ad7b..d3e695e18da7f7d0c2f0702fb1cd22395fa05b75 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 1cdbc061c35430b6a470621727202dd3bb24514c..f4e56d9fd0dda593547cad87a230bff1a374b6d7 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 b9a0eee7f7fafb3364c28c09787cbc29ba7e52af..996d197b6571d1c1c6803b3f87e5a9641817777a 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