diff --git a/lib/datasource/gitlab-tags/index.spec.ts b/lib/datasource/gitlab-tags/index.spec.ts index 0f468cf8a7db6cf5843d8eac671b40fbb9a181e3..1c7ae2c8ba7ca7beda04200b99fd33e52a3108f1 100644 --- a/lib/datasource/gitlab-tags/index.spec.ts +++ b/lib/datasource/gitlab-tags/index.spec.ts @@ -1,4 +1,4 @@ -import { getPkgReleases } from '..'; +import { getDigest, getPkgReleases } from '..'; import * as httpMock from '../../../test/http-mock'; import { id as datasource } from '.'; @@ -76,4 +76,75 @@ describe('datasource/gitlab-tags/index', () => { expect(res.releases).toHaveLength(2); }); }); + + describe('getDigest', () => { + it('returns commits from gitlab installation', async () => { + const digest = 'abcd00001234'; + const body = [ + { + id: digest, + }, + ]; + httpMock + .scope('https://gitlab.company.com') + .get('/api/v4/projects/some%2Fdep2/repository/commits?per_page=1') + .reply(200, body); + const res = await getDigest({ + datasource, + registryUrls: ['https://gitlab.company.com/api/v4/'], + depName: 'some/dep2', + }); + expect(res).toBe(digest); + }); + + it('returns commits from gitlab installation for a specific branch', async () => { + const digest = 'abcd00001234'; + const body = { + id: digest, + }; + httpMock + .scope('https://gitlab.company.com') + .get('/api/v4/projects/some%2Fdep2/repository/commits/branch') + .reply(200, body); + const res = await getDigest( + { + datasource, + registryUrls: ['https://gitlab.company.com/api/v4/'], + depName: 'some/dep2', + }, + 'branch' + ); + expect(res).toBe(digest); + }); + + it('returns null from gitlab installation with no commits', async () => { + const body = []; + httpMock + .scope('https://gitlab.company.com') + .get('/api/v4/projects/some%2Fdep2/repository/commits?per_page=1') + .reply(200, body); + const res = await getDigest({ + datasource, + registryUrls: ['https://gitlab.company.com/api/v4/'], + depName: 'some/dep2', + }); + expect(res).toBeNull(); + }); + + it('returns null from gitlab installation with unknown branch', async () => { + httpMock + .scope('https://gitlab.company.com') + .get('/api/v4/projects/some%2Fdep2/repository/commits/unknown-branch') + .reply(404, null); + const res = await getDigest( + { + datasource, + registryUrls: ['https://gitlab.company.com/api/v4/'], + depName: 'some/dep2', + }, + 'unknown-branch' + ); + expect(res).toBeNull(); + }); + }); }); diff --git a/lib/datasource/gitlab-tags/index.ts b/lib/datasource/gitlab-tags/index.ts index b7c75fafcad5297834d416a32c083689559cb96e..7f7f234b0403f75dec9303fb5c072bcad133bd95 100644 --- a/lib/datasource/gitlab-tags/index.ts +++ b/lib/datasource/gitlab-tags/index.ts @@ -1,8 +1,9 @@ +import { logger } from '../../logger'; import * as packageCache from '../../util/cache/package'; import { GitlabHttp } from '../../util/http/gitlab'; import { joinUrlParts } from '../../util/url'; -import type { GetReleasesConfig, ReleaseResult } from '../types'; -import type { GitlabTag } from './types'; +import type { DigestConfig, GetReleasesConfig, ReleaseResult } from '../types'; +import type { GitlabCommit, GitlabTag } from './types'; import { defaultRegistryUrl, getDepHost, getSourceUrl } from './util'; export const id = 'gitlab-tags'; @@ -14,8 +15,7 @@ export const registryStrategy = 'first'; const cacheNamespace = 'datasource-gitlab'; -function getCacheKey(depHost: string, repo: string): string { - const type = 'tags'; +function getCacheKey(depHost: string, repo: string, type = 'tags'): string { return `${depHost}:${repo}:${type}`; } @@ -69,3 +69,68 @@ export async function getReleases({ ); return dependency; } + +/** + * gitlab.getDigest + * + * This function will simply return the latest commit hash for the configured repository. + */ +export async function getDigest( + { lookupName: repo, registryUrl }: Partial<DigestConfig>, + newValue?: string +): Promise<string | null> { + const depHost = getDepHost(registryUrl); + + const cachedResult = await packageCache.get<string>( + cacheNamespace, + getCacheKey(depHost, repo, 'commit') + ); + // istanbul ignore if + if (cachedResult) { + return cachedResult; + } + + const urlEncodedRepo = encodeURIComponent(repo); + let digest: string; + + try { + if (newValue) { + const url = joinUrlParts( + depHost, + `api/v4/projects`, + urlEncodedRepo, + `repository/commits/`, + newValue + ); + const gitlabCommits = await gitlabApi.getJson<GitlabCommit>(url); + digest = gitlabCommits.body.id; + } else { + const url = joinUrlParts( + depHost, + `api/v4/projects`, + urlEncodedRepo, + `repository/commits?per_page=1` + ); + const gitlabCommits = await gitlabApi.getJson<GitlabCommit[]>(url); + digest = gitlabCommits.body[0].id; + } + } catch (err) { + logger.debug( + { gitlabRepo: repo, err, registryUrl }, + 'Error getting latest commit from Gitlab repo' + ); + } + + if (!digest) { + return null; + } + + const cacheMinutes = 10; + await packageCache.set( + cacheNamespace, + getCacheKey(registryUrl, repo, 'commit'), + digest, + cacheMinutes + ); + return digest; +} diff --git a/lib/datasource/gitlab-tags/types.ts b/lib/datasource/gitlab-tags/types.ts index 47d6ee66bda8bcb4492d6c72766f08ecf1cab5d5..3664fd7106bbba318a96528ec0e00de03a647016 100644 --- a/lib/datasource/gitlab-tags/types.ts +++ b/lib/datasource/gitlab-tags/types.ts @@ -4,3 +4,7 @@ export type GitlabTag = { created_at?: string; }; }; + +export type GitlabCommit = { + id: string; +}; diff --git a/lib/datasource/go/__snapshots__/digest.spec.ts.snap b/lib/datasource/go/__snapshots__/digest.spec.ts.snap index ca66566f8f16b01da298224d515af137d556b97a..15c72755c5fa856f930d76be4ee4399fa0af2d22 100644 --- a/lib/datasource/go/__snapshots__/digest.spec.ts.snap +++ b/lib/datasource/go/__snapshots__/digest.spec.ts.snap @@ -1,19 +1,5 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`datasource/go/digest getDigest gitlab digest is not supported at the moment 1`] = ` -Array [ - Object { - "headers": Object { - "accept-encoding": "gzip, deflate, br", - "host": "gitlab.com", - "user-agent": "RenovateBot/0.0.0-semantic-release (https://github.com/renovatebot/renovate)", - }, - "method": "GET", - "url": "https://gitlab.com/golang/text?go-get=1", - }, -] -`; - exports[`datasource/go/digest getDigest returns digest 1`] = ` Array [ Object { diff --git a/lib/datasource/go/digest.spec.ts b/lib/datasource/go/digest.spec.ts index 1439970baa663f6971d69e38d5d71c0175416fba..88acefd298f704a9d3247bf5e2df4e456a490a3d 100644 --- a/lib/datasource/go/digest.spec.ts +++ b/lib/datasource/go/digest.spec.ts @@ -1,5 +1,5 @@ import * as httpMock from '../../../test/http-mock'; -import { mocked } from '../../../test/util'; +import { loadFixture, mocked } from '../../../test/util'; import * as _hostRules from '../../util/host-rules'; import { getDigest } from '.'; @@ -49,17 +49,36 @@ describe('datasource/go/digest', () => { expect(res).toBeNull(); expect(httpMock.getTrace()).toMatchSnapshot(); }); - it('gitlab digest is not supported at the moment', async () => { + it('supports gitlab digest', async () => { httpMock .scope('https://gitlab.com/') - .get('/golang/text?go-get=1') - .reply(200, ''); + .get('/group/subgroup?go-get=1') + .reply(200, loadFixture('go-get-gitlab.html')); + httpMock + .scope('https://gitlab.com/') + .get('/api/v4/projects/group%2Fsubgroup/repository/commits?per_page=1') + .reply(200, [{ id: 'abcdefabcdefabcdefabcdef' }]); const res = await getDigest( - { lookupName: 'gitlab.com/golang/text' }, + { lookupName: 'gitlab.com/group/subgroup' }, null ); - expect(res).toBeNull(); - expect(httpMock.getTrace()).toMatchSnapshot(); + expect(res).toBe('abcdefabcdefabcdefabcdef'); + }); + it('supports gitlab digest with a specific branch', async () => { + const branch = 'some-branch'; + httpMock + .scope('https://gitlab.com/') + .get('/group/subgroup?go-get=1') + .reply(200, loadFixture('go-get-gitlab.html')); + httpMock + .scope('https://gitlab.com/') + .get(`/api/v4/projects/group%2Fsubgroup/repository/commits/${branch}`) + .reply(200, { id: 'abcdefabcdefabcdefabcdef' }); + const res = await getDigest( + { lookupName: 'gitlab.com/group/subgroup' }, + branch + ); + expect(res).toBe('abcdefabcdefabcdefabcdef'); }); it('returns digest', async () => { httpMock diff --git a/lib/datasource/go/digest.ts b/lib/datasource/go/digest.ts index 7ea05e6171e4efb9ee77c217e3168b65bd4c95e2..9344cbaa5a78d377adb577e7ab91f8119ab74760 100644 --- a/lib/datasource/go/digest.ts +++ b/lib/datasource/go/digest.ts @@ -1,4 +1,5 @@ import * as github from '../github-tags'; +import * as gitlab from '../gitlab-tags'; import type { DigestConfig } from '../types'; import { bitbucket } from './common'; import { getDatasource } from './get-datasource'; @@ -32,6 +33,9 @@ export async function getDigest( case bitbucket.id: { return bitbucket.getDigest(source, tag); } + case gitlab.id: { + return gitlab.getDigest(source, tag); + } /* istanbul ignore next: can never happen, makes lint happy */ default: { return null;