/
extract.ts
130 lines (119 loc) · 3.43 KB
/
extract.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
import URL from 'url';
import Git, { SimpleGit } from 'simple-git';
import upath from 'upath';
import { getGlobalConfig } from '../../config/global';
import * as datasourceGitRefs from '../../datasource/git-refs';
import { logger } from '../../logger';
import { getHttpUrl, getRemoteUrlWithToken } from '../../util/git/url';
import type { ExtractConfig, PackageFile } from '../types';
import { GitModule } from './types';
async function getUrl(
git: SimpleGit,
gitModulesPath: string,
submoduleName: string
): Promise<string> {
const path = (
await Git().raw([
'config',
'--file',
gitModulesPath,
'--get',
`submodule.${submoduleName}.url`,
])
)?.trim();
if (!path?.startsWith('../')) {
return path;
}
const remoteUrl = (
await git.raw(['config', '--get', 'remote.origin.url'])
).trim();
return URL.resolve(`${remoteUrl}/`, path);
}
const headRefRe = /ref: refs\/heads\/(?<branch>\w+)\s/;
async function getDefaultBranch(subModuleUrl: string): Promise<string> {
const val = await Git().listRemote(['--symref', subModuleUrl, 'HEAD']);
return headRefRe.exec(val)?.groups?.branch ?? 'master';
}
async function getBranch(
gitModulesPath: string,
submoduleName: string,
subModuleUrl: string
): Promise<string> {
return (
(await Git().raw([
'config',
'--file',
gitModulesPath,
'--get',
`submodule.${submoduleName}.branch`,
])) || (await getDefaultBranch(subModuleUrl))
).trim();
}
async function getModules(
git: SimpleGit,
gitModulesPath: string
): Promise<GitModule[]> {
const res: GitModule[] = [];
try {
const modules = (
(await git.raw([
'config',
'--file',
gitModulesPath,
'--get-regexp',
'\\.path',
])) ?? /* istanbul ignore next: should never happen */ ''
)
.trim()
.split(/\n/)
.filter((s) => !!s);
for (const line of modules) {
const [, name, path] = line.split(/submodule\.(.+?)\.path\s(.+)/);
res.push({ name, path });
}
} catch (err) /* istanbul ignore next */ {
logger.warn({ err }, 'Error getting git submodules during extract');
}
return res;
}
export default async function extractPackageFile(
_content: string,
fileName: string,
config: ExtractConfig
): Promise<PackageFile | null> {
const { localDir } = getGlobalConfig();
const git = Git(localDir);
const gitModulesPath = upath.join(localDir, fileName);
const depNames = await getModules(git, gitModulesPath);
if (!depNames.length) {
return null;
}
const deps = [];
for (const { name, path } of depNames) {
try {
const [currentDigest] = (await git.subModule(['status', path]))
.trim()
.replace(/^[-+]/, '')
.split(/\s/);
const subModuleUrl = await getUrl(git, gitModulesPath, name);
// hostRules only understands HTTP URLs
// Find HTTP URL, then apply token
let httpSubModuleUrl = getHttpUrl(subModuleUrl);
httpSubModuleUrl = getRemoteUrlWithToken(httpSubModuleUrl);
const currentValue = await getBranch(
gitModulesPath,
name,
httpSubModuleUrl
);
deps.push({
depName: path,
lookupName: getHttpUrl(subModuleUrl),
currentValue,
currentDigest,
});
} catch (err) /* istanbul ignore next */ {
logger.warn({ err }, 'Error mapping git submodules during extraction');
}
}
return { deps, datasource: datasourceGitRefs.id };
}