Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docs/ps.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ FLAGS
-a, --app=<value> (required) [env: HEROKU_APP] app to run command against
-r, --remote=<value> git remote of app to use
--json display as json
--no-wrap disable wrapped table cells for easier copy/paste

GLOBAL FLAGS
--prompt interactively prompt for command arguments and flags
Expand Down
54 changes: 24 additions & 30 deletions src/commands/ps/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {AccountQuota} from '../../lib/types/account-quota.js'
import {AppProcessTier} from '../../lib/types/app-process-tier.js'
import {DynoExtended} from '../../lib/types/dyno-extended.js'
import {Account} from '../../lib/types/fir.js'
import {huxTableNoWrapOptions} from '../../lib/utils/table-utils.js'

const heredoc = tsheredoc.default

Expand All @@ -29,7 +28,6 @@ export default class Index extends Command {
app: flags.app({required: true}),
extended: flags.boolean({char: 'x', hidden: true}), // only works with sudo privileges
json: flags.boolean({description: 'display as json'}),
'no-wrap': flags.noWrap(),
remote: flags.remote(),
}
static strict = false
Expand Down Expand Up @@ -77,7 +75,7 @@ export default class Index extends Command {
if (json)
hux.styledJSON(selectedDynos)
else if (extended)
printExtended(selectedDynos, flags['no-wrap'])
printExtended(selectedDynos)
else {
await printAccountQuota(this.heroku, appInfo, accountInfo)
if (selectedDynos.length === 0)
Expand Down Expand Up @@ -205,35 +203,31 @@ function printDynos(dynos: DynoExtended[]) : void {
}
}

function printExtended(dynos: DynoExtended[], noWrap = false) {
function printExtended(dynos: DynoExtended[]) {
const sortedDynos = dynos.sort(byProcessTypeAndNumber)

/* eslint-disable perfectionist/sort-objects */
hux.table<DynoExtended>(
sortedDynos,
{
ID: {get: (dyno: DynoExtended) => dyno.id},
Process: {get: (dyno: DynoExtended) => dyno.name},
State: {get: (dyno: DynoExtended) => `${dyno.state} ${ago(new Date(dyno.updated_at))}`},
Region: {get: (dyno: DynoExtended) => dyno.extended?.region ?? ''},
'Execution Plane': {get: (dyno: DynoExtended) => dyno.extended?.execution_plane ?? ''},
Fleet: {get: (dyno: DynoExtended) => dyno.extended?.fleet ?? ''},
Instance: {get: (dyno: DynoExtended) => dyno.extended?.instance ?? ''},
IP: {get: (dyno: DynoExtended) => dyno.extended?.ip ?? ''},
Port: {get: (dyno: DynoExtended) => dyno.extended?.port?.toString() ?? ''},
AZ: {get: (dyno: DynoExtended) => dyno.extended?.az ?? ''},
Release: {get: (dyno: DynoExtended) => dyno.release.version},
Command: {get: (dyno: DynoExtended) => truncate(dyno.command)},
Route: {get: (dyno: DynoExtended) => dyno.extended?.route ?? ''},
Size: {get: (dyno: DynoExtended) => dyno.size},
},
huxTableNoWrapOptions(noWrap),
)
/* eslint-enable perfectionist/sort-objects */
}

function truncate(s: string) {
return s.length > 35 ? `${s.slice(0, 34)}…` : s
for (const dyno of sortedDynos) {
const ext = dyno.extended ?? {}

hux.styledHeader(`${color.label(dyno.name)} (${color.info(dyno.size)})`)
/* eslint-disable perfectionist/sort-objects */
hux.styledObject({
ID: dyno.id,
State: `${dyno.state} ${ago(new Date(dyno.updated_at))}`,
Release: dyno.release.version,
Command: dyno.command,
Region: ext.region,
'Execution Plane': ext.execution_plane,
Fleet: ext.fleet,
Instance: ext.instance,
IP: ext.ip,
Port: ext.port,
AZ: ext.az,
Route: ext.route,
})
/* eslint-enable perfectionist/sort-objects */
ux.stdout()
}
}

function uniqueValues(value: string, index: number, self: string[]) : boolean {
Expand Down
118 changes: 69 additions & 49 deletions test/unit/commands/ps/index.unit.test.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import {runCommand} from '@heroku-cli/test-utils'
import {hux} from '@heroku/heroku-cli-util'
import ansis from 'ansis'
import {expect} from 'chai'
import nock from 'nock'
import {restore, stub} from 'sinon'
import {restore} from 'sinon'
import strftime from 'strftime'
import tsheredoc from 'tsheredoc'

Expand Down Expand Up @@ -269,50 +268,37 @@ describe('ps', function () {
api.done()

expect(normalizeTableOutput(stdout)).to.equal(normalizeTableOutput(`
Id Process State Region Execution plane Fleet Instance Ip Port Az Release Command Route Size
─── ─────── ─────────────────────────────────────── ────── ─────────────── ───── ──────── ──────── ──── ─────── ─────── ───────── ──────── ────
101 run.1 up ${hourAgoStr} (~ 1h ago) us execution_plane fleet instance 10.0.0.2 8000 us-east 40 bash da route Eco
100 web.1 up ${hourAgoStr} (~ 1h ago) us execution_plane fleet instance 10.0.0.1 8000 us-east 40 npm start da route Eco
=== run.1 (Eco)
ID: 101
State: up ${hourAgoStr} (~ 1h ago)
Release: 40
Command: bash
Region: us
Execution Plane: execution_plane
Fleet: fleet
Instance: instance
IP: 10.0.0.2
Port: 8000
AZ: us-east
Route: da route
=== web.1 (Eco)
ID: 100
State: up ${hourAgoStr} (~ 1h ago)
Release: 40
Command: npm start
Region: us
Execution Plane: execution_plane
Fleet: fleet
Instance: instance
IP: 10.0.0.1
Port: 8000
AZ: us-east
Route: da route
`))

expect(stderr).to.equal('')
})

it('passes no-wrap option through to extended table rendering', async function () {
nock('https://api.heroku.com', {reqheaders: {accept: 'application/vnd.heroku+json; version=3.sdk'}})
.get('/account')
.reply(200, {id: '1234'})
.get('/apps/myapp')
.reply(200, {name: 'myapp'})
.get('/apps/myapp/dynos?extended=true')
.reply(200, [{
command: 'npm start',
extended: {
az: 'us-east',
execution_plane: 'execution_plane',
fleet: 'fleet',
instance: 'instance',
ip: '10.0.0.1',
port: 8000,
region: 'us',
route: 'da route',
},
id: '100',
name: 'web.1',
release: {id: '10', version: '40'},
size: 'Eco',
state: 'up',
type: 'web',
updated_at: hourAgo,
}])

const tableStub = stub(hux, 'table')
await runCommand(Cmd, ['--app', 'myapp', '--extended', '--no-wrap'])

const callArgs = tableStub.firstCall.args
expect(callArgs[2]).to.include({maxWidth: 'none', overflow: 'truncate'})
})

it('shows extended info for Private Space app', async function () {
const api = nock('https://api.heroku.com', {reqheaders: {accept: 'application/vnd.heroku+json; version=3.sdk'}})
.get('/account')
Expand Down Expand Up @@ -369,10 +355,22 @@ describe('ps', function () {
api.done()

expect(normalizeTableOutput(stdout)).to.equal(normalizeTableOutput(`
Id Process State Region Execution plane Fleet Instance Ip Port Az Release Command Route Size
─── ─────── ─────────────────────────────────────── ────── ─────────────── ───── ──────── ──────── ──── ── ─────── ───────── ───── ────
101 run.1 up ${hourAgoStr} (~ 1h ago) us instance 10.0.0.1 40 bash Eco
100 web.1 up ${hourAgoStr} (~ 1h ago) us instance 10.0.0.1 40 npm start Eco
=== run.1 (Eco)
ID: 101
State: up ${hourAgoStr} (~ 1h ago)
Release: 40
Command: bash
Region: us
Instance: instance
IP: 10.0.0.1
=== web.1 (Eco)
ID: 100
State: up ${hourAgoStr} (~ 1h ago)
Release: 40
Command: npm start
Region: us
Instance: instance
IP: 10.0.0.1
`))
expect(stderr).to.equal('')
})
Expand Down Expand Up @@ -419,10 +417,32 @@ describe('ps', function () {
api.done()

expect(normalizeTableOutput(stdout)).to.equal(normalizeTableOutput(`
Id Process State Region Execution plane Fleet Instance Ip Port Az Release Command Route Size
─── ─────── ─────────────────────────────────────── ────── ─────────────── ───── ──────── ──────── ──── ─────── ─────── ───────── ──────── ────────
101 run.1 up ${hourAgoStr} (~ 1h ago) us execution_plane fleet instance 10.0.0.2 8000 us-east 40 bash da route Shield-L
100 web.1 up ${hourAgoStr} (~ 1h ago) us execution_plane fleet instance 10.0.0.1 8000 us-east 40 npm start da route Shield-M
=== run.1 (Shield-L)
ID: 101
State: up ${hourAgoStr} (~ 1h ago)
Release: 40
Command: bash
Region: us
Execution Plane: execution_plane
Fleet: fleet
Instance: instance
IP: 10.0.0.2
Port: 8000
AZ: us-east
Route: da route
=== web.1 (Shield-M)
ID: 100
State: up ${hourAgoStr} (~ 1h ago)
Release: 40
Command: npm start
Region: us
Execution Plane: execution_plane
Fleet: fleet
Instance: instance
IP: 10.0.0.1
Port: 8000
AZ: us-east
Route: da route
`))
expect(stderr).to.equal('')
})
Expand Down
Loading