-
Notifications
You must be signed in to change notification settings - Fork 1
/
version.ts
153 lines (129 loc) · 4.48 KB
/
version.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
153
import {Command, Flags, Interfaces} from '@oclif/core'
import {Ansis} from 'ansis'
import {exec} from 'node:child_process'
import {EOL} from 'node:os'
const ansis = new Ansis()
export type VersionDetail = {
pluginVersions?: string[]
} & Omit<Interfaces.VersionDetails, 'pluginVersions'>
type NpmDetails = {
date: string
'dist-tags': Record<string, string>
name: string
time: Record<string, string>
version: string
versions: string[]
}
async function getNpmDetails(pkg: string): Promise<NpmDetails | false> {
return new Promise((resolve) => {
exec(`npm view ${pkg} --json`, (error, stdout) => {
if (error) {
resolve(false)
} else {
resolve(JSON.parse(stdout) as NpmDetails)
}
})
})
}
function daysAgo(date: string): number {
const now = new Date()
const then = new Date(date)
const diff = now.getTime() - then.getTime()
return Math.floor(diff / (1000 * 60 * 60 * 24))
}
function humanReadableDate(date: string): string {
return new Date(date).toDateString()
}
async function formatPlugins(
config: Interfaces.Config,
plugins: Record<string, Interfaces.PluginVersionDetail>,
): Promise<string[]> {
const sorted = Object.entries(plugins)
.map(([name, plugin]) => ({name, ...plugin}))
.sort((a, b) => (a.name > b.name ? 1 : -1))
return Promise.all(
sorted.map(async (plugin) => {
const base =
`${getFriendlyName(config, plugin.name)} ${ansis.dim(plugin.version)} ${ansis.dim(`(${plugin.type})`)} ${
plugin.type === 'link' ? ansis.dim(plugin.root) : ''
}`.trim()
if (plugin.type === 'user') {
const npmDetails = await getNpmDetails(plugin.name)
const publishedString = npmDetails
? ansis.dim(
` published ${daysAgo(npmDetails.time[plugin.version])} days ago (${humanReadableDate(npmDetails.time[plugin.version])})`,
)
: ''
const notLatestWarning =
npmDetails && plugin.version !== npmDetails['dist-tags'].latest
? ansis.red(` (latest is ${npmDetails['dist-tags'].latest})`)
: ''
return `${base}${publishedString}${notLatestWarning}`
}
return base
}),
)
}
function getFriendlyName(config: Interfaces.Config, name: string): string {
const {scope} = config.pjson.oclif
if (!scope) return name
const match = name.match(`@${scope}/plugin-(.+)`)
if (!match) return name
return match[1]
}
export default class Version extends Command {
static enableJsonFlag = true
public static flags = {
verbose: Flags.boolean({
description:
'Additionally shows the architecture, node version, operating system, and versions of plugins that the CLI is using.',
summary: 'Show additional information about the CLI.',
}),
}
async run(): Promise<VersionDetail> {
const {flags} = await this.parse(Version)
const {pluginVersions, ...theRest} = this.config.versionDetails
const versionDetail: VersionDetail = {...theRest}
let output = `${this.config.userAgent}`
if (flags.verbose) {
const details = await getNpmDetails(this.config.pjson.name)
const cliPublishedString = details
? ansis.dim(
` published ${daysAgo(details.time[this.config.version])} days ago (${humanReadableDate(details.time[this.config.version])})`,
)
: ''
const notLatestWarning =
details && this.config.version !== details['dist-tags'].latest
? ansis.red(` (latest is ${details['dist-tags'].latest})`)
: ''
versionDetail.pluginVersions = await formatPlugins(this.config, pluginVersions ?? {})
versionDetail.shell ??= 'unknown'
output = ` ${ansis.bold('CLI Version')}:
\t${versionDetail.cliVersion}${cliPublishedString}${notLatestWarning}
${ansis.bold('Architecture')}:
\t${versionDetail.architecture}
${ansis.bold('Node Version')}:
\t${versionDetail.nodeVersion}
${ansis.bold('Plugin Version')}:
\t${(versionDetail.pluginVersions ?? []).join(EOL + '\t')}
${ansis.bold('OS and Version')}:
\t${versionDetail.osVersion}
${ansis.bold('Shell')}:
\t${versionDetail.shell}
${ansis.bold('Root Path')}:
\t${versionDetail.rootPath}
`
}
this.log(output)
return flags.verbose
? {
...versionDetail,
pluginVersions: versionDetail.pluginVersions?.map((plugin) => ansis.strip(plugin)),
}
: {
architecture: versionDetail.architecture,
cliVersion: versionDetail.cliVersion,
nodeVersion: versionDetail.nodeVersion,
}
}
}