feat(ADR): implement ADR plugin

Signed-off-by: Phil Kuang <pkuang@factset.com>
This commit is contained in:
Phil Kuang
2022-04-13 14:39:17 -04:00
parent 1cb9cec16b
commit e73075a301
37 changed files with 1679 additions and 1 deletions
+126
View File
@@ -0,0 +1,126 @@
# Architecture Decision Records (ADR) Plugin
Welcome to the ADR plugin!
This plugin allows you to browse ADRs associated with your entities as well as a way to discover ADRs across others entities via Backstage Search. Use this to learn from the past experience of other projects to guide your own architecture decisions.
NOTE: This plugin currently only supports entities/ADRs registered via GitHub integration.
## Setup
Install this plugin:
```bash
# From your Backstage root directory
yarn --cwd packages/app add @backstage/plugin-adr
```
### Entity Pages
1. Add the plugin as a tab to your Entity pages:
```jsx
// In packages/app/src/components/catalog/EntityPage.tsx
import { EntityAdrContent, isAdrAvailable } from '@backstage/plugin-adr';
...
const serviceEntityPage = (
<EntityLayout>
{/* other tabs... */}
<EntityLayout.Route if={isAdrAvailable} path="/adrs" title="ADRs">
<EntityAdrContent />
</EntityLayout.Route>
</EntityLayout>
```
2. Add `backstage.io/adr-location` annotation to your `catalog-info.yaml`:
```yaml
metadata:
annotations:
backstage.io/adr-location: <RELATIVE_PATH_TO_ADR_FILES_DIR>
```
The value for `backstage.io/adr-location` should be a path relative to your `catalog-info.yaml` file or a absolute URL to the directory which contains your ADR markdown files.
For example, if you have the following directory structure, you would set `backstage.io/adr-location: docs/adrs`:
```
repo-root/
README.md
src/
catalog-info.yaml
docs/
adrs/
0001-use-adrs.md
0002-use-cloud.md
```
### Search
First, make sure to setup Backstage Search with the [ADR backend plugin](../adr-backend/README.md).
Afterwards, add the following code snippet to use `AdrSearchResultListItem` when the type of the search results is `adr`:
```tsx
// In packages/app/src/components/search/SearchPage.tsx
import { AdrSearchResultListItem } from '@backstage/plugin-adr';
...
case 'adr':
return (
<AdrSearchResultListItem
key={document.location}
result={document}
/>
);
```
## Custom ADR formats
By default, this plugin will parse ADRs according to the format specified by the [Markdown Architecture Decision Record (MADR)](https://adr.github.io/madr/) template. If your ADRs are written using a different format, you can apply the following customizations to correctly identify and parse your documents:
### Custom Filename/Path Format
In order to ensure the plugin fetches the correct ADR files (e.g. ignoring your template file), you can pass in an optional `filePathFilterFn` parameter to `EntityAdrContent` which will be called with each file path relative to the ADR location specified by `backstage.io/adr-location`. For example, the follow custom filter function will ignore the ADR template file and include files with a specific naming convention including those under a specified sub-directory:
```tsx
const myCustomFilterFn: AdrFilePathFilterFn = (path: string): boolean => {
if (path === '0000-adr-template.md') {
return false;
}
// Match all files following the pattern NNNN-title-with-dashes.md including those under decided-adrs/
return /^(decided-adrs\/)?\d{4}-.+\.md$/.test(path);
}
...
<EntityAdrContent filePathFilterFn={myCustomFilterFn} />
```
### Custom Content Decorators
Your ADR Markdown content will typically be rendered in the UI as is with the exception of relative links/embeds being rewritten as absolute URLs so they can be linked correctly (e.g. `./my-diagram.png` => `<ABSOLUTE_ADR_DIR_URL>/my-diagram.png`). Depending on your ADR format, you may want to apply additional transformations to the content (e.g. parsing/ignoring front matter). You can do so by passing in a list of custom content decorators for the optional `contentDecorators` parameter. Note that passing in this parameter will override the default decorators. If you want to include the default ones, make sure to add them as well:
```tsx
import {
AdrReader,
...
} from '@backstage/plugin-adr';
...
const myCustomDecorator: AdrContentDecorator = ({ content }) => {
return { content: applyCustomContentTransformation(content) };
};
...
<EntityAdrContent contentDecorators={[
AdrReader.decorators.createRewriteRelativeLinksDecorator(),
AdrReader.decorators.createRewriteRelativeEmbedsDecorator(),
myCustomDecorator,
]}
/>
```