Global Find and Replace Rules
The Global Find and Replace Rules feature allows you to define custom find and replace rules that Copado applies whenever you commit and deploy files org-to-org or git-to-org.
The rules must be written in a .YML file and then uploaded to Copado as an attachment, or created online with Copado's YAML Editor, in an Environment record and/or a Deployment Flow record. If the Copado.yml file is uploaded in a deployment flow, the rules will apply to any deployments and commits of the environments and the branches of the deployment flow. If the Copado.yml file is uploaded to an environment, the rules will apply to metadata/Git metadata deployments.
Copado's Global Find & Replace Online Rule Editor:
As of Copado v11, the YAML editor in Copado shows and warns about tabs and white spaces, among other errors.
In order to open the rule editor just open the environment or deployment flow and click on the Rule Editor button.
A common use case for this feature is to remove offending XML tags that will make a file not deployable, see the examples below:
- Remove all ManageSandbox user permissions from a profile, since this user permission only exists in production environments and will fail if you try to deploy it to sandboxes.
- Remove FLS of deprecated fields, etc.
Click here to open a sample Copado.yml file.
.YML File Structure
The .YML file structure must have two sections: regex_lib and rules. These sections are configured as follows:
The "regex_lib" section contains the 'find' regex expressions. These regex expressions are saved in a variable name so that they can be referenced in the rules section.
In the following example, the 'find' regex expression for a field is assigned to a variable name called "field":
The "rules" section contains one or more rules to be executed. A rule consists of a rule name and several rule parameters. The rule name cannot have spaces or special characters.
- A list of the exact names of the metadata files where the find and replace will be executed (e.g. "Account.object", "MyCustomLayout.layout", etc.).
- The rule will execute once for every file name listed.
- If you use file_names you cannot use extensions, but at least one of those is required.
- A list of the metadata file extensions where the find and replace will be executed (e.g. "object", "layout", etc.).
- The rule will execute once for every file that has one of the extensions listed.
- If you use extensions you cannot use file_names, but at least one of those is required.
- The variable name of the regex expression defined in the regex_lib section.
- Required value.
- A list of values to replace in the regex expression (___REPLACEVALUE___).
- If you do not need to replace values, you can omit replace_values and the ___REPLACEVALUE___ text.
- The value that will replace the text that is found by the regex expression.
- Leaving this parameter blank means the matching regex will be deleted instead of being replaced with this.
- No backreferences are allowed ( \1 or $1 in the replacement string ).
- The list of Git branches where the rule applies. If left blank, the rule applies to all Git branches.
- The list of Git branches where the rule does not apply (as of Copado v8.5). This parameter overrides the branches parameter in case both are included in the .YML file. If left blank, the rule applies to all Git branches.
In the following example, the 'invalid_fields' rule will be applied to the Account and Contact objects. The rule's regex expression is 'field' and the values to be replaced in the regex expression are 'History__c' and 'History_Date__c'. The value to replace this with is blank, since the purpose of the rule is to delete the fields. If using the Git integration, the branches where the rule applies are dev1, uat and master.
invalid_fields: #this is the rule name
Important Details on How to Create Regular Expressions
To avoid surprises, you should always:
- Use (?s) at the beginning to match newlines with the dot operator.
- Non-greedy qualifiers ( *? and +? ), never regular ones ( * and + ), to avoid consuming the longest possible match.
- With nested tags, use assertions (?!text). This will force the regular expression to skip nested tags.
'<a>1</a> <a> 2 </a> <a>3</a>'.replace( new RegExp('(s?)<a>.*?2.*</a>'), "xxx")
// incorrect, results in "xxx", replacing the first <a> until the last </a>
'<a>1</a> <a> 2 </a> <a>3</a>'.replace( new RegExp('(s?)<a>.*? 2 .*?.*?</a>'), "xxx")
// incorrect, results in "xxx <a>3</a>", replacing the first <a> until the first </a>
'<a>1</a> <a> 2 </a> <a>3</a>'.replace( new RegExp('(s?)<a>(?:(?!</a><a>).)*? 2 .*?(?:(?!</a>).)*?'), "xxx")
// correct, results in "<a>1</a> xxx <a>3</a>", replacing the first <a> until the first </a> that contains the text " 2 "