Skip to content

Commit

Permalink
Merge pull request #123 from OldSneerJaw/local-timezone
Browse files Browse the repository at this point in the history
Local timezone in command output
  • Loading branch information
OldSneerJaw authored Mar 15, 2023
2 parents 782cf55 + f98e254 commit 5dd3977
Show file tree
Hide file tree
Showing 7 changed files with 39 additions and 28 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# Change Log
This project adheres to [Semantic Versioning](http://semver.org/). All notable changes will be documented in this file.

## [Unreleased](https://github.com/OldSneerJaw/borealis-pg-cli/compare/v1.4.0...HEAD)
- Shows times in the user's local time zone

## [1.4.0](https://github.com/OldSneerJaw/borealis-pg-cli/compare/v1.3.0...v1.4.0)
- Adds the `borealis-pg:restore:capabilities` command to retrieve an add-on's database restore capabilities
- Adds the `borealis-pg:restore:execute` command to perform an add-on database restore/clone
Expand Down
21 changes: 11 additions & 10 deletions src/commands/borealis-pg/info.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {DateTime} from 'luxon'
import {borealisPgApiBaseUrl, expect, herokuApiBaseUrl, test} from '../../test-utils'

const fakeAddonId = '330ab3c7-faf5-4da7-98ed-d1eac0983372'
Expand All @@ -10,7 +11,7 @@ const fakeHerokuAppId = 'fdedc223-6782-40c1-8431-0a65348732f5'
const fakeHerokuAppName = 'my-super-neat-fake-app'

const fakeAppDbName = 'my-super-neat-fake-app-db'
const fakeCreatedAt = '2022-06-30T23:52:14.019+00:00'
const fakeCreatedAt = '2022-06-30T23:52:14.019Z'
const fakePlanName = 'my-super-neat-fake-plan'
const fakePostgresVersion = '14.4'
const fakeStorageComplianceDeadline = '2022-07-08T18:40:38.193-07:00'
Expand Down Expand Up @@ -87,7 +88,7 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 2')
expect(ctx.stdout).to.containIgnoreSpaces(`App DB Name: ${fakeAppDbName}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces('Restored/Cloned From Add-on: N/A')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: OK')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Deadline: N/A')
Expand Down Expand Up @@ -129,7 +130,7 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 0')
expect(ctx.stdout).to.containIgnoreSpaces(`App DB Name: ${fakeAppDbName}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces('Restored/Cloned From Add-on: N/A')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: Proximity Warning')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Deadline: N/A')
Expand Down Expand Up @@ -171,7 +172,7 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 0')
expect(ctx.stdout).to.containIgnoreSpaces(`App DB Name: ${fakeAppDbName}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces('Restored/Cloned From Add-on: N/A')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: OK')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Deadline: N/A')
Expand Down Expand Up @@ -213,7 +214,7 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 1')
expect(ctx.stdout).to.containIgnoreSpaces(`App DB Name: ${fakeAppDbName}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Restored/Cloned From Add-on: ${fakeRestoreSourceAddonName}`)
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: OK')
Expand Down Expand Up @@ -256,7 +257,7 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 1')
expect(ctx.stdout).to.containIgnoreSpaces(`App DB Name: ${fakeAppDbName}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces('Restored/Cloned From Add-on: N/A')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: super-duper')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Deadline: N/A')
Expand Down Expand Up @@ -298,7 +299,7 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 2')
expect(ctx.stdout).to.containIgnoreSpaces('App DB Name: (pending)')
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces('Restored/Cloned From Add-on: N/A')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: OK')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Deadline: N/A')
Expand Down Expand Up @@ -340,11 +341,11 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 0')
expect(ctx.stdout).to.containIgnoreSpaces(`App DB Name: ${fakeAppDbName}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces('Restored/Cloned From Add-on: N/A')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: Violating')
expect(ctx.stdout).to.containIgnoreSpaces(
`Storage Compliance Deadline: ${new Date(fakeStorageComplianceDeadline).toISOString()}`)
`Storage Compliance Deadline: ${DateTime.fromISO(fakeStorageComplianceDeadline).toISO()}`)
})

defaultTestContext
Expand Down Expand Up @@ -383,7 +384,7 @@ describe('add-on info command', () => {
expect(ctx.stdout).to.containIgnoreSpaces('Read-only Replicas: 0')
expect(ctx.stdout).to.containIgnoreSpaces(`App DB Name: ${fakeAppDbName}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Created At: ${new Date(fakeCreatedAt).toISOString()}`)
`Created At: ${DateTime.fromISO(fakeCreatedAt).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces('Restored/Cloned From Add-on: N/A')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Status: Restricted')
expect(ctx.stdout).to.containIgnoreSpaces('Storage Compliance Deadline: N/A')
Expand Down
13 changes: 6 additions & 7 deletions src/commands/borealis-pg/info.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import color from '@heroku-cli/color'
import {Command} from '@heroku-cli/command'
import {HTTP, HTTPError} from 'http-call'
import {DateTime} from 'luxon'
import {applyActionSpinner} from '../../async-actions'
import {getBorealisPgApiUrl, getBorealisPgAuthHeader} from '../../borealis-api'
import {
Expand Down Expand Up @@ -85,13 +86,11 @@ export default class AddonInfoCommand extends Command {
const dbTenancyType = dbTenancyTypes[addonInfo.dbTenancyType] ?? addonInfo.dbTenancyType

const addonStatus = addonStatuses[addonInfo.status] ?? addonInfo.status
const storageComplianceStatus =
storageComplianceStatuses[addonInfo.storageComplianceStatus] ??
const storageComplianceStatus = storageComplianceStatuses[addonInfo.storageComplianceStatus] ??
addonInfo.storageComplianceStatus
const storageComplianceDeadline =
(addonInfo.storageComplianceDeadline !== null) ?
new Date(addonInfo.storageComplianceDeadline).toISOString() :
'N/A'
const storageComplianceDeadline = addonInfo.storageComplianceDeadline ?
DateTime.fromISO(addonInfo.storageComplianceDeadline).toISO() :
'N/A'

const dbStorageMaxGib = addonInfo.dbStorageMaxBytes / bytesPerGib
const dbStorageMaxFractionDigits = (dbStorageMaxGib < 1) ? 2 : 0
Expand All @@ -103,7 +102,7 @@ export default class AddonInfoCommand extends Command {

const appDbName = addonInfo.appDbName ?? '(pending)'

const createdAt = new Date(addonInfo.createdAt).toISOString()
const createdAt = DateTime.fromISO(addonInfo.createdAt).toISO()

const restoreSourceAddonName = addonInfo.restoreSourceAddonName ?? 'N/A'

Expand Down
5 changes: 3 additions & 2 deletions src/commands/borealis-pg/integrations/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {DateTime} from 'luxon'
import {borealisPgApiBaseUrl, expect, herokuApiBaseUrl, test} from '../../../test-utils'

const fakeAddonId = '0818035e-0103-4f85-880d-c3b4a712cf8d'
Expand Down Expand Up @@ -86,8 +87,8 @@ describe('data integration list command', () => {
expect(ctx.stdout).to.containIgnoreSpaces(
' Data Integration DB Username SSH Username Write Access Created At')
expect(ctx.stdout).to.containIgnoreSpaces(
` ${fakeIntegration1Name} ${fakeIntegration1DbUsername} ${fakeIntegration1SshUsername} ${fakeIntegration1WriteAccess} ${fakeIntegration1CreatedAt} \n` +
` ${fakeIntegration2Name} ${fakeIntegration2DbUsername} ${fakeIntegration2SshUsername} ${fakeIntegration2WriteAccess} ${fakeIntegration2CreatedAt}`)
` ${fakeIntegration1Name} ${fakeIntegration1DbUsername} ${fakeIntegration1SshUsername} ${fakeIntegration1WriteAccess} ${DateTime.fromISO(fakeIntegration1CreatedAt).toISO()}\n` +
` ${fakeIntegration2Name} ${fakeIntegration2DbUsername} ${fakeIntegration2SshUsername} ${fakeIntegration2WriteAccess} ${DateTime.fromISO(fakeIntegration2CreatedAt).toISO()}`)
})

defaultTestContext
Expand Down
3 changes: 2 additions & 1 deletion src/commands/borealis-pg/integrations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import color from '@heroku-cli/color'
import {Command} from '@heroku-cli/command'
import {CliUx} from '@oclif/core'
import {HTTP, HTTPError} from 'http-call'
import {DateTime} from 'luxon'
import {applyActionSpinner} from '../../../async-actions'
import {getBorealisPgApiUrl, getBorealisPgAuthHeader} from '../../../borealis-api'
import {
Expand Down Expand Up @@ -52,7 +53,7 @@ via a secure tunnel using semi-permanent SSH server and database credentials.`
dbUsername: value.dbUsername,
sshUsername: value.sshUsername,
writeAccess: value.writeAccess,
createdAt: new Date(value.createdAt),
createdAt: DateTime.fromISO(value.createdAt).toISO(),
}
})

Expand Down
13 changes: 7 additions & 6 deletions src/commands/borealis-pg/restore/capabilities.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {DateTime} from 'luxon'
import {borealisPgApiBaseUrl, expect, herokuApiBaseUrl, test} from '../../../test-utils'

const fakeAddonId = '330ab3c7-faf5-4da7-98ed-d1eac0983372'
Expand All @@ -12,8 +13,8 @@ const fakeHerokuAppName = 'my-super-neat-fake-app'
const fakeHerokuAuthToken = 'my-fake-heroku-auth-token'
const fakeHerokuAuthId = 'my-fake-heroku-auth'

const fakeEarliestRestorableTime = '2023-02-21T03:15:28.675-08:00'
const fakeLatestRestorableTime = '2023-02-24T11:04:46.081-08:00'
const fakeEarliestRestorableTime = '2023-02-21T03:15:28.675+01:00'
const fakeLatestRestorableTime = '2023-02-24T11:04:46.081-04:00'

const defaultTestContext = test.stdout()
.stderr()
Expand Down Expand Up @@ -62,9 +63,9 @@ describe('database restore capabilities command', () => {
.it('displays restore capabilities of a single tenant add-on', ctx => {
expect(ctx.stdout).to.containIgnoreSpaces('Restore/Clone Supported: Yes')
expect(ctx.stdout).to.containIgnoreSpaces(
`Earliest Restorable Time: ${fakeEarliestRestorableTime}`)
`Earliest Restorable Time: ${DateTime.fromISO(fakeEarliestRestorableTime).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Latest Restorable Time: ${fakeLatestRestorableTime}`)
`Latest Restorable Time: ${DateTime.fromISO(fakeLatestRestorableTime).toISO()}`)
})

defaultTestContext
Expand Down Expand Up @@ -98,9 +99,9 @@ describe('database restore capabilities command', () => {
.it('displays restore capabilities via the borealis-pg:restore:info alias', ctx => {
expect(ctx.stdout).to.containIgnoreSpaces('Restore/Clone Supported: Yes')
expect(ctx.stdout).to.containIgnoreSpaces(
`Earliest Restorable Time: ${fakeEarliestRestorableTime}`)
`Earliest Restorable Time: ${DateTime.fromISO(fakeEarliestRestorableTime).toISO()}`)
expect(ctx.stdout).to.containIgnoreSpaces(
`Latest Restorable Time: ${fakeLatestRestorableTime}`)
`Latest Restorable Time: ${DateTime.fromISO(fakeLatestRestorableTime).toISO()}`)
})

defaultTestContext
Expand Down
9 changes: 7 additions & 2 deletions src/commands/borealis-pg/restore/capabilities.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import color from '@heroku-cli/color'
import {Command} from '@heroku-cli/command'
import {HTTP, HTTPError} from 'http-call'
import {DateTime} from 'luxon'
import {applyActionSpinner} from '../../../async-actions'
import {getBorealisPgApiUrl, getBorealisPgAuthHeader} from '../../../borealis-api'
import {
Expand Down Expand Up @@ -58,8 +59,12 @@ See the ${cliCmdColour('borealis-pg:restore:execute')} command to perform a rest

private async printDbRestoreInfo(dbRestoreInfo: DbRestoreInfo) {
const restoreSupportedDisplay = dbRestoreInfo.restoreSupported ? 'Yes' : 'No'
const earliestRestoreTimeDisplay = dbRestoreInfo.earliestRestorableTime ?? 'N/A'
const latestRestoreTimeDisplay = dbRestoreInfo.latestRestorableTime ?? 'N/A'
const earliestRestoreTimeDisplay = dbRestoreInfo.earliestRestorableTime ?
DateTime.fromISO(dbRestoreInfo.earliestRestorableTime).toISO() :
'N/A'
const latestRestoreTimeDisplay = dbRestoreInfo.latestRestorableTime ?
DateTime.fromISO(dbRestoreInfo.latestRestorableTime).toISO() :
'N/A'

this.log()
this.log(` ${keyColour('Restore/Clone Supported')}: ${valueColour(restoreSupportedDisplay)}`)
Expand Down

0 comments on commit 5dd3977

Please sign in to comment.