Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions workspaces/extensions/.changeset/khaki-points-mate.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@red-hat-developer-hub/backstage-plugin-catalog-backend-module-extensions': minor
'@red-hat-developer-hub/backstage-plugin-extensions-common': minor
---

Add catalog source annotations to entities
44 changes: 16 additions & 28 deletions workspaces/extensions/app-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ backend:
# See https://backstage.io/docs/auth/service-to-service-auth for
# information on the format
auth:
dangerouslyDisableDefaultAuthPolicy: true
# keys:
# - secret: ${BACKEND_SECRET}
baseUrl: http://localhost:7007
Expand Down Expand Up @@ -101,37 +100,25 @@ catalog:
pullRequestBranchName: backstage-integration
rules:
- allow:
[
Component,
System,
API,
Resource,
Plugin,
PluginCollection,
Package,
Location,
]
- Component
- System
- API
- Resource
- Plugin
- PluginCollection
- Package
- Location

locations:
- type: file
target: ../../catalog-info.yaml
rules:
- allow: [Component]
# Guest user and group
- type: file
target: ../../examples/all-orgs.yaml
rules:
- allow: [Group]
- type: file
target: ../../examples/all-plugins.yaml
rules:
- allow: [Plugin]
- type: file
target: ../../examples/all-collections.yaml
rules:
- allow: [PluginCollection]
- type: file
target: ../../examples/all-packages.yaml
target: ../../org.yaml
rules:
- allow: [Package]
- allow: [User, Group]

kubernetes:
# see https://backstage.io/docs/features/kubernetes/configuration for kubernetes configuration options
Expand All @@ -151,10 +138,11 @@ permission:
- name: user:development/guest

extensions:
# directory: ../../examples # YAML files are in the examples directory
### Example for how to enable installation to a file.
# YAML files are in the examples directory
directory: ../../examples

# Example for how to enable installation to a file.
# installation:
# enabled: true
# saveToSingleFile:
# file: ${EXTENSIONS_PLUGIN_CONFIG}
dangerouslyAllowSignInWithoutUserInCatalog: true
15 changes: 15 additions & 0 deletions workspaces/extensions/docs/catalog/plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,21 @@ spec:

## Annotations

### Catalog source

Automatically set by the `BaseEntityProvider` to identify which catalog image each entity came from. The value is derived from the on-disk directory layout produced by `install-dynamic-plugins`:

- Entities under the primary `catalog-entities/` tree get `"primary"`
- Entities under `extra/<name>/catalog-entities/` get `<name>` as the source (matching the name from `EXTRA_CATALOG_INDEX_IMAGES`)

This annotation is always set and should not be manually specified in YAML files.

```yaml
metadata:
annotations:
extensions.backstage.io/catalog-source: 'primary'
```

### Support type for Core and Community plugins

```yaml
Expand Down
4 changes: 2 additions & 2 deletions workspaces/extensions/e2e-tests/extensions.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,14 +108,14 @@ test.describe('Admin > Extensions', () => {
await extensions.selectDropdown(translations.search.author);
await extensions.toggleOption('Red Hat');
await sharedPage.keyboard.press(`Escape`);
await extensionHelper.verifyHeading('APIs with 3scale');
await extensionHelper.verifyHeading('Pipelines with Tekton');
await extensionHelper.verifyTextInLocator(
'',
`${translations.metadata.by} Red Hat`,
true,
);

await extensionHelper.clickHeading('APIs with 3scale');
await extensionHelper.clickHeading('Pipelines with Tekton');
await extensionHelper.verifyTableHeadingAndRows([
translations.table.packageName,
translations.table.version,
Expand Down
10 changes: 0 additions & 10 deletions workspaces/extensions/examples/all-collections.yaml

This file was deleted.

9 changes: 0 additions & 9 deletions workspaces/extensions/examples/all-orgs.yaml

This file was deleted.

18 changes: 0 additions & 18 deletions workspaces/extensions/examples/all-packages.yaml

This file was deleted.

32 changes: 0 additions & 32 deletions workspaces/extensions/examples/all-plugins.yaml

This file was deleted.

8 changes: 0 additions & 8 deletions workspaces/extensions/examples/orgs/redhat.yaml

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

28 changes: 28 additions & 0 deletions workspaces/extensions/org.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-user
apiVersion: backstage.io/v1alpha1
kind: User
metadata:
namespace: development
name: guest
spec:
memberOf: [guests]
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-group
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
namespace: development
name: guests
spec:
type: team
children: []
---
# https://backstage.io/docs/features/software-catalog/descriptor-format#kind-group
apiVersion: backstage.io/v1alpha1
kind: Group
metadata:
name: redhat
spec:
type: team
children: []
1 change: 1 addition & 0 deletions workspaces/extensions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
},
"devDependencies": {
"@backstage/cli": "^0.36.3",
"@backstage/cli-defaults": "^0.1.3",
"@backstage/e2e-test-utils": "^0.1.2",
"@backstage/repo-tools": "^0.17.3",
"@changesets/cli": "^2.27.1",
Expand Down
6 changes: 5 additions & 1 deletion workspaces/extensions/playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@ export default defineConfig({
: [
{
command: startCommand,
port: 3000,
reuseExistingServer: false,
cwd: __dirname,
wait: {
// wait for this message and expect 10+ loaded plugins.
stdout:
/extensions-plugin-provider applied [1-9]\d+ entities to the catalog/,
},
},
],

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,33 @@ extensions:
directory: /path/to/custom/extensions
```

### Multi-source catalog layout

When the `install-dynamic-plugins` init container is configured with `EXTRA_CATALOG_INDEX_IMAGES`, it extracts additional catalog entities into subdirectories under `extra/`:

```
<extensionsDir>/
catalog-entities/ # primary source
plugins/
plugin-a.yaml
extra/
community/ # extra source "community"
catalog-entities/
plugins/
plugin-b.yaml
partner/ # extra source "partner"
catalog-entities/
plugins/
plugin-c.yaml
```

The provider reads all YAML files recursively from the extensions directory and automatically sets the `extensions.backstage.io/catalog-source` annotation on each entity based on where it was found:

- Entities from the primary `catalog-entities/` tree get `catalog-source: "primary"`
- Entities from `extra/<name>/catalog-entities/` get `catalog-source: "<name>"`

This allows the Extensions UI to identify which catalog each plugin came from (e.g. Red Hat, Community, partner).

### Collision behavior

When multiple YAML sources define the same entity identity (`kind:namespace/name`), the provider handles collisions as follows:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ export abstract class BaseEntityProvider<T extends Entity>
);
// (undocumented)
connect(connection: EntityProviderConnection): Promise<void>;
static readonly DEFAULT_CATALOG_SOURCE = 'primary';
static deriveCatalogSource(filePath: string, extensionsRoot: string): string;
// (undocumented)
getEntities(allEntities: JsonFileData<T>[]): T[];
getEntities(allEntities: JsonFileData<T>[], extensionsRoot?: string): T[];
// (undocumented)
abstract getKind(): string;
// (undocumented)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,11 @@ export const catalogModuleExtensions = createBackendModule({
}) {
logger.info('Adding Extensions providers and processors to catalog...');
const taskRunner = scheduler.createScheduledTaskRunner({
frequency: { minutes: 30 },
frequency: { hours: 1 },
timeout: { minutes: 10 },
});
const delayedTaskRunner = scheduler.createScheduledTaskRunner({
frequency: { minutes: 30 },
frequency: { hours: 1 },
timeout: { minutes: 10 },
initialDelay: { seconds: 20 },
});
Expand Down
Loading
Loading