Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,7 @@ node_modules
# os specific files
.DS_Store
.idea

# exclude sfdx and sf config files
.sf
.sfdx
4 changes: 4 additions & 0 deletions messages/create.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ This command works with only scratch orgs.

This command doesn't work when authorizing an org using the JWT flow if the org is on Hyperforce.

# error.invalidRoleDeveloperName

Invalid roleDeveloperName: "%s". Must start with a letter and contain only alphanumeric characters or single underscores, with no double or final underscores.

# error.jwtHyperforce.actions

- Authorize your Dev Hub with either the `org login web` or `org login sfdx-url` command. You can then successfully use the `org create user` command on scratch orgs that you create with your Dev Hub.
20 changes: 19 additions & 1 deletion src/commands/org/create/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,9 @@ export class CreateUserCommand extends SfCommand<CreateUserOutput> {
} else if (key.toLowerCase() === 'profilename') {
// @ts-expect-error standardize profileName casing
defaultFields['profileName'] = this.varargs[key];
} else if (key.toLowerCase() === 'roledevelopername') {
// @ts-expect-error standardize roleDeveloperName casing
defaultFields['roleDeveloperName'] = this.varargs[key];
} else {
// @ts-expect-error all other varargs are left "as is"
defaultFields[lowerFirstLetter(key)] = this.varargs[key];
Expand All @@ -220,6 +223,21 @@ export class CreateUserCommand extends SfCommand<CreateUserOutput> {
defaultFields.profileId = profile.Id;
}

// @ts-expect-error check if "roleDeveloperName" was passed, this needs to become a userRoleId before calling User.create
if (defaultFields['roleDeveloperName']) {
// @ts-expect-error roleDeveloperName is not a valid field on UserFields
const devName = defaultFields['roleDeveloperName'] as string;
if (!/^[a-z](?!.*__)(?!.*_$)\w*$/i.test(devName)) {
throw messages.createError('error.invalidRoleDeveloperName', [devName]);
}
logger.debug(`Querying org for user role name [${devName}]`);
const userRole = await this.flags['target-org']
.getConnection(this.flags['api-version'])
.singleRecordQuery<{ Id: string }>(`SELECT id FROM userrole WHERE developername='${devName}'`);
Comment thread
baslu93 marked this conversation as resolved.
// @ts-expect-error userRoleId is an optional field therefore not defined on UserFields
defaultFields['userRoleId'] = userRole.Id;
}

return defaultFields;
}

Expand Down Expand Up @@ -280,7 +298,7 @@ const lowerFirstLetter = (word: string): string => word[0].toLowerCase() + word.
* @private
*/
const stripInvalidAPIFields = (fields: UserFields & Dictionary<string>): UserFields =>
omit(fields, ['permsets', 'generatepassword', 'generatePassword', 'profileName']);
omit(fields, ['permsets', 'generatepassword', 'generatePassword', 'profileName', 'roleDeveloperName']);

const getNewUserAuthInfo = async (
targetOrgUser: User,
Expand Down
18 changes: 17 additions & 1 deletion test/commands/create.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,9 @@ describe('org:create:user', () => {
}

if (readsFile) {
$$.SANDBOXES.CONNECTION.stub(Connection.prototype, 'singleRecordQuery').resolves({ Id: '12345678' });
$$.SANDBOXES.CONNECTION.stub(Connection.prototype, 'singleRecordQuery')
.withArgs('SELECT id FROM profile WHERE name=\'profileFromArgs\'').resolves({ Id: '12345678' })
.withArgs('SELECT id FROM userrole WHERE developername=\'roleFromArgs\'').resolves({ Id: '87654321' })
$$.SANDBOX.stub(Logger.prototype, 'debug');
if (typeof readsFile !== 'boolean') {
const fsStub = $$.SANDBOX.stub(fs.promises, 'readFile');
Expand Down Expand Up @@ -429,5 +431,19 @@ describe('org:create:user', () => {
);
}
});

it('will handle a failed `createUser` call with a InvalidRoleDeveloperName error', async () => {
await prepareStubs({}, true);
try {
await CreateUserCommand.run(['--json', '--target-org', testOrg.username,'roleDeveloperName=_Invalid_Role']);
expect.fail('should have thrown an error');
} catch (e) {
assert(e instanceof Error);
expect(e.name).to.equal('InvalidRoleDeveloperNameError');
expect(e.message).to.equal(
'Invalid roleDeveloperName: "_Invalid_Role". Must start with a letter and contain only alphanumeric characters or single underscores, with no double or final underscores.'
);
}
});
});
});
1 change: 1 addition & 0 deletions test/df17AppBuilding/config/complexUser.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
"LanguageLocaleKey": "en_US",
"profileName": "Standard Platform User",
"permsets": ["VolunteeringApp"],
"roleDeveloperName": "Guide",
"generatePassword": true
}
1 change: 1 addition & 0 deletions test/df17AppBuilding/config/project-scratch-def.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"edition": "Developer",
"description": "nuts for plugin-user",
"features": ["EnableSetPasswordInApi", "AnalyticsAppEmbedded", "DataMaskUser"],
"language": "en_US",
"settings": {
"lightningExperienceSettings": {
"enableS1DesktopEnabled": true
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<Role xmlns="http://soap.sforce.com/2006/04/metadata">
<caseAccessLevel>Edit</caseAccessLevel>
<contactAccessLevel>Edit</contactAccessLevel>
<mayForecastManagerShare>false</mayForecastManagerShare>
<name>Guide</name>
<opportunityAccessLevel>Edit</opportunityAccessLevel>
</Role>
Loading