@heroku-cli/plugin-addons-v5
Version:
`heroku addons:*` commands
130 lines (104 loc) • 4.2 kB
JavaScript
const cli = require('heroku-cli-util')
let context
let heroku
let app
let name
let plan
let addon
let service
function noPlanError() {
throw new Error(`Error: No plan specified.
You need to specify a plan to move ${cli.color.yellow(name)} to.
For example: ${cli.color.blue('heroku addons:upgrade heroku-redis:premium-0')}
${cli.color.cyan('https://devcenter.heroku.com/articles/managing-add-ons')}`)
}
function handlePlanChangeAPIError(err) {
const {sortBy} = require('lodash')
if (err.statusCode === 422 && err.body.message && err.body.message.startsWith("Couldn't find either the add-on")) {
return heroku.get(`/addon-services/${service}/plans`)
.then(plans => {
plans = sortBy(plans, 'price.cents').map(plans => plans.name)
throw new Error(`${err.body.message}
Here are the available plans for ${cli.color.yellow(service)}:
${plans.join('\n')}
See more plan information with ${cli.color.blue('heroku addons:plans ' + service)}
${cli.color.cyan('https://devcenter.heroku.com/articles/managing-add-ons')}`)
})
}
throw err
}
function handleAPIError(err) {
if (err.statusCode === 422 && err.body.id === 'multiple_matches') {
let example = err.body.message.split(', ')[2] || 'redis-triangular-1234'
throw new Error(`${err.body.message}
Multiple add-ons match ${cli.color.yellow(name)}${app ? ' on ' + app : ''}
It is not clear which add-on's plan you are trying to change.
Specify the add-on name instead of the name of the add-on service.
For example, instead of: ${cli.color.blue('heroku addons:upgrade ' + context.args.addon + ' ' + (context.args.plan || ''))}
Run this: ${cli.color.blue('heroku addons:upgrade ' + example + ' ' + name + ':' + plan)}
${
!app ? 'Alternatively, specify an app to filter by with ' + cli.color.blue('--app') : ''
}
${cli.color.cyan('https://devcenter.heroku.com/articles/managing-add-ons')}`)
}
throw err
}
async function run(c, h) {
const resolver = require('../../lib/resolve')
const util = require('../../lib/util')
context = c
heroku = h
app = context.app
name = context.args.addon
plan = context.args.plan
// called with just one argument in the form of `heroku addons:upgrade heroku-redis:hobby`
if (!plan && name.includes(':')) {
let s = name.split(':')
name = s[0]
plan = s[1]
}
if (!plan) noPlanError()
// ignore the service part of the plan since we can infer the service based on the add-on
if (plan.includes(':')) plan = plan.split(':')[1]
// find the add-on to be changed
addon = await resolver.addon(h, app, name).catch(error => handleAPIError(error))
service = addon.addon_service.name
app = addon.app.name
plan = `${service}:${plan}`
await cli.action(`Changing ${cli.color.magenta(addon.name)} on ${cli.color.cyan(app)} from ${cli.color.blue(addon.plan.name)} to ${cli.color.blue(plan)}`, {success: false}, (async function () {
addon = await heroku.request({
path: `/apps/${app}/addons/${addon.name}`,
method: 'PATCH',
body: {plan: {name: plan}},
headers: {
'Accept-Expansion': 'plan',
'X-Heroku-Legacy-Provider-Messages': 'true',
},
}).catch(error => handlePlanChangeAPIError(error))
cli.action.done(`done${addon.plan.price ? `, ${util.formatPriceText(addon.plan.price)}` : ''}`)
if (addon.provision_message) cli.log(addon.provision_message)
})())
}
let cmd = {
topic: 'addons',
description: 'change add-on plan',
help: `See available plans with \`heroku addons:plans SERVICE\`.
Note that \`heroku addons:upgrade\` and \`heroku addons:downgrade\` are the same.
Either one can be used to change an add-on plan up or down.
https://devcenter.heroku.com/articles/managing-add-ons`,
examples: [
`Upgrade an add-on by service name:
$ heroku addons:upgrade heroku-redis:premium-2
Upgrade a specific add-on:
$ heroku addons:upgrade swimming-briskly-123 heroku-redis:premium-2`,
],
needsAuth: true,
wantsApp: true,
args: [{name: 'addon'}, {name: 'plan', optional: true}],
run: cli.command({preauth: true}, run),
}
module.exports = [
Object.assign({command: 'upgrade'}, cmd),
Object.assign({command: 'downgrade'}, cmd),
]