From b08441ec0e944352554987c4078b3e99b89bf9cc Mon Sep 17 00:00:00 2001 From: Devin Sag Date: Tue, 23 Aug 2022 13:39:49 -0400 Subject: [PATCH 1/4] update Flag.boolean to booleanString --- src/base-command.ts | 12 ++++++++++++ src/commands/deploy.ts | 22 +++++++++++----------- src/commands/dev.ts | 15 ++++++++------- src/commands/environments/destroy.ts | 10 ++++++---- src/commands/exec.ts | 9 ++++----- src/commands/logs.ts | 7 ++++--- src/commands/platforms/create.ts | 9 +++++++-- src/commands/platforms/destroy.ts | 10 ++++++---- src/commands/secrets/upload.ts | 4 ++-- src/commands/task.ts | 4 +++- src/commands/unlink.ts | 5 +++-- src/common/utils/oclif.ts | 9 ++++++++- 12 files changed, 74 insertions(+), 42 deletions(-) diff --git a/src/base-command.ts b/src/base-command.ts index e3531d224..52ac74422 100644 --- a/src/base-command.ts +++ b/src/base-command.ts @@ -5,6 +5,7 @@ import { ValidationErrors } from '.'; import AppService from './app-config/service'; import { prettyValidationErrors } from './common/dependency-manager/validation'; import LoginRequiredError from './common/errors/login-required'; +import { isBooleanStringFlag } from './common/utils/oclif'; import SentryService from './sentry'; const DEPRECATED_LABEL = '[deprecated]'; @@ -78,7 +79,18 @@ export default abstract class BaseCommand extends Command { const args = []; const flags = []; let flag_option = false; + + const new_args = []; for (const arg of argv) { + if (!arg.startsWith('-')) { + new_args.push(arg); + } else { + const flag = arg.startsWith('--') ? flag_definitions[arg.replace('--', '')] : Object.values(flag_definitions).find((f: any) => f.char === arg.replace('-', '')); + new_args.push(isBooleanStringFlag(flag) ? `${arg}=true` : arg); + } + } + + for (const arg of new_args) { const is_flag = arg.startsWith('-'); if (is_flag || flag_option) { diff --git a/src/commands/deploy.ts b/src/commands/deploy.ts index 40865d3af..c0be8b39d 100644 --- a/src/commands/deploy.ts +++ b/src/commands/deploy.ts @@ -8,6 +8,7 @@ import PipelineUtils from '../architect/pipeline/pipeline.utils'; import BaseCommand from '../base-command'; import { DeploymentFailedError, PipelineAbortedError, PollingTimeout } from '../common/errors/pipeline-errors'; import DeployUtils from '../common/utils/deploy.utils'; +import { booleanString } from '../common/utils/oclif'; import { buildSpecFromPath } from '../dependency-manager/spec/utils/component-builder'; import { ComponentVersionSlugUtils } from '../dependency-manager/spec/utils/slugs'; import Dev from "./dev"; @@ -80,17 +81,19 @@ export default class Deploy extends DeployCommand { ...DeployCommand.flags, ...AccountUtils.flags, ...EnvironmentUtils.flags, - local: Flags.boolean({ + local: booleanString({ char: 'l', description: `${BaseCommand.DEPRECATED} Deploy the stack locally instead of via Architect Cloud`, exclusive: ['account', 'auto-approve', 'auto_approve', 'refresh'], hidden: true, sensitive: false, + default: undefined, }), - production: Flags.boolean({ + production: booleanString({ description: `${BaseCommand.DEPRECATED} Please use --environment.`, dependsOn: ['local'], sensitive: false, + default: undefined, }), compose_file: Flags.string({ description: `${BaseCommand.DEPRECATED} Please use --compose-file.`, @@ -105,11 +108,12 @@ export default class Deploy extends DeployCommand { exclusive: ['account', 'environment', 'auto-approve', 'auto_approve', 'refresh'], sensitive: false, }), - detached: Flags.boolean({ + detached: booleanString({ description: 'Run in detached mode', char: 'd', dependsOn: ['local'], sensitive: false, + default: undefined, }), parameter: Flags.string({ char: 'p', @@ -146,30 +150,26 @@ export default class Deploy extends DeployCommand { multiple: true, description: `${BaseCommand.DEPRECATED} Please use --secret-file.`, }), - 'deletion-protection': Flags.boolean({ + 'deletion-protection': booleanString({ default: true, - allowNo: true, description: '[default: true] Toggle for deletion protection on deployments', exclusive: ['local'], sensitive: false, }), - recursive: Flags.boolean({ + recursive: booleanString({ char: 'r', default: true, - allowNo: true, description: '[default: true] Toggle to automatically deploy all dependencies', sensitive: false, }), - refresh: Flags.boolean({ + refresh: booleanString({ default: true, hidden: true, - allowNo: true, exclusive: ['local', 'compose-file', 'compose_file'], sensitive: false, }), - browser: Flags.boolean({ + browser: booleanString({ default: true, - allowNo: true, description: '[default: true] Automatically open urls in the browser for local deployments', sensitive: false, }), diff --git a/src/commands/dev.ts b/src/commands/dev.ts index 6055bae8f..7fa5175b9 100644 --- a/src/commands/dev.ts +++ b/src/commands/dev.ts @@ -236,16 +236,14 @@ export default class Dev extends BaseCommand { multiple: true, default: [], }), - recursive: Flags.boolean({ + recursive: booleanString({ char: 'r', default: true, - allowNo: true, description: '[default: true] Toggle to automatically deploy all dependencies', sensitive: false, }), - browser: Flags.boolean({ + browser: booleanString({ default: true, - allowNo: true, description: '[default: true] Automatically open urls in the browser for local deployments', sensitive: false, }), @@ -254,18 +252,20 @@ export default class Dev extends BaseCommand { sensitive: false, }), // Used for proxy from deploy to dev. These will be removed once --local is deprecated - local: Flags.boolean({ + local: booleanString({ char: 'l', description: `${Command.DEPRECATED} Deploy the stack locally instead of via Architect Cloud`, exclusive: ['account', 'auto-approve', 'auto_approve', 'refresh'], hidden: true, sensitive: false, + default: undefined, }), - production: Flags.boolean({ + production: booleanString({ description: `${Command.DEPRECATED} Please use --environment.`, dependsOn: ['local'], hidden: true, sensitive: false, + default: undefined, }), compose_file: Flags.string({ description: `${Command.DEPRECATED} Please use --compose-file.`, @@ -278,10 +278,11 @@ export default class Dev extends BaseCommand { hidden: true, description: `${Command.DEPRECATED} Please use --secret-file.`, }), - detached: Flags.boolean({ + detached: booleanString({ description: 'Run in detached mode', char: 'd', sensitive: false, + default: false, }), debug: booleanString({ description: `[default: true] Turn debug mode on (true) or off (false)`, diff --git a/src/commands/environments/destroy.ts b/src/commands/environments/destroy.ts index c4d93ed59..7f652d5d1 100644 --- a/src/commands/environments/destroy.ts +++ b/src/commands/environments/destroy.ts @@ -1,9 +1,10 @@ -import { CliUx, Flags, Interfaces } from '@oclif/core'; +import { CliUx, Interfaces } from '@oclif/core'; import chalk from 'chalk'; import inquirer from 'inquirer'; import AccountUtils from '../../architect/account/account.utils'; import { EnvironmentUtils } from '../../architect/environment/environment.utils'; import BaseCommand from '../../base-command'; +import { booleanString } from '../../common/utils/oclif'; export default class EnvironmentDestroy extends BaseCommand { static aliases = ['environment:destroy', 'envs:destroy', 'env:destroy', 'env:deregister', 'environment:deregister']; @@ -15,17 +16,18 @@ export default class EnvironmentDestroy extends BaseCommand { static flags = { ...BaseCommand.flags, ...AccountUtils.flags, - auto_approve: Flags.boolean({ + auto_approve: booleanString({ description: `${BaseCommand.DEPRECATED} Please use --auto-approve.`, hidden: true, sensitive: false, + default: false, }), - ['auto-approve']: Flags.boolean({ + ['auto-approve']: booleanString({ description: 'Automatically apply the changes', default: false, sensitive: false, }), - force: Flags.boolean({ + force: booleanString({ description: 'Force the deletion even if the environment is not empty', char: 'f', default: false, diff --git a/src/commands/exec.ts b/src/commands/exec.ts index c5f6ec3d6..49df54e65 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -1,4 +1,4 @@ -import { Flags, Interfaces } from '@oclif/core'; +import { Interfaces } from '@oclif/core'; import { OutputArgs, OutputFlags } from '@oclif/core/lib/interfaces'; import chalk from 'chalk'; import inquirer from 'inquirer'; @@ -10,6 +10,7 @@ import AccountUtils from '../architect/account/account.utils'; import { EnvironmentUtils, Replica } from '../architect/environment/environment.utils'; import BaseCommand from '../base-command'; import { DockerComposeUtils } from '../common/docker-compose'; +import { booleanString } from '../common/utils/oclif'; enum RemoteExecCommandOutputStatus { SUCCESS = 'Success', @@ -44,16 +45,14 @@ export default class Exec extends BaseCommand { ...BaseCommand.flags, ...AccountUtils.flags, ...EnvironmentUtils.flags, - stdin: Flags.boolean({ + stdin: booleanString({ description: 'Pass stdin to the container. Only works on remote deploys.', char: 'i', - allowNo: true, default: true, }), - tty: Flags.boolean({ + tty: booleanString({ description: 'Stdin is a TTY. If the flag isn\'t supplied, tty or no-tty is automatically detected.', char: 't', - allowNo: true, default: undefined, sensitive: false, }), diff --git a/src/commands/logs.ts b/src/commands/logs.ts index 0e14f8b21..254b7ed48 100644 --- a/src/commands/logs.ts +++ b/src/commands/logs.ts @@ -10,6 +10,7 @@ import Environment from '../architect/environment/environment.entity'; import { EnvironmentUtils, Replica } from '../architect/environment/environment.utils'; import BaseCommand from '../base-command'; import { DockerComposeUtils } from '../common/docker-compose'; +import { booleanString } from '../common/utils/oclif'; export default class Logs extends BaseCommand { async auth_required(): Promise { @@ -25,7 +26,7 @@ export default class Logs extends BaseCommand { ...BaseCommand.flags, ...AccountUtils.flags, ...EnvironmentUtils.flags, - follow: Flags.boolean({ + follow: booleanString({ description: 'Specify if the logs should be streamed.', char: 'f', default: false, @@ -36,7 +37,7 @@ export default class Logs extends BaseCommand { default: '', sensitive: false, }), - raw: Flags.boolean({ + raw: booleanString({ description: 'Show the raw output of the logs.', default: false, sensitive: false, @@ -46,7 +47,7 @@ export default class Logs extends BaseCommand { default: -1, sensitive: false, }), - timestamps: Flags.boolean({ + timestamps: booleanString({ description: 'Include timestamps on each line in the log output.', default: false, sensitive: false, diff --git a/src/commands/platforms/create.ts b/src/commands/platforms/create.ts index fc0a2285b..70f33993d 100644 --- a/src/commands/platforms/create.ts +++ b/src/commands/platforms/create.ts @@ -7,6 +7,7 @@ import PipelineUtils from '../../architect/pipeline/pipeline.utils'; import { CreatePlatformInput } from '../../architect/platform/platform.utils'; import BaseCommand from '../../base-command'; import { KubernetesPlatformUtils } from '../../common/utils/kubernetes-platform.utils'; +import { booleanString } from '../../common/utils/oclif'; export default class PlatformCreate extends BaseCommand { static aliases = ['platforms:register', 'platform:create', 'platforms:create']; @@ -25,12 +26,16 @@ export default class PlatformCreate extends BaseCommand { static flags = { ...BaseCommand.flags, ...AccountUtils.flags, - auto_approve: Flags.boolean({ + auto_approve: booleanString({ description: `${BaseCommand.DEPRECATED} Please use --auto-approve.`, hidden: true, sensitive: false, + default: false, + }), + ['auto-approve']: booleanString({ + sensitive: false, + default: false, }), - ['auto-approve']: Flags.boolean({ sensitive: false }), type: Flags.string({ char: 't', options: ['KUBERNETES', 'kubernetes'], diff --git a/src/commands/platforms/destroy.ts b/src/commands/platforms/destroy.ts index 0f2d41bc8..9d24a9cea 100644 --- a/src/commands/platforms/destroy.ts +++ b/src/commands/platforms/destroy.ts @@ -1,9 +1,10 @@ -import { CliUx, Flags, Interfaces } from '@oclif/core'; +import { CliUx, Interfaces } from '@oclif/core'; import chalk from 'chalk'; import inquirer from 'inquirer'; import AccountUtils from '../../architect/account/account.utils'; import PlatformUtils from '../../architect/platform/platform.utils'; import BaseCommand from '../../base-command'; +import { booleanString } from '../../common/utils/oclif'; export default class PlatformDestroy extends BaseCommand { static aliases = ['platforms:deregister', 'platform:destroy', 'platforms:destroy']; @@ -15,17 +16,18 @@ export default class PlatformDestroy extends BaseCommand { static flags = { ...BaseCommand.flags, ...AccountUtils.flags, - auto_approve: Flags.boolean({ + auto_approve: booleanString({ description: `${BaseCommand.DEPRECATED} Please use --auto-approve.`, hidden: true, sensitive: false, + default: false, }), - ['auto-approve']: Flags.boolean({ + ['auto-approve']: booleanString({ description: 'Automatically apply the changes', default: false, sensitive: false, }), - force: Flags.boolean({ + force: booleanString({ description: 'Force the deletion even if the platform is not empty', char: 'f', default: false, diff --git a/src/commands/secrets/upload.ts b/src/commands/secrets/upload.ts index d0f72ceb9..12428e732 100644 --- a/src/commands/secrets/upload.ts +++ b/src/commands/secrets/upload.ts @@ -1,4 +1,3 @@ -import { Flags } from '@oclif/core'; import fs from 'fs-extra'; import yaml from 'js-yaml'; import path from 'path'; @@ -9,6 +8,7 @@ import { EnvironmentUtils } from '../../architect/environment/environment.utils' import SecretUtils, { Secret } from '../../architect/secret/secret.utils'; import UserUtils from '../../architect/user/user.utils'; import BaseCommand from '../../base-command'; +import { booleanString } from '../../common/utils/oclif'; import { SecretsDict } from '../../dependency-manager/secrets/type'; export default class SecretsUpload extends BaseCommand { @@ -22,7 +22,7 @@ export default class SecretsUpload extends BaseCommand { ...BaseCommand.flags, ...AccountUtils.flags, ...EnvironmentUtils.flags, - override: Flags.boolean({ + override: booleanString({ description: 'Allow override of existing secrets', default: false, sensitive: false, diff --git a/src/commands/task.ts b/src/commands/task.ts index 35c9d36ee..04b7154eb 100644 --- a/src/commands/task.ts +++ b/src/commands/task.ts @@ -6,6 +6,7 @@ import { EnvironmentUtils } from '../architect/environment/environment.utils'; import BaseCommand from '../base-command'; import { DockerComposeUtils } from '../common/docker-compose'; import * as Docker from '../common/utils/docker'; +import { booleanString } from '../common/utils/oclif'; export default class TaskExec extends BaseCommand { static aliases = ['task:exec']; @@ -25,11 +26,12 @@ export default class TaskExec extends BaseCommand { ...AccountUtils.flags, ...EnvironmentUtils.flags, - local: Flags.boolean({ + local: booleanString({ char: 'l', description: 'Deploy the stack locally instead of via Architect Cloud', exclusive: ['account', 'auto-approve', 'auto_approve', 'refresh'], sensitive: false, + default: false, }), compose_file: Flags.string({ description: `${BaseCommand.DEPRECATED} Please use --compose-file.`, diff --git a/src/commands/unlink.ts b/src/commands/unlink.ts index 8ed738536..49ca3e967 100644 --- a/src/commands/unlink.ts +++ b/src/commands/unlink.ts @@ -1,9 +1,9 @@ -import { Flags } from '@oclif/core'; import chalk from 'chalk'; import path from 'path'; import untildify from 'untildify'; import { buildSpecFromPath } from '../'; import BaseCommand from '../base-command'; +import { booleanString } from '../common/utils/oclif'; export default class Unlink extends BaseCommand { async auth_required(): Promise { @@ -18,9 +18,10 @@ export default class Unlink extends BaseCommand { ]; static flags = { ...BaseCommand.flags, - all: Flags.boolean({ + all: booleanString({ description: 'Unlink all components registered locally', sensitive: false, + default: false, }), }; diff --git a/src/common/utils/oclif.ts b/src/common/utils/oclif.ts index 4b7b72dda..1ffa54907 100644 --- a/src/common/utils/oclif.ts +++ b/src/common/utils/oclif.ts @@ -1,6 +1,6 @@ import { Flags } from '@oclif/core'; -export const booleanString = Flags.build({ +export const booleanString = Flags.build({ parse: async (input, _) => { const boolean_string = input.toLowerCase(); if (['true', 'false'].includes(boolean_string)) { @@ -10,4 +10,11 @@ export const booleanString = Flags.build({ } }, default: false, + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + _type: 'booleanstring', // Used to check if the flag is a booleanstring }); + +export const isBooleanStringFlag = (flag: any): boolean => { + return flag && flag._type === 'booleanstring'; +}; From d815216793ea9f568b90bf51bff308312e038389 Mon Sep 17 00:00:00 2001 From: Devin Sag Date: Tue, 23 Aug 2022 13:46:03 -0400 Subject: [PATCH 2/4] add import for Flags --- src/commands/exec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/exec.ts b/src/commands/exec.ts index 85a9f9542..de539936f 100644 --- a/src/commands/exec.ts +++ b/src/commands/exec.ts @@ -1,4 +1,4 @@ -import { Interfaces } from '@oclif/core'; +import { Flags, Interfaces } from '@oclif/core'; import { OutputArgs, OutputFlags } from '@oclif/core/lib/interfaces'; import chalk from 'chalk'; import inquirer from 'inquirer'; From 9502fcf95789a40a301495ed73447b43d2f99584 Mon Sep 17 00:00:00 2001 From: Devin Sag Date: Tue, 23 Aug 2022 13:59:45 -0400 Subject: [PATCH 3/4] update dev example --- src/commands/dev.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/commands/dev.ts b/src/commands/dev.ts index 7fa5175b9..ace1ad05c 100644 --- a/src/commands/dev.ts +++ b/src/commands/dev.ts @@ -192,7 +192,7 @@ export default class Dev extends BaseCommand { static examples = [ 'architect dev ./mycomponent/architect.yml', - 'architect dev --port=81 --no-browser --debug=true --secret-file=./mycomponent/mysecrets.yml ./mycomponent/architect.yml', + 'architect dev --port=81 --browser=false --debug=true --secret-file=./mycomponent/mysecrets.yml ./mycomponent/architect.yml', ]; static flags = { From 2c69abc09cdb7cdf349c36fe0530946c9de52053 Mon Sep 17 00:00:00 2001 From: Devin Sag Date: Tue, 23 Aug 2022 16:47:22 -0400 Subject: [PATCH 4/4] test booleanFlag auto-approve for platform:create --- test/commands/platforms/create.test.ts | 137 +++++++++++++++++++++++-- 1 file changed, 130 insertions(+), 7 deletions(-) diff --git a/test/commands/platforms/create.test.ts b/test/commands/platforms/create.test.ts index bd7f2f51b..4e0460d95 100644 --- a/test/commands/platforms/create.test.ts +++ b/test/commands/platforms/create.test.ts @@ -13,20 +13,20 @@ import { KubernetesPlatformUtils } from '../../../src/common/utils/kubernetes-pl import ARCHITECTPATHS from '../../../src/paths'; describe('platform:create', function () { - let tmp_dir = os.tmpdir(); + const tmp_dir = os.tmpdir(); const account = { id: 'test-account-id', - name: 'test-account-name' - } + name: 'test-account-name', + }; beforeEach(() => { // Stub the logger sinon.replace(PlatformCreate.prototype, 'log', sinon.stub()); const mock_pipeline = { - id: 'test-pipeline-id' - } + id: 'test-pipeline-id', + }; sinon.replace(PipelineUtils, 'pollPipeline', async () => mock_pipeline); // Stub the log_level @@ -39,7 +39,7 @@ describe('platform:create', function () { sinon.replace(AppService, 'create', app_config_stub); }); - it('Creates a Kubernetes platform with input', async () => { + it('Does not auto approve creation when auto-approve flag value is false', async () => { const inquirerStub = sinon.stub(inquirer, 'prompt'); inquirerStub.resolves({ context: 'minikube', @@ -56,7 +56,89 @@ describe('platform:create', function () { nock('https://api.architect.io').post(`/accounts/${account.id}/platforms`) .reply(200, { id: test_platform_id, - account: account + account: account, + }); + + nock('https://api.architect.io').post(`/platforms/${test_platform_id}/apps`) + .reply(200, { + id: 'test-deployment-id', + pipeline: { + id: test_pipeline_id, + }, + }); + + const create_platform_applications_spy = sinon.spy(PlatformCreate.prototype, 'createPlatformApplications'); + const create_platform_spy = sinon.spy(PlatformCreate.prototype, 'createArchitectPlatform'); + const post_to_api_spy = sinon.spy(PlatformCreate.prototype, 'postPlatformToApi'); + const kubernetes_configuration_fake = sinon.fake.returns({ name: 'new_k8s_platform', type: 'KUBERNETES' }); + sinon.replace(KubernetesPlatformUtils, 'configureKubernetesPlatform', kubernetes_configuration_fake); + + await PlatformCreate.run(['platform-name', '-a', 'test-account-name', '-t', 'kubernetes', '--auto-approve=false']); + expect(create_platform_spy.calledOnce).true; + expect(post_to_api_spy.calledOnce).true; + expect(kubernetes_configuration_fake.calledOnce).true; + expect(create_platform_applications_spy.calledOnce).false; + }); + + it('Auto approve creation when auto-approve flag value is true', async () => { + const inquirerStub = sinon.stub(inquirer, 'prompt'); + inquirerStub.resolves({ + context: 'minikube', + service_account_name: 'architect', + use_existing_sa: true, + }); + + const test_platform_id = 'test-platform-id'; + const test_pipeline_id = 'test-pipeline-id'; + + nock('https://api.architect.io').get(`/accounts/${account.name}`) + .reply(200, account); + + nock('https://api.architect.io').post(`/accounts/${account.id}/platforms`) + .reply(200, { + id: test_platform_id, + account: account, + }); + + nock('https://api.architect.io').post(`/platforms/${test_platform_id}/apps`) + .reply(200, { + id: 'test-deployment-id', + pipeline: { + id: test_pipeline_id, + }, + }); + + const create_platform_applications_spy = sinon.spy(PlatformCreate.prototype, 'createPlatformApplications'); + const create_platform_spy = sinon.spy(PlatformCreate.prototype, 'createArchitectPlatform'); + const post_to_api_spy = sinon.spy(PlatformCreate.prototype, 'postPlatformToApi'); + const kubernetes_configuration_fake = sinon.fake.returns({ name: 'new_k8s_platform', type: 'KUBERNETES' }); + sinon.replace(KubernetesPlatformUtils, 'configureKubernetesPlatform', kubernetes_configuration_fake); + + await PlatformCreate.run(['platform-name', '-a', 'test-account-name', '-t', 'kubernetes', '--auto-approve=true']); + expect(create_platform_spy.calledOnce).true; + expect(post_to_api_spy.calledOnce).true; + expect(kubernetes_configuration_fake.calledOnce).true; + expect(create_platform_applications_spy.calledOnce).true; + }); + + it('Auto approve creation when auto-approve flag value is not specified', async () => { + const inquirerStub = sinon.stub(inquirer, 'prompt'); + inquirerStub.resolves({ + context: 'minikube', + service_account_name: 'architect', + use_existing_sa: true, + }); + + const test_platform_id = 'test-platform-id'; + const test_pipeline_id = 'test-pipeline-id'; + + nock('https://api.architect.io').get(`/accounts/${account.name}`) + .reply(200, account); + + nock('https://api.architect.io').post(`/accounts/${account.id}/platforms`) + .reply(200, { + id: test_platform_id, + account: account, }); nock('https://api.architect.io').post(`/platforms/${test_platform_id}/apps`) @@ -79,4 +161,45 @@ describe('platform:create', function () { expect(kubernetes_configuration_fake.calledOnce).true; expect(create_platform_applications_spy.calledOnce).true; }); + + it('Do not auto approve creation with auto-approve flag default value', async () => { + const inquirerStub = sinon.stub(inquirer, 'prompt'); + inquirerStub.resolves({ + context: 'minikube', + service_account_name: 'architect', + use_existing_sa: true, + }); + + const test_platform_id = 'test-platform-id'; + const test_pipeline_id = 'test-pipeline-id'; + + nock('https://api.architect.io').get(`/accounts/${account.name}`) + .reply(200, account); + + nock('https://api.architect.io').post(`/accounts/${account.id}/platforms`) + .reply(200, { + id: test_platform_id, + account: account, + }); + + nock('https://api.architect.io').post(`/platforms/${test_platform_id}/apps`) + .reply(200, { + id: 'test-deployment-id', + pipeline: { + id: test_pipeline_id, + }, + }); + + const create_platform_applications_spy = sinon.spy(PlatformCreate.prototype, 'createPlatformApplications'); + const create_platform_spy = sinon.spy(PlatformCreate.prototype, 'createArchitectPlatform'); + const post_to_api_spy = sinon.spy(PlatformCreate.prototype, 'postPlatformToApi'); + const kubernetes_configuration_fake = sinon.fake.returns({ name: 'new_k8s_platform', type: 'KUBERNETES' }); + sinon.replace(KubernetesPlatformUtils, 'configureKubernetesPlatform', kubernetes_configuration_fake); + + await PlatformCreate.run(['platform-name', '-a', 'test-account-name', '-t', 'kubernetes']); + expect(create_platform_spy.calledOnce).true; + expect(post_to_api_spy.calledOnce).true; + expect(kubernetes_configuration_fake.calledOnce).true; + expect(create_platform_applications_spy.calledOnce).false; + }); });