diff --git a/src/commands/env/create/compute.ts b/src/commands/env/create/compute.ts index 9105ff3a..e185a526 100644 --- a/src/commands/env/create/compute.ts +++ b/src/commands/env/create/compute.ts @@ -35,6 +35,16 @@ export default class EnvCreateCompute extends Command { const org = await this.fetchOrg(flags['connected-org']) const orgId = org.getOrgId() + if (!await this.isFunctionsEnabled(org)) { + this.error( + `The org you are attempting to create a compute environment for does not have the ${herokuColor.green('Functions')} feature enabled.\n` + + '\n' + + 'Before you can create a compute environment, please:\n' + + '1. Enable Functions in your DevHub org\n' + + `2. Add ${herokuColor.green('Functions')} to the "features" list in your scratch org definition JSON file, e.g. "features": ["Functions"]`, + ) + } + cli.action.start(`Creating compute environment for org ID ${orgId}`) const project = await this.fetchSfdxProject() diff --git a/src/commands/generate/function.ts b/src/commands/generate/function.ts index 03e42f87..b29ff303 100644 --- a/src/commands/generate/function.ts +++ b/src/commands/generate/function.ts @@ -329,8 +329,8 @@ export default class GenerateFunction extends Command { this.log('') this.log( 'Before creating Scratch Orgs for development, please ensure that:\n' + - '1. Functions is enabled in your DevHub org\n' + - `2. ${herokuColor.green('"Functions"')} is added to your scratch org definition file ${herokuColor.green('"features"')} list`, + '1. Enable Functions in your DevHub org\n' + + `2. Add ${herokuColor.green('Functions')} to the "features" list in your scratch org definition JSON file, e.g. "features": ["Functions"]`, ) } } diff --git a/src/lib/base.ts b/src/lib/base.ts index 829242aa..69f708d4 100644 --- a/src/lib/base.ts +++ b/src/lib/base.ts @@ -133,6 +133,25 @@ export default abstract class Command extends Base { return appName } + protected async isFunctionsEnabled(org: Org) { + const conn = org.getConnection() + + // This is a roundabout away of checking if a given org has Functions enabled. If they do NOT have functions enabled, + // then querying for FunctionReferences will throw an error which complains about not having access to the + // FunctionReference object for the given org. + try { + await conn.metadata.list({type: 'FunctionReference'}) + return true + } catch (error) { + if (error.name.includes('INVALID_TYPE') || error.message.includes('Cannot use: FunctionReference in this organization')) { + return false + } + + // If we get here, something very unexpected has happened so just bail + throw error + } + } + private fetchConfirmationValue(name: string, confirm?: string | string[]): string | undefined { // If multiple confirm values have been specified, we iterate over each one until finding something that could match // If there isn't a match, we'll simply return undefined diff --git a/test/commands/env/create/compute.test.ts b/test/commands/env/create/compute.test.ts index 85960496..b9725ce0 100644 --- a/test/commands/env/create/compute.test.ts +++ b/test/commands/env/create/compute.test.ts @@ -9,6 +9,12 @@ const APP_MOCK = { const USERNAME = 'fakeusername@salesforce.com' +const CONN_MOCK = { + metadata: { + list: sinon.stub(), + }, +} + const ORG_MOCK = { id: '1', getOrgId() { @@ -17,6 +23,9 @@ const ORG_MOCK = { getUsername() { return USERNAME }, + getConnection() { + return CONN_MOCK + }, } const PROJECT_CONFIG_MOCK = { @@ -145,4 +154,22 @@ describe('sf env create compute', () => { expect(ctx.stderr).to.contain('error!') expect(ctx.stdout).to.contain(`Compute Environment ID: ${APP_MOCK.name}`) }) + + test + .stdout() + .stderr() + .do(() => { + orgStub = sandbox.stub(Org, 'create' as any).returns(ORG_MOCK) + sandbox.stub(SfdxProject, 'resolve' as any).returns(PROJECT_MOCK) + CONN_MOCK.metadata.list = sinon.stub().throws('INVALID_TYPE') + }) + .finally(() => { + sandbox.restore() + sinon.restore() + }) + .command(['env:create:compute']) + .catch(error => { + expect(error.message).to.contain('The org you are attempting to create a compute environment for does not have the Functions feature enabled.') + }) + .it('displays an informative error message if the org doesn\'t have functions enabled') })