@meza/adr-tools 1.0.1
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/.adr-dir +1 -0
- package/.editorconfig +13 -0
- package/.eslintignore +2 -0
- package/.eslintrc.json +23 -0
- package/.github/dependabot.yml +14 -0
- package/.github/stale.yml +18 -0
- package/.github/workflows/auto-merge.yml +14 -0
- package/.github/workflows/ci.yml +89 -0
- package/.husky/commit-msg +4 -0
- package/.releaserc.json +41 -0
- package/README.md +30 -0
- package/doc/adr/0001-record-architecture-decisions.md +21 -0
- package/doc/adr/0002-using-heavy-e2e-tests.md +20 -0
- package/docs/CHANGELOG.md +6 -0
- package/package.json +91 -0
- package/src/environment.d.ts +14 -0
- package/src/index.ts +115 -0
- package/src/lib/adr.ts +242 -0
- package/src/lib/config.ts +34 -0
- package/src/lib/links.test.ts +86 -0
- package/src/lib/links.ts +34 -0
- package/src/lib/manipulator.test.ts +88 -0
- package/src/lib/manipulator.ts +86 -0
- package/src/lib/numbering.test.ts +41 -0
- package/src/lib/numbering.ts +26 -0
- package/src/lib/template.ts +18 -0
- package/src/templates/init.md +21 -0
- package/src/templates/template.md +19 -0
- package/src/version.ts +1 -0
- package/tests/__snapshots__/generate-graph.e2e.test.ts.snap +39 -0
- package/tests/__snapshots__/init-adr-repository.e2e.test.ts.snap +51 -0
- package/tests/__snapshots__/linking-records.e2e.test.ts.snap +155 -0
- package/tests/__snapshots__/new-adr.e2e.test.ts.snap +54 -0
- package/tests/__snapshots__/superseding-records.e2e.test.ts.snap +122 -0
- package/tests/__snapshots__/toc-prefixing.e2e.test.ts.snap +9 -0
- package/tests/__snapshots__/use-template-override.e2e.test.ts.snap +17 -0
- package/tests/edit-on-create.e2e.test.ts +54 -0
- package/tests/fake-editor +3 -0
- package/tests/fake-visual +3 -0
- package/tests/funny-characters.e2e.test.ts +43 -0
- package/tests/generate-graph.e2e.test.ts +45 -0
- package/tests/init-adr-repository.e2e.test.ts +53 -0
- package/tests/linking-records.e2e.test.ts +64 -0
- package/tests/list-adrs.e2e.test.ts +48 -0
- package/tests/new-adr.e2e.test.ts +58 -0
- package/tests/superseding-records.e2e.test.ts +58 -0
- package/tests/toc-prefixing.e2e.test.ts +38 -0
- package/tests/use-template-override.e2e.test.ts +43 -0
- package/tests/work-form-other-directories.e2e.test.ts +44 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +12 -0
package/.adr-dir
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
doc/adr
|
package/.editorconfig
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# EditorConfig is awesome: http://EditorConfig.org
|
|
2
|
+
|
|
3
|
+
# top-most EditorConfig file
|
|
4
|
+
root = true
|
|
5
|
+
|
|
6
|
+
# Unix-style newlines with a newline ending every file
|
|
7
|
+
[*]
|
|
8
|
+
charset = utf-8
|
|
9
|
+
insert_final_newline = true
|
|
10
|
+
end_of_line = lf
|
|
11
|
+
indent_size = 2
|
|
12
|
+
indent_style = space
|
|
13
|
+
trim_trailing_whitespace = true
|
package/.eslintignore
ADDED
package/.eslintrc.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": [
|
|
3
|
+
"tailored-tunes",
|
|
4
|
+
"plugin:json/recommended",
|
|
5
|
+
"plugin:security/recommended"
|
|
6
|
+
],
|
|
7
|
+
"root": true,
|
|
8
|
+
"parser": "@typescript-eslint/parser",
|
|
9
|
+
"plugins": [
|
|
10
|
+
"json",
|
|
11
|
+
"@typescript-eslint"
|
|
12
|
+
],
|
|
13
|
+
"rules": {
|
|
14
|
+
"no-console": "off",
|
|
15
|
+
"security/detect-object-injection": 0,
|
|
16
|
+
"security/detect-non-literal-fs-filename": 0
|
|
17
|
+
},
|
|
18
|
+
"env": {
|
|
19
|
+
"commonjs": false,
|
|
20
|
+
"es6": true,
|
|
21
|
+
"node": true
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# To get started with Dependabot version updates, you'll need to specify which
|
|
2
|
+
# package ecosystems to update and where the package manifests are located.
|
|
3
|
+
# Please see the documentation for all configuration options:
|
|
4
|
+
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
|
5
|
+
|
|
6
|
+
version: 2
|
|
7
|
+
updates:
|
|
8
|
+
- package-ecosystem: "npm" # See documentation for possible values
|
|
9
|
+
directory: "/" # Location of package manifests
|
|
10
|
+
versioning-strategy: increase-if-necessary
|
|
11
|
+
commit-message:
|
|
12
|
+
prefix: "chore: "
|
|
13
|
+
schedule:
|
|
14
|
+
interval: "daily"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Number of days of inactivity before an issue becomes stale
|
|
2
|
+
daysUntilStale: 90
|
|
3
|
+
# Number of days of inactivity before a stale issue is closed
|
|
4
|
+
daysUntilClose: 275
|
|
5
|
+
# Issues with these labels will never be considered stale
|
|
6
|
+
exemptLabels:
|
|
7
|
+
- pinned
|
|
8
|
+
- security
|
|
9
|
+
# Label to use when marking an issue as stale
|
|
10
|
+
staleLabel: stale
|
|
11
|
+
# Comment to post when marking an issue as stale. Set to `false` to disable
|
|
12
|
+
markComment: >
|
|
13
|
+
This issue has been automatically marked as stale because it has not had
|
|
14
|
+
recent activity. It will be closed if no further activity occurs. Thank you
|
|
15
|
+
for your contributions.
|
|
16
|
+
# Comment to post when closing a stale issue. Set to `false` to disable
|
|
17
|
+
closeComment: >
|
|
18
|
+
This issue has been automatically closed because it has not had recent activity.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
name: auto-merge dependabot
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
auto-merge:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
steps:
|
|
10
|
+
- uses: actions/checkout@v2
|
|
11
|
+
- uses: ahmadnassri/action-dependabot-auto-merge@v2
|
|
12
|
+
with:
|
|
13
|
+
target: minor # includes patch updates!
|
|
14
|
+
github-token: ${{ secrets.GITHUB_TOKEN }}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
name: Verify and Release
|
|
2
|
+
|
|
3
|
+
on: [push]
|
|
4
|
+
|
|
5
|
+
jobs:
|
|
6
|
+
build:
|
|
7
|
+
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
|
|
10
|
+
strategy:
|
|
11
|
+
matrix:
|
|
12
|
+
node-version: [ 18.x ]
|
|
13
|
+
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
|
14
|
+
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v2
|
|
17
|
+
|
|
18
|
+
- name: Cache multiple paths
|
|
19
|
+
uses: actions/cache@v2
|
|
20
|
+
with:
|
|
21
|
+
path: |
|
|
22
|
+
~/.cache
|
|
23
|
+
~/node_modules
|
|
24
|
+
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
|
25
|
+
|
|
26
|
+
- name: Get yarn cache directory path
|
|
27
|
+
id: yarn-cache-dir-path
|
|
28
|
+
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
|
|
29
|
+
|
|
30
|
+
- uses: actions/cache@v2
|
|
31
|
+
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
|
32
|
+
with:
|
|
33
|
+
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
34
|
+
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
35
|
+
restore-keys: |
|
|
36
|
+
${{ runner.os }}-yarn-
|
|
37
|
+
|
|
38
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
39
|
+
uses: actions/setup-node@v2
|
|
40
|
+
with:
|
|
41
|
+
node-version: ${{ matrix.node-version }}
|
|
42
|
+
cache: 'yarn'
|
|
43
|
+
|
|
44
|
+
- run: yarn --pure-lockfile
|
|
45
|
+
- run: yarn lint
|
|
46
|
+
|
|
47
|
+
release:
|
|
48
|
+
needs: [build]
|
|
49
|
+
name: Release
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
if: ${{github.ref == 'ref/head/main'}} || ${{github.ref == 'ref/head/next'}}
|
|
52
|
+
steps:
|
|
53
|
+
- name: Checkout
|
|
54
|
+
uses: actions/checkout@v2
|
|
55
|
+
with:
|
|
56
|
+
fetch-depth: 0
|
|
57
|
+
- name: Cache multiple paths
|
|
58
|
+
uses: actions/cache@v2
|
|
59
|
+
with:
|
|
60
|
+
path: |
|
|
61
|
+
~/.cache
|
|
62
|
+
~/node_modules
|
|
63
|
+
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
|
|
64
|
+
|
|
65
|
+
- name: Get yarn cache directory path
|
|
66
|
+
id: yarn-cache-dir-path
|
|
67
|
+
run: echo "::set-output name=dir::$(yarn config get cacheFolder)"
|
|
68
|
+
|
|
69
|
+
- uses: actions/cache@v2
|
|
70
|
+
id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`)
|
|
71
|
+
with:
|
|
72
|
+
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
|
73
|
+
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
|
|
74
|
+
restore-keys: |
|
|
75
|
+
${{ runner.os }}-yarn-
|
|
76
|
+
|
|
77
|
+
- name: Use Node.js ${{ matrix.node-version }}
|
|
78
|
+
uses: actions/setup-node@v2
|
|
79
|
+
with:
|
|
80
|
+
node-version: ${{ matrix.node-version }}
|
|
81
|
+
cache: 'yarn'
|
|
82
|
+
|
|
83
|
+
- run: yarn --pure-lockfile --offline
|
|
84
|
+
|
|
85
|
+
- name: Release
|
|
86
|
+
env:
|
|
87
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
88
|
+
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
89
|
+
run: yarn release
|
package/.releaserc.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"plugins": [
|
|
3
|
+
"@semantic-release/npm",
|
|
4
|
+
"@semantic-release/commit-analyzer",
|
|
5
|
+
"@semantic-release/release-notes-generator",
|
|
6
|
+
[
|
|
7
|
+
"@semantic-release/changelog",
|
|
8
|
+
{
|
|
9
|
+
"changelogFile": "docs/CHANGELOG.md"
|
|
10
|
+
}
|
|
11
|
+
],
|
|
12
|
+
[
|
|
13
|
+
"@semantic-release/git",
|
|
14
|
+
{
|
|
15
|
+
"assets": [
|
|
16
|
+
"CHANGELOG.md"
|
|
17
|
+
]
|
|
18
|
+
}
|
|
19
|
+
],
|
|
20
|
+
[
|
|
21
|
+
"@semantic-release/git",
|
|
22
|
+
{
|
|
23
|
+
"assets": ["CHANGELOG.md"]
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
"@semantic-release/github",
|
|
28
|
+
{
|
|
29
|
+
"assets": [
|
|
30
|
+
{
|
|
31
|
+
"path": [
|
|
32
|
+
"dist/**",
|
|
33
|
+
"CHANGELOG.md"
|
|
34
|
+
],
|
|
35
|
+
"name": "adr-tools-${nextRelease.gitTag}.zip",
|
|
36
|
+
"label": "ADR-Tools ${nextRelease.gitTag}"
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}]
|
|
40
|
+
]
|
|
41
|
+
}
|
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# ADR-TOOLS
|
|
2
|
+
|
|
3
|
+
> THIS REPO IS UNDER HEAVY DEVELOPMENT. CODE YOU SEE HERE IS... NOT QUITE READY OR PRETTY (yet).
|
|
4
|
+
|
|
5
|
+
This is a Typescript fork of Nat Pryce's [ADR-TOOLS](https://github.com/npryce/adr-tools).
|
|
6
|
+
|
|
7
|
+
There are a few other forks out there which do some parts of the original tool but none actually do it fully.
|
|
8
|
+
|
|
9
|
+
This does.
|
|
10
|
+
|
|
11
|
+
More documentation to follow very soon!
|
|
12
|
+
|
|
13
|
+
## Conventions
|
|
14
|
+
|
|
15
|
+
An ADR file MUST have a `# title` at the top and a `## Status` header.
|
|
16
|
+
|
|
17
|
+
## Local Development
|
|
18
|
+
|
|
19
|
+
`yarn install`
|
|
20
|
+
|
|
21
|
+
### Commits
|
|
22
|
+
|
|
23
|
+
This project uses conventional commits. See [conventional-commits](https://www.conventionalcommits.org/en/v1.0.0/).
|
|
24
|
+
|
|
25
|
+
There are git hooks that check the commit messages and enforce the commit rules.
|
|
26
|
+
There is a helper tool to make it easier to create commits when unfamiliar with the rules:
|
|
27
|
+
|
|
28
|
+
`yarn commit`
|
|
29
|
+
|
|
30
|
+
This will use the [commitlint prompt tool](https://commitlint.js.org/#/guides-use-prompt) to help you create commits.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# 1. Record architecture decisions
|
|
2
|
+
|
|
3
|
+
Date: 2022-06-22
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Accepted
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
We need to record the architectural decisions made on this project.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions).
|
|
16
|
+
|
|
17
|
+
## Consequences
|
|
18
|
+
|
|
19
|
+
See Michael Nygard's article, linked above.
|
|
20
|
+
For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools).
|
|
21
|
+
> For a node version of the same tooling, see Meza's [adr-tools](https://github.com/meza/adr-tools).
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 2. Using Heavy E2E Tests
|
|
2
|
+
|
|
3
|
+
Date: 2022-06-22
|
|
4
|
+
|
|
5
|
+
## Status
|
|
6
|
+
|
|
7
|
+
Accepted
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
|
|
11
|
+
The original tool has an [exhaustive test suite](https://github.com/npryce/adr-tools/tree/master/tests) that allows us to make sure that we're backwards compatible.
|
|
12
|
+
|
|
13
|
+
## Decision
|
|
14
|
+
|
|
15
|
+
We'll be re-implementing those tests for ourselves too. This means that we will be using the original examples,
|
|
16
|
+
expectations and the ethos of invoking the tool with the given examples.
|
|
17
|
+
|
|
18
|
+
## Consequences
|
|
19
|
+
|
|
20
|
+
The E2E test suite will be very slow to run and it can only be executed sequentially.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
## [1.0.1](https://github.com/meza/adr-tools/compare/v1.0.0...v1.0.1) (2022-06-27)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* fixed deployment restrictions [#27](https://github.com/meza/adr-tools/issues/27) ([af4f4cc](https://github.com/meza/adr-tools/commit/af4f4cc2b208ff696baddad1bda0563170bfe1ce))
|
package/package.json
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@meza/adr-tools",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"main": "dist/index.js",
|
|
5
|
+
"bin": {
|
|
6
|
+
"adr": "dist/index.js"
|
|
7
|
+
},
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"access": "public"
|
|
10
|
+
},
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"private": false,
|
|
13
|
+
"scripts": {
|
|
14
|
+
"prebuild": "node -p \"'export const LIB_VERSION = ' + require('./package.json').version + ';'\" > src/version.ts",
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"start": "ts-node src/index.ts",
|
|
17
|
+
"commit": "commit",
|
|
18
|
+
"ci": "npm set editor '' && yarn lint && yarn test",
|
|
19
|
+
"ci:dev": "exit 0",
|
|
20
|
+
"clean": "rm -rf dist .cache/tsbuildinfo",
|
|
21
|
+
"clean:all": "yarn clean && rm -rf node_modules .cache",
|
|
22
|
+
"lint:eslint": "eslint . --ext .ts --ext .json --cache --cache-location .cache/",
|
|
23
|
+
"lint:tsc": "tsc --noEmit",
|
|
24
|
+
"lint:fix": "yarn lint:eslint --fix && yarn lint:tsc",
|
|
25
|
+
"lint": "yarn lint:eslint && yarn lint:tsc",
|
|
26
|
+
"test": "vitest",
|
|
27
|
+
"prepare": "husky install",
|
|
28
|
+
"report": "exit 0",
|
|
29
|
+
"semantic-release": "semantic-release",
|
|
30
|
+
"release": "semantic-release"
|
|
31
|
+
},
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@types/inquirer": "^8.2.1",
|
|
34
|
+
"@types/marked": "^4.0.3",
|
|
35
|
+
"@types/node": "^18.0.0",
|
|
36
|
+
"chalk": "^4.1.2",
|
|
37
|
+
"commander": "^9.3.0",
|
|
38
|
+
"core-js": "^3.19.1",
|
|
39
|
+
"inquirer": "^8.2.4",
|
|
40
|
+
"marked": "^4.0.17"
|
|
41
|
+
},
|
|
42
|
+
"commitlint": {
|
|
43
|
+
"extends": [
|
|
44
|
+
"@commitlint/config-conventional"
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
"husky": {
|
|
48
|
+
"hooks": {
|
|
49
|
+
"post-merge": "install-deps-postmerge",
|
|
50
|
+
"pre-push": "yarn ci",
|
|
51
|
+
"pre-commit": "yarn lint",
|
|
52
|
+
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
|
53
|
+
}
|
|
54
|
+
},
|
|
55
|
+
"devDependencies": {
|
|
56
|
+
"@commitlint/cli": "^17.0.2",
|
|
57
|
+
"@commitlint/config-conventional": "^17.0.2",
|
|
58
|
+
"@commitlint/prompt-cli": "^17.0.0",
|
|
59
|
+
"@meza/tsconfig-base": "^1.1.0",
|
|
60
|
+
"@release-it/conventional-changelog": "^5.0.0",
|
|
61
|
+
"@semantic-release/changelog": "^6.0.1",
|
|
62
|
+
"@semantic-release/commit-analyzer": "^9.0.2",
|
|
63
|
+
"@semantic-release/git": "^10.0.1",
|
|
64
|
+
"@semantic-release/github": "^8.0.4",
|
|
65
|
+
"@semantic-release/npm": "^9.0.1",
|
|
66
|
+
"@semantic-release/release-notes-generator": "^10.0.3",
|
|
67
|
+
"@types/uuid": "^8.3.4",
|
|
68
|
+
"@typescript-eslint/eslint-plugin": "^5.29.0",
|
|
69
|
+
"@typescript-eslint/parser": "^5.3.0",
|
|
70
|
+
"@vitest/ui": "^0.15.2",
|
|
71
|
+
"c8": "^7.11.3",
|
|
72
|
+
"eslint": "^8.1.0",
|
|
73
|
+
"eslint-config-tailored-tunes": "^5.0.2",
|
|
74
|
+
"eslint-plugin-json": "^3.1.0",
|
|
75
|
+
"eslint-plugin-security": "^1.5.0",
|
|
76
|
+
"husky": "^8.0.1",
|
|
77
|
+
"install-deps-postmerge": "^2.0.1",
|
|
78
|
+
"mock-cwd": "^1.0.0",
|
|
79
|
+
"semantic-release": "^19.0.3",
|
|
80
|
+
"standard-version": "^9.3.2",
|
|
81
|
+
"ts-node": "^10.8.1",
|
|
82
|
+
"typescript": "^4.4.4",
|
|
83
|
+
"uuid": "^8.3.2",
|
|
84
|
+
"vitest": "^0.15.2",
|
|
85
|
+
"yarn": "^1.22.17"
|
|
86
|
+
},
|
|
87
|
+
"repository": {
|
|
88
|
+
"type": "git",
|
|
89
|
+
"url": "https://github.com/meza/adr-tools.git"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
declare global {
|
|
2
|
+
// eslint-disable-next-line no-unused-vars
|
|
3
|
+
namespace NodeJS {
|
|
4
|
+
// eslint-disable-next-line no-unused-vars
|
|
5
|
+
interface ProcessEnv {
|
|
6
|
+
ADR_TEMPLATE: string;
|
|
7
|
+
ADR_DATE: string;
|
|
8
|
+
VISUAL: string;
|
|
9
|
+
EDITOR: string;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export {};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { Command } from 'commander';
|
|
4
|
+
import { LIB_VERSION } from './version';
|
|
5
|
+
import { generateToc, init, link, listAdrs, newAdr } from './lib/adr';
|
|
6
|
+
import chalk from 'chalk';
|
|
7
|
+
import { workingDir } from './lib/config';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import { getLinksFrom, getTitleFrom } from './lib/manipulator';
|
|
10
|
+
import fs from 'fs/promises';
|
|
11
|
+
|
|
12
|
+
const program = new Command();
|
|
13
|
+
|
|
14
|
+
const collectLinks = (val: string, memo: string[]) => {
|
|
15
|
+
memo.push(val);
|
|
16
|
+
return memo;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const collectSupersedes = (val: string, memo: string[]) => {
|
|
20
|
+
memo.push(val);
|
|
21
|
+
return memo;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
const generateGraph = async (options?: {prefix: string, extension :string}) => {
|
|
25
|
+
let text = 'digraph {\n';
|
|
26
|
+
text += ' node [shape=plaintext];\n';
|
|
27
|
+
text += ' subgraph {\n';
|
|
28
|
+
|
|
29
|
+
const adrs = await listAdrs();
|
|
30
|
+
for (let i = 0; i < adrs.length; i++) {
|
|
31
|
+
const n = i + 1;
|
|
32
|
+
const adrPath = adrs[i];
|
|
33
|
+
const contents = await fs.readFile(adrPath, 'utf8');
|
|
34
|
+
const title = getTitleFrom(contents);
|
|
35
|
+
text += ` _${n} [label="${title}"; URL="${options?.prefix || ''}${path.basename(adrPath, '.md')}${options?.extension}"];\n`;
|
|
36
|
+
if (n > 1) {
|
|
37
|
+
text += ` _${n - 1} -> _${n} [style="dotted", weight=1];\n`;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
text += ' }\n';
|
|
41
|
+
for (let i = 0; i < adrs.length; i++) {
|
|
42
|
+
const n = i + 1;
|
|
43
|
+
const adrPath = adrs[i];
|
|
44
|
+
const contents = await fs.readFile(adrPath, 'utf8');
|
|
45
|
+
const linksInADR = getLinksFrom(contents);
|
|
46
|
+
|
|
47
|
+
for (let j = 0; j < linksInADR.length; j++) {
|
|
48
|
+
if (!linksInADR[j].label.endsWith('by')) {
|
|
49
|
+
text += ` _${n} -> _${linksInADR[j].targetNumber} [label="${linksInADR[j].label}", weight=0]\n`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
text += '}\n';
|
|
56
|
+
console.log(text);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
program.name('adr').version(LIB_VERSION).description('Manage Architecture Decision Logs');
|
|
60
|
+
|
|
61
|
+
program.command('new')
|
|
62
|
+
.argument('<title...>', 'The title of the decision')
|
|
63
|
+
.option('-q, --quiet', 'Do not ask for clarification. If multiple files match the search pattern, an error will be thrown.')
|
|
64
|
+
.option('-s, --supersede <SUPERSEDE>', 'A reference (number or partial filename) of a previous decision that the new decision supercedes.\n'
|
|
65
|
+
+ 'A Markdown link to the superceded ADR is inserted into the Status section.\n'
|
|
66
|
+
+ 'The status of the superceded ADR is changed to record that it has been superceded by the new ADR.', collectSupersedes, [])
|
|
67
|
+
.option('-l, --link "<TARGET:LINK:REVERSE-LINK>"', 'Links the new ADR to a previous ADR.\n'
|
|
68
|
+
+ `${chalk.bold('TARGET')} is a reference (number or partial filename) of a previous decision.\n`
|
|
69
|
+
+ `${chalk.bold('LINK')} is the description of the link created in the new ADR.\n`
|
|
70
|
+
+ `${chalk.bold('REVERSE-LINK')} is the description of the link created in the existing ADR that will refer to the new ADR`, collectLinks, [])
|
|
71
|
+
.action(async (title: string[], options) => {
|
|
72
|
+
try {
|
|
73
|
+
await newAdr(title.join(' '), {
|
|
74
|
+
supersedes: options.supersede,
|
|
75
|
+
date: process.env.ADR_DATE,
|
|
76
|
+
suppressPrompts: options.quiet || false,
|
|
77
|
+
links: options.link
|
|
78
|
+
});
|
|
79
|
+
} catch (e) {
|
|
80
|
+
program.error(chalk.red((e as Error).message), { exitCode: 1 });
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
const generate = program.command('generate');
|
|
85
|
+
|
|
86
|
+
generate.command('toc')
|
|
87
|
+
.option('-p, --prefix <PREFIX>', 'The prefix to use for each file link in the generated TOC.')
|
|
88
|
+
.action((options) => generateToc(options));
|
|
89
|
+
|
|
90
|
+
generate.command('graph')
|
|
91
|
+
.option('-p, --prefix <PREFIX>', 'Prefix each decision file link with PREFIX.')
|
|
92
|
+
.option('-e, --extension <EXTENSION>', 'the file extension of the documents to which generated links refer. Defaults to .html', '.html')
|
|
93
|
+
.action(async (options) => {
|
|
94
|
+
await generateGraph(options);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
program.command('link')
|
|
98
|
+
.argument('<SOURCE>', 'Full or Partial reference number to an ADR')
|
|
99
|
+
.argument('<LINK>', 'The description of the link created in the SOURCE')
|
|
100
|
+
.argument('<TARGET>', 'Full or Partial reference number to an ADR')
|
|
101
|
+
.argument('<REVERSE-LINK>', 'The description of the link created in the TARGET')
|
|
102
|
+
.option('-q, --quiet', 'Do not ask for clarification. If multiple files match the search pattern, an error will be thrown.')
|
|
103
|
+
.action(link);
|
|
104
|
+
|
|
105
|
+
program.command('init').argument('[directory]', 'Initialize a new ADR directory').action(async (directory?: string) => {
|
|
106
|
+
await init(directory);
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
program.command('list').action(async () => {
|
|
110
|
+
const adrs = await listAdrs();
|
|
111
|
+
console.log(adrs.map(adr => path.relative(workingDir(), adr)).join('\n'));
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
program.parse();
|
|
115
|
+
|