Modular devops with Salesforce
23 Sep 2022
I created 5 folders inside a parent folder and opened up the parent folder in VSCode.
Opened the terminal into folder2
.
Ran cci flow run dev_org --org beta
in a folder with nothing but a .gitignore
. Error was Error: The file cumulusci.yml was not found in the repo root: C:\folder2. Are you in a CumulusCI Project directory?
. So I definitely need a cumulusci.yml
file. Hmmm – let’s see what cci project init
makes.
# Project Info
The following prompts will collect general information about the project
Enter the project name. The name is usually the same as your repository name. NOTE: Do not use spaces in the project name!
Project Name [sf-devops-02-org-agnostic-utils]:
CumulusCI uses an unmanaged package as a container for your project's metadata. Enter the name of the package you want to use.
Package Name [sf-devops-02-org-agnostic-utils]:
Is this a managed package project? [y/N]: N
Salesforce API Version [55.0]:
Salesforce metadata can be stored using Metadata API format or DX source format. Which do you want to use?
Source format (sfdx, mdapi) [sfdx]:
# Extend Project
CumulusCI makes it easy to build extensions of other projects configured for CumulusCI like Salesforce.org's NPSP and EDA. If you are building an extension of another project using CumulusCI and have
access to its Github repository, use this section to configure this project as an extension.
Are you extending another CumulusCI project such as NPSP or EDA? [y/N]: y
Please select from the following options:
1: EDA (https://github.com/SalesforceFoundation/EDA)
2: NPSP (https://github.com/SalesforceFoundation/NPSP)
3: Github URL (provide a URL to a Github repository configured for CumulusCI)
Enter your selection: 2
# Git Configuration
CumulusCI assumes the current git branch is your default branch, your feature branches are named feature/*, your beta release tags are named beta/*, and your release tags are release/*. If you want to use a different branch/tag naming scheme, you can configure the overrides here. Otherwise, just accept the defaults.
Default Branch [main]:
Feature Branch Prefix [feature/]:
Beta Tag Prefix [beta/]:
Release Tag Prefix [release/]:
# Apex Tests Configuration
The CumulusCI Apex test runner uses a SOQL where clause to select which tests to run. Enter the SOQL pattern to use to match test class names.
Test Name Match [%_TEST%]:
Do you want to check Apex code coverage when tests are run? [Y/n]:
Minimum code coverage percentage [75]:
dot-gitignore already exists. As a reference, here is what would be placed in the file if it didn't already exist:
# CCI
.cci
/src.orig
/src
# Python
*.pyc
__pycache__
# Robot Framework results
robot/sf-devops-02-org-agnostic-utils/results/
# Salesforce cache
.sf/
.sfdx/
.localdevserver/
deploy-options.json
# LWC VSCode autocomplete
**/lwc/jsconfig.json
# LWC Jest coverage reports
coverage/
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Dependency directories
node_modules/
# Eslint cache
.eslintcache
# MacOS system files
.DS_Store
# Windows system files
Thumbs.db
ehthumbs.db
[Dd]esktop.ini
$RECYCLE.BIN/
# Editors
*.sublime-project
*.sublime-workspace
.vscode
.idea
.project
.settings
Your project is now initialized for use with CumulusCI
Here’s the sfdx-project.json
it made:
{"packageDirectories": [{"path": "force-app", "default": true}], "namespace": null, "sourceApiVersion": "55.0"}
Here’s the cumulusci.yml
it made:
minimum_cumulusci_version: '3.65.0'
project:
name: sf-devops-02-org-agnostic-utils
package:
name: sf-devops-02-org-agnostic-utils
api_version: '55.0'
dependencies:
- github: 'https://github.com/SalesforceFoundation/NPSP'
git:
default_branch: 'main'
source_format: sfdx
tasks:
robot:
options:
suites: robot/sf-devops-02-org-agnostic-utils/tests
options:
outputdir: robot/sf-devops-02-org-agnostic-utils/results
robot_testdoc:
options:
path: robot/sf-devops-02-org-agnostic-utils/tests
output: robot/sf-devops-02-org-agnostic-utils/doc/sf-devops-02-org-agnostic-utils_tests.html
run_tests:
options:
required_org_code_coverage_percent: 75
It created an empty force-app
folder.
I deleted README.md
, robot
folder that came w/ a test-contact, I went ahead and left the 4 beta.json
, dev.json
, feature.json
, and release.json
configs it gave me in orgs
, the datasets/mapping.yml
folder it made me with the way one would populate Account
and Contact
if one had some data handy, and the .github/PULL_REQUEST_TEMPLATE.md
file it made me.
Ok, actually, I deleted everything, updated my .gitignore
a bit, and added a cumulusci.yml
like this:
project:
name: devops-demo-02-org-agnostic-utils
package:
name: DevOps Demo 02 - Org-Agnostic Utils
git:
default_branch: 'main'
source_format: sfdx
Now I get this error from cci flow run dev_org --org beta
: Error: [Errno 2] No such file or directory: 'orgs/beta.json'
.
Guess I’ll grab those 4 no-dependency org templates out of .ignoreme
and throw them in, changing the package name a bit.
OK, now cci flow run dev_org --org beta
errors out as follows:
[09/23/22 07:35:38] ============================================================
Initializing flow: FlowCoordinator (dev_org)
Set up an org as a development environment for unmanaged metadata
============================================================
Verifying and refreshing credentials for the specified org: beta.
Creating scratch org with command: sfdx force:org:create --json -f orgs/beta.json -w 120 -n --durationdays 1 -a devops-demo-02-org-agnostic-utils__beta
[email protected]
Error: Failed to create scratch org:
{
"status": 1,
"name": "RequiresDevhubUsername",
"message": "This command requires a dev hub org username set either with a flag or by default in the config.",
"exitCode": 1,
"context": "OrgCreateCommand",
"stack": "RequiresDevhubUsername: This command requires a dev hub org username set either with a flag or by default in the config.\n at Messages.createError (C:\\Program
Files\\sfdx\\client\\node_modules\\@salesforce\\core\\lib\\messages.js:446:16)\n at OrgCreateCommand.run (C:\\Program
Files\\sfdx\\client\\node_modules\\salesforce-alm\\dist\\commands\\force\\org\\create.js:102:32)\n at async OrgCreateCommand._run (C:\\Program
Files\\sfdx\\client\\node_modules\\@salesforce\\command\\lib\\sfdxCommand.js:89:40)\n at async Config.runCommand (C:\\Program
Files\\sfdx\\client\\node_modules\\@oclif\\config\\lib\\config.js:173:24)\n at async SfdxMain.run (C:\\Program Files\\sfdx\\client\\node_modules\\@oclif\\command\\lib\\main.js:27:9)\n at async
SfdxMain._run (C:\\Program Files\\sfdx\\client\\node_modules\\@oclif\\command\\lib\\command.js:43:20)\n at async Object.run (C:\\Program Files\\sfdx\\client\\dist\\cli.js:162:47)",
"warnings": [],
"commandName": "OrgCreateCommand"
}
Ok, let’s see what I nicknamed various orgs I’ve logged the sfdx
CLI into: sfdx force:auth:list
.
=== authenticated orgs
ALIAS USERNAME ORG ID INSTANCE URL AUTH METHOD
───────────── ───────────────── ────────────────── ─────────────────────────────── ───────────
sfdxorgalias1 [email protected] 00D111111111111AAA https://example1.salesforce.com web
sfdxorgalias2 [email protected] 00D222222222222BBB https://example2.salesforce.com web
Cool, I’ll pick sfdxorgalias1
.
I have to do all of the following (inside each repo’s folder – .sfdx
above the 5 one level doesn’t work):
.sfdx/sfdx-config.json
of{"defaultdevhubusername": "sfdxorgalias1"}
.sfdx-project.json
of{"packageDirectories": [{"path": "force-app","default": true}],"namespace": null, "sourceApiVersion": "53.0"}
. I hate locking down version, but as of today, we’re in release-season, and CumulusCI is already trying to do version 56.0 when I don’t specify, but scratch orgs with the hub I picked are still on version 55.0.force-app/.gitkeep
(lest I getError: Command exited with return code 1: ERROR running force:source:tracking:reset: The path "force-app", specified in sfdx-project.json, does not exist. Be sure this directory is included in your project root.
).
Ok, now cci flow run dev_org --org beta
works, as does cci org browser --org beta
.
I added a test class and a unit test class to a project and ran cci task run dx_push --org beta
(without having yet committed my changes) and refreshed the Apex Classes page in my browser and sure enough, there they were. Yay, commit and push.
OK, I went over to folder2
and spun it up w/ just a force-app/.gitkeep
baseline, broswer’ed just fine.
Then I ran cci task run update_dependencies --org beta
after adding - github: https://github.com/kkgthb/sf-devops-02-org-agnostic-utils
to project.dependencies
in cumulusci.yml
an dit said it was pushing out 2 Apex classes.
Refreshing the Apex Classes page in the browser, they show up!
Run All Tests works great (93%). It seems that even though the tests came from #2 and the scratch org was spun up from #4, the resulting org considers them native, not “packaged” in any way.
Let’s throw in a proper package as a second dependency and see what happens.
See comments of my YAML for this. Interestingly, all of the repos that have proper packages – managed or unmanaged – do this – hence version IDs:
Resolving dependencies...
Error: 404 Not Found
aoristdual — Today at 1:38 PM
Yeah, I should have been more specific. What I described is required to consume package versions. When you use a repo like that one as a dependency, CumulusCI will see that there are no releases and fall back to deploying the latest commit on the main branch as unmanaged metadata.
project:
name: devops-demo-04-an-hr-feature
package:
name: DevOps Demo 04 - An HR Feature
dependencies:
- github: https://github.com/kkgthb/sf-devops-02-org-agnostic-utils
- version_id: '04t6g000008b0RpAAI' # Apex rollup. Unmanaged package. 2 minutes to deploy. Shows up with null "Namespace Prefix" but a value in "Installed Package." Banner alerts "This Apex Class is part of a package. You'll lose any edits you make directly in the org if you reinstall or upgrade the package. Immediately inform your development team of any changes you make." Uninstallable from "Installed Packages" settings page.
#- version_id: '04t5Y0000015lvuQAA' # 04t5Y0000015lvuQAA is Nebula Logger unlocked package; 04t5Y0000015lsgQAA is Nebula Logger managed package
- version_id: '04t4x000000RqyHAAS' # RecordTypePicker. Unlocked package. 1-2 minutes to deploy.
- namespace: et4ae5 # Marketing Cloud. Managed package. 10 minutes to deploy. Shows up with "Namespace Prefix" & "Marketing Cloud" both populated. Banner alerts "This Apex Class is managed, meaning that you may only edit certain attributes." Uninstallable from "Installed Packages" settings page.
version: 238.3
git:
default_branch: 'main'
source_format: sfdx