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
12 changes: 12 additions & 0 deletions command/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type ScratchFeature enumflag.Flag

const (
PersonAccounts ScratchFeature = iota
B2BCommerce
ContactsToMultipleAccounts
FinancialServicesUser
StateAndCountryPicklist
Expand All @@ -35,6 +36,7 @@ const (

var ScratchFeatureIds = map[ScratchFeature][]string{
PersonAccounts: {"PersonAccounts"},
B2BCommerce: {"B2BCommerce"},
ContactsToMultipleAccounts: {"ContactsToMultipleAccounts"},
FinancialServicesUser: {"FinancialServicesUser"},
StateAndCountryPicklist: {"StateAndCountryPicklist"},
Expand All @@ -58,13 +60,15 @@ const (
CommunitiesProduct
HealthCloudProduct
CRMAnalyticsProduct
B2BCommerceProduct
)

var ScratchProductIds = map[ScratchProduct][]string{
FSC: {"fsc"},
CommunitiesProduct: {"communities"},
HealthCloudProduct: {"healthcloud"},
CRMAnalyticsProduct: {"crmanalytics"},
B2BCommerceProduct: {"b2bcommerce"},
}

type ScratchEdition enumflag.Flag
Expand Down Expand Up @@ -97,6 +101,7 @@ const (
EnableEnhancedNotes ScratchSetting = iota
EnableQuote
NetworksEnabled
CommerceEnabled
EnableApexApprovalLockUnlock
PermsetsInFieldCreation
EnableLightningPreviewPref
Expand All @@ -106,6 +111,7 @@ var ScratchSettingIds = map[ScratchSetting][]string{
EnableEnhancedNotes: {"enableEnhancedNotes"},
EnableQuote: {"enableQuote"},
NetworksEnabled: {"networksEnabled"},
CommerceEnabled: {"commerceEnabled"},
EnableApexApprovalLockUnlock: {"enableApexApprovalLockUnlock"},
PermsetsInFieldCreation: {"permsetsInFieldCreation"},
EnableLightningPreviewPref: {"enableLightningPreviewPref"},
Expand Down Expand Up @@ -190,6 +196,7 @@ var scratchCmd = &cobra.Command{

Available Features:
AnalyticsAdminPerms - Enables CRM Analytics admin permissions
B2BCommerce - Enables B2B Commerce
Communities - Enables Experience Cloud (Communities)
ContactsToMultipleAccounts - Allows a single Contact to be associated with multiple Accounts
DevelopmentWave - Enables CRM Analytics development features
Expand All @@ -206,6 +213,7 @@ Available Features:
WavePlatform - Enables Wave Platform (CRM Analytics)

Available Products:
b2bcommerce - B2B Commerce (enables B2BCommerce feature and commerceEnabled setting)
communities - Experience Cloud (enables Communities feature and networksEnabled setting)
crmanalytics - CRM Analytics (enables AnalyticsAdminPerms, WavePlatform, InsightsPlatform, EinsteinAnalyticsPlus, EinsteinBuilderFree, DevelopmentWave)
fsc - Financial Services Cloud (enables PersonAccounts, ContactsToMultipleAccounts, FinancialServicesUser)
Expand All @@ -225,6 +233,7 @@ Available Settings (deployed after org creation):
enableEnhancedNotes - Enable Enhanced Notes
enableQuote - Enable Quotes
networksEnabled - Enable Experience Cloud (Communities)
commerceEnabled - Enable Commerce
enableApexApprovalLockUnlock - Allow Apex to lock/unlock approval processes
permsetsInFieldCreation - Allow assigning permission sets during field creation
enableLightningPreviewPref - Enable Lightning Experience preview pref
Expand All @@ -241,6 +250,7 @@ Examples:
force login scratch --edition Enterprise --product fsc
force login scratch --setting enableEnhancedNotes
force login scratch --setting enableQuote
force login scratch --product b2bcommerce
force login scratch --product communities
force login scratch --product crmanalytics
force login scratch --product healthcloud
Expand Down Expand Up @@ -317,6 +327,7 @@ func expandProductsToFeatures(products []ScratchProduct, features []ScratchFeatu
CommunitiesProduct: {Communities},
HealthCloudProduct: {HealthCloudAddOn, HealthCloudUser},
CRMAnalyticsProduct: {AnalyticsAdminPerms, WavePlatform, InsightsPlatform, EinsteinAnalyticsPlus, EinsteinBuilderFree, DevelopmentWave},
B2BCommerceProduct: {B2BCommerce},
}

featureSet := make(map[ScratchFeature]bool)
Expand Down Expand Up @@ -360,6 +371,7 @@ func convertSettingsToStrings(settings []ScratchSetting) []string {
func expandProductsToSettings(products []ScratchProduct, settings []ScratchSetting) []string {
productSettings := map[ScratchProduct][]ScratchSetting{
CommunitiesProduct: {NetworksEnabled},
B2BCommerceProduct: {CommerceEnabled},
}

settingSet := make(map[ScratchSetting]bool)
Expand Down
77 changes: 77 additions & 0 deletions command/login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,16 @@ func TestExpandProductsToFeatures_SingleFeature(t *testing.T) {
}
}

func TestExpandProductsToFeatures_B2BCommerce(t *testing.T) {
result := expandProductsToFeatures([]ScratchProduct{}, []ScratchFeature{B2BCommerce}, map[string]string{})
if len(result) != 1 {
t.Fatalf("Expected 1 feature, got %d", len(result))
}
if result[0] != "B2BCommerce" {
t.Errorf("Expected B2BCommerce, got %s", result[0])
}
}

func TestExpandProductsToFeatures_MultipleFeatures(t *testing.T) {
result := expandProductsToFeatures([]ScratchProduct{}, []ScratchFeature{PersonAccounts, ContactsToMultipleAccounts}, map[string]string{})
if len(result) != 2 {
Expand Down Expand Up @@ -162,6 +172,16 @@ func TestExpandProductsToFeatures_CommunitiesProduct(t *testing.T) {
}
}

func TestExpandProductsToFeatures_B2BCommerceProduct(t *testing.T) {
result := expandProductsToFeatures([]ScratchProduct{B2BCommerceProduct}, []ScratchFeature{}, map[string]string{})
if len(result) != 1 {
t.Errorf("Expected 1 feature from b2bcommerce product, got %d", len(result))
}
if result[0] != "B2BCommerce" {
t.Errorf("Expected B2BCommerce, got %s", result[0])
}
}

func TestExpandProductsToFeatures_HealthCloudProduct(t *testing.T) {
result := expandProductsToFeatures([]ScratchProduct{HealthCloudProduct}, []ScratchFeature{}, map[string]string{})
if len(result) != 2 {
Expand Down Expand Up @@ -226,6 +246,16 @@ func TestExpandProductsToSettings_CommunitiesProduct(t *testing.T) {
}
}

func TestExpandProductsToSettings_B2BCommerceProduct(t *testing.T) {
result := expandProductsToSettings([]ScratchProduct{B2BCommerceProduct}, []ScratchSetting{})
if len(result) != 1 {
t.Errorf("Expected 1 setting from b2bcommerce product, got %d", len(result))
}
if result[0] != "commerceEnabled" {
t.Errorf("Expected commerceEnabled, got %s", result[0])
}
}

func TestExpandProductsToSettings_CommunitiesProductWithAdditionalSetting(t *testing.T) {
result := expandProductsToSettings([]ScratchProduct{CommunitiesProduct}, []ScratchSetting{EnableEnhancedNotes})
if len(result) != 2 {
Expand Down Expand Up @@ -281,6 +311,42 @@ func TestScratchEditionIds_AllEditionsDefined(t *testing.T) {
}
}

func TestScratchFeatureIds_AllFeaturesDefined(t *testing.T) {
expectedFeatures := map[string]bool{
"AnalyticsAdminPerms": true,
"B2BCommerce": true,
"Communities": true,
"ContactsToMultipleAccounts": true,
"DevelopmentWave": true,
"EinsteinAnalyticsPlus": true,
"EinsteinBuilderFree": true,
"EventLogFile": true,
"FinancialServicesUser": true,
"HealthCloudAddOn": true,
"HealthCloudUser": true,
"ApexUserModeWithPermset": true,
"InsightsPlatform": true,
"PersonAccounts": true,
"StateAndCountryPicklist": true,
"WavePlatform": true,
}

if len(ScratchFeatureIds) != len(expectedFeatures) {
t.Errorf("Expected %d features, got %d", len(expectedFeatures), len(ScratchFeatureIds))
}

for _, ids := range ScratchFeatureIds {
if len(ids) != 1 {
t.Errorf("Expected 1 ID per feature, got %d", len(ids))
continue
}
featureName := ids[0]
if !expectedFeatures[featureName] {
t.Errorf("Unexpected feature: %s", featureName)
}
}
}

func TestConvertSettingsToStrings_NoSettings(t *testing.T) {
result := convertSettingsToStrings([]ScratchSetting{})
if len(result) != 0 {
Expand Down Expand Up @@ -318,6 +384,16 @@ func TestConvertSettingsToStrings_NetworksEnabled(t *testing.T) {
}
}

func TestConvertSettingsToStrings_CommerceEnabled(t *testing.T) {
result := convertSettingsToStrings([]ScratchSetting{CommerceEnabled})
if len(result) != 1 {
t.Errorf("Expected 1 setting, got %d", len(result))
}
if result[0] != "commerceEnabled" {
t.Errorf("Expected commerceEnabled, got %s", result[0])
}
}

func TestConvertSettingsToStrings_EnableApexApprovalLockUnlock(t *testing.T) {
result := convertSettingsToStrings([]ScratchSetting{EnableApexApprovalLockUnlock})
if len(result) != 1 {
Expand Down Expand Up @@ -353,6 +429,7 @@ func TestScratchSettingIds_AllSettingsDefined(t *testing.T) {
"enableEnhancedNotes": true,
"enableQuote": true,
"networksEnabled": true,
"commerceEnabled": true,
"enableApexApprovalLockUnlock": true,
"permsetsInFieldCreation": true,
"enableLightningPreviewPref": true,
Expand Down
5 changes: 4 additions & 1 deletion docs/force_login_scratch.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Create scratch org and log in

Available Features:
AnalyticsAdminPerms - Enables CRM Analytics admin permissions
B2BCommerce - Enables B2B Commerce
Communities - Enables Experience Cloud (Communities)
ContactsToMultipleAccounts - Allows a single Contact to be associated with multiple Accounts
DevelopmentWave - Enables CRM Analytics development features
Expand All @@ -24,6 +25,7 @@ Available Features:
WavePlatform - Enables Wave Platform (CRM Analytics)

Available Products:
b2bcommerce - B2B Commerce (enables B2BCommerce feature and commerceEnabled setting)
communities - Experience Cloud (enables Communities feature and networksEnabled setting)
crmanalytics - CRM Analytics (enables AnalyticsAdminPerms, WavePlatform, InsightsPlatform, EinsteinAnalyticsPlus, EinsteinBuilderFree, DevelopmentWave)
fsc - Financial Services Cloud (enables PersonAccounts, ContactsToMultipleAccounts, FinancialServicesUser)
Expand All @@ -43,6 +45,7 @@ Available Settings (deployed after org creation):
enableEnhancedNotes - Enable Enhanced Notes
enableQuote - Enable Quotes
networksEnabled - Enable Experience Cloud (Communities)
commerceEnabled - Enable Commerce
enableApexApprovalLockUnlock - Allow Apex to lock/unlock approval processes
permsetsInFieldCreation - Allow assigning permission sets during field creation
enableLightningPreviewPref - Enable Lightning Experience preview pref
Expand All @@ -59,6 +62,7 @@ Examples:
force login scratch --edition Enterprise --product fsc
force login scratch --setting enableEnhancedNotes
force login scratch --setting enableQuote
force login scratch --product b2bcommerce
force login scratch --product communities
force login scratch --product crmanalytics
force login scratch --product healthcloud
Expand Down Expand Up @@ -96,4 +100,3 @@ force login scratch [flags]
### SEE ALSO

* [force login](force_login.md) - Log into Salesforce and store a session token

12 changes: 12 additions & 0 deletions lib/scratch.go
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ func buildSettingsMetadata(settings []string) ForceMetadataFiles {
apexSettings := false
userManagementSettings := false
lightningExperienceSettings := false
commerceSettings := false

for _, setting := range settings {
switch setting {
Expand All @@ -228,6 +229,8 @@ func buildSettingsMetadata(settings []string) ForceMetadataFiles {
<enableNetworksEnabled>true</enableNetworksEnabled>
</CommunitiesSettings>`
files["unpackaged/settings/Communities.settings"] = []byte(communitiesSettings)
case "commerceEnabled":
commerceSettings = true
case "enableApexApprovalLockUnlock":
apexSettings = true
case "permsetsInFieldCreation":
Expand Down Expand Up @@ -264,6 +267,15 @@ func buildSettingsMetadata(settings []string) ForceMetadataFiles {
files["unpackaged/settings/LightningExperience.settings"] = lexBuffer.Bytes()
}

if commerceSettings {
var commerceBuffer bytes.Buffer
commerceBuffer.WriteString(`<?xml version="1.0" encoding="UTF-8"?>
<CommerceSettings xmlns="http://soap.sforce.com/2006/04/metadata">
<commerceEnabled>true</commerceEnabled>
</CommerceSettings>`)
files["unpackaged/settings/Commerce.settings"] = commerceBuffer.Bytes()
}

return files
}

Expand Down
23 changes: 23 additions & 0 deletions lib/scratch_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,29 @@ func TestBuildSettingsMetadata_ExcludesLightningExperienceSettingsWhenUnused(t *
}
}

func TestBuildSettingsMetadata_AddsCommerceSettings(t *testing.T) {
files := buildSettingsMetadata([]string{"commerceEnabled"})

content, ok := files["unpackaged/settings/Commerce.settings"]
if !ok {
t.Fatalf("Commerce.settings not generated")
}
if !strings.Contains(string(content), "<commerceEnabled>true</commerceEnabled>") {
t.Errorf("Commerce.settings missing commerceEnabled preference:\n%s", content)
}
if !strings.Contains(string(content), "<CommerceSettings ") {
t.Errorf("Commerce.settings missing CommerceSettings metadata type:\n%s", content)
}
}

func TestBuildSettingsMetadata_ExcludesCommerceSettingsWhenUnused(t *testing.T) {
files := buildSettingsMetadata([]string{"enableEnhancedNotes"})

if _, ok := files["unpackaged/settings/Commerce.settings"]; ok {
t.Fatalf("Commerce.settings should not be generated when not requested")
}
}

func TestGetScratchOrg_returns_error_when_SignupUsername_is_nil(t *testing.T) {
f := &Force{}
f.Credentials = &ForceSession{}
Expand Down
Loading