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.cs with version attributes
  • You have push access to the main branch (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

ComponentWhat you doWhy
App RegistryAdd entry to deploy/app-registry.jsonCentral config: maps your app to build/deploy paths
Release WorkflowAdd your folder to the dropdown in release.ymlEnables manual deploy via GitHub Actions
Network ShareFirst deploy auto-creates the folder structureWhere Pro Update reads versions from
Pro UpdateRegistry sync auto-updates PSApplications.txtHow 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

FieldDescriptionExample
displayNameName shown in Pro Update and on the network share folder"Print Part Label"
executableThe main .exe file name"PSI.PrintPartLabel.exe"
accessWho can see/install the app. "all" or comma-separated user IDs"all" or "AMD,BMC,JPT"
betaAccessArray of user IDs or group names with beta access["developers"] or ["AMD","BMC"]
alphaAccessArray of user IDs or group names with alpha access["AMD"]
ci.repoFolderTop-level folder name in PSI.All (must match exactly)"PSI.PrintPartLabel"
ci.solutionPathRelative path to your .sln file"YourApp/Trunk/YourApp.sln"
ci.projectPathRelative path to your main .csproj"YourApp/Trunk/YourApp/YourApp.csproj"
ci.assemblyInfoPathRelative path to AssemblyInfo.cs"YourApp/Trunk/YourApp/Properties/AssemblyInfo.cs"
ci.buildOutputSubpathBuild output folder relative to the .csproj directory"bin/Release"
ci.enabledSet true to allow deploys, false to blocktrue
ci.platformOptional 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 line

The 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

  1. Go to Actions tab → “Release: Deploy App”Run workflow
  2. Select your app from the dropdown
  3. Choose alpha for the first test deploy (safe, no notifications)
  4. Enter release notes
  5. 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:

  1. Open Pro Update on your machine
  2. Your app should appear in the list
  3. If you deployed to alpha, only users with alpha access will see it
  4. If you deployed to beta, only users in betaAccess will see the beta version

Release Channels

ChannelVersion fileWho sees itWhen to use
Alphaalphaversion.txtAlpha testers only (in Pro Update only, not Application Manager)Dev testing, iterate freely
Betabetaversion.txtNamed testers onlyStructured testing before release
Minorversion.txtAll usersNormal production release (bumps last version segment)
Majorversion.txtAll usersBreaking changes (bumps second-to-last segment)

Beta Testing Flow

  1. Configure beta testers via Admin Panel (or pass beta_users in the workflow)
  2. Deploy to beta channel
  3. GitHub tracking issue auto-created: [Beta] AppName vX.X.X.X
  4. Teams group chat created between deployer and testers
  5. Testers get the update automatically via Pro Update
  6. When testing passes, comment /promote on the tracking issue
  7. 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:

  1. Detects which top-level folders changed
  2. Finds all .sln files in those folders
  3. Runs NuGet restore + MSBuild in Release configuration
  4. 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

  1. Application Manager (system tray) polls version.txt every ~5 minutes for stable updates
  2. Pro Update (full client) checks all 3 channels and shows available updates
  3. Updates are file-copy based: network share → local install folder (C:\Users\Public\Progressive Surface\{AppName}\)

Access Control

  • access: "all" → everyone sees the app
  • access: "AMD,BMC" → only listed users see the app
  • betaAccess → 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 by sc.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.json with ci.enabled: true
  • Folder added to release.yml dropdown
  • 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

FilePurpose
deploy/app-registry.jsonSource of truth for all app config
deploy/bump-version.ps1Increments AssemblyVersion
deploy/deploy-to-share.ps1Copies build output to network share
deploy/sync-registry.ps1Syncs registry → PSApplications.txt / PSServices.txt
deploy/send-teams-notification.ps1Teams group chat + bot messages for beta
.github/workflows/release.ymlRelease pipeline (all apps)
.github/workflows/build-app.ymlPR build validation
.github/workflows/promote-beta.yml/promote command handler
.github/workflows/beta-reminder.yml7-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 collisionbump-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