diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/bug_report.md similarity index 86% rename from .github/ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE/bug_report.md index 577081b8..e0af92a9 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -1,3 +1,11 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' +--- + - [] I have searched for [similar issues](https://github.com/raineorshine/npm-check-updates/issues) --- diff --git a/package-lock.json b/package-lock.json index ae97b4cd..8bb9f3b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "npm-check-updates", - "version": "17.1.15", + "version": "17.1.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "npm-check-updates", - "version": "17.1.15", + "version": "17.1.16", "license": "Apache-2.0", "bin": { "ncu": "build/cli.js", @@ -30,7 +30,6 @@ "@types/picomatch": "^3.0.1", "@types/progress": "^2.0.7", "@types/prompts": "^2.4.9", - "@types/remote-git-tags": "^4.0.2", "@types/semver": "^7.5.8", "@types/semver-utils": "^1.1.3", "@types/sinon": "^17.0.3", @@ -76,7 +75,6 @@ "progress": "^2.0.3", "prompts-ncu": "^3.0.2", "rc-config-loader": "^4.1.3", - "remote-git-tags": "^3.0.0", "rfdc": "^1.4.1", "rimraf": "^6.0.1", "rollup-plugin-node-externals": "^7.1.3", @@ -2257,12 +2255,6 @@ "kleur": "^3.0.3" } }, - "node_modules/@types/remote-git-tags": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/remote-git-tags/-/remote-git-tags-4.0.2.tgz", - "integrity": "sha512-2zrhBA1c6dr1kTT+6BpMoeOaXQPpvgbLPnPHJjuLR1WtkyL1LYytGA2J9LndV/DZTiI3kX9hffJjlZ6XPp5rmg==", - "dev": true - }, "node_modules/@types/semver": { "version": "7.5.8", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", @@ -10889,16 +10881,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/remote-git-tags": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remote-git-tags/-/remote-git-tags-3.0.0.tgz", - "integrity": "sha512-C9hAO4eoEsX+OXA4rla66pXZQ+TLQ8T9dttgQj18yuKlPMTVkIkdYXvlMC55IuUsIkV6DpmQYi10JKFLaU+l7w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", diff --git a/package.json b/package.json index 65428b57..14eeb50c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "npm-check-updates", - "version": "17.1.15", + "version": "17.1.16", "author": "Tomas Junnonen ", "license": "Apache-2.0", "contributors": [ @@ -74,7 +74,6 @@ "@types/picomatch": "^3.0.1", "@types/progress": "^2.0.7", "@types/prompts": "^2.4.9", - "@types/remote-git-tags": "^4.0.2", "@types/semver": "^7.5.8", "@types/semver-utils": "^1.1.3", "@types/sinon": "^17.0.3", @@ -120,7 +119,6 @@ "progress": "^2.0.3", "prompts-ncu": "^3.0.2", "rc-config-loader": "^4.1.3", - "remote-git-tags": "^3.0.0", "rfdc": "^1.4.1", "rimraf": "^6.0.1", "rollup-plugin-node-externals": "^7.1.3", diff --git a/src/index.ts b/src/index.ts index 8a7a0c1c..9d15bb94 100755 --- a/src/index.ts +++ b/src/index.ts @@ -146,7 +146,8 @@ const install = async ( for await (const pkgFile of pkgsNormalized) { const packageManager = await getPackageManagerForInstall(options, pkgFile) - const cmd = packageManager + (process.platform === 'win32' ? '.cmd' : '') + // npm, yarn, pnpm use .cmd on Windows, but bun does not + const cmd = packageManager + (process.platform === 'win32' && packageManager !== 'bun' ? '.cmd' : '') const cwd = options.cwd || path.resolve(pkgFile, '..') let stdout = '' try { diff --git a/src/package-managers/gitTags.ts b/src/package-managers/gitTags.ts index 725577e6..e6987a45 100644 --- a/src/package-managers/gitTags.ts +++ b/src/package-managers/gitTags.ts @@ -1,53 +1,72 @@ /** Fetches package metadata from Github tags. */ +import childProcess from 'node:child_process' +import { promisify } from 'node:util' import parseGithubUrl from 'parse-github-url' -import remoteGitTags from 'remote-git-tags' import { valid } from 'semver' import { print } from '../lib/logging' import * as versionUtil from '../lib/version-util' import { GetVersion } from '../types/GetVersion' +import { Index } from '../types/IndexType' import { Options } from '../types/Options' import { VersionLevel } from '../types/VersionLevel' import { VersionResult } from '../types/VersionResult' import { VersionSpec } from '../types/VersionSpec' +const execFile = promisify(childProcess.execFile) + +/** + * Fetches and extracts all git tags from a git url. + * + * @param url - url to a github repository. + * @returns the extracted git tags. + */ +async function getGitTags(url: string): Promise> { + const out = (await execFile('git', ['ls-remote', '--tags', url])).stdout + const tags: Index = {} + for (const line of out.trim().split('\n')) { + const splitted = line.split('\t') + tags[splitted[1].replace(/^refs\/tags\/|\^{}$/g, '')] = splitted[0] + } + return tags +} + /** Gets remote versions sorted. */ -const getSortedVersions = async (name: string, declaration: VersionSpec, options?: Options) => { +async function getSortedVersions( + name: string, + declaration: VersionSpec, + options?: Options, +): Promise { // if present, github: is parsed as the protocol. This is not valid when passed into remote-git-tags. declaration = declaration.replace(/^github:/, '') const { auth, protocol, host, path } = parseGithubUrl(declaration)! - let tagMap = new Map() - let tagsPromise = Promise.resolve(tagMap) - const protocolKnown = protocol != null - if (protocolKnown) { - tagsPromise = tagsPromise.then(() => - remoteGitTags( - `${protocol ? protocol.replace('git+', '') : 'https:'}//${auth ? auth + '@' : ''}${host}/${path?.replace(/^:/, '')}`, - ), - ) - } else { - // try ssh first, then https on failure - tagsPromise = tagsPromise - .then(() => remoteGitTags(`ssh://git@${host}/${path?.replace(/^:/, '')}`)) - .catch(() => remoteGitTags(`https://${auth ? auth + '@' : ''}${host}/${path}`)) - } + let tags: Index - // fetch remote tags try { - tagMap = await tagsPromise + if (protocol !== null) { + tags = await getGitTags( + `${protocol ? protocol.replace('git+', '') : 'https:'}//${auth ? auth + '@' : ''}${host}/${path?.replace(/^:/, '')}`, + ) + } else { + try { + tags = await getGitTags(`ssh://git@${host}/${path?.replace(/^:/, '')}`) + } catch { + tags = await getGitTags(`https://${auth ? auth + '@' : ''}${host}/${path}`) + } + } } catch (e) { // catch a variety of errors that occur on invalid or private repos - print(options || {}, `Invalid, private repo, or no tags for ${name}: ${declaration}`, 'verbose') - return null + print(options ?? {}, `Invalid, private repo, or no tags for ${name}: ${declaration}`, 'verbose') + return } - const tags = Array.from(tagMap.keys()) - .map(versionUtil.fixPseudoVersion) - // do not pass semver.valid reference directly since the mapping index will be interpreted as the loose option - // https://github.com/npm/node-semver#functions - .filter(tag => valid(tag)) - .sort(versionUtil.compareVersions) - - return tags + return ( + Object.keys(tags) + .map(versionUtil.fixPseudoVersion) + // do not pass semver.valid reference directly since the mapping index will be interpreted as the loose option + // https://github.com/npm/node-semver#functions + .filter(tag => valid(tag)) + .sort(versionUtil.compareVersions) + ) } /** Return the highest non-prerelease numbered tag on a remote Git URL. */