diff --git a/.github/workflows/vale.yml b/.github/workflows/vale.yml new file mode 100644 index 000000000..d212a0b3b --- /dev/null +++ b/.github/workflows/vale.yml @@ -0,0 +1,49 @@ +name: Vale + +on: + pull_request: + types: [opened, synchronize, reopened] + paths: + - 'website/**/*.md' + - '.vale.ini' + - '.vale/**' + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +permissions: + contents: read + checks: write + pull-requests: write + +jobs: + vale: + name: Lint prose + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Get changed files + id: changed-files + uses: tj-actions/changed-files@v45 + with: + files: | + website/**/*.md + files_ignore: | + website/about/legal-disclosure.md + website/archived/** + separator: "," + + - name: Vale + if: steps.changed-files.outputs.any_changed == 'true' + uses: vale-cli/vale-action@v2.1.1 + with: + files: '${{ steps.changed-files.outputs.all_changed_files }}' + vale_flags: "--minAlertLevel=warning" + reporter: github-pr-review + fail_on_error: true + filter_mode: file + separator: "," diff --git a/.vale.ini b/.vale.ini new file mode 100644 index 000000000..36e945df8 --- /dev/null +++ b/.vale.ini @@ -0,0 +1,19 @@ +StylesPath = .vale/styles +MinAlertLevel = warning + +Vocab = GardenerTerms, ThirdPartyProducts, TechJargon, General + +IgnoredScopes = code, tt, code block + +[*.md] +BasedOnStyles = Gardener + +TokenIgnores = (`[^`]+`), (<[^>]+>), (v[0-9]+(?:\.[0-9]+)*(?:alpha[0-9]+|beta[0-9]+)?), (/[^\s]+), (https?://\S+), ([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]+), (\w+\(s\)), (\*+\w+\**|\w+\*+) + +BlockIgnores = (?s)(\{\{.*?\}\}) + +[website/about/legal-disclosure.md] +BasedOnStyles = + +[website/archived/**] +BasedOnStyles = diff --git a/.vale/styles/Gardener/Articles.yml b/.vale/styles/Gardener/Articles.yml new file mode 100644 index 000000000..84c08c219 --- /dev/null +++ b/.vale/styles/Gardener/Articles.yml @@ -0,0 +1,40 @@ +extends: substitution +message: "Use '%s' instead of '%s'. The article depends on pronunciation, not spelling." +link: https://github.com/gardener/documentation/blob/master/website/documentation/contribute/documentation/style-guide/_index.md +level: warning +ignorecase: false +action: + name: replace +swap: + # Acronyms starting with vowel-sound letters that need "an" + # A (ay), E (ee), F (ef), H (aitch), I (eye), L (el), M (em), N (en), O (oh), R (ar), S (es), X (ex) + 'a OS': an OS + 'a HA': an HA + 'a HTTP': an HTTP + 'a HTML': an HTML + 'a SSH': an SSH + 'a SSL': an SSL + 'a API': an API + 'a OIDC': an OIDC + 'a OCI': an OCI + 'a SSD': an SSD + 'a SDK': an SDK + 'a XML': an XML + 'a IDE': an IDE + 'a IAM': an IAM + 'a HPA': an HPA + 'a FAQ': an FAQ + 'a ETCD': an ETCD + 'a NFS': an NFS + 'a RBAC': an RBAC + # Acronyms starting with consonant-sound letters that need "a" + # U (yoo), V (vee), W (double-yoo), C (see) when starts acronym + 'an VM': a VM + 'an VPA': a VPA + 'an VPC': a VPC + 'an VPN': a VPN + 'an URL': a URL + 'an URI': a URI + 'an GPU': a GPU + 'an CPU': a CPU + 'an SIG': a SIG diff --git a/.vale/styles/Gardener/CommandPrompt.yml b/.vale/styles/Gardener/CommandPrompt.yml new file mode 100644 index 000000000..ec2a16d80 --- /dev/null +++ b/.vale/styles/Gardener/CommandPrompt.yml @@ -0,0 +1,8 @@ +extends: existence +message: "Don't include the command prompt '%s' in code blocks. Show only the command itself." +level: error +link: https://github.com/gardener/documentation/blob/master/website/documentation/contribute/documentation/formatting-guide.md +scope: raw +tokens: + - '```[a-z]*\n\$\s' + - '`\$\s\w' diff --git a/.vale/styles/Gardener/Links.yml b/.vale/styles/Gardener/Links.yml new file mode 100644 index 000000000..f6867263e --- /dev/null +++ b/.vale/styles/Gardener/Links.yml @@ -0,0 +1,13 @@ +extends: existence +message: "Avoid generic link text '%s'. Use a descriptor of the link's destination instead." +level: warning +link: https://github.com/gardener/documentation/blob/master/website/documentation/contribute/documentation/style-guide/_index.md +scope: raw +nonword: true +tokens: + - '\[here\]\(' + - '\[click here\]\(' + - '\[this link\]\(' + - '\[this page\]\(' + - '\[read more\]\(' + - '\[learn more\]\(' diff --git a/.vale/styles/Gardener/SecondPerson.yml b/.vale/styles/Gardener/SecondPerson.yml new file mode 100644 index 000000000..a21f9bfbd --- /dev/null +++ b/.vale/styles/Gardener/SecondPerson.yml @@ -0,0 +1,15 @@ +extends: substitution +message: "Use '%s' instead of '%s'. Address the reader directly as 'you'." +level: warning +link: https://github.com/gardener/documentation/blob/master/website/documentation/contribute/documentation/style-guide/_index.md +action: + name: replace +ignorecase: true +swap: + 'the user can': 'you can' + 'the user must': 'you must' + 'the user should': 'you should' + 'the user needs to': 'you need to' + 'the user has to': 'you have to' + 'the user is': 'you are' + 'the user wants': 'you want' diff --git a/.vale/styles/Gardener/Spelling.yml b/.vale/styles/Gardener/Spelling.yml new file mode 100644 index 000000000..fa0eb2f89 --- /dev/null +++ b/.vale/styles/Gardener/Spelling.yml @@ -0,0 +1,28 @@ +extends: spelling +message: "Did you really mean '%s'?" +level: error +append: true +ignore: + - GardenerTerms/accept.txt + - ThirdPartyProducts/accept.txt + - TechJargon/accept.txt + - Places/accept.txt + - General/accept.txt +filters: + # Uppercase acronyms (e.g. HTTP, YAML, REST) + - '[A-Z]{2,}' + # Uppercase acronym plurals (e.g. CAs, VMs, CRDs, APIs) + - '[A-Z]{2,}s\b' + # camelCase and PascalCase identifiers (e.g. kubeConfig, GardenNamespace) + - '[a-z]+[A-Z][a-zA-Z]+' + - '[A-Z][a-z]+[A-Z][a-zA-Z]+' + # Tokens with digits (e.g. IPv4, log4j, int64, v1alpha1) + - '[a-zA-Z]*[0-9]+[a-zA-Z0-9]*' + # CLI flags (e.g. --flag, -f) + - '--?[a-zA-Z][a-zA-Z0-9-]+' + # File extensions and dot-separated identifiers (e.g. .yaml, cert.gardener.cloud) + - '\.[a-zA-Z]{1,6}\b' + # Underscore-separated identifiers (e.g. config_key, _source) + - '_?[a-zA-Z]+_[a-zA-Z0-9_]+' + # Version strings (e.g. v1, v1.2, v1alpha1, v2beta1) + - '[vV][0-9]+(?:\.[0-9]+)*(?:alpha[0-9]+|beta[0-9]+)?' diff --git a/.vale/styles/Gardener/Terms.yml b/.vale/styles/Gardener/Terms.yml new file mode 100644 index 000000000..2c0dd9392 --- /dev/null +++ b/.vale/styles/Gardener/Terms.yml @@ -0,0 +1,17 @@ +extends: substitution +message: "Use '%s' instead of '%s'." +level: error +action: + name: replace +ignorecase: false +swap: + '(?/dev/null 2>&1; then \ + echo "Vale is already installed: $$(vale --version)"; \ + else \ + echo "Installing Vale..."; \ + mkdir -p bin; \ + if [ "$$(uname)" = "Darwin" ]; then \ + if [ "$$(uname -m)" = "arm64" ]; then \ + curl -sL https://github.com/vale-cli/vale/releases/download/v3.14.2/vale_3.14.2_macOS_arm64.tar.gz | tar -xz -C bin vale; \ + else \ + curl -sL https://github.com/vale-cli/vale/releases/download/v3.14.2/vale_3.14.2_macOS_64-bit.tar.gz | tar -xz -C bin vale; \ + fi; \ + elif [ "$$(uname)" = "Linux" ]; then \ + if [ "$$(uname -m)" = "aarch64" ] || [ "$$(uname -m)" = "arm64" ]; then \ + curl -sL https://github.com/vale-cli/vale/releases/download/v3.14.2/vale_3.14.2_Linux_arm64.tar.gz | tar -xz -C bin vale; \ + else \ + curl -sL https://github.com/vale-cli/vale/releases/download/v3.14.2/vale_3.14.2_Linux_64-bit.tar.gz | tar -xz -C bin vale; \ + fi; \ + elif echo "$$(uname -s)" | grep -qi "mingw\|cygwin\|msys"; then \ + curl -sL https://github.com/vale-cli/vale/releases/download/v3.14.2/vale_3.14.2_Windows_64-bit.zip -o bin/vale.zip; \ + unzip -q bin/vale.zip vale.exe -d bin; \ + rm -f bin/vale.zip; \ + else \ + echo "Unsupported OS. Install Vale manually: https://vale.sh/docs/install"; \ + exit 1; \ + fi; \ + echo "Vale installed to bin/. Add bin/ to your PATH or run: bin/vale"; \ + fi + +.PHONY: vale-run +vale-run: ## Lint changed website markdown files with Vale + @CHANGED=$$(git diff --name-only --diff-filter=d HEAD -- 'website/**/*.md' | \ + grep -v '^website/about/legal-disclosure\.md' | \ + grep -v '^website/archived/'); \ + if [ -n "$$CHANGED" ]; then \ + vale $$CHANGED; \ + else \ + echo "No changed .md files to lint."; \ + fi + +.PHONY: vale +vale: vale-install vale-run ## Install Vale and lint changed website markdown files \ No newline at end of file