UNPKG

heroku

Version:

CLI to interact with Heroku

203 lines (196 loc) 8.29 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const yaml = require("js-yaml"); const fs_extra_1 = require("fs-extra"); const command_1 = require("@heroku-cli/command"); const completions_1 = require("@heroku-cli/command/lib/completions"); const core_1 = require("@oclif/core"); const heroku_cli_util_1 = require("@heroku/heroku-cli-util"); const color_1 = require("@heroku-cli/color"); const lodash_1 = require("lodash"); const git_1 = require("../../lib/git/git"); const git = new git_1.default(); function createText(name, space) { let text = `Creating ${name ? color_1.default.app(name) : 'app'}`; if (space) { text += ` in space ${space}`; } return text; } async function createApp(context, heroku, name, stack) { var _a, _b; const { flags } = context; const params = { name, team: flags.team, region: flags.region, space: flags.space, stack, internal_routing: flags['internal-routing'], feature_flags: flags.features, kernel: flags.kernel, locked: flags.locked, }; const requestPath = (params.space || params.team) ? '/teams/apps' : '/apps'; const { body: app } = await heroku.post(requestPath, { body: params, }); let status = name ? 'done' : `done, ${color_1.default.app(app.name || '')}`; if (flags.region) { status += `, region is ${color_1.default.yellow(((_a = app.region) === null || _a === void 0 ? void 0 : _a.name) || '')}`; } if (stack) { status += `, stack is ${color_1.default.yellow(((_b = app.stack) === null || _b === void 0 ? void 0 : _b.name) || '')}`; } core_1.ux.action.stop(status); return app; } async function addAddons(heroku, app, addons) { for (const addon of addons) { const body = { plan: addon.plan, attachment: addon.as ? { name: addon.as } : undefined, }; core_1.ux.action.start(`Adding ${color_1.default.green(addon.plan)}`); await heroku.post(`/apps/${app.name}/addons`, { body }); core_1.ux.action.stop(); } } async function addConfigVars(heroku, app, configVars) { if (Object.keys(configVars).length > 0) { core_1.ux.action.start('Setting config vars'); await heroku.patch(`/apps/${app.name}/config-vars`, { body: configVars, }); core_1.ux.action.stop(); } } function addonsFromPlans(plans) { return plans.map(plan => ({ plan: plan.trim(), })); } async function configureGitRemote(context, app) { const remoteUrl = git.httpGitUrl(app.name || ''); if (!context.flags['no-remote'] && git.inGitRepo()) { await git.createRemote(context.flags.remote || 'heroku', remoteUrl); } return remoteUrl; } function printAppSummary(context, app, remoteUrl) { if (context.flags.json) { heroku_cli_util_1.hux.styledJSON(app); } else { core_1.ux.log(`${color_1.default.cyan(app.web_url || '')} | ${color_1.default.green(remoteUrl)}`); } } async function runFromFlags(context, heroku, config) { const { flags, args } = context; if (flags['internal-routing'] && !flags.space) { throw new Error('Space name required.\nInternal Web Apps are only available for Private Spaces.\nUSAGE: heroku apps:create --space my-space --internal-routing'); } const name = flags.app || args.app || process.env.HEROKU_APP; async function addBuildpack(app, buildpack) { core_1.ux.action.start(`Setting buildpack to ${color_1.default.cyan(buildpack)}`); await heroku.put(`/apps/${app.name}/buildpack-installations`, { headers: { Range: '' }, body: { updates: [{ buildpack: buildpack }] }, }); core_1.ux.action.stop(); } core_1.ux.action.start(createText(name, flags.space)); const app = await createApp(context, heroku, name, flags.stack); core_1.ux.action.stop(); if (flags.addons) { const plans = flags.addons.split(','); const addons = addonsFromPlans(plans); await addAddons(heroku, app, addons); } if (flags.buildpack) { await addBuildpack(app, flags.buildpack); } const remoteUrl = await configureGitRemote(context, app); await config.runHook('recache', { type: 'app', app: app.name }); printAppSummary(context, app, remoteUrl); } async function readManifest() { const buffer = await (0, fs_extra_1.readFile)('heroku.yml'); return yaml.load(buffer.toString(), { filename: 'heroku.yml' }); } async function runFromManifest(context, heroku) { const { flags, args } = context; const name = flags.app || args.app || process.env.HEROKU_APP; core_1.ux.action.start('Reading heroku.yml manifest'); const manifest = await readManifest(); core_1.ux.action.stop(); core_1.ux.action.start(createText(name, flags.space)); const app = await createApp(context, heroku, name, 'container'); core_1.ux.action.stop(); // _.get used here to avoid type guards when working with `unknown` const setup = (0, lodash_1.get)(manifest, 'setup', {}); const addons = setup.addons || []; const configVars = setup.config || {}; await addAddons(heroku, app, addons); await addConfigVars(heroku, app, configVars); const remoteUrl = await configureGitRemote(context, app); printAppSummary(context, app, remoteUrl); } class Create extends command_1.Command { async run() { const context = await this.parse(Create); const { flags } = context; if (this.config.channel === 'beta' && flags.manifest) { return runFromManifest(context, this.heroku); } await runFromFlags(context, this.heroku, this.config); } } exports.default = Create; Create.description = 'creates a new app'; Create.hiddenAliases = ['create']; Create.examples = [ `$ heroku apps:create Creating app... done, stack is heroku-24 https://floating-dragon-42.heroku.com/ | https://git.heroku.com/floating-dragon-42.git # or just $ heroku create # use a heroku.yml manifest file $ heroku apps:create --manifest # specify a buildpack $ heroku apps:create --buildpack https://github.com/some/buildpack.git # specify a name $ heroku apps:create example # create a staging app $ heroku apps:create example-staging --remote staging # create an app in the eu region $ heroku apps:create --region eu`, ]; Create.args = { app: core_1.Args.string({ description: 'name of app to create', required: false }), }; Create.flags = { // `app` set to `flags.string` instead of `flags.app` to maintain original v5 functionality and avoid a default value from the git remote set when used without an app app: command_1.flags.string({ hidden: true }), addons: command_1.flags.string({ description: 'comma-delimited list of addons to install' }), buildpack: command_1.flags.string({ char: 'b', description: 'buildpack url to use for this app', completion: completions_1.BuildpackCompletion, }), manifest: command_1.flags.boolean({ char: 'm', description: 'use heroku.yml settings for this app', hidden: true }), 'no-remote': command_1.flags.boolean({ char: 'n', description: 'do not create a git remote' }), remote: command_1.flags.remote({ description: 'the git remote to create, default "heroku"', default: 'heroku' }), stack: command_1.flags.string({ char: 's', description: 'the stack to create the app on', completion: completions_1.StackCompletion }), space: command_1.flags.string({ description: 'the private space to create the app in', completion: completions_1.SpaceCompletion }), region: command_1.flags.string({ description: 'specify region for the app to run in', completion: completions_1.RegionCompletion }), 'internal-routing': command_1.flags.boolean({ hidden: true, description: 'private space-only. create as an Internal Web App that is only routable in the local network.', }), features: command_1.flags.string({ hidden: true }), kernel: command_1.flags.string({ hidden: true }), locked: command_1.flags.boolean({ hidden: true }), json: command_1.flags.boolean({ description: 'output in json format' }), team: command_1.flags.team(), };