-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
index.ts
152 lines (146 loc) · 4.67 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import { logger } from '../../logger';
import { Http } from '../../util/http';
import { regEx } from '../../util/regex';
import { DigestConfig, GetReleasesConfig, ReleaseResult } from '../common';
import * as github from '../github-tags';
import * as gitlab from '../gitlab-tags';
export const id = 'go';
const http = new Http(id);
interface DataSource {
datasource: string;
registryUrl?: string;
lookupName: string;
}
async function getDatasource(goModule: string): Promise<DataSource | null> {
if (goModule.startsWith('gopkg.in/')) {
const [pkg] = goModule.replace('gopkg.in/', '').split('.');
if (pkg.includes('/')) {
return { datasource: github.id, lookupName: pkg };
}
return {
datasource: github.id,
lookupName: `go-${pkg}/${pkg}`,
};
}
if (goModule.startsWith('github.com/')) {
const split = goModule.split('/');
const lookupName = split[1] + '/' + split[2];
return {
datasource: github.id,
lookupName,
};
}
const pkgUrl = `https://${goModule}?go-get=1`;
const res = (await http.get(pkgUrl)).body;
const sourceMatch = regEx(
`<meta\\s+name="go-source"\\s+content="([^\\s]+)\\s+([^\\s]+)`
).exec(res);
if (sourceMatch) {
const [, prefix, goSourceUrl] = sourceMatch;
if (!goModule.startsWith(prefix)) {
logger.trace({ goModule }, 'go-source header prefix not match');
return null;
}
logger.debug({ goModule, goSourceUrl }, 'Go lookup source url');
if (goSourceUrl?.startsWith('https://github.com/')) {
return {
datasource: github.id,
lookupName: goSourceUrl
.replace('https://github.com/', '')
.replace(/\/$/, ''),
};
}
if (goSourceUrl?.match('^https://[^/]*gitlab.[^/]*/.+')) {
const gitlabRegExp = /^(https:\/\/[^/]*gitlab.[^/]*)\/(.*)$/;
const gitlabRes = gitlabRegExp.exec(goSourceUrl);
return {
datasource: gitlab.id,
registryUrl: gitlabRes[1],
lookupName: gitlabRes[2].replace(/\/$/, ''),
};
}
} else {
logger.trace({ goModule }, 'No go-source header found');
}
return null;
}
/**
* go.getReleases
*
* This datasource resolves a go module URL into its source repository
* and then fetch it if it is on GitHub.
*
* This function will:
* - Determine the source URL for the module
* - Call the respective getReleases in github/gitlab to retrieve the tags
* - Filter module tags according to the module path
*/
export async function getReleases({
lookupName,
}: GetReleasesConfig): Promise<ReleaseResult | null> {
logger.trace(`go.getReleases(${lookupName})`);
const source = await getDatasource(lookupName);
if (source?.datasource !== github.id && source?.datasource !== gitlab.id) {
return null;
}
const res =
source.datasource === github.id
? await github.getReleases(source)
: await gitlab.getReleases(source);
// istanbul ignore if
if (!res) {
return res;
}
/**
* github.com/org/mod/submodule should be tagged as submodule/va.b.c
* and that tag should be used instead of just va.b.c, although for compatibility
* the old behaviour stays the same.
*/
const nameParts = lookupName.split('/');
logger.trace({ nameParts, releases: res.releases }, 'go.getReleases');
if (nameParts.length > 3) {
const prefix = nameParts.slice(3, nameParts.length).join('/');
logger.trace(`go.getReleases.prefix:${prefix}`);
const submodReleases = res.releases
.filter((release) => release.version?.startsWith(prefix))
.map((release) => {
const r2 = release;
r2.version = r2.version.replace(`${prefix}/`, '');
return r2;
});
logger.trace({ submodReleases }, 'go.getReleases');
if (submodReleases.length > 0) {
res.releases = submodReleases;
return res;
}
}
if (res?.releases) {
res.releases = res.releases.filter((release) =>
release.version?.startsWith('v')
);
}
return res;
}
/**
* go.getDigest
*
* This datasource resolves a go module URL into its source repository
* and then fetches the digest it if it is on GitHub.
*
* This function will:
* - Determine the source URL for the module
* - Call the respective getDigest in github to retrieve the commit hash
*/
export async function getDigest(
{ lookupName }: Partial<DigestConfig>,
value?: string
): Promise<string | null> {
const source = await getDatasource(lookupName);
if (source && source.datasource === github.id) {
// ignore v0.0.0- pseudo versions that are used Go Modules - look up default branch instead
const tag = value && !value.startsWith('v0.0.0-2') ? value : undefined;
const digest = await github.getDigest(source, tag);
return digest;
}
return null;
}