Skip to content

Commit

Permalink
feat(marketplace): add backend, common and frontend plugin scaffold
Browse files Browse the repository at this point in the history
Signed-off-by: Christoph Jerolimov <[email protected]>
  • Loading branch information
christoph-jerolimov committed Nov 7, 2024
1 parent dea7f02 commit fd74ca4
Show file tree
Hide file tree
Showing 41 changed files with 2,005 additions and 15 deletions.
1 change: 1 addition & 0 deletions workspaces/marketplace/packages/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
"@backstage/theme": "^0.6.0",
"@material-ui/core": "^4.12.2",
"@material-ui/icons": "^4.9.1",
"@red-hat-developer-hub/backstage-plugin-marketplace": "workspace:^",
"react": "^18.0.2",
"react-dom": "^18.0.2",
"react-router": "^6.3.0",
Expand Down
2 changes: 2 additions & 0 deletions workspaces/marketplace/packages/app/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { AppRouter, FlatRoutes } from '@backstage/core-app-api';
import { CatalogGraphPage } from '@backstage/plugin-catalog-graph';
import { RequirePermission } from '@backstage/plugin-permission-react';
import { catalogEntityCreatePermission } from '@backstage/plugin-catalog-common/alpha';
import { MarketplacePage } from '@red-hat-developer-hub/backstage-plugin-marketplace';

const app = createApp({
apis,
Expand Down Expand Up @@ -110,6 +111,7 @@ const routes = (
</Route>
<Route path="/settings" element={<UserSettingsPage />} />
<Route path="/catalog-graph" element={<CatalogGraphPage />} />
<Route path="/marketplace" element={<MarketplacePage />} />
</FlatRoutes>
);

Expand Down
1 change: 1 addition & 0 deletions workspaces/marketplace/packages/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"@backstage/plugin-search-backend-module-techdocs": "^0.3.0",
"@backstage/plugin-search-backend-node": "^1.3.3",
"@backstage/plugin-techdocs-backend": "^1.11.0",
"@red-hat-developer-hub/backstage-plugin-marketplace-backend": "workspace:^",
"app": "link:../app",
"better-sqlite3": "^9.0.0",
"node-gyp": "^10.0.0",
Expand Down
5 changes: 5 additions & 0 deletions workspaces/marketplace/packages/backend/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,4 +59,9 @@ backend.add(import('@backstage/plugin-search-backend-module-techdocs/alpha'));
// kubernetes
backend.add(import('@backstage/plugin-kubernetes-backend/alpha'));

// marketplace
backend.add(
import('@red-hat-developer-hub/backstage-plugin-marketplace-backend'),
);

backend.start();
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
30 changes: 30 additions & 0 deletions workspaces/marketplace/plugins/marketplace-backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# marketplace

This plugin backend was templated using the Backstage CLI. You should replace this text with a description of your plugin backend.

## Installation

This plugin is installed via the `@red-hat-developer-hub/backstage-plugin-marketplace-backend` package. To install it to your backend package, run the following command:

```bash
# From your root directory
yarn --cwd packages/backend add @red-hat-developer-hub/backstage-plugin-marketplace-backend
```

Then add the plugin to your backend in `packages/backend/src/index.ts`:

```ts
const backend = createBackend();
// ...
backend.add(
import('@red-hat-developer-hub/backstage-plugin-marketplace-backend'),
);
```

## Development

This plugin backend can be started in a standalone mode from directly in this
package with `yarn start`. It is a limited setup that is most convenient when
developing the plugin backend itself.

If you want to run the entire project, including the frontend, run `yarn dev` from the root directory.
13 changes: 13 additions & 0 deletions workspaces/marketplace/plugins/marketplace-backend/api-report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## API Report File for "@red-hat-developer-hub/backstage-plugin-marketplace-backend"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts
import { BackendFeature } from '@backstage/backend-plugin-api';

// @public
const marketplacePlugin: BackendFeature;
export default marketplacePlugin;

// (No @packageDocumentation comment for this package)
```
75 changes: 75 additions & 0 deletions workspaces/marketplace/plugins/marketplace-backend/dev/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { createBackend } from '@backstage/backend-defaults';
import { mockServices } from '@backstage/backend-test-utils';
import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils';

// TEMPLATE NOTE:
// This is the development setup for your plugin that wires up a
// minimal backend that can use both real and mocked plugins and services.
//
// Start up the backend by running `yarn start` in the package directory.
// Once it's up and running, try out the following requests:
//
// Create a new todo item, standalone or for the sample component:
//
// curl http://localhost:7007/api/marketplace/todos -H 'Content-Type: application/json' -d '{"title": "My Todo"}'
// curl http://localhost:7007/api/marketplace/todos -H 'Content-Type: application/json' -d '{"title": "My Todo", "entityRef": "component:default/sample"}'
//
// List TODOs:
//
// curl http://localhost:7007/api/marketplace/todos
//
// Explicitly make an unauthenticated request, or with service auth:
//
// curl http://localhost:7007/api/marketplace/todos -H 'Authorization: Bearer mock-none-token'
// curl http://localhost:7007/api/marketplace/todos -H 'Authorization: Bearer mock-service-token'

const backend = createBackend();

// TEMPLATE NOTE:
// Mocking the auth and httpAuth service allows you to call your plugin API without
// having to authenticate.
//
// If you want to use real auth, you can install the following instead:
// backend.add(import('@backstage/plugin-auth-backend'));
// backend.add(import('@backstage/plugin-auth-backend-module-guest-provider'));
backend.add(mockServices.auth.factory());
backend.add(mockServices.httpAuth.factory());

// TEMPLATE NOTE:
// Rather than using a real catalog you can use a mock with a fixed set of entities.
backend.add(
catalogServiceMock.factory({
entities: [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'sample',
title: 'Sample Component',
},
spec: {
type: 'service',
},
},
],
}),
);

backend.add(import('../src'));

backend.start();
57 changes: 57 additions & 0 deletions workspaces/marketplace/plugins/marketplace-backend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"name": "@red-hat-developer-hub/backstage-plugin-marketplace-backend",
"version": "0.1.0",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
"private": true,
"publishConfig": {
"access": "public",
"main": "dist/index.cjs.js",
"types": "dist/index.d.ts"
},
"repository": {
"type": "git",
"url": "https://github.com/redhat-developer/rhdh-plugins",
"directory": "workspaces/marketplace/plugins/marketplace-backend"
},
"backstage": {
"role": "backend-plugin",
"pluginId": "marketplace",
"pluginPackages": [
"@red-hat-developer-hub/backstage-plugin-marketplace",
"@red-hat-developer-hub/backstage-plugin-marketplace-backend",
"@red-hat-developer-hub/backstage-plugin-marketplace-common"
]
},
"scripts": {
"start": "backstage-cli package start",
"build": "backstage-cli package build",
"lint": "backstage-cli package lint",
"test": "backstage-cli package test",
"clean": "backstage-cli package clean",
"prepack": "backstage-cli package prepack",
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/backend-defaults": "^0.5.2",
"@backstage/backend-plugin-api": "^1.0.1",
"@backstage/catalog-client": "^1.7.1",
"@backstage/errors": "^1.2.4",
"@backstage/plugin-catalog-node": "^1.13.1",
"@red-hat-developer-hub/backstage-plugin-marketplace-common": "workspace:^",
"express": "^4.17.1",
"express-promise-router": "^4.1.0",
"zod": "^3.22.4"
},
"devDependencies": {
"@backstage/backend-test-utils": "^1.0.2",
"@backstage/cli": "^0.28.0",
"@types/express": "*",
"@types/supertest": "^2.0.12",
"supertest": "^6.2.4"
},
"files": [
"dist"
]
}
16 changes: 16 additions & 0 deletions workspaces/marketplace/plugins/marketplace-backend/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { marketplacePlugin as default } from './plugin';
100 changes: 100 additions & 0 deletions workspaces/marketplace/plugins/marketplace-backend/src/plugin.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
mockCredentials,
startTestBackend,
} from '@backstage/backend-test-utils';
import { marketplacePlugin } from './plugin';
import request from 'supertest';
import { catalogServiceMock } from '@backstage/plugin-catalog-node/testUtils';

// TEMPLATE NOTE:
// Plugin tests are integration tests for your plugin, ensuring that all pieces
// work together end-to-end. You can still mock injected backend services
// however, just like anyone who installs your plugin might replace the
// services with their own implementations.
describe('plugin', () => {
it('should create and read TODO items', async () => {
const { server } = await startTestBackend({
features: [marketplacePlugin],
});

await request(server).get('/api/marketplace/todos').expect(200, {
items: [],
});

const createRes = await request(server)
.post('/api/marketplace/todos')
.send({ title: 'My Todo' });

expect(createRes.status).toBe(201);
expect(createRes.body).toEqual({
id: expect.any(String),
title: 'My Todo',
createdBy: mockCredentials.user().principal.userEntityRef,
createdAt: expect.any(String),
});

const createdTodoItem = createRes.body;

await request(server)
.get('/api/marketplace/todos')
.expect(200, {
items: [createdTodoItem],
});

await request(server)
.get(`/api/marketplace/todos/${createdTodoItem.id}`)
.expect(200, createdTodoItem);
});

it('should create TODO item with catalog information', async () => {
const { server } = await startTestBackend({
features: [
marketplacePlugin,
catalogServiceMock.factory({
entities: [
{
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'my-component',
namespace: 'default',
title: 'My Component',
},
spec: {
type: 'service',
owner: 'me',
},
},
],
}),
],
});

const createRes = await request(server)
.post('/api/marketplace/todos')
.send({ title: 'My Todo', entityRef: 'component:default/my-component' });

expect(createRes.status).toBe(201);
expect(createRes.body).toEqual({
id: expect.any(String),
title: '[My Component] My Todo',
createdBy: mockCredentials.user().principal.userEntityRef,
createdAt: expect.any(String),
});
});
});
56 changes: 56 additions & 0 deletions workspaces/marketplace/plugins/marketplace-backend/src/plugin.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2024 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import {
coreServices,
createBackendPlugin,
} from '@backstage/backend-plugin-api';
import { createRouter } from './router';
import { catalogServiceRef } from '@backstage/plugin-catalog-node/alpha';
import { createTodoListService } from './services/TodoListService';

/**
* marketplacePlugin backend plugin
*
* @public
*/
export const marketplacePlugin = createBackendPlugin({
pluginId: 'marketplace',
register(env) {
env.registerInit({
deps: {
logger: coreServices.logger,
auth: coreServices.auth,
httpAuth: coreServices.httpAuth,
httpRouter: coreServices.httpRouter,
catalog: catalogServiceRef,
},
async init({ logger, auth, httpAuth, httpRouter, catalog }) {
const todoListService = await createTodoListService({
logger,
auth,
catalog,
});

httpRouter.use(
await createRouter({
httpAuth,
todoListService,
}),
);
},
});
},
});
Loading

0 comments on commit fd74ca4

Please sign in to comment.