From 998e38057ef5770adb6ac6307fa27adbbce98ac0 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Wed, 13 Mar 2024 17:50:08 -0400 Subject: [PATCH 01/20] refactor: initial migration of apps:transfer to oclif/core --- packages/cli/src/commands/apps/transfer.ts | 69 ++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 packages/cli/src/commands/apps/transfer.ts diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts new file mode 100644 index 0000000000..deb31ec9db --- /dev/null +++ b/packages/cli/src/commands/apps/transfer.ts @@ -0,0 +1,69 @@ +import color from '@heroku-cli/color' +import {Command, flags} from '@heroku-cli/command' +import {Args, ux} from '@oclif/core' +import * as Heroku from '@heroku-cli/schema' +import {sortBy} from 'lodash' +import * as inquirer from 'inquirer' +import {getOwner} from '../../lib/access/utils' +import lock from './lock' + +let AppTransfer = require('../../lib/app_transfer') +let lock = require('./lock.js')[0] +function getAppsToTransfer(apps) { + return inquirer.prompt([{ + type: 'checkbox', name: 'choices', pageSize: 20, message: 'Select applications you would like to transfer', choices: apps.map(function (app) { + return { + name: `${app.name} (${getOwner(app.owner.email)})`, value: {name: app.name, owner: app.owner.email}, + } + }), + }]) +} + +export default class AppsTransfer extends Command { + static topic = 'apps'; + static description = 'transfer applications to another user or team'; + static flags = { + locked: flags.boolean({char: 'l', required: false, description: 'lock the app upon transfer'}), + bulk: flags.boolean({required: false, description: 'transfer applications in bulk'}), + app: flags.app(), + remote: flags.remote({char: 'r'}), + }; + + static args = { + recipient: Args.string({description: 'user or team to transfer applications to', required: true}), + }; + + public async run(): Promise { + const {flags, argv, args} = await this.parse(AppsTransfer) + const {app, bulk, locked} = flags + let recipient = args.recipient + if (bulk) { + let allApps = await this.heroku.get('/apps') + let selectedApps = await getAppsToTransfer(sortBy(allApps, 'name')) + console.error(`Transferring applications to ${color.magenta(recipient)}...\n`) + for (let app of selectedApps.choices) { + try { + let appTransfer = new AppTransfer({ + heroku: heroku, appName: app.name, recipient: recipient, personalToPersonal: Utils.isValidEmail(recipient) && !Utils.isteamApp(app.owner), bulk: true, + }) + await appTransfer.start() + } catch (error) { + ux.error(error) + } + } + } else { + let appInfo = await this.heroku.get(`/apps/${app}`) + if (Utils.isValidEmail(recipient) && Utils.isteamApp(appInfo.owner.email)) { + await cli.confirmApp(app, confirm, 'All collaborators will be removed from this app') + } + + let appTransfer = new AppTransfer({ + heroku: heroku, appName: appInfo.name, recipient: recipient, personalToPersonal: Utils.isValidEmail(recipient) && !Utils.isteamApp(appInfo.owner.email), + }) + await appTransfer.start() + if (locked) { + await lock.run(context) + } + } + } +} From f2621483c49c5b15e9a961c7bea8365469332919 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Fri, 15 Mar 2024 09:34:44 -0400 Subject: [PATCH 02/20] refactor: move access utils since they are used by apps command --- packages/cli/src/commands/access/add.ts | 2 +- packages/cli/src/commands/access/index.ts | 2 +- packages/cli/src/commands/access/update.ts | 2 +- packages/cli/src/commands/apps/transfer.ts | 35 ++++++++++++------- .../src/lib/{access/utils.ts => teamUtils.ts} | 0 5 files changed, 25 insertions(+), 16 deletions(-) rename packages/cli/src/lib/{access/utils.ts => teamUtils.ts} (100%) diff --git a/packages/cli/src/commands/access/add.ts b/packages/cli/src/commands/access/add.ts index 71c806c7d6..5885d231e7 100644 --- a/packages/cli/src/commands/access/add.ts +++ b/packages/cli/src/commands/access/add.ts @@ -2,7 +2,7 @@ import color from '@heroku-cli/color' import {Command, flags} from '@heroku-cli/command' import {Args, ux} from '@oclif/core' import * as Heroku from '@heroku-cli/schema' -import {isTeamApp, getOwner} from '../../lib/access/utils' +import {isTeamApp, getOwner} from '../../lib/teamUtils' import * as _ from 'lodash' export default class AccessAdd extends Command { static description = 'add new users to your app' diff --git a/packages/cli/src/commands/access/index.ts b/packages/cli/src/commands/access/index.ts index cb7115ee19..3335b52c5d 100644 --- a/packages/cli/src/commands/access/index.ts +++ b/packages/cli/src/commands/access/index.ts @@ -3,7 +3,7 @@ import {Command, flags} from '@heroku-cli/command' import {ux} from '@oclif/core' import * as Heroku from '@heroku-cli/schema' import * as _ from 'lodash' -import {isTeamApp, getOwner} from '../../lib/access/utils' +import {isTeamApp, getOwner} from '../../lib/teamUtils' type MemberData = { email: string, diff --git a/packages/cli/src/commands/access/update.ts b/packages/cli/src/commands/access/update.ts index 6d2f0203ea..a93bce689b 100644 --- a/packages/cli/src/commands/access/update.ts +++ b/packages/cli/src/commands/access/update.ts @@ -2,7 +2,7 @@ import color from '@heroku-cli/color' import {Command, flags} from '@heroku-cli/command' import {Args, ux} from '@oclif/core' import * as Heroku from '@heroku-cli/schema' -import {isTeamApp} from '../../lib/access/utils' +import {isTeamApp} from '../../lib/teamUtils' export default class Update extends Command { static topic = 'access'; diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index deb31ec9db..ab98a7b950 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -4,11 +4,11 @@ import {Args, ux} from '@oclif/core' import * as Heroku from '@heroku-cli/schema' import {sortBy} from 'lodash' import * as inquirer from 'inquirer' -import {getOwner} from '../../lib/access/utils' +import {getOwner, isTeamApp, isValidEmail} from '../../lib/teamUtils' import lock from './lock' -let AppTransfer = require('../../lib/app_transfer') -let lock = require('./lock.js')[0] +const AppTransfer = require('../../lib/app_transfer') + function getAppsToTransfer(apps) { return inquirer.prompt([{ type: 'checkbox', name: 'choices', pageSize: 20, message: 'Select applications you would like to transfer', choices: apps.map(function (app) { @@ -33,18 +33,27 @@ export default class AppsTransfer extends Command { recipient: Args.string({description: 'user or team to transfer applications to', required: true}), }; + static example = `$ heroku apps:transfer collaborator@example.com +Transferring example to collaborator@example.com... done + +$ heroku apps:transfer acme-widgets +Transferring example to acme-widgets... done + +$ heroku apps:transfer --bulk acme-widgets +...` + public async run(): Promise { const {flags, argv, args} = await this.parse(AppsTransfer) const {app, bulk, locked} = flags - let recipient = args.recipient + const recipient = args.recipient if (bulk) { - let allApps = await this.heroku.get('/apps') - let selectedApps = await getAppsToTransfer(sortBy(allApps, 'name')) + const allApps = await this.heroku.get('/apps') + const selectedApps = await getAppsToTransfer(sortBy(allApps, 'name')) console.error(`Transferring applications to ${color.magenta(recipient)}...\n`) - for (let app of selectedApps.choices) { + for (const app of selectedApps.choices) { try { - let appTransfer = new AppTransfer({ - heroku: heroku, appName: app.name, recipient: recipient, personalToPersonal: Utils.isValidEmail(recipient) && !Utils.isteamApp(app.owner), bulk: true, + const appTransfer = new AppTransfer({ + heroku: this.heroku, appName: app.name, recipient: recipient, personalToPersonal: isValidEmail(recipient) && !isTeamApp(app.owner), bulk: true, }) await appTransfer.start() } catch (error) { @@ -52,13 +61,13 @@ export default class AppsTransfer extends Command { } } } else { - let appInfo = await this.heroku.get(`/apps/${app}`) - if (Utils.isValidEmail(recipient) && Utils.isteamApp(appInfo.owner.email)) { + const appInfo = await this.heroku.get(`/apps/${app}`) + if (isValidEmail(recipient) && isTeamApp(appInfo.owner.email)) { await cli.confirmApp(app, confirm, 'All collaborators will be removed from this app') } - let appTransfer = new AppTransfer({ - heroku: heroku, appName: appInfo.name, recipient: recipient, personalToPersonal: Utils.isValidEmail(recipient) && !Utils.isteamApp(appInfo.owner.email), + const appTransfer = new AppTransfer({ + heroku: this.heroku, appName: appInfo.name, recipient: recipient, personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner.email), }) await appTransfer.start() if (locked) { diff --git a/packages/cli/src/lib/access/utils.ts b/packages/cli/src/lib/teamUtils.ts similarity index 100% rename from packages/cli/src/lib/access/utils.ts rename to packages/cli/src/lib/teamUtils.ts From daec2e8f74428d3611ba57b79e70b9b61708a7dd Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Fri, 15 Mar 2024 09:37:41 -0400 Subject: [PATCH 03/20] refactor: add isValidEmail to teamUtils --- packages/cli/src/lib/teamUtils.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/cli/src/lib/teamUtils.ts b/packages/cli/src/lib/teamUtils.ts index 125f3a69c5..2dba380df3 100644 --- a/packages/cli/src/lib/teamUtils.ts +++ b/packages/cli/src/lib/teamUtils.ts @@ -9,3 +9,7 @@ export const getOwner = function (owner: string | undefined) { return owner } + +export const isValidEmail = function (email: string) { + return /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(email) +} From f0c93037a0a4f08a08eb45ffbc2f1f3e3277533c Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Fri, 15 Mar 2024 10:24:23 -0400 Subject: [PATCH 04/20] refactor: migrate AppTransfer lib class --- packages/cli/src/commands/apps/transfer.ts | 9 ++- packages/cli/src/lib/apps/appTransfer.ts | 72 ++++++++++++++++++++++ 2 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 packages/cli/src/lib/apps/appTransfer.ts diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index ab98a7b950..8a64905fee 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -6,8 +6,7 @@ import {sortBy} from 'lodash' import * as inquirer from 'inquirer' import {getOwner, isTeamApp, isValidEmail} from '../../lib/teamUtils' import lock from './lock' - -const AppTransfer = require('../../lib/app_transfer') +import {AppTransfer} from '../../lib/apps/appTransfer' function getAppsToTransfer(apps) { return inquirer.prompt([{ @@ -67,7 +66,11 @@ $ heroku apps:transfer --bulk acme-widgets } const appTransfer = new AppTransfer({ - heroku: this.heroku, appName: appInfo.name, recipient: recipient, personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner.email), + heroku: this.heroku, + appName: appInfo.name, + recipient, + personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner.email), + bulk, }) await appTransfer.start() if (locked) { diff --git a/packages/cli/src/lib/apps/appTransfer.ts b/packages/cli/src/lib/apps/appTransfer.ts new file mode 100644 index 0000000000..2a550ba40a --- /dev/null +++ b/packages/cli/src/lib/apps/appTransfer.ts @@ -0,0 +1,72 @@ +import {APIClient} from '@heroku-cli/command' +import {color} from '@heroku-cli/color' +import * as Heroku from '@heroku-cli/schema' +import {ux} from '@oclif/core' + +type Options = { + heroku: APIClient, + appName: string, + recipient: string, + personalToPersonal: boolean, + bulk: boolean, +} + +export class AppTransfer { + private heroku: APIClient + private appName: string + private recipient: string + private personalToPersonal: boolean + private opts: Options + private body: { app?: string; recipient?: string, owner?: string } + private transferMsg: string + private path: string + private method: string + + /** + * @param {Object} options.heroku - instance of heroku-client + * @param {string} options.appName - application that is being transferred + * @param {string} options.recipient - recipient of the transfer + * @param {boolean} options.personalToPersonal - determines if it is a transfer between individual accounts + * @param {boolean} options.bulk - determines if it is a bulk transfer + * @param {Options} opts + */ + constructor(opts: Options) { + this.opts = opts + this.heroku = this.opts.heroku + this.appName = this.opts.appName + this.recipient = this.opts.recipient + this.personalToPersonal = this.opts.personalToPersonal + + if (this.personalToPersonal === undefined) this.personalToPersonal = true + + if (this.personalToPersonal) { + this.body = {app: this.appName, recipient: this.recipient} + this.transferMsg = `Initiating transfer of ${color.app(this.appName)}` + if (!this.opts.bulk) this.transferMsg += ` to ${color.magenta(this.recipient)}` + this.path = '/account/app-transfers' + this.method = 'POST' + } else { + this.body = {owner: this.recipient} + this.transferMsg = `Transferring ${color.app(this.appName)}` + if (!this.opts.bulk) this.transferMsg += ` to ${color.magenta(this.recipient)}` + this.path = `/teams/apps/${this.appName}` + this.method = 'PATCH' + } + } + + async start() { + ux.action.start(this.transferMsg) + const {body: request} = await this.init() + if (request.state === 'pending') ux.log('email sent') + ux.action.stop() + } + + init() { + return this.heroku.request( + this.path, + { + method: this.method, + body: this.body, + }) + } +} From 6dc469a6ece242d31d4122da6b4d3b3c24ada1d1 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Fri, 15 Mar 2024 11:14:45 -0400 Subject: [PATCH 05/20] refactor: fix types and update getAppsToTransfer --- packages/cli/src/commands/apps/transfer.ts | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index 8a64905fee..61fecbff78 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -8,11 +8,15 @@ import {getOwner, isTeamApp, isValidEmail} from '../../lib/teamUtils' import lock from './lock' import {AppTransfer} from '../../lib/apps/appTransfer' -function getAppsToTransfer(apps) { +function getAppsToTransfer(apps: Heroku.App[]) { return inquirer.prompt([{ - type: 'checkbox', name: 'choices', pageSize: 20, message: 'Select applications you would like to transfer', choices: apps.map(function (app) { + type: 'checkbox', + name: 'choices', + pageSize: 20, + message: 'Select applications you would like to transfer', + choices: apps.map(function (app) { return { - name: `${app.name} (${getOwner(app.owner.email)})`, value: {name: app.name, owner: app.owner.email}, + name: `${app.name} (${getOwner(app.owner?.email)})`, value: {name: app.name, owner: app.owner?.email}, } }), }]) @@ -46,7 +50,7 @@ $ heroku apps:transfer --bulk acme-widgets const {app, bulk, locked} = flags const recipient = args.recipient if (bulk) { - const allApps = await this.heroku.get('/apps') + const {body: allApps} = await this.heroku.get('/apps') const selectedApps = await getAppsToTransfer(sortBy(allApps, 'name')) console.error(`Transferring applications to ${color.magenta(recipient)}...\n`) for (const app of selectedApps.choices) { @@ -60,16 +64,16 @@ $ heroku apps:transfer --bulk acme-widgets } } } else { - const appInfo = await this.heroku.get(`/apps/${app}`) - if (isValidEmail(recipient) && isTeamApp(appInfo.owner.email)) { + const {body: appInfo} = await this.heroku.get(`/apps/${app}`) + if (isValidEmail(recipient) && isTeamApp(appInfo.owner?.email)) { await cli.confirmApp(app, confirm, 'All collaborators will be removed from this app') } const appTransfer = new AppTransfer({ heroku: this.heroku, - appName: appInfo.name, + appName: appInfo.name ?? app ?? '', recipient, - personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner.email), + personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner?.email), bulk, }) await appTransfer.start() From 0209fd554db74c55a5d7d43160ecb5bd0a2fe2f3 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Fri, 15 Mar 2024 14:46:10 -0400 Subject: [PATCH 06/20] refactor: add confirm flag and construct app name --- packages/cli/src/commands/apps/transfer.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index 61fecbff78..550ceda44d 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -7,6 +7,7 @@ import * as inquirer from 'inquirer' import {getOwner, isTeamApp, isValidEmail} from '../../lib/teamUtils' import lock from './lock' import {AppTransfer} from '../../lib/apps/appTransfer' +import confirmApp from '../../lib/apps/confirm-app' function getAppsToTransfer(apps: Heroku.App[]) { return inquirer.prompt([{ @@ -30,6 +31,7 @@ export default class AppsTransfer extends Command { bulk: flags.boolean({required: false, description: 'transfer applications in bulk'}), app: flags.app(), remote: flags.remote({char: 'r'}), + confirm: flags.string({char: 'c', hidden: true}), }; static args = { @@ -46,13 +48,13 @@ $ heroku apps:transfer --bulk acme-widgets ...` public async run(): Promise { - const {flags, argv, args} = await this.parse(AppsTransfer) - const {app, bulk, locked} = flags + const {flags, args} = await this.parse(AppsTransfer) + const {app, bulk, locked, confirm} = flags const recipient = args.recipient if (bulk) { const {body: allApps} = await this.heroku.get('/apps') const selectedApps = await getAppsToTransfer(sortBy(allApps, 'name')) - console.error(`Transferring applications to ${color.magenta(recipient)}...\n`) + ux.warn(`Transferring applications to ${color.magenta(recipient)}...\n`) for (const app of selectedApps.choices) { try { const appTransfer = new AppTransfer({ @@ -65,13 +67,14 @@ $ heroku apps:transfer --bulk acme-widgets } } else { const {body: appInfo} = await this.heroku.get(`/apps/${app}`) + const appName = appInfo.name ?? app ?? '' if (isValidEmail(recipient) && isTeamApp(appInfo.owner?.email)) { - await cli.confirmApp(app, confirm, 'All collaborators will be removed from this app') + await confirmApp(appName, confirm, 'All collaborators will be removed from this app') } const appTransfer = new AppTransfer({ heroku: this.heroku, - appName: appInfo.name ?? app ?? '', + appName, recipient, personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner?.email), bulk, From e5bff00670a66a51ba3c2b3c3cae5fb8c99cb707 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Fri, 15 Mar 2024 15:35:51 -0400 Subject: [PATCH 07/20] refactor: print error message and update lock.run call --- packages/cli/src/commands/apps/transfer.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index 550ceda44d..31390e7b1a 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -62,7 +62,8 @@ $ heroku apps:transfer --bulk acme-widgets }) await appTransfer.start() } catch (error) { - ux.error(error) + const {message} = error as {message: string} + ux.error(message) } } } else { @@ -81,7 +82,7 @@ $ heroku apps:transfer --bulk acme-widgets }) await appTransfer.start() if (locked) { - await lock.run(context) + await lock.run([], this.config) } } } From f9ed17c0272172d5f6895d59c98917034db7f1f1 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Tue, 2 Apr 2024 10:36:03 -0400 Subject: [PATCH 08/20] refactor: initial refactor of apps:transfer tests --- .../unit/commands/apps/transfer.unit.test.ts | 143 ++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 packages/cli/test/unit/commands/apps/transfer.unit.test.ts diff --git a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts new file mode 100644 index 0000000000..49c285db9c --- /dev/null +++ b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts @@ -0,0 +1,143 @@ +import {stdout, stderr} from 'stdout-stderr' +import * as nock from 'nock' +import * as proxyquire from 'proxyquire' +import {expect} from 'chai' +import runCommand, {GenericCmd} from '../../../helpers/runCommand' +import {apps, personalApp, teamApp} from '../../../helpers/stubs/get' +import {teamAppTransfer} from '../../../helpers/stubs/patch' +import {personalToPersonal} from '../../../helpers/stubs/post' + +let Cmd: GenericCmd +let inquirer: {prompt?: (prompts: { choices: any }[]) => void} = {} + +describe('heroku apps:transfer', () => { + beforeEach(() => { + inquirer = {} + Cmd = proxyquire('../../../../src/commands/apps/transfer', { + inquirer, + '@noCallThru': true, + })[0] + }) + afterEach(() => nock.cleanAll()) + context('when transferring in bulk', () => { + beforeEach(() => { + apps() + }) + it('transfers selected apps to a team', async () => { + inquirer.prompt = (prompts: { choices: any }[]) => { + const choices = prompts[0].choices + expect(choices).to.eql([ + { + name: 'my-team-app (team)', value: {name: 'my-team-app', owner: 'team@herokumanager.com'}, + }, { + name: 'myapp (foo@foo.com)', value: {name: 'myapp', owner: 'foo@foo.com'}, + }, + ]) + return Promise.resolve({choices: [{name: 'myapp', owner: 'foo@foo.com'}]}) + } + + const api = teamAppTransfer() + await runCommand(Cmd, [ + '--bulk', + 'team', + ]) + api.done() + expect(stderr.output).to.equal('Transferring applications to team...\n\nTransferring myapp... done\n') + }) + it('transfers selected apps to a personal account', async () => { + inquirer.prompt = (prompts: { choices: any }[]) => { + const choices = prompts[0].choices + expect(choices).to.eql([ + { + name: 'my-team-app (team)', value: {name: 'my-team-app', owner: 'team@herokumanager.com'}, + }, { + name: 'myapp (foo@foo.com)', value: {name: 'myapp', owner: 'foo@foo.com'}, + }, + ]) + return Promise.resolve({choices: [{name: 'myapp', owner: 'foo@foo.com'}]}) + } + + const api = personalToPersonal() + await runCommand(Cmd, [ + '--bulk', + 'raulb@heroku.com', + ]) + api.done() + expect(stderr.output).to.equal('Transferring applications to raulb@heroku.com...\n\nInitiating transfer of myapp... email sent\n') + }) + }) + context('when it is a personal app', () => { + beforeEach(() => { + personalApp() + }) + it('transfers the app to a personal account', async () => { + const api = personalToPersonal() + await runCommand(Cmd, [ + '--app', + 'myapp', + 'raulb@heroku.com', + ]) + expect('').to.eq(stdout.output) + expect('Initiating transfer of myapp to raulb@heroku.com... email sent\n').to.eq(stderr.output) + api.done() + }) + it('transfers the app to a team', async () => { + const api = teamAppTransfer() + await runCommand(Cmd, [ + '--app', + 'myapp', + 'team', + ]) + expect('').to.eq(stdout.output) + expect('Transferring myapp to team... done\n').to.eq(stderr.output) + api.done() + }) + }) + context('when it is an org app', () => { + beforeEach(() => { + teamApp() + }) + it('transfers the app to a personal account confirming app name', async () => { + const api = teamAppTransfer() + await runCommand(Cmd, [ + '--app', + 'myapp', + '--confirm', + 'myapp', + 'team', + ]) + expect('').to.eq(stdout.output) + expect('Transferring myapp to team... done\n').to.eq(stderr.output) + api.done() + }) + it('transfers the app to a team', async () => { + const api = teamAppTransfer() + await runCommand(Cmd, [ + '--app', + 'myapp', + 'team', + ]) + expect('').to.eq(stdout.output) + expect('Transferring myapp to team... done\n').to.eq(stderr.output) + api.done() + }) + it('transfers and locks the app if --locked is passed', async () => { + const api = teamAppTransfer() + const lockedAPI = nock('https://api.heroku.com:443') + .get('/teams/apps/myapp') + .reply(200, {name: 'myapp', locked: false}) + .patch('/teams/apps/myapp', {locked: true}) + .reply(200) + await runCommand(Cmd, [ + '--app', + 'myapp', + '--locked', + 'team', + ]) + expect('').to.eq(stdout.output) + expect('Transferring myapp to team... done\nLocking myapp... done\n').to.eq(stderr.output) + api.done() + lockedAPI.done() + }) + }) +}) From 2f93e3a31ebdf09915ecef0827625d2318e4d36c Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Tue, 2 Apr 2024 15:17:13 -0400 Subject: [PATCH 09/20] refactor: replace AppTransfer class with function and fix message output --- packages/cli/src/commands/apps/transfer.ts | 14 +++-- packages/cli/src/lib/apps/app-transfer.ts | 45 ++++++++++++++ packages/cli/src/lib/apps/appTransfer.ts | 72 ---------------------- 3 files changed, 53 insertions(+), 78 deletions(-) create mode 100644 packages/cli/src/lib/apps/app-transfer.ts delete mode 100644 packages/cli/src/lib/apps/appTransfer.ts diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index 31390e7b1a..5f0c990db9 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -6,7 +6,7 @@ import {sortBy} from 'lodash' import * as inquirer from 'inquirer' import {getOwner, isTeamApp, isValidEmail} from '../../lib/teamUtils' import lock from './lock' -import {AppTransfer} from '../../lib/apps/appTransfer' +import {appTransfer} from '../../lib/apps/app-transfer' import confirmApp from '../../lib/apps/confirm-app' function getAppsToTransfer(apps: Heroku.App[]) { @@ -57,10 +57,13 @@ $ heroku apps:transfer --bulk acme-widgets ux.warn(`Transferring applications to ${color.magenta(recipient)}...\n`) for (const app of selectedApps.choices) { try { - const appTransfer = new AppTransfer({ - heroku: this.heroku, appName: app.name, recipient: recipient, personalToPersonal: isValidEmail(recipient) && !isTeamApp(app.owner), bulk: true, + await appTransfer({ + heroku: this.heroku, + appName: app.name, + recipient: recipient, + personalToPersonal: isValidEmail(recipient) && !isTeamApp(app.owner), + bulk: true, }) - await appTransfer.start() } catch (error) { const {message} = error as {message: string} ux.error(message) @@ -73,14 +76,13 @@ $ heroku apps:transfer --bulk acme-widgets await confirmApp(appName, confirm, 'All collaborators will be removed from this app') } - const appTransfer = new AppTransfer({ + await appTransfer({ heroku: this.heroku, appName, recipient, personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner?.email), bulk, }) - await appTransfer.start() if (locked) { await lock.run([], this.config) } diff --git a/packages/cli/src/lib/apps/app-transfer.ts b/packages/cli/src/lib/apps/app-transfer.ts new file mode 100644 index 0000000000..cce1e452b4 --- /dev/null +++ b/packages/cli/src/lib/apps/app-transfer.ts @@ -0,0 +1,45 @@ +import {APIClient} from '@heroku-cli/command' +import {color} from '@heroku-cli/color' +import * as Heroku from '@heroku-cli/schema' +import {ux} from '@oclif/core' + +type Options = { + heroku: APIClient, + appName: string, + recipient: string, + personalToPersonal: boolean, + bulk: boolean, +} + +const getRequestOpts = (options: Options) => { + const {appName, bulk, recipient, personalToPersonal} = options + const isPersonalToPersonal = personalToPersonal || personalToPersonal === undefined + const requestOpts = isPersonalToPersonal ? + { + body: {app: appName, recipient}, + transferMsg: `Initiating transfer of ${color.app(appName)}`, + path: '/account/app-transfers', + method: 'POST', + } : { + body: {owner: recipient}, + transferMsg: `Transferring ${color.app(appName)}`, + path: `/teams/apps/${appName}`, + method: 'PATCH', + } + if (!bulk) requestOpts.transferMsg += ` to ${color.magenta(recipient)}` + return requestOpts +} + +export const appTransfer = async (options: Options) => { + const {body, transferMsg, path, method} = getRequestOpts(options) + ux.action.start(transferMsg) + const {body: request} = await options.heroku.request( + path, + { + method, + body, + }, + ) + const message = request.state === 'pending' ? 'email sent' : undefined + ux.action.stop(message) +} diff --git a/packages/cli/src/lib/apps/appTransfer.ts b/packages/cli/src/lib/apps/appTransfer.ts deleted file mode 100644 index 2a550ba40a..0000000000 --- a/packages/cli/src/lib/apps/appTransfer.ts +++ /dev/null @@ -1,72 +0,0 @@ -import {APIClient} from '@heroku-cli/command' -import {color} from '@heroku-cli/color' -import * as Heroku from '@heroku-cli/schema' -import {ux} from '@oclif/core' - -type Options = { - heroku: APIClient, - appName: string, - recipient: string, - personalToPersonal: boolean, - bulk: boolean, -} - -export class AppTransfer { - private heroku: APIClient - private appName: string - private recipient: string - private personalToPersonal: boolean - private opts: Options - private body: { app?: string; recipient?: string, owner?: string } - private transferMsg: string - private path: string - private method: string - - /** - * @param {Object} options.heroku - instance of heroku-client - * @param {string} options.appName - application that is being transferred - * @param {string} options.recipient - recipient of the transfer - * @param {boolean} options.personalToPersonal - determines if it is a transfer between individual accounts - * @param {boolean} options.bulk - determines if it is a bulk transfer - * @param {Options} opts - */ - constructor(opts: Options) { - this.opts = opts - this.heroku = this.opts.heroku - this.appName = this.opts.appName - this.recipient = this.opts.recipient - this.personalToPersonal = this.opts.personalToPersonal - - if (this.personalToPersonal === undefined) this.personalToPersonal = true - - if (this.personalToPersonal) { - this.body = {app: this.appName, recipient: this.recipient} - this.transferMsg = `Initiating transfer of ${color.app(this.appName)}` - if (!this.opts.bulk) this.transferMsg += ` to ${color.magenta(this.recipient)}` - this.path = '/account/app-transfers' - this.method = 'POST' - } else { - this.body = {owner: this.recipient} - this.transferMsg = `Transferring ${color.app(this.appName)}` - if (!this.opts.bulk) this.transferMsg += ` to ${color.magenta(this.recipient)}` - this.path = `/teams/apps/${this.appName}` - this.method = 'PATCH' - } - } - - async start() { - ux.action.start(this.transferMsg) - const {body: request} = await this.init() - if (request.state === 'pending') ux.log('email sent') - ux.action.stop() - } - - init() { - return this.heroku.request( - this.path, - { - method: this.method, - body: this.body, - }) - } -} From 4f914e4053b0c737b8df62c5b379ba89f8ff7d20 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Wed, 3 Apr 2024 10:05:33 -0400 Subject: [PATCH 10/20] refactor: test fixes --- packages/cli/src/commands/apps/transfer.ts | 4 ++-- .../unit/commands/apps/transfer.unit.test.ts | 19 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index 5f0c990db9..fd0d2452d9 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -5,7 +5,7 @@ import * as Heroku from '@heroku-cli/schema' import {sortBy} from 'lodash' import * as inquirer from 'inquirer' import {getOwner, isTeamApp, isValidEmail} from '../../lib/teamUtils' -import lock from './lock' +import AppsLock from './lock' import {appTransfer} from '../../lib/apps/app-transfer' import confirmApp from '../../lib/apps/confirm-app' @@ -84,7 +84,7 @@ $ heroku apps:transfer --bulk acme-widgets bulk, }) if (locked) { - await lock.run([], this.config) + await AppsLock.run([], this.config) } } } diff --git a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts index 49c285db9c..c32603943e 100644 --- a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts +++ b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts @@ -13,10 +13,11 @@ let inquirer: {prompt?: (prompts: { choices: any }[]) => void} = {} describe('heroku apps:transfer', () => { beforeEach(() => { inquirer = {} - Cmd = proxyquire('../../../../src/commands/apps/transfer', { + const {default: proxyCmd} = proxyquire('../../../../src/commands/apps/transfer', { inquirer, '@noCallThru': true, - })[0] + }) + Cmd = proxyCmd }) afterEach(() => nock.cleanAll()) context('when transferring in bulk', () => { @@ -42,7 +43,7 @@ describe('heroku apps:transfer', () => { 'team', ]) api.done() - expect(stderr.output).to.equal('Transferring applications to team...\n\nTransferring myapp... done\n') + expect(stderr.output).to.equal(' › Warning: Transferring applications to team...\n ›\nTransferring ⬢ myapp...\nTransferring ⬢ myapp... done\n') }) it('transfers selected apps to a personal account', async () => { inquirer.prompt = (prompts: { choices: any }[]) => { @@ -63,7 +64,7 @@ describe('heroku apps:transfer', () => { 'raulb@heroku.com', ]) api.done() - expect(stderr.output).to.equal('Transferring applications to raulb@heroku.com...\n\nInitiating transfer of myapp... email sent\n') + expect(stderr.output).to.equal(' › Warning: Transferring applications to raulb@heroku.com...\n ›\nInitiating transfer of ⬢ myapp...\nInitiating transfer of ⬢ myapp... email sent\n') }) }) context('when it is a personal app', () => { @@ -78,7 +79,7 @@ describe('heroku apps:transfer', () => { 'raulb@heroku.com', ]) expect('').to.eq(stdout.output) - expect('Initiating transfer of myapp to raulb@heroku.com... email sent\n').to.eq(stderr.output) + expect('Initiating transfer of ⬢ myapp to raulb@heroku.com...\nInitiating transfer of ⬢ myapp to raulb@heroku.com... email sent\n').to.eq(stderr.output) api.done() }) it('transfers the app to a team', async () => { @@ -89,7 +90,7 @@ describe('heroku apps:transfer', () => { 'team', ]) expect('').to.eq(stdout.output) - expect('Transferring myapp to team... done\n').to.eq(stderr.output) + expect('Transferring ⬢ myapp to team...\nTransferring ⬢ myapp to team... done\n').to.eq(stderr.output) api.done() }) }) @@ -107,7 +108,7 @@ describe('heroku apps:transfer', () => { 'team', ]) expect('').to.eq(stdout.output) - expect('Transferring myapp to team... done\n').to.eq(stderr.output) + expect('Transferring ⬢ myapp to team...\nTransferring ⬢ myapp to team... done\n').to.eq(stderr.output) api.done() }) it('transfers the app to a team', async () => { @@ -118,10 +119,10 @@ describe('heroku apps:transfer', () => { 'team', ]) expect('').to.eq(stdout.output) - expect('Transferring myapp to team... done\n').to.eq(stderr.output) + expect('Transferring ⬢ myapp to team...\nTransferring ⬢ myapp to team... done\n').to.eq(stderr.output) api.done() }) - it('transfers and locks the app if --locked is passed', async () => { + it.only('transfers and locks the app if --locked is passed', async () => { const api = teamAppTransfer() const lockedAPI = nock('https://api.heroku.com:443') .get('/teams/apps/myapp') From c4f93113d6d08c88a61ae94fee79a66309dac711 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Wed, 3 Apr 2024 10:14:28 -0400 Subject: [PATCH 11/20] refactor: remove .only --- packages/cli/test/unit/commands/apps/transfer.unit.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts index c32603943e..aff25fc370 100644 --- a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts +++ b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts @@ -122,7 +122,7 @@ describe('heroku apps:transfer', () => { expect('Transferring ⬢ myapp to team...\nTransferring ⬢ myapp to team... done\n').to.eq(stderr.output) api.done() }) - it.only('transfers and locks the app if --locked is passed', async () => { + it('transfers and locks the app if --locked is passed', async () => { const api = teamAppTransfer() const lockedAPI = nock('https://api.heroku.com:443') .get('/teams/apps/myapp') From 3086ba3ce7988d83bdb5f29293719bd53c62a66f Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Wed, 3 Apr 2024 17:24:49 -0400 Subject: [PATCH 12/20] refactor: add await to getConfig for test setup --- packages/cli/test/helpers/runCommand.ts | 5 +++-- packages/cli/test/helpers/testInstances.ts | 12 ++++++++++-- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/cli/test/helpers/runCommand.ts b/packages/cli/test/helpers/runCommand.ts index 6088d720d1..7ee62a4c30 100644 --- a/packages/cli/test/helpers/runCommand.ts +++ b/packages/cli/test/helpers/runCommand.ts @@ -10,8 +10,9 @@ const stopMock = () => { stderr.stop() } -const runCommand = (Cmd: GenericCmd, args: string[] = [], printStd = false) => { - const instance = new Cmd(args, getConfig()) +const runCommand = async (Cmd: GenericCmd, args: string[] = [], printStd = false) => { + const conf = await getConfig() + const instance = new Cmd(args, conf) if (printStd) { stdout.print = true stderr.print = true diff --git a/packages/cli/test/helpers/testInstances.ts b/packages/cli/test/helpers/testInstances.ts index 5b0ef73ecd..2492e366ef 100644 --- a/packages/cli/test/helpers/testInstances.ts +++ b/packages/cli/test/helpers/testInstances.ts @@ -1,6 +1,14 @@ import {APIClient} from '@heroku-cli/command' import {Config} from '@oclif/core' -export const getConfig = () => new Config({root: '../../package.json'}) +export const getConfig = async () => { + const pjsonPath = require.resolve('../../package.json') + const conf = new Config({root: pjsonPath}) + await conf.load() + return conf +} -export const getHerokuAPI = () => new APIClient(getConfig()) +export const getHerokuAPI = async () => { + const conf = await getConfig() + return new APIClient(conf) +} From dc0556ff485bee33b63209755ca223f8bf1e17fb Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Wed, 3 Apr 2024 17:26:50 -0400 Subject: [PATCH 13/20] fix: add app flag to AppsLock.run call and fix test --- packages/cli/src/commands/apps/transfer.ts | 102 +++++++++--------- .../unit/commands/apps/transfer.unit.test.ts | 2 +- 2 files changed, 52 insertions(+), 52 deletions(-) diff --git a/packages/cli/src/commands/apps/transfer.ts b/packages/cli/src/commands/apps/transfer.ts index fd0d2452d9..83b191a544 100644 --- a/packages/cli/src/commands/apps/transfer.ts +++ b/packages/cli/src/commands/apps/transfer.ts @@ -24,68 +24,68 @@ function getAppsToTransfer(apps: Heroku.App[]) { } export default class AppsTransfer extends Command { - static topic = 'apps'; - static description = 'transfer applications to another user or team'; - static flags = { - locked: flags.boolean({char: 'l', required: false, description: 'lock the app upon transfer'}), - bulk: flags.boolean({required: false, description: 'transfer applications in bulk'}), - app: flags.app(), - remote: flags.remote({char: 'r'}), - confirm: flags.string({char: 'c', hidden: true}), - }; + static topic = 'apps'; + static description = 'transfer applications to another user or team'; + static flags = { + locked: flags.boolean({char: 'l', required: false, description: 'lock the app upon transfer'}), + bulk: flags.boolean({required: false, description: 'transfer applications in bulk'}), + app: flags.app(), + remote: flags.remote({char: 'r'}), + confirm: flags.string({char: 'c', hidden: true}), + }; - static args = { - recipient: Args.string({description: 'user or team to transfer applications to', required: true}), - }; + static args = { + recipient: Args.string({description: 'user or team to transfer applications to', required: true}), + }; - static example = `$ heroku apps:transfer collaborator@example.com + static examples = [`$ heroku apps:transfer collaborator@example.com Transferring example to collaborator@example.com... done $ heroku apps:transfer acme-widgets Transferring example to acme-widgets... done $ heroku apps:transfer --bulk acme-widgets -...` +...`] - public async run(): Promise { - const {flags, args} = await this.parse(AppsTransfer) - const {app, bulk, locked, confirm} = flags - const recipient = args.recipient - if (bulk) { - const {body: allApps} = await this.heroku.get('/apps') - const selectedApps = await getAppsToTransfer(sortBy(allApps, 'name')) - ux.warn(`Transferring applications to ${color.magenta(recipient)}...\n`) - for (const app of selectedApps.choices) { - try { - await appTransfer({ - heroku: this.heroku, - appName: app.name, - recipient: recipient, - personalToPersonal: isValidEmail(recipient) && !isTeamApp(app.owner), - bulk: true, - }) - } catch (error) { - const {message} = error as {message: string} - ux.error(message) - } - } - } else { - const {body: appInfo} = await this.heroku.get(`/apps/${app}`) - const appName = appInfo.name ?? app ?? '' - if (isValidEmail(recipient) && isTeamApp(appInfo.owner?.email)) { - await confirmApp(appName, confirm, 'All collaborators will be removed from this app') + public async run() { + const {flags, args} = await this.parse(AppsTransfer) + const {app, bulk, locked, confirm} = flags + const recipient = args.recipient + if (bulk) { + const {body: allApps} = await this.heroku.get('/apps') + const selectedApps = await getAppsToTransfer(sortBy(allApps, 'name')) + ux.warn(`Transferring applications to ${color.magenta(recipient)}...\n`) + for (const app of selectedApps.choices) { + try { + await appTransfer({ + heroku: this.heroku, + appName: app.name, + recipient: recipient, + personalToPersonal: isValidEmail(recipient) && !isTeamApp(app.owner), + bulk: true, + }) + } catch (error) { + const {message} = error as {message: string} + ux.error(message) } + } + } else { + const {body: appInfo} = await this.heroku.get(`/apps/${app}`) + const appName = appInfo.name ?? app ?? '' + if (isValidEmail(recipient) && isTeamApp(appInfo.owner?.email)) { + await confirmApp(appName, confirm, 'All collaborators will be removed from this app') + } - await appTransfer({ - heroku: this.heroku, - appName, - recipient, - personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner?.email), - bulk, - }) - if (locked) { - await AppsLock.run([], this.config) - } + await appTransfer({ + heroku: this.heroku, + appName, + recipient, + personalToPersonal: isValidEmail(recipient) && !isTeamApp(appInfo.owner?.email), + bulk, + }) + if (locked) { + await AppsLock.run(['--app', appName], this.config) } } + } } diff --git a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts index aff25fc370..055f1f9bd1 100644 --- a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts +++ b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts @@ -136,7 +136,7 @@ describe('heroku apps:transfer', () => { 'team', ]) expect('').to.eq(stdout.output) - expect('Transferring myapp to team... done\nLocking myapp... done\n').to.eq(stderr.output) + expect('Transferring ⬢ myapp to team...\nTransferring ⬢ myapp to team... done\nLocking myapp...\nLocking myapp... done\n').to.eq(stderr.output) api.done() lockedAPI.done() }) From 683d4afc52b391322f525f4d27bce7aee27a9897 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Thu, 4 Apr 2024 13:38:01 -0400 Subject: [PATCH 14/20] fix: add async await for commands that need the config --- .../test/unit/lib/addons/resolve.unit.test.ts | 54 ++++++++++--------- packages/cli/test/unit/lib/api.unit.test.ts | 4 +- .../test/unit/lib/ci/pipelines.unit.test.ts | 4 +- 3 files changed, 32 insertions(+), 30 deletions(-) diff --git a/packages/cli/test/unit/lib/addons/resolve.unit.test.ts b/packages/cli/test/unit/lib/addons/resolve.unit.test.ts index 317ec30124..fa8a7d894c 100644 --- a/packages/cli/test/unit/lib/addons/resolve.unit.test.ts +++ b/packages/cli/test/unit/lib/addons/resolve.unit.test.ts @@ -6,7 +6,9 @@ const {expect} = require('chai') import * as nock from 'nock' import * as Heroku from '@heroku-cli/schema' -describe('resolve', () => { +describe('resolve', async () => { + const herokuAPI = await getHerokuAPI() + beforeEach(function () { // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore @@ -20,7 +22,7 @@ describe('resolve', () => { const api = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: null, addon: 'myaddon-1'}).reply(200, [{name: 'myaddon-1'}]) - return resolveAddon(getHerokuAPI(), undefined, 'myaddon-1') + return resolveAddon(herokuAPI, undefined, 'myaddon-1') .then((addon: Heroku.AddOn) => expect(addon).to.deep.equal({name: 'myaddon-1'})) .then(() => api.done()) }) @@ -29,7 +31,7 @@ describe('resolve', () => { const api = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-2'}).reply(200, [{name: 'myaddon-2'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-2') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-2') .then((addon: Heroku.AddOn) => expect(addon).to.deep.equal({name: 'myaddon-2'})) .then(() => api.done()) }) @@ -39,7 +41,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-3'}).reply(404, {resource: 'add_on'}) .post('/actions/addons/resolve', {app: null, addon: 'myaddon-3'}).reply(404, {resource: 'add_on'}) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-3') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-3') .then(() => { throw new Error('unreachable') }) @@ -51,7 +53,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-3', addon_service: 'slowdb'}).reply(404, {resource: 'add_on'}) .post('/actions/addons/resolve', {app: null, addon: 'myaddon-3', addon_service: 'slowdb'}).reply(404, {resource: 'add_on'}) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-3', {addon_service: 'slowdb'}) + return resolveAddon(herokuAPI, 'myapp', 'myaddon-3', {addon_service: 'slowdb'}) .then(() => { throw new Error('unreachable') }) @@ -63,7 +65,7 @@ describe('resolve', () => { nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-5'}).reply(401) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-5') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-5') .then(() => { throw new Error('unreachable') }) @@ -75,7 +77,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-5'}) .reply(200, [{name: 'myaddon-5'}, {name: 'myaddon-6'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-5') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-5') .then(() => { throw new Error('unreachable') }) @@ -90,7 +92,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-3', addon_service: 'slowdb'}).reply(404, {resource: 'add_on'}) .post('/actions/addons/resolve', {app: null, addon: 'myaddon-3', addon_service: 'slowdb'}).reply(404, {resource: 'add_on'}) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-3', {addon_service: 'slowdb'}) + return resolveAddon(herokuAPI, 'myapp', 'myaddon-3', {addon_service: 'slowdb'}) .then(() => { throw new Error('unreachable') }) @@ -104,7 +106,7 @@ describe('resolve', () => { const api = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-3', addon_service: 'slowdb'}).reply(404, {resource: 'app'}) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-3', {addon_service: 'slowdb'}) + return resolveAddon(herokuAPI, 'myapp', 'myaddon-3', {addon_service: 'slowdb'}) .then(() => { throw new Error('unreachable') }) @@ -122,7 +124,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-1'}) .reply(200, [{name: 'myaddon-1', namespace: null}, {name: 'myaddon-1b', namespace: 'definitely-not-null'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-1') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-1') .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-1'})) .then(() => api.done()) }) @@ -132,7 +134,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-1'}) .reply(200, [{name: 'myaddon-1'}, {name: 'myaddon-1b', namespace: 'definitely-not-null'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-1') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-1') .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-1'})) .then(() => api.done()) }) @@ -142,7 +144,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-1'}) .reply(200, [{name: 'myaddon-1'}, {name: 'myaddon-1b', namespace: 'great-namespace'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-1', {namespace: 'great-namespace'}) + return resolveAddon(herokuAPI, 'myapp', 'myaddon-1', {namespace: 'great-namespace'}) .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-1b'})) .then(() => api.done()) }) @@ -152,7 +154,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-1'}) .reply(200, [{name: 'myaddon-1b', namespace: 'great-namespace'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-1', {namespace: 'great-namespace'}) + return resolveAddon(herokuAPI, 'myapp', 'myaddon-1', {namespace: 'great-namespace'}) .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-1b'})) .then(() => api.done()) }) @@ -162,7 +164,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-1'}) .reply(200, [{name: 'myaddon-1'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-1', {namespace: 'amazing-namespace'}) + return resolveAddon(herokuAPI, 'myapp', 'myaddon-1', {namespace: 'amazing-namespace'}) .then(() => { throw new Error('unreachable') }) @@ -177,7 +179,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-1'}) .reply(200, [{name: 'myaddon-1', namespace: 'definitely-not-null'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-1') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-1') .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-1'})) .then(() => api.done()) }) @@ -187,7 +189,7 @@ describe('resolve', () => { const api = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-6'}).reply(200, [{name: 'myaddon-6'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-6') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-6') .then(function (addon: Heroku.AddOn) { expect(addon).to.have.nested.include({name: 'myaddon-6'}) api.done() @@ -195,7 +197,7 @@ describe('resolve', () => { .then(function () { nock.cleanAll() - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-6') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-6') .then(function (memoizedAddon: Heroku.AddOn) { expect(memoizedAddon).to.have.nested.include({name: 'myaddon-6'}) }) @@ -204,7 +206,7 @@ describe('resolve', () => { const diffId = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-7'}).reply(200, [{name: 'myaddon-7'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-7') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-7') .then(function (diffIdAddon: Heroku.AddOn) { expect(diffIdAddon).to.have.nested.include({name: 'myaddon-7'}) diffId.done() @@ -214,7 +216,7 @@ describe('resolve', () => { const diffApp = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'fooapp', addon: 'myaddon-6'}).reply(200, [{name: 'myaddon-6'}]) - return resolveAddon(getHerokuAPI(), 'fooapp', 'myaddon-6') + return resolveAddon(herokuAPI, 'fooapp', 'myaddon-6') .then(function (diffAppAddon: Heroku.AddOn) { expect(diffAppAddon).to.have.nested.include({name: 'myaddon-6'}) diffApp.done() @@ -224,7 +226,7 @@ describe('resolve', () => { const diffAddonService = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'fooapp', addon: 'myaddon-6', addon_service: 'slowdb'}).reply(200, [{name: 'myaddon-6'}]) - return resolveAddon(getHerokuAPI(), 'fooapp', 'myaddon-6', {addon_service: 'slowdb'}) + return resolveAddon(herokuAPI, 'fooapp', 'myaddon-6', {addon_service: 'slowdb'}) .then(function (diffAddonServiceAddon: Heroku.AddOn) { expect(diffAddonServiceAddon).to.have.nested.include({name: 'myaddon-6'}) diffAddonService.done() @@ -236,7 +238,7 @@ describe('resolve', () => { const api = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-8'}).reply(500, {id: 'internal server error'}) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-8') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-8') .then(() => { throw new Error('unreachable') }) @@ -250,14 +252,14 @@ describe('resolve', () => { const apiRetry = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-8'}).reply(200, [{name: 'myaddon-8'}]) - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-8') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-8') .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-8'})) .then(() => apiRetry.done()) }) .then(function () { nock.cleanAll() - return resolveAddon(getHerokuAPI(), 'myapp', 'myaddon-8') + return resolveAddon(herokuAPI, 'myapp', 'myaddon-8') .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-8'})) }) }) @@ -269,7 +271,7 @@ describe('resolve', () => { const api = nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-2'}).reply(200, [{name: 'myaddon-2'}]) - return appAddon(getHerokuAPI(), 'myapp', 'myaddon-2') + return appAddon(herokuAPI, 'myapp', 'myaddon-2') .then((addon: Heroku.AddOn) => expect(addon).to.have.nested.include({name: 'myaddon-2'})) .then(() => api.done()) }) @@ -278,7 +280,7 @@ describe('resolve', () => { nock('https://api.heroku.com:443') .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-5'}).reply(404) - return appAddon(getHerokuAPI(), 'myapp', 'myaddon-5') + return appAddon(herokuAPI, 'myapp', 'myaddon-5') .then(() => { throw new Error('unreachable') }) @@ -290,7 +292,7 @@ describe('resolve', () => { .post('/actions/addons/resolve', {app: 'myapp', addon: 'myaddon-5'}) .reply(200, [{name: 'myaddon-5'}, {name: 'myaddon-6'}]) - return appAddon(getHerokuAPI(), 'myapp', 'myaddon-5') + return appAddon(herokuAPI, 'myapp', 'myaddon-5') .then(() => { throw new Error('unreachable') }) diff --git a/packages/cli/test/unit/lib/api.unit.test.ts b/packages/cli/test/unit/lib/api.unit.test.ts index 0729b85e4f..b035bef2bd 100644 --- a/packages/cli/test/unit/lib/api.unit.test.ts +++ b/packages/cli/test/unit/lib/api.unit.test.ts @@ -3,10 +3,10 @@ import {getHerokuAPI} from '../../helpers/testInstances' import * as nock from 'nock' import {expect} from 'chai' -const herokuAPI = getHerokuAPI() const TEST_RUN = {id: 'uuid-999'} -describe('api', () => { +describe('api', async () => { + const herokuAPI = await getHerokuAPI() describe('#createTestRun', function () { it('creates test run', async function () { const api = nock('https://api.heroku.com', {reqheaders: {Accept: 'application/vnd.heroku+json; version=3.ci'}}) diff --git a/packages/cli/test/unit/lib/ci/pipelines.unit.test.ts b/packages/cli/test/unit/lib/ci/pipelines.unit.test.ts index 612993eeba..744a81c4d4 100644 --- a/packages/cli/test/unit/lib/ci/pipelines.unit.test.ts +++ b/packages/cli/test/unit/lib/ci/pipelines.unit.test.ts @@ -8,9 +8,9 @@ const PIPELINE = { name: 'test-pipeline', } const FLAGS = {pipeline: PIPELINE.id} -const herokuAPI = getHerokuAPI() -describe('pipelines.ts', function () { +describe('pipelines.ts', async function () { + const herokuAPI = await getHerokuAPI() afterEach(() => nock.cleanAll()) describe('#getPipeline', function () { From 7ff03717a79b3665fada4090ccc163f4e42d2682 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Thu, 4 Apr 2024 13:58:37 -0400 Subject: [PATCH 15/20] fix: add nock for addons:wait test api call --- packages/cli/test/unit/commands/addons/wait.unit.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/cli/test/unit/commands/addons/wait.unit.test.ts b/packages/cli/test/unit/commands/addons/wait.unit.test.ts index 403fd08839..b08dcc9bdc 100644 --- a/packages/cli/test/unit/commands/addons/wait.unit.test.ts +++ b/packages/cli/test/unit/commands/addons/wait.unit.test.ts @@ -136,6 +136,8 @@ Created www-redis as REDIS_URL }) it('shows that it failed to provision', function () { nock('https://api.heroku.com') + .post('/actions/addons/resolve', {app: null, addon: 'www-redis'}) + .reply(200, [fixtures.addons['www-redis']]) .get('/addons/www-redis') .reply(200, fixtures.addons['www-redis']) const deprovisionedAddon = _.clone(fixtures.addons['www-redis']) From 8ef5709a90bceaf02e98fb121b9f4e8030384bc0 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Thu, 4 Apr 2024 14:10:29 -0400 Subject: [PATCH 16/20] fix: fix apps:transfer test accounting for mac and windows formatting --- packages/cli/test/unit/commands/apps/transfer.unit.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts index 055f1f9bd1..3ce360de6b 100644 --- a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts +++ b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts @@ -43,7 +43,7 @@ describe('heroku apps:transfer', () => { 'team', ]) api.done() - expect(stderr.output).to.equal(' › Warning: Transferring applications to team...\n ›\nTransferring ⬢ myapp...\nTransferring ⬢ myapp... done\n') + expect(stderr.output).to.include('Warning: Transferring applications to team...\n ›\nTransferring ⬢ myapp...\nTransferring ⬢ myapp... done\n') }) it('transfers selected apps to a personal account', async () => { inquirer.prompt = (prompts: { choices: any }[]) => { @@ -64,7 +64,7 @@ describe('heroku apps:transfer', () => { 'raulb@heroku.com', ]) api.done() - expect(stderr.output).to.equal(' › Warning: Transferring applications to raulb@heroku.com...\n ›\nInitiating transfer of ⬢ myapp...\nInitiating transfer of ⬢ myapp... email sent\n') + expect(stderr.output).to.include('Warning: Transferring applications to raulb@heroku.com...\n ›\nInitiating transfer of ⬢ myapp...\nInitiating transfer of ⬢ myapp... email sent\n') }) }) context('when it is a personal app', () => { From 3eb5dbed5f030652bf1819d9ca25e75ef6953ac3 Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Thu, 4 Apr 2024 14:27:03 -0400 Subject: [PATCH 17/20] fix: one more windows test fix for apps:transfer --- packages/cli/test/unit/commands/apps/transfer.unit.test.ts | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts index 3ce360de6b..1ab0cbf659 100644 --- a/packages/cli/test/unit/commands/apps/transfer.unit.test.ts +++ b/packages/cli/test/unit/commands/apps/transfer.unit.test.ts @@ -43,7 +43,8 @@ describe('heroku apps:transfer', () => { 'team', ]) api.done() - expect(stderr.output).to.include('Warning: Transferring applications to team...\n ›\nTransferring ⬢ myapp...\nTransferring ⬢ myapp... done\n') + expect(stderr.output).to.include('Warning: Transferring applications to team...\n') + expect(stderr.output).to.include('\nTransferring ⬢ myapp...\nTransferring ⬢ myapp... done\n') }) it('transfers selected apps to a personal account', async () => { inquirer.prompt = (prompts: { choices: any }[]) => { @@ -64,7 +65,8 @@ describe('heroku apps:transfer', () => { 'raulb@heroku.com', ]) api.done() - expect(stderr.output).to.include('Warning: Transferring applications to raulb@heroku.com...\n ›\nInitiating transfer of ⬢ myapp...\nInitiating transfer of ⬢ myapp... email sent\n') + expect(stderr.output).to.include('Warning: Transferring applications to raulb@heroku.com...\n') + expect(stderr.output).to.include('\nInitiating transfer of ⬢ myapp...\nInitiating transfer of ⬢ myapp... email sent\n') }) }) context('when it is a personal app', () => { From b573e241ca3f4710de7ff9db17129115eb28699d Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Thu, 4 Apr 2024 15:04:06 -0400 Subject: [PATCH 18/20] refactor: remove orgs-v5 package directory --- packages/orgs-v5/.gitignore | 2 - packages/orgs-v5/CHANGELOG.md | 419 ------------------ packages/orgs-v5/LICENSE | 6 - packages/orgs-v5/README.md | 408 ----------------- packages/orgs-v5/commands/apps/lock.js | 30 -- packages/orgs-v5/commands/apps/transfer.js | 109 ----- packages/orgs-v5/index.js | 19 - packages/orgs-v5/lib/app_transfer.js | 53 --- packages/orgs-v5/lib/error.js | 37 -- packages/orgs-v5/lib/utils.js | 60 --- packages/orgs-v5/package.json | 84 ---- packages/orgs-v5/test/assert_exit.js | 17 - packages/orgs-v5/test/helpers.js | 15 - .../unit/commands/apps/transfer.unit.test.js | 145 ------ packages/orgs-v5/test/unit/stub/get.js | 93 ---- packages/orgs-v5/test/unit/stub/patch.js | 20 - packages/orgs-v5/test/unit/stub/post.js | 34 -- packages/orgs-v5/test/unwrap.js | 10 - 18 files changed, 1561 deletions(-) delete mode 100644 packages/orgs-v5/.gitignore delete mode 100644 packages/orgs-v5/CHANGELOG.md delete mode 100644 packages/orgs-v5/LICENSE delete mode 100644 packages/orgs-v5/README.md delete mode 100644 packages/orgs-v5/commands/apps/lock.js delete mode 100644 packages/orgs-v5/commands/apps/transfer.js delete mode 100644 packages/orgs-v5/index.js delete mode 100644 packages/orgs-v5/lib/app_transfer.js delete mode 100644 packages/orgs-v5/lib/error.js delete mode 100644 packages/orgs-v5/lib/utils.js delete mode 100644 packages/orgs-v5/package.json delete mode 100644 packages/orgs-v5/test/assert_exit.js delete mode 100644 packages/orgs-v5/test/helpers.js delete mode 100644 packages/orgs-v5/test/unit/commands/apps/transfer.unit.test.js delete mode 100644 packages/orgs-v5/test/unit/stub/get.js delete mode 100644 packages/orgs-v5/test/unit/stub/patch.js delete mode 100644 packages/orgs-v5/test/unit/stub/post.js delete mode 100644 packages/orgs-v5/test/unwrap.js diff --git a/packages/orgs-v5/.gitignore b/packages/orgs-v5/.gitignore deleted file mode 100644 index 16d4f51201..0000000000 --- a/packages/orgs-v5/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -.nyc_output -node_modules diff --git a/packages/orgs-v5/CHANGELOG.md b/packages/orgs-v5/CHANGELOG.md deleted file mode 100644 index 4310c0d4bb..0000000000 --- a/packages/orgs-v5/CHANGELOG.md +++ /dev/null @@ -1,419 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [9.0.0-alpha.0](https://github.com/heroku/cli/compare/v8.5.0...v9.0.0-alpha.0) (2023-10-04) - - -### Bug Fixes - -* run lint after every test. ([#2490](https://github.com/heroku/cli/issues/2490)) ([d4db466](https://github.com/heroku/cli/commit/d4db46648baef355f9e362679fca827591f037c1)) - - - - - -# [8.2.0](https://github.com/heroku/cli/compare/v8.1.9...v8.2.0) (2023-08-14) - - -### Bug Fixes - -* monorepo dependency issues - upgrade to yarn 3 ([#2429](https://github.com/heroku/cli/issues/2429)) ([0d7e5ca](https://github.com/heroku/cli/commit/0d7e5ca519799af4352ec973f51b45748699f3a1)) - - - - - -## [8.1.4](https://github.com/heroku/cli/compare/v8.1.3...v8.1.4) (2023-05-24) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -# [8.1.0](https://github.com/heroku/cli/compare/v8.0.6...v8.1.0) (2023-04-27) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [8.0.6](https://github.com/heroku/cli/compare/v8.0.5...v8.0.6) (2023-04-24) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [8.0.5](https://github.com/heroku/cli/compare/v8.0.4...v8.0.5) (2023-04-18) - - -### Bug Fixes - -* oclif promote step ([#2301](https://github.com/heroku/cli/issues/2301)) ([4e94fb1](https://github.com/heroku/cli/commit/4e94fb1fdc1a591bd1b744e2da69c0e0df03ed6e)) - - - - - -## [8.0.2](https://github.com/heroku/cli/compare/v7.69.1...v8.0.2) (2023-03-16) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.69.2](https://github.com/heroku/cli/compare/v7.69.1...v7.69.2) (2023-03-16) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -# [7.68.0](https://github.com/heroku/cli/compare/v8.0.1...v7.68.0) (2023-02-06) - - -### Bug Fixes - -* revert to v7.67.2 ([#2235](https://github.com/heroku/cli/issues/2235)) ([0955a24](https://github.com/heroku/cli/commit/0955a24d6aeafdec7211ffd6179f772560f35098)), closes [#2231](https://github.com/heroku/cli/issues/2231) [#2230](https://github.com/heroku/cli/issues/2230) [#2229](https://github.com/heroku/cli/issues/2229) [#2228](https://github.com/heroku/cli/issues/2228) [#2227](https://github.com/heroku/cli/issues/2227) [#2225](https://github.com/heroku/cli/issues/2225) [#2144](https://github.com/heroku/cli/issues/2144) [#2216](https://github.com/heroku/cli/issues/2216) [#2207](https://github.com/heroku/cli/issues/2207) [#2212](https://github.com/heroku/cli/issues/2212) [#2212](https://github.com/heroku/cli/issues/2212) - - - - - -## [7.66.3](https://github.com/heroku/cli/compare/v7.66.2...v7.66.3) (2022-11-14) - - -### Bug Fixes - -* debian builds ([#2128](https://github.com/heroku/cli/issues/2128)) ([8f80622](https://github.com/heroku/cli/commit/8f80622617194c8be8ebce1688e1e5b565a8ffb1)) - - - - - -# [7.54.0](https://github.com/heroku/cli/compare/v7.47.10...v7.54.0) (2021-05-18) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -# [7.53.0](https://github.com/heroku/cli/compare/v7.52.0...v7.53.0) (2021-04-27) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -# [7.49.0](https://github.com/heroku/cli/compare/v7.47.13...v7.49.0) (2021-02-24) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.47.13](https://github.com/heroku/cli/compare/v7.47.12...v7.47.13) (2021-02-18) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -# [7.43.0](https://github.com/heroku/cli/compare/v7.42.13...v7.43.0) (2020-09-15) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.42.8](https://github.com/heroku/cli/compare/v7.42.7...v7.42.8) (2020-08-17) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.42.7](https://github.com/heroku/cli/compare/v7.42.6...v7.42.7) (2020-08-17) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.39.2](https://github.com/heroku/cli/compare/v7.39.1...v7.39.2) (2020-03-30) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.38.1](https://github.com/heroku/cli/compare/v7.38.0...v7.38.1) (2020-02-10) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -# [7.26.0](https://github.com/heroku/cli/compare/v7.25.0...v7.26.0) (2019-06-26) - - -### Bug Fixes - -* team flag prioritized over org flag ([#1250](https://github.com/heroku/cli/issues/1250)) ([9eda2e6](https://github.com/heroku/cli/commit/9eda2e6)) - - - - - -# [7.24.0](https://github.com/heroku/cli/compare/v7.23.0...v7.24.0) (2019-04-25) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.22.7](https://github.com/heroku/cli/compare/v7.22.6...v7.22.7) (2019-03-14) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.22.6](https://github.com/heroku/cli/compare/v7.22.5...v7.22.6) (2019-03-14) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.22.5](https://github.com/heroku/cli/compare/v7.22.4...v7.22.5) (2019-03-13) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - -## [7.22.4](https://github.com/heroku/cli/compare/v7.22.3...v7.22.4) (2019-03-06) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - - -## [7.22.2](https://github.com/heroku/cli/compare/v7.22.1...v7.22.2) (2019-02-28) - - -### Bug Fixes - -* revert "No more wantsOrg" ([#1204](https://github.com/heroku/cli/issues/1204)) ([7641009](https://github.com/heroku/cli/commit/7641009)) - - - - - -## [7.16.2](https://github.com/heroku/cli/compare/v7.16.1...v7.16.2) (2018-10-02) - - -### Bug Fixes - -* updated deps ([482dc85](https://github.com/heroku/cli/commit/482dc85)) - - - - - - -# [7.16.0](https://github.com/heroku/cli/compare/v7.15.2...v7.16.0) (2018-09-14) - - -### Bug Fixes - -* updated deps ([6d3be5a](https://github.com/heroku/cli/commit/6d3be5a)) -* updated dev-cli ([022396b](https://github.com/heroku/cli/commit/022396b)) - - - - - - -# [7.15.0](https://github.com/heroku/cli/compare/v7.14.4...v7.15.0) (2018-09-10) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - - -## [7.14.3](https://github.com/heroku/cli/compare/v7.14.2...v7.14.3) (2018-09-06) - - -### Bug Fixes - -* add help description to heroku teams ([031a2f6](https://github.com/heroku/cli/commit/031a2f6)) - - - - - -## [7.12.6](https://github.com/heroku/cli/compare/v7.12.5...v7.12.6) (2018-08-30) - - -### Bug Fixes - -* windows test failures ([5b4d171](https://github.com/heroku/cli/commit/5b4d171)) - - - - - - -## [7.12.4](https://github.com/heroku/cli/compare/v7.12.3...v7.12.4) (2018-08-29) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - - -## [7.9.4](https://github.com/heroku/cli/compare/v7.9.3...v7.9.4) (2018-08-21) - - -### Bug Fixes - -* updated notifier ([85ad480](https://github.com/heroku/cli/commit/85ad480)) - - - - - - -## [7.9.3](https://github.com/heroku/cli/compare/v7.9.2...v7.9.3) (2018-08-18) - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - - - - - -## [7.9.2](https://github.com/heroku/cli/compare/v7.9.1...v7.9.2) (2018-08-18) - - -### Bug Fixes - -* typescript 3.0 ([268c0af](https://github.com/heroku/cli/commit/268c0af)) - - - - - - -## [7.9.1](https://github.com/heroku/cli/compare/v7.9.0...v7.9.1) (2018-08-17) - - -### Bug Fixes - -* updated some dependencies ([0306f88](https://github.com/heroku/cli/commit/0306f88)) - - - - - -## [7.5.6](https://github.com/heroku/cli/compare/v7.5.5...v7.5.6) (2018-06-29) - - -### Bug Fixes - -* bump legacy and color ([a3fa970](https://github.com/heroku/cli/commit/a3fa970)) - - - - - -## [7.5.5](https://github.com/heroku/cli/compare/v7.5.4...v7.5.5) (2018-06-29) - - - - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - -## [7.5.1](https://github.com/heroku/cli/compare/v7.5.0...v7.5.1) (2018-06-26) - - -### Bug Fixes - -* bump dev-cli ([fb3e41a](https://github.com/heroku/cli/commit/fb3e41a)) - - - - - -# [7.5.0](https://github.com/heroku/cli/compare/v7.4.11...v7.5.0) (2018-06-26) - - - - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - -## [7.4.8](https://github.com/heroku/cli/compare/v7.4.7...v7.4.8) (2018-06-21) - - - - -**Note:** Version bump only for package @heroku-cli/plugin-orgs-v5 - - -## [7.4.6](https://github.com/heroku/cli/compare/v7.4.5...v7.4.6) (2018-06-20) - - -### Bug Fixes - -* update dev-cli readme generation ([42a77bc](https://github.com/heroku/cli/commit/42a77bc)) - - - - - -## [7.4.5](https://github.com/heroku/cli/compare/v7.4.4...v7.4.5) (2018-06-20) - - -### Bug Fixes - -* updated monorepo documentation urls ([4bb6fe0](https://github.com/heroku/cli/commit/4bb6fe0)) - - - - - -# [7.4.0](https://github.com/heroku/cli/compare/v7.3.0...v7.4.0) (2018-06-19) - - -### Bug Fixes - -* repo name ([c306c78](https://github.com/heroku/cli/commit/c306c78)) diff --git a/packages/orgs-v5/LICENSE b/packages/orgs-v5/LICENSE deleted file mode 100644 index 7577b50298..0000000000 --- a/packages/orgs-v5/LICENSE +++ /dev/null @@ -1,6 +0,0 @@ -ISC License (ISC) -Copyright (c) 2016, Heroku - -Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/packages/orgs-v5/README.md b/packages/orgs-v5/README.md deleted file mode 100644 index f516e79b1f..0000000000 --- a/packages/orgs-v5/README.md +++ /dev/null @@ -1,408 +0,0 @@ -Heroku Orgs CLI [![CircleCI](https://circleci.com/gh/heroku/heroku-orgs/tree/master.svg?style=svg)](https://circleci.com/gh/heroku/heroku-orgs/tree/master) -=========== -[![Code Climate](https://codeclimate.com/github/heroku/heroku-orgs/badges/gpa.svg)](https://codeclimate.com/github/heroku/heroku-orgs) -[![npm version](https://badge.fury.io/js/heroku-orgs.svg)](https://badge.fury.io/js/heroku-orgs) -[![License](https://img.shields.io/github/license/heroku/heroku-orgs.svg)](https://github.com/heroku/heroku-orgs/blob/master/LICENSE) - -[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard) - -### Available commands - -https://github.com/heroku/heroku-orgs/blob/master/index.js. - -### Development - -First, please read [Developing CLI Plugins on Heroku's DevCenter](https://devcenter.heroku.com/articles/developing-toolbelt-plug-ins). - -#### Run Tests - -``` -$ npm test -``` - -#### Deploy - -1. Release a new version of this npm package. - - ``` - $ npm version patch/minor/major - ``` - -2. Open a new pr in https://github.com/heroku/cli/blob/master/package.json, updating to the appropriate heroku-orgs version. - -#### Commands - - -* [`heroku access`](#heroku-access) -* [`heroku access:add EMAIL`](#heroku-accessadd-email) -* [`heroku access:remove EMAIL`](#heroku-accessremove-email) -* [`heroku access:update EMAIL`](#heroku-accessupdate-email) -* [`heroku apps:join`](#heroku-appsjoin) -* [`heroku apps:leave`](#heroku-appsleave) -* [`heroku apps:lock`](#heroku-appslock) -* [`heroku apps:transfer RECIPIENT`](#heroku-appstransfer-recipient) -* [`heroku apps:unlock`](#heroku-appsunlock) -* [`heroku join`](#heroku-join) -* [`heroku leave`](#heroku-leave) -* [`heroku lock`](#heroku-lock) -* [`heroku members`](#heroku-members) -* [`heroku members:add EMAIL`](#heroku-membersadd-email) -* [`heroku members:remove EMAIL`](#heroku-membersremove-email) -* [`heroku members:set EMAIL`](#heroku-membersset-email) -* [`heroku orgs`](#heroku-orgs) -* [`heroku orgs:open`](#heroku-orgsopen) -* [`heroku teams`](#heroku-teams) -* [`heroku unlock`](#heroku-unlock) - -## `heroku access` - -list who has access to an app - -``` -USAGE - $ heroku access -a [--json] [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - --json output in json format - -DESCRIPTION - list who has access to an app -``` - -## `heroku access:add EMAIL` - -add new users to your app - -``` -USAGE - $ heroku access:add EMAIL -a [-p ] [-r ] - -FLAGS - -a, --app= (required) app to run command against - -p, --permissions= list of permissions comma separated - -r, --remote= git remote of app to use - -DESCRIPTION - add new users to your app - - -EXAMPLES - $ heroku access:add user@email.com --app APP # add a collaborator to your app - - $ heroku access:add user@email.com --app APP --permissions deploy,manage,operate # permissions must be comma separated -``` - -## `heroku access:remove EMAIL` - -remove users from a team app - -``` -USAGE - $ heroku access:remove EMAIL -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - remove users from a team app - - -EXAMPLES - $ heroku access:remove user@email.com --app APP -``` - -## `heroku access:update EMAIL` - -update existing collaborators on an team app - -``` -USAGE - $ heroku access:update EMAIL -a [-p ] [-r ] - -FLAGS - -a, --app= (required) app to run command against - -p, --permissions= comma-delimited list of permissions to update (deploy,manage,operate) - -r, --remote= git remote of app to use - -DESCRIPTION - update existing collaborators on an team app - - -EXAMPLES - $ heroku access:update user@email.com --app APP --permissions deploy,manage,operate -``` - -## `heroku apps:join` - -add yourself to a team app - -``` -USAGE - $ heroku apps:join -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - add yourself to a team app -``` - -## `heroku apps:leave` - -remove yourself from a team app - -``` -USAGE - $ heroku apps:leave -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - remove yourself from a team app -``` - -## `heroku apps:lock` - -prevent team members from joining an app - -``` -USAGE - $ heroku apps:lock -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - prevent team members from joining an app -``` - -## `heroku apps:transfer RECIPIENT` - -transfer applications to another user or team - -``` -USAGE - $ heroku apps:transfer RECIPIENT [-l] [--bulk] [-a ] [-r ] - -ARGUMENTS - RECIPIENT user or team to transfer applications to - -FLAGS - -a, --app= app to run command against - -l, --locked lock the app upon transfer - -r, --remote= git remote of app to use - --bulk transfer applications in bulk - -DESCRIPTION - transfer applications to another user or team - - -EXAMPLES - $ heroku apps:transfer collaborator@example.com - Transferring example to collaborator@example.com... done - $ heroku apps:transfer acme-widgets - Transferring example to acme-widgets... done - $ heroku apps:transfer --bulk acme-widgets - ... -``` - -## `heroku apps:unlock` - -unlock an app so any team member can join - -``` -USAGE - $ heroku apps:unlock -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - unlock an app so any team member can join -``` - -## `heroku join` - -add yourself to a team app - -``` -USAGE - $ heroku join -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - add yourself to a team app -``` - -## `heroku leave` - -remove yourself from a team app - -``` -USAGE - $ heroku leave -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - remove yourself from a team app -``` - -## `heroku lock` - -prevent team members from joining an app - -``` -USAGE - $ heroku lock -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - prevent team members from joining an app -``` - -## `heroku members` - -list members of a team - -``` -USAGE - $ heroku members [-r ] [--pending] [--json] [-t ] - -FLAGS - -r, --role= filter by role - -t, --team= team to use - --json output in json format - --pending filter by pending team invitations - -DESCRIPTION - list members of a team -``` - -## `heroku members:add EMAIL` - -adds a user to a team - -``` -USAGE - $ heroku members:add EMAIL -r [-t ] - -FLAGS - -r, --role= (required) member role (admin, collaborator, member, owner) - -t, --team= team to use - -DESCRIPTION - adds a user to a team -``` - -## `heroku members:remove EMAIL` - -removes a user from a team - -``` -USAGE - $ heroku members:remove EMAIL [-t ] - -FLAGS - -t, --team= team to use - -DESCRIPTION - removes a user from a team -``` - -## `heroku members:set EMAIL` - -sets a members role in a team - -``` -USAGE - $ heroku members:set EMAIL -r [-t ] - -FLAGS - -r, --role= (required) member role (admin, collaborator, member, owner) - -t, --team= team to use - -DESCRIPTION - sets a members role in a team -``` - -## `heroku orgs` - -list the teams that you are a member of - -``` -USAGE - $ heroku orgs [--json] [--enterprise] - -FLAGS - --enterprise filter by enterprise teams - --json output in json format - -DESCRIPTION - list the teams that you are a member of -``` - -## `heroku orgs:open` - -open the team interface in a browser window - -``` -USAGE - $ heroku orgs:open [-t ] - -FLAGS - -t, --team= team to use - -DESCRIPTION - open the team interface in a browser window -``` - -## `heroku teams` - -list the teams that you are a member of - -``` -USAGE - $ heroku teams [--json] - -FLAGS - --json output in json format - -DESCRIPTION - list the teams that you are a member of - - Use heroku members:* to manage team members. -``` - -## `heroku unlock` - -unlock an app so any team member can join - -``` -USAGE - $ heroku unlock -a [-r ] - -FLAGS - -a, --app= (required) app to run command against - -r, --remote= git remote of app to use - -DESCRIPTION - unlock an app so any team member can join -``` - diff --git a/packages/orgs-v5/commands/apps/lock.js b/packages/orgs-v5/commands/apps/lock.js deleted file mode 100644 index b76eeef02e..0000000000 --- a/packages/orgs-v5/commands/apps/lock.js +++ /dev/null @@ -1,30 +0,0 @@ -'use strict' - -let cli = require('heroku-cli-util') - -async function run(context, heroku) { - let app = await heroku.get(`/teams/apps/${context.app}`) - if (app.locked) { - throw new Error(`Error: cannot lock ${cli.color.cyan(app.name)} -This app is already locked.`) - } - - let request = heroku.request({ - method: 'PATCH', - path: `/teams/apps/${app.name}`, - body: {locked: true}, - }) - await cli.action(`Locking ${cli.color.cyan(app.name)}`, request) -} - -let cmd = { - description: 'prevent team members from joining an app', - needsAuth: true, - needsApp: true, - run: cli.command(run), -} - -module.exports = [ - Object.assign({topic: 'apps', command: 'lock'}, cmd), - Object.assign({topic: 'lock'}, cmd), -] diff --git a/packages/orgs-v5/commands/apps/transfer.js b/packages/orgs-v5/commands/apps/transfer.js deleted file mode 100644 index 6191c3fc51..0000000000 --- a/packages/orgs-v5/commands/apps/transfer.js +++ /dev/null @@ -1,109 +0,0 @@ -'use strict' - -let _ = require('lodash') -let AppTransfer = require('../../lib/app_transfer') -let cli = require('heroku-cli-util') -let inquirer = require('inquirer') -let lock = require('./lock.js')[0] -let Utils = require('../../lib/utils') - -function getAppsToTransfer(apps) { - return inquirer.prompt([{ - type: 'checkbox', - name: 'choices', - pageSize: 20, - message: 'Select applications you would like to transfer', - choices: apps.map(function (app) { - return { - name: `${app.name} (${Utils.getOwner(app.owner.email)})`, - value: {name: app.name, owner: app.owner.email}, - } - }), - }]) -} - -async function run(context, heroku) { - let app = context.app - let recipient = context.args.recipient - - // App transfers in bulk - if (context.flags.bulk) { - let allApps = await heroku.get('/apps') - let selectedApps = await getAppsToTransfer(_.sortBy(allApps, 'name')) - cli.console.error(`Transferring applications to ${cli.color.magenta(recipient)}... -`) - - for (let app of selectedApps.choices) { - try { - let appTransfer = new AppTransfer({ - heroku: heroku, - appName: app.name, - recipient: recipient, - personalToPersonal: Utils.isValidEmail(recipient) && !Utils.isteamApp(app.owner), - bulk: true, - }) - await appTransfer.start() - } catch (error) { - cli.error(error) - } - } - } else { // Single app transfer - let appInfo = await heroku.get(`/apps/${app}`) - - // Shows warning when app is transferred from a team/org to a personal account - if (Utils.isValidEmail(recipient) && Utils.isteamApp(appInfo.owner.email)) { - await cli.confirmApp(app, context.flags.confirm, 'All collaborators will be removed from this app') - } - - let appTransfer = new AppTransfer({ - heroku: heroku, - appName: appInfo.name, - recipient: recipient, - personalToPersonal: Utils.isValidEmail(recipient) && !Utils.isteamApp(appInfo.owner.email), - }) - await appTransfer.start() - - if (context.flags.locked) { - await lock.run(context) - } - } -} - -let cmd = { - topic: 'apps', - command: 'transfer', - description: 'transfer applications to another user or team', - needsAuth: true, - wantsApp: true, - run: cli.command(run), - args: [ - {name: 'recipient', description: 'user or team to transfer applications to'}, - ], - flags: [ - {name: 'locked', char: 'l', hasValue: false, required: false, description: 'lock the app upon transfer'}, - {name: 'bulk', hasValue: false, required: false, description: 'transfer applications in bulk'}, - ], - examples: `$ heroku apps:transfer collaborator@example.com -Transferring example to collaborator@example.com... done - -$ heroku apps:transfer acme-widgets -Transferring example to acme-widgets... done - -$ heroku apps:transfer --bulk acme-widgets -...`, -} - -module.exports = [ - cmd, - { - topic: 'sharing', - command: 'transfer', - help: 'this command is now heroku apps:transfer', - variableArgs: true, - hidden: true, - run: () => { - cli.error(`This command is now ${cli.color.cyan('heroku apps:transfer')}`) - process.exit(1) - }, - }, -] diff --git a/packages/orgs-v5/index.js b/packages/orgs-v5/index.js deleted file mode 100644 index a9dfbc8e68..0000000000 --- a/packages/orgs-v5/index.js +++ /dev/null @@ -1,19 +0,0 @@ -'use strict' - -const flatten = require('lodash.flatten') - -exports.topics = [ - {name: 'access', description: 'manage user access to apps'}, - {name: 'orgs', description: 'manage teams'}, - {name: 'members', description: 'manage team members'}, - {name: 'teams', description: 'manage teams'}, - {name: 'sharing', hidden: true}, - {name: 'join', hidden: true}, - {name: 'leave', hidden: true}, - {name: 'lock', hidden: true}, - {name: 'unlock', hidden: true}, -] - -exports.commands = flatten([ - require('./commands/apps/transfer'), -]) diff --git a/packages/orgs-v5/lib/app_transfer.js b/packages/orgs-v5/lib/app_transfer.js deleted file mode 100644 index a2e4aef963..0000000000 --- a/packages/orgs-v5/lib/app_transfer.js +++ /dev/null @@ -1,53 +0,0 @@ -'use strict' - -let cli = require('heroku-cli-util') - -class AppTransfer { - /** - * @param {Object} options - * @param {Object} options.heroku - instance of heroku-client - * @param {string} options.appName - application that is being transferred - * @param {string} options.recipient - recipient of the transfer - * @param {boolean} options.personalToPersonal - determines if it is a transfer between individual accounts - */ - constructor(opts) { - this.opts = opts - this.heroku = this.opts.heroku - this.appName = this.opts.appName - this.recipient = this.opts.recipient - this.personalToPersonal = this.opts.personalToPersonal - - if (this.personalToPersonal === undefined) this.personalToPersonal = true - - if (this.personalToPersonal) { - this.body = {app: this.appName, recipient: this.recipient} - this.transferMsg = `Initiating transfer of ${cli.color.app(this.appName)}` - if (!this.opts.bulk) this.transferMsg += ` to ${cli.color.magenta(this.recipient)}` - this.path = '/account/app-transfers' - this.method = 'POST' - } else { - this.body = {owner: this.recipient} - this.transferMsg = `Transferring ${cli.color.app(this.appName)}` - if (!this.opts.bulk) this.transferMsg += ` to ${cli.color.magenta(this.recipient)}` - this.path = `/teams/apps/${this.appName}` - this.method = 'PATCH' - } - } - - start() { - let request = this.init().then(request => { - if (request.state === 'pending') cli.action.done('email sent') - }) - return cli.action(this.transferMsg, request) - } - - init() { - return this.heroku.request({ - path: this.path, - method: this.method, - body: this.body, - }) - } -} - -module.exports = AppTransfer diff --git a/packages/orgs-v5/lib/error.js b/packages/orgs-v5/lib/error.js deleted file mode 100644 index 313207401e..0000000000 --- a/packages/orgs-v5/lib/error.js +++ /dev/null @@ -1,37 +0,0 @@ -'use strict' - -var util = require('util') -var cli = require('heroku-cli-util') - -function ErrorExit(code) { - Error.call(this) - Error.captureStackTrace(this, this.constructor) - this.name = this.constructor.name - - this.code = code -} - -util.inherits(ErrorExit, Error) - -var mocking - -function exit(code, message) { - if (message) { - cli.error(message) - } - - if (mocking) { - throw new ErrorExit(code) - } else { - process.exit(code) - } -} - -exit.mock = function () { - mocking = true -} - -module.exports = { - exit, - ErrorExit, -} diff --git a/packages/orgs-v5/lib/utils.js b/packages/orgs-v5/lib/utils.js deleted file mode 100644 index f8357eb69a..0000000000 --- a/packages/orgs-v5/lib/utils.js +++ /dev/null @@ -1,60 +0,0 @@ -let _ = require('lodash') -let cli = require('heroku-cli-util') -let error = require('./error') - -let getOwner = function (owner) { - if (isteamApp(owner)) { - return owner.split('@herokumanager.com')[0] - } - - return owner -} - -let isteamApp = function (owner) { - return (/@herokumanager\.com$/.test(owner)) -} - -let isValidEmail = function (email) { - return /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/.test(email) -} - -// eslint-disable-next-line unicorn/no-object-as-default-parameter -let printGroups = function (group, type = {label: 'Team'}) { - group = _.sortBy(group, 'name') - cli.table(group, { - columns: [ - {key: 'name', label: type.label, format: o => cli.color.green(o)}, - {key: 'role', label: 'Role', format: r => r}, - ], - printHeader: false, - }) -} - -let printGroupsJSON = function (group) { - cli.log(JSON.stringify(group, null, 2)) -} - -let teamInfo = async function (context, heroku) { - let teamName = context.flags.team - if (!teamName) error.exit(1, 'No team or org specified.\nRun this command with --team') - return await heroku.get(`/teams/${teamName}`) -} - -let addMemberToTeam = async function (email, role, groupName, heroku, method = 'PUT') { - let request = heroku.request({ - method: method, - path: `/teams/${groupName}/members`, - body: {email, role}, - }) - await cli.action(`Adding ${cli.color.cyan(email)} to ${cli.color.magenta(groupName)} as ${cli.color.green(role)}`, request) -} - -module.exports = { - addMemberToTeam, - getOwner, - isteamApp, - isValidEmail, - teamInfo, - printGroups, - printGroupsJSON, -} diff --git a/packages/orgs-v5/package.json b/packages/orgs-v5/package.json deleted file mode 100644 index a7d62d53be..0000000000 --- a/packages/orgs-v5/package.json +++ /dev/null @@ -1,84 +0,0 @@ -{ - "name": "@heroku-cli/plugin-orgs-v5", - "description": "CLI to manage Heroku Organizations", - "version": "9.0.0-alpha.0", - "author": "Raul Barroso @raulb", - "bugs": "https://github.com/heroku/cli/issues", - "cli-engine": { - "bin": "heroku", - "topics": { - "access": { - "description": "manage user access to apps" - }, - "orgs": { - "description": "manage organizations" - }, - "members": { - "description": "manage organization members" - }, - "teams": { - "description": "manage teams" - }, - "sharing": { - "hidden": true - }, - "join": { - "hidden": true - }, - "leave": { - "hidden": true - }, - "lock": { - "hidden": true - }, - "unlock": { - "hidden": true - } - }, - "repositoryPrefix": "<%- repo %>/blob/v<%- version %>/packages/orgs-v5/<%- commandPath %>" - }, - "dependencies": { - "@heroku-cli/command": "^9.0.2", - "heroku-cli-util": "^8.0.11", - "inquirer": "^8.2.6", - "lodash": "^4.17.21", - "lodash.flatten": "^4.4.0" - }, - "devDependencies": { - "@oclif/plugin-legacy": "^1.3.0", - "chai": "^4.2.0", - "mocha": "^9.2.2", - "nock": "^10.0.6", - "nyc": "^15.1.0", - "oclif": "3.11.3", - "proxyquire": "^2.1.0", - "sinon": "^6.3.5" - }, - "files": [ - "oclif.manifest.json", - "index.js", - "commands", - "lib" - ], - "homepage": "https://github.com/heroku/cli/tree/main/packages/orgs-v5", - "keywords": [ - "heroku-plugin" - ], - "license": "ISC", - "main": "index.js", - "mocha": { - "require": [ - "./test/helpers.js" - ], - "recursive": true, - "timeout": 360000 - }, - "repository": "heroku/cli", - "scripts": { - "lint": "eslint . --ext .js --config ../../.eslintrc --ignore-path ../../.eslintignore", - "postpublish": "rm oclif.manifest.json", - "prepack": "oclif manifest", - "test": "nyc mocha ./test/**/*.unit.test.js && yarn lint", - "version": "oclif readme && git add README.md" - } -} diff --git a/packages/orgs-v5/test/assert_exit.js b/packages/orgs-v5/test/assert_exit.js deleted file mode 100644 index 3f00a83cb5..0000000000 --- a/packages/orgs-v5/test/assert_exit.js +++ /dev/null @@ -1,17 +0,0 @@ -'use strict' - -let expect = require('chai').expect -let ErrorExit = require('../lib/error.js').ErrorExit - -function assertErrorExit(code, gen) { - var actual - return gen.catch(function (error) { - expect(error).to.be.an.instanceof(ErrorExit) - actual = error.code - }).then(function () { - expect(actual).to.be.an('number', 'Expected error.exit(i) to be called with a number') - expect(actual).to.equal(code) - }) -} - -module.exports = assertErrorExit diff --git a/packages/orgs-v5/test/helpers.js b/packages/orgs-v5/test/helpers.js deleted file mode 100644 index cfbca46460..0000000000 --- a/packages/orgs-v5/test/helpers.js +++ /dev/null @@ -1,15 +0,0 @@ -'use strict' -/* globals nock cli */ - -global.apikey = process.env.HEROKU_API_KEY -global.columns = 80 -global.cli = require('heroku-cli-util') -global.expect = require('chai').expect -global.nock = require('nock') -cli.raiseErrors = true -cli.color.enabled = false -nock.disableNetConnect() - -if (process.env.ENABLE_NET_CONNECT === 'true') { - nock.enableNetConnect() -} diff --git a/packages/orgs-v5/test/unit/commands/apps/transfer.unit.test.js b/packages/orgs-v5/test/unit/commands/apps/transfer.unit.test.js deleted file mode 100644 index 1591a3cd23..0000000000 --- a/packages/orgs-v5/test/unit/commands/apps/transfer.unit.test.js +++ /dev/null @@ -1,145 +0,0 @@ -'use strict' -/* globals beforeEach afterEach cli nock context expect */ - -let cmd -let inquirer = {} -let stubGet = require('../../stub/get') -let stubPost = require('../../stub/post') -let stubPatch = require('../../stub/patch') -let proxyquire = require('proxyquire').noCallThru() - -describe('heroku apps:transfer', () => { - beforeEach(() => { - cli.mockConsole() - inquirer = {} - cmd = proxyquire('../../../../commands/apps/transfer', {inquirer})[0] - }) - - afterEach(() => nock.cleanAll()) - - context('when transferring in bulk', () => { - beforeEach(() => { - stubGet.apps() - }) - - it('transfers selected apps to a team', () => { - inquirer.prompt = prompts => { - let choices = prompts[0].choices - expect(choices).to.eql([ - { - name: 'my-team-app (team)', - value: {name: 'my-team-app', owner: 'team@herokumanager.com'}, - }, - { - name: 'myapp (foo@foo.com)', - value: {name: 'myapp', owner: 'foo@foo.com'}, - }, - ]) - return Promise.resolve({choices: [{name: 'myapp', owner: 'foo@foo.com'}]}) - } - - let api = stubPatch.teamAppTransfer() - return cmd.run({args: {recipient: 'team'}, flags: {bulk: true}}) - .then(function () { - api.done() - expect(cli.stderr).to.equal(`Transferring applications to team... - -Transferring myapp... done -`) - }) - }) - - it('transfers selected apps to a personal account', () => { - inquirer.prompt = prompts => { - let choices = prompts[0].choices - expect(choices).to.eql([ - { - name: 'my-team-app (team)', - value: {name: 'my-team-app', owner: 'team@herokumanager.com'}, - }, - { - name: 'myapp (foo@foo.com)', - value: {name: 'myapp', owner: 'foo@foo.com'}, - }, - ]) - return Promise.resolve({choices: [{name: 'myapp', owner: 'foo@foo.com'}]}) - } - - let api = stubPost.personalToPersonal() - return cmd.run({args: {recipient: 'raulb@heroku.com'}, flags: {bulk: true}}) - .then(function () { - api.done() - expect(cli.stderr).to.equal(`Transferring applications to raulb@heroku.com... - -Initiating transfer of myapp... email sent -`) - }) - }) - }) - - context('when it is a personal app', () => { - beforeEach(() => { - stubGet.personalApp() - }) - - it('transfers the app to a personal account', () => { - let api = stubPost.personalToPersonal() - return cmd.run({app: 'myapp', args: {recipient: 'raulb@heroku.com'}, flags: {}}) - .then(() => expect('').to.eq(cli.stdout)) - .then(() => expect(`Initiating transfer of myapp to raulb@heroku.com... email sent -`).to.eq(cli.stderr)) - .then(() => api.done()) - }) - - it('transfers the app to a team', () => { - let api = stubPatch.teamAppTransfer() - return cmd.run({app: 'myapp', args: {recipient: 'team'}, flags: {}}) - .then(() => expect('').to.eq(cli.stdout)) - .then(() => expect(`Transferring myapp to team... done -`).to.eq(cli.stderr)) - .then(() => api.done()) - }) - }) - - context('when it is an org app', () => { - beforeEach(() => { - stubGet.teamApp() - }) - - it('transfers the app to a personal account confirming app name', () => { - let api = stubPatch.teamAppTransfer() - return cmd.run({app: 'myapp', args: {recipient: 'team'}, flags: {confirm: 'myapp'}}) - .then(() => expect('').to.eq(cli.stdout)) - .then(() => expect(`Transferring myapp to team... done -`).to.eq(cli.stderr)) - .then(() => api.done()) - }) - - it('transfers the app to a team', () => { - let api = stubPatch.teamAppTransfer() - return cmd.run({app: 'myapp', args: {recipient: 'team'}, flags: {}}) - .then(() => expect('').to.eq(cli.stdout)) - .then(() => expect(`Transferring myapp to team... done -`).to.eq(cli.stderr)) - .then(() => api.done()) - }) - - it('transfers and locks the app if --locked is passed', () => { - let api = stubPatch.teamAppTransfer() - - let lockedAPI = nock('https://api.heroku.com:443') - .get('/teams/apps/myapp') - .reply(200, {name: 'myapp', locked: false}) - .patch('/teams/apps/myapp', {locked: true}) - .reply(200) - - return cmd.run({app: 'myapp', args: {recipient: 'team'}, flags: {locked: true}}) - .then(() => expect('').to.eq(cli.stdout)) - .then(() => expect(`Transferring myapp to team... done -Locking myapp... done -`).to.eq(cli.stderr)) - .then(() => api.done()) - .then(() => lockedAPI.done()) - }) - }) -}) diff --git a/packages/orgs-v5/test/unit/stub/get.js b/packages/orgs-v5/test/unit/stub/get.js deleted file mode 100644 index 286a1c7bdf..0000000000 --- a/packages/orgs-v5/test/unit/stub/get.js +++ /dev/null @@ -1,93 +0,0 @@ -'use strict' - -const nock = require('nock') - -function apps() { - return nock('https://api.heroku.com:443') - .get('/apps') - .reply(200, [ - {name: 'my-team-app', owner: {email: 'team@herokumanager.com'}}, - {name: 'myapp', owner: {email: 'foo@foo.com'}}, - ]) -} - -function teams(teams = [ - {name: 'enterprise a', role: 'collaborator', type: 'enterprise'}, - {name: 'team a', role: 'collaborator', type: 'team'}, - {name: 'enterprise b', role: 'admin', type: 'enterprise'}, - {name: 'team b', role: 'admin', type: 'team'}, -]) { - return nock('https://api.heroku.com:443') - .get('/teams') - .reply(200, teams) -} - -function teamApp(locked = false) { - return nock('https://api.heroku.com:443') - .get('/apps/myapp') - .reply(200, { - name: 'myapp', - owner: {email: 'myteam@herokumanager.com'}, - locked: locked, - }) -} - -function teamFeatures(features) { - return nock('https://api.heroku.com:443', { - reqheaders: {Accept: 'application/vnd.heroku+json; version=3'}, - }) - .get('/teams/myteam/features') - .reply(200, features) -} - -function teamInfo(type = 'enterprise') { - return nock('https://api.heroku.com:443', { - reqheaders: {Accept: 'application/vnd.heroku+json; version=3'}, - }) - .get('/teams/myteam') - .reply(200, { - name: 'myteam', - role: 'admin', - type: type, - }) -} - -function teamInvites(invites = [ - { - invited_by: {email: 'raulb@heroku.com'}, - role: 'admin', - user: {email: 'invited-user@mail.com'}, - }, -]) { - return nock('https://api.heroku.com:443', { - reqheaders: {Accept: 'application/vnd.heroku+json; version=3.team-invitations'}, - }) - .get('/teams/myteam/invitations') - .reply(200, invites) -} - -function personalApp() { - return nock('https://api.heroku.com:443') - .get('/apps/myapp') - .reply(200, { - name: 'myapp', - owner: {email: 'raulb@heroku.com'}, - }) -} - -function userAccount(email = 'raulb@heroku.com') { - return nock('https://api.heroku.com:443') - .get('/account') - .reply(200, {email}) -} - -module.exports = { - apps, - personalApp, - teamApp, - teamFeatures, - teamInfo, - teamInvites, - teams, - userAccount, -} diff --git a/packages/orgs-v5/test/unit/stub/patch.js b/packages/orgs-v5/test/unit/stub/patch.js deleted file mode 100644 index 86f096746c..0000000000 --- a/packages/orgs-v5/test/unit/stub/patch.js +++ /dev/null @@ -1,20 +0,0 @@ -'use strict' - -const nock = require('nock') - -function teamAppTransfer() { - return nock('https://api.heroku.com:443') - .patch('/teams/apps/myapp', {owner: 'team'}) - .reply(200, {name: 'myapp', owner: {email: 'team@herokumanager.com'}}) -} - -function personalToPersonal() { - return nock('https://api.heroku.com:443') - .patch('/teams/apps/myapp', {owner: 'raulb@heroku.com'}) - .reply(200, {name: 'myapp', owner: {email: 'raulb@heroku.com'}}) -} - -module.exports = { - teamAppTransfer, - personalToPersonal, -} diff --git a/packages/orgs-v5/test/unit/stub/post.js b/packages/orgs-v5/test/unit/stub/post.js deleted file mode 100644 index f5d112de19..0000000000 --- a/packages/orgs-v5/test/unit/stub/post.js +++ /dev/null @@ -1,34 +0,0 @@ -'use strict' - -const nock = require('nock') - -function collaborators() { - return nock('https://api.heroku.com:443') - .post('/apps/myapp/collaborators', { - user: 'raulb@heroku.com', - }).reply(200) -} - -function teamAppCollaborators(email = 'raulb@heroku.com', permissions = []) { - let body = {user: email} - if (permissions.length > 0) { - body.permissions = permissions - } - - return nock('https://api.heroku.com:443', { - reqheaders: {Accept: 'application/vnd.heroku+json; version=3'}, - }) - .post('/teams/apps/myapp/collaborators', body).reply(200) -} - -function personalToPersonal() { - return nock('https://api.heroku.com:443') - .post('/account/app-transfers', {app: 'myapp', recipient: 'raulb@heroku.com'}) - .reply(200, {state: 'pending'}) -} - -module.exports = { - collaborators, - personalToPersonal, - teamAppCollaborators, -} diff --git a/packages/orgs-v5/test/unwrap.js b/packages/orgs-v5/test/unwrap.js deleted file mode 100644 index be2a2e01b2..0000000000 --- a/packages/orgs-v5/test/unwrap.js +++ /dev/null @@ -1,10 +0,0 @@ -'use strict' - -function unwrap(str) { - let sanitize = str.replace(/\n ([▸!]) {3}/g, '') - sanitize = sanitize.replace(/ ([▸!]) {4}/g, '') - - return sanitize -} - -module.exports = unwrap From d6169f9649c69a169d3c786a4c96132ca536037f Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Thu, 4 Apr 2024 15:09:15 -0400 Subject: [PATCH 19/20] fix: update yarn.lock --- yarn.lock | 163 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 85 insertions(+), 78 deletions(-) diff --git a/yarn.lock b/yarn.lock index 670faf6ad5..ac6eae2f46 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1322,25 +1322,18 @@ __metadata: languageName: unknown linkType: soft -"@heroku-cli/plugin-orgs-v5@^9.0.0-alpha.0, @heroku-cli/plugin-orgs-v5@workspace:packages/orgs-v5": - version: 0.0.0-use.local - resolution: "@heroku-cli/plugin-orgs-v5@workspace:packages/orgs-v5" +"@heroku-cli/plugin-orgs-v5@npm:^9.0.0-alpha.0": + version: 9.0.0-dev.0 + resolution: "@heroku-cli/plugin-orgs-v5@npm:9.0.0-dev.0" dependencies: "@heroku-cli/command": ^9.0.2 - "@oclif/plugin-legacy": ^1.3.0 - chai: ^4.2.0 heroku-cli-util: ^8.0.11 - inquirer: ^8.2.6 - lodash: ^4.17.21 + inquirer: ^6.2.2 + lodash: ^4.17.11 lodash.flatten: ^4.4.0 - mocha: ^9.2.2 - nock: ^10.0.6 - nyc: ^15.1.0 - oclif: 3.11.3 - proxyquire: ^2.1.0 - sinon: ^6.3.5 - languageName: unknown - linkType: soft + checksum: 87ae8c2279defa09983a4f7a7248ef1a8862cdc142fa3d93669ac66ae9e850a3d8efc534a70054fb8c866cfbc7790f392544de5454c2a4d4bb6030a0b9007326 + languageName: node + linkType: hard "@heroku-cli/plugin-pg-v5@^9.0.0-alpha.0, @heroku-cli/plugin-pg-v5@workspace:packages/pg-v5": version: 0.0.0-use.local @@ -4319,15 +4312,6 @@ __metadata: languageName: node linkType: hard -"@sinonjs/formatio@npm:^3.0.0": - version: 3.1.0 - resolution: "@sinonjs/formatio@npm:3.1.0" - dependencies: - "@sinonjs/samsam": ^2 || ^3 - checksum: 31368e66a8b1ec0ab2b7233d7e5227877ff22c319adbe0f75b501b227c33a535cac8938e6df13a29d80ae7b83ecbe72d53e2dceb88b51823e23d375e570d9bcb - languageName: node - linkType: hard - "@sinonjs/formatio@npm:^3.2.1": version: 3.2.1 resolution: "@sinonjs/formatio@npm:3.2.1" @@ -4338,24 +4322,6 @@ __metadata: languageName: node linkType: hard -"@sinonjs/samsam@npm:^2 || ^3": - version: 3.1.0 - resolution: "@sinonjs/samsam@npm:3.1.0" - dependencies: - "@sinonjs/commons": ^1.0.2 - array-from: ^2.1.1 - lodash.get: ^4.4.2 - checksum: 7dd2789727a59edc4f2faeea9292dc6bd4c6f4e81d1603ee1929494aaa0a8abc6f86ec689ac3ed50e0731665848e1274bcfb2dc361b5a06f831e1f4f393998ec - languageName: node - linkType: hard - -"@sinonjs/samsam@npm:^2.1.2": - version: 2.1.3 - resolution: "@sinonjs/samsam@npm:2.1.3" - checksum: 4abc77d3c5f69dd0dd0c1139a8f8ee0026771dda9ae083e72f25717f43bff038bfded5f19a24c6ecef39f4809bc8acd8edcf5179a242bc8aa5d90f542d99d362 - languageName: node - linkType: hard - "@sinonjs/samsam@npm:^3.1.0, @sinonjs/samsam@npm:^3.3.2": version: 3.3.2 resolution: "@sinonjs/samsam@npm:3.3.2" @@ -5984,7 +5950,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:3.2.0, ansi-escapes@npm:^3.1.0": +"ansi-escapes@npm:3.2.0, ansi-escapes@npm:^3.1.0, ansi-escapes@npm:^3.2.0": version: 3.2.0 resolution: "ansi-escapes@npm:3.2.0" checksum: 0f94695b677ea742f7f1eed961f7fd8d05670f744c6ad1f8f635362f6681dcfbc1575cb05b43abc7bb6d67e25a75fb8c7ea8f2a57330eb2c76b33f18cb2cef0a @@ -7190,6 +7156,15 @@ __metadata: languageName: node linkType: hard +"cli-cursor@npm:^2.1.0": + version: 2.1.0 + resolution: "cli-cursor@npm:2.1.0" + dependencies: + restore-cursor: ^2.0.0 + checksum: d88e97bfdac01046a3ffe7d49f06757b3126559d7e44aa2122637eb179284dc6cd49fca2fac4f67c19faaf7e6dab716b6fe1dfcd309977407d8c7578ec2d044d + languageName: node + linkType: hard + "cli-progress@npm:^3.10.0, cli-progress@npm:^3.11.2, cli-progress@npm:^3.12.0": version: 3.12.0 resolution: "cli-progress@npm:3.12.0" @@ -9587,6 +9562,15 @@ __metadata: languageName: node linkType: hard +"figures@npm:^2.0.0": + version: 2.0.0 + resolution: "figures@npm:2.0.0" + dependencies: + escape-string-regexp: ^1.0.5 + checksum: 081beb16ea57d1716f8447c694f637668322398b57017b20929376aaf5def9823b35245b734cdd87e4832dc96e9c6f46274833cada77bfe15e5f980fea1fd21f + languageName: node + linkType: hard + "figures@npm:^3.0.0": version: 3.0.0 resolution: "figures@npm:3.0.0" @@ -11480,6 +11464,27 @@ __metadata: languageName: node linkType: hard +"inquirer@npm:^6.2.2": + version: 6.5.2 + resolution: "inquirer@npm:6.5.2" + dependencies: + ansi-escapes: ^3.2.0 + chalk: ^2.4.2 + cli-cursor: ^2.1.0 + cli-width: ^2.0.0 + external-editor: ^3.0.3 + figures: ^2.0.0 + lodash: ^4.17.12 + mute-stream: 0.0.7 + run-async: ^2.2.0 + rxjs: ^6.4.0 + string-width: ^2.1.0 + strip-ansi: ^5.1.0 + through: ^2.3.6 + checksum: 175ad4cd1ebed493b231b240185f1da5afeace5f4e8811dfa83cf55dcae59c3255eaed990aa71871b0fd31aa9dc212f43c44c50ed04fb529364405e72f484d28 + languageName: node + linkType: hard + "inquirer@npm:^7.0.0": version: 7.0.0 resolution: "inquirer@npm:7.0.0" @@ -12874,13 +12879,6 @@ __metadata: languageName: node linkType: hard -"lodash.get@npm:^4.4.2": - version: 4.4.2 - resolution: "lodash.get@npm:4.4.2" - checksum: e403047ddb03181c9d0e92df9556570e2b67e0f0a930fcbbbd779370972368f5568e914f913e93f3b08f6d492abc71e14d4e9b7a18916c31fa04bd2306efe545 - languageName: node - linkType: hard - "lodash.ismatch@npm:^4.4.0": version: 4.4.0 resolution: "lodash.ismatch@npm:4.4.0" @@ -12949,7 +12947,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.5": +"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.5": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -12989,13 +12987,6 @@ __metadata: languageName: node linkType: hard -"lolex@npm:^2.7.5": - version: 2.7.5 - resolution: "lolex@npm:2.7.5" - checksum: 25a0bc7487e76748bff5c0baf6ac7040dded620f76daef9f7d829e3aa0cf6126195c993b05b147b3e32720097def6bf3985d3f8ecbfb654300a878dceb963c7f - languageName: node - linkType: hard - "lolex@npm:^3.1.0": version: 3.1.0 resolution: "lolex@npm:3.1.0" @@ -13364,6 +13355,13 @@ __metadata: languageName: node linkType: hard +"mimic-fn@npm:^1.0.0": + version: 1.2.0 + resolution: "mimic-fn@npm:1.2.0" + checksum: 69c08205156a1f4906d9c46f9b4dc08d18a50176352e77fdeb645cedfe9f20c0b19865d465bd2dec27a5c432347f24dc07fc3695e11159d193f892834233e939 + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -13772,6 +13770,13 @@ __metadata: languageName: node linkType: hard +"mute-stream@npm:0.0.7": + version: 0.0.7 + resolution: "mute-stream@npm:0.0.7" + checksum: a9d4772c1c84206aa37c218ed4751cd060239bf1d678893124f51e037f6f22f4a159b2918c030236c93252638a74beb29c9b1fd3267c9f24d4b3253cf1eaa86f + languageName: node + linkType: hard + "mute-stream@npm:0.0.8, mute-stream@npm:~0.0.4": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -13881,7 +13886,7 @@ __metadata: languageName: node linkType: hard -"nise@npm:^1.4.5, nise@npm:^1.5.1": +"nise@npm:^1.5.1": version: 1.5.3 resolution: "nise@npm:1.5.3" dependencies: @@ -14818,6 +14823,15 @@ __metadata: languageName: node linkType: hard +"onetime@npm:^2.0.0": + version: 2.0.1 + resolution: "onetime@npm:2.0.1" + dependencies: + mimic-fn: ^1.0.0 + checksum: bb44015ac7a525d0fb43b029a583d4ad359834632b4424ca209b438aacf6d669dda81b5edfbdb42c22636e607b276ba5589f46694a729e3bc27948ce26f4cc1a + languageName: node + linkType: hard + "onetime@npm:^5.1.0, onetime@npm:^5.1.2": version: 5.1.2 resolution: "onetime@npm:5.1.2" @@ -16570,6 +16584,16 @@ __metadata: languageName: node linkType: hard +"restore-cursor@npm:^2.0.0": + version: 2.0.0 + resolution: "restore-cursor@npm:2.0.0" + dependencies: + onetime: ^2.0.0 + signal-exit: ^3.0.2 + checksum: 482e13d02d834b6e5e3aa90304a8b5e840775d6f06916cc92a50038adf9f098dcc72405b567da8a37e137ae40ad3e31896fa3136ae62f7a426c2fbf53d036536 + languageName: node + linkType: hard + "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -17177,23 +17201,6 @@ __metadata: languageName: node linkType: hard -"sinon@npm:^6.3.5": - version: 6.3.5 - resolution: "sinon@npm:6.3.5" - dependencies: - "@sinonjs/commons": ^1.0.2 - "@sinonjs/formatio": ^3.0.0 - "@sinonjs/samsam": ^2.1.2 - diff: ^3.5.0 - lodash.get: ^4.4.2 - lolex: ^2.7.5 - nise: ^1.4.5 - supports-color: ^5.5.0 - type-detect: ^4.0.8 - checksum: e477bce307937d355ec5d063ed259ee8e302b0b7adc5056e4993c5354181b9c7d89194037b63a9db7bf6a1372cb6f5a58cafff7ce9154a8c8f2c0ecbb1ac5765 - languageName: node - linkType: hard - "sinon@npm:^7.2.3, sinon@npm:^7.2.4": version: 7.4.1 resolution: "sinon@npm:7.4.1" @@ -17630,7 +17637,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^2.0.0": +"string-width@npm:^2.0.0, string-width@npm:^2.1.0": version: 2.1.1 resolution: "string-width@npm:2.1.1" dependencies: @@ -18493,7 +18500,7 @@ __metadata: languageName: node linkType: hard -"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5, type-detect@npm:^4.0.8": +"type-detect@npm:4.0.8, type-detect@npm:^4.0.0, type-detect@npm:^4.0.5": version: 4.0.8 resolution: "type-detect@npm:4.0.8" checksum: 62b5628bff67c0eb0b66afa371bd73e230399a8d2ad30d852716efcc4656a7516904570cd8631a49a3ce57c10225adf5d0cbdcb47f6b0255fe6557c453925a15 From b273ffbdad73cdb47bdb3825daa50a1cab68b6da Mon Sep 17 00:00:00 2001 From: Katy Bowman Date: Mon, 8 Apr 2024 14:28:48 -0400 Subject: [PATCH 20/20] refactor: remove import of orgs-v5 plugin from cli --- packages/cli/package.json | 2 - yarn.lock | 92 ++------------------------------------- 2 files changed, 3 insertions(+), 91 deletions(-) diff --git a/packages/cli/package.json b/packages/cli/package.json index a288f462bb..25d3f87e21 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -12,7 +12,6 @@ "@heroku-cli/notifications": "^1.2.4", "@heroku-cli/plugin-certs-v5": "^9.0.0-alpha.0", "@heroku-cli/plugin-ci-v5": "^9.0.0-alpha.0", - "@heroku-cli/plugin-orgs-v5": "^9.0.0-alpha.0", "@heroku-cli/plugin-pg-v5": "^9.0.0-alpha.0", "@heroku-cli/plugin-ps": "^8.1.7", "@heroku-cli/plugin-ps-exec": "^2.4.0", @@ -182,7 +181,6 @@ "plugins": [ "@oclif/plugin-legacy", "@heroku-cli/plugin-certs-v5", - "@heroku-cli/plugin-orgs-v5", "@heroku-cli/plugin-pg-v5", "@heroku-cli/plugin-ps-exec", "@heroku-cli/plugin-spaces", diff --git a/yarn.lock b/yarn.lock index ac6eae2f46..66438132dd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1322,19 +1322,6 @@ __metadata: languageName: unknown linkType: soft -"@heroku-cli/plugin-orgs-v5@npm:^9.0.0-alpha.0": - version: 9.0.0-dev.0 - resolution: "@heroku-cli/plugin-orgs-v5@npm:9.0.0-dev.0" - dependencies: - "@heroku-cli/command": ^9.0.2 - heroku-cli-util: ^8.0.11 - inquirer: ^6.2.2 - lodash: ^4.17.11 - lodash.flatten: ^4.4.0 - checksum: 87ae8c2279defa09983a4f7a7248ef1a8862cdc142fa3d93669ac66ae9e850a3d8efc534a70054fb8c866cfbc7790f392544de5454c2a4d4bb6030a0b9007326 - languageName: node - linkType: hard - "@heroku-cli/plugin-pg-v5@^9.0.0-alpha.0, @heroku-cli/plugin-pg-v5@workspace:packages/pg-v5": version: 0.0.0-use.local resolution: "@heroku-cli/plugin-pg-v5@workspace:packages/pg-v5" @@ -5950,7 +5937,7 @@ __metadata: languageName: node linkType: hard -"ansi-escapes@npm:3.2.0, ansi-escapes@npm:^3.1.0, ansi-escapes@npm:^3.2.0": +"ansi-escapes@npm:3.2.0, ansi-escapes@npm:^3.1.0": version: 3.2.0 resolution: "ansi-escapes@npm:3.2.0" checksum: 0f94695b677ea742f7f1eed961f7fd8d05670f744c6ad1f8f635362f6681dcfbc1575cb05b43abc7bb6d67e25a75fb8c7ea8f2a57330eb2c76b33f18cb2cef0a @@ -7156,15 +7143,6 @@ __metadata: languageName: node linkType: hard -"cli-cursor@npm:^2.1.0": - version: 2.1.0 - resolution: "cli-cursor@npm:2.1.0" - dependencies: - restore-cursor: ^2.0.0 - checksum: d88e97bfdac01046a3ffe7d49f06757b3126559d7e44aa2122637eb179284dc6cd49fca2fac4f67c19faaf7e6dab716b6fe1dfcd309977407d8c7578ec2d044d - languageName: node - linkType: hard - "cli-progress@npm:^3.10.0, cli-progress@npm:^3.11.2, cli-progress@npm:^3.12.0": version: 3.12.0 resolution: "cli-progress@npm:3.12.0" @@ -9562,15 +9540,6 @@ __metadata: languageName: node linkType: hard -"figures@npm:^2.0.0": - version: 2.0.0 - resolution: "figures@npm:2.0.0" - dependencies: - escape-string-regexp: ^1.0.5 - checksum: 081beb16ea57d1716f8447c694f637668322398b57017b20929376aaf5def9823b35245b734cdd87e4832dc96e9c6f46274833cada77bfe15e5f980fea1fd21f - languageName: node - linkType: hard - "figures@npm:^3.0.0": version: 3.0.0 resolution: "figures@npm:3.0.0" @@ -10936,7 +10905,6 @@ __metadata: "@heroku-cli/notifications": ^1.2.4 "@heroku-cli/plugin-certs-v5": ^9.0.0-alpha.0 "@heroku-cli/plugin-ci-v5": ^9.0.0-alpha.0 - "@heroku-cli/plugin-orgs-v5": ^9.0.0-alpha.0 "@heroku-cli/plugin-pg-v5": ^9.0.0-alpha.0 "@heroku-cli/plugin-ps": ^8.1.7 "@heroku-cli/plugin-ps-exec": ^2.4.0 @@ -11464,27 +11432,6 @@ __metadata: languageName: node linkType: hard -"inquirer@npm:^6.2.2": - version: 6.5.2 - resolution: "inquirer@npm:6.5.2" - dependencies: - ansi-escapes: ^3.2.0 - chalk: ^2.4.2 - cli-cursor: ^2.1.0 - cli-width: ^2.0.0 - external-editor: ^3.0.3 - figures: ^2.0.0 - lodash: ^4.17.12 - mute-stream: 0.0.7 - run-async: ^2.2.0 - rxjs: ^6.4.0 - string-width: ^2.1.0 - strip-ansi: ^5.1.0 - through: ^2.3.6 - checksum: 175ad4cd1ebed493b231b240185f1da5afeace5f4e8811dfa83cf55dcae59c3255eaed990aa71871b0fd31aa9dc212f43c44c50ed04fb529364405e72f484d28 - languageName: node - linkType: hard - "inquirer@npm:^7.0.0": version: 7.0.0 resolution: "inquirer@npm:7.0.0" @@ -12947,7 +12894,7 @@ __metadata: languageName: node linkType: hard -"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.12, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.5": +"lodash@npm:^4.17.10, lodash@npm:^4.17.11, lodash@npm:^4.17.13, lodash@npm:^4.17.14, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.17.5": version: 4.17.21 resolution: "lodash@npm:4.17.21" checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 @@ -13355,13 +13302,6 @@ __metadata: languageName: node linkType: hard -"mimic-fn@npm:^1.0.0": - version: 1.2.0 - resolution: "mimic-fn@npm:1.2.0" - checksum: 69c08205156a1f4906d9c46f9b4dc08d18a50176352e77fdeb645cedfe9f20c0b19865d465bd2dec27a5c432347f24dc07fc3695e11159d193f892834233e939 - languageName: node - linkType: hard - "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -13770,13 +13710,6 @@ __metadata: languageName: node linkType: hard -"mute-stream@npm:0.0.7": - version: 0.0.7 - resolution: "mute-stream@npm:0.0.7" - checksum: a9d4772c1c84206aa37c218ed4751cd060239bf1d678893124f51e037f6f22f4a159b2918c030236c93252638a74beb29c9b1fd3267c9f24d4b3253cf1eaa86f - languageName: node - linkType: hard - "mute-stream@npm:0.0.8, mute-stream@npm:~0.0.4": version: 0.0.8 resolution: "mute-stream@npm:0.0.8" @@ -14823,15 +14756,6 @@ __metadata: languageName: node linkType: hard -"onetime@npm:^2.0.0": - version: 2.0.1 - resolution: "onetime@npm:2.0.1" - dependencies: - mimic-fn: ^1.0.0 - checksum: bb44015ac7a525d0fb43b029a583d4ad359834632b4424ca209b438aacf6d669dda81b5edfbdb42c22636e607b276ba5589f46694a729e3bc27948ce26f4cc1a - languageName: node - linkType: hard - "onetime@npm:^5.1.0, onetime@npm:^5.1.2": version: 5.1.2 resolution: "onetime@npm:5.1.2" @@ -16584,16 +16508,6 @@ __metadata: languageName: node linkType: hard -"restore-cursor@npm:^2.0.0": - version: 2.0.0 - resolution: "restore-cursor@npm:2.0.0" - dependencies: - onetime: ^2.0.0 - signal-exit: ^3.0.2 - checksum: 482e13d02d834b6e5e3aa90304a8b5e840775d6f06916cc92a50038adf9f098dcc72405b567da8a37e137ae40ad3e31896fa3136ae62f7a426c2fbf53d036536 - languageName: node - linkType: hard - "restore-cursor@npm:^3.1.0": version: 3.1.0 resolution: "restore-cursor@npm:3.1.0" @@ -17637,7 +17551,7 @@ __metadata: languageName: node linkType: hard -"string-width@npm:^2.0.0, string-width@npm:^2.1.0": +"string-width@npm:^2.0.0": version: 2.1.1 resolution: "string-width@npm:2.1.1" dependencies: