Need to update my presentation slide

I was asked to give a talk on the upcoming SF Meetup.

I have started from the first slide, need to update it since there were changes.

I have currently a position of Associate Salesforce Architect
I have 3 personal Listings Published on AppExchange
I am the #50th on Salesforce Stack Exchange
I am 17x Salesforce Certified Specialist
I have 12 years of Development experience
I have 10 years of Salesforce Development experience

Posted in Self-promotion | Tagged , | Leave a comment

Use sh scripts to get the current user permissions to a field

In the past, I was describing how we can use Apex to find out the current permissions of a user to a particular field

Today I would like to expand this topic further and present you sample scripts which can be used.

Sometimes query on FieldDefinition do not work if the current user doesn’t have access to the field. Instead, we can use Tooling API to query CustomField object directly, but then we will have to cut off the last three symbols of Field Id.

First we can write a short sh script getUserId.sh to get user Id by some parameter like following

sf data query -q "SELECT Id FROM User WHERE $1 = '$2' LIMIT 1" --json | jq '.result.records[0].Id' -r

Then we can write a short sh script getFieldId.sh to get field Id like following

sf data query -q "SELECT Id FROM CustomField where EntityDefinitionId = '$1' AND DeveloperName = '$2'" -t --json | jq '.result.records[0].Id' -r

Also we need a short sh script getUserFieldAccess.sh to get User Field Level Access like following 

sf data query -q "SELECT Id, IsAccessible, IsUpdatable FROM UserFieldAccess WHERE DurableId = '$1.$2.$3' LIMIT 1"

And finally we can write the script checkFieldsAccess.sh to check access

userId=$(./getUserId.sh "Profile.Name" "Salesforce API Only System Integrations")
for field in Field1 Field2 Field3 Field4 Field5
do
    fieldId=$(./getFieldId.sh Account $field)
    len=${#fieldId}
    fieldId=${fieldId:0:$len-3}
    echo "Verifying access for $field field with Id $fieldId for user $userId"
    ./getUserFieldAccess.sh Account $fieldId $userId
done
Posted in field, sh | Tagged , , | Leave a comment

Regexp to replace empty field permissions

<fieldPermissions>
<editable>false</editable>
<field>([a-zA-z0-9_]+.[a-zA-z0-9_]+.)</field>
<readable>false</readable>
</fieldPermissions>
view raw fp.apex hosted with ❤ by GitHub
Posted in Uncategorized | Leave a comment

How can I quickly fetch or grab sfdx auth url?

When we need to know sfdx auth url to transfer it to another machine or use as CI/CD Secret key in Github or Gitlab, and we have multiple environments, like 10+ different Developer Edition, Sandboxes and Devhub environments which are needed in CI/CD process, this requires a long time to manually execute sfdx force:org:display --verbose command for every environment and then manually grab and find SFDX Auth URL from the response to copy and paste it into Secrets.

Is there a way to automate this or make it more easy to grab the SFDX Auth URL from the command response?

Yes! Actually we can leverage JQ tool to quickly grab the SFDX Auth URL from the command using --json switch. I have posted this solution into SSE.

Still we need to authorize the env

sfdx force:auth:web:login -a al -r https://test.salesforce.com for sandbox or skip -r parameter for production/Developer Edition environment and substitute al with actual desired alias for the org; and then use --json parameter and pass the result to jq command

sfdx force:org:display -u al --verbose --json | jq '.result.sfdxAuthUrl' -r

To install jq, use brew install jq on MacOS.

Sample sh script to be used for that

echo "$(sfdx force:org:display -u $1 –verbose –json | jq '.result.sfdxAuthUrl' -r)"
view raw grab.sh hosted with ❤ by GitHub

and can be used like ./grab.sh al

where al is your alias.

Posted in CI/CD, sfdx | Tagged , , , | Leave a comment

How do I create, fetch or grab SFDX Auth URL?

Assuming that you have SFDX CLI tool installed, perform the next steps.

  1. First set up an alias for an org. For sandbox or scratch org, use the following command changing alias to the desired alias of your sandbox or scratch org

sfdx force:auth:web:login -a alias -r https://test.salesforce.com

To set up an alias for the production or developer edition org, -r parameter can be omitted like following

sfdx force:auth:web:login -a alias

The browser window should open, where you need to input your credentials and authorize SFDX app.

2. Execute the following command to grab the SFDX Auth URL (change al with your alias)

sfdx force:org:display -u al --verbose --json | jq '.result.sfdxAuthUrl' -r

To install jq, use brew install jq on MacOS.

3. Copy SFDX Auth URL where needed to update the CI or store the credential on another machine as alias.txt file and then executing the command

sfdx auth:sfdxurl:store -f ./alias.txt -a alias


Posted in sfdx | Tagged , , | Leave a comment

Which actions should be completed before a package can be moved to another devhub?

  1. We need to link client customer namespace to the new devhub org.
  2. We need to remove error notification user from every package we want to migrate by running a command sfdx package update --package 0Ho00000000PACKAGE --error-notification-username ''
  3. Open a Salesforce support case and wait for the Salesforce support team to complete the migration/transition.
Posted in Uncategorized | Leave a comment

How to rename or change signature for a namespace accessible or global method?

Let’s assume that we have a base package and package extension.

Let’s assume that we have some base class BasePackageClass in the base package

@namespaceAccessible
public inherited sharing BasePackageClass{
@namespaceAccessible public void method() {}
}

which we extend inside a class ExtensionPackageClass which is part of Extension package

public inherited sharing ExtensionPackageClass extends BasePackageClass{
public override void method() {}
}

Let’s assume we have successfully released package version 1.0 of base package and package version 1.0 of extension package. Now we want to modify either method name or method signature for the BasePackageClass as follows

@namespaceAccessible
public inherited sharing BasePackageClass{
@namespaceAccessible public void method(String a, String b, String c, String d, String e) {}
}

and we also have to modify extensing class ExtensionPackageClass to

public inherited sharing ExtensionPackageClass extends BasePackageClass{
public override void method(String a, String b, String c, String d, String e) {}
}

If we try to build both packages and install them in a fresh org, no error will happen, but if we try to install first package version 1.0 of base and extension packages and then upgrade to base package version 1.1, we will receive an error

Dependent class is invalid and needs recompilation: Class Namespace.ExtensionPackageClass : Method does not exist or incorrect signature: void method(NULL, NULL, NULL, NULL, NULL) from the type Namespace.BasePackageClass

It is clear something wrong here, which means we shouldn’t rename global or namespace accessible method like that, so how should we rename or update signature for a namespace accessible method correctly?

We would have to keep the original signature and name of base class method at least for one release but we can mark it as deprecated like follows

@namespaceAccessible
public inherited sharing BasePackageClass{
@deprecated @namespaceAccessible public void method() {}
@namespaceAccessible public void method(String a, String b, String c, String d, String e) {}
}

while in ExtensionPackageClass we don’t have to keep the original implementation but rather get rid of it

public inherited sharing ExtensionPackageClass extends BasePackageClass{
public override void method(String a, String b, String c, String d, String e) {}
}

Now, why do we have to do this? If we try to upgrade Base Package to 1.1, it fails since classes compilation run during upgrade for both base and extension packages and Extension Package 1.1 cannot be compiled with the code base of Base Package 1.0 since method method has changed signature.

enter image description here

The correct way is to deprecate the base method with old name or old signature and add a TODO comment to delete that method in a subsequent release and update signature of the overridden method method in Extension package 1.1 so that the method without parameters in base class could be deleted in the subsequent release after the current release.

enter image description here

If someone would directly try to upgrade 1.0 to 1.2, that would fail with the same error as we have now, but for that we will have a resolution: someone should upgrade first to 1.1 and Extension Package 1.1 and only after that upgrade to 1.2.

Another option to have dynamic implementation is to use Callable interface.

Posted in apex, extension, namespace, package | Tagged , , , | Leave a comment

Publishing Your Package to AppExchange in 2023

This is my presentation https://www.slideshare.net/JulfyPatlatus/publishing-your-package-to-appexchangein-2023

and this is the video of my speech

Posted in package | Tagged , , | Leave a comment

Namespace shadowing and namespace prepending in Salesforce

First of all, this post is about managed package development.

When developing managed package, usually development takes place in unnamespaced scratch org or sandbox in personal scratch org or personal sandbox per each developer and then the code is merged together inside a developer branch in version control system like Git on git repository system like Github or Gitlab and then the code from developer branch is build into 2GMP version by SFDX or deployed into packaging org for 1GMP and a package version is built there.

There are some peculiarities and differences between having packaged namespaced code and unpackaged code without namespace. Also, sandboxes cannot have namespace. Still, scratch org support namespace. So one of the possible way of development might be working with namespaced scratch orgs and hard-coding namespaces there. On my recent project I couldn’t go with that route since when we started project development we didn’t have access to the client namespace so we couldn’t hardcode it. For POC and MVP we were building the package with my personal namespace and then we rebuilt it with client namespace one they have setup it on devhub but before that time we were expected to deliver some results and show how managed packages work.

So even if we used namespaced scratch org and started hardcoding namespaces there, it wouldn’t work for us since when we got access to devhub with presetup client namespace we would have then to change every hardcoded namespace into another one. So we ended up using dynamic namespace prepending. But before we deep dive into that let’s discover what is namespace shadowing and what are the other options.

Namespace shadowing is a term which describes how Apex code works with custom objects and fields inside a managed package. Let’s assume we have a custom object CustomObject__c with a custom field CustomField__c. When we want to query this record, we write as follows:

CustomObject__c record = [SELECT CustomField__c FROM CustomObject__c LIMIT 1];

Let’s assume now we build a package with namespace ns and try to run the same code in the same class, it would work without any issue inside packaged class. If we want to access this object by unmanaged code on the org where the package is installed, we would have to prepend a namespace like follows:

ns__CustomObject__c record = [SELECT ns__CustomField__c FROM ns__CustomObject__c LIMIT 1];

We could also use the same query inside a package assuming we are deploying that code into a packaging org for 1GMP or to namespaced scratch org. However, we wouldn’t be able to deploy that code into unnamespaced scratch org or a sandbox.

Assume that a customer created a custom field with coincides with the name of our packaged field, and now on custom object ns__CustomObject__c there are two fields: ns__CustomField__c and CustomField__c. Now field CustomField__c is not available to our package, since anytime if we try to refer it in a static SOQL or dynamic SOQL, a namespace prefix will be automatically prepended and internally CustomField__c will be changed into ns__CustomField__c and packaged code will not be able to access it. If, however, a field will be created with a different name like CustomField1__c and there are no such field with such name inside a package, this field will be available to access, since when apex tries to access such field, and it doesn’t find it in a package, it accesses it without namespace. This is how namespace shadowing works.

Now let’s go further. If we try to refer an object or a field inside a FrontEnd like Visualforce Javascript, LWC or retired Aura. then there will be no namespace shadowing. That means we would have to prepend prefix ourselves or decide another options. Which options do we have?

Option 1. Create DTO model class and refer in LWC or Visualforce that class instance and properties instead of object or fields.

public inherited sharing class CustomObjectDTOModel {

@AuraEnabled public String customField {get; set;}

public CustomObjectDTOModel(CustomObject record) {

customField = record.CustomField__c;

}

}

Now instead of passing directly an Object like follows:

public inherited sharing class Controller{

@AuraEnabled @RemoteAction

public static CustomObject__c getRecord() {

return [SELECT CustomField__c FROM CustomObject__c LIMIT 1];

}

}

we change this into

public inherited sharing class Controller{

@AuraEnabled @RemoteAction

public static CustomObjectDTOModel getRecord() {

return new CustomObjectDTOModel([SELECT CustomField__c FROM CustomObject__c LIMIT 1]);

}

}

and we refer not to CustomField__c field but to DTO Model property customField which is namespace agnostic.

Option 2. Automatically prepend namespace before building a package version.

For example, we still need to prepend namespace in some other places. When one LWC parent refers another LWC child, inside a unnamespaced org, it should look <c:child> but when it is inside a packaged code, it should looke like <ns:child>

We can use some script like follows

rm -r force-app

cp -r ../unpackaged/force-app .

namespace=$(cat sfdx-project.json | jq ‘.namespace’ -r)

find force-app -type f \( -name “*.app” -o -name “*.component” -o -name “*.page” \) -exec sed -i ” “s/c:/$namespace:/g” {} \;

to replace every <c:child> with <ns:child> in every LWC, VisualforcePage or Lightning App. We could implement a similar script for namespacing fields, but in this case it is hard to determine a generic replace rule unless we follow some convention. For example, if we agree to have every field started with F_ we then could potentially have script like

find force-app -type f \( -name “*.app” -o -name “*.component” -o -name “*.page” \) -exec sed -i ” “s/ F_/ ${namespace}F_:/g” {} \;

Option 3. Instead of hardcoding or mingling with namespaces manually or by CI/CD script, we could use dynamic namespace prepending. This approach works in the following way.

First of all, we need to determine if we are inside a managed package or unpackaged code.

If we know that we have a CustomObject__c with a CustomField__c inside our package, we can refer to Namespace Shadowing to determine that. if namespace shadowing occurs, we are inside a managedd package and if it doesn’t occur, we are inside an unmanaged unpackaged code.

public static String getNamespace() {

Schema.DescribeFieldResult dfr = CustomObject__c.CustomField__c.getDescribe();

return dfr.getName().remove(dfr.getLocalName());

}

public static String getBareNamespace() {

String prefix = getNamespace();

return prefix.left(prefix.length() – 2);

}

This is not the only option but just one of the many options available to determine namespace.

Now whenever we want to know namespace, we can call getNamespace method to get it. We may cache it not to call it many times during a single transaction but for the sake of simplicity I don’t show caching code here.

Inside our example, getNamespace() method will returnthe whole prefix ns__, the namespace and double underscore for the packaged code and empty string for unpackaged code. If we need just the bare namepsace without double underscore insertion, we might use getBareNamespace() method.

We may use getBareNamespace() method if we for example, have both namespaced and unnamespaced permission set with the same name and we want to distinguish them.

For example, if we want to query all users who are assigned packaged permission set.

[

SELECT Email, FirstName, LastName, UserName

FROM User WHERE Id IN (

SELECT AssigneeId FROM PermissionSetAssignment

WHERE PermissionSet.Name = ‘PermissionSet’ AND PermissionSet.NamespacePrefix =: getBareNamespace()

)

];

I hope this is helpful for you.

Posted in apex, namespace, package | Tagged , , , , , | Leave a comment

CI/CD problem with package version creation has been fixed in SFDX CLI

On June 8th 2023, the issue has been fixed by SFDX CLI Team on the 8th of June by changing the library it uses for zip files.

https://github.com/forcedotcom/cli/tree/main/releasenotes/sfdx#72046-june-8-2023

FIX: We’ve fixed a number of issues related to Node.js v18.16.0. If you followed our suggestions for working around the issues, you can now return to the version of Node.js you were using before and update Salesforce CLI to the latest version. (GitHub issue #2125, source-deploy-retrieve PR #975)

https://github.com/forcedotcom/source-deploy-retrieve/pull/975

bug report in upstream node: https://github.com/nodejs/node/issues/48406

Previous workaround required to downgrade NodeJS to the previous version like following, for example, for Github Actions CI/CD:

- uses: actions/setup-node@v3
  with:
    node-version: 18.15.0
Posted in CI/CD | Tagged | Leave a comment