UNPKG

quip-cli

Version:

A Command Line Interface for the Quip Live Apps platform

158 lines (157 loc) 6.11 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.doPublish = exports.createBundle = void 0; const tslib_1 = require("tslib"); const command_1 = require("@oclif/command"); const chalk_1 = tslib_1.__importDefault(require("chalk")); const form_data_1 = tslib_1.__importDefault(require("form-data")); const fs_1 = tslib_1.__importDefault(require("fs")); const minimatch_1 = tslib_1.__importDefault(require("minimatch")); const path_1 = tslib_1.__importDefault(require("path")); const crypto_1 = tslib_1.__importDefault(require("crypto")); const cli_api_1 = tslib_1.__importStar(require("../lib/cli-api")); const config_1 = require("../lib/config"); const manifest_1 = require("../lib/manifest"); const print_1 = require("../lib/print"); const types_1 = require("../lib/types"); const util_1 = require("../lib/util"); exports.createBundle = async (manifest, manifestPath, ignore) => { const root = path_1.default.dirname(manifestPath); const allFiles = new Set(await util_1.readRecursive(root, ignore)); const missing = new Map(); const bundle = []; const addToFiles = (matcher, source) => { if (!matcher) { return; } let found = false; for (let file of allFiles) { if (minimatch_1.default(file, matcher)) { bundle.push(file); found = true; } } if (!found) { missing.set(source, missing.get(source) || new Set()); missing.get(source).add(matcher); } }; const addAll = (files, source) => { if (!files) { return; } files.forEach(matcher => { if (types_1.isMigration(matcher)) { addToFiles(matcher.js_file, source); } else { addToFiles(matcher, source); } }); }; addToFiles("manifest.json", "manifest file"); addToFiles(manifest.thumbnail, "thumbnail"); addToFiles(manifest.toolbar_icon, "toolbar_icon"); addAll(manifest.js_files, "js_files"); addAll(manifest.css_files, "css_file"); addAll(manifest.other_resources, "other_resources"); addAll(manifest.migrations, "migrations"); return { root, bundle, missing }; }; exports.doPublish = async (manifest, manifestPath, ignore, config, site, printJson) => { let gitsha = null; try { gitsha = await util_1.runCmdPromise(path_1.default.dirname(manifestPath), "git", "rev-parse", "HEAD"); } catch (e) { /* swallow this error, this is just a best effort. */ } const form = new form_data_1.default(); const { root, bundle, missing } = await exports.createBundle(manifest, manifestPath, ignore); if (missing.size > 0) { print_1.println(chalk_1.default `{red WARNING: the following files were defined in your manifest, but were not found.} {red This bundle may be incomplete, you should include these files or remove them from your manifest.}`); for (let [source, files] of missing) { print_1.println(chalk_1.default `{red === ${source} ===}`); files.forEach(f => print_1.println(chalk_1.default `{red ${f}}`)); } } const files = await Promise.all(bundle.map(async (name) => { const fileBuffer = await fs_1.default.promises.readFile(path_1.default.join(root, name)); return [ name, fileBuffer, crypto_1.default .createHash("md5") .update(fileBuffer) .digest("hex"), ]; })); const bundlemd5 = crypto_1.default.createHash("md5"); // Sort by md5 alphabetically so the md5 of these md5s is stable files .sort(([_na, _fa, a], [_nb, _fb, b]) => (a === b ? 0 : a < b ? -1 : 1)) .forEach(([name, data, md5]) => { form.append("bundle", data, { filepath: name, }); bundlemd5.update(md5); }); form.append("md5", bundlemd5.digest("hex")); if (gitsha) { form.append("gitsha", gitsha); } const fetch = await cli_api_1.default(config, site); const response = await cli_api_1.successOnly(fetch(`app/${manifest.id}`, "post", form), printJson); if (!response) { return null; } return response; }; class Publish extends command_1.Command { async run() { const { args, flags } = this.parse(Publish); const manifestPath = await manifest_1.findManifest(process.cwd()); if (!manifestPath) { throw new Error(`Could not find a manifest.json file.`); } const manifest = await manifest_1.getManifest(manifestPath); const success = await exports.doPublish(manifest, manifestPath, flags.ignore, flags.config, flags.site, flags.json); if (success) { if (!flags.json) { print_1.println(chalk_1.default `{magenta Successfully published ${manifest.name} v${manifest.version_name} (${manifest.version_number})}`); } } else { if (!flags.json) { print_1.println(chalk_1.default `{red Publishing failed.}`); } process.exit(1); } } } exports.default = Publish; Publish.description = "Uploads this bundle to the developer console, and sets it as the latest development version."; Publish.flags = { help: command_1.flags.help({ char: "h" }), json: command_1.flags.boolean({ char: "j", description: "output responses in JSON", }), ignore: command_1.flags.string({ char: "i", description: "blob to ignore. Defaults to 'node_modules'", default: "node_modules", }), site: command_1.flags.string({ char: "s", description: "use a specific quip site rather than the standard quip.com login", default: config_1.DEFAULT_SITE, }), config: command_1.flags.string({ hidden: true, description: "Use a custom config file (default ~/.quiprc)", default: () => config_1.defaultConfigPath(), }), }; Publish.args = [];