@npmcli/git
Advanced tools
Comparing version 2.0.6 to 2.0.7
@@ -18,5 +18,7 @@ // The goal here is to minimize both git workload and | ||
'bitbucket.com', | ||
'bitbucket.org', | ||
'bitbucket.org' | ||
]) | ||
const { parse } = require('url') | ||
// we have to use url.parse until we add the same shim that hosted-git-info has | ||
// to handle scp:// urls | ||
const { parse } = require('url') // eslint-disable-line node/no-deprecated-api | ||
const { basename, resolve } = require('path') | ||
@@ -26,5 +28,5 @@ | ||
const spawn = require('./spawn.js') | ||
const { isWindows, escapePath } = require('./utils.js') | ||
const pickManifest = require('npm-pick-manifest') | ||
const { promisify } = require('util') | ||
const fs = require('fs') | ||
@@ -43,17 +45,24 @@ const mkdirp = require('mkdirp') | ||
const maybeShallow = (repo, opts) => | ||
opts.gitShallow === false || opts.gitShallow ? opts.gitShallow | ||
: shallowHosts.has(parse(repo).host) | ||
const maybeShallow = (repo, opts) => { | ||
if (opts.gitShallow === false || opts.gitShallow) { | ||
return opts.gitShallow | ||
} | ||
return shallowHosts.has(parse(repo).host) | ||
} | ||
const isWindows = opts => (opts.fakePlatform || process.platform) === 'win32' | ||
const defaultTarget = (repo, /* istanbul ignore next */ cwd = process.cwd()) => | ||
resolve(cwd, basename(repo.replace(/[\/\\]?\.git$/, ''))) | ||
resolve(cwd, basename(repo.replace(/[/\\]?\.git$/, ''))) | ||
const clone = (repo, revs, ref, revDoc, target, opts) => | ||
!revDoc ? unresolved(repo, ref, target, opts) | ||
: revDoc.sha === revs.refs.HEAD.sha ? plain(repo, revDoc, target, opts) | ||
: revDoc.type === 'tag' || revDoc.type === 'branch' | ||
? branch(repo, revDoc, target, opts) | ||
: other(repo, revDoc, target, opts) | ||
const clone = (repo, revs, ref, revDoc, target, opts) => { | ||
if (!revDoc) { | ||
return unresolved(repo, ref, target, opts) | ||
} | ||
if (revDoc.sha === revs.refs.HEAD.sha) { | ||
return plain(repo, revDoc, target, opts) | ||
} | ||
if (revDoc.type === 'tag' || revDoc.type === 'branch') { | ||
return branch(repo, revDoc, target, opts) | ||
} | ||
return other(repo, revDoc, target, opts) | ||
} | ||
@@ -63,8 +72,19 @@ const resolveRef = (revs, ref, opts) => { | ||
ref = spec.gitCommittish || ref | ||
return !revs ? /* istanbul ignore next - will fail anyway, can't pull */ null | ||
: spec.gitRange ? pickManifest(revs, spec.gitRange, opts) | ||
: !ref ? revs.refs.HEAD | ||
: revs.refs[ref] ? revs.refs[ref] | ||
: revs.shas[ref] ? revs.refs[revs.shas[ref][0]] | ||
: null | ||
/* istanbul ignore next - will fail anyway, can't pull */ | ||
if (!revs) { | ||
return null | ||
} | ||
if (spec.gitRange) { | ||
return pickManifest(revs, spec.gitRange, opts) | ||
} | ||
if (!ref) { | ||
return revs.refs.HEAD | ||
} | ||
if (revs.refs[ref]) { | ||
return revs.refs[ref] | ||
} | ||
if (revs.shas[ref]) { | ||
return revs.refs[revs.shas[ref][0]] | ||
} | ||
return null | ||
} | ||
@@ -76,3 +96,3 @@ | ||
const fetchOrigin = [ 'fetch', 'origin', revDoc.rawRef ] | ||
const fetchOrigin = ['fetch', 'origin', revDoc.rawRef] | ||
.concat(shallow ? ['--depth=1'] : []) | ||
@@ -100,9 +120,7 @@ | ||
repo, | ||
target, | ||
'--recurse-submodules', | ||
escapePath(target, opts), | ||
'--recurse-submodules' | ||
] | ||
if (maybeShallow(repo, opts)) | ||
args.push('--depth=1') | ||
if (isWindows(opts)) | ||
args.push('--config', 'core.longpaths=true') | ||
if (maybeShallow(repo, opts)) { args.push('--depth=1') } | ||
if (isWindows(opts)) { args.push('--config', 'core.longpaths=true') } | ||
return spawn(args, opts).then(() => revDoc.sha) | ||
@@ -116,15 +134,16 @@ } | ||
repo, | ||
target, | ||
escapePath(target, opts), | ||
'--recurse-submodules' | ||
] | ||
if (maybeShallow(repo, opts)) | ||
args.push('--depth=1') | ||
if (isWindows(opts)) | ||
args.push('--config', 'core.longpaths=true') | ||
if (maybeShallow(repo, opts)) { args.push('--depth=1') } | ||
if (isWindows(opts)) { args.push('--config', 'core.longpaths=true') } | ||
return spawn(args, opts).then(() => revDoc.sha) | ||
} | ||
const updateSubmodules = (target, opts) => new Promise(res => | ||
fs.stat(target + '/.gitmodules', er => res(er ? null | ||
: spawn([ | ||
const updateSubmodules = (target, opts) => new Promise(resolve => | ||
fs.stat(target + '/.gitmodules', er => { | ||
if (er) { | ||
return resolve(null) | ||
} | ||
return resolve(spawn([ | ||
'submodule', | ||
@@ -135,3 +154,4 @@ 'update', | ||
'--recursive' | ||
], { ...opts, cwd: target })))) | ||
], { ...opts, cwd: target })) | ||
})) | ||
@@ -142,3 +162,3 @@ const unresolved = (repo, ref, target, opts) => { | ||
const lp = isWindows(opts) ? ['--config', 'core.longpaths=true'] : [] | ||
const cloneArgs = ['clone', '--mirror', '-q', repo, target + '/.git'] | ||
const cloneArgs = ['clone', '--mirror', '-q', repo, escapePath(target + '/.git', opts)] | ||
const git = (args) => spawn(args, { ...opts, cwd: target }) | ||
@@ -151,3 +171,3 @@ return mkdirp(target) | ||
.then(() => git(['rev-parse', '--revs-only', 'HEAD'])) | ||
.then(({stdout}) => stdout.trim()) | ||
.then(({ stdout }) => stdout.trim()) | ||
} |
const is = require('./is.js') | ||
const { dirname } = require('path') | ||
const check = (cwd, prev) => is({ cwd }).then(isGit => | ||
isGit ? cwd | ||
: cwd === prev ? null | ||
: check(dirname(cwd), cwd)) | ||
module.exports = ({ cwd = process.cwd() } = {}) => check(cwd) | ||
module.exports = async ({ cwd = process.cwd() } = {}) => { | ||
if (await is({ cwd })) { | ||
return cwd | ||
} | ||
while (cwd !== dirname(cwd)) { | ||
cwd = dirname(cwd) | ||
if (await is({ cwd })) { | ||
return cwd | ||
} | ||
} | ||
return null | ||
} |
@@ -7,3 +7,3 @@ module.exports = { | ||
find: require('./find.js'), | ||
isClean: require('./is-clean.js'), | ||
isClean: require('./is-clean.js') | ||
} |
const spawn = require('./spawn.js') | ||
module.exports = (opts = {}) => | ||
spawn([ 'status', '--porcelain=v1', '-uno' ], opts) | ||
.then(res => res.stdout.trim().split(/\r?\n+/) | ||
.map(l => l.trim()).filter(l => l).length ? false : true) | ||
spawn(['status', '--porcelain=v1', '-uno'], opts) | ||
.then(res => !res.stdout.trim().split(/\r?\n+/) | ||
.map(l => l.trim()).filter(l => l).length) |
@@ -10,3 +10,3 @@ // turn an array of lines from `git ls-remote` into a thing | ||
refs: {}, | ||
shas: {}, | ||
shas: {} | ||
})) | ||
@@ -19,7 +19,8 @@ | ||
Object.keys(revs.refs).forEach(ref => { | ||
doc = revs.refs[ref] | ||
if (revs.shas[doc.sha]) | ||
const doc = revs.refs[ref] | ||
if (!revs.shas[doc.sha]) { | ||
revs.shas[doc.sha] = [ref] | ||
} else { | ||
revs.shas[doc.sha].push(ref) | ||
else | ||
revs.shas[doc.sha] = [ref] | ||
} | ||
}) | ||
@@ -29,3 +30,2 @@ return revs | ||
// Replace any tags with their ^{} counterparts, if those exist | ||
@@ -54,8 +54,7 @@ const peelTags = revs => { | ||
const ver = revs.versions[v] | ||
if (revs.refs.latest && ver.sha === revs.refs.latest.sha) | ||
if (revs.refs.latest && ver.sha === revs.refs.latest.sha) { | ||
revs['dist-tags'].latest = v | ||
else if (ver.sha === HEAD.sha) { | ||
} else if (ver.sha === HEAD.sha) { | ||
revs['dist-tags'].HEAD = v | ||
if (!revs.refs.latest) | ||
revs['dist-tags'].latest = v | ||
if (!revs.refs.latest) { revs['dist-tags'].latest = v } | ||
} | ||
@@ -66,9 +65,19 @@ }) | ||
const refType = ref => | ||
ref.startsWith('refs/tags/') ? 'tag' | ||
: ref.startsWith('refs/heads/') ? 'branch' | ||
: ref.startsWith('refs/pull/') ? 'pull' | ||
: ref === 'HEAD' ? 'head' | ||
// Could be anything, ignore for now | ||
: /* istanbul ignore next */ 'other' | ||
const refType = ref => { | ||
if (ref.startsWith('refs/tags/')) { | ||
return 'tag' | ||
} | ||
if (ref.startsWith('refs/heads/')) { | ||
return 'branch' | ||
} | ||
if (ref.startsWith('refs/pull/')) { | ||
return 'pull' | ||
} | ||
if (ref === 'HEAD') { | ||
return 'head' | ||
} | ||
// Could be anything, ignore for now | ||
/* istanbul ignore next */ | ||
return 'other' | ||
} | ||
@@ -78,4 +87,3 @@ // return the doc, or null if we should ignore it. | ||
const split = line.trim().split(/\s+/, 2) | ||
if (split.length < 2) | ||
return null | ||
if (split.length < 2) { return null } | ||
@@ -123,4 +131,3 @@ const sha = split[0].trim() | ||
if (!doc) | ||
return revs | ||
if (!doc) { return revs } | ||
@@ -135,4 +142,5 @@ revs.refs[doc.ref] = doc | ||
doc.ref.match(/v?(\d+\.\d+\.\d+(?:[-+].+)?)$/) | ||
if (match && semver.valid(match[1], true)) | ||
if (match && semver.valid(match[1], true)) { | ||
revs.versions[semver.clean(match[1], true)] = doc | ||
} | ||
} | ||
@@ -139,0 +147,0 @@ |
@@ -1,6 +0,11 @@ | ||
const gitEnv = require('./env.js') | ||
// Values we want to set if they're not already defined by the end user | ||
// This defaults to accepting new ssh host key fingerprints | ||
const gitEnv = { | ||
GIT_ASKPASS: 'echo', | ||
GIT_SSH_COMMAND: 'ssh -oStrictHostKeyChecking=accept-new' | ||
} | ||
module.exports = (opts = {}) => ({ | ||
stdioString: true, | ||
...opts, | ||
env: opts.env || gitEnv(), | ||
env: opts.env || { ...gitEnv, ...process.env } | ||
}) |
@@ -7,3 +7,3 @@ const pinflight = require('promise-inflight') | ||
max: 100, | ||
maxAge: 5 * 60 * 1000, | ||
maxAge: 5 * 60 * 1000 | ||
}) | ||
@@ -13,7 +13,8 @@ | ||
module.exports = (repo, opts = {}) => { | ||
module.exports = async (repo, opts = {}) => { | ||
if (!opts.noGitRevCache) { | ||
const cached = revsCache.get(repo) | ||
if (cached) | ||
return Promise.resolve(cached) | ||
if (cached) { | ||
return cached | ||
} | ||
} | ||
@@ -23,5 +24,8 @@ | ||
spawn(['ls-remote', repo], opts) | ||
.then(({stdout}) => linesToRevs(stdout.trim().split('\n'))) | ||
.then(revs => (revsCache.set(repo, revs), revs)) | ||
.then(({ stdout }) => linesToRevs(stdout.trim().split('\n'))) | ||
.then(revs => { | ||
revsCache.set(repo, revs) | ||
return revs | ||
}) | ||
) | ||
} |
@@ -11,24 +11,28 @@ const spawn = require('@npmcli/promise-spawn') | ||
if (gitPath instanceof Error) | ||
return Promise.reject(gitPath) | ||
if (gitPath instanceof Error) { return Promise.reject(gitPath) } | ||
const log = opts.log || procLog | ||
let retry = opts.retry | ||
if (retry === null || retry === undefined) { | ||
retry = { | ||
retries: opts.fetchRetries || 2, | ||
factor: opts.fetchRetryFactor || 10, | ||
maxTimeout: opts.fetchRetryMaxtimeout || 60000, | ||
minTimeout: opts.fetchRetryMintimeout || 1000 | ||
} | ||
} | ||
return promiseRetry((retry, number) => { | ||
if (number !== 1) | ||
if (number !== 1) { | ||
log.silly('pacote', `Retrying git command: ${ | ||
gitArgs.join(' ')} attempt # ${number}`) | ||
} | ||
return spawn(gitPath, gitArgs, makeOpts(opts)) | ||
.catch(er => { | ||
if (shouldRetry(er.stderr, number)) | ||
retry(er) | ||
else | ||
if (!shouldRetry(er.stderr, number)) { | ||
throw er | ||
} | ||
retry(er) | ||
}) | ||
}, opts.retry !== null && opts.retry !== undefined ? opts.retry : { | ||
retries: opts.fetchRetries || 2, | ||
factor: opts.fetchRetryFactor || 10, | ||
maxTimeout: opts.fetchRetryMaxtimeout || 60000, | ||
minTimeout: opts.fetchRetryMintimeout || 1000, | ||
}) | ||
}, retry) | ||
} |
@@ -0,1 +1,2 @@ | ||
const { escapePath } = require('./utils.js') | ||
const which = require('which') | ||
@@ -8,5 +9,10 @@ | ||
module.exports = (opts = {}) => | ||
opts.git || | ||
opts.git !== false && gitPath || | ||
Object.assign(new Error('No git binary found in $PATH'), { code: 'ENOGIT' }) | ||
module.exports = (opts = {}) => { | ||
if (opts.git) { | ||
return opts.git | ||
} | ||
if (!gitPath || opts.git === false) { | ||
return Object.assign(new Error('No git binary found in $PATH'), { code: 'ENOGIT' }) | ||
} | ||
return escapePath(gitPath, opts) | ||
} |
{ | ||
"name": "@npmcli/git", | ||
"version": "2.0.6", | ||
"version": "2.0.7", | ||
"main": "lib/index.js", | ||
@@ -16,7 +16,9 @@ "files": [ | ||
"scripts": { | ||
"test": "tap", | ||
"lint": "standard", | ||
"lint:fix": "standard --fix", | ||
"postversion": "npm publish", | ||
"prepublishOnly": "git push origin --follow-tags", | ||
"preversion": "npm test", | ||
"snap": "tap", | ||
"preversion": "npm test", | ||
"postversion": "npm publish", | ||
"prepublishOnly": "git push origin --follow-tags" | ||
"test": "tap" | ||
}, | ||
@@ -29,15 +31,15 @@ "tap": { | ||
"slash": "^3.0.0", | ||
"tap": "^14.10.6" | ||
"standard": "^16.0.3", | ||
"tap": "^14.11.0" | ||
}, | ||
"dependencies": { | ||
"@npmcli/promise-spawn": "^1.1.0", | ||
"@npmcli/promise-spawn": "^1.3.2", | ||
"lru-cache": "^6.0.0", | ||
"mkdirp": "^1.0.3", | ||
"npm-pick-manifest": "^6.0.0", | ||
"mkdirp": "^1.0.4", | ||
"npm-pick-manifest": "^6.1.1", | ||
"promise-inflight": "^1.0.1", | ||
"promise-retry": "^2.0.1", | ||
"semver": "^7.3.2", | ||
"unique-filename": "^1.1.1", | ||
"semver": "^7.3.5", | ||
"which": "^2.0.2" | ||
} | ||
} |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
20956
8
432
2
3
- Removedunique-filename@^1.1.1
- Removedimurmurhash@0.1.4(transitive)
- Removedunique-filename@1.1.1(transitive)
- Removedunique-slug@2.0.2(transitive)
Updated@npmcli/promise-spawn@^1.3.2
Updatedmkdirp@^1.0.4
Updatednpm-pick-manifest@^6.1.1
Updatedsemver@^7.3.5