Skip to content

Commit

Permalink
feat(go): add support for github enterprise in go datasource (#7252)
Browse files Browse the repository at this point in the history
  • Loading branch information
handsomematt authored Sep 22, 2020
1 parent edc2016 commit 2932e88
Show file tree
Hide file tree
Showing 6 changed files with 162 additions and 3 deletions.
32 changes: 32 additions & 0 deletions lib/datasource/github-tags/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -138,3 +138,35 @@ Array [
},
]
`;

exports[`datasource/github-tags getReleases supports ghe 1`] = `
Object {
"releases": Array [
Object {
"gitRef": "v1.0.0",
"version": "v1.0.0",
},
Object {
"gitRef": "v1.1.0",
"version": "v1.1.0",
},
],
"sourceUrl": "https://git.enterprise.com/some/dep2",
}
`;

exports[`datasource/github-tags getReleases supports ghe 2`] = `
Array [
Object {
"headers": Object {
"accept": "application/vnd.github.v3+json",
"accept-encoding": "gzip, deflate",
"authorization": "token some-token",
"host": "git.enterprise.com",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://git.enterprise.com/api/v3/repos/some/dep2/tags?per_page=100",
},
]
`;
15 changes: 15 additions & 0 deletions lib/datasource/github-tags/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ jest.mock('../../util/host-rules');
const hostRules: any = _hostRules;

const githubApiHost = 'https://api.github.com';
const githubEnterpriseApiHost = 'https://git.enterprise.com';

describe('datasource/github-tags', () => {
beforeEach(() => {
Expand Down Expand Up @@ -102,5 +103,19 @@ describe('datasource/github-tags', () => {
expect(res.releases).toHaveLength(2);
expect(httpMock.getTrace()).toMatchSnapshot();
});

it('supports ghe', async () => {
const body = [{ name: 'v1.0.0' }, { name: 'v1.1.0' }];
httpMock
.scope(githubEnterpriseApiHost)
.get(`/api/v3/repos/${depName}/tags?per_page=100`)
.reply(200, body);
const res = await github.getReleases({
registryUrl: 'https://git.enterprise.com',
lookupName: depName,
});
expect(res).toMatchSnapshot();
expect(httpMock.getTrace()).toMatchSnapshot();
});
});
});
13 changes: 11 additions & 2 deletions lib/datasource/github-tags/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import URL from 'url';
import { logger } from '../../logger';
import * as packageCache from '../../util/cache/package';
import { GithubHttp } from '../../util/http/github';
Expand Down Expand Up @@ -119,6 +120,7 @@ export async function getDigest(
* - Return a dependency object containing sourceUrl string and releases array
*/
export async function getReleases({
registryUrl: depHost,
lookupName: repo,
}: GetReleasesConfig): Promise<ReleaseResult | null> {
const cachedResult = await packageCache.get<ReleaseResult>(
Expand All @@ -129,8 +131,15 @@ export async function getReleases({
if (cachedResult) {
return cachedResult;
}

// default to GitHub.com if no GHE host is specified.
const sourceUrlBase = depHost ?? `https://github.com/`;
const apiBaseUrl = depHost
? URL.resolve(depHost, 'api/v3/')
: `https://api.github.com/`;

// tag
const url = `https://api.github.com/repos/${repo}/tags?per_page=100`;
const url = URL.resolve(apiBaseUrl, `repos/${repo}/tags?per_page=100`);
type GitHubTag = {
name: string;
}[];
Expand All @@ -141,7 +150,7 @@ export async function getReleases({
})
).body.map((o) => o.name);
const dependency: ReleaseResult = {
sourceUrl: 'https://github.com/' + repo,
sourceUrl: URL.resolve(sourceUrlBase, repo),
releases: null,
};
dependency.releases = versions.map((version) => ({
Expand Down
27 changes: 27 additions & 0 deletions lib/datasource/go/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,33 @@ Array [
]
`;

exports[`datasource/go getReleases support ghe 1`] = `
Object {
"releases": Array [
Object {
"version": "v1.0.0",
},
Object {
"version": "v2.0.0",
},
],
}
`;

exports[`datasource/go getReleases support ghe 2`] = `
Array [
Object {
"headers": Object {
"accept-encoding": "gzip, deflate",
"host": "git.enterprise.com",
"user-agent": "https://github.com/renovatebot/renovate",
},
"method": "GET",
"url": "https://git.enterprise.com/example/module?go-get=1",
},
]
`;

exports[`datasource/go getReleases works for known servers 1`] = `
Array [
Array [
Expand Down
48 changes: 48 additions & 0 deletions lib/datasource/go/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ Nothing to see here; <a href="https://godoc.org/golang.org/x/text">move along</a
</body>
</html>`;

const resGitHubEnterprise = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Go remote import path metadata</title>
<meta name="go-import" content="git.enterprise.com/example/module git https://git.enterprise.com/example/module.git">
</head>
<body>
<!-- Metadata for Go remote import path -->
</body>
</html>`;

describe('datasource/go', () => {
beforeEach(() => {
httpMock.setup();
Expand Down Expand Up @@ -145,6 +159,40 @@ describe('datasource/go', () => {
expect(res).toBeDefined();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('support ghe', async () => {
httpMock
.scope('https://git.enterprise.com/')
.get('/example/module?go-get=1')
.reply(200, resGitHubEnterprise);
github.getReleases.mockResolvedValueOnce({
releases: [{ version: 'v1.0.0' }, { version: 'v2.0.0' }],
});
const res = await getPkgReleases({
datasource,
depName: 'git.enterprise.com/example/module',
});
expect(res).toMatchSnapshot();
expect(res).not.toBeNull();
expect(res).toBeDefined();
expect(httpMock.getTrace()).toMatchSnapshot();
});
it('returns null for go-import prefix mismatch', async () => {
httpMock
.scope('https://git.enterprise.com/')
.get('/example/module?go-get=1')
.reply(
200,
resGitHubEnterprise.replace(
'git.enterprise.com/example/module',
'git.enterprise.com/badexample/badmodule'
)
);
const res = await getPkgReleases({
datasource,
depName: 'git.enterprise.com/example/module',
});
expect(res).toBeNull();
});
it('skips wrong package', async () => {
httpMock
.scope('https://golang.org/')
Expand Down
30 changes: 29 additions & 1 deletion lib/datasource/go/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import URL from 'url';
import { logger } from '../../logger';
import { Http } from '../../util/http';
import { regEx } from '../../util/regex';
Expand Down Expand Up @@ -35,6 +36,7 @@ async function getDatasource(goModule: string): Promise<DataSource | null> {
lookupName,
};
}

const pkgUrl = `https://${goModule}?go-get=1`;
const res = (await http.get(pkgUrl)).body;
const sourceMatch = regEx(
Expand Down Expand Up @@ -64,7 +66,33 @@ async function getDatasource(goModule: string): Promise<DataSource | null> {
};
}
} else {
logger.trace({ goModule }, 'No go-source header found');
// GitHub Enterprise only returns a go-import meta
const importMatch = regEx(
`<meta\\s+name="go-import"\\s+content="([^\\s]+)\\s+([^\\s]+)\\s+([^\\s]+)">`
).exec(res);
if (importMatch) {
const [, prefix, , goImportURL] = importMatch;
if (!goModule.startsWith(prefix)) {
logger.trace({ goModule }, 'go-import header prefix not match');
return null;
}
logger.debug({ goModule, goImportURL }, 'Go lookup import url');

// get server base url from import url
const parsedUrl = URL.parse(goImportURL);

// split the go module from the URL: host/go/module -> go/module
const split = goModule.split('/');
const lookupName = split[1] + '/' + split[2];

return {
datasource: github.id,
registryUrl: `${parsedUrl.protocol}//${parsedUrl.host}`,
lookupName,
};
}

logger.trace({ goModule }, 'No go-source or go-import header found');
}
return null;
}
Expand Down

0 comments on commit 2932e88

Please sign in to comment.