@axis-backstage/plugin-readme-backend 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @axis-backstage/plugin-readme-backend
2
2
 
3
+ ## 0.11.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 6939770: **BREAKING**: The `readme-backend` has been migrated to the new backend system. If
8
+ you are using the new backend system module, this does not affect you.
9
+
3
10
  ## 0.10.1
4
11
 
5
12
  ### Patch Changes
package/README.md CHANGED
@@ -21,45 +21,6 @@ yarn --cwd packages/backend add @axis-backstage/plugin-readme-backend
21
21
 
22
22
  Here's how to get the backend plugin up and running:
23
23
 
24
- 1. Create a new file named `packages/backend/src/plugins/readme.ts`, and add the following to it:
25
-
26
- ```ts
27
- import { createRouter } from '@axis-backstage/plugin-readme-backend';
28
- import { Router } from 'express';
29
- import { PluginEnvironment } from '../types';
30
-
31
- export default async function createPlugin(
32
- env: PluginEnvironment,
33
- ): Promise<Router> {
34
- return await createRouter({
35
- logger: env.logger,
36
- config: env.config,
37
- reader: env.reader,
38
- discovery: env.discovery,
39
- tokenManager: env.tokenManager,
40
- });
41
- }
42
- ```
43
-
44
- 2. Wire this into the overall backend router by adding the following to `packages/backend/src/index.ts`:
45
-
46
- ```ts
47
- import readme from './plugins/readme';
48
- ...
49
-
50
- async function main() {
51
- // Add this line under the other lines that follow the useHotMemoize pattern
52
- const readmeEnv = useHotMemoize(module, () => createEnv('readme'),
53
-
54
- // Add this under the lines that add their routers to apiRouter
55
- apiRouter.use('/readme', await readme(readmeEnv));
56
- }
57
- ```
58
-
59
- ### New Backend System
60
-
61
- The Readme backend plugin has support for the [new backend system](https://backstage.io/docs/backend-system/). Here is how you can set it up:
62
-
63
24
  In your `packages/backend/src/index.ts` make the following changes:
64
25
 
65
26
  ```diff
package/dist/index.cjs.js CHANGED
@@ -2,16 +2,15 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var backendPluginApi = require('@backstage/backend-plugin-api');
5
6
  var rootHttpRouter = require('@backstage/backend-defaults/rootHttpRouter');
6
7
  var cache = require('@backstage/backend-defaults/cache');
7
- var backendCommon = require('@backstage/backend-common');
8
8
  var integration = require('@backstage/integration');
9
9
  var catalogModel = require('@backstage/catalog-model');
10
10
  var catalogClient = require('@backstage/catalog-client');
11
11
  var errors = require('@backstage/errors');
12
12
  var express = require('express');
13
13
  var Router = require('express-promise-router');
14
- var backendPluginApi = require('@backstage/backend-plugin-api');
15
14
 
16
15
  function _interopDefaultCompat (e) { return e && typeof e === 'object' && 'default' in e ? e : { default: e }; }
17
16
 
@@ -39,8 +38,7 @@ const README_TYPES = [
39
38
  ];
40
39
 
41
40
  async function createRouter(options) {
42
- const { logger, config, reader, discovery } = options;
43
- const { auth } = backendCommon.createLegacyAuthAdapters(options);
41
+ const { auth, logger, config, reader, discovery } = options;
44
42
  const catalogClient$1 = new catalogClient.CatalogClient({ discoveryApi: discovery });
45
43
  const pluginCache = cache.CacheManager.fromConfig(config).forPlugin("readme");
46
44
  const cache$1 = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });
@@ -144,12 +142,12 @@ const readmePlugin = backendPluginApi.createBackendPlugin({
144
142
  register(env) {
145
143
  env.registerInit({
146
144
  deps: {
147
- logger: backendPluginApi.coreServices.logger,
145
+ auth: backendPluginApi.coreServices.auth,
148
146
  config: backendPluginApi.coreServices.rootConfig,
149
- reader: backendPluginApi.coreServices.urlReader,
150
147
  discovery: backendPluginApi.coreServices.discovery,
151
- auth: backendPluginApi.coreServices.auth,
152
- httpRouter: backendPluginApi.coreServices.httpRouter
148
+ httpRouter: backendPluginApi.coreServices.httpRouter,
149
+ logger: backendPluginApi.coreServices.logger,
150
+ reader: backendPluginApi.coreServices.urlReader
153
151
  },
154
152
  async init({ auth, logger, config, reader, discovery, httpRouter }) {
155
153
  httpRouter.use(
@@ -166,6 +164,5 @@ const readmePlugin = backendPluginApi.createBackendPlugin({
166
164
  }
167
165
  });
168
166
 
169
- exports.createRouter = createRouter;
170
167
  exports.default = readmePlugin;
171
168
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/lib.ts","../src/service/constants.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["const DETECT_SYMLINKS_REGEX = '^(w+|.|/|-)+$';\n\nexport const isSymLink = (content: string): boolean => {\n const lines = content.split('\\n');\n if (lines.length > 1) return false;\n const line = lines[0];\n if (line.includes(' ')) return false;\n\n const regex = RegExp(DETECT_SYMLINKS_REGEX);\n return regex.test(content);\n};\n","import { FileType } from './types';\n\n// Cache placeholder for entities where no readme\nexport const NOT_FOUND_PLACEHOLDER = 'NOT_FOUND';\nexport const DEFAULT_TTL = 1800 * 1000;\n\nexport const README_TYPES: FileType[] = [\n { name: 'README', type: 'text/plain' },\n { name: 'README.md', type: 'text/markdown' },\n { name: 'README.rst', type: 'text/plain' },\n { name: 'README.txt', type: 'text/plain' },\n { name: 'README.MD', type: 'text/markdown' },\n];\n","import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { CacheManager } from '@backstage/backend-defaults/cache';\nimport {\n AuthService,\n DiscoveryService,\n LoggerService,\n RootConfigService,\n UrlReaderService,\n TokenManagerService,\n} from '@backstage/backend-plugin-api';\nimport { createLegacyAuthAdapters } from '@backstage/backend-common';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n getEntitySourceLocation,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { isError, NotFoundError } from '@backstage/errors';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { isSymLink } from '../lib';\nimport { DEFAULT_TTL, NOT_FOUND_PLACEHOLDER, README_TYPES } from './constants';\nimport { ReadmeFile } from './types';\n\n/**\n * Constructs a readme router.\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport interface RouterOptions {\n /**\n * Implementation of Winston logger\n */\n logger: LoggerService;\n\n /**\n * Backstage config object\n */\n config: RootConfigService;\n\n /**\n * Backstage url reader instance\n */\n reader: UrlReaderService;\n /**\n * Backstage discovery service\n */\n discovery: DiscoveryService;\n /**\n * Backstage token manager service\n */\n tokenManager?: TokenManagerService;\n /**\n * Backstage auth service\n */\n auth?: AuthService;\n}\n\n/**\n * Constructs a readme router.\n *\n * @deprecated Please migrate to the new backend system as this will be removed in the future.\n * @public\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { logger, config, reader, discovery } = options;\n const { auth } = createLegacyAuthAdapters(options);\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n const pluginCache = CacheManager.fromConfig(config).forPlugin('readme');\n const cache = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });\n\n logger.info('Initializing readme backend');\n const integrations = ScmIntegrations.fromConfig(config);\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n router.get('/:kind/:namespace/:name', async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const cacheDoc = (await cache.get(entityRef)) as ReadmeFile | undefined;\n\n if (cacheDoc && cacheDoc.name === NOT_FOUND_PLACEHOLDER) {\n throw new NotFoundError('Readme could not be found');\n }\n if (cacheDoc) {\n logger.info(`Loading README for ${entityRef} from cache.`);\n response.type(cacheDoc.type);\n response.send(cacheDoc.content);\n return;\n }\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n if (!entity) {\n logger.info(`No integration found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No integration found for ${entityRef}` });\n return;\n }\n const source = getEntitySourceLocation(entity);\n\n if (!source || source.type !== 'url') {\n const errorMessage = `Not valid location for ${source.target}`;\n logger.info(errorMessage);\n throw new NotFoundError(errorMessage);\n }\n const integration = integrations.byUrl(source.target);\n\n if (!integration) {\n logger.info(`No integration found for ${source.target}`);\n response\n .status(500)\n .json({ error: `No integration found for ${source.target}` });\n return;\n }\n\n for (const fileType of README_TYPES) {\n const url = integration.resolveUrl({\n url: fileType.name,\n base: source.target,\n });\n\n let content;\n\n try {\n logger.debug(`Trying README location: ${url} for ${entityRef} `);\n response.type(fileType.type);\n\n const urlResponse = await reader.readUrl(url);\n content = (await urlResponse.buffer()).toString('utf-8');\n\n if (isSymLink(content)) {\n const symLinkUrl = integration.resolveUrl({\n url: content,\n base: source.target,\n });\n const symLinkUrlResponse = await reader.readUrl(symLinkUrl);\n content = (await symLinkUrlResponse.buffer()).toString('utf-8');\n }\n\n cache.set(entityRef, {\n name: fileType.name,\n type: fileType.type,\n content: content,\n });\n logger.info(\n `Found README for ${entityRef}: ${url} type ${fileType.type}`,\n );\n response.send(content);\n return;\n } catch (error: unknown) {\n if (isError(error) && error.name === 'NotFoundError') {\n continue;\n } else {\n response.status(500).json({\n error: `Readme failure: ${error}`,\n });\n return;\n }\n }\n }\n logger.info(`Readme not found for ${entityRef}`);\n cache.set(entityRef, {\n name: NOT_FOUND_PLACEHOLDER,\n type: '',\n content: '',\n });\n throw new NotFoundError('Readme could not be found');\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n router.use(middleware.error());\n return router;\n}\n","import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * The Readme backend plugin.\n *\n * @public\n */\nexport const readmePlugin = createBackendPlugin({\n pluginId: 'readme',\n register(env) {\n env.registerInit({\n deps: {\n logger: coreServices.logger,\n config: coreServices.rootConfig,\n reader: coreServices.urlReader,\n discovery: coreServices.discovery,\n auth: coreServices.auth,\n httpRouter: coreServices.httpRouter,\n },\n async init({ auth, logger, config, reader, discovery, httpRouter }) {\n httpRouter.use(\n await createRouter({\n auth,\n logger,\n config,\n reader,\n discovery,\n }),\n );\n },\n });\n },\n});\n"],"names":["createLegacyAuthAdapters","catalogClient","CatalogClient","CacheManager","cache","ScmIntegrations","Router","express","stringifyEntityRef","NotFoundError","getEntitySourceLocation","isError","MiddlewareFactory","createBackendPlugin","coreServices"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/lib.ts","../src/service/constants.ts","../src/service/router.ts","../src/plugin.ts"],"sourcesContent":["const DETECT_SYMLINKS_REGEX = '^(w+|.|/|-)+$';\n\nexport const isSymLink = (content: string): boolean => {\n const lines = content.split('\\n');\n if (lines.length > 1) return false;\n const line = lines[0];\n if (line.includes(' ')) return false;\n\n const regex = RegExp(DETECT_SYMLINKS_REGEX);\n return regex.test(content);\n};\n","import { FileType } from './types';\n\n// Cache placeholder for entities where no readme\nexport const NOT_FOUND_PLACEHOLDER = 'NOT_FOUND';\nexport const DEFAULT_TTL = 1800 * 1000;\n\nexport const README_TYPES: FileType[] = [\n { name: 'README', type: 'text/plain' },\n { name: 'README.md', type: 'text/markdown' },\n { name: 'README.rst', type: 'text/plain' },\n { name: 'README.txt', type: 'text/plain' },\n { name: 'README.MD', type: 'text/markdown' },\n];\n","import { MiddlewareFactory } from '@backstage/backend-defaults/rootHttpRouter';\nimport { CacheManager } from '@backstage/backend-defaults/cache';\nimport {\n AuthService,\n DiscoveryService,\n LoggerService,\n RootConfigService,\n UrlReaderService,\n} from '@backstage/backend-plugin-api';\nimport { ScmIntegrations } from '@backstage/integration';\nimport {\n getEntitySourceLocation,\n stringifyEntityRef,\n} from '@backstage/catalog-model';\nimport { CatalogClient } from '@backstage/catalog-client';\nimport { isError, NotFoundError } from '@backstage/errors';\nimport express from 'express';\nimport Router from 'express-promise-router';\nimport { isSymLink } from '../lib';\nimport { DEFAULT_TTL, NOT_FOUND_PLACEHOLDER, README_TYPES } from './constants';\nimport { ReadmeFile } from './types';\n\n/**\n * Constructs a readme router.\n *\n */\ninterface RouterOptions {\n auth: AuthService;\n config: RootConfigService;\n discovery: DiscoveryService;\n logger: LoggerService;\n reader: UrlReaderService;\n}\n\n/**\n * Constructs a readme router.\n *\n */\nexport async function createRouter(\n options: RouterOptions,\n): Promise<express.Router> {\n const { auth, logger, config, reader, discovery } = options;\n const catalogClient = new CatalogClient({ discoveryApi: discovery });\n\n const pluginCache = CacheManager.fromConfig(config).forPlugin('readme');\n const cache = pluginCache.getClient({ defaultTtl: DEFAULT_TTL });\n\n logger.info('Initializing readme backend');\n const integrations = ScmIntegrations.fromConfig(config);\n const router = Router();\n router.use(express.json());\n\n router.get('/health', (_, response) => {\n response.json({ status: 'ok' });\n });\n\n router.get('/:kind/:namespace/:name', async (request, response) => {\n const { kind, namespace, name } = request.params;\n const entityRef = stringifyEntityRef({ kind, namespace, name });\n const cacheDoc = (await cache.get(entityRef)) as ReadmeFile | undefined;\n\n if (cacheDoc && cacheDoc.name === NOT_FOUND_PLACEHOLDER) {\n throw new NotFoundError('Readme could not be found');\n }\n if (cacheDoc) {\n logger.info(`Loading README for ${entityRef} from cache.`);\n response.type(cacheDoc.type);\n response.send(cacheDoc.content);\n return;\n }\n const { token } = await auth.getPluginRequestToken({\n onBehalfOf: await auth.getOwnServiceCredentials(),\n targetPluginId: 'catalog',\n });\n const entity = await catalogClient.getEntityByRef(entityRef, { token });\n if (!entity) {\n logger.info(`No integration found for ${entityRef}`);\n response\n .status(500)\n .json({ error: `No integration found for ${entityRef}` });\n return;\n }\n const source = getEntitySourceLocation(entity);\n\n if (!source || source.type !== 'url') {\n const errorMessage = `Not valid location for ${source.target}`;\n logger.info(errorMessage);\n throw new NotFoundError(errorMessage);\n }\n const integration = integrations.byUrl(source.target);\n\n if (!integration) {\n logger.info(`No integration found for ${source.target}`);\n response\n .status(500)\n .json({ error: `No integration found for ${source.target}` });\n return;\n }\n\n for (const fileType of README_TYPES) {\n const url = integration.resolveUrl({\n url: fileType.name,\n base: source.target,\n });\n\n let content;\n\n try {\n logger.debug(`Trying README location: ${url} for ${entityRef} `);\n response.type(fileType.type);\n\n const urlResponse = await reader.readUrl(url);\n content = (await urlResponse.buffer()).toString('utf-8');\n\n if (isSymLink(content)) {\n const symLinkUrl = integration.resolveUrl({\n url: content,\n base: source.target,\n });\n const symLinkUrlResponse = await reader.readUrl(symLinkUrl);\n content = (await symLinkUrlResponse.buffer()).toString('utf-8');\n }\n\n cache.set(entityRef, {\n name: fileType.name,\n type: fileType.type,\n content: content,\n });\n logger.info(\n `Found README for ${entityRef}: ${url} type ${fileType.type}`,\n );\n response.send(content);\n return;\n } catch (error: unknown) {\n if (isError(error) && error.name === 'NotFoundError') {\n continue;\n } else {\n response.status(500).json({\n error: `Readme failure: ${error}`,\n });\n return;\n }\n }\n }\n logger.info(`Readme not found for ${entityRef}`);\n cache.set(entityRef, {\n name: NOT_FOUND_PLACEHOLDER,\n type: '',\n content: '',\n });\n throw new NotFoundError('Readme could not be found');\n });\n\n const middleware = MiddlewareFactory.create({ logger, config });\n router.use(middleware.error());\n return router;\n}\n","import {\n coreServices,\n createBackendPlugin,\n} from '@backstage/backend-plugin-api';\nimport { createRouter } from './service/router';\n\n/**\n * The Readme backend plugin.\n *\n * @public\n */\nexport const readmePlugin = createBackendPlugin({\n pluginId: 'readme',\n register(env) {\n env.registerInit({\n deps: {\n auth: coreServices.auth,\n config: coreServices.rootConfig,\n discovery: coreServices.discovery,\n httpRouter: coreServices.httpRouter,\n logger: coreServices.logger,\n reader: coreServices.urlReader,\n },\n async init({ auth, logger, config, reader, discovery, httpRouter }) {\n httpRouter.use(\n await createRouter({\n auth,\n logger,\n config,\n reader,\n discovery,\n }),\n );\n },\n });\n },\n});\n"],"names":["catalogClient","CatalogClient","CacheManager","cache","ScmIntegrations","Router","express","stringifyEntityRef","NotFoundError","getEntitySourceLocation","isError","MiddlewareFactory","createBackendPlugin","coreServices"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,45 +1,4 @@
1
1
  import * as _backstage_backend_plugin_api from '@backstage/backend-plugin-api';
2
- import { LoggerService, RootConfigService, UrlReaderService, DiscoveryService, TokenManagerService, AuthService } from '@backstage/backend-plugin-api';
3
- import express from 'express';
4
-
5
- /**
6
- * Constructs a readme router.
7
- * @deprecated Please migrate to the new backend system as this will be removed in the future.
8
- * @public
9
- */
10
- interface RouterOptions {
11
- /**
12
- * Implementation of Winston logger
13
- */
14
- logger: LoggerService;
15
- /**
16
- * Backstage config object
17
- */
18
- config: RootConfigService;
19
- /**
20
- * Backstage url reader instance
21
- */
22
- reader: UrlReaderService;
23
- /**
24
- * Backstage discovery service
25
- */
26
- discovery: DiscoveryService;
27
- /**
28
- * Backstage token manager service
29
- */
30
- tokenManager?: TokenManagerService;
31
- /**
32
- * Backstage auth service
33
- */
34
- auth?: AuthService;
35
- }
36
- /**
37
- * Constructs a readme router.
38
- *
39
- * @deprecated Please migrate to the new backend system as this will be removed in the future.
40
- * @public
41
- */
42
- declare function createRouter(options: RouterOptions): Promise<express.Router>;
43
2
 
44
3
  /**
45
4
  * The Readme backend plugin.
@@ -48,4 +7,4 @@ declare function createRouter(options: RouterOptions): Promise<express.Router>;
48
7
  */
49
8
  declare const readmePlugin: _backstage_backend_plugin_api.BackendFeatureCompat;
50
9
 
51
- export { type RouterOptions, createRouter, readmePlugin as default };
10
+ export { readmePlugin as default };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axis-backstage/plugin-readme-backend",
3
- "version": "0.10.1",
3
+ "version": "0.11.0",
4
4
  "main": "dist/index.cjs.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "Apache-2.0",
@@ -28,7 +28,6 @@
28
28
  "postpack": "backstage-cli package postpack"
29
29
  },
30
30
  "dependencies": {
31
- "@backstage/backend-common": "^0.24.0",
32
31
  "@backstage/backend-defaults": "^0.4.3",
33
32
  "@backstage/backend-plugin-api": "^0.8.0",
34
33
  "@backstage/catalog-client": "^1.6.6",