Skip to content

feat(extensions): Introduce fetch endpoints for configuration#740

Merged
dzemanov merged 19 commits intoredhat-developer:mainfrom
dzemanov:RHIDP-6807_marketplace_fetch_config
May 29, 2025
Merged

feat(extensions): Introduce fetch endpoints for configuration#740
dzemanov merged 19 commits intoredhat-developer:mainfrom
dzemanov:RHIDP-6807_marketplace_fetch_config

Conversation

@dzemanov
Copy link
Copy Markdown
Member

@dzemanov dzemanov commented May 6, 2025

Hey, I just made a Pull Request!

Introduces fetch endpoints for plugin configuration.

Fixes

Fixes RHIDP-6807

How to test

  1. Create dynamic-plugins.yaml with:
plugins:
  - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import-backend-dynamic
    disabled: false
  - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-bulk-import
    disabled: true
    pluginConfig:
      dynamicPlugins:
        frontend:
          red-hat-developer-hub.backstage-plugin-bulk-import:
            appIcons:
              - name: bulkImportIcon3
                importName: BulkImportIcon3
            dynamicRoutes:
              - path: /bulk-import/repositories
                importName: BulkImportPage
                menuItem:
                  icon: bulkImportIcon
                  text: Bulk import
  - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-marketplace-backend-dynamic
    disabled: false
  - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-marketplace
    disabled: false # COMMENT
    pluginConfig:
      dynamicPlugins:
        frontend:
          red-hat-developer-hub.backstage-plugin-marketplace:
            appIcons:
              - name: marketplace
                importName: MarketplaceIcon
            dynamicRoutes:
              - path: /extensions/catalog
                importName: DynamicMarketplacePluginRouter
            mountPoints:
              - mountPoint: internal.plugins/tab
                importName: DynamicMarketplacePluginContent
                config:
                  path: marketplace
                  title: Catalog
  1. Test that the endpoints return 503 if extensions.installation.enabled is not set:
{
  "error": {
    "name": "InstallationInitError",
    "message": "Installation feature is disabled under 'extensions.installation.enabled'",
    "reason": "INSTALLATION_DISABLED",
    "statusCode": 503,
    "stack": "..."
  },
  "request": {
    "method": "GET",
    "url": "/plugin/marketplace-plugin-demo/marketplace/configuration"
  },
  "response": {
    "statusCode": 503
  }
curl -X GET "http://localhost:7007/api/extensions/package/marketplace-plugin-demo/red-hat-developer-hub-backstage-plugin-marketplace/configuration" -H "Content-Type: application/json" -H "Authorization: Bearer $token"
curl -X GET "http://localhost:7007/api/extensions/plugin/marketplace-plugin-demo/marketplace/configuration" -H "Content-Type: application/json" -H "Authorization: Bearer $token"
  1. Update extensions.installation to point to the dynamic-plugins.yaml file
extensions:
  installation:
    enabled: true
    saveToSingleFile:
      file: /my-path/dynamic-plugins.yaml
  1. Test GET package configuration
curl -X GET "http://localhost:7007/api/extensions/package/marketplace-plugin-demo/red-hat-developer-hub-backstage-plugin-marketplace/configuration" -H "Content-Type: application/json" -H "Authorization: Bearer $token"

Should return:

{
"configYaml":
    "- package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-marketplace
      disabled: false # COMMENT
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-marketplace:
              appIcons:
                - name: marketplace
                  importName: MarketplaceIcon
              dynamicRoutes:
                - path: /extensions/catalog
                  importName: DynamicMarketplacePluginRouter
              mountPoints:
                - mountPoint: internal.plugins/tab
                  importName: DynamicMarketplacePluginContent
                  config:
                    path: marketplace
                    title: Catalog"
}
  1. Test GET plugin configuration
curl -X GET "http://localhost:7007/api/extensions/plugin/marketplace-plugin-demo/marketplace/configuration" -H "Content-Type: application/json" -H "Authorization: Bearer $token"

Should return

{
"configYaml":
    "- package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-marketplace
      disabled: false # COMMENT
      pluginConfig:
        dynamicPlugins:
          frontend:
            red-hat-developer-hub.backstage-plugin-marketplace:
              appIcons:
                - name: marketplace
                  importName: MarketplaceIcon
              dynamicRoutes:
                - path: /extensions/catalog
                  importName: DynamicMarketplacePluginRouter
              mountPoints:
                - mountPoint: internal.plugins/tab
                  importName: DynamicMarketplacePluginContent
                  config:
                    path: marketplace
                    title: Catalog
    - package: ./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-marketplace-backend-dynamic
      disabled: false"
}
  1. Update plugins config to point to nonexistent file and call one of the new endpoints
{
  "error": {
    "name": "InstallationInitError",
    "message": "Installation config file does not exist: /path/to/dynamic-plugins-nonexistent.yaml",
    "reason": "FILE_NOT_EXISTS",
    "statusCode": 500,
    "stack": "..."
  },
  "request": {
    "method": "GET",
    "url": "/plugin/marketplace-plugin-demo/marketplace/configuration"
  },
  "response": {
    "statusCode": 500
  }
}
  1. Remove file from config, while installation is enabled and call one of the new endpoints
{
  "error": {
    "name": "InstallationInitError",
    "message": "Missing required config value at 'extensions.installation.saveToSingleFile.file'",
    "reason": "FILE_CONFIG_VALUE_MISSING",
    "statusCode": 500,
    "stack": "..."
  },
  "request": {
    "method": "GET",
    "url": "/plugin/marketplace-plugin-demo/marketplace/configuration"
  },
  "response": {
    "statusCode": 500
  }
}
  1. Update plugins config to invalid format and call one of the new endpoints
{
  "error": {
    "name": "InstallationInitError",
    "message": "Invalid installation configuration, optional 'disabled' field in each package item must be a boolean",
    "reason": "INVALID_CONFIG",
    "statusCode": 500,
    "stack": "..."
  },
  "request": {
    "method": "GET",
    "url": "/plugin/marketplace-plugin-demo/marketplace/configuration"
  },
  "response": {
    "statusCode": 500
  }
}

✔️ Checklist

  • A changeset describing the change and affected packages. (more info)
  • Added or Updated documentation
  • Tests for new functionality and regression tests for bug fixes
  • Screenshots attached (for UI changes)

@rhdh-gh-app
Copy link
Copy Markdown

rhdh-gh-app Bot commented May 6, 2025

Important

This PR includes changes that affect public-facing API. Please ensure you are adding/updating documentation for new features or behavior.

Changed Packages

Package Name Package Path Changeset Bump Current Version
@red-hat-developer-hub/backstage-plugin-marketplace-backend workspaces/marketplace/plugins/marketplace-backend minor v0.3.1
@red-hat-developer-hub/backstage-plugin-marketplace-common workspaces/marketplace/plugins/marketplace-common minor v0.3.0

@dzemanov dzemanov force-pushed the RHIDP-6807_marketplace_fetch_config branch from eb434f0 to f116610 Compare May 13, 2025 11:53
@dzemanov dzemanov marked this pull request as ready for review May 13, 2025 12:10
Comment thread workspaces/marketplace/app-config.yaml Outdated
@dzemanov dzemanov force-pushed the RHIDP-6807_marketplace_fetch_config branch 4 times, most recently from 75e5555 to 7559164 Compare May 15, 2025 07:52
@dzemanov dzemanov changed the title feat(marketplace): Introduce fetch endpoints for configuration feat(extensions): Introduce fetch endpoints for configuration May 15, 2025
@dzemanov dzemanov requested a review from debsmita1 May 15, 2025 16:17
dzemanov added 3 commits May 16, 2025 08:24
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@dzemanov dzemanov force-pushed the RHIDP-6807_marketplace_fetch_config branch from 3d08c10 to 3897b82 Compare May 16, 2025 09:55
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Copy link
Copy Markdown
Member

@debsmita1 debsmita1 left a comment

Choose a reason for hiding this comment

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

For a configuration like

extensions:
  ### Example for how to enable installation to a file.
  installation:
    enabled: true
    # type: 'saveToSingleFile'
    # saveToSingleFile:
    #   file: /Users/dsantra/Documents/rhdh-plugins/workspaces/marketplace/dynamic-plugins.yaml

The API throws an error saying

Installation is disabled under 'extensions.installation.enabled'.

If we are only support saving to a single file now, would it make sense to not have the type: 'saveToSingleFile' config property ?
We can add the type, once we support more installation types

For dynamic-plugin.yaml content containing a random string like xyz , I get a response like

{
  "error": {
      "name": "Error",
      "message": "Installation is disabled under 'extensions.installation.enabled'.",
      ...
          },
  "request": {
      "method": "GET",
      "url": "/plugin/marketplace-plugin-demo/marketplace/configuration"
  },
  "response": {
      "statusCode": 500
  }
}

@dzemanov
Copy link
Copy Markdown
Member Author

@debsmita1 sure, we can remove the type for now.

The cases with invalid config should fall under 6. case, Marketplace installation feature is disabled, the log includes Error while loading installation data. Installation will be disabled. Error: ... and api endpoints return 500. Would it be more appropriate to throw an error and prevent plugin from starting up in case of invalid file format?

For the case when file is not specified although installation is enabled, we can change the behavior as well to throw an error and prevent plugin from starting up.

Comment thread workspaces/marketplace/plugins/marketplace-backend/src/router.ts Outdated
dzemanov added 2 commits May 20, 2025 12:39
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@debsmita1
Copy link
Copy Markdown
Member

@debsmita1 sure, we can remove the type for now.

The cases with invalid config should fall under 6. case, Marketplace installation feature is disabled, the log includes Error while loading installation data. Installation will be disabled. Error: ... and api endpoints return 500. Would it be more appropriate to throw an error and prevent plugin from starting up in case of invalid file format?

I checked what we currently do with our RBAC plugin that consumes a .csv file. Invalid content in that file doesn't stop the backend or the frontend from starting, but it does disable the Create role button. So, in our case, we can disable the Install button

For the case when file is not specified although installation is enabled, we can change the behavior as well to throw an error and prevent plugin from starting up.

From our last working group call, what I have understood is, if the file is not specified, then we disable the Install button. So, if you can return an appropriate status like ex: "DYNAMIC_PLUGINS_FILE_MISSING" or something like this, then we can handle this in the UI

@ShiranHi Could you help me with how we can show this in the UI so that we can guide the users on how to get rid of the error ?

@ShiranHi
Copy link
Copy Markdown

For the case when file is not specified although installation is enabled, we can change the behavior as well to throw an error and prevent plugin from starting up.

From our last working group call, what I have understood is, if the file is not specified, then we disable the Install button. So, if you can return an appropriate status like ex: "DYNAMIC_PLUGINS_FILE_MISSING" or something like this, then we can handle this in the UI

@ShiranHi Could you help me with how we can show this in the UI so that we can guide the users on how to get rid of the error ?

Yes, disabling the Install button on the configuration page would work, we can add a tooltip on hover to say "Plugin installation is disabled. Contact your administrator for assistance."

dzemanov added 2 commits May 21, 2025 09:34
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@dzemanov dzemanov requested a review from debsmita1 May 21, 2025 08:16
dzemanov added 3 commits May 21, 2025 16:57
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Copy link
Copy Markdown
Member

@debsmita1 debsmita1 left a comment

Choose a reason for hiding this comment

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

Thank you @dzemanov !
I am able to test all the scenarios

Screenshot 2025-05-27 at 12 30 40 AM

Could you resolve the Sonarqube cloud issues ?

Tagging @PatAKnight for API review

dzemanov added 2 commits May 27, 2025 09:56
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@dzemanov dzemanov requested a review from PatAKnight May 27, 2025 10:37
Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@dzemanov
Copy link
Copy Markdown
Member Author

@debsmita1 sonarqube issues are fixed, thank you for pointing them out!

Copy link
Copy Markdown
Contributor

@AndrienkoAleksandr AndrienkoAleksandr left a comment

Choose a reason for hiding this comment

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

Tested, works fine. Reviewed, pr looks good to me. @dzemanov, Thank you for great code !

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
@sonarqubecloud
Copy link
Copy Markdown

@dzemanov dzemanov merged commit f56908a into redhat-developer:main May 29, 2025
10 checks passed
@dzemanov dzemanov deleted the RHIDP-6807_marketplace_fetch_config branch September 25, 2025 07:00
elai-shalev pushed a commit to elai-shalev/rhdh-plugins that referenced this pull request Jan 21, 2026
…-developer#740)

* Introduce configuration get endpoints

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Add bulk-import to examples

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Return yaml format

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Do not throw error when config not found

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Disable installation if invalid config file instead of throwing

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Deduplicate configValidation

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Change namespace

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Disable line wrap

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Use array

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Return error objects

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Remove installation type

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Use set

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Return json from config endpoints

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Update api report

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Rename

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Fix sonarqube issues

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Add not found test cases

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Fix sonarqube issue to safely access value

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

* Introduce ConfigurationResponse type

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>

---------

Signed-off-by: Dominika Zemanovicova <dzemanov@redhat.com>
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.

4 participants