Skip to content

Commit

Permalink
feat(pg:upgrade): support essential dbs (#2637)
Browse files Browse the repository at this point in the history
* Proof-of-concept on changes to support essential pg:upgrade

This code is still a work-in-progress but I am just trying to get an
idea of what changes would be required in the CLI for us to support
pg:upgrade on the essential tier.

* WIP update tests

* WIP update tests waiting on feedback

Waiting for feedback before finalizaing updated tests

* Update tests

* Update copy

* Update smoke tests

* WIP fix smoke tests

* Update api call from PR feedback

* Add comment for custom stripAnsi function

---------

Co-authored-by: Zane Whitfield <zwhitfield@salesforce.com>
  • Loading branch information
binarycleric and zwhitfield3 committed Mar 1, 2024
1 parent bffd998 commit c062c59
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 30 deletions.
2 changes: 1 addition & 1 deletion packages/cli/test/acceptance/commands-output.ts
Expand Up @@ -208,7 +208,7 @@ export default `\u001B[1m Command Summary
pg:settings:log-statement log_statement controls which SQL statements are logged.
pg:settings:track-functions track_functions controls tracking of function call counts and time used. Default is none.
pg:unfollow stop a replica from following and make it a writeable database
pg:upgrade unfollow a database and upgrade it to the latest stable PostgreSQL version
pg:upgrade For an Essential-* plan, this command upgrades the database to the latest stable PostgreSQL version. For a Standard-tier and higher plan, this command unfollows the parent database before upgrading to the latest stable PostgreSQL version.
pg:vacuum-stats show dead rows and whether an automatic vacuum is expected to be triggered
pg:wait blocks until database is available
pipelines list pipelines you have access to
Expand Down
11 changes: 10 additions & 1 deletion packages/cli/test/acceptance/smoke.acceptance.test.ts
Expand Up @@ -7,6 +7,15 @@ import * as qq from 'qqjs'

import commandsOutput from './commands-output'

// this is a custom function that strips both ansi characters and several additional characters
const stripAnsi = (input: string) => {
// eslint-disable-next-line no-control-regex, unicorn/escape-case
const ansiRegex = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\s|─/g
const cleanedString = input.replace(ansiRegex, '')

return cleanedString
}

const globby = require('globby')

const app = 'heroku-cli-ci-smoke-test-app'
Expand Down Expand Up @@ -193,7 +202,7 @@ describe('@acceptance smoke tests', () => {
// this test will fail when run locally depending on which plugins you have installed
it('heroku commands', async () => {
const {stdout} = await run('commands')
expect(stdout).to.equal(commandsOutput)
expect(stripAnsi(stdout)).to.equal(stripAnsi(commandsOutput))
})

it('asserts monorepo plugins are in core', async () => {
Expand Down
28 changes: 13 additions & 15 deletions packages/pg-v5/commands/upgrade.js
Expand Up @@ -9,25 +9,23 @@ async function run(context, heroku) {
let {app, args, flags} = context
let db = await fetcher.addon(app, args.database)

if (util.essentialPlan(db)) throw new Error('pg:upgrade is only available for follower databases on at least the Standard tier.')
if (util.legacyEssentialPlan(db)) throw new Error('pg:upgrade is only available for Essential-* databases and follower databases on Standard-tier and higher plans.')

let [replica, status] = await Promise.all([
heroku.get(`/client/v11/databases/${db.id}`, {host: host(db)}),
heroku.get(`/client/v11/databases/${db.id}/upgrade_status`, {host: host(db)}),
])
const replica = await heroku.get(`/client/v11/databases/${db.id}`, {host: host(db)})

if (status.error) throw new Error(status.error)
if (replica.following) {
let origin = util.databaseNameFromUrl(replica.following, await heroku.get(`/apps/${app}/config-vars`))

if (!replica.following) {
throw new Error('pg:upgrade is only available for follower databases on at least the Standard tier.')
}

let origin = util.databaseNameFromUrl(replica.following, await heroku.get(`/apps/${app}/config-vars`))
await cli.confirmApp(app, flags.confirm, `WARNING: Destructive action
${cli.color.addon(db.name)} will be upgraded to a newer PostgreSQL version, stop following ${origin}, and become writable.
await cli.confirmApp(app, flags.confirm, `WARNING: Destructive action
${cli.color.addon(db.name)} will be upgraded to a newer PostgreSQL version, stop following ${origin}, and become writable.
This cannot be undone.`)
} else {
await cli.confirmApp(app, flags.confirm, `WARNING: Destructive action
${cli.color.addon(db.name)} will be upgraded to a newer PostgreSQL version.
This cannot be undone.`)
This cannot be undone.`)
}

let data = {version: flags.version}

Expand All @@ -40,7 +38,7 @@ This cannot be undone.`)
module.exports = {
topic: 'pg',
command: 'upgrade',
description: 'unfollow a database and upgrade it to the latest stable PostgreSQL version',
description: 'For an Essential-* plan, this command upgrades the database to the latest stable PostgreSQL version. For a Standard-tier and higher plan, this command unfollows the parent database before upgrading to the latest stable PostgreSQL version.',
help: 'to upgrade to another PostgreSQL version, use pg:copy instead',
needsApp: true,
needsAuth: true,
Expand Down
16 changes: 3 additions & 13 deletions packages/pg-v5/test/unit/commands/upgrade.unit.test.js
Expand Up @@ -39,25 +39,16 @@ describe('pg:upgrade', () => {
pg.done()
})

it('refuses to upgrade essential dbs', () => {
addon.plan = {name: 'heroku-postgresql:hobby-dev'}
it('refuses to upgrade legacy essential dbs', () => {
addon.plan = {name: 'heroku-postgresql:basic'}

return expect(cmd.run({app: 'myapp', args: {}, flags: {confirm: 'myapp'}}))
.to.be.rejectedWith(Error, 'pg:upgrade is only available for follower databases on at least the Standard tier.')
})

it('refuses to upgrade non-follower dbs', () => {
pg.get('/client/v11/databases/1').reply(200, {forked_from: 'postgres://db1'})
pg.get('/client/v11/databases/1/upgrade_status').reply(200, {})

return expect(cmd.run({app: 'myapp', args: {}, flags: {confirm: 'myapp'}}))
.to.be.rejectedWith(Error, 'pg:upgrade is only available for follower databases on at least the Standard tier.')
.to.be.rejectedWith(Error, 'pg:upgrade is only available for Essential-* databases and follower databases on Standard-tier and higher plans.')
})

it('upgrades db', () => {
api.get('/apps/myapp/config-vars').reply(200, {DATABASE_URL: 'postgres://db1'})
pg.get('/client/v11/databases/1').reply(200, {following: 'postgres://db1'})
pg.get('/client/v11/databases/1/upgrade_status').reply(200, {})
pg.post('/client/v11/databases/1/upgrade').reply(200)
return cmd.run({app: 'myapp', args: {}, flags: {confirm: 'myapp'}})
.then(() => expect(cli.stderr).to.equal('Starting upgrade of postgres-1... heroku pg:wait to track status\n'))
Expand All @@ -66,7 +57,6 @@ describe('pg:upgrade', () => {
it('upgrades db with version flag', () => {
api.get('/apps/myapp/config-vars').reply(200, {DATABASE_URL: 'postgres://db1'})
pg.get('/client/v11/databases/1').reply(200, {following: 'postgres://db1'})
pg.get('/client/v11/databases/1/upgrade_status').reply(200, {})
pg.post('/client/v11/databases/1/upgrade').reply(200)
return cmd.run({app: 'myapp', args: {}, flags: {confirm: 'myapp', version: '9.6'}})
.then(() => expect(cli.stderr).to.equal('Starting upgrade of postgres-1... heroku pg:wait to track status\n'))
Expand Down

0 comments on commit c062c59

Please sign in to comment.