diff --git a/.eslintrc.json b/.eslintrc.json index 709f2712..82e101f3 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -9,9 +9,15 @@ "warn", "always" ], - "perfectionist/sort-classes": [ - "off" - ], + "perfectionist/sort-classes": "off", + "perfectionist/sort-interfaces": "off", + "perfectionist/sort-enums": "off", + "perfectionist/sort-objects": "off", + "perfectionist/sort-object-types": "off", + "unicorn/no-array-reduce": "off", + "unicorn/no-array-for-each": "off", + "unicorn/prefer-object-from-entries": "off", + "unicorn/prefer-type-error": "off", "quotes": [ "error", "single" diff --git a/README.md b/README.md index 17357dea..6db6aa5a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ $ npm install -g codify $ codify COMMAND running command... $ codify (--version) -codify/0.0.1 darwin-arm64 node-v20.15.0 +codify/0.0.4 darwin-arm64 node-v20.15.0 $ codify --help [COMMAND] USAGE $ codify COMMAND @@ -28,6 +28,7 @@ USAGE # Commands * [`codify apply`](#codify-apply) +* [`codify autocomplete [SHELL]`](#codify-autocomplete-shell) * [`codify help [COMMAND]`](#codify-help-command) * [`codify plan`](#codify-plan) * [`codify plugins`](#codify-plugins) @@ -41,6 +42,7 @@ USAGE * [`codify plugins unlink [PLUGIN]`](#codify-plugins-unlink-plugin) * [`codify plugins update`](#codify-plugins-update) * [`codify uninstall`](#codify-uninstall) +* [`codify update [CHANNEL]`](#codify-update-channel) ## `codify apply` @@ -68,7 +70,36 @@ EXAMPLES $ codify apply ``` -_See code: [src/commands/apply/index.ts](https://github.com/kevinwang5658/codify/blob/v0.0.1/src/commands/apply/index.ts)_ +## `codify autocomplete [SHELL]` + +Display autocomplete installation instructions. + +``` +USAGE + $ codify autocomplete [SHELL] [-r] + +ARGUMENTS + SHELL (zsh|bash|powershell) Shell type + +FLAGS + -r, --refresh-cache Refresh cache (ignores displaying instructions) + +DESCRIPTION + Display autocomplete installation instructions. + +EXAMPLES + $ codify autocomplete + + $ codify autocomplete bash + + $ codify autocomplete zsh + + $ codify autocomplete powershell + + $ codify autocomplete --refresh-cache +``` + +_See code: [@oclif/plugin-autocomplete](https://github.com/oclif/plugin-autocomplete/blob/v3.2.4/src/commands/autocomplete/index.ts)_ ## `codify help [COMMAND]` @@ -88,7 +119,7 @@ DESCRIPTION Display help for codify. ``` -_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.4/src/commands/help.ts)_ +_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v6.2.5/src/commands/help.ts)_ ## `codify plan` @@ -116,8 +147,6 @@ EXAMPLES $ codify plan ``` -_See code: [src/commands/plan/index.ts](https://github.com/kevinwang5658/codify/blob/v0.0.1/src/commands/plan/index.ts)_ - ## `codify plugins` List installed plugins. @@ -139,7 +168,7 @@ EXAMPLES $ codify plugins ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.3/src/commands/plugins/index.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.4/src/commands/plugins/index.ts)_ ## `codify plugins add PLUGIN` @@ -213,7 +242,7 @@ EXAMPLES $ codify plugins inspect myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.3/src/commands/plugins/inspect.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.4/src/commands/plugins/inspect.ts)_ ## `codify plugins install PLUGIN` @@ -262,7 +291,7 @@ EXAMPLES $ codify plugins install someuser/someplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.3/src/commands/plugins/install.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.4/src/commands/plugins/install.ts)_ ## `codify plugins link PATH` @@ -292,7 +321,7 @@ EXAMPLES $ codify plugins link myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.3/src/commands/plugins/link.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.4/src/commands/plugins/link.ts)_ ## `codify plugins remove [PLUGIN]` @@ -333,7 +362,7 @@ FLAGS --reinstall Reinstall all plugins after uninstalling. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.3/src/commands/plugins/reset.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.4/src/commands/plugins/reset.ts)_ ## `codify plugins uninstall [PLUGIN]` @@ -361,7 +390,7 @@ EXAMPLES $ codify plugins uninstall myplugin ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.3/src/commands/plugins/uninstall.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.4/src/commands/plugins/uninstall.ts)_ ## `codify plugins unlink [PLUGIN]` @@ -405,7 +434,7 @@ DESCRIPTION Update installed plugins. ``` -_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.3/src/commands/plugins/update.ts)_ +_See code: [@oclif/plugin-plugins](https://github.com/oclif/plugin-plugins/blob/v5.3.4/src/commands/plugins/update.ts)_ ## `codify uninstall` @@ -431,5 +460,40 @@ EXAMPLES $ codify uninstall ``` -_See code: [src/commands/uninstall.ts](https://github.com/kevinwang5658/codify/blob/v0.0.1/src/commands/uninstall.ts)_ +## `codify update [CHANNEL]` + +update the codify CLI + +``` +USAGE + $ codify update [CHANNEL] [--force | | [-a | -v | -i]] + +FLAGS + -a, --available See available versions. + -i, --interactive Interactively select version to install. This is ignored if a channel is provided. + -v, --version= Install a specific version. + --force Force a re-download of the requested version. + +DESCRIPTION + update the codify CLI + +EXAMPLES + Update to the stable channel: + + $ codify update stable + + Update to a specific version: + + $ codify update --version 1.0.0 + + Interactively select version: + + $ codify update --interactive + + See available versions: + + $ codify update --available +``` + +_See code: [@oclif/plugin-update](https://github.com/oclif/plugin-update/blob/v4.5.9/src/commands/update.ts)_ diff --git a/package.json b/package.json index 1c2e84ef..72e320fc 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,16 @@ "@oclif/core": "^4.0.8", "@oclif/plugin-help": "^6.2.4", "@oclif/plugin-plugins": "^5.3.3", + "@oclif/plugin-autocomplete": "3.2.4", + "@oclif/plugin-commands": "4.0.16", + "@oclif/plugin-update": "4.5.9", + "@oclif/plugin-version": "2.2.13", + "@oclif/plugin-warn-if-update-available": "3.1.17", + "@oclif/plugin-which": "3.2.14", "ajv": "^8.12.0", "ajv-formats": "^3.0.1", "chalk": "^5.3.0", - "codify-schemas": "1.0.44", + "codify-schemas": "1.0.45", "debug": "^4.3.4", "ink": "^4.4.1", "parse-json": "^8.1.0", @@ -26,6 +32,12 @@ "devDependencies": { "@oclif/prettier-config": "^0.2.1", "@oclif/test": "^4.0.4", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-typescript": "^11.1.6", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-wasm": "^6.2.2", "@types/chai": "^4", "@types/chai-as-promised": "^7.1.7", "@types/chalk": "^2.2.0", @@ -46,6 +58,8 @@ "mocha": "^10", "mock-fs": "^5.2.0", "oclif": "4.13.12", + "rollup": "^4.12.0", + "rollup-plugin-copy": "^3.5.0", "shx": "^0.3.3", "strip-ansi": "^7.1.0", "tsx": "^4.7.3", @@ -69,11 +83,18 @@ "oclif": { "bin": "codify", "dirname": "codify", - "commands": "./dist/commands", "plugins": [ "@oclif/plugin-help", - "@oclif/plugin-plugins" + "@oclif/plugin-plugins", + "@oclif/plugin-autocomplete", + "@oclif/plugin-update", + "@oclif/plugin-warn-if-update-available" ], + "commands": { + "strategy": "explicit", + "target": "./dist/index.js", + "identifier": "COMMANDS" + }, "topicSeparator": " ", "topics": { "plan": { @@ -86,6 +107,15 @@ "macos": { "identifier": "com.codify.cli", "sign": "\"Developer ID Installer: Qingran Wang (PCG246DPVT)\"" + }, + "update": { + "s3": { + "host": "https://releases.codifycli.com", + "bucket": "cli-releases" + } + }, + "warn-if-update-available": { + "timeoutInDays": 7 } }, "repository": "kevinwang5658/codify", @@ -93,7 +123,7 @@ "build": "shx rm -rf dist && tsc -b", "lint": "tsc && eslint . --ext .ts", "postpack": "shx rm -f oclif.manifest.json", - "pkg": "tsc && oclif pack macos -r .", + "pkg": "shx rm -rf dist && rollup -c && oclif pack macos -r .", "posttest": "npm run lint", "prepack": "oclif manifest && oclif readme", "test": "mocha --forbid-only \"test/**/*.test.ts\"", @@ -101,7 +131,7 @@ "start:dev": "./bin/dev.js", "start:vm": "npm run build && npm run pack:macos && npm run start:vm" }, - "version": "0.0.1", + "version": "0.0.4", "bugs": "https://github.com/kevinwang5658/codify/issues", "keywords": [ "oclif" diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 00000000..2ad1a451 --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,26 @@ +import commonjs from '@rollup/plugin-commonjs'; +import json from '@rollup/plugin-json'; +import nodeResolve from '@rollup/plugin-node-resolve'; +import terser from '@rollup/plugin-terser'; +import typescript from '@rollup/plugin-typescript'; +import wasm from '@rollup/plugin-wasm'; +import copy from 'rollup-plugin-copy'; + +export default { + input: 'src/index.ts', + output: { + dir:'./dist', + format: 'es' + }, + plugins: [ + copy({ + targets: [{ dest: './dist/', src: './node_modules/yoga-wasm-web/dist/yoga.wasm' }] + }), + json(), + wasm(), + nodeResolve({ exportConditions: ['node'] }), + typescript(), + commonjs(), + terser() + ] +} diff --git a/scripts/pkg.ts b/scripts/pkg.ts new file mode 100755 index 00000000..62385c8a --- /dev/null +++ b/scripts/pkg.ts @@ -0,0 +1,34 @@ + +import chalk from 'chalk' +import { ChildProcess, exec } from 'node:child_process' +import fs from 'node:fs/promises' + +console.log(chalk.magenta('Removing ./dist folder')) +await fs.rm('../dist', { + force: true, + recursive: true, +}) + +console.log(chalk.magenta('Creating build directory')) +try { + await fs.mkdir('../build', {}); +} catch { + console.error('Directory already exists') +} + +await fs.cp('../src/', '../build') +await fs.cp('../package.json', '../build') + + +console.log(chalk.magenta('Running rollup')) +const rollupProcess = exec('rollup -c --file '); +addStdout(rollupProcess) + +function addStdout(process: ChildProcess) { + process.stdout!.on('data', (data) => { + console.log(data) + }) + process.stderr!.on('data', (data) => { + console.log(data) + }) +} diff --git a/scripts/upload.sh b/scripts/upload.sh new file mode 100644 index 00000000..25572aa8 --- /dev/null +++ b/scripts/upload.sh @@ -0,0 +1,4 @@ +npm run pkg +oclif pack tarballs -r . -t darwin-arm64,darwin-x64 +oclif upload macos +oclif upload tarballs -t darwin-arm64,darwin-x64 diff --git a/src/commands/apply/index.ts b/src/commands/apply/index.ts index 4a77e1ea..b5e36e82 100644 --- a/src/commands/apply/index.ts +++ b/src/commands/apply/index.ts @@ -1,4 +1,4 @@ -import { Args, Flags } from '@oclif/core' +import Flags from '@oclif/core/flags' import * as path from 'node:path'; import { BaseCommand } from '../../common/base-command.js'; diff --git a/src/commands/plan/index.ts b/src/commands/plan/index.ts index c30867f6..ccc5a32f 100644 --- a/src/commands/plan/index.ts +++ b/src/commands/plan/index.ts @@ -1,8 +1,8 @@ -import { Args, Flags } from '@oclif/core' +import Flags from '@oclif/core/flags' import * as path from 'node:path'; -import { PlanOrchestrator } from '../../orchestrators/plan.js'; import { BaseCommand } from '../../common/base-command.js'; +import { PlanOrchestrator } from '../../orchestrators/plan.js'; export default class Plan extends BaseCommand { static description = 'Generate a plan based on a codify.json file. This plan will list ' + diff --git a/src/common/base-command.ts b/src/common/base-command.ts index 592244b4..00c3370e 100644 --- a/src/common/base-command.ts +++ b/src/common/base-command.ts @@ -1,4 +1,5 @@ import { Command, Flags } from '@oclif/core'; +import { OutputFlags } from '@oclif/core/interfaces'; import chalk from 'chalk'; import { SudoRequestData } from 'codify-schemas'; import createDebug from 'debug'; @@ -6,7 +7,6 @@ import createDebug from 'debug'; import { Event, ctx } from '../events/context.js'; import { Reporter, ReporterFactory, ReporterType } from '../ui/reporters/reporter.js'; import { prettyPrintError } from './errors.js'; -import { OutputFlags } from '@oclif/core/interfaces'; export abstract class BaseCommand extends Command { diff --git a/src/index.ts b/src/index.ts index 0237950a..bf149a09 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1 +1,15 @@ -export { run } from '@oclif/core' +import { Command, execute } from '@oclif/core'; + +import Apply from './commands/apply/index.js' +import Plan from './commands/plan/index.js' +import Uninstall from './commands/uninstall.js' + +export const COMMANDS: Record = { + apply: Apply, + plan: Plan, + uninstall: Uninstall, +} + +export async function run() { + await execute({ dir: import.meta.url }) +} diff --git a/src/plugins/plugin-manager.ts b/src/plugins/plugin-manager.ts index 22268bb0..b8e769ac 100644 --- a/src/plugins/plugin-manager.ts +++ b/src/plugins/plugin-manager.ts @@ -1,15 +1,14 @@ import { ResourceOperation, ValidateResponseData } from 'codify-schemas'; +import { InternalError } from '../common/errors.js'; import { Plan, ResourcePlan } from '../entities/plan.js'; +import { PlanRequest } from '../entities/plan-request.js'; import { Project } from '../entities/project.js'; -import { ResourceConfig } from '../entities/resource-config.js'; import { SubProcessName, ctx } from '../events/context.js'; import { prettyFormatResourcePlan } from '../ui/plan-pretty-printer.js'; import { groupBy } from '../utils/index.js'; import { Plugin } from './plugin.js'; import { PluginResolver } from './resolver.js'; -import { InternalError } from '../common/errors.js'; -import { PlanRequest } from '../entities/plan-request.js'; type PluginName = string; type ResourceTypeId = string; @@ -96,10 +95,10 @@ export class PluginManager { }; const configPlugins = await Promise.all(Object.entries(pluginDefinitions).map(([name, version]) => - PluginResolver.resolve(name, version) + PluginResolver.getOrDownload(name, version) )); - const existingPlugins = await PluginResolver.resolveExisting(Object.keys(pluginDefinitions)); + const existingPlugins = await PluginResolver.getAllExisting(Object.keys(pluginDefinitions)); return [...existingPlugins, ...configPlugins]; } diff --git a/src/plugins/resolver.ts b/src/plugins/resolver.ts index 4976dede..97a32263 100644 --- a/src/plugins/resolver.ts +++ b/src/plugins/resolver.ts @@ -12,28 +12,31 @@ const PLUGIN_CACHE_DIR = '/Library/Caches/codify/plugins' export class PluginResolver { - static async resolve(name: string, version: string): Promise { - await PluginResolver.checkAndCreateCacheDirIfNotExists() + static async getOrDownload(name: string, versionOrPath?: string): Promise { + await PluginResolver.createPluginDirIfNotExists() + + // Default versions to latest + versionOrPath = versionOrPath ?? 'latest'; let directoryStat; try { - directoryStat = await fs.stat(version); + directoryStat = await fs.stat(versionOrPath); } catch { } // For easier development. A direct js file can be specified for the plugin. if (directoryStat && directoryStat.isFile()) { - return PluginResolver.resolvePluginFs(name, version) + return PluginResolver.getFromFileSystem(name, versionOrPath) } if (name === 'default') { - return PluginResolver.resolvePluginDefault(name, version) + return PluginResolver.downloadDefaultPlugin(name, versionOrPath) } throw new Error('Non-default plugins are not currently supported'); } - static async resolveExisting(exclude: string[]): Promise { + static async getAllExisting(exclude: string[]): Promise { let files; try { files = await fs.readdir(PLUGIN_CACHE_DIR); @@ -57,7 +60,7 @@ export class PluginResolver { } } - private static async resolvePluginFs(name: string, filePath: string): Promise { + private static async getFromFileSystem(name: string, filePath: string): Promise { const fileExtension = filePath.slice(filePath.lastIndexOf('.')) if (fileExtension !== '.js' && fileExtension !== '.ts') { throw new Error(`Only .js and .ts plugins are support currently. Can't resolve ${filePath}`); @@ -70,7 +73,7 @@ export class PluginResolver { ) } - private static async resolvePluginDefault(name: string, version: string): Promise { + private static async downloadDefaultPlugin(name: string, version: string): Promise { const { body } = await fetch(DEFAULT_PLUGIN_URL) if (!body) { throw new Error('Un-able to fetch the default plugin (body not found). Exiting'); @@ -89,7 +92,7 @@ export class PluginResolver { ) } - private static async checkAndCreateCacheDirIfNotExists() { + private static async createPluginDirIfNotExists() { let pluginDirStat = null; try { pluginDirStat = await fs.stat(PluginResolver.getCacheDir()) diff --git a/src/utils/ajv.ts b/src/utils/ajv.ts index 616b1fb0..d7181374 100644 --- a/src/utils/ajv.ts +++ b/src/utils/ajv.ts @@ -1,9 +1,10 @@ -import Ajv2020 from 'ajv/dist/2020.js'; -import addFormats from 'ajv-formats'; +import { Ajv } from 'ajv'; import { ErrorObject } from 'ajv'; +import addFormats from 'ajv-formats'; + import { SourceMapCache } from '../parser/source-maps.js'; -const ajv = new Ajv2020.default({ +const ajv = new Ajv({ allErrors: true, strict: true, }); diff --git a/test/integration/resolver.test.ts b/test/integration/resolver.test.ts index 83313861..47aa36d5 100644 --- a/test/integration/resolver.test.ts +++ b/test/integration/resolver.test.ts @@ -13,7 +13,7 @@ describe('Plugin resolver integration test', () => { }) it('resolves the default plugin', async () => { - const plugin = await PluginResolver.resolve('default') + const plugin = await PluginResolver.getOrDownload('default') expect(fs.existsSync('/Library/Caches/codify/plugins/default.js')).to.be.true; }) diff --git a/tsconfig.json b/tsconfig.json index 69915ca9..b7dfba11 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,5 @@ { "compilerOptions": { - "declaration": true, "module": "NodeNext", "moduleResolution": "Node16", "esModuleInterop": true,