Teach Me Salesforce

A community approach to learning salesforce.com

Salesforce DX Monoliths: Chipping Away at the Metadata (part 2)

leave a comment »

After carefully removing all the metadata that I do not think I’ll need I got myself to the test of force:source:push again. It seems like I’ll always have to do –forceoverwrite because I always see a conflict with the Business Account record type.

The source:push generated some errors of course. The first two that jump out at me are those related to history-tracked fields:

force-app/main/default/objects/Lead.object-meta.xml The entity: Lead does not have history tracking enabled
N/A The entity: Account does not have history tracking enabled (12:13)

I mistook this for issues with the  true in the object files to accompany the true in the fields’ definitions but it actually appears to be due to true because when I deleted the Record Type History Tracking I was able to avoid the error.

The next error I got seems like it might actually be a bug (I’ll explain after)

N/A Required field is missing: businessProcess (75:18)

Since I’m trying to deploy Leads with a Record Type, you need to have a business process associated with the record type. I did keep the .businessProcess file for this purpose but I noticed that there is no  tag in the Lead’s .recordType file’s XML. I reverted the file back to its original state to make sure I hadn’t inadvertently deleted it. When I added  and the name of the Business Process, that error along with another one that was apparently related was cleared up.

force-app/main/default/permissionsets/My_pSet.permissionset-meta.xml In field: field – no CustomField named Lead.my_field__c found

I’m glad the above error was somehow dependent on fixing the business process because I had no idea why that would be considered missing. Now it seems like it must be due to the compiler’s inability to load the Record Type which defined that picklist’s values for the Record Type.

The next error was coming from the PersonAccounts, which frankly are performing much better than expected given their troublesome history.

force-app/main/default/objects/PersonAccount.object-meta.xml An unknown exception has occurred.

I was able to clear this up by removing  Private from the PersonAccount.object-meta.xml file. I didn’t consider it on my first review but when I was looking at the file now I realized that there is no sharingModel setting for a PersonAccount since it’s not a real object. Account takes care of its sharing model setting.

One error remains!

force-app/main/default/profiles/API.profile-meta.xml invalid cross reference id

The dreaded “invalid cross reference id”! Oh how many times I’ve been stumped by those 4 vague words. I guessed correctly that it’s probably the reference to the PersonAccount.PersonAccount record so I simply deleted it from the profile altogether…and Hooray! I got the metadata to push successfully!

Advertisements

Written by Always Thinkin

January 17, 2018 at 4:38 pm

Posted in Uncategorized

Salesforce DX Monoliths: Chipping Away at the Metadata

leave a comment »

Yesterday I started preparations to build a package from actual production metadata after experimenting with 2GP in a Trial DX Org first. My goal is quite modest: a package with the 4-5 fields and matching Permission Set necessary for one of our integrations.

The preparations followed a predictable pattern:

  1. Authorize a new DevHub (I’ve got 35 orgs, I hope my DevHub aliasing convention works for the other 32 yet to be DXed!)
  2. Clone the git repo where our metadata is backed up daily by Copado (fast easy way to do this).
    1. Create a new branch for DX-related manipulations.
  3. Create a new DX project (finally understood the difference between –outputdir and –defaultpackagedir. I mistook outputdir as the location that new metadata files would go into eventually. But it’s simply the location that the sfdx-project.json, config/scratch-project-def.json, .forceignore and the readme.MD)

Then began the process of getting just the metadata I wanted in the package. I saw a couple approaches:

  1. Create and populate the files manually (maybe just cutting and pasting from actual metadata).
  2. Retrieve the actual metadata and remove what I don’t want in the package.

The first would probably have been faster and what I would do in the future but I thought it would be a good exercise to remind myself of all the metadata that is there and be sure I kept all the dependencies intact.

So for a couple hours I used git rm -r to remove all the unnecessary metadata from the branch. This was tedious, especially when I had to leave one file like a Permission Set but delete all the other files in a folder.

After getting down to just the two Objects with fields I want plus the Profile and Permission Set that will be used for the integration user, I attempted my first $sfdx force:mdapi:convert -r ../src/ -d force-app/
and I got an errorI had deleted my package.xml and had to restore it and strip out all the unnecessary references.

After I restored the package.xml, the convert worked although I got an apparently non-critical fatalError message because I left a ” </recordTypeVisibilities>” tag in the profile file. I think I also had a missing end tag in the package.xml.

[xmldom fatalError] end tag name: recordTypeVisibilities is not match the current start tagName:Profile
@#[line:8,col:30]
[xmldom error] element parse error: end tag name: recordTypeVisibilities is not match the current start tagName:Profile
@#[line:8,col:30]
[xmldom fatalError] end tag name: Profile is not match the current start tagName:undefined
@#[line:24,col:23]
[xmldom error] element parse error: end tag name: Profile is not match the current start tagName:undefined
@#[line:24,col:23]

But the convert worked anyway. I had decided to leave the two Object files intact rather than remove all the additional metadata in them. So I ended up with extra folders I’ll have to delete:

  • fieldSets
  • listViews
  • recordTypes
  • validationRules
  • webLinks
  • Plus the Account.object-meta.xml with ActionOverrides and other metadata I won’t need.

When I ran sfdx force:source:push -f I left <trackHistory>true</trackHistory> in the field definition files but had deleted the object-metadata.xml file that contained the <enableHistory>true</enableHistory> so I got errors like:

PROJECT PATH ERROR
───────────────────────────────────────────────────────────
N/A                      The entity: Account does not have history tracking enabled (3:13)
N/A                      The entity: Lead does not have history tracking enabled (3:13)

And I had a couple of custom picklist values in the Lead businessProcess and the Account recordType files that I had to remove from the XML.

PROJECT PATH ERROR
───────────────────────────────────────────────────────────N/A                      Picklist value: New not found (48:24)
N/A                      Picklist value: inboundcounselor in picklist: AccountSource not found (37:18)

But, one of those picklist values was the default, so I got a very tricky error:

PROJECT PATH ERROR
───────────────────────────────────────────────────────────N/A                     No default value specified (48:24)

And I could only figure that one out by noticing that the 48:24 reference matched a previous error so at least I could look in the correct file for the problem.

At this point I recognized that I should have left the StandardValueSet in place so that the businessProcess file can refer to the picklist values for Lead.Status. I was expecting that other dependencies were waiting for me so I decided I should just start over. git reset –hard ffc1b. Glad I was committing frequently as I made small changes!

 

Written by Always Thinkin

January 14, 2018 at 5:16 pm

Salesforce DX Monoliths: Exploring 2GP (2nd Generation Packaging)

with one comment

In preparation for breaking up my monolithic metadata, I’m working out how to use Second Generation Packaging or 2GP. Following the documentation’s suggestion, I’m not doing this in my own production orgs but rather in a DX Trial Org.

I studied first to get an idea of how to use 2GP, you can see the Resources list of those sites below.

I created a Scratch Org and added only 2 simple components: a custom field and a permission set for that field.

When I attempted to pull the components with force:pull to my local environment I got the error:

ERROR: Metadata API received improper input. Please ensure file name and capitalization is correct. Load of metadata from db failed for metadata of type:Profile and file name:admin.

which I could only resolve by adding Admin.profile to my .forceignore file. At first this bothered me because I was concerned that the Admin profile would not get access to the new field but as with any installed package, you can ensure that Admins get access to all components during the install process.

After getting the metadata pulled down to my /force-app folder I started the process of creating an unlocked package.

I started by running sfdx force:package2:version:create -d force-app -v gs-trial-devhub and got the expected return message:

Package2 version creation request is InProgress. Run “sfdx force:package2:version:create:get -i 08c1I000000003jQAA” to query for status.

but when I ran sfdx force:package2:version:create:get -i 08c1I000000003jQAA I got an unexpected message:

ERROR:
Tag, Branch, CreatedDate FROM Package2VersionCreateRequest WHERE
^
ERROR at Row:1:Column:125
sObject type ‘Package2VersionCreateRequest’ is not supported. If you are attempting to use a custom object, be sure to append the ‘__c’ after the entity name. Please reference your WSDL or the describe call for the appropriate names.

Try this:
Second-generation packaging is not enabled on this org. Verify that you are authenticated to the desired org and try again. Otherwise, contact Salesforce Customer Support for more information.

And, yes, I had neglected to enable Second Generation Packaging in my org. That was easy enough to resolve. After enabling it I got the expected return messages when running sfdx force:package2:version:create:get -i 08c1I000000003jQAA

=== Package2 Version Create Request
NAME VALUE
────────────────────────────── ──────────────────
ID 08c1I000000003jQAA
Status InProgress
Package2 Id 0Ho1I0000008OJDSA2
Package2 Version Id
Subscriber Package2 Version Id
Tag
Branch
Created Date 2018-01-09 18:09

And a little while later, success!

=== Package2 Version Create Request
NAME VALUE
────────────────────────────── ──────────────────
ID 08c1I000000003jQAA
Status Success
Package2 Id 0Ho1I0000008OJDSA2
Package2 Version Id 05i1I000000001nQAA
Subscriber Package2 Version Id 04t1I000003cm03QAA
Tag
Branch
Created Date 2018-01-09 18:09

After that though, things got troublesome. I decided to see what happens if you try to install a package that has not been released with the command so I ran sfdx force:package:install -u gs-trial-devhub -i 04t1I000003cm03QAA and I got:

PackageInstallRequest is still InProgress or Unknown. You can query the status using
sfdx force:package:install:get -i 0Hf1I000000Qe9cSAC -u gs-trial-devhub

When I ran the suggested command, sfdx force:package:install:get -i 0Hf1I000000Qe9cSAC -u gs-trial-devhub, I got:

ERROR: Encountered errors installing the package!,Installation errors:
1) Package(0331I000000m3Qe) Unable to install beta package, Details: The package you attempted to install is a beta package, which you can only install in Force.com Sandbox or Developer Edition organizations.
ERROR: Installation errors:
1) Package(0331I000000m3Qe) Unable to install beta package, Details: The package you attempted to install is a beta package, which you can only install in Force.com Sandbox or Developer Edition organizations.

(Note that the above messages changed recently to read “Can’t install package in a production org, Details: You can install this second-generation package only in a sandbox or scratch org.”)

Now I assumed this was because I hadn’t released the package, so I ran sfdx force:package2:version:update -i 05i1I000000001nQAA -v gs-trial-devhub –setasreleased and got the expected message:

Successfully updated the package version. ID: 05i1I000000001nQAA.

But even with a released package, I was still unable to install the package into my DX Trial Org’s Dev Hub.

So next I created a new Scratch Org and for about 4 hours I got the same messages when trying to install the package and check its status. The first two attempts to run sfdx force:package:install -ugs-scratchorg01 -i 04t1I000003cm03QAA resulted in the same status messages as above.

Finally after the 3rd attempt at installing the package in the new Scratch Org  I logged in to the org and I was able to see the Installed Package, and when I returned to the CLI I got the happy success message when I ran sfdx force:package:install:get -i 0Hf3D0000008SUeSAM -u gs-scratchorg01

Successfully installed package [04t1I000003cm03QAA]

One note is that installing from the CLI apparently defaults the installation settings to “Install for All Users” because all the Profiles in the Scratch Org have read and edit access to the new field – even the Read Only Profile.

I can’t actually conclude that I did something different that solved this. It is a beta product, so maybe that’s why there was some delays.

Resources:

Trailblazer Community Group “Packaging 2 Beta”: https://success.salesforce.com/_ui/core/chatter/groups/GroupProfilePage?g=0F93A000000Lg5U

Sign up for a DX Trial Org: https://developer.salesforce.com/promotions/orgs/dx-signup

DF17 Session “How Everyone Can Leverage Salesforce DX Packaging”: https://success.salesforce.com/Sessions?eventId=a1Q3A00000stRRuUAM#/session/a2q3A000000GV6nQAG

Developer Controlled Packages Description, Tips and Practice Demo: https://success.salesforce.com/0693A0000068ZKt

And, of course, TFM: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_dev2gp.htm?search_text=forceignore

Written by Always Thinkin

January 10, 2018 at 3:47 pm

Building Salesforce DX Scratch Orgs from Monolithic Metadata

leave a comment »

Salesforce DX is revolutionizing SDLC for SFDC. Getting all your metadata from a mature org (the proverbial Monolithic metadataset) is a challenge. I am accepting that challenge and documenting the struggle here, for you.

This post will likely grow over time as I refine the process. Or, perhaps like the advice I’ve read to break down your metadata into distinct modular applications, this will break down into multiple posts.

My Salesforce environment is composed of ~35 UE Orgs that have similar metadata, roughly 80% consistency. So I’ll get to do this ~35 times to perfect it.

Our metadata is hopefully average enough that it represents a good cross-section of the typical Salesforce org out there and thus will help others in this project.

Some Metadata Stats:

Custom Objects: 44
Lines of Apex Code: 161,849 characters of Apex Code
Installed Packages: 0 (actually quite a few but left out of the DX metadata)

Step 1: Metadata Retrieval

I use Copado to backup my metadata daily to Github. So I did not have to use one of the metadata retrieval tools (e.g. Salesforce package.xml Builder) to establish my full set of metadata for conversion.

Step 2: Metadata Conversion

This was the first hurdle. I used sfdx force:mdapi:convert on the unedited metadata I retrieved and starting receiving errors. (error message TK)

I attempted to delete the specific referenced files like SvgIcon.cmp but it seemed like every file in the aura/SvgIcon/ and aura/Toast/ folders was going to throw the error so I deleted all the files and left the empty folders. This allowed me to successfully convert my metadata.

However, I made a mistake in the referenced target folder (-d OUTPUTDIR) in sfdx force:mdapi:convert -r . -d ./force-app and instead of going to the force-app/ folder I created as a sibling to config, the force-app folder was created automatically in the same folder as all my metadata.

Step 3. Create the Scratch Org

Nothing fancy here: sfdx force:org:create -d 30 -v 2U-DevHub -f config/project-scratch-def.json -a 2Ufull01 with the following configs:

{
“orgName”: “2U”,
“country”: “US”,
“edition”: “Enterprise”,
“hasSampleData”: “false”,
“features”: [“PersonAccounts”, “Communities”, “CustomApps”, “CustomTabs”, “DebugApex”, “API”,”MultiCurrency”, “AuthorApex”],
“orgPreferences”: {
“enabled”: [“NetworksEnabled”,”S1DesktopEnabled”, “ChatterEnabled”],
“disabled”: [“IsNameSuffixEnabled”]
}
}

Step 4. Pushing the Metadata

This is where I expect things to get really hard, and where I’ll be documenting what had to be done to make it work.

Next Up: Salesforce DX Monoliths: Exploring 2GP (2nd Generation Packaging)

Written by Always Thinkin

January 4, 2018 at 11:43 am

Posted in Uncategorized

Apex Workshop Webinar 11: Custom Settings

leave a comment »

The video for the workshop session on Apex with Custom Settings can be found on YouTube here: https://youtu.be/UGFvV501qHo

The trigger and its unit test we worked with in this session is available here:

Written by Always Thinkin

July 8, 2017 at 7:15 pm

Posted in Uncategorized

Apex Workshop Webinar 10: Exception Handling

leave a comment »

The video for the workshop session on Apex Exception Handling can be found on YouTube here: https://youtu.be/mFlUdCNsfso

The trigger and its unit test we worked with in this session is available here:

Written by Always Thinkin

July 8, 2017 at 7:05 pm

Posted in Uncategorized

Apex Workshop Webinar 9: Unit Tests

leave a comment »

The video for the workshop session on Apex Unit Testing can be found on YouTube here: https://youtu.be/s_45tsHHbp0

The trigger and its unit test we worked with in this session is available here:

Written by Always Thinkin

July 8, 2017 at 7:01 pm

Posted in Uncategorized