Skip to content

Commit

Permalink
feat: incorporate jit plugins
Browse files Browse the repository at this point in the history
  • Loading branch information
mdonnalley committed Sep 14, 2023
1 parent 60626db commit 8b48a8c
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 4 deletions.
25 changes: 22 additions & 3 deletions src/commands/plugins/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import * as chalk from 'chalk'
import {Command, Flags, Plugin, ux} from '@oclif/core'
import {Command, Flags, Interfaces, Plugin, ux} from '@oclif/core'

import Plugins from '../../plugins'
import {sortBy} from '../../util'

type JitPlugin = {name: string; version: string; type: 'jit'}
type PluginsJson = Array<Interfaces.Plugin | JitPlugin>

export default class PluginsIndex extends Command {
static enableJsonFlag = true
static flags = {
Expand All @@ -16,7 +19,7 @@ export default class PluginsIndex extends Command {

plugins = new Plugins(this.config)

async run(): Promise<ReturnType<Plugins['list']>> {
async run(): Promise<PluginsJson> {
const {flags} = await this.parse(PluginsIndex)
let plugins = this.config.getPluginsList()
sortBy(plugins, p => this.plugins.friendlyName(p.name))
Expand All @@ -29,11 +32,19 @@ export default class PluginsIndex extends Command {
return []
}

const jitPluginsConfig = this.config.pjson.oclif.jitPlugins ?? {}

const jitPlugins: JitPlugin[] = Object.entries(jitPluginsConfig).map(([name, version]) => ({name: this.plugins.friendlyName(name), version, type: 'jit'}))
sortBy(jitPlugins, p => p.name)

if (!this.jsonEnabled()) {
this.display(plugins as Plugin[])
this.displayJitPlugins(jitPlugins)
}

return this.plugins.list()
const results = this.config.getPluginsList()

return [...results, ...jitPlugins]
}

private display(plugins: Plugin[]) {
Expand All @@ -46,6 +57,14 @@ export default class PluginsIndex extends Command {
}
}

private displayJitPlugins(jitPlugins: JitPlugin[]) {
if (jitPlugins.length === 0) return
this.log(chalk.dim('\nUninstalled JIT Plugins:'))
for (const {name, version} of jitPlugins) {
this.log(`${name} ${chalk.dim(version)}`)
}
}

private createTree(plugin: Plugin) {
const tree = ux.tree()
for (const p of plugin.children) {
Expand Down
4 changes: 4 additions & 0 deletions src/commands/plugins/inspect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ export default class PluginsInspect extends Command {
const pluginConfig = this.config.getPluginsList().find(plg => plg.name === pluginName)

if (pluginConfig) return pluginConfig as Plugin
if (this.config.pjson.oclif.jitPlugins?.[pluginName]) {
this.warn(`Plugin ${pluginName} is a JIT plugin. It will be installed the first time you run one of it's commands.`)
}

throw new Error(`${pluginName} not installed`)
}

Expand Down
17 changes: 16 additions & 1 deletion src/commands/plugins/install.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Command, Flags, ux, Args, Errors} from '@oclif/core'
import {Command, Flags, ux, Args, Errors, Interfaces} from '@oclif/core'
import * as validate from 'validate-npm-package-name'
import * as chalk from 'chalk'

Expand Down Expand Up @@ -34,17 +34,22 @@ e.g. If you have a core plugin that has a 'hello' command, installing a user-ins
char: 'f',
description: 'Run yarn install with force flag.',
}),
jit: Flags.boolean({
hidden: true,
}),
};

static aliases = ['plugins:add'];

plugins = new Plugins(this.config);
flags!: Interfaces.InferredFlags<typeof PluginsInstall.flags>;

// In this case we want these operations to happen
// sequentially so the `no-await-in-loop` rule is ignored
/* eslint-disable no-await-in-loop */
async run(): Promise<void> {
const {flags, argv} = await this.parse(PluginsInstall)
this.flags = flags
if (flags.verbose) this.plugins.verbose = true
const aliases = this.config.pjson.oclif.aliases || {}
for (let name of argv as string[]) {
Expand Down Expand Up @@ -98,6 +103,16 @@ e.g. If you have a core plugin that has a 'hello' command, installing a user-ins
const [splitName, tag = 'latest'] = input.split('@')
const name = await this.plugins.maybeUnfriendlyName(splitName)
validateNpmPkgName(name)

if (this.flags.jit) {
const jitVersion = this.config.pjson.oclif?.jitPlugins?.[name]
if (jitVersion && input.includes('@')) {
this.warn(`--jit flag is present. Ignoring tag ${tag} and using the version specified in package.json (${jitVersion}).`)
}

return {name, tag: jitVersion ?? tag, type: 'npm'}
}

return {name, tag, type: 'npm'}
}
}
Expand Down
3 changes: 3 additions & 0 deletions test/commands/plugins/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,18 @@ describe('command', () => {
.it('installs and uninstalls @oclif/example-plugin-ts')

test
.stdout()
.command(['plugins', '--json'], {reset: true})
.do(output => expect((output.returned)).to.deep.equal([]))
.command(['plugins:install', '@oclif/example-plugin-ts'], {reset: true})
.stdout()
.command(['plugins', '--json'], {reset: true})
.do(output => expect((output.returned as [{name: string}]).find(o => o.name === '@oclif/example-plugin-ts')).to.have.property('type', 'user'))
.stdout()
.command(['hello'], {reset: true})
.do(output => expect(output.stdout).to.contain('hello world'))
.command(['plugins:uninstall', '@heroku-cli/plugin-@oclif/example-plugin-ts'])
.stdout()
.command(['plugins', '--json'], {reset: true})
.do(output => expect((output.returned)).to.deep.equal([]))
.it('installs and uninstalls @oclif/example-plugin-ts (--json)')
Expand Down

0 comments on commit 8b48a8c

Please sign in to comment.