Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

build(sfdx): update cli commands to sf #64

Merged
merged 1 commit into from
Apr 26, 2023
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
121 changes: 63 additions & 58 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,27 @@ This code was developed for Marketing Admins who want to automate and enforce th
> This application is designed to run on the Salesforce Platform

- [Campaign Type Member Statuses](#campaign-type-member-statuses)
- [A solution for Protected Campaign Member Statuses and step-by-step instructions for use.](#a-solution-for-protected-campaign-member-statuses-and-step-by-step-instructions-for-use)
- [Originally written by Adam Erstelle](#originally-written-by-adam-erstelle)
- [A solution for Protected Campaign Member Statuses and step-by-step instructions for use.](#a-solution-for-protected-campaign-member-statuses-and-step-by-step-instructions-for-use)
- [Originally written by Adam Erstelle](#originally-written-by-adam-erstelle)
- [**Protected Campaign Member Statuses**](#protected-campaign-member-statuses)
- [Get started](#get-started)
- [**That's cool.** **What's behind the curtain?**](#thats-cool-whats-behind-the-curtain)
- [How it Works](#how-it-works)
- [New Campaign Created](#new-campaign-created)
- [Editing a Campaign Type Member Status](#editing-a-campaign-type-member-status)
- [Removing a Campaign Type Member Status](#removing-a-campaign-type-member-status)
- [FAQ](#faq)
- [Do you have any suggested statuses?](#do-you-have-any-suggested-statuses)
- [Why Don't you just prevent people from messing around with Protected Statuses?](#why-dont-you-just-prevent-people-from-messing-around-with-protected-statuses)
- [I get Apex test errors after deploying the code. How can I fix them?](#i-get-apex-test-errors-after-deploying-the-code-how-can-i-fix-them)
- [Installation Instructions](#installation-instructions)
- [What You Get](#what-you-get)
- [Pushing Code to a Sandbox](#pushing-code-to-a-sandbox)
- [Installing into a Scratch Org](#installing-into-a-scratch-org)

## A solution for Protected Campaign Member Statuses and step-by-step instructions for use.

### Originally written by [Adam Erstelle](https://thespotforpardot.com/author/adamsercante-com/)
- [Get started](#get-started)
- [**That's cool.** **What's behind the curtain?**](#thats-cool-whats-behind-the-curtain)
- [How it Works](#how-it-works)
- [New Campaign Created](#new-campaign-created)
- [Editing a Campaign Type Member Status](#editing-a-campaign-type-member-status)
- [Removing a Campaign Type Member Status](#removing-a-campaign-type-member-status)
- [FAQ](#faq)
- [Do you have any suggested statuses?](#do-you-have-any-suggested-statuses)
- [Why Don't you just prevent people from messing around with Protected Statuses?](#why-dont-you-just-prevent-people-from-messing-around-with-protected-statuses)
- [I get Apex test errors after deploying the code. How can I fix them?](#i-get-apex-test-errors-after-deploying-the-code-how-can-i-fix-them)
- [Pushing Code to a Sandbox](#pushing-code-to-a-sandbox)
- [Installing into a Scratch Org](#installing-into-a-scratch-org)

# A solution for Protected Campaign Member Statuses and step-by-step instructions for use.

## Originally written by [Adam Erstelle](https://thespotforpardot.com/author/adamsercante-com/)

We go through all the effort of setting up beautiful Salesforce Campaigns, naming standards and maybe even a hierarchy. The next challenge in completing your beautiful work of campaign art is getting a hold on your Campaign Member Statuses for each campaign.

Expand All @@ -51,7 +51,23 @@ Protected Campaign Member Statuses is a solution to solve this problem of automa
3. Create additional Statuses for specific reasons.
4. Override by authorized users on a per-Campaign basis.

### Get started
# Installation Instructions

- [Pushing Code to a Sandbox](#pushing-code-to-a-sandbox)
- [Installing into a Scratch Org](#installing-into-a-scratch-org)

## What You Get

When deploying this package to your org, you will get:

- 1 Custom Metadata Type (and page layout)
- 1 Campaign Custom Field
- 1 ChangeDataCapture configuration
- 2 Apex Triggers
- 5 Production Apex Classes
- 3 Apex Test Classes

## Get started

Once installed, you need to define your Protected Statuses. This is done with Custom Metadata Types.

Expand Down Expand Up @@ -87,70 +103,58 @@ You are good to go once you have provided your statuses. Give it a whirl by crea

Campaigns with Types not already set up will keep the default two statuses that Salesforce creates.

## **That's cool.** **What's behind the curtain?**
# **That's cool.** **What's behind the curtain?**

To accomplish this, we leverage a few cool tools available to us:

- Custom Metadata Types: Allows the Protected Statuses to be treated like normal Salesforce metadata and can be deployed around like any other metadata (changesets, insert devops tool here)
- Campaign Custom Field: Campaign.Has_Protected_Campaign_Member_Statuses\_\_c is automatically checked by the solution if a Campaign is created and there are Custom Metadata Type records that specify this Campaign's Type. It is also what allows the rest of the code to keep the statuses intact. You can clear the checkbox for this field to make changes to the statuses if you need to. However, you can't enable protection afterwards.
- Campaign Custom Field: `Campaign.Has_Protected_Campaign_Member_Statuses__c` is automatically checked by the solution if a Campaign is created and there are Custom Metadata Type records that specify this Campaign's Type. It is also what allows the rest of the code to keep the statuses intact. You can clear the checkbox for this field to make changes to the statuses if you need to. However, you can't enable protection afterwards.
- Change Data Capture: We turn this on for CampaignMemberStatus so we can detect edits to statuses and then fix the records after-the-fact. Sadly we can't (yet?) put any triggers on CampaignMemberStatus (which would have been ideal).
- Triggers: We use them to kick off the automation that we've built when a Campaign is created. We also use them to watch for Campaign Member Status edits (through the ChangeEvents from Change Data Capture) so we can set things right afterwardsd.

If you want even more details, check out the [original Github project](https://github.com/sercante-llc/protected-campaign-statuses) where you can see all the inner workings of what is going on.

## How it Works
# How it Works

Once everything is set up, Campaigns should maintain a consistent set of Campaign Member Statuses. Here's how we accomplish that.

### New Campaign Created
## New Campaign Created

When a new Campaign is created, we check to see if the Type of Campaign is defined in any of the Protected Campaign Member Status records (the Custom Metadata Type that was set up earlier). If there is a match, the solution will:

1. Automatically add a checkbox to the Campaign Custom Field "Has Campaign Type Member Statuses".
1. Automatically adjust the CampaignMemberStatus records to match all Protected Campaign Member Statuses expected

### Editing a Campaign Type Member Status
## Editing a Campaign Type Member Status

For a Campaign that "Has Campaign Type Member Statuses", when one of the CampaignMemberStatus records is edited we will double check all statuses of that Campaign to make sure that all Protected ones still exist. If there are any missing, they will be recreated almost instantly (you may need to refresh the page for them to show up if there's a delay).

### Removing a Campaign Type Member Status
## Removing a Campaign Type Member Status

If a user removes a Campaign Type Member Status, the Scheduled Job (that was created as part of [Post-Install Configuration](#installation-instructions)) will search for Campaigns missing a Status and recreate it.

## FAQ
# FAQ

### Do you have any suggested statuses?
## Do you have any suggested statuses?

Of course! Here are a few to get your creative juices flowing.

![Suggested Campaign Member Statuses](doc-assets/assets/CMStatuses.png)

### Why Don't you just prevent people from messing around with Protected Statuses?
## Why Don't you just prevent people from messing around with Protected Statuses?

We really wish we could. A "before update" and "before delete" Apex Trigger would be the simplest way to handle this. Unfortunately, Apex Triggers are not (yet) possible on CampaignMemberStatus records, so we end up having to fix it after-the-fact.

### I get Apex test errors after deploying the code. How can I fix them?
## I get Apex test errors after deploying the code. How can I fix them?

If you have Apex tests which set up a Campaign record as part of the test, the functionality in this package will get called and might blow up. This is because how Salesforce internally treats the automatic generation of Campaign Member Status records when a new Campaign is created (it's weird).

You have 2 options:

1. For the purpose of the test, disable this functionality. You can accomplish this by adding `TriggerHandler.bypass('CampaignTriggerHandler` in your Apex Test set up.
2. To actually see the records that Salesforce would create, you would need to have your test `@isTest(seeAllData=true)`. There are a lot of considerations with this approach, so please use wisely.

# Installation Instructions

## What You Get

When deploying this package to your org, you will get:

- 1 Custom Metadata Type (and page layout)
- 1 Campaign Custom Field
- 1 ChangeDataCapture configuration
- 2 Apex Triggers
- 5 Production Apex Classes
- 3 Apex Test Classes
1. To actually see the records that Salesforce would create, you would need to have your test `@isTest(seeAllData=true)`. There are a lot of considerations with this approach, so please use wisely.

## Pushing Code to a Sandbox
# Pushing Code to a Sandbox

Follow this set of instructions if you want to deploy the solution into your org without using an Unlocked Package. This will require a Sandbox, and then a ChangeSet to deploy into Production.

Expand All @@ -168,16 +172,17 @@ Follow this set of instructions if you want to deploy the solution into your org
- or [install from npm](https://www.npmjs.com/package/sfdx-cli)
```shell
npm install --global sfdx-cli
npm install @salesforce/cli --global
```

1. Authorize your Salesforce org and provide it with an alias (**myorg** in the commands below)

```shell
# Connect SFDX to a Sandbox Org
sfdx force:auth:web:login -s -a myorg -r https://test.salesforce.com
# Connect your project to a Sandbox Org
sf org login web --set-default --alias myorg --instance-url https://test.salesforce.com

# if for some reason you need to specify a specific URL, use this slightly altered command, making the correct adjustments
sfdx force:auth:web:login -s -a myorg -r https://mycompanyloginurl.my.salesforce.com
# if you need to specify a specific URL, use this slightly altered command, making the correct adjustments
sf org login web --set-default --alias myorg --instance-url https://mucustomdomain.my.salesforce.com
```

1. Run a series of commands to deploy each of the three parts, or skip to the next item to push them all at once
Expand All @@ -187,40 +192,40 @@ Follow this set of instructions if you want to deploy the solution into your org
Or run this command in a terminal to deploy the required trigger handler

```shell
sfdx force:source:deploy -p triggerhandler --tracksource
sf project deploy start --source-dir triggerhandler --tracksource
```

Run this command in a terminal to deploy the main code

```shell
sfdx force:source:deploy -p force-app --tracksource -u myorg
sf project deploy start --source-dir force-app --alias myorg
```

Run this command in a terminal to deploy the bundled sample custom metadata

```shell
sfdx force:source:deploy -p unpackaged --tracksource -u myorg
sf project deploy start --source-dir unpackaged --alias myorg
```

1. Or just run one command to push all three parts in sequence

```shell
sfdx force:source:push
sf project deploy start
```

1. You'll need a custom permission set to access the Campaign field, or just add it to an existing permission set and delete this one

```shell
sfdx force:user:permset:assign -n Campaign_Type_Member_Status_Admin
sf org assign permset --name Campaign_Type_Member_Status_Admin --target-org myorg
```

1. Continue with [Post-Install Configuration](#installation-instructions)
1. Continue with [Post-Install Configuration](#get-started))

## Installing into a Scratch Org
# Installing into a Scratch Org

1. Set up your environment. The steps include:

- Enable Dev Hub in your org
- Enable Dev Hub in your main org
- [Install Salesforce CLI](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_install_cli.htm)

1. If you haven't already done so, authorize your hub org and provide it with an alias (**myhuborg** in the command below):
Expand All @@ -239,7 +244,7 @@ Follow this set of instructions if you want to deploy the solution into your org
1. Run the included script to create a scratch org and push the metadata

```shell
. scripts/scratchorg.sh
. scripts/campaignmember-scratchorg.sh
```

1. Continue with [Post-Install Configuration](#installation-instructions)
1. Continue with [Post-Install Configuration](#get-started))
4 changes: 2 additions & 2 deletions apexdox.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ engine:
scope:
- global
- public
- protected
#- protected
- private
- webService
#- webService
- testMethod
homePagePath: '${workspaceFolder}/doc-assets/main.html'
#pages:
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@
"test": "npm run test:unit",
"apex:local:start": "node node_modules/prettier-plugin-apex/dist/bin/start-apex-server.js",
"apex:local:stop": "node node_modules/prettier-plugin-apex/dist/bin/stop-apex-server.js",
"apex:test:local": "rm testresults/* && sfdx force:apex:test:run -l RunLocalTests -d testresults -r human -c",
"pmd:scan:csv": "$HOME/pmd/bin/run.sh pmd -d force-app -R pmd/ruleset.xml -f csv -r pmd/pmd.csv --cache .pmdCache --short-names",
"pmd:scan:deploy:csv": "$HOME/pmd/bin/run.sh pmd -d force-app -R pmd/deployRules.xml -f csv -r pmd/deploy.csv --cache .pmdCache --short-names",
"apex:test:local": "rm testresults/* && sf apex run test --test-level RunLocalTests --output-dir testresults --result-format human --code-coverage",
"pmd:scan:csv": "$HOME/pmd/bin/check --dir force-app --rulesets pmd/ruleset.xml --format csv --rulesets pmd/pmd.csv --cache .pmdCache --short-names",
"pmd:scan:deploy:csv": "$HOME/pmd/bin/check --dir force-app --rulesets pmd/deployRules.xml --format csv --rulesets pmd/deploy.csv --cache .pmdCache --short-names",
"precommit": "lint-staged",
"prepare": "husky install",
"prettier:apex": "prettier --write \"force-app/**/*.cls\"",
Expand Down
10 changes: 5 additions & 5 deletions scripts/campaignmember-push.sh
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
# UNMANAGED for use with developer edition or playground

echo "Clearing namespace"
#echo "Clearing namespace"
#sed -i "" "s|\"namespace\": \"\"|\"namespace\": \"\"|" sfdx-project.json

# For use with developer edition or playground
echo "Pushing source..."
sfdx force:source:deploy -p triggerhandler --tracksource
sfdx force:source:deploy -p force-app --tracksource
sfdx force:source:deploy -p unpackaged --tracksource
sf project deploy start --source-dir triggerhandler
sf project deploy start --source-dir force-app
sf project deploy start --source-dir unpackaged

echo "opening org..."
sfdx force:org:open
sf org open
14 changes: 5 additions & 9 deletions scripts/campaignmember-scratchorg.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,19 @@ sf org delete scratch --no-prompt --target-org CampaignMemberStatus
#sed -i "" "s|\"namespace\": \"\"|\"namespace\": \"\"|" sfdx-project.json

echo "Creating new scratch org"
#sfdx force:org:create --definitionfile config/project-scratch-def.json --setalias CampaignMemberStatus --nonamespace --setdefaultusername --noancestors --durationdays 14 -w 20
sf org create scratch --definition-file config/project-scratch-def.json --alias CampaignMemberStatus --no-namespace --set-default --duration-days 3 --track-source --wait 20

# For use with namespaced scratch org in package development process
echo "Deploying metadata"
#sf deploy metadata --source-dir triggerhandler
#sf deploy metadata --source-dir force-app
#sf deploy metadata --source-dir unpackaged

sfdx force:source:push
sf project deploy start --source-dir triggerhandler
sf project deploy start --source-dir force-app
sf project deploy start --source-dir unpackaged

sf org assign permset --name Campaign_Type_Member_Status_Admin --target-org CampaignMemberStatus

sfdx force:apex:test:run -l RunLocalTests -r human -w 20
sf apex run test --test-level RunLocalTests --wait 20

echo "opening org"
sfdx force:org:open
#sf env open
sf org open

echo "Org is set up"