From a686f542700952f8831de830e0fd24e16a752924 Mon Sep 17 00:00:00 2001 From: Fortune-Ndlovu Date: Thu, 20 Mar 2025 16:03:47 +0000 Subject: [PATCH 01/23] feat(config): Introduce user-specific config files to prevent merge conflicts - Added and as sample configuration files. - Removed and from the repository. - Updated to exclude user-specific config files. - Modified to allow missing config files and fall back to sample files if necessary. - Updated README with instructions on copying sample config files. Signed-off-by: Fortune-Ndlovu --- .gitignore | 6 +++++- README.md | 8 +++++++- compose.yaml | 4 ++++ ...app-config.local.yaml => app-config.local.yaml.sample} | 0 .../{dynamic-plugins.yaml => dynamic-plugins.yaml.sample} | 0 5 files changed, 16 insertions(+), 2 deletions(-) rename configs/{app-config.local.yaml => app-config.local.yaml.sample} (100%) rename configs/{dynamic-plugins.yaml => dynamic-plugins.yaml.sample} (100%) diff --git a/.gitignore b/.gitignore index ff1df5c..80e4d19 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,7 @@ .env configs/github-app-credentials.yaml -/tmp \ No newline at end of file +/tmp + +# Ignore user-modified config files +configs/app-config.local.yaml +configs/dynamic-plugins.yaml diff --git a/README.md b/README.md index 363657e..2764203 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,13 @@ To use RHDH Local you'll need a few things: In most cases, when you don't need GitHub Auth or testing different releases you can leave it as it is, and it should work. -1. (Optional) Update `configs/app-config.local.yaml`. +1. (Recommended) Set up your configuration files. + To prevent merge conflicts, create copies of the provided sample configuration files: + + ```sh + cp configs/app-config.local.yaml.sample configs/app-config.local.yaml + cp configs/dynamic-plugins.yaml.sample configs/dynamic-plugins.yaml + ``` If you need features that fetch files from GitHub you should configure `integrations.github`. The recommended way is to use GitHub Apps. You can find hints on how to configure it in [github-app-credentials.example.yaml](configs/github-app-credentials.example.yaml) or a more detailed instruction in [Backstage documentation](https://backstage.io/docs/integrations/github/github-apps). diff --git a/compose.yaml b/compose.yaml index 0f98bdd..aae31f1 100644 --- a/compose.yaml +++ b/compose.yaml @@ -31,6 +31,10 @@ services: ports: # dclint disable-line no-unbound-port-interfaces - "7007:7007" volumes: + - ./configs/app-config.local.yaml:/opt/app-root/src/app-config.local.yaml:ro + - ./configs/dynamic-plugins.yaml:/opt/app-root/src/dynamic-plugins.yaml:ro + - ./configs/app-config.local.yaml.sample:/opt/app-root/src/app-config.local.yaml:ro + - ./configs/dynamic-plugins.yaml.sample:/opt/app-root/src/dynamic-plugins.yaml:ro - type: bind source: "./wait-for-plugins.sh" target: "/opt/app-root/src/wait-for-plugins.sh" diff --git a/configs/app-config.local.yaml b/configs/app-config.local.yaml.sample similarity index 100% rename from configs/app-config.local.yaml rename to configs/app-config.local.yaml.sample diff --git a/configs/dynamic-plugins.yaml b/configs/dynamic-plugins.yaml.sample similarity index 100% rename from configs/dynamic-plugins.yaml rename to configs/dynamic-plugins.yaml.sample From 92351d969eb1158b921d5354b3971536269cc47f Mon Sep 17 00:00:00 2001 From: Fortune-Ndlovu Date: Thu, 20 Mar 2025 16:24:56 +0000 Subject: [PATCH 02/23] fix(ci): Ensure sample config files are copied in CI/CD Signed-off-by: Fortune-Ndlovu --- .github/workflows/test.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 2d3dd90..95c4858 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,6 +51,11 @@ jobs: - name: prepare .env run: cp env.sample .env + - name: Prepare config files + run: | + cp configs/app-config.local.yaml.sample configs/app-config.local.yaml + cp configs/dynamic-plugins.yaml.sample configs/dynamic-plugins.yaml + - name: Install tool if: ${{ matrix.tool == 'podman' }} env: From cbf8824ee5ecc49326b2d99ce914ee879922cdde Mon Sep 17 00:00:00 2001 From: Fortune-Ndlovu Date: Thu, 20 Mar 2025 16:41:22 +0000 Subject: [PATCH 03/23] fix(ci): Improve Podman Compose debugging and startup checks --- .github/workflows/test.yml | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 95c4858..65222c9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,6 +56,10 @@ jobs: cp configs/app-config.local.yaml.sample configs/app-config.local.yaml cp configs/dynamic-plugins.yaml.sample configs/dynamic-plugins.yaml + - name: Ensure Podman runs in rootless mode + if: ${{ matrix.tool == 'podman' }} + run: export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus" + - name: Install tool if: ${{ matrix.tool == 'podman' }} env: @@ -66,7 +70,20 @@ jobs: - name: Start app run: | ${{ matrix.tool }} compose ${{ matrix.composeConfig.cliArgs }} up -d - ${{ matrix.tool }} compose ${{ matrix.composeConfig.cliArgs }} ps + echo "Checking if the RHDH container started correctly..." + sleep 10 + ${{ matrix.tool }} compose ps + echo "Printing logs from RHDH container..." + ${{ matrix.tool }} compose logs rhdh || true + + - name: Ensure RHDH container is running before HTTP check + run: | + echo "Verifying that the RHDH container is running..." + if ! ${{ matrix.tool }} compose ps | grep -q "rhdh"; then + echo "ERROR: RHDH container is NOT running! Printing logs..." + ${{ matrix.tool }} compose logs rhdh + exit 1 + fi - name: Wait for HTTP 200 response from homepage run: | From e6287e12ea31688a39222c86302f4e42be7b9efa Mon Sep 17 00:00:00 2001 From: Fortune-Ndlovu Date: Mon, 24 Mar 2025 11:49:25 +0000 Subject: [PATCH 04/23] Revert CI workflow to only include config file setup --- .github/workflows/test.yml | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 65222c9..95c4858 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -56,10 +56,6 @@ jobs: cp configs/app-config.local.yaml.sample configs/app-config.local.yaml cp configs/dynamic-plugins.yaml.sample configs/dynamic-plugins.yaml - - name: Ensure Podman runs in rootless mode - if: ${{ matrix.tool == 'podman' }} - run: export DBUS_SESSION_BUS_ADDRESS="unix:path=$XDG_RUNTIME_DIR/bus" - - name: Install tool if: ${{ matrix.tool == 'podman' }} env: @@ -70,20 +66,7 @@ jobs: - name: Start app run: | ${{ matrix.tool }} compose ${{ matrix.composeConfig.cliArgs }} up -d - echo "Checking if the RHDH container started correctly..." - sleep 10 - ${{ matrix.tool }} compose ps - echo "Printing logs from RHDH container..." - ${{ matrix.tool }} compose logs rhdh || true - - - name: Ensure RHDH container is running before HTTP check - run: | - echo "Verifying that the RHDH container is running..." - if ! ${{ matrix.tool }} compose ps | grep -q "rhdh"; then - echo "ERROR: RHDH container is NOT running! Printing logs..." - ${{ matrix.tool }} compose logs rhdh - exit 1 - fi + ${{ matrix.tool }} compose ${{ matrix.composeConfig.cliArgs }} ps - name: Wait for HTTP 200 response from homepage run: | From 65758187f07ba15d035e03813afe6e2693b9d1cd Mon Sep 17 00:00:00 2001 From: Fortune-Ndlovu Date: Mon, 24 Mar 2025 11:58:58 +0000 Subject: [PATCH 05/23] Update README to clearly mark setting up configuration files as Required. Signed-off-by: Fortune-Ndlovu --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2764203..7f51ea1 100644 --- a/README.md +++ b/README.md @@ -40,8 +40,8 @@ To use RHDH Local you'll need a few things: In most cases, when you don't need GitHub Auth or testing different releases you can leave it as it is, and it should work. -1. (Recommended) Set up your configuration files. - To prevent merge conflicts, create copies of the provided sample configuration files: +1. **Required**: Set up your configuration files. + To prevent merge conflicts, create copies of the provided sample configuration files. Do this before running `docker compose up` or `podman compose up` for the first time: ```sh cp configs/app-config.local.yaml.sample configs/app-config.local.yaml From 42322309e6346e59e752f9178fb0650987444d3c Mon Sep 17 00:00:00 2001 From: Fortune-Ndlovu Date: Mon, 24 Mar 2025 12:43:00 +0000 Subject: [PATCH 06/23] refactor(config): support automatic local config overrides using structured configs/ layout Signed-off-by: Fortune-Ndlovu --- .github/workflows/test.yml | 5 -- .gitignore | 8 +- README.md | 22 +++-- compose.yaml | 5 +- .../app-config.yaml} | 0 .../dynamic-plugins.local.yaml} | 0 configs/dynamic-plugins/dynamic-plugins.yaml | 80 +++++++++++++++++++ .../github-app-credentials.example.yaml | 0 fixes.sh | 13 +++ wait-for-plugins.sh | 19 +++-- 10 files changed, 128 insertions(+), 24 deletions(-) rename configs/{app-config.local.yaml.sample => app-config/app-config.yaml} (100%) rename configs/{dynamic-plugins.yaml.sample => dynamic-plugins/dynamic-plugins.local.yaml} (100%) create mode 100644 configs/dynamic-plugins/dynamic-plugins.yaml rename configs/{ => extra-files}/github-app-credentials.example.yaml (100%) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 95c4858..2d3dd90 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,11 +51,6 @@ jobs: - name: prepare .env run: cp env.sample .env - - name: Prepare config files - run: | - cp configs/app-config.local.yaml.sample configs/app-config.local.yaml - cp configs/dynamic-plugins.yaml.sample configs/dynamic-plugins.yaml - - name: Install tool if: ${{ matrix.tool == 'podman' }} env: diff --git a/.gitignore b/.gitignore index 80e4d19..d1d15ef 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ configs/github-app-credentials.yaml /tmp -# Ignore user-modified config files -configs/app-config.local.yaml -configs/dynamic-plugins.yaml +# Ignore user-specific config overrides +configs/app-config/app-config.local.yaml +configs/dynamic-plugins/dynamic-plugins.override.yaml +configs/extra-files/* +!configs/extra-files/github-app-credentials.example.yaml diff --git a/README.md b/README.md index 7f51ea1..252aaf7 100644 --- a/README.md +++ b/README.md @@ -40,17 +40,25 @@ To use RHDH Local you'll need a few things: In most cases, when you don't need GitHub Auth or testing different releases you can leave it as it is, and it should work. -1. **Required**: Set up your configuration files. - To prevent merge conflicts, create copies of the provided sample configuration files. Do this before running `docker compose up` or `podman compose up` for the first time: +1. (Optional) Create local configuration overrides. + + RHDH Local now supports user-specific configuration overrides using a structured `configs/` directory. You do not need to copy or modify default files. However, if you want to customize your setup: + + - Add your app config overrides to: + `configs/app-config/app-config.local.yaml` + + - Add your plugin config overrides to: + `configs/dynamic-plugins/dynamic-plugins.override.yaml` + + - Add any extra files (like GitHub credentials) to: + `configs/extra-files/` (already Git-ignored) + + If present, these files will be automatically loaded by the system on startup. - ```sh - cp configs/app-config.local.yaml.sample configs/app-config.local.yaml - cp configs/dynamic-plugins.yaml.sample configs/dynamic-plugins.yaml - ``` If you need features that fetch files from GitHub you should configure `integrations.github`. The recommended way is to use GitHub Apps. You can find hints on how to configure it in [github-app-credentials.example.yaml](configs/github-app-credentials.example.yaml) or a more detailed instruction in [Backstage documentation](https://backstage.io/docs/integrations/github/github-apps). -1. Start RHDH Local. +2. Start RHDH Local. This repository should work with either `docker compose` using Docker Engine or `podman-compose` using Podman. When using Podman there are some exceptions. Check [Known Issues when using Podman Compose](#known-issues-when-using-podman-compose) for more info. ```sh diff --git a/compose.yaml b/compose.yaml index aae31f1..61cfd14 100644 --- a/compose.yaml +++ b/compose.yaml @@ -31,10 +31,7 @@ services: ports: # dclint disable-line no-unbound-port-interfaces - "7007:7007" volumes: - - ./configs/app-config.local.yaml:/opt/app-root/src/app-config.local.yaml:ro - - ./configs/dynamic-plugins.yaml:/opt/app-root/src/dynamic-plugins.yaml:ro - - ./configs/app-config.local.yaml.sample:/opt/app-root/src/app-config.local.yaml:ro - - ./configs/dynamic-plugins.yaml.sample:/opt/app-root/src/dynamic-plugins.yaml:ro + - ./configs:/opt/app-root/src/configs:Z - type: bind source: "./wait-for-plugins.sh" target: "/opt/app-root/src/wait-for-plugins.sh" diff --git a/configs/app-config.local.yaml.sample b/configs/app-config/app-config.yaml similarity index 100% rename from configs/app-config.local.yaml.sample rename to configs/app-config/app-config.yaml diff --git a/configs/dynamic-plugins.yaml.sample b/configs/dynamic-plugins/dynamic-plugins.local.yaml similarity index 100% rename from configs/dynamic-plugins.yaml.sample rename to configs/dynamic-plugins/dynamic-plugins.local.yaml diff --git a/configs/dynamic-plugins/dynamic-plugins.yaml b/configs/dynamic-plugins/dynamic-plugins.yaml new file mode 100644 index 0000000..30e9044 --- /dev/null +++ b/configs/dynamic-plugins/dynamic-plugins.yaml @@ -0,0 +1,80 @@ +includes: + - dynamic-plugins.default.yaml +plugins: [] + + # EXAMPLES: + # loading plugin from host directory + # - package: ./local-plugins/todo + # disabled: false + # pluginConfig: + # dynamicPlugins: + # frontend: + # backstage-community.plugin-todo: + # mountPoints: + # - mountPoint: entity.page.todo/cards + # importName: EntityTodoContent + # entityTabs: + # - path: /todo + # title: Todo + # mountPoint: entity.page.todo + + # loading image from container image + # - package: oci://docker.io/tomaskral/simple-chat:v0.0.1!internal-backstage-plugin-simple-chat + # disabled: false + # pluginConfig: + # dynamicPlugins: + # frontend: + # internal.backstage-plugin-simple-chat: + # appIcons: + # - name: chatIcon + # importName: ChatIcon + # dynamicRoutes: + # - path: /simple-chat + # importName: SimpleChatPage + # menuItem: + # text: 'Simple Chat' + # icon: chatIcon + + # # loading image from tarball URL + # - disabled: false + # package: >- + # https://github.com/redhat-developer/rhdh-plugin-export-backstage-community-plugins/releases/download/v1.2.0/backstage-community-plugin-tech-insights-dynamic-0.3.28.tgz + # integrity: sha512-cNHXSwPa5fOi2BcNVSe7tfdLyM0JY988CE5t+P9p/XlboP1QpQbMcLBmqPrlXZdpedAyp81Zz3yPQYGnPuy9ww== + # pluginConfig: + # dynamicPlugins: + # techInsights: + # factRetrievers: + # entityOwnershipFactRetriever: + # cadence: '*/15 * * * *' + # lifecycle: { timeToLive: { weeks: 2 } } + # entityMetadataFactRetriever: + # cadence: '*/15 * * * *' + # lifecycle: { timeToLive: { weeks: 2 } } + # techdocsFactRetriever: + # cadence: '*/15 * * * *' + # lifecycle: { timeToLive: { weeks: 2 } } + # apiDefinitionFactRetriever: + # cadence: '*/15 * * * *' + # lifecycle: { timeToLive: { weeks: 2 } } + + # # loading plugin from directory inside the RHDH container + # - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-rbac + # disabled: true + # pluginConfig: + # dynamicPlugins: + # frontend: + # janus-idp.backstage-plugin-rbac: + # mountPoints: + # - mountPoint: admin.page.rbac/cards + # module: RbacPlugin + # importName: RbacPage + # config: + # layout: + # gridColumn: "1 / -1" + # width: 100vw + # props: + # useHeader: false + # dynamicRoutes: + # - path: /admin/rbac + # module: RbacPlugin + # importName: RbacPage diff --git a/configs/github-app-credentials.example.yaml b/configs/extra-files/github-app-credentials.example.yaml similarity index 100% rename from configs/github-app-credentials.example.yaml rename to configs/extra-files/github-app-credentials.example.yaml diff --git a/fixes.sh b/fixes.sh index dacdb44..fbf1245 100755 --- a/fixes.sh +++ b/fixes.sh @@ -19,5 +19,18 @@ fi echo "Removing ~/.npmrc to fix RHIDP-4410" rm -rf ~/.npmrc +# handle dynamic-plugins config override +DYNAMIC_PLUGINS_DEFAULT="/opt/app-root/src/configs/dynamic-plugins/dynamic-plugins.yaml" +DYNAMIC_PLUGINS_OVERRIDE="/opt/app-root/src/configs/dynamic-plugins/dynamic-plugins.override.yaml" +LINK_TARGET="/opt/app-root/src/dynamic-plugins.yaml" + +if [ -f "$DYNAMIC_PLUGINS_OVERRIDE" ]; then + echo "Using dynamic-plugins.override.yaml" + ln -sf "$DYNAMIC_PLUGINS_OVERRIDE" "$LINK_TARGET" +else + echo "Using default dynamic-plugins.yaml" + ln -sf "$DYNAMIC_PLUGINS_DEFAULT" "$LINK_TARGET" +fi + echo "Running install-dynamic-plugins.sh" ./install-dynamic-plugins.sh /dynamic-plugins-root \ No newline at end of file diff --git a/wait-for-plugins.sh b/wait-for-plugins.sh index 0c9faf6..9e84882 100755 --- a/wait-for-plugins.sh +++ b/wait-for-plugins.sh @@ -3,17 +3,26 @@ # This script is a workaround for podman-compose absence of support for depends_on DYNAMIC_PLUGINS_CONFIG="dynamic-plugins-root/app-config.dynamic-plugins.yaml" +USER_APP_CONFIG="configs/app-config/app-config.local.yaml" +DEFAULT_APP_CONFIG="configs/app-config/app-config.yaml" - +# Wait for dynamic plugins config to be generated while [ ! -f "$DYNAMIC_PLUGINS_CONFIG" ]; do echo "Waiting for $DYNAMIC_PLUGINS_CONFIG to be created by install-dynamic-plugins container ..." - sleep 2 + sleep 2 done +# Optionally include user app-config.local.yaml if it exists +EXTRA_CLI_ARGS="" +if [ -f "$USER_APP_CONFIG" ]; then + echo "Using user app-config.local.yaml" + EXTRA_CLI_ARGS="--config $USER_APP_CONFIG" +fi +# Run Backstage with default + optional config overrides node packages/backend --no-node-snapshot \ - --config app-config.yaml \ + --config "$DEFAULT_APP_CONFIG" \ --config app-config.example.yaml \ --config app-config.example.production.yaml \ - --config $DYNAMIC_PLUGINS_CONFIG \ - --config configs/app-config.local.yaml + --config "$DYNAMIC_PLUGINS_CONFIG" \ + $EXTRA_CLI_ARGS From 3a9f1d878bec1d59792be3f4be058e3f63796518 Mon Sep 17 00:00:00 2001 From: Fortune-Ndlovu Date: Mon, 24 Mar 2025 13:04:07 +0000 Subject: [PATCH 07/23] fix(compose): remove obsolete dynamic-plugins.yaml mount causing CI failure Signed-off-by: Fortune-Ndlovu --- .gitignore | 1 + compose.yaml | 5 ----- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index d1d15ef..188fa93 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ configs/app-config/app-config.local.yaml configs/dynamic-plugins/dynamic-plugins.override.yaml configs/extra-files/* !configs/extra-files/github-app-credentials.example.yaml +.qodo diff --git a/compose.yaml b/compose.yaml index 61cfd14..ecb555c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -80,11 +80,6 @@ services: target: "/opt/app-root/src/configs" bind: selinux: "Z" - - type: bind - source: "./configs/dynamic-plugins.yaml" - target: "/opt/app-root/src/dynamic-plugins.yaml" - bind: - selinux: "Z" - type: volume source: dynamic-plugins-root target: /dynamic-plugins-root From 6fac27c99bbebc1532cd2ac713a1cc4b5296c73a Mon Sep 17 00:00:00 2001 From: my-name Date: Mon, 31 Mar 2025 14:33:40 +0100 Subject: [PATCH 08/23] fixup: Added app-config first in the list and its the first file in the image. AND made the default app-onfig file from this repo to be last Signed-off-by: my-name --- wait-for-plugins.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wait-for-plugins.sh b/wait-for-plugins.sh index 9e84882..34d2dd0 100755 --- a/wait-for-plugins.sh +++ b/wait-for-plugins.sh @@ -21,8 +21,8 @@ fi # Run Backstage with default + optional config overrides node packages/backend --no-node-snapshot \ - --config "$DEFAULT_APP_CONFIG" \ + --config "app-config.yaml" \ --config app-config.example.yaml \ --config app-config.example.production.yaml \ --config "$DYNAMIC_PLUGINS_CONFIG" \ - $EXTRA_CLI_ARGS + --config "$DEFAULT_APP_CONFIG" "$EXTRA_CLI_ARGS" From 39d8ebf578f09c78106a2ceb7feae53de33c2272 Mon Sep 17 00:00:00 2001 From: my-name Date: Mon, 31 Mar 2025 14:42:31 +0100 Subject: [PATCH 09/23] Update: Ignore any *.local.yaml files (and any *-credentials.yaml) similar to the rhdh repo. Also Ignore dynamic-plugins.override.yaml and extra-files/* BUT Keep legacy files (e.g., dynamic-plugins.yaml, github-app-credentials.example.yaml) ignored for backward compatibility. Signed-off-by: my-name --- .gitignore | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/.gitignore b/.gitignore index 188fa93..ac6c1ce 100644 --- a/.gitignore +++ b/.gitignore @@ -2,9 +2,15 @@ configs/github-app-credentials.yaml /tmp -# Ignore user-specific config overrides -configs/app-config/app-config.local.yaml -configs/dynamic-plugins/dynamic-plugins.override.yaml -configs/extra-files/* -!configs/extra-files/github-app-credentials.example.yaml -.qodo +# User-specific local configuration files +*.local.yaml +*-credentials.yaml +/configs/dynamic-plugins/dynamic-plugins.override.yaml + +# Extra-files +/configs/extra-files/* +!/configs/extra-files/github-app-credentials.example.yaml + +# Kept for backward compatibility, but now Git-ignored +/configs/dynamic-plugins.yaml +/configs/github-app-credentials.example.yaml \ No newline at end of file From 2cbd8ecffad6afec27cafc4c127e3c3538bb73d5 Mon Sep 17 00:00:00 2001 From: my-name Date: Mon, 31 Mar 2025 14:45:53 +0100 Subject: [PATCH 10/23] delete: dynamic-plugins.local.yaml because users would provide a dynamic-plugins.override.yaml file instead. So dynamic-plugins.local.yaml is not needed. Signed-off-by: my-name --- .../dynamic-plugins.local.yaml | 80 ------------------- 1 file changed, 80 deletions(-) delete mode 100644 configs/dynamic-plugins/dynamic-plugins.local.yaml diff --git a/configs/dynamic-plugins/dynamic-plugins.local.yaml b/configs/dynamic-plugins/dynamic-plugins.local.yaml deleted file mode 100644 index 30e9044..0000000 --- a/configs/dynamic-plugins/dynamic-plugins.local.yaml +++ /dev/null @@ -1,80 +0,0 @@ -includes: - - dynamic-plugins.default.yaml -plugins: [] - - # EXAMPLES: - # loading plugin from host directory - # - package: ./local-plugins/todo - # disabled: false - # pluginConfig: - # dynamicPlugins: - # frontend: - # backstage-community.plugin-todo: - # mountPoints: - # - mountPoint: entity.page.todo/cards - # importName: EntityTodoContent - # entityTabs: - # - path: /todo - # title: Todo - # mountPoint: entity.page.todo - - # loading image from container image - # - package: oci://docker.io/tomaskral/simple-chat:v0.0.1!internal-backstage-plugin-simple-chat - # disabled: false - # pluginConfig: - # dynamicPlugins: - # frontend: - # internal.backstage-plugin-simple-chat: - # appIcons: - # - name: chatIcon - # importName: ChatIcon - # dynamicRoutes: - # - path: /simple-chat - # importName: SimpleChatPage - # menuItem: - # text: 'Simple Chat' - # icon: chatIcon - - # # loading image from tarball URL - # - disabled: false - # package: >- - # https://github.com/redhat-developer/rhdh-plugin-export-backstage-community-plugins/releases/download/v1.2.0/backstage-community-plugin-tech-insights-dynamic-0.3.28.tgz - # integrity: sha512-cNHXSwPa5fOi2BcNVSe7tfdLyM0JY988CE5t+P9p/XlboP1QpQbMcLBmqPrlXZdpedAyp81Zz3yPQYGnPuy9ww== - # pluginConfig: - # dynamicPlugins: - # techInsights: - # factRetrievers: - # entityOwnershipFactRetriever: - # cadence: '*/15 * * * *' - # lifecycle: { timeToLive: { weeks: 2 } } - # entityMetadataFactRetriever: - # cadence: '*/15 * * * *' - # lifecycle: { timeToLive: { weeks: 2 } } - # techdocsFactRetriever: - # cadence: '*/15 * * * *' - # lifecycle: { timeToLive: { weeks: 2 } } - # apiDefinitionFactRetriever: - # cadence: '*/15 * * * *' - # lifecycle: { timeToLive: { weeks: 2 } } - - # # loading plugin from directory inside the RHDH container - # - package: ./dynamic-plugins/dist/janus-idp-backstage-plugin-rbac - # disabled: true - # pluginConfig: - # dynamicPlugins: - # frontend: - # janus-idp.backstage-plugin-rbac: - # mountPoints: - # - mountPoint: admin.page.rbac/cards - # module: RbacPlugin - # importName: RbacPage - # config: - # layout: - # gridColumn: "1 / -1" - # width: 100vw - # props: - # useHeader: false - # dynamicRoutes: - # - path: /admin/rbac - # module: RbacPlugin - # importName: RbacPage From 2ffc9f681efc6ce290da7ab78ad506e7fb1bc072 Mon Sep 17 00:00:00 2001 From: my-name Date: Mon, 31 Mar 2025 15:57:58 +0100 Subject: [PATCH 11/23] Updates: Keep 'configs/extra-files/github-app-credentials.example.yaml' but also copy it to 'configs/github-app-credentials.example.yaml' for backward compatibility and made sure that 'configs/github-app-credentials.example.yaml' is git-ignored. MOREOVER Keep 'configs/dynamic-plugins/dynamic-plugins.yaml' but also copy it to 'configs/dynamic-plugins.yaml', for backward compatibility and made sure that configs/dynamic-plugins.yaml is git-ignored. MOREOVER keep 'configs/app-config/app-config.yaml' and copy it to configs/app-config.local.yaml, for backward compatibility? Just make sure that configs/app-config.local.yaml is git-ignored. Signed-off-by: my-name --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ac6c1ce..c2ba920 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,6 @@ configs/github-app-credentials.yaml !/configs/extra-files/github-app-credentials.example.yaml # Kept for backward compatibility, but now Git-ignored +/configs/app-config.local.yaml /configs/dynamic-plugins.yaml /configs/github-app-credentials.example.yaml \ No newline at end of file From abcd4a073ad6ca12fd1e48a2415792b1963d6fdc Mon Sep 17 00:00:00 2001 From: my-name Date: Mon, 31 Mar 2025 16:06:39 +0100 Subject: [PATCH 12/23] Update: Add an elif in a backward compatible way so we dont break existing users nor create any Git conflicts. Signed-off-by: my-name --- fixes.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fixes.sh b/fixes.sh index fbf1245..15b5b9c 100755 --- a/fixes.sh +++ b/fixes.sh @@ -27,6 +27,9 @@ LINK_TARGET="/opt/app-root/src/dynamic-plugins.yaml" if [ -f "$DYNAMIC_PLUGINS_OVERRIDE" ]; then echo "Using dynamic-plugins.override.yaml" ln -sf "$DYNAMIC_PLUGINS_OVERRIDE" "$LINK_TARGET" +elif [ -f "/opt/app-root/src/configs/dynamic-plugins.yaml" ]; then + echo "[warn] Using legacy dynamic-plugins.yaml. This method is deprecated. You can override the dynamic plugins configuration by renaming your file into configs/dynamic-plugins/dynamic-plugins.override.yaml" + ln -sf "/opt/app-root/src/configs/dynamic-plugins.yaml" "$LINK_TARGET" else echo "Using default dynamic-plugins.yaml" ln -sf "$DYNAMIC_PLUGINS_DEFAULT" "$LINK_TARGET" From c491f48b589bbf993b13ba1554d03e5a498e95e9 Mon Sep 17 00:00:00 2001 From: my-name Date: Mon, 31 Mar 2025 16:08:52 +0100 Subject: [PATCH 13/23] Update: Also add another elif in a backward compatible way so we dont break existing users nor create any Git conflicts. Signed-off-by: my-name --- wait-for-plugins.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wait-for-plugins.sh b/wait-for-plugins.sh index 34d2dd0..a8f7ba7 100755 --- a/wait-for-plugins.sh +++ b/wait-for-plugins.sh @@ -17,6 +17,9 @@ EXTRA_CLI_ARGS="" if [ -f "$USER_APP_CONFIG" ]; then echo "Using user app-config.local.yaml" EXTRA_CLI_ARGS="--config $USER_APP_CONFIG" +elif [ -f "configs/app-config.local.yaml" ]; then + echo "[warn] Using legacy app-config.local.yaml. This method is deprecated. You should move your local app-config file under configs/app-config/app-config.local.yaml and extra files under configs/extra-files." + EXTRA_CLI_ARGS="--config configs/app-config.local.yaml" fi # Run Backstage with default + optional config overrides From 3393f44f951c110694530b1a9b6e36b250cb1115 Mon Sep 17 00:00:00 2001 From: my-name Date: Tue, 15 Apr 2025 10:56:29 +0100 Subject: [PATCH 14/23] Update README to mention new path AND mention that the configs/dynamic-plugins.yaml can be loaded if present as well. Signed-off-by: my-name --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 252aaf7..ff5b40a 100644 --- a/README.md +++ b/README.md @@ -88,14 +88,22 @@ podman-compose stop rhdh && podman-compose start rhdh ## Loading dynamic plugins from a local directory -During boot the `install-dynamic-plugins` container reads the contents of the `configs/dynamic-plugins.yaml` file and activates, configures, or downloads any plugins contained in that file. In addition, the `local-plugins` directory is mounted into the `install-dynamic-plugins` container on the path `/opt/app-root/src/local-plugins`. Any plugins in that location can also be activated and configured in the same way (without downloading). +During boot, the `install-dynamic-plugins` container reads the contents of the plugin configuration file and activates, configures, or downloads any plugins listed. RHDH Local supports two ways of specifying dynamic plugin configuration: -You can use the `local-plugins` folder install dynamic plugins directly from your local machine using the following steps: +1. Default path (tracked by Git): `configs/dynamic-plugins/dynamic-plugins.yaml` + +1. User override path (Git-ignored): `configs/dynamic-plugins/dynamic-plugins.override.yaml` If present, this file will automatically override the default and be used by the `install-dynamic-plugins` container. + +In addition, the `local-plugins` directory is mounted into the `install-dynamic-plugins` container at `/opt/app-root/src/local-plugins`. Any plugins placed there can be activated/configured the same way (without downloading). + +To load dynamic plugins from your local machine: 1. Copy the dynamic plugin binary file into the `local-plugins` directory. -2. Make sure that the permissions are set to allow container to read files (quick and dirty solution is `chmod -R 777 local-plugins`) -3. Configure your dynamic plugin in `dynamic-plugins.yaml`. See commented out examples in that file for examples. -4. See [Changing Your Configuration](#changing-your-configuration) section for more information about how to change and load new configuration. +2. Make sure permissions allow the container to read the files (e.g. `chmod -R 777 local-plugins` for quick testing). +3. Configure your plugin in one of the supported config files: + - Prefer `configs/dynamic-plugins/dynamic-plugins.override.yaml` for local user overrides. + - If no override file is present, `configs/dynamic-plugins/dynamic-plugins.yaml` will be used. +4. See [Changing Your Configuration](#changing-your-configuration) for more on updating and reloading configs. ## Changing The Container Image From 66d795c5dd1638fa71adb7a20c01ff19b8113020 Mon Sep 17 00:00:00 2001 From: my-name Date: Tue, 15 Apr 2025 12:07:38 +0100 Subject: [PATCH 15/23] fixup(config): Remove quotes around because this allows the shell to expand the string into proper CLI flags instead of passing it as one long argument. Signed-off-by: my-name --- wait-for-plugins.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/wait-for-plugins.sh b/wait-for-plugins.sh index a8f7ba7..770cabf 100755 --- a/wait-for-plugins.sh +++ b/wait-for-plugins.sh @@ -28,4 +28,4 @@ node packages/backend --no-node-snapshot \ --config app-config.example.yaml \ --config app-config.example.production.yaml \ --config "$DYNAMIC_PLUGINS_CONFIG" \ - --config "$DEFAULT_APP_CONFIG" "$EXTRA_CLI_ARGS" + --config "$DEFAULT_APP_CONFIG" $EXTRA_CLI_ARGS From c5f93bee56f886ef8a29e93df94a2c7558ad409f Mon Sep 17 00:00:00 2001 From: my-name Date: Wed, 16 Apr 2025 13:12:20 +0100 Subject: [PATCH 16/23] Add comments on config files To make sure that even if someone accidentally opens this file they see that they might be on a wrong place Signed-off-by: my-name --- configs/app-config/app-config.yaml | 1 + configs/dynamic-plugins/dynamic-plugins.yaml | 1 + 2 files changed, 2 insertions(+) diff --git a/configs/app-config/app-config.yaml b/configs/app-config/app-config.yaml index dc6cc6b..ba2f3e2 100644 --- a/configs/app-config/app-config.yaml +++ b/configs/app-config/app-config.yaml @@ -1,3 +1,4 @@ +# This is the default rhdh-local config, and any user configuration should be added app-config.local.yaml instead auth: environment: development providers: diff --git a/configs/dynamic-plugins/dynamic-plugins.yaml b/configs/dynamic-plugins/dynamic-plugins.yaml index 30e9044..55397b0 100644 --- a/configs/dynamic-plugins/dynamic-plugins.yaml +++ b/configs/dynamic-plugins/dynamic-plugins.yaml @@ -1,3 +1,4 @@ +# This is the default dynamic plugins config, and any user configuration should be added dynamic-plugins.override.yaml instead includes: - dynamic-plugins.default.yaml plugins: [] From 2f3f87aa66c4d985552f39dd146ad6eb62b45c13 Mon Sep 17 00:00:00 2001 From: my-name Date: Wed, 16 Apr 2025 14:45:44 +0100 Subject: [PATCH 17/23] Update Read me to improve onboarding Signed-off-by: my-name --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ff5b40a..1ad7742 100644 --- a/README.md +++ b/README.md @@ -48,11 +48,21 @@ To use RHDH Local you'll need a few things: `configs/app-config/app-config.local.yaml` - Add your plugin config overrides to: - `configs/dynamic-plugins/dynamic-plugins.override.yaml` + `configs/dynamic-plugins/dynamic-plugins.override.yaml` + > The override file must start with: + > ```yaml + > includes: + > - dynamic-plugins.default.yaml + > ``` + > This ensures the base plugin list is preserved and extended, rather than replaced. - Add any extra files (like GitHub credentials) to: `configs/extra-files/` (already Git-ignored) + You can also look at the provided example files for guidance: + - [`configs/app-config/app-config.local.example.yaml`](configs/app-config/app-config.local.example.yaml) + - [`configs/dynamic-plugins/dynamic-plugins.override.example.yaml`](configs/dynamic-plugins/dynamic-plugins.override.example.yaml) + If present, these files will be automatically loaded by the system on startup. If you need features that fetch files from GitHub you should configure `integrations.github`. From 141954185ee2a49c98a6bd9a8f792e338a9509ce Mon Sep 17 00:00:00 2001 From: my-name Date: Wed, 16 Apr 2025 15:24:08 +0100 Subject: [PATCH 18/23] Cleanup Signed-off-by: my-name --- README.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/README.md b/README.md index 1ad7742..05dc57f 100644 --- a/README.md +++ b/README.md @@ -59,10 +59,6 @@ To use RHDH Local you'll need a few things: - Add any extra files (like GitHub credentials) to: `configs/extra-files/` (already Git-ignored) - You can also look at the provided example files for guidance: - - [`configs/app-config/app-config.local.example.yaml`](configs/app-config/app-config.local.example.yaml) - - [`configs/dynamic-plugins/dynamic-plugins.override.example.yaml`](configs/dynamic-plugins/dynamic-plugins.override.example.yaml) - If present, these files will be automatically loaded by the system on startup. If you need features that fetch files from GitHub you should configure `integrations.github`. From 3576b661f7113e5c7bd201a5c1ad36c2db84b155 Mon Sep 17 00:00:00 2001 From: my-name Date: Thu, 24 Apr 2025 12:04:42 +0100 Subject: [PATCH 19/23] update(README): Users can still copy existing default files and rename the copy if they wish. Signed-off-by: my-name --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 05dc57f..9aa6214 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ To use RHDH Local you'll need a few things: 1. (Optional) Create local configuration overrides. - RHDH Local now supports user-specific configuration overrides using a structured `configs/` directory. You do not need to copy or modify default files. However, if you want to customize your setup: + RHDH Local supports user-specific configuration overrides using a structured `configs/` directory. You do not need to modify default files. However, if you want to customize your setup: - Add your app config overrides to: `configs/app-config/app-config.local.yaml` From a2df71dca9f605589f48f8f384e15bc68103ca7a Mon Sep 17 00:00:00 2001 From: my-name Date: Thu, 24 Apr 2025 12:17:49 +0100 Subject: [PATCH 20/23] update README Signed-off-by: my-name --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 392ad32..6697505 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ To use RHDH Local you'll need a few things: > This ensures the base plugin list is preserved and extended, rather than replaced. - Add any extra files (like GitHub credentials) to: - `configs/extra-files/` (already Git-ignored) + `configs/extra-files/` If present, these files will be automatically loaded by the system on startup. @@ -91,9 +91,9 @@ podman-compose stop rhdh && podman-compose start rhdh During boot, the `install-dynamic-plugins` container reads the contents of the plugin configuration file and activates, configures, or downloads any plugins listed. RHDH Local supports two ways of specifying dynamic plugin configuration: -1. Default path (tracked by Git): `configs/dynamic-plugins/dynamic-plugins.yaml` +1. Default path: `configs/dynamic-plugins/dynamic-plugins.yaml` -1. User override path (Git-ignored): `configs/dynamic-plugins/dynamic-plugins.override.yaml` If present, this file will automatically override the default and be used by the `install-dynamic-plugins` container. +1. User override path: `configs/dynamic-plugins/dynamic-plugins.override.yaml` or `configs/dynamic-plugins.yaml` If present, this file will automatically override the default and be used by the `install-dynamic-plugins` container. `configs/dynamic-plugins/dynamic-plugins.override.yaml` takes precedence over `configs/dynamic-plugins.yaml`. In addition, the `local-plugins` directory is mounted into the `install-dynamic-plugins` container at `/opt/app-root/src/local-plugins`. Any plugins placed there can be activated/configured the same way (without downloading). From b0db05087a59901d66a5a0c8966efaa252e5e8b0 Mon Sep 17 00:00:00 2001 From: my-name Date: Thu, 24 Apr 2025 15:58:41 +0100 Subject: [PATCH 21/23] Update(docs): add example config files for app-config and dynamic plugins Signed-off-by: my-name --- README.md | 12 ++++++++---- configs/app-config/app-config.local.example.yaml | 12 ++++++++++++ .../dynamic-plugins.override.example.yaml | 13 +++++++++++++ 3 files changed, 33 insertions(+), 4 deletions(-) create mode 100644 configs/app-config/app-config.local.example.yaml create mode 100644 configs/dynamic-plugins/dynamic-plugins.override.example.yaml diff --git a/README.md b/README.md index 6697505..9571af2 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,13 @@ To use RHDH Local you'll need a few things: RHDH Local supports user-specific configuration overrides using a structured `configs/` directory. You do not need to modify default files. However, if you want to customize your setup: - - Add your app config overrides to: - `configs/app-config/app-config.local.yaml` + - Add your app config overrides to: `configs/app-config/app-config.local.yaml` + > You can use the included `.example.yaml` files to get started quickly: + > + > ```sh + > cp configs/app-config/app-config.local.example.yaml configs/app-config/app-config.local.yaml + > cp configs/dynamic-plugins/dynamic-plugins.override.example.yaml configs/dynamic-plugins/dynamic-plugins.override.yaml + > ``` - Add your plugin config overrides to: `configs/dynamic-plugins/dynamic-plugins.override.yaml` @@ -51,8 +56,7 @@ To use RHDH Local you'll need a few things: > ``` > This ensures the base plugin list is preserved and extended, rather than replaced. - - Add any extra files (like GitHub credentials) to: - `configs/extra-files/` + - Add any extra files (like GitHub credentials) to: `configs/extra-files/` If present, these files will be automatically loaded by the system on startup. diff --git a/configs/app-config/app-config.local.example.yaml b/configs/app-config/app-config.local.example.yaml new file mode 100644 index 0000000..3fa61ec --- /dev/null +++ b/configs/app-config/app-config.local.example.yaml @@ -0,0 +1,12 @@ +# Copy this file to app-config.local.yaml to override default app settings. +# Example with GitHub integration using credentials from extra-files. + +integrations: + github: + - host: github.com + apps: + - appId: ${GITHUB_APP_APP_ID} + clientId: ${GITHUB_APP_CLIENT_ID} + clientSecret: ${GITHUB_APP_CLIENT_SECRET} + webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} + privateKey: ${GITHUB_APP_PRIVATE_KEY} diff --git a/configs/dynamic-plugins/dynamic-plugins.override.example.yaml b/configs/dynamic-plugins/dynamic-plugins.override.example.yaml new file mode 100644 index 0000000..6ae2ff3 --- /dev/null +++ b/configs/dynamic-plugins/dynamic-plugins.override.example.yaml @@ -0,0 +1,13 @@ +# Example dynamic plugin override config. +# Copy to dynamic-plugins.override.yaml to activate local plugins. + +includes: + - dynamic-plugins.default.yaml + +# Below you can add custom dynamic plugins, including local ones. +dynamicPlugins: + - package: local-plugins/example-plugin + disabled: false + pluginConfig: + # Optional: Configuration passed to your plugin + message: "Hello from local plugin" From 150ec8f417942d105f810cd42878f010774abe24 Mon Sep 17 00:00:00 2001 From: my-name Date: Thu, 24 Apr 2025 17:29:48 +0100 Subject: [PATCH 22/23] refactor: update example configs to use include-based GitHub App credentials Signed-off-by: my-name --- .../app-config/app-config.local.example.yaml | 8 ++----- .../github-app-credentials.example.yaml | 22 ++++++++++--------- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/configs/app-config/app-config.local.example.yaml b/configs/app-config/app-config.local.example.yaml index 3fa61ec..02269f9 100644 --- a/configs/app-config/app-config.local.example.yaml +++ b/configs/app-config/app-config.local.example.yaml @@ -1,12 +1,8 @@ # Copy this file to app-config.local.yaml to override default app settings. -# Example with GitHub integration using credentials from extra-files. +# Example with GitHub integration referencing external secrets file. integrations: github: - host: github.com apps: - - appId: ${GITHUB_APP_APP_ID} - clientId: ${GITHUB_APP_CLIENT_ID} - clientSecret: ${GITHUB_APP_CLIENT_SECRET} - webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} - privateKey: ${GITHUB_APP_PRIVATE_KEY} + - $include: ../extra-files/github-app-credentials.yaml diff --git a/configs/extra-files/github-app-credentials.example.yaml b/configs/extra-files/github-app-credentials.example.yaml index 3d59e34..6775ca6 100644 --- a/configs/extra-files/github-app-credentials.example.yaml +++ b/configs/extra-files/github-app-credentials.example.yaml @@ -1,11 +1,13 @@ -# github-app-credentials.yaml can be created using the following command: -# npx @backstage/cli create-github-app -# and renaming the file to github-app-credentials.yaml or changing the include path in app-config.local.yaml +# This file defines GitHub App credentials used by Backstage/RHDH. +# It is included from app-config.local.yaml using: +# $include: ../extra-files/github-app-credentials.yaml +# +# You can generate the values using: +# npx @backstage/cli create-github-app +# Then rename this file to github-app-credentials.yaml -appId: -webhookUrl: -clientId: -clientSecret: -webhookSecret: -privateKey: - \ No newline at end of file +appId: ${GITHUB_APP_APP_ID} +clientId: ${GITHUB_APP_CLIENT_ID} +clientSecret: ${GITHUB_APP_CLIENT_SECRET} +webhookSecret: ${GITHUB_APP_WEBHOOK_SECRET} +privateKey: ${GITHUB_APP_PRIVATE_KEY} From eab4929dcaa358d99127a00c7cea529ae4fb680c Mon Sep 17 00:00:00 2001 From: my-name Date: Fri, 25 Apr 2025 12:40:16 +0100 Subject: [PATCH 23/23] chore(format): Ensure that the format in dynamic-plugins.yaml and dynamic-plugins.override.yaml Signed-off-by: my-name --- configs/dynamic-plugins/dynamic-plugins.override.example.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configs/dynamic-plugins/dynamic-plugins.override.example.yaml b/configs/dynamic-plugins/dynamic-plugins.override.example.yaml index 6ae2ff3..eff463d 100644 --- a/configs/dynamic-plugins/dynamic-plugins.override.example.yaml +++ b/configs/dynamic-plugins/dynamic-plugins.override.example.yaml @@ -5,7 +5,7 @@ includes: - dynamic-plugins.default.yaml # Below you can add custom dynamic plugins, including local ones. -dynamicPlugins: +plugins: - package: local-plugins/example-plugin disabled: false pluginConfig: