Skip to content

Commit

Permalink
Merge branch 'prerelease/9.0.0-alpha' into jw/certs-v5/migrate-genera…
Browse files Browse the repository at this point in the history
…te-command
  • Loading branch information
justinwilaby authored Mar 14, 2024
2 parents 4e638d7 + 0911dc2 commit 8a2a416
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 267 deletions.
25 changes: 25 additions & 0 deletions packages/cli/src/commands/apps/leave.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import color from '@heroku-cli/color'
import {Command, flags} from '@heroku-cli/command'
import {ux} from '@oclif/core'
import * as Heroku from '@heroku-cli/schema'

export default class Leave extends Command {
static topic = 'apps'
static aliases = ['leave'];
static description = 'remove yourself from a team app'
static example = 'heroku apps:leave -a APP'
static flags = {
app: flags.app({required: true}),
remote: flags.remote(),
}

public async run(): Promise<void> {
const {flags} = await this.parse(Leave)
const {app} = flags
const request = await this.heroku.get<Heroku.Account>('/account')
ux.action.start(`Leaving ${color.cyan(app)}`)
const {body: account} = request
await this.heroku.delete(`/apps/${app}/collaborators/${encodeURIComponent(account.email as string)}`)
ux.action.stop()
}
}
9 changes: 7 additions & 2 deletions packages/cli/test/acceptance/smoke.acceptance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,16 @@ describe('@acceptance smoke tests', () => {
expect(cmd.stdout).to.contain('@oclif/plugin-which')
})

// this test will fail when run locally depending on which plugins you have installed
it('heroku commands', async () => {
const removeSpaces = (str: string) => str.replace(/ /g, '')
const {stdout} = await run('commands')
expect(stripAnsi(removeSpaces(stdout))).to.equal(stripAnsi(removeSpaces(commandsOutput)))
const commandsByline = stdout.split('\n')
const commandsOutputByLine = commandsOutput.split('\n')
const commandOutputSet = new Set(commandsByline.map((line:string) => stripAnsi(removeSpaces(line))))
commandsOutputByLine.forEach((line: string) => {
const strippedLine = stripAnsi(removeSpaces(line))
expect(commandOutputSet.has(strippedLine), `'${strippedLine}' was expected but wasn't found`).to.be.true
})
})

it('asserts monorepo plugins are in core', async () => {
Expand Down
82 changes: 82 additions & 0 deletions packages/cli/test/unit/commands/apps/leave.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import {stdout, stderr} from 'stdout-stderr'
import Cmd from '../../../../src/commands/apps/leave'
import runCommand from '../../../helpers/runCommand'
import * as nock from 'nock'
import {expect} from '@oclif/test'

function mockUserAccount(email = 'raulb@heroku.com') {
return nock('https://api.heroku.com:443')
.get('/account')
.reply(200, {email})
}

function mockCollaboratorsPersonalApp(app: string, email: string) {
return nock('https://api.heroku.com:443', {})
.delete(`/apps/${app}/collaborators/${encodeURIComponent(email)}`)
.reply(200, {})
}

function mockCollaboratorsPersonalAppDeleteFailure(app: string, email: string) {
return nock('https://api.heroku.com:443', {})
.delete(`/apps/${app}/collaborators/${encodeURIComponent(email)}`).reply(404, {})
}

describe('heroku apps:leave', () => {
let apiGetUserAccount: ReturnType<typeof mockUserAccount>
let apiDeletePersonalAppCollaborator: ReturnType<typeof mockCollaboratorsPersonalApp>

beforeEach(() => {
apiGetUserAccount = mockUserAccount()
apiDeletePersonalAppCollaborator = mockCollaboratorsPersonalApp('myapp', 'raulb@heroku.com')
})

afterEach(() => nock.cleanAll())

context('when it is an org app', () => {
it('leaves the app', async () => {
await runCommand(Cmd, [
'--app',
'myapp',
])
expect('').to.eq(stdout.output)
expect(stderr.output).to.eq('Leaving myapp...\nLeaving myapp... done\n')
apiGetUserAccount.done()
apiDeletePersonalAppCollaborator.done()
})
})

context('when it is not an org app', () => {
it('leaves the app', async () => {
await runCommand(Cmd, [
'--app',
'myapp',
])
expect('').to.eq(stdout.output)
expect(stderr.output).to.eq('Leaving myapp...\nLeaving myapp... done\n')
apiGetUserAccount.done()
apiDeletePersonalAppCollaborator.done()
})
})

describe('when the user tries to leave the app', () => {
before(() => {
apiGetUserAccount = mockUserAccount()
apiDeletePersonalAppCollaborator = mockCollaboratorsPersonalAppDeleteFailure('myapp', 'raulb@heroku.com')
})

after(() => nock.cleanAll())

it('shows an error if the heroku.delete() operation returns an error', async () => {
try {
await runCommand(Cmd, [
'--app',
'myapp',
])
apiGetUserAccount.done()
apiDeletePersonalAppCollaborator.done()
} catch (error) {
expect(error).to.be.an.instanceof(Error)
}
})
})
})
26 changes: 0 additions & 26 deletions packages/orgs-v5/commands/apps/leave.js

This file was deleted.

1 change: 0 additions & 1 deletion packages/orgs-v5/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ exports.topics = [
]

exports.commands = flatten([
require('./commands/apps/leave'),
require('./commands/apps/lock'),
require('./commands/apps/transfer'),
require('./commands/apps/unlock'),
Expand Down
59 changes: 0 additions & 59 deletions packages/orgs-v5/test/unit/commands/apps/leave.unit.test.js

This file was deleted.

40 changes: 0 additions & 40 deletions packages/orgs-v5/test/unit/stub/delete.js

This file was deleted.

Loading

0 comments on commit 8a2a416

Please sign in to comment.