Onboard a New App to PSI CI/CD
Step-by-step guide to integrating a new desktop application into the PSI CI/CD pipeline so it builds automatically, deploys to the network share, and updates users via Pro Update.
Prerequisites
- Your app is a .NET Framework 4.8 (or .NET 8) desktop application
- Your code is in the PSI.All mono-repo at
https://progressivesurface.ghe.com/ProgressiveSurface/PSI.All - Your project has a standard
Properties/AssemblyInfo.cswith version attributes - You have push access to the
mainbranch (or can create PRs)
If your app is in a separate repo: The CI/CD pipeline currently lives in PSI.All. You’ll need to either move your project folder into PSI.All, or set up equivalent workflows in your repo. This guide assumes PSI.All.
Overview: What Gets Configured
| Component | What you do | Why |
|---|---|---|
| App Registry | Add entry to deploy/app-registry.json | Central config: maps your app to build/deploy paths |
| Release Workflow | Add your folder to the dropdown in release.yml | Enables manual deploy via GitHub Actions |
| Network Share | First deploy auto-creates the folder structure | Where Pro Update reads versions from |
| Pro Update | Registry sync auto-updates PSApplications.txt | How users discover and install your app |
Step 1: Project Structure
Your project folder in PSI.All should look like this:
PSI.All/
YourApp/
Trunk/ (or just the root)
YourApp.sln
YourApp/ (main project)
YourApp.csproj
Properties/
AssemblyInfo.cs <-- REQUIRED for version bumping
bin/
Release/ <-- Build output (default location)
YourApp.exe
*.dll
AssemblyInfo.cs Requirements
The version bumper (deploy/bump-version.ps1) expects these two lines:
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]Both must use the 4-part format X.X.X.X. The bumper increments the last segment for minor releases and the second-to-last for major releases.
Step 2: Add to App Registry
Edit deploy/app-registry.json and add your app to the applications array:
{
"displayName": "Your App Name",
"executable": "YourApp.exe",
"access": "all",
"betaAccess": [],
"alphaAccess": [],
"ci": {
"repoFolder": "YourApp",
"solutionPath": "YourApp/Trunk/YourApp.sln",
"projectPath": "YourApp/Trunk/YourApp/YourApp.csproj",
"assemblyInfoPath": "YourApp/Trunk/YourApp/Properties/AssemblyInfo.cs",
"buildOutputSubpath": "bin/Release",
"enabled": true
}
}Field Reference
| Field | Description | Example |
|---|---|---|
displayName | Name shown in Pro Update and on the network share folder | "Print Part Label" |
executable | The main .exe file name | "PSI.PrintPartLabel.exe" |
access | Who can see/install the app. "all" or comma-separated user IDs | "all" or "AMD,BMC,JPT" |
betaAccess | Array of user IDs or group names with beta access | ["developers"] or ["AMD","BMC"] |
alphaAccess | Array of user IDs or group names with alpha access | ["AMD"] |
ci.repoFolder | Top-level folder name in PSI.All (must match exactly) | "PSI.PrintPartLabel" |
ci.solutionPath | Relative path to your .sln file | "YourApp/Trunk/YourApp.sln" |
ci.projectPath | Relative path to your main .csproj | "YourApp/Trunk/YourApp/YourApp.csproj" |
ci.assemblyInfoPath | Relative path to AssemblyInfo.cs | "YourApp/Trunk/YourApp/Properties/AssemblyInfo.cs" |
ci.buildOutputSubpath | Build output folder relative to the .csproj directory | "bin/Release" |
ci.enabled | Set true to allow deploys, false to block | true |
ci.platform | Optional MSBuild platform. Defaults to "AnyCPU" | "AnyCPU" or "x86" |
Groups
You can use group names in betaAccess and alphaAccess. Groups are defined at the top of the registry:
"groups": {
"developers": ["AMD", "JPT", "BMS", "CHK", "BMC"],
"engineering": ["JDC", "ORL", "DCC", "RSY"]
}Using "betaAccess": ["developers"] expands to every member of the developers group in app-registry.json. Manage the list via the Pro Update Admin Panel — click the gear icon (Beta Management) in the main window. The gear is visible to members of the AD\IT - RF security group; no launch argument is required.
Step 3: Add to Release Workflow Dropdown
Edit .github/workflows/release.yml and add your repo folder to the app_folder choice list (alphabetical order preferred):
inputs:
app_folder:
description: "Application to deploy"
required: true
type: choice
options:
# ... existing apps ...
- YourApp # <-- Add this lineThe value must exactly match the ci.repoFolder in your registry entry.
Step 4: Commit and Push
Create a PR with your changes:
deploy/app-registry.json(new entry).github/workflows/release.yml(dropdown addition)- Your app folder (if new to the repo)
CI will automatically build your app on the PR if it detects changes in your folder.
Step 5: First Deploy
- Go to Actions tab → “Release: Deploy App” → Run workflow
- Select your app from the dropdown
- Choose
alphafor the first test deploy (safe, no notifications) - Enter release notes
- Click Run workflow
The deploy script will automatically create the folder structure on the network share:
\\ad.ptihome.com\DFS\Data\APPS\Approved\DotNet\AppDeployments\
Apps\
Your App Name\ <-- Created automatically (uses displayName)
version.txt <-- Written on stable deploy
betaversion.txt <-- Written on beta deploy
alphaversion.txt <-- Written on alpha deploy
_alpha\
1.0.0.1\ <-- Alpha binaries
1.0.0.1\ <-- Beta/stable binaries
After the first deploy, run sync-registry.ps1 (happens automatically in the workflow) to update PSApplications.txt so Pro Update discovers your app.
Step 6: Verify in Pro Update
After the deploy + sync:
- Open Pro Update on your machine
- Your app should appear in the list
- If you deployed to alpha, only users with alpha access will see it
- If you deployed to beta, only users in betaAccess will see the beta version
Release Channels
| Channel | Version file | Who sees it | When to use |
|---|---|---|---|
| Alpha | alphaversion.txt | Alpha testers only (in Pro Update only, not Application Manager) | Dev testing, iterate freely |
| Beta | betaversion.txt | Named testers only | Structured testing before release |
| Minor | version.txt | All users | Normal production release (bumps last version segment) |
| Major | version.txt | All users | Breaking changes (bumps second-to-last segment) |
Beta Testing Flow
- Configure beta testers via Admin Panel (or pass
beta_usersin the workflow) - Deploy to beta channel
- GitHub tracking issue auto-created:
[Beta] AppName vX.X.X.X - Teams group chat created between deployer and testers
- Testers get the update automatically via Pro Update
- When testing passes, comment
/promoteon the tracking issue - Beta is promoted to stable — all users get the update
How CI Builds Work
When you open a PR that touches files in your app folder, the CI: Changed Apps workflow:
- Detects which top-level folders changed
- Finds all
.slnfiles in those folders - Runs NuGet restore + MSBuild in Release configuration
- Reports pass/fail on the PR
No configuration needed — CI auto-detects based on changed file paths. Just make sure your solution builds with MSBuild in Release configuration.
Build Environment
The self-hosted runner (PS-GR-RUNNER) has:
- Visual Studio Build Tools 2022
- .NET Framework 4.8 SDK
- MSBuild, NuGet CLI, PowerShell 7, Git, GitHub CLI
- Active Directory PowerShell module
- Network access to the deployment share and AD
Runner labels: [self-hosted, windows, dotnet-framework]
Integration with Pro Update (Launcher)
Pro Update discovers apps by reading PSApplications.txt from the network share:
Your App Name;YourApp.exe;all;AMD,BMC;AMD
Format: DisplayName;Executable;Access;BetaAccess;AlphaAccess
This file is automatically generated from app-registry.json by sync-registry.ps1. Do not edit the txt file directly — changes are overwritten on the next sync.
How Users Get Updates
- Application Manager (system tray) polls
version.txtevery ~5 minutes for stable updates - Pro Update (full client) checks all 3 channels and shows available updates
- Updates are file-copy based: network share → local install folder (
C:\Users\Public\Progressive Surface\{AppName}\)
Access Control
access: "all"→ everyone sees the appaccess: "AMD,BMC"→ only listed users see the appbetaAccess→ who sees beta versions (managed via Admin Panel or workflow)alphaAccess→ who sees alpha versions (managed via Admin Panel or workflow)
If Your App Is a Windows Service
Add it to the services array instead of applications:
{
"displayName": "YourServiceName",
"executable": "YourService.exe",
"serviceName": "YourServiceName",
"serviceDisplayName": "Progressive Surface YourService",
"betaAccess": [],
"alphaAccess": [],
"ci": {
"repoFolder": "YourService",
"solutionPath": "YourService/Trunk/YourService.sln",
"projectPath": "YourService/Trunk/YourService/YourService.csproj",
"assemblyInfoPath": "YourService/Trunk/YourService/Properties/AssemblyInfo.cs",
"buildOutputSubpath": "bin/Release",
"enabled": true
}
}Services have additional fields:
serviceName: Windows SCM service name (used bysc.exe/Get-Service)serviceDisplayName: Friendly name shown in Services console
Services are listed in PSServices.txt (4 fields minimum: ServiceName;Executable;ServiceDisplayName;BetaUsers).
Pro Update handles service updates differently — it uses WCF via PSILocalService first, then falls back to ServiceUpdate.ps1 for reliability.
Checklist
- Project folder exists in PSI.All with valid
AssemblyInfo.cs - Solution builds with
msbuild YourApp.csproj /p:Configuration=Release /p:Platform=AnyCPU - Entry added to
deploy/app-registry.jsonwithci.enabled: true - Folder added to
release.ymldropdown - PR created and CI passes
- First alpha deploy succeeds
- App appears in Pro Update
- Beta deploy tested with testers
- First stable (minor) release to all users
Key Files Reference
| File | Purpose |
|---|---|
deploy/app-registry.json | Source of truth for all app config |
deploy/bump-version.ps1 | Increments AssemblyVersion |
deploy/deploy-to-share.ps1 | Copies build output to network share |
deploy/sync-registry.ps1 | Syncs registry → PSApplications.txt / PSServices.txt |
deploy/send-teams-notification.ps1 | Teams group chat + bot messages for beta |
.github/workflows/release.yml | Release pipeline (all apps) |
.github/workflows/build-app.yml | PR build validation |
.github/workflows/promote-beta.yml | /promote command handler |
.github/workflows/beta-reminder.yml | 7-day stale beta nagger |
Troubleshooting
“App not found in deploy/app-registry.json” — The ci.repoFolder in your registry entry doesn’t match the app_folder you selected in the workflow.
Build fails on PR — Make sure your solution builds locally with msbuild /p:Configuration=Release. Check for missing NuGet packages or project references.
App doesn’t appear in Pro Update — Run sync-registry.ps1 to update txt files, or wait for the next deploy which triggers it automatically. Also check that access includes the user.
Version collision — bump-version.ps1 auto-increments past existing version folders on the share. If your AssemblyInfo is far behind, you may see a larger jump.
See Also
Last updated: March 2026