Skip to content

Volunteer Management: separate-identity OS build + AppSource→OS migration script#50

Open
lukasdominms wants to merge 4 commits into
masterfrom
users/lukasdominms/vm-os-separate-identity
Open

Volunteer Management: separate-identity OS build + AppSource→OS migration script#50
lukasdominms wants to merge 4 commits into
masterfrom
users/lukasdominms/vm-os-separate-identity

Conversation

@lukasdominms

Copy link
Copy Markdown
Contributor

Summary

Enables the open-source (OS) Volunteer Management build to be deployed side-by-side with the AppSource managed solution under a separate identity, and adds a productized script to migrate an environment from the AppSource solution to the OS build.

Both solutions are published by Microsoft; they are distinguished by origin — the AppSource managed solution (installed from the marketplace) vs. the OS build (compiled from this repository).

Why

The OS build previously shared its identity (solution unique name, plugin assembly strong-name) with the AppSource solution, so the two could not coexist. To support a controlled migration, the OS build now ships under its own identity. This lets it install alongside the AppSource solution, after which the AppSource solution can be removed.

Removing the AppSource solution is blocked by a hard dependency: the forms and views it contributes reference its PCF controls in the active (merged) layer. That Form → Control Published dependency lives in the active layer independent of solution ownership, so it prevents deletion. Re-assigning component ownership to the OS solution does not clear it (verified empirically). The dependency must be removed by rewriting the active form/view layers.

Changes

  • Separate identity for the OS build
    • Plugin assembly renamed PluginsPluginsOS, with a dedicated stable signing key (PluginsOS.snk, token 703f25cc8a15a472) and a new assembly GUID.
    • Solution unique name VolunteerManagementvolunteermanagementos (display name "Volunteer Management (OS)").
    • Plugin type / SDK step GUIDs remapped consistently across metadata, root components, and step files.
    • Solution version bumped to 1.2.4.0.
  • Migration tooling under VolunteerManagement/Deployment/
    • Migrate-VolunteerManagementToOpenSource.ps1 — parameterized, opt-in stages:
      • -StripReferences — rewrites forms + saved queries to substitute the default control for the AppSource PCF controls, then PublishAllXml (clears the blocking dependency).
      • -DeleteAppSourceSolution — deletes the AppSource managed solution by unique name.
      • -Verify — reports plugin assemblies, PCF control ownership, and SDK step registration.
    • Generic auth (az account get-access-token by default; -AccessToken / -AzCommand overrides). Destructive stages support -WhatIf / -Confirm (ConfirmImpact = High).
    • README.md documenting the full side-by-side migration flow.

How to use

  1. Build the OS managed solution: dotnet build VolunteerManagement/VolunteerManagement/VolunteerManagement.cdsproj -c Release
  2. Import it side-by-side: pac solution import --path .../VolunteerManagement_managed.zip
  3. .\Migrate-VolunteerManagementToOpenSource.ps1 -EnvironmentUrl <url> -StripReferences
  4. .\Migrate-VolunteerManagementToOpenSource.ps1 -EnvironmentUrl <url> -DeleteAppSourceSolution
  5. Re-import / upgrade the OS solution so its forms restore the PCF controls (OS-owned).
  6. .\Migrate-VolunteerManagementToOpenSource.ps1 -EnvironmentUrl <url> -Verify

Testing

  • The managed solution builds cleanly via the cdsproj and bundles all four PCF controls; the package was verified to contain the OS identity only (no AppSource GUIDs/strong-name token).
  • The strip → delete → reimport flow was validated end-to-end against test environments.

Notes

  • Take an environment backup before the destructive stages; deleting the AppSource solution is irreversible without one.

Lukas Domin added 3 commits June 23, 2026 15:06
…edicated key (token 703f25cc8a15a472), remap assembly/type/step GUIDs, solution uniquename->volunteermanagementos
VolunteerManagement/Deployment/Migrate-VolunteerManagementToOpenSource.ps1 (parameterized strip-references / delete-appsource-solution / verify stages, generic az-cli auth, SupportsShouldProcess) plus README. Both solutions are Microsoft-published; named by goal (migrate to open-source) and distinguished by origin (AppSource vs OS build) rather than ambiguous 'official'.
@vuhrova

vuhrova commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

I noticed one metadata consistency issue from the solution rename: VolunteerManagement/VolunteerManagement/Solution/Resources/en-US/resources.en-US.resx still has the old solution localized-name entry:

<data name="15062:LocalizedName,VolunteerManagement" xml:space="preserve">
  <value>Volunteer Management</value>
  <comment> 'VolunteerManagement' : LocalizedName for Solution</comment>
</data>

Since the solution unique name/display name changed to volunteermanagementos / Volunteer Management (OS), should this resource entry be regenerated or updated as well?

</LocalizedNames>
<Descriptions />
<Version>1.0.3.10172</Version>
<Version>1.2.4.0</Version>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This version (1.2.4.0) does not appear to comply with our OneNonprofit versioning guide: https://dev.azure.com/oneCELA/OneNonprofit/_wiki/wikis/OneNonprofit.wiki/1925/Versioning. Can we update this to follow the required version format before merging?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — 1.2.4.0 used stage 4, which isn't valid per the guide (stage is 0–3). Updated to 1.1.3.0: minor bump for the OS variant, stage 3 (GA), build 0, and higher than the AppSource package (1.0.3.10172) for version continuity. Happy to adjust major/minor if a different lineage is preferred.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR enables the open-source Volunteer Management solution to install side-by-side with the AppSource managed solution by separating solution/assembly identity, and adds a PowerShell migration tool to strip blocking PCF references and delete the AppSource solution during migration.

Changes:

  • Renames the plugin assembly identity to PluginsOS (new strong-name key) and updates solution metadata to reference the OS identity.
  • Remaps plugin type / SDK step IDs and updates solution root components accordingly.
  • Adds a productized migration script and README under VolunteerManagement/Deployment/.

Reviewed changes

Copilot reviewed 30 out of 31 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
VolunteerManagement/VolunteerManagementResources/Plugins/Plugins.csproj Renames the plugin assembly to PluginsOS and switches signing key to PluginsOS.snk.
VolunteerManagement/VolunteerManagement/Solution/Other/Solution.xml Changes solution unique name/display name/version and updates root components to OS plugin assembly + remapped step IDs.
VolunteerManagement/VolunteerManagement/Solution/PluginAssemblies/PluginsOS-50D34BB8-E4AA-4DF8-84EA-9D70B19DC72D/PluginsOS.dll.data.xml Adds OS plugin assembly registration metadata (new assembly/token + plugin type IDs).
VolunteerManagement/VolunteerManagement/Solution/PluginAssemblies/Plugins-5D562315-37A4-EB11-B1AC-000D3A1FC0E7/Plugins.dll.data.xml Removes legacy plugin assembly registration metadata for the AppSource identity.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{f47addb7-4a4e-4a86-8056-4e4bcbb37f19}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{e64ae12c-30cd-44eb-97e0-b57d576ab55b}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{dc676866-dead-48da-9b43-52059af2ab83}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{be4980b9-ce95-45a3-8cc7-37aa9d8eeb67}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{9b5438cb-cf96-43df-ad7f-fe771e84e3d3}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{86e747bf-c118-47b2-8dd4-cfb70d016bf7}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{867d43b7-af76-4888-bfe2-fed50d694fdf}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{85b90a27-8b53-40aa-a130-f2d0d5b91c9e}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{8271517a-25f9-4cf2-a006-20e7248dc767}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{81f97b73-9836-4d95-91b6-6e6736f581b1}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{7fec674a-f06a-4fef-89c0-9a7f814e5e86}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{7a061612-6940-4b13-8706-3d0fb99e2c30}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{78d39fed-f4da-46fe-86f3-82ef5193777a}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{719cbec5-f3dd-4b86-80ac-3080893f7bd2}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{671dd33c-2ae1-434c-8652-40a96ea4a6d2}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{6664dd0c-4ca7-4045-bc59-7614a4af751e}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{659e5220-eae9-430a-b1a0-75f423107a4a}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{5751b036-57ec-4d93-b297-2004a77c8ae7}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{442d349d-61bc-4265-a52e-cf2222d69ef0}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{39ef623b-a978-4e2a-a5cf-9df6268c4cce}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{2c7c7185-3d66-41d3-89fb-c8c635046dae}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{2a00b8be-03e1-46db-a352-b49f1c379753}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{252d5074-6f45-4861-a269-ee1ea14ac398}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{055e9f02-c8e4-4834-86e5-d5912bd34619}.xml Updates step ID and retargets step to PluginsOS / new plugin type ID.
VolunteerManagement/Deployment/Migrate-VolunteerManagementToOpenSource.ps1 Adds the staged migration script (strip references / delete AppSource / verify).
VolunteerManagement/Deployment/README.md Adds migration flow documentation and usage guidance for the new script.
Comments suppressed due to low confidence (4)

VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{f47addb7-4a4e-4a86-8056-4e4bcbb37f19}.xml:2

  • Typo in the SDK step display name: "Opportuntiy" → "Opportunity". Since this line is being rewritten in this PR anyway, it’s a good opportunity to correct the spelling for readability in the Dataverse registration UI.
    VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{e64ae12c-30cd-44eb-97e0-b57d576ab55b}.xml:2
  • Typo in the SDK step display name: "Opportuntiy" → "Opportunity". Keeping these display names clean helps when troubleshooting step registrations in the plugin registration UI.
    VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{7a061612-6940-4b13-8706-3d0fb99e2c30}.xml:2
  • Typo in the SDK step display name: "Opportuntiy" → "Opportunity".
    VolunteerManagement/VolunteerManagement/Solution/SdkMessageProcessingSteps/{055e9f02-c8e4-4834-86e5-d5912bd34619}.xml:2
  • Typo in the SDK step display name: "Opportuntiy" → "Opportunity".

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


function Invoke-StripReferences {
Write-Host '=== Stripping AppSource PCF references from system forms ===' -ForegroundColor Cyan
$forms = (Invoke-RestMethod -Uri "$base/systemforms?`$select=formid,name,objecttypecode,formxml" -Headers $headers).value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — added a Get-AllPages helper that follows @odata.nextLink, so the system forms query now reads every page.

Write-Host "Patched forms: $patchedForms"

Write-Host '=== Stripping AppSource PCF references from saved queries (views) ===' -ForegroundColor Cyan
$views = (Invoke-RestMethod -Uri "$base/savedqueries?`$select=savedqueryid,name,returnedtypecode,layoutxml" -Headers $headers).value

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — the saved queries query now pages through @odata.nextLink via the same Get-AllPages helper.

Comment on lines +39 to +43
```powershell
pac solution import --path .\VolunteerManagement\bin\Release\VolunteerManagement_managed.zip
```

(Build it first with `dotnet build VolunteerManagement\VolunteerManagement.cdsproj -c Release`.)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed — paths are now repo-root-relative and I added a note that all commands run from the repository root.

Comment thread VolunteerManagement/Deployment/README.md
- Solution version 1.2.4.0 -> 1.1.3.0 (versioning guide: stage must be 0-3 GA=3; higher than AppSource 1.0.3.10172)

- Migration script: page through @odata.nextLink for systemforms and savedqueries (Get-AllPages helper) so large environments don't miss references

- README: repo-root-relative paths and explicit working-directory note
@vuhrova vuhrova assigned vuhrova and unassigned vuhrova Jun 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants