diff --git a/.vscode/launch.json b/.vscode/launch.json index f5f4b7c351..9e2205f1a2 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,43 +1,35 @@ { - // Use IntelliSense to learn about possible Node.js debug attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "attach", - "name": "Attach to Remote", - "address": "localhost", - "port": 9229, - "localRoot": "${workspaceFolder}" - }, - { - "type": "node", - "request": "launch", - "name": "Launch exports", - "preLaunchTask": "compile", - "program": "${workspaceRoot}/lib/exports.js", - "sourceMaps": true, - "outFiles": [ - "${workspaceRoot}/out/**/*.js" - ] - }, - { - "type": "node", - "request": "launch", - "name": "Debug Unit Tests", - "program": "${workspaceRoot}/node_modules/.bin/_mocha", - "preLaunchTask": "compile", - "args": [ - "--timeout", - "999999", - "dist/test/unit/**/*.js" - ], - "sourceMaps": true, - "outFiles": [ - "${workspaceRoot}/dist/**/*.js" - ] - } - ] -} \ No newline at end of file + // Use IntelliSense to learn about possible Node.js debug attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "attach", + "name": "Attach to Remote", + "address": "localhost", + "port": 9229, + "skipFiles": ["/**/*.js"] + }, + { + "type": "node", + "request": "launch", + "name": "Launch exports", + "preLaunchTask": "compile", + "program": "${workspaceRoot}/lib/exports.js", + "sourceMaps": true, + "outFiles": ["${workspaceRoot}/out/**/*.js"] + }, + { + "type": "node", + "request": "launch", + "name": "Debug Unit Tests", + "program": "${workspaceRoot}/node_modules/.bin/_mocha", + "preLaunchTask": "compile", + "args": ["--timeout", "999999", "dist/test/unit/**/*.js"], + "sourceMaps": true, + "outFiles": ["${workspaceRoot}/dist/**/*.js"] + } + ] +} diff --git a/src/org.ts b/src/org.ts index 066211daff..2f41482206 100644 --- a/src/org.ts +++ b/src/org.ts @@ -16,6 +16,7 @@ import { getNumber, getString, isArray, + isBoolean, isString, JsonArray, JsonMap, @@ -143,7 +144,7 @@ export class Org extends AsyncCreatable { orgForUser = await Org.create({ connection }); } - const orgType = (await this.isDevHubOrg()) ? Config.DEFAULT_DEV_HUB_USERNAME : Config.DEFAULT_USERNAME; + const orgType = this.isDevHubOrg() ? Config.DEFAULT_DEV_HUB_USERNAME : Config.DEFAULT_USERNAME; const configInfo: ConfigInfo = await orgForUser.configAggregator.getInfo(orgType); @@ -208,7 +209,7 @@ export class Org extends AsyncCreatable { */ public async getDevHubOrg(): Promise> { if (this.isDevHubOrg()) { - return Promise.resolve(this); + return this; } else if (this.getField(Org.Fields.DEV_HUB_USERNAME)) { const devHubUsername = ensureString(this.getField(Org.Fields.DEV_HUB_USERNAME)); return Org.create({ @@ -221,9 +222,49 @@ export class Org extends AsyncCreatable { /** * Returns `true` if the org is a Dev Hub. + * + * **Note** This relies on a cached value in the auth file. If that property + * is not cached, this method will **always return false even if the org is a + * dev hub**. If you need accuracy, use the {@link Org.determineIfDevhub} method. */ public isDevHubOrg(): boolean { - return this.getField(Org.Fields.IS_DEV_HUB) as boolean; + const isDevHub = this.getField(Org.Fields.IS_DEV_HUB); + if (isBoolean(isDevHub)) { + return isDevHub; + } else { + return false; + } + } + + /** + * Returns `true` if the org is a Dev Hub. + * + * Use a cached value. If the cached value is not set, then check access to the + * ScratchOrgInfo object to determine if the org is a dev hub. + */ + public async determineIfDevHubOrg() { + if (this.isDevHubOrg()) { + return true; + } + + const conn = this.getConnection(); + let isDevHub = false; + try { + await conn.query('SELECT Id FROM ScratchOrgInfo'); + isDevHub = true; + } catch (err) { + /* Not a dev hub */ + } + + const username = ensure(this.getUsername()); + const auth = await AuthInfo.create({ username }); + await auth.save({ isDevHub }); + AuthInfo.clearCache(username); + // Reset the connection with the updated auth file + this.connection = await Connection.create({ + authInfo: await AuthInfo.create({ username }) + }); + return isDevHub; } /** diff --git a/src/testSetup.ts b/src/testSetup.ts index b783753b39..20e16066f2 100644 --- a/src/testSetup.ts +++ b/src/testSetup.ts @@ -293,6 +293,9 @@ const _testSetup = (sinon?: any) => { } return testContext.fakeConnectionRequest.call(this, request, options); }); + + // Always start with the default and tests beforeEach or it methods can override it. + testContext.fakeConnectionRequest = defaultFakeConnectionRequest; }); afterEach(() => { diff --git a/test/unit/orgTest.ts b/test/unit/orgTest.ts index 85414442df..78ec215377 100644 --- a/test/unit/orgTest.ts +++ b/test/unit/orgTest.ts @@ -623,4 +623,25 @@ describe('Org Tests', () => { }); }); }); + + describe('determineDevHub', () => { + it('should return true and cache if dev hub', async () => { + const org: Org = await Org.create({ aliasOrUsername: testData.username }); + $$.fakeConnectionRequest = async (request: AnyJson, options?: AnyJson) => { + return { records: [] }; + }; + expect(org.isDevHubOrg()).to.be.false; + expect(await org.determineIfDevHubOrg()).to.be.true; + expect(org.isDevHubOrg()).to.be.true; + }); + it('should return false and cache if dev hub', async () => { + const org: Org = await Org.create({ aliasOrUsername: testData.username }); + $$.fakeConnectionRequest = async (request: AnyJson, options?: AnyJson) => { + throw new Error(); + }; + expect(org.isDevHubOrg()).to.be.false; + expect(await org.determineIfDevHubOrg()).to.be.false; + expect(org.isDevHubOrg()).to.be.false; + }); + }); });