Skip to content

feat: add ppds plugins command group for plugin registration management#57

Merged
joshsmithxrm merged 8 commits intomainfrom
feature/plugins-cli
Dec 31, 2025
Merged

feat: add ppds plugins command group for plugin registration management#57
joshsmithxrm merged 8 commits intomainfrom
feature/plugins-cli

Conversation

@joshsmithxrm
Copy link
Copy Markdown
Owner

Summary

Adds ppds plugins command group for managing Dataverse plugin registrations via CLI, enabling code-first plugin deployment workflows.

New Commands

  • ppds plugins extract - Extract [PluginStep]/[PluginImage] attributes from assembly to JSON config
  • ppds plugins deploy - Deploy plugin registrations to Dataverse
  • ppds plugins diff - Compare config against environment, detect drift
  • ppds plugins list - List registered plugins with full hierarchy
  • ppds plugins clean - Remove orphaned registrations

Key Features

  • Code-first workflow: Define registrations via C# attributes, extract to JSON, deploy
  • Merge on re-extract: Running extract preserves deployment settings (solution, runAsUser, etc.)
  • Full hierarchy output: Package → Assembly → Type → Step → Image
  • Connection pooling: Improved performance for plugin operations
  • Solution support: --solution option on extract and deploy

PPDS.Plugins v2.0.0 (Breaking)

  • Added: Description, AsyncAutoDelete properties to PluginStepAttribute
  • Removed: SecureConfiguration (security risk - secrets in source control)

PPDS.Cli v1.0.0-beta.2

  • Full plugin command group
  • Step fields: deployment, runAsUser, description, asyncAutoDelete
  • Extract options: --solution, --force
  • List options: --package, --assembly
  • [JsonExtensionData] for forward compatibility

Test plan

  • Build passes
  • All tests pass (PPDS.Plugins.Tests, PPDS.Cli.Tests, PPDS.Dataverse.Tests)
  • Manual test: ppds plugins extract -i <dll> --solution <name>
  • Manual test: ppds plugins list shows hierarchy
  • Manual test: ppds plugins deploy --what-if

🤖 Generated with Claude Code

joshsmithxrm and others added 7 commits December 30, 2025 14:10
Implements #39 - Plugin registration management commands:
- `ppds plugins extract` - Extract [PluginStep]/[PluginImage] attributes from assembly or nupkg
- `ppds plugins deploy` - Deploy registrations to Dataverse with --solution, --clean, --what-if
- `ppds plugins diff` - Compare config vs environment state, detect drift
- `ppds plugins list` - List registered plugins in environment
- `ppds plugins clean` - Remove orphaned registrations not in config

Key implementation details:
- Uses MetadataLoadContext for safe, read-only assembly reflection
- Supports both classic assemblies (.dll) and NuGet plugin packages (.nupkg)
- SDK-only Dataverse operations via IOrganizationService
- JSON output for all commands (--json flag for tool integration)
- NuGet extractor scans all DLLs to find those with plugin attributes

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Plugin commands (diff, deploy, list, clean) now correctly get
ServiceClient from IDataverseConnectionPool instead of trying
to resolve it directly from DI container.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Adds support for filtering by plugin packages (NuGet) in addition to
classic assemblies (DLL):

- `--assembly, -a` filters pluginassembly entities
- `--package, -pkg` filters pluginpackage entities

When no filter is specified, both assemblies and packages are listed.
Specifying one filter excludes the other.

Also fixes the package → type query to correctly traverse:
pluginpackage → pluginassembly (via packageid) → plugintype

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…ins list

Step registration now supports:
- deployment: ServerOnly (default), Offline, or Both
- runAsUser: CallingUser (default) or systemuser GUID
- description: step documentation
- asyncAutoDelete: auto-delete async jobs on success

List command changes:
- Package hierarchy: Package → Assembly → Type → Step → Image
- New JSON output model with PackageOutput containing Assemblies
- Console output shows non-default step options on one line
- Summary includes types/images with proper pluralization

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Extract command changes:
- Add --solution (-s) option to set solution on initial extract
- Add --force (-f) option to skip merge and overwrite
- When file exists, merge preserves deployment settings:
  - Assembly: solution, unknown fields
  - Step: deployment, runAsUser, description, asyncAutoDelete
  - All levels: ExtensionData for unknown JSON properties

Config models now include [JsonExtensionData] to preserve unknown
properties during round-trip serialization, enabling forward
compatibility with future schema changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Document all plugin command features:
- Full step registration fields (deployment, runAsUser, etc.)
- Extract merge behavior and --solution/--force options
- List command hierarchy and filtering enhancements
- Connection pooling for improved performance

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
…ration

BREAKING CHANGE: SecureConfiguration removed from PluginStepAttribute.
Secrets should never be committed to source control. Use environment
variables, Azure Key Vault, or configure via Plugin Registration Tool.

Added to PluginStepAttribute:
- Description: documents what the step does
- AsyncAutoDelete: auto-delete async jobs on success

Updated:
- AssemblyExtractor reads new attributes
- Tests updated for new properties
- PPDS.Plugins v2.0.0

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings December 31, 2025 07:11
@gemini-code-assist
Copy link
Copy Markdown

Summary of Changes

Hello @joshsmithxrm, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the ppds CLI tool by introducing a dedicated command group for managing Dataverse plugin registrations. It shifts towards a more developer-friendly, code-first approach, allowing plugin definitions to be maintained in source control and deployed programmatically. This change streamlines the entire lifecycle of Dataverse plugins, from development and configuration extraction to deployment, drift detection, and cleanup, ultimately improving efficiency and consistency in Dataverse solutions.

Highlights

  • New ppds plugins Command Group: Introduces a comprehensive command group for managing Dataverse plugin registrations directly from the CLI, enabling a code-first deployment workflow.
  • Five New Plugin Commands: Adds extract (to generate JSON config from C# attributes), deploy (to register plugins in Dataverse), diff (to compare config with environment state), list (to view registered plugins), and clean (to remove orphaned registrations).
  • Code-First Workflow: Allows defining plugin steps and images using C# attributes ([PluginStep]/[PluginImage]), which can then be extracted to a JSON configuration file for deployment.
  • Enhanced Extraction and Deployment: The extract command now preserves deployment settings on re-extraction and supports --solution and --force options. The deploy command includes --solution, --clean for orphan removal, and --what-if for previewing changes.
  • Detailed Plugin Listing: The list command provides a full hierarchical output of plugins (Package → Assembly → Type → Step → Image) and displays non-default step options.
  • PPDS.Plugins v2.0.0 (Breaking Change): Adds Description and AsyncAutoDelete properties to PluginStepAttribute for better documentation and async job management, while removing the SecureConfiguration property due to security concerns.
  • Performance Improvements: Implements connection pooling for all plugin-related commands to enhance performance during Dataverse interactions.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces a comprehensive plugins command group to the CLI, enabling a code-first workflow for Dataverse plugin registration. The new commands (extract, deploy, diff, list, clean) are well-structured and cover the entire lifecycle of plugin management from source code attributes. The changes also include a necessary breaking change to PluginStepAttribute to improve security by removing SecureConfiguration. The implementation is robust, leveraging MetadataLoadContext for safe assembly inspection and providing features like merging configurations and what-if modes. My review focuses on a few key areas for performance optimization in the deploy and clean commands, and a best-practice suggestion for asynchronous operations in the PluginRegistrationService. All comments align with best practices and do not contradict any established rules.

Copy link
Copy Markdown

@github-advanced-security github-advanced-security bot left a comment

Choose a reason for hiding this comment

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

CodeQL found more than 20 potential problems in the proposed changes. Check the Files changed tab for more details.

Copy link
Copy Markdown

Copilot AI left a comment

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 adds a comprehensive ppds plugins command group to enable code-first plugin deployment workflows for Dataverse, supporting both classic assemblies and NuGet packages. The implementation includes extraction of plugin metadata from attributes, deployment to environments, drift detection, listing, and cleanup of orphaned registrations.

Key Changes

  • Breaking change in PPDS.Plugins v2.0.0: Removes SecureConfiguration property from PluginStepAttribute (security risk), adds Description and AsyncAutoDelete properties
  • PPDS.Cli v1.0.0-beta.2: Adds complete plugin command group with 5 subcommands (extract, deploy, diff, list, clean)
  • Metadata extraction: Uses MetadataLoadContext for safe assembly reflection without loading dependencies into current AppDomain

Reviewed changes

Copilot reviewed 23 out of 23 changed files in this pull request and generated 16 comments.

Show a summary per file
File Description
src/PPDS.Plugins/Attributes/PluginStepAttribute.cs Removes SecureConfiguration, adds Description and AsyncAutoDelete properties
src/PPDS.Plugins/CHANGELOG.md Documents breaking v2.0.0 release
tests/PPDS.Plugins.Tests/PluginStepAttributeTests.cs Updates tests for removed SecureConfiguration property
src/PPDS.Cli/Program.cs Registers new PluginsCommandGroup
src/PPDS.Cli/PPDS.Cli.csproj Adds PPDS.Plugins reference and System.Reflection.MetadataLoadContext dependency
src/PPDS.Cli/Plugins/Models/PluginRegistrationConfig.cs Defines JSON config models with JsonExtensionData for forward compatibility
src/PPDS.Cli/Plugins/Extraction/AssemblyExtractor.cs Extracts plugin attributes from assemblies using MetadataLoadContext
src/PPDS.Cli/Plugins/Extraction/NupkgExtractor.cs Extracts plugin metadata from NuGet packages
src/PPDS.Cli/Plugins/Registration/PluginRegistrationService.cs Service for querying and managing plugin registrations in Dataverse
src/PPDS.Cli/Commands/Plugins/PluginsCommandGroup.cs Command group definition with shared options
src/PPDS.Cli/Commands/Plugins/ExtractCommand.cs Extracts attributes to JSON with merge support
src/PPDS.Cli/Commands/Plugins/DeployCommand.cs Deploys registrations to Dataverse with upsert logic
src/PPDS.Cli/Commands/Plugins/DiffCommand.cs Detects drift between config and environment
src/PPDS.Cli/Commands/Plugins/ListCommand.cs Lists plugin hierarchy from environment
src/PPDS.Cli/Commands/Plugins/CleanCommand.cs Removes orphaned registrations
src/PPDS.Cli/CHANGELOG.md Documents beta.2 release with plugin features
tests/PPDS.Cli.Tests/Plugins/Models/PluginRegistrationConfigTests.cs Tests for config model serialization
tests/PPDS.Cli.Tests/Commands/Plugins/*.cs Unit tests for command structure and parsing

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

@joshsmithxrm joshsmithxrm moved this from Todo to In Progress in PPDS Roadmap Dec 31, 2025
@joshsmithxrm joshsmithxrm self-assigned this Dec 31, 2025
Performance improvements:
- DeployCommand: Use Dictionary for O(1) orphan step lookup instead of O(n*m) re-querying
- CleanCommand: Calculate remaining step count in memory instead of re-querying
- PluginRegistrationService: Use native IOrganizationServiceAsync2 when available

Bug fixes:
- DeployCommand: Skip image query in what-if mode for new steps (stepId doesn't exist)
- ExtractCommand: Remove redundant !json check
- CleanCommand: Remove unused configuredTypeNames variable
- DiffCommand: Remove unused existingTypeMap variable

Code quality:
- AssemblyExtractor: Use LINQ FirstOrDefault for cleaner StepId lookup

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@joshsmithxrm joshsmithxrm merged commit 628610a into main Dec 31, 2025
5 checks passed
@github-project-automation github-project-automation bot moved this from In Progress to Done in PPDS Roadmap Dec 31, 2025
@joshsmithxrm joshsmithxrm deleted the feature/plugins-cli branch December 31, 2025 16:03
joshsmithxrm added a commit that referenced this pull request Jan 8, 2026
…tch qs security vulnerability (#57)

* chore(deps): bump actions/upload-artifact from 5 to 6

Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](actions/upload-artifact@v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix(deps): patch qs security vulnerability

Ran npm audit fix to update qs from 6.14.0 to 6.14.1.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Josh Smith <6895577+joshsmithxrm@users.noreply.github.com>
joshsmithxrm added a commit that referenced this pull request Mar 18, 2026
- Add Connection References + Environment Variables to sidebar Tools (#56, #57)
- Standardize command titles: "Open Data Explorer", "Open Plugin Traces" (#51)
- Remove text-transform: uppercase from 5 panel CSS files for Title Case headers (#10)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
joshsmithxrm added a commit that referenced this pull request Mar 19, 2026
- Add Connection References + Environment Variables to sidebar Tools (#56, #57)
- Standardize command titles: "Open Data Explorer", "Open Plugin Traces" (#51)
- Remove text-transform: uppercase from 5 panel CSS files for Title Case headers (#10)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
joshsmithxrm added a commit that referenced this pull request Mar 19, 2026
* fix(cdp): use pwsh Expand-Archive for VSIX extraction on Windows

bsdtar interprets the C: drive prefix as a remote host, breaking
VSIX extraction in --vsix mode. Use PowerShell's Expand-Archive on
Windows; keep tar on other platforms.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* plan: extension UX audit fixes — 28 findings across 10 phases

Side-by-side comparison of legacy v0.3.4 vs new extension produced
55 findings. After triage: 28 fixes, 22 keep-new-behavior, 5 deferred.
Organized into 10 phases (1 cross-cutting + 9 per-panel) for parallel
agent execution.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ext): Phase 1 — cross-cutting infrastructure fixes

- Add Connection References + Environment Variables to sidebar Tools (#56, #57)
- Standardize command titles: "Open Data Explorer", "Open Plugin Traces" (#51)
- Remove text-transform: uppercase from 5 panel CSS files for Title Case headers (#10)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* feat(ext): Phases 2-9 — UX audit fixes across all 8 panels

Solutions (#1,#2,#3,#5): Include Managed toggle, sort controls,
Visible/API Managed fields, Maker Portal button, isVisible/isApiManaged
end-to-end C# support.

Import Jobs (#7,#8,#9): Search bar, Operation Context column
(end-to-end C#→TS), record count with filtered status.

Plugin Traces (#11,#12,#17,#18,#55): CRITICAL Trace Level dropdown
fix, Maker Portal URL fix (Dynamics 365 classic), status text labels,
record count, search bar.

Web Resources (#19): Restored Created By and Created On columns.

Connection References (#23,#24,#25,#28,#55): Expandable flow/connection
detail with chevron toggle, ISO timestamp formatting, search bar,
status badge improvements (Unknown/Unbound), Sync Settings button.

Environment Variables (#29,#31,#55): Modified On column restored,
search bar, Sync Settings button.

Metadata Browser (#37): Custom Only filter toggle for entities.

Data Explorer (#41,#42): Clear button, Import button (file dialog).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): review fixes — colSpan bug and command injection

- Connection References: fix colCount from wrong heuristic (8) to
  correct value (7) matching actual column count
- CDP tool: sanitize paths for PowerShell injection (escape single
  quotes); use execFileSync for tar on Unix to avoid shell interpretation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* style(ext): extract inline styles to CSS classes per Gemini review

Move search input and sort select inline styles to dedicated
.toolbar-search and .toolbar-select CSS classes across 4 panels
(Connection Refs, Env Variables, Import Jobs, Solutions).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): add missing webview entry points to knip config

The 6 non-query/solutions webview panels are esbuild entry points but
were missing from knip.json, causing false-positive unused-file reports.
Also un-export internal-only types from shared modules.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): solution filter GUID bug and raw ISO timestamps

- SolutionFilter shared component used uniqueName as option value
  instead of GUID id, causing "solutionId must be a valid GUID" error
  on Web Resources (and silently wrong on Conn Refs / Env Vars)
- Import Jobs and Web Resources rendered raw ISO timestamps; add
  formatDateTime helper matching Plugin Traces / Conn Refs pattern

Found by QA blind verification agents.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): review fixes — escaping, shell safety, URL normalization

- Solutions panel: escape rootComponentBehavior and boolean ternaries
  before innerHTML insertion (S1 compliance)
- Connection References: escape literal "Unbound" for consistent
  escaping discipline
- CDP tool: use execFileSync instead of execSync for PowerShell
  VSIX extraction (S2 compliance — no shell: true)
- Plugin Traces: strip trailing slash from environment URL before
  Maker Portal link construction

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(ext): escape formatDate output in solutions detail card

Wrap formatDate() calls in escapeHtml() for consistent escaping
discipline — formatDate can return raw ISO string on parse failure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants