diff --git a/.github/styles/vocab.txt b/.github/styles/vocab.txt new file mode 100644 index 0000000000..21045f04dd --- /dev/null +++ b/.github/styles/vocab.txt @@ -0,0 +1,203 @@ +abc +Apdex +api +Api +apis +args +asciidoc +async +Avro +backrub +Balachandran +Bigtable +Blackbox +bool +boolean +Chai +changeset +changesets +Changesets +changset +chanwit +Chanwit +cisphobia +cissexist +classname +cli +cncf +codeblocks +Codecov +codehilite +Codehilite +codeowners +config +Config +configs +const +cookiecutter +css +dariddler +deadnaming +destructured +dev +devs +discoverability +Discoverability +dls +docgen +Dockerfile +Dockerize +dockerode +Docusaurus +eg +Ek +env +Env +eslint +facto +failover +Figma +Firekube +Fredrik +github +Github +Gitlab +graphql +graphviz +Hackathons +haproxy +heroku +Hostname +http +https +img +incentivised +inlinehilite +interop +javascript +Javascript +jq +js +json +jsx +Kaewkasi +Knex +kubectl +kubernetes +learnings +lerna +Lerna +magiclink +mailto +Malus +md +microsite +middleware +minikube +Minikube +misgendering +mkdocs +Mkdocs +monorepo +Monorepo +monorepos +msw +namespace +Namespaces +neuro +newrelic +nginx +Niklas +nohoist +nonces +npm +nvm +oauth +Oauth +Okta +Oldsberg +onboarding +Onboarding +pagerduty +Patrik +Phoen +plantuml +Pomaceous +postgres +pre +prebaked +preconfigured +Preprarer +Prerequisities +productional +Protobuf +proxying +Proxying +pygments +pymdownx +Raghunandan +rankdir +readme +Readme +Redash +repo +Repo +repos +rerender +rollbar +Rollbar +Rollup +Rosaceae +rst +rsync +ruleset +sam +scaffolded +scaffolder +Scaffolder +semlas +Serverless +Sinon +smartsymobls +sparklines +Spotifiers +spotify +Spotify +squidfunk +src +subkey +superfences +Superfences +talkdesk +Talkdesk +tasklist +techdocs +templated +templater +Templater +templaters +Templaters +Thauer +theres +toc +tolerations +Tolerations +toolsets +touchpoints +ui +upvote +url +utils +validators +Voi +Wealthsimple +Weaveworks +xyz +yaml +Zalando +Zhou +Billett +cloudbuild +Grafana +Iain +Snyk diff --git a/.github/workflows/docs-quality-checker.yml b/.github/workflows/docs-quality-checker.yml new file mode 100644 index 0000000000..45cf1dafe3 --- /dev/null +++ b/.github/workflows/docs-quality-checker.yml @@ -0,0 +1,18 @@ +name: Check Markdown files quality + +on: + pull_request: + branches: [master] + paths: + - '**.md' + +jobs: + check-all-files: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: documentation quality check + uses: errata-ai/vale-action@v1.3.0 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 0000000000..fd1ea53b0d --- /dev/null +++ b/.vale.ini @@ -0,0 +1,4 @@ +StylesPath = .github/styles + +[*.md] +BasedOnStyles = Vale diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2b6b49e1f8..85834076d4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -76,6 +76,8 @@ If you're contributing to the backend or CLI tooling, be mindful of cross-platfo Also be sure to skim through our [ADRs](https://github.com/spotify/backstage/tree/master/docs/architecture-decisions) to see if they cover what you're working on. In particular [ADR006: Avoid React.FC and React.SFC](https://github.com/spotify/backstage/blob/master/docs/architecture-decisions/adr006-avoid-react-fc.md) is one to look out for. +If there are any updates in `markdown` file please make sure to run `yarn run lint:docs`. Though it is checked on `lint-staged`. It is required to install [vale](https://docs.errata.ai/vale/install) separately and make sure it is accessed by global command. + # Creating Changesets We use [changesets](https://github.com/atlassian/changesets) to help us prepare releases. It helps us make sure that every package affected by a change gets a proper version number and an entry in its `CHANGELOG.md`. To make the process of generating releases easy. it helps when contributors include changesets with their pull requests. diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index be77f0d4de..1aebbeb0eb 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -4,7 +4,7 @@ Deploying to heroku is relatively easy following these steps. -First, make sure you have the [heroku CLI installed](https://devcenter.heroku.com/articles/heroku-cli) and log into it as well as loging into Heroku's [container registry](https://devcenter.heroku.com/articles/container-registry-and-runtime). +First, make sure you have the [heroku CLI installed](https://devcenter.heroku.com/articles/heroku-cli) and log into it as well as login into Heroku's [container registry](https://devcenter.heroku.com/articles/container-registry-and-runtime). ```bash $ heroku login diff --git a/docs/features/software-templates/extending/create-your-own-preparer.md b/docs/features/software-templates/extending/create-your-own-preparer.md index e354c0941e..80287c6ce1 100644 --- a/docs/features/software-templates/extending/create-your-own-preparer.md +++ b/docs/features/software-templates/extending/create-your-own-preparer.md @@ -88,7 +88,7 @@ Some good examples exist here: - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/src/scaffolder/stages/prepare/file.ts - https://github.com/spotify/backstage/blob/master/plugins/scaffolder-backend/src/scaffolder/stages/prepare/github.ts -### Registerinng your own Preparer +### Registering your own Preparer You can register the preparer that you have created with the `PreparerBuilder` by using the `PreparerKey` from the Catalog, for example like this: diff --git a/docs/features/techdocs/FAQ.md b/docs/features/techdocs/FAQ.md index 1c5c4795be..e81e9d82c7 100644 --- a/docs/features/techdocs/FAQ.md +++ b/docs/features/techdocs/FAQ.md @@ -35,4 +35,4 @@ well as a selection of Python Markdown extensions that TechDocs supports. Not right now. We are currently using MkDocs to generate the documentation from source, so the files have to be in Markdown format. However, in the future we want to support other static site generators which will make it possible to use -otherfile formats. +other file formats. diff --git a/docs/plugins/testing.md b/docs/plugins/testing.md index bb5a577c7d..c6e1599786 100644 --- a/docs/plugins/testing.md +++ b/docs/plugins/testing.md @@ -166,7 +166,7 @@ because it fulfills all the principles above: ✓ **Fulfills Input/Output Principle**: Verifies the output changes when the input changes -✓ **Fufills Blackbox Principle**: Does not verify _how_ the `` +✓ **Fulfills Blackbox Principle**: Does not verify _how_ the `` component is mounted, just that it is mounted in response to the input. ✓ **Fulfills Scalability Principle**: If we decide to refactor the entire way diff --git a/docs/reference/utility-apis/AlertApi.md b/docs/reference/utility-apis/AlertApi.md index d096276c3b..6219f520f5 100644 --- a/docs/reference/utility-apis/AlertApi.md +++ b/docs/reference/utility-apis/AlertApi.md @@ -73,7 +73,7 @@ Referenced by: [alert\$](#alert). ### Observer -This file contains non-react related core types used throught Backstage. +This file contains non-react related core types used through Backstage. Observer interface for consuming an Observer, see TC39. diff --git a/docs/reference/utility-apis/AppThemeApi.md b/docs/reference/utility-apis/AppThemeApi.md index d37282adea..eb35eb38ef 100644 --- a/docs/reference/utility-apis/AppThemeApi.md +++ b/docs/reference/utility-apis/AppThemeApi.md @@ -135,7 +135,7 @@ Referenced by: [activeThemeId\$](#activethemeid). ### Observer -This file contains non-react related core types used throught Backstage. +This file contains non-react related core types used through Backstage. Observer interface for consuming an Observer, see TC39. diff --git a/docs/reference/utility-apis/ErrorApi.md b/docs/reference/utility-apis/ErrorApi.md index 4de58b34a1..762d2016d5 100644 --- a/docs/reference/utility-apis/ErrorApi.md +++ b/docs/reference/utility-apis/ErrorApi.md @@ -93,7 +93,7 @@ Referenced by: [error\$](#error). ### Observer -This file contains non-react related core types used throught Backstage. +This file contains non-react related core types used through Backstage. Observer interface for consuming an Observer, see TC39. diff --git a/docs/reference/utility-apis/OAuthRequestApi.md b/docs/reference/utility-apis/OAuthRequestApi.md index ac11764682..1328aabeec 100644 --- a/docs/reference/utility-apis/OAuthRequestApi.md +++ b/docs/reference/utility-apis/OAuthRequestApi.md @@ -11,7 +11,8 @@ The following Utility API implements this type: ### createAuthRequester() A utility for showing login popups or similar things, and merging together -multiple requests for different scopes into one request that inclues all scopes. +multiple requests for different scopes into one request that includes all +scopes. The passed in options provide information about the login provider, and how to handle auth requests. @@ -30,7 +31,7 @@ createAuthRequester<AuthResponse>( ### authRequest\$() -Observers panding auth requests. The returned observable will emit all current +Observers pending auth requests. The returned observable will emit all current active auth request, at most one for each created auth requester. Each request has its own info about the login provider, forwarded from the auth @@ -156,7 +157,7 @@ Referenced by: [authRequest\$](#authrequest). ### Observer -This file contains non-react related core types used throught Backstage. +This file contains non-react related core types used through Backstage. Observer interface for consuming an Observer, see TC39. diff --git a/docs/reference/utility-apis/SessionApi.md b/docs/reference/utility-apis/SessionApi.md index 5e40b3317b..e7a9e58c59 100644 --- a/docs/reference/utility-apis/SessionApi.md +++ b/docs/reference/utility-apis/SessionApi.md @@ -81,7 +81,7 @@ Referenced by: [sessionState\$](#sessionstate). ### Observer -This file contains non-react related core types used throught Backstage. +This file contains non-react related core types used through Backstage. Observer interface for consuming an Observer, see TC39. diff --git a/docs/reference/utility-apis/SessionStateApi.md b/docs/reference/utility-apis/SessionStateApi.md index c1821f2381..81f25aa349 100644 --- a/docs/reference/utility-apis/SessionStateApi.md +++ b/docs/reference/utility-apis/SessionStateApi.md @@ -62,7 +62,7 @@ Referenced by: [sessionState\$](#sessionstate). ### Observer -This file contains non-react related core types used throught Backstage. +This file contains non-react related core types used through Backstage. Observer interface for consuming an Observer, see TC39. diff --git a/docs/reference/utility-apis/StorageApi.md b/docs/reference/utility-apis/StorageApi.md index 3fd75a42d6..e7d5131ff9 100644 --- a/docs/reference/utility-apis/StorageApi.md +++ b/docs/reference/utility-apis/StorageApi.md @@ -35,7 +35,7 @@ remove(key: string): Promise<void> ### set() -Save persistant data, and emit messages to anyone that is using observe\$ for +Save persistent data, and emit messages to anyone that is using observe\$ for this key
@@ -85,7 +85,7 @@ Referenced by: [observe\$](#observe), [StorageApi](#storageapi).
 
 ### Observer
 
-This file contains non-react related core types used throught Backstage.
+This file contains non-react related core types used through Backstage.
 
 Observer interface for consuming an Observer, see TC39.
 
@@ -129,7 +129,7 @@ export interface StorageApi {
   remove(key: string): Promise<void>;
 
   /**
-   * Save persistant data, and emit messages to anyone that is using observe$ for this key
+   * Save persistent data, and emit messages to anyone that is using observe$ for this key
    *
    * @param {String} key Unique key associated with the data.
    */
diff --git a/package.json b/package.json
index 45e13d30f4..b9c84a4d90 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
     "test": "lerna run test --since origin/master -- --coverage",
     "test:all": "lerna run test -- --coverage",
     "lint": "lerna run lint --since origin/master --",
+    "lint:docs": "node ./scripts/check-docs-quality",
     "lint:all": "lerna run lint --",
     "lint:type-deps": "node scripts/check-type-dependencies.js",
     "docgen": "lerna run docgen",
@@ -46,7 +47,8 @@
     "lerna": "^3.20.2",
     "lint-staged": "^10.1.0",
     "prettier": "^2.0.5",
-    "recursive-readdir": "^2.2.2"
+    "recursive-readdir": "^2.2.2",
+    "shx": "^0.3.2"
   },
   "husky": {
     "hooks": {
@@ -61,6 +63,9 @@
     ],
     "*.{json,md}": [
       "prettier --write"
+    ],
+    "*.md": [
+      "vale"
     ]
   },
   "jest": {
diff --git a/packages/core/src/components/StructuredMetadataTable/README.md b/packages/core/src/components/StructuredMetadataTable/README.md
index 452d32490f..60952e5e34 100644
--- a/packages/core/src/components/StructuredMetadataTable/README.md
+++ b/packages/core/src/components/StructuredMetadataTable/README.md
@@ -23,7 +23,7 @@ The component itself only handles the display area, so you can use standard JS t
 
 This will step through each of the keys and based on their types display them in a logical way.
 
-### Primatives
+### Primitives
 
 Any non complex value will be displayed using `{value}` which will just output the value as text.
 
diff --git a/packages/techdocs-container/mock-docs/docs/index.md b/packages/techdocs-container/mock-docs/docs/index.md
index 3c323d6fc1..94a53acfa3 100644
--- a/packages/techdocs-container/mock-docs/docs/index.md
+++ b/packages/techdocs-container/mock-docs/docs/index.md
@@ -1,7 +1,7 @@
 ## hello mock docs
 
 !!! test
-Testing somethin
+Testing something
 
 Abbreviations:
 Some text about MOCDOC
diff --git a/plugins/api-docs/README.md b/plugins/api-docs/README.md
index 17f354e997..ecc0e5a560 100644
--- a/plugins/api-docs/README.md
+++ b/plugins/api-docs/README.md
@@ -18,7 +18,7 @@ Right now, the following API formats are supported:
 - [AsyncAPI](https://www.asyncapi.com/docs/specifications/latest/)
 - [GraphQL](https://graphql.org/learn/schema/)
 
-Other formats are displayed as plain text, but this can easily be extented.
+Other formats are displayed as plain text, but this can easily be extended.
 
 To fill the catalog with APIs, [provide entities of kind API](https://backstage.io/docs/features/software-catalog/descriptor-format#kind-api).
 To link that an component implements an API, see [`implementsApis` property on components](https://backstage.io/docs/features/software-catalog/descriptor-format#specimplementsapis-optional).
diff --git a/plugins/cost-insights/README.md b/plugins/cost-insights/README.md
index ce0b68383b..221f9f37d8 100644
--- a/plugins/cost-insights/README.md
+++ b/plugins/cost-insights/README.md
@@ -81,7 +81,7 @@ costInsights:
 
 In the `Cost Overview` panel, users can choose from a dropdown of business metrics to see costs as they relate to a metric, such as daily active users. Metrics must be defined as keys on the `metrics` field. A user-friendly name is **required**. Metrics will be provided to the `getDailyCost` and `getProjectCosts` API methods via the `metric` parameter.
 
-**Note:** Cost Insights displays daily cost without a metric by default. The dropdown text for this default can be overriden by assigning it a value on the `dailyCost` field.
+**Note:** Cost Insights displays daily cost without a metric by default. The dropdown text for this default can be overridden by assigning it a value on the `dailyCost` field.
 
 ```yaml
 ## ./app-config.yaml
diff --git a/scripts/check-docs-quality.js b/scripts/check-docs-quality.js
new file mode 100755
index 0000000000..61968a2ac0
--- /dev/null
+++ b/scripts/check-docs-quality.js
@@ -0,0 +1,68 @@
+#!/usr/bin/env node
+/*
+ * Copyright 2020 Spotify AB
+ *
+ * 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.
+ */
+const { execSync, spawnSync } = require('child_process');
+const path = require('path');
+
+const listFilesTrackedByGit = 'git ls-files';
+
+const inheritStdIo = {
+  stdio: 'inherit',
+};
+
+const ERROR_MESSAGE =
+  'Please install vale linter(https://docs.errata.ai/vale/install). Ignore this message if already installed.\n';
+
+// xargs is not supported by shx.
+if (process.platform === 'win32') {
+  const validMDFilesCommand = `${listFilesTrackedByGit} | .\\node_modules\\.bin\\shx grep ".md"`;
+  try {
+    // get list of all md files except in directories of gitignore.
+    let filesToLint = execSync(validMDFilesCommand, {
+      stdio: ['ignore', 'pipe', 'inherit'],
+    });
+
+    // set all file(s) path as absolute path
+    filesToLint = filesToLint
+      .toString()
+      .split('\n')
+      .map(filepath => (filepath ? path.join(process.cwd(), filepath) : null))
+      .filter(Boolean);
+
+    const output = spawnSync('vale', filesToLint, inheritStdIo);
+
+    // if the command does not succeed
+    if (output.status !== 0) {
+      // if it contains system level error. [in this case vale does not exist]
+      if (output.error) {
+        console.error(ERROR_MESSAGE);
+      }
+      process.exit(1);
+    }
+  } catch (e) {
+    console.error(e.message);
+    process.exit(1);
+  }
+} else {
+  const validMDFilesCommand = `${listFilesTrackedByGit} | ./node_modules/.bin/shx grep ".md"`;
+  // use xargs
+  try {
+    execSync(`${validMDFilesCommand} | xargs vale`, inheritStdIo);
+  } catch (e) {
+    console.error(ERROR_MESSAGE);
+    process.exit(1);
+  }
+}
diff --git a/yarn.lock b/yarn.lock
index 9cee3c3602..c5429eafce 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10430,6 +10430,11 @@ es6-iterator@^2.0.3, es6-iterator@~2.0.3:
     es5-ext "^0.10.35"
     es6-symbol "^3.1.1"
 
+es6-object-assign@^1.0.3:
+  version "1.1.0"
+  resolved "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz#c2c3582656247c39ea107cb1e6652b6f9f24523c"
+  integrity sha1-wsNYJlYkfDnqEHyx5mUrb58kUjw=
+
 es6-promise@^4.0.3:
   version "4.2.8"
   resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a"
@@ -20703,7 +20708,7 @@ shell-quote@1.7.2:
   resolved "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz#67a7d02c76c9da24f99d20808fcaded0e0e04be2"
   integrity sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==
 
-shelljs@^0.8.2, shelljs@^0.8.3:
+shelljs@^0.8.1, shelljs@^0.8.2, shelljs@^0.8.3:
   version "0.8.4"
   resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2"
   integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ==
@@ -20724,6 +20729,15 @@ shortid@^2.2.14:
   dependencies:
     nanoid "^2.1.0"
 
+shx@^0.3.2:
+  version "0.3.2"
+  resolved "https://registry.npmjs.org/shx/-/shx-0.3.2.tgz#40501ce14eb5e0cbcac7ddbd4b325563aad8c123"
+  integrity sha512-aS0mWtW3T2sHAenrSrip2XGv39O9dXIFUqxAEWHEOS1ePtGIBavdPJY1kE2IHl14V/4iCbUiNDPGdyYTtmhSoA==
+  dependencies:
+    es6-object-assign "^1.0.3"
+    minimist "^1.2.0"
+    shelljs "^0.8.1"
+
 side-channel@^1.0.2:
   version "1.0.2"
   resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.2.tgz#df5d1abadb4e4bf4af1cd8852bf132d2f7876947"