# P4Sudo — Use Cases --- ## Use Case 001: Bootstrap Black Belt INFO.md on PPN ### Overview When a new customer is onboarded to the Perforce **Black Belt** consulting subscription program, a standard `INFO.md` file must be created from a template and submitted to the PPN (Perforce Partner Network) P4 server in a customer-specific depot path. A corresponding row must also be added to a shared customer index file. This is a technically complex operation requiring P4 super access (creating depots and streams), but the person initiating it is typically a non-technical program manager. P4Sudo exposes this as a single web-form interaction backed by a script that handles all P4 operations transparently. **Server:** PPN (`ssl:50.18.77.74:1670` / `ssl:ppn.perforce.com:1670`) **Command name:** `mkblackbelt` **Command type:** site-defined script **Invocation:** `p4 sudo mkblackbelt [options]` --- ### Authorization | Who | Access | |-----|--------| | Black Belt program managers | Authorized to run `mkblackbelt` via web UI | | P4 administrators | Can run all `p4 sudo` commands | This command runs exclusively via the web UI; CLI invocation is for admin/debug use only. --- ### Workflow The command executes the following steps in order. Any abort leaves the ephemeral workspace in place (to aid debugging) and logs a detailed error. ``` 1. Validate inputs 2. Fetch INFO.md template from PPN 3. Provision // stream depot (idempotent) 4. Provision ///main stream (idempotent) 5. Create ephemeral workspace for ///main 6. Instantiate INFO.md from template (text substitution) 7. Submit INFO.md to ///main/BlackBelt/INFO.md 8. Delete ephemeral workspace (only on success) 9. Update CustomerIndex.md via persistent BlackBelt workspace ``` #### Step-by-step detail **Step 1 — Validate inputs** - All required fields present and non-empty - CustomerTag matches pattern: alphanumeric, any case, no spaces, no special characters, must not start with a digit - Dates in YYYY/MM/DD format - Abort with descriptive error on any validation failure **Step 2 — Fetch template** - `p4 print -q -o //BlackBelt/main/docs/INFO.md.template` - Abort if file cannot be fetched (log P4 error output) - No workspace needed for this step **Step 3 — Provision depot** - Check: `p4 depots -e ` — if exists, skip creation and continue - If not: `p4 depot -i` to create a stream depot named `` - Abort if creation fails **Step 4 — Provision stream** - Check: `p4 streams -e ///main` — if exists, skip and continue - If not: `p4 stream -i` to create `///main` as a mainline stream - Abort if creation fails **Step 5 — Create ephemeral workspace** - Name: `p4sudo-mkblackbelt--` - Root: a temp directory (e.g. `/tmp/p4sudo-mkblackbelt--`) - Stream: `///main` - Owner: `p4sudo-svc` - On success of step 8: delete workspace and temp directory - On abort: leave workspace and temp directory in place for debugging **Step 6 — Instantiate INFO.md** - Perform token substitutions on the fetched template (see Substitution Tokens section below) - Write result to `/BlackBelt/INFO.md` **Step 7 — Submit INFO.md** - `p4 -c add /BlackBelt/INFO.md` - `p4 -c submit -d "Bootstrap Black Belt INFO.md for "` - Abort if add or submit fails **Step 8 — Delete ephemeral workspace** *(only on success)* - `p4 client -d ` - Remove temp directory **Step 9 — Update CustomerIndex.md** - Uses persistent workspace mapped to `//BlackBelt/main` - `p4 -c sync //BlackBelt/main/Customers/CustomerIndex.md` - `p4 -c edit //BlackBelt/main/Customers/CustomerIndex.md` - Insert new row in the **Active Customers** table (see Row Format below) - `p4 -c submit -d "Add to Black Belt Customer Index"` - Abort if any step fails --- ### Template and Substitution Tokens **Template location on PPN:** `//BlackBelt/main/docs/INFO.md.template` | Token | Field | Notes | |-------|-------|-------| | `__EDITME_CUSTOMER_TAG__` | CustomerTag | Used in multiple places | | `__EDITME_SALESFORCE_LINK__` | Salesforce URL | Full URL | | `__EDITME_YYYY_MM_DD__` | Activation date | Date INFO.md is created (auto-set to today) | | `__EDITME_LICENSED_USERS__` | Licensed user count | Integer | | `__EDITME_BACKGROUND_USERS__` | Background user count | Integer | | `__EDITME_PROGRAM_START_DATE__` | Program start date | YYYY/MM/DD | | `__EDITME_PROGRAM_END_DATE__` | Program end date | YYYY/MM/DD | | `__EDITME_CONTACT_1_NAME__` | Customer contact 1 name | | | `__EDITME_CONTACT_1_EMAIL__` | Customer contact 1 email | | | `__EDITME_CONTACT_1_ROLE_AND_NOTES__` | Customer contact 1 role | | | `__EDITME_CONTACT_2_NAME__` | Customer contact 2 name | Optional | | `__EDITME_CONTACT_2_EMAIL__` | Customer contact 2 email | Optional | | `__EDITME_CONTACT_2_ROLE_AND_NOTES__` | Customer contact 2 role | Optional | | `__EDITME_P4_PRIMARY_NAME__` | P4 primary contact name | | | `__EDITME_P4_PRIMARY_EMAIL__` | P4 primary contact email | | | `__EDITME_P4_PRIMARY_ROLE_AND_NOTES__` | P4 primary contact role | | | `__EDITME_P4_SECONDARY_NAME__` | P4 secondary contact name | Optional | | `__EDITME_P4_SECONDARY_EMAIL__` | P4 secondary contact email | | | `__EDITME_P4_SECONDARY_ROLE_AND_NOTES__` | P4 secondary contact role | | | `__EDITME_P4_EXTRA_1_NAME__` | P4 extra contact 1 name | Optional | | `__EDITME_P4_EXTRA_1_EMAIL__` | P4 extra contact 1 email | Optional | | `__EDITME_P4_EXTRA_1_ROLE_AND_NOTES__` | P4 extra contact 1 role | Optional | | `__EDITME_P4_EXTRA_2_NAME__` | P4 extra contact 2 name | Optional | | `__EDITME_P4_EXTRA_2_EMAIL__` | P4 extra contact 2 email | Optional | | `__EDITME_P4_EXTRA_2_ROLE_AND_NOTES__` | P4 extra contact 2 role | Optional | | `__EDITME_YY_MM_DD__` | History entry date | Auto-set to today (YY/MM/DD format) | **Note:** Virginia Tong `` appears as a hard-coded P4 staff contact in the template (Program Management role). No substitution needed for that row. --- ### CustomerIndex.md Row Format **File location on PPN:** `//BlackBelt/main/Customers/CustomerIndex.md` New rows are appended to the **Active Customers** table. The link uses the P4 Code Review (Swarm) URL format: ```markdown | [](https://ppn.perforce.com/files//main/BlackBelt/INFO.md) | Active | | | | | | ``` | Column | Source | |--------|--------| | Customer | CustomerTag (linked to Swarm URL) | | Status | Always `Active` for new entries | | Start | Program Start Date (YYYY/MM/DD) | | End | Program End Date (YYYY/MM/DD) | | Tier | User input (Standard / Enterprise / Essential) | | Comms | User input (e.g. `Slack #ext-`) | | Notes | User input (optional free text) | --- ### Web UI Form Fields The web form presents the following inputs. Fields marked **Required** must be filled before submission; **Optional** fields may be left blank (tokens for those fields will be replaced with an empty string in the generated INFO.md, pending manual cleanup). #### Customer Identity | Field | Type | Required | Notes | |-------|------|----------|-------| | Customer Tag | `word` | Yes | Alphanumeric, no spaces, no leading digit. Becomes P4 depot name | | Salesforce Link | `url` | Yes | Full Salesforce opportunity/account URL | | Tier | `select` | Yes | Options: Standard, Enterprise, Essential | | Comms Channel | `line` | Yes | e.g. `Slack #ext-acme-perforce-bb` | | Notes | `line` | No | Free text for CustomerIndex Notes column | #### Program Dates | Field | Type | Required | Notes | |-------|------|----------|-------| | Program Start Date | `date` | Yes | YYYY/MM/DD | | Program End Date | `date` | Yes | YYYY/MM/DD | | Licensed Users | `integer` | Yes | | | Background Users | `integer` | Yes | | *Activation date (`__EDITME_YYYY_MM_DD__`) and history date (`__EDITME_YY_MM_DD__`) are set automatically to today.* #### Customer Contacts | Field | Type | Required | Notes | |-------|------|----------|-------| | Contact 1 Name | `line` | Yes | | | Contact 1 Email | `email` | Yes | | | Contact 1 Role/Notes | `line` | Yes | | | Contact 2 Name | `line` | No | | | Contact 2 Email | `email` | No | | | Contact 2 Role/Notes | `line` | No | | #### P4 Staff Contacts | Field | Type | Required | Notes | |-------|------|----------|-------| | P4 Primary Name | `line` | Yes | | | P4 Primary Email | `email` | Yes | | | P4 Primary Role/Notes | `line` | Yes | | | P4 Secondary Name | `line` | No | | | P4 Secondary Email | `email` | No | | | P4 Secondary Role/Notes | `line` | No | | | P4 Extra Contact 1 Name | `line` | No | | | P4 Extra Contact 1 Email | `email` | No | | | P4 Extra Contact 1 Role/Notes | `line` | No | | | P4 Extra Contact 2 Name | `line` | No | | | P4 Extra Contact 2 Email | `email` | No | | | P4 Extra Contact 2 Role/Notes | `line` | No | | --- ### Design Implications This use case reveals that the INI-style `p4sudo.cfg` format (designed for simple commands with a handful of scalar arguments) is not sufficient to describe a command with: - Grouped / composite fields (a contact = name + email + role) - Typed fields (date, url, email, integer, select) - Optional vs. required fields - Auto-populated fields (today's date) - Multiple repeatable groups (several contacts) **Recommended approach:** Keep `p4sudo.cfg` for command *registration* (type, script path, description, authorization rules). Add a separate per-command **UI definition file** in a structured format (YAML or JSON) that describes the web form. The `[commands]` entry in `p4sudo.cfg` gains one new key: `.ui_def = /p4/common/site/p4sudo/commands/.ui.yaml` This keeps the INI config simple and human-editable while allowing rich form definitions for complex commands. Example `p4sudo.cfg` addition: ```ini mkblackbelt.type = script mkblackbelt.script = /p4/common/site/p4sudo/commands/mkblackbelt.sh mkblackbelt.description = Bootstrap a new Black Belt customer on PPN. mkblackbelt.usage = p4 sudo mkblackbelt [options] mkblackbelt.ui_def = /p4/common/site/p4sudo/commands/mkblackbelt.ui.yaml ``` The `mkblackbelt.ui.yaml` file defines the full form structure with field types, labels, groupings, required/optional, and default values. --- ### Open Questions — Resolved **Q1. Optional contact token handling** Keep the row in the table even when a field is empty. Empty optional tokens are substituted with an empty string; no rows are removed. Required vs. optional field designation lives in `mkblackbelt.ui.yaml` (not in code), so it can be adjusted without a script change. **Q2. CustomerTag validation** No automated validation for now — manual input only. Future integration with Perforce1 (internal Salesforce) is anticipated but not yet accessible. CustomerTag values may intentionally differ from Salesforce names (e.g. `FGS` vs. `Friendly Greeting System`) for depot-naming compatibility. **Q3. Persistent BlackBelt workspace** The `p4sudo-svc` account requires a persistent workspace mapped to `//BlackBelt/main` on PPN. Suggested name: `p4sudo-svc.blackbelt`. The workspace root must be a directory on the production server machine. This workspace is pre-created as part of P4Sudo deployment on PPN and documented in the Admin Guide. It cannot be created by the script itself. **Q4. Conflict handling for CustomerIndex.md** Concurrent runs are unlikely but worth protecting against. The script performs a sync-edit-submit cycle on `CustomerIndex.md` and retries once on a submit conflict (re-sync, re-apply the row addition, re-submit). If the retry also fails, abort with a clear error. **Q5. Date token format** Resolved: template updated by Tom Tyler (2026-04-06) to use `__EDITME_YYYY_MM_DD__` throughout. Both occurrences (line 9 "Active as of" and line 45 history entry) use the same token and are set to today's date at run time. **Q6. Swarm URL format** `https://ppn.perforce.com/files//main/BlackBelt/INFO.md` is confirmed correct and stable. (The product has been rebranded from "Helix Swarm" to "P4 Code Review" but the URL is unaffected.) --- *Use case captured from session with Tom Tyler, 2026-04-06.* *Open questions resolved 2026-04-06.*