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.
Rules must be defined in YAML format, which is an industry-standard format to store information in a structure that can be easily read by humans and interpreted by machines.
If the Copado.yml file is uploaded in a pipeline, the rules will apply to any deployments and commits in the environments and the branches of the pipeline. 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:
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 Pipeline record and click on the Find & Replace 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.
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 rule defines the following:
- The files or file types to which a regex base is applied.
- The rule-specific modifications to be made to the base during runtime, when the logic is executed.
- The branches to which the rule should be applied.
- In the case of a match, you can specify if you want to delete it or replace it with another string.
- 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 back references are allowed ( \1 or $1 in the replacement string ).
- The list of Git branches where the rule applies. If left blank, the rule will apply to all Git branches.
- The list of Git branches where the rule does not apply. This parameter overrides the branches parameter in case both are included in the .YML file. If left blank, the rule will apply to all Git branches.
In the following example, the 'invalid_fields' rule will be applied to the Account and Contact objects. The regex expression of the rule 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
file_names: - 'Account.object' - 'Contact.object'regex_name: 'field'replace_values: - History__c - History_Date__cbranches: - dev1 - uat - masterreplace_with:
How to Use Global Find and Replace Rules in a Deployment Step
You can use the Find and Replace functionality in a specific deployment step to remove from or replace the offending tags in a specific deployment. To do this, follow the steps below:
- Go to a Deployment record and click on the deployment step.
- Click on Add Find/Replace text:
- This will display the find and replace boxes:
- In the Find box on top, enter the find regex expression for the tag that is causing your deployment to fail, and in the Replace with the box below, enter the value you want to use to replace the tag. If what you want to do is remove it, just leave it empty.
The below will skip the Create Custom Badge Definitions user permission for all the profiles and permission sets included in that deployment:
- You can continue clicking on Add Find/Replace text to perform multiple replacements.
- Once you are done, click on Save in the deployment step and redeploy.
Important Details on How to Create Regular Expressions
To avoid surprises, you should always:
- Use (?s) at the beginning to match new lines with the dot operator.
- Use 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 "