@pnpm/resolving.git-resolver 1100.1.11 → 1100.1.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -0
- package/lib/createGitHostedPkgId.d.ts +6 -0
- package/lib/createGitHostedPkgId.js +21 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.js +3 -1
- package/lib/parseBareSpecifier.d.ts +16 -0
- package/lib/parseBareSpecifier.js +177 -0
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
# @pnpm/git-resolver
|
|
2
2
|
|
|
3
|
+
## 1100.1.13
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Updated dependencies:
|
|
8
|
+
- @pnpm/network.fetch@1100.1.9
|
|
9
|
+
- @pnpm/resolving.resolver-base@1100.5.5
|
|
10
|
+
|
|
11
|
+
## 1100.1.12
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Added a new setting, `update.githubActionsServer`, for specifying the base URL of the GitHub server that hosts the repositories of the GitHub Actions referenced by the workflow files (for example, a GitHub Enterprise Server). When the setting is not defined, the URL is read from the `GITHUB_SERVER_URL` environment variable, falling back to `https://github.com`. The URL must use the `https://` or `http://` protocol [#13220](https://github.com/pnpm/pnpm/issues/13220).
|
|
16
|
+
|
|
17
|
+
`pnpm outdated` and `pnpm update` no longer fail when the refs of a GitHub Action's repository cannot be read (for example, when the action's repository is private or hosted on a different GitHub server). Such actions are now skipped with a warning.
|
|
18
|
+
|
|
19
|
+
Setting `update.githubActions` to `false` now makes `pnpm outdated` and the interactive `pnpm update` skip GitHub Actions dependencies.
|
|
20
|
+
|
|
21
|
+
- Republished every package: the tarballs published by the v11.13.1 through v11.16.0 releases were missing most of their compiled files due to a packing bug [#13164](https://github.com/pnpm/pnpm/issues/13164).
|
|
22
|
+
|
|
23
|
+
- Updated dependencies:
|
|
24
|
+
- @pnpm/error@1100.1.0
|
|
25
|
+
- @pnpm/network.fetch@1100.1.8
|
|
26
|
+
- @pnpm/resolving.resolver-base@1100.5.4
|
|
27
|
+
|
|
3
28
|
## 1100.1.11
|
|
4
29
|
|
|
5
30
|
### Patch Changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export function createGitHostedPkgId({ repo, commit, path }) {
|
|
2
|
+
const normalizedRepo = normalizeGitRepoForPkgResolutionId(repo);
|
|
3
|
+
let id = `${normalizedRepo.includes('://') ? '' : 'https://'}${normalizedRepo}#${commit}`;
|
|
4
|
+
if (!id.startsWith('git+'))
|
|
5
|
+
id = `git+${id}`;
|
|
6
|
+
if (path) {
|
|
7
|
+
id += `&path:${path}`;
|
|
8
|
+
}
|
|
9
|
+
return id;
|
|
10
|
+
}
|
|
11
|
+
function normalizeGitRepoForPkgResolutionId(repo) {
|
|
12
|
+
// Only scp-style shorthand (`user@host:path`) needs rewriting. A repo that
|
|
13
|
+
// already carries a URL scheme (e.g. `ssh://user@host:2222/path`) is left
|
|
14
|
+
// alone — its `@host:port` would otherwise match the scp pattern and get
|
|
15
|
+
// mangled into `ssh://ssh://…`.
|
|
16
|
+
if (repo.includes('://'))
|
|
17
|
+
return repo;
|
|
18
|
+
const scp = /^([^@\s]+@[^:\s]+):(.+)$/.exec(repo);
|
|
19
|
+
return scp == null ? repo : `ssh://${scp[1]}/${scp[2]}`;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=createGitHostedPkgId.js.map
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { DispatcherOptions } from '@pnpm/network.fetch';
|
|
2
|
+
import type { GitResolution, LatestInfo, LatestQuery, ResolveOptions, ResolveResult, TarballResolution } from '@pnpm/resolving.resolver-base';
|
|
3
|
+
import { createGitHostedPkgId } from './createGitHostedPkgId.js';
|
|
4
|
+
import { type HostedPackageSpec } from './parseBareSpecifier.js';
|
|
5
|
+
export { createGitHostedPkgId };
|
|
6
|
+
export type { HostedPackageSpec };
|
|
7
|
+
export interface GitResolveResult extends ResolveResult {
|
|
8
|
+
normalizedBareSpecifier?: string;
|
|
9
|
+
resolution: GitResolution | TarballResolution;
|
|
10
|
+
resolvedVia: 'git-repository';
|
|
11
|
+
}
|
|
12
|
+
export type GitResolver = (wantedDependency: {
|
|
13
|
+
bareSpecifier: string;
|
|
14
|
+
}, opts?: Pick<ResolveOptions, 'currentPkg' | 'update'>) => Promise<GitResolveResult | null>;
|
|
15
|
+
export declare function createGitResolver(opts: DispatcherOptions): GitResolver;
|
|
16
|
+
export declare function resolveLatestFromGit(query: LatestQuery): Promise<LatestInfo | undefined>;
|
|
17
|
+
export declare function getRepoRefs(repo: string, ref: string | null): Promise<Record<string, string>>;
|
package/lib/index.js
CHANGED
|
@@ -90,7 +90,9 @@ function resolveVTags(vTags, range) {
|
|
|
90
90
|
return semver.maxSatisfying(vTags, range, true);
|
|
91
91
|
}
|
|
92
92
|
export async function getRepoRefs(repo, ref) {
|
|
93
|
-
|
|
93
|
+
// `--` keeps a repo URL that starts with a dash (e.g. from a malicious
|
|
94
|
+
// config value) from being parsed as a git flag, matching the Rust runner.
|
|
95
|
+
const gitArgs = ['--', repo];
|
|
94
96
|
if (ref) {
|
|
95
97
|
gitArgs.push(ref);
|
|
96
98
|
// Also request the peeled ref for annotated tags (e.g., refs/tags/v1.0.0^{})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type DispatcherOptions } from '@pnpm/network.fetch';
|
|
2
|
+
export interface HostedPackageSpec {
|
|
3
|
+
fetchSpec: string;
|
|
4
|
+
hosted?: {
|
|
5
|
+
type: string;
|
|
6
|
+
user: string;
|
|
7
|
+
project: string;
|
|
8
|
+
committish: string;
|
|
9
|
+
tarball: () => string | undefined;
|
|
10
|
+
};
|
|
11
|
+
normalizedBareSpecifier: string;
|
|
12
|
+
gitCommittish: string | null;
|
|
13
|
+
gitRange?: string;
|
|
14
|
+
path?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function parseBareSpecifier(bareSpecifier: string, opts: DispatcherOptions): null | (() => Promise<HostedPackageSpec>);
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
// cspell:ignore sshurl
|
|
2
|
+
import urlLib, { URL } from 'node:url';
|
|
3
|
+
import { fetchWithDispatcher } from '@pnpm/network.fetch';
|
|
4
|
+
import { gracefulGit as git } from 'graceful-git';
|
|
5
|
+
import HostedGit from 'hosted-git-info';
|
|
6
|
+
const gitProtocols = new Set([
|
|
7
|
+
'git',
|
|
8
|
+
'git+http',
|
|
9
|
+
'git+https',
|
|
10
|
+
'git+rsync',
|
|
11
|
+
'git+ftp',
|
|
12
|
+
'git+file',
|
|
13
|
+
'git+ssh',
|
|
14
|
+
'ssh',
|
|
15
|
+
]);
|
|
16
|
+
export function parseBareSpecifier(bareSpecifier, opts) {
|
|
17
|
+
const hosted = HostedGit.fromUrl(bareSpecifier);
|
|
18
|
+
if (hosted != null) {
|
|
19
|
+
return () => fromHostedGit(hosted, opts);
|
|
20
|
+
}
|
|
21
|
+
const colonsPos = bareSpecifier.indexOf(':');
|
|
22
|
+
if (colonsPos === -1)
|
|
23
|
+
return null;
|
|
24
|
+
const protocol = bareSpecifier.slice(0, colonsPos);
|
|
25
|
+
// Also detect http/https URLs ending in .git as git repositories
|
|
26
|
+
const isGitUrl = gitProtocols.has(protocol.toLocaleLowerCase()) ||
|
|
27
|
+
((protocol === 'http' || protocol === 'https') && /\.git(?:#|$)/.test(bareSpecifier));
|
|
28
|
+
if (protocol && isGitUrl) {
|
|
29
|
+
const correctBareSpecifier = correctUrl(bareSpecifier);
|
|
30
|
+
const url = new URL(correctBareSpecifier);
|
|
31
|
+
if (!url?.protocol)
|
|
32
|
+
return null;
|
|
33
|
+
const hash = (url.hash?.length > 1) ? decodeURIComponent(url.hash.slice(1)) : null;
|
|
34
|
+
return async () => ({
|
|
35
|
+
fetchSpec: urlToFetchSpec(url),
|
|
36
|
+
normalizedBareSpecifier: bareSpecifier,
|
|
37
|
+
...parseGitParams(hash),
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
function urlToFetchSpec(url) {
|
|
43
|
+
url.hash = '';
|
|
44
|
+
const fetchSpec = urlLib.format(url);
|
|
45
|
+
if (fetchSpec.startsWith('git+')) {
|
|
46
|
+
return fetchSpec.slice(4);
|
|
47
|
+
}
|
|
48
|
+
return fetchSpec;
|
|
49
|
+
}
|
|
50
|
+
async function fromHostedGit(hosted, dispatcherOptions) {
|
|
51
|
+
let fetchSpec = null;
|
|
52
|
+
// try git/https url before fallback to ssh url
|
|
53
|
+
const gitHttpsUrl = hosted.https({ noCommittish: true, noGitPlus: true });
|
|
54
|
+
if (gitHttpsUrl && await isRepoPublic(gitHttpsUrl, dispatcherOptions) && await accessRepository(gitHttpsUrl)) {
|
|
55
|
+
fetchSpec = gitHttpsUrl;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const gitSshUrl = hosted.ssh({ noCommittish: true });
|
|
59
|
+
if (gitSshUrl && await accessRepository(gitSshUrl)) {
|
|
60
|
+
fetchSpec = gitSshUrl;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (!fetchSpec) {
|
|
64
|
+
const httpsUrl = hosted.https({ noGitPlus: true, noCommittish: true });
|
|
65
|
+
if (httpsUrl) {
|
|
66
|
+
if ((hosted.auth || !await isRepoPublic(httpsUrl, dispatcherOptions)) && await accessRepository(httpsUrl)) {
|
|
67
|
+
return {
|
|
68
|
+
fetchSpec: httpsUrl,
|
|
69
|
+
hosted: {
|
|
70
|
+
...hosted,
|
|
71
|
+
_fill: hosted._fill,
|
|
72
|
+
tarball: undefined,
|
|
73
|
+
},
|
|
74
|
+
normalizedBareSpecifier: `git+${httpsUrl}`,
|
|
75
|
+
...parseGitParams(hosted.committish),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
try {
|
|
80
|
+
// when git ls-remote private repo, it asks for login credentials.
|
|
81
|
+
// use HTTP HEAD request to test whether this is a private repo, to avoid login prompt.
|
|
82
|
+
// this is very similar to yarn classic's behavior.
|
|
83
|
+
// npm instead tries git ls-remote directly which prompts user for login credentials.
|
|
84
|
+
// HTTP HEAD on https://domain/user/repo, strip out ".git"
|
|
85
|
+
const response = await fetchWithDispatcher(httpsUrl.replace(/\.git$/, ''), { method: 'HEAD', redirect: 'manual', retry: { retries: 0 }, dispatcherOptions });
|
|
86
|
+
if (response.ok) {
|
|
87
|
+
fetchSpec = httpsUrl;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// ignore
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!fetchSpec) {
|
|
97
|
+
// use ssh url for likely private repo
|
|
98
|
+
fetchSpec = hosted.sshurl({ noCommittish: true });
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
fetchSpec: fetchSpec,
|
|
102
|
+
hosted: {
|
|
103
|
+
...hosted,
|
|
104
|
+
tarballtemplate: hosted.type === 'gitlab' ? gitlabTarballTemplate : hosted.tarballtemplate,
|
|
105
|
+
_fill: hosted._fill,
|
|
106
|
+
tarball: hosted.tarball,
|
|
107
|
+
},
|
|
108
|
+
normalizedBareSpecifier: hosted.shortcut(),
|
|
109
|
+
...parseGitParams(hosted.committish),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// hosted-git-info's default GitLab tarball URL contains an encoded slash
|
|
113
|
+
// (`%2F`) which survives into the virtual store directory name and makes
|
|
114
|
+
// Node refuse to import the package (ERR_INVALID_MODULE_SPECIFIER).
|
|
115
|
+
function gitlabTarballTemplate({ domain, user, project, committish }) {
|
|
116
|
+
const ref = committish ? encodeURIComponent(committish) : 'HEAD';
|
|
117
|
+
return `https://${domain}/${user}/${project}/-/archive/${ref}/${project}-${ref}.tar.gz`;
|
|
118
|
+
}
|
|
119
|
+
async function isRepoPublic(httpsUrl, dispatcherOptions) {
|
|
120
|
+
try {
|
|
121
|
+
const response = await fetchWithDispatcher(httpsUrl.replace(/\.git$/, ''), { method: 'HEAD', redirect: 'manual', retry: { retries: 0 }, dispatcherOptions });
|
|
122
|
+
return response.ok;
|
|
123
|
+
}
|
|
124
|
+
catch {
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
async function accessRepository(repository) {
|
|
129
|
+
try {
|
|
130
|
+
await git(['ls-remote', '--exit-code', repository, 'HEAD'], { retries: 0 });
|
|
131
|
+
return true;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function parseGitParams(committish) {
|
|
138
|
+
const result = { gitCommittish: null };
|
|
139
|
+
if (!committish) {
|
|
140
|
+
return result;
|
|
141
|
+
}
|
|
142
|
+
const params = committish.split('&');
|
|
143
|
+
for (const param of params) {
|
|
144
|
+
if (param.length >= 7 && param.slice(0, 7) === 'semver:') {
|
|
145
|
+
result.gitRange = param.slice(7);
|
|
146
|
+
}
|
|
147
|
+
else if (param.slice(0, 5) === 'path:') {
|
|
148
|
+
result.path = param.slice(5);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
result.gitCommittish = param;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return result;
|
|
155
|
+
}
|
|
156
|
+
// handle SCP-like URLs
|
|
157
|
+
// see https://github.com/yarnpkg/yarn/blob/5682d55/src/util/git.js#L103
|
|
158
|
+
function correctUrl(gitUrl) {
|
|
159
|
+
let _gitUrl = gitUrl.replace(/^git\+/, '');
|
|
160
|
+
if (_gitUrl.startsWith('ssh://')) {
|
|
161
|
+
const hashIndex = _gitUrl.indexOf('#');
|
|
162
|
+
let hash = '';
|
|
163
|
+
if (hashIndex !== -1) {
|
|
164
|
+
hash = _gitUrl.slice(hashIndex);
|
|
165
|
+
_gitUrl = _gitUrl.slice(0, hashIndex);
|
|
166
|
+
}
|
|
167
|
+
const [auth, ...pathname] = _gitUrl.slice(6).split('/');
|
|
168
|
+
const [, host] = auth.split('@');
|
|
169
|
+
if (host.includes(':') && !/:\d+$/.test(host)) {
|
|
170
|
+
const authArr = auth.split(':');
|
|
171
|
+
const protocol = gitUrl.split('://')[0];
|
|
172
|
+
gitUrl = `${protocol}://${authArr.slice(0, -1).join(':') + '/' + authArr[authArr.length - 1]}${pathname.length ? '/' + pathname.join('/') : ''}${hash}`;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return gitUrl;
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=parseBareSpecifier.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pnpm/resolving.git-resolver",
|
|
3
|
-
"version": "1100.1.
|
|
3
|
+
"version": "1100.1.13",
|
|
4
4
|
"description": "Resolver for git-hosted packages",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pnpm",
|
|
@@ -29,16 +29,16 @@
|
|
|
29
29
|
"!*.map"
|
|
30
30
|
],
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@pnpm/error": "1100.0
|
|
33
|
-
"@pnpm/network.fetch": "1100.1.
|
|
34
|
-
"@pnpm/resolving.resolver-base": "1100.5.
|
|
32
|
+
"@pnpm/error": "1100.1.0",
|
|
33
|
+
"@pnpm/network.fetch": "1100.1.9",
|
|
34
|
+
"@pnpm/resolving.resolver-base": "1100.5.5",
|
|
35
35
|
"graceful-git": "^5.0.0",
|
|
36
36
|
"hosted-git-info": "npm:@pnpm/hosted-git-info@1.0.0",
|
|
37
|
-
"semver": "^7.8.
|
|
37
|
+
"semver": "^7.8.5"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@jest/globals": "30.4.1",
|
|
41
|
-
"@pnpm/resolving.git-resolver": "1100.1.
|
|
41
|
+
"@pnpm/resolving.git-resolver": "1100.1.13",
|
|
42
42
|
"@types/hosted-git-info": "^3.0.5",
|
|
43
43
|
"@types/is-windows": "^1.0.2",
|
|
44
44
|
"@types/semver": "7.7.1",
|