diff --git a/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap index 06724af9a404efac6ca37a6173e6eb59dd5a5456..5603dd7dc7ee6da00839a1d4030fe41c5a08fe11 100644 --- a/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap +++ b/lib/modules/datasource/git-refs/__snapshots__/index.spec.ts.snap @@ -1,9 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`modules/datasource/git-refs/index getDigest() returns digest for HEAD 1`] = `"a9920c014aebc28dc1b23e7efcc006d0455cc710"`; - -exports[`modules/datasource/git-refs/index getDigest() returns digest for tag 1`] = `"2b52829c7c1bd65b3501c450849c53b90b11fa0e"`; - exports[`modules/datasource/git-refs/index getReleases returns versions filtered from tags 1`] = ` { "releases": [ diff --git a/lib/modules/datasource/git-refs/base.ts b/lib/modules/datasource/git-refs/base.ts index eddd489e9cf67b4588d67378477f61607414108b..261a0a8543aa2c6c4ab383f870f7c8165d9fe714 100644 --- a/lib/modules/datasource/git-refs/base.ts +++ b/lib/modules/datasource/git-refs/base.ts @@ -2,6 +2,7 @@ import is from '@sindresorhus/is'; import { simpleGit } from 'simple-git'; import { logger } from '../../../logger'; import { cache } from '../../../util/cache/package/decorator'; +import { getGitEnvironmentVariables } from '../../../util/git/auth'; import { simpleGitConfig } from '../../../util/git/config'; import { getRemoteUrlWithToken } from '../../../util/git/url'; import { newlineRegex, regEx } from '../../../util/regex'; @@ -27,7 +28,16 @@ export abstract class GitDatasource extends Datasource { async getRawRefs({ packageName, }: GetReleasesConfig): Promise<RawRefs[] | null> { - const git = simpleGit(simpleGitConfig()); + const gitSubmoduleAuthEnvironmentVariables = getGitEnvironmentVariables([ + this.id, + ]); + const gitEnv = { + // pass all existing env variables + ...process.env, + // add all known git Variables + ...gitSubmoduleAuthEnvironmentVariables, + }; + const git = simpleGit(simpleGitConfig()).env(gitEnv); // fetch remote tags const lsRemote = await git.listRemote([ diff --git a/lib/modules/datasource/git-refs/index.spec.ts b/lib/modules/datasource/git-refs/index.spec.ts index 75405d464710de4fb14465b4e6b27e86b39d9a11..026bdd292f37108a2fc759a5158bc987495aa634 100644 --- a/lib/modules/datasource/git-refs/index.spec.ts +++ b/lib/modules/datasource/git-refs/index.spec.ts @@ -1,10 +1,11 @@ -import _simpleGit, { Response, SimpleGit } from 'simple-git'; +import { SimpleGit, simpleGit } from 'simple-git'; import { getPkgReleases } from '..'; import { Fixtures } from '../../../../test/fixtures'; +import { add, clear } from '../../../util/host-rules'; import { GitRefsDatasource } from '.'; jest.mock('simple-git'); -const simpleGit: jest.Mock<Partial<SimpleGit>> = _simpleGit as never; +const simpleGitFactoryMock = simpleGit as jest.Mock; const packageName = 'https://github.com/example/example.git'; @@ -13,13 +14,29 @@ const lsRemote1 = Fixtures.get('ls-remote-1.txt'); const datasource = GitRefsDatasource.id; describe('modules/datasource/git-refs/index', () => { + let gitMock: any; + + beforeEach(() => { + // clear host rules + clear(); + + // clear environment variables + process.env = {}; + + // reset git mock + gitMock = { + env: jest.fn(), + listRemote: jest.fn(), + }; + + simpleGitFactoryMock.mockReturnValue(gitMock); + gitMock.env.mockImplementation(() => gitMock as unknown as SimpleGit); + }); + describe('getReleases', () => { it('returns nil if response is wrong', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve('') as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(''); + const versions = await getPkgReleases({ datasource, packageName, @@ -28,11 +45,8 @@ describe('modules/datasource/git-refs/index', () => { }); it('returns nil if response is malformed', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve('aabbccddeeff') as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue('aabbccddeeff'); + const { releases } = (await getPkgReleases({ datasource, packageName, @@ -41,11 +55,8 @@ describe('modules/datasource/git-refs/index', () => { }); it('returns nil if remote call throws exception', async () => { - simpleGit.mockReturnValue({ - listRemote() { - throw new Error(); - }, - }); + gitMock.listRemote.mockRejectedValue(new Error()); + const versions = await getPkgReleases({ datasource, packageName, @@ -54,11 +65,7 @@ describe('modules/datasource/git-refs/index', () => { }); it('returns versions filtered from tags', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(lsRemote1); const versions = await getPkgReleases({ datasource, @@ -72,11 +79,8 @@ describe('modules/datasource/git-refs/index', () => { describe('getDigest()', () => { it('returns null if not found', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(lsRemote1); + const digest = await new GitRefsDatasource().getDigest( { packageName: 'a tag to look up' }, 'v2.0.0' @@ -85,24 +89,18 @@ describe('modules/datasource/git-refs/index', () => { }); it('returns digest for tag', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(lsRemote1); + const digest = await new GitRefsDatasource().getDigest( { packageName: 'a tag to look up' }, 'v1.0.4' ); - expect(digest).toMatchSnapshot(); + expect(digest).toBe('2b52829c7c1bd65b3501c450849c53b90b11fa0e'); }); it('ignores refs/for/', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(lsRemote1); + const digest = await new GitRefsDatasource().getDigest( { packageName: 'a tag to look up' }, 'master' @@ -111,16 +109,74 @@ describe('modules/datasource/git-refs/index', () => { }); it('returns digest for HEAD', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, + gitMock.listRemote.mockResolvedValue(lsRemote1); + + const digest = await new GitRefsDatasource().getDigest( + { packageName: 'another tag to look up' }, + undefined + ); + expect(digest).toBe('a9920c014aebc28dc1b23e7efcc006d0455cc710'); + }); + + it('calls simpleGit with emptyEnv if no hostrules exist', async () => { + gitMock.listRemote.mockResolvedValue(lsRemote1); + + const digest = await new GitRefsDatasource().getDigest( + { packageName: 'another tag to look up' }, + undefined + ); + expect(digest).toBe('a9920c014aebc28dc1b23e7efcc006d0455cc710'); + expect(gitMock.env).toHaveBeenCalledWith({}); + }); + + it('calls simpleGit with git envs if hostrules exist', async () => { + gitMock.listRemote.mockResolvedValue(lsRemote1); + + add({ + hostType: 'github', + matchHost: 'api.github.com', + token: 'token123', }); + const digest = await new GitRefsDatasource().getDigest( { packageName: 'another tag to look up' }, undefined ); - expect(digest).toMatchSnapshot(); + expect(digest).toBe('a9920c014aebc28dc1b23e7efcc006d0455cc710'); + expect(gitMock.env).toHaveBeenCalledWith({ + GIT_CONFIG_COUNT: '3', + GIT_CONFIG_KEY_0: 'url.https://ssh:token123@github.com/.insteadOf', + GIT_CONFIG_KEY_1: 'url.https://git:token123@github.com/.insteadOf', + GIT_CONFIG_KEY_2: 'url.https://token123@github.com/.insteadOf', + GIT_CONFIG_VALUE_0: 'ssh://git@github.com/', + GIT_CONFIG_VALUE_1: 'git@github.com:', + GIT_CONFIG_VALUE_2: 'https://github.com/', + }); + }); + + it('calls simpleGit with git envs if hostrules exist for datasource type git-refs', async () => { + gitMock.listRemote.mockResolvedValue(lsRemote1); + + add({ + hostType: 'git-refs', + matchHost: 'git.example.com', + token: 'token123', + }); + + const digest = await new GitRefsDatasource().getDigest( + { packageName: 'another tag to look up' }, + undefined + ); + expect(digest).toBe('a9920c014aebc28dc1b23e7efcc006d0455cc710'); + expect(gitMock.env).toHaveBeenCalledWith({ + GIT_CONFIG_COUNT: '3', + GIT_CONFIG_KEY_0: 'url.https://ssh:token123@git.example.com/.insteadOf', + GIT_CONFIG_KEY_1: 'url.https://git:token123@git.example.com/.insteadOf', + GIT_CONFIG_KEY_2: 'url.https://token123@git.example.com/.insteadOf', + GIT_CONFIG_VALUE_0: 'ssh://git@git.example.com/', + GIT_CONFIG_VALUE_1: 'git@git.example.com:', + GIT_CONFIG_VALUE_2: 'https://git.example.com/', + }); }); }); }); diff --git a/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap b/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap index c056809881df8c30ca28512405a615db2f5004d2..28b3c827883563dbd826103ac069853b436a170b 100644 --- a/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap +++ b/lib/modules/datasource/git-tags/__snapshots__/index.spec.ts.snap @@ -1,9 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`modules/datasource/git-tags/index getDigest() returns digest for HEAD 1`] = `"a9920c014aebc28dc1b23e7efcc006d0455cc710"`; - -exports[`modules/datasource/git-tags/index getDigest() returns digest for tag 1`] = `"9cb93e0b236385a4e2efd089d7c6a458f5ff321f"`; - exports[`modules/datasource/git-tags/index getReleases returns versions filtered from tags 1`] = ` { "releases": [ diff --git a/lib/modules/datasource/git-tags/index.spec.ts b/lib/modules/datasource/git-tags/index.spec.ts index a14744c6f7d6af2e5f5673af152423cd195b8236..468de9850432bc8a8cdb210f810695b6fdc3de21 100644 --- a/lib/modules/datasource/git-tags/index.spec.ts +++ b/lib/modules/datasource/git-tags/index.spec.ts @@ -1,10 +1,11 @@ -import _simpleGit, { Response, SimpleGit } from 'simple-git'; +import { SimpleGit, simpleGit } from 'simple-git'; import { getPkgReleases } from '..'; import { Fixtures } from '../../../../test/fixtures'; +import { add, clear } from '../../../util/host-rules'; import { GitTagsDatasource } from '.'; jest.mock('simple-git'); -const simpleGit: jest.Mock<Partial<SimpleGit>> = _simpleGit as never; +const simpleGitFactoryMock = simpleGit as jest.Mock; const packageName = 'https://github.com/example/example.git'; @@ -14,33 +15,42 @@ const datasource = GitTagsDatasource.id; const datasourceInstance = new GitTagsDatasource(); describe('modules/datasource/git-tags/index', () => { + let gitMock: any; + + beforeEach(() => { + // clear host rules + clear(); + + // clear environment variables + process.env = {}; + + // reset git mock + gitMock = { + env: jest.fn(), + listRemote: jest.fn(), + }; + + simpleGitFactoryMock.mockReturnValue(gitMock); + gitMock.env.mockImplementation(() => gitMock as unknown as SimpleGit); + }); + describe('getReleases', () => { it('returns nil if response is wrong', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve('') as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(''); + const versions = await getPkgReleases({ datasource, packageName }); expect(versions).toBeNull(); }); it('returns nil if remote call throws exception', async () => { - simpleGit.mockReturnValue({ - listRemote() { - throw new Error(); - }, - }); + gitMock.listRemote.mockRejectedValue(new Error()); + const versions = await getPkgReleases({ datasource, packageName }); expect(versions).toBeNull(); }); it('returns versions filtered from tags', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(lsRemote1); const versions = await getPkgReleases({ datasource, @@ -52,11 +62,8 @@ describe('modules/datasource/git-tags/index', () => { describe('getDigest()', () => { it('returns null if not found', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(lsRemote1); + const digest = await datasourceInstance.getDigest( { packageName: 'a tag to look up' }, 'notfound' @@ -65,29 +72,73 @@ describe('modules/datasource/git-tags/index', () => { }); it('returns digest for tag', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, - }); + gitMock.listRemote.mockResolvedValue(lsRemote1); + const digest = await datasourceInstance.getDigest( { packageName: 'a tag to look up' }, 'v1.0.2' ); - expect(digest).toMatchSnapshot(); + expect(digest).toBe('9cb93e0b236385a4e2efd089d7c6a458f5ff321f'); }); it('returns digest for HEAD', async () => { - simpleGit.mockReturnValue({ - listRemote() { - return Promise.resolve(lsRemote1) as Response<string>; - }, + gitMock.listRemote.mockResolvedValue(lsRemote1); + + const digest = await datasourceInstance.getDigest( + { packageName: 'another tag to look up' }, + undefined + ); + expect(digest).toBe('a9920c014aebc28dc1b23e7efcc006d0455cc710'); + }); + + it('returns digest for HEAD with authentication environment variables', async () => { + gitMock.listRemote.mockResolvedValue(lsRemote1); + + add({ + hostType: 'github', + matchHost: 'api.github.com', + token: 'token123', }); + const digest = await datasourceInstance.getDigest( { packageName: 'another tag to look up' }, undefined ); - expect(digest).toMatchSnapshot(); + expect(digest).toBe('a9920c014aebc28dc1b23e7efcc006d0455cc710'); + expect(gitMock.env).toHaveBeenCalledWith({ + GIT_CONFIG_COUNT: '3', + GIT_CONFIG_KEY_0: 'url.https://ssh:token123@github.com/.insteadOf', + GIT_CONFIG_KEY_1: 'url.https://git:token123@github.com/.insteadOf', + GIT_CONFIG_KEY_2: 'url.https://token123@github.com/.insteadOf', + GIT_CONFIG_VALUE_0: 'ssh://git@github.com/', + GIT_CONFIG_VALUE_1: 'git@github.com:', + GIT_CONFIG_VALUE_2: 'https://github.com/', + }); + }); + + it('returns digest for HEAD with authentication environment variables for datasource type git-tags', async () => { + gitMock.listRemote.mockResolvedValue(lsRemote1); + + add({ + hostType: 'git-tags', + matchHost: 'git.example.com', + token: 'token123', + }); + + const digest = await datasourceInstance.getDigest( + { packageName: 'another tag to look up' }, + undefined + ); + expect(digest).toBe('a9920c014aebc28dc1b23e7efcc006d0455cc710'); + expect(gitMock.env).toHaveBeenCalledWith({ + GIT_CONFIG_COUNT: '3', + GIT_CONFIG_KEY_0: 'url.https://ssh:token123@git.example.com/.insteadOf', + GIT_CONFIG_KEY_1: 'url.https://git:token123@git.example.com/.insteadOf', + GIT_CONFIG_KEY_2: 'url.https://token123@git.example.com/.insteadOf', + GIT_CONFIG_VALUE_0: 'ssh://git@git.example.com/', + GIT_CONFIG_VALUE_1: 'git@git.example.com:', + GIT_CONFIG_VALUE_2: 'https://git.example.com/', + }); }); }); });