Skip to content

Conversation

@sunker
Copy link
Contributor

@sunker sunker commented Oct 17, 2025

What this PR does / why we need it:

This PR adds support for a new create-plugin add cmd that lets users add optional features not enabled by default when scaffolding new plugins.

add Command

Users can now add features to their existing plugins:

npx @grafana/create-plugin add <addition-name> [options]

Additions are codemods that modify the plugin codebase. Each addition can accept validated options through Valibot schemas, providing full type safety and automatic validation.

Example:

npx @grafana/create-plugin add i18n --locales=sv-SE,fr-FR --grafana11Support=true

Migrations vs Additions

Both migrations and additions are codemods that share the same execution pipeline and can be used interchangeably. The key difference is their purpose and when they run:

  • Migrations: Automatically run during create-plugin update to keep plugins compatible with newer versions of the tooling. They are forced upon developers to ensure compatibility and are versioned based on the create-plugin version.

  • Additions: Optional features that developers choose to add via create-plugin add. They are not versioned and can be run at any time to enhance a plugin with new capabilities.

The distinction between the two is purely semantic based on their use case.

To support additions and simplify the codebase, migrations and additions goes through a shared codemod architecture. A single runner handles execution for both type of codemods, with common steps like formatting, flushing changes and dependency installation. The migrations manager is thin and responsible for version filtering, sequential execution and git commits. The add command directly invokes the runner directly.

Schema-Based Validation with Valibot

Codemods can optionally define options using Valibot schemas, providing automatic ts type inference, runtime validation with clear error messages and a single source of truth for both validation rules and types. Valibot is lightweight (~1kb) and tree-shakeable.

Example:

export const schema = v.object({
  grafana11Support: v.optional(v.boolean(), true),
  locales: v.optional(v.array(v.string())),
  featureName: v.pipe(
    v.string(),
    v.minLength(3, 'Feature name must be at least 3 characters'),
    v.maxLength(50, 'Feature name must be at most 50 characters')
  ),
});

type ExampleOptions = v.InferOutput<typeof schema>;

export default function exampleAddition(context: Context, options: ExampleOptions): Context {
  // Fully typed 
  const { featureName, enabled, port } = options;
}

Which issue(s) this PR fixes:

Fixes #2193

Special notes for your reviewer:

Once this PR is getting closer to a mergeable state, I should add:

  • Docs
  • CI steps for verifying additions work as expected(?)
📦 Published PR as canary version: Canary Versions

✨ Test out this PR locally via:

npm install [email protected]
npm install @grafana/[email protected]
npm install @grafana/[email protected]
npm install @grafana/[email protected]
# or 
yarn add [email protected]
yarn add @grafana/[email protected]
yarn add @grafana/[email protected]
yarn add @grafana/[email protected]

@github-actions
Copy link
Contributor

github-actions bot commented Oct 17, 2025

Hello! 👋 This repository uses Auto for releasing packages using PR labels.

✨ This PR can be merged and will trigger a new minor release.
NOTE: When merging a PR with the release label please avoid merging another PR. For further information see here.

@sunker sunker added minor Increment the minor version when merged release Create a release when this pr is merged labels Oct 17, 2025
@grafana-plugins-platform-bot grafana-plugins-platform-bot bot moved this from 📬 Triage to 🔬 In review in Plugins Platform / Grafana Community Oct 17, 2025
@sunker
Copy link
Contributor Author

sunker commented Oct 28, 2025

After async discussions with @jackw, these are the next steps to be taken:

  • When an addition has completed, it should update the .config/cprs.json and set features[featureName] to enabled. The featureName should be defined in the addtionMeta type.
  • Replace the prompts with command line args. e.g create-plugin add i18n --locales=en-US, se-SV
  • Instead of passing the addition name to runAddition, pass the prompt itself so the user can choose which addition to execute.
  • Move the i18n script to a separate, follow-up pr

Next steps (after this PR has been merged):

  • Write a migration that moves the root cprc.json to .config/cprc.json and deletes the root config
  • Create additions scripts for the existing feature flags (bundleGrafanaUI, useReactRouterV6 & useExperimentalRspack)

@sunker sunker self-assigned this Oct 29, 2025
@sunker sunker moved this from 🔬 In review to 🧑‍💻 In development in Plugins Platform / Grafana Community Oct 29, 2025
@sunker sunker force-pushed the create-plugin/add-cmd branch from 776e264 to 343bbdc Compare October 30, 2025 09:38
- Create additions registry for managing optional feature additions
- Implement additions manager with runAddition, executeAddition
- Add utilities that reuse migration infrastructure (Context, formatFiles, etc.)
- Support for version-agnostic, idempotent additions
- Designed to be extensible for future additions beyond i18n

     Fri Oct 17 09:48:24 2025 +0200
add core infrastructure for 'add' command
implement 'add' command with pre-flight checks
implement 'add i18n' script with full automation
  packages/create-plugin/src/additions/additions.ts
  packages/create-plugin/src/additions/manager.ts
  packages/create-plugin/src/additions/utils.ts
- Add new 'add' command to CLI (npx @grafana/create-plugin add <feature>)
- Implement pre-flight checks (git directory, clean working tree, plugin directory)
- Add interactive prompts for i18n locale selection using enquirer
- Support for multiple locale selection with multiselect UI
- Allow custom locale codes to be entered manually
- Register command in CLI entry point and command index

     Fri Oct 17 09:48:37 2025 +0200
add core infrastructure for 'add' command
implement 'add' command with pre-flight checks
implement 'add i18n' script with full automation
document new 'add' command and 'add i18n' feature
  packages/create-plugin/src/bin/run.ts
  packages/create-plugin/src/commands/add.command.ts
  packages/create-plugin/src/commands/add/prompts.ts
  packages/create-plugin/src/commands/index.ts
Implements complete i18n setup automation:
- Updates docker-compose.yaml with localizationForPlugins feature toggle
- Updates plugin.json with languages array and grafanaDependency >= 12.1.0
- Creates locale folders and translation files for selected locales
- Adds @grafana/i18n dependency to package.json
- Adds i18next-cli dev dependency and i18n-extract script
- Creates i18next.config.ts with proper extraction configuration
- Updates eslint.config.mjs with i18n linting rules
- Adds i18n imports to module.ts/tsx automatically
safely runs multiple times without breaking
- Comprehensive test suite with 8 passing tests covering:
  * Idempotency verification
  * Single and multiple locale support
  * Skipping when already configured
  * Handling existing feature toggles
  * Support for both .ts and .tsx modules
  * Version-aware dependency updates
  * Edge cases (missing scripts, etc.)

This automates all manual steps shown in grafana/grafana-plugin-examples#588

     Fri Oct 17 09:48:52 2025 +0200
implement 'add' command with pre-flight checks
implement 'add i18n' script with full automation
document new 'add' command and 'add i18n' feature
include additions scripts in rollup build
  packages/create-plugin/src/additions/scripts/add-i18n.test.ts
  packages/create-plugin/src/additions/scripts/add-i18n.ts
- Add comprehensive documentation for the new 'add' command
- Document 'add i18n' usage with interactive prompts
- List all actions performed by the i18n addition
- Provide examples of common locales that can be selected
- Link to plugin internationalization documentation
- Explain the automated setup process

     Fri Oct 17 09:49:03 2025 +0200
implement 'add i18n' script with full automation
document new 'add' command and 'add i18n' feature
include additions scripts in rollup build
improve add i18n command with backward compatibility
  packages/create-plugin/README.md
- Add additions scripts to rollup input alongside migrations
- Ensures add-i18n.js is compiled and available in dist/
- Fixes module resolution error when running npx @grafana/create-plugin add i18n

     Fri Oct 17 10:02:28 2025 +0200
document new 'add' command and 'add i18n' feature
include additions scripts in rollup build
improve add i18n command with backward compatibility
make additions self-contained with dynamic flag loading
  rollup.config.ts
This commit enhances the add i18n command to better support plugins
targeting different Grafana versions:

Key improvements:
Automatically detects if a
   plugin targets Grafana < 12.1.0 and applies the appropriate configuration:
   - Sets grafanaDependency to >=11.0.0 (instead of >=12.1.0)
   - Creates loadResources.ts file for manual resource loading
   - Adds conditional loader logic in module initialization
   - Adds semver as a regular dependency (not just dev)
   - Skips docker-compose.yaml feature toggle (not needed for < 12.1.0)

2. **Updated dependency versions**:
12.2.2 (was ^1.0.0)
^7.6.0 and @types/semver: ^7.5.0 for version checks

Generated locale JSON files now include
   example translation structure (components and config sections) to help
   users understand the format

Updated rollup.config.ts to properly bundle
   addition scripts from src/additions/scripts directory

The implementation follows the official Grafana documentation for i18n
support in plugins before Grafana 12.1.0, including:
- loadResources.ts for resource loading
- Conditional loaders based on Grafana version
- Proper import setup for semver and config from @grafana/runtime

Tests updated to cover both backward compatibility mode (Grafana 11+)
and modern mode (Grafana 12.1.0+).

     Fri Oct 17 10:19:56 2025 +0200
include additions scripts in rollup build
improve add i18n command with backward compatibility
make additions self-contained with dynamic flag loading
move prompt from cmd file to the manager
  packages/create-plugin/src/additions/scripts/add-i18n.test.ts
  packages/create-plugin/src/additions/scripts/add-i18n.ts
  rollup.config.ts
- Each addition script now exports its own flags and parseFlags function
- Removed prompts.ts in favor of CLI flags
- Manager dynamically loads flags from addition scripts
- Simplified additions.ts to only contain metadata
- Makes adding new additions fully plug-and-play without touching core files

     Thu Oct 30 09:28:25 2025 +0100
improve add i18n command with backward compatibility
make additions self-contained with dynamic flag loading
move prompt from cmd file to the manager
  packages/create-plugin/src/additions/additions.ts
  packages/create-plugin/src/additions/manager.ts
  packages/create-plugin/src/additions/scripts/add-i18n.ts
  packages/create-plugin/src/commands/add.command.ts
   packages/create-plugin/src/commands/add/prompts.ts
     Thu Oct 30 10:29:39 2025 +0100
make additions self-contained with dynamic flag loading
move prompt from cmd file to the manager
  packages/create-plugin/src/additions/manager.ts
  packages/create-plugin/src/commands/add.command.ts
@sunker sunker force-pushed the create-plugin/add-cmd branch from 343bbdc to 0d94e1d Compare October 30, 2025 09:56
@sunker sunker mentioned this pull request Nov 3, 2025
7 tasks
@jackw jackw self-requested a review November 5, 2025 11:53
@sunker sunker marked this pull request as draft November 10, 2025 12:22
@sunker
Copy link
Contributor Author

sunker commented Nov 10, 2025

Planning to iterate a bit more on this PR so moving it to draft state.

{
name: 'example-addition',
description: 'Example addition demonstrating Valibot schema with type inference',
scriptPath: './scripts/example-addition.ts',
Copy link
Contributor Author

Choose a reason for hiding this comment

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

will remove this before merging to main

{
name: 'example-addition',
description: 'Example addition demonstrating Valibot schema with type inference',
scriptPath: resolveScriptPath(import.meta.url, './scripts/example-addition.js'),
Copy link
Contributor Author

Choose a reason for hiding this comment

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

scripts are now imported from the shared codemod runner, so paths must be resolved relative to this registry file's location to ensure correct resolution at runtime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

minor Increment the minor version when merged release Create a release when this pr is merged

Projects

Status: 🧑‍💻 In development

Development

Successfully merging this pull request may close these issues.

Feat: Support for new add command

1 participant