├── docs ├── CHANGELOG.md ├── sources │ ├── write │ │ ├── front-matter │ │ │ └── twitter.png │ │ ├── style-guide │ │ │ ├── _index.md │ │ │ └── security │ │ │ │ └── index.md │ │ └── _index.md │ ├── shared │ │ ├── index.md │ │ ├── make-help.md │ │ ├── hugo-error-example-bad-link.md │ │ └── refs-example.md │ ├── review │ │ └── _index.md │ └── _index.md ├── Makefile ├── variables.mk ├── static │ └── templates │ │ ├── section-template.md │ │ └── concept-template.md └── README.md ├── vale ├── Google │ ├── vocab.txt │ ├── meta.json │ ├── Will.yml │ ├── Parens.yml │ ├── Colons.yml │ ├── Ordinal.yml │ ├── Semicolons.yml │ ├── OxfordComma.yml │ ├── Quotes.yml │ ├── Ellipses.yml │ ├── Periods.yml │ ├── Ranges.yml │ ├── Gender.yml │ ├── AMPM.yml │ ├── Slang.yml │ ├── Spacing.yml │ ├── Units.yml │ ├── EmDash.yml │ ├── Spelling.yml │ ├── We.yml │ ├── Exclamation.yml │ ├── LyHyphens.yml │ ├── OptionalPlurals.yml │ ├── Latin.yml │ ├── FirstPerson.yml │ ├── HeadingPunctuation.yml │ ├── DateFormat.yml │ ├── Headings.yml │ ├── Contractions.yml │ ├── Acronyms.yml │ └── GenderBias.yml ├── fixtures │ └── Grafana │ │ ├── OK │ │ ├── testvalid.md │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ └── testinvalid.md │ │ ├── HTTP │ │ ├── testvalid.golden │ │ ├── testinvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ └── testvalid.md │ │ ├── SQL │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ └── testinvalid.md │ │ ├── Wish │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── Admin │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── Admonitions │ │ ├── testvalid.md │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ └── testinvalid.md │ │ ├── Agentless │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── AltText │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testinvalid.golden │ │ └── testvalid.md │ │ ├── AndOr │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── Archives │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── DropDown │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── Gerunds │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── Headings │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ └── testinvalid.md │ │ ├── Latin │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── OAuth │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── Ordinal │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── React │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── ReferTo │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── RepeatedWords │ │ ├── testvalid.md │ │ ├── testvalid.golden │ │ ├── testinvalid.md │ │ ├── filter.expr │ │ └── testinvalid.golden │ │ ├── Wordlist │ │ ├── testvalid.golden │ │ ├── testinvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ └── testvalid.md │ │ ├── DatadogProxy │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── Kubernetes │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── ProductPossessives │ │ ├── testvalid.md │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── Quickstart │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── Shortcodes │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── SmartQuotes │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ ├── AmazonCloudWatch │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── ApacheProjectNames │ │ ├── testvalid.golden │ │ ├── testinvalid.md │ │ ├── filter.expr │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── CommandLinePrompts │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testinvalid.md │ │ ├── testvalid.md │ │ └── testinvalid.golden │ │ ├── DocumentationTeam │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden │ │ └── PrometheusExporters │ │ ├── testvalid.golden │ │ ├── filter.expr │ │ ├── testvalid.md │ │ ├── testinvalid.md │ │ └── testinvalid.golden ├── Grafana │ └── styles │ │ ├── config │ │ ├── vocabularies │ │ │ └── Grafana │ │ │ │ └── accept.txt │ │ ├── dictionaries │ │ │ ├── en_US-places.dic │ │ │ ├── en_US-places.wordlist │ │ │ ├── en_US-places.aff │ │ │ ├── en_US-grafana.jsonnet │ │ │ ├── Makefile │ │ │ └── en_US-grafana.aff │ │ └── scripts │ │ │ ├── go.mod │ │ │ ├── tengo.go │ │ │ ├── Relref.tengo │ │ │ ├── Paragraphs.tengo │ │ │ ├── SmartQuotes.tengo │ │ │ ├── go.sum │ │ │ ├── CommandLinePrompts.tengo │ │ │ └── Paragraphs_test.go │ │ └── Grafana │ │ ├── RepeatedWords.yml │ │ ├── DatadogProxy.yml │ │ ├── GoogleSemicolons.yml │ │ ├── GoogleOxfordComma.yml │ │ ├── Wish.yml │ │ ├── ReadabilityLIX.yml │ │ ├── GooglePeriods.yml │ │ ├── ReadabilitySMOG.yml │ │ ├── EndToEnd.yml │ │ ├── GoogleEllipses.yml │ │ ├── ReadabilityGunningFog.yml │ │ ├── AllowsTo.yml │ │ ├── Please.yml │ │ ├── Latin.yml │ │ ├── GoogleRanges.yml │ │ ├── GoogleGender.yml │ │ ├── ReadabilityAutomatedReadability.yml │ │ ├── ReadabilityColemanLiau.yml │ │ ├── ReadabilityFleschKincaid.yml │ │ ├── DocumentationTeam.yml │ │ ├── GoogleAMPM.yml │ │ ├── GoogleSpacing.yml │ │ ├── GoogleSpelling.yml │ │ ├── GoogleSlang.yml │ │ ├── OAuth.yml │ │ ├── React.yml │ │ ├── ReadabilityFleschReadingEase.yml │ │ ├── Exclamation.yml │ │ ├── GoogleEmDash.yml │ │ ├── Admin.yml │ │ ├── GoogleEnDash.yml │ │ ├── Parentheses.yml │ │ ├── ApacheProjectNames.yml │ │ ├── GoogleWill.yml │ │ ├── MetaMonitoring.yml │ │ ├── PrometheusExporters.yml │ │ ├── GoogleProductNames.yml │ │ ├── Ordinal.yml │ │ ├── SelfManaged.yml │ │ ├── GoogleLyHyphens.yml │ │ ├── GoogleOptionalPlurals.yml │ │ ├── Archives.yml │ │ ├── DialogBox.yml │ │ ├── AltText.yml │ │ ├── Relref.yml │ │ ├── GoogleFirstPerson.yml │ │ ├── README.yml │ │ ├── DropDown.yml │ │ ├── Paragraphs.yml │ │ ├── AmazonCloudWatch.yml │ │ ├── GoogleHeadingPunctuation.yml │ │ ├── CHANGELOG.yml │ │ ├── Quickstart.yml │ │ ├── AndOr.yml │ │ ├── ReferTo.yml │ │ ├── CommandLinePrompts.yml │ │ ├── GoogleDateFormat.yml │ │ ├── GrafanaCom.yml │ │ ├── SmartQuotes.yml │ │ ├── We.yml │ │ ├── AmazonProductNames.yml │ │ ├── Simple.yml │ │ ├── Admonitions.yml │ │ ├── Shortcodes.yml │ │ ├── OK.yml │ │ ├── Agentless.yml │ │ ├── Kubernetes.yml │ │ ├── GoogleContractions.yml │ │ ├── SQL.yml │ │ ├── Timeless.yml │ │ ├── Gerunds.yml │ │ ├── Spelling.yml │ │ ├── Acronyms.yml │ │ └── GoogleGenderBias.yml ├── Readability │ ├── meta.json │ ├── SMOG.yml │ ├── GunningFog.yml │ ├── AutomatedReadability.yml │ ├── ColemanLiau.yml │ ├── FleschKincaid.yml │ ├── FleschReadingEase.yml │ └── LIX.yml ├── .vale.ini ├── dictionary │ ├── y.jsonnet │ ├── z.jsonnet │ ├── x.jsonnet │ ├── q.jsonnet │ ├── n.jsonnet │ ├── word.jsonnet │ ├── e.jsonnet │ ├── h.jsonnet │ ├── i.jsonnet │ ├── f.jsonnet │ ├── w.jsonnet │ ├── l.jsonnet │ ├── j.jsonnet │ ├── m.jsonnet │ ├── u.jsonnet │ ├── v.jsonnet │ ├── o.jsonnet │ ├── b.jsonnet │ ├── k.jsonnet │ ├── d.jsonnet │ ├── t.jsonnet │ └── g.jsonnet ├── .vale-config │ └── 1-Hugo.ini ├── tools │ ├── go.mod │ ├── .golangci.yml │ └── cmd │ │ └── filter-sarif │ │ ├── sarif │ │ └── sarif.go │ │ └── testdata │ │ └── 102941-filtered.sarif ├── AmazonProductNames.jsonnet ├── ApacheProjectNames.jsonnet ├── GoogleProductNames.jsonnet ├── README.md ├── .vale.jsonnet ├── ProductPossessives.jsonnet ├── Acronyms.jsonnet ├── Dockerfile ├── WordList.jsonnet ├── dictionary.libsonnet └── readability.jsonnet ├── tools ├── cmd │ └── generate-documentation │ │ ├── ruleDefault.tmpl │ │ ├── ruleExistence.tmpl │ │ ├── ruleSubstitution.tmpl │ │ ├── rule.tmpl │ │ └── page.tmpl ├── exit │ └── exit.go ├── rwfilefs │ ├── rwfilefs.go │ ├── mapfs.go │ └── osdirfs.go ├── go.mod └── hugo │ └── hugo.go ├── scripts ├── spellings └── add-date ├── add-to-docs-project ├── project-id.graphql ├── add-to-project.graphql ├── issues.graphql ├── package.json └── index.mts ├── .gitignore ├── .vale.ini ├── yarn.lock ├── deploy-preview ├── Dockerfile ├── config.yaml └── urls ├── .policy.yml ├── .github ├── PULL_REQUEST_TEMPLATE.md ├── workflows │ ├── prettier.yml │ ├── publish-technical-documentation.yml │ ├── validate-policy-bot-config.yml │ ├── image.yml │ ├── deploy-pr-preview.yml │ ├── from-comment.js │ ├── validate-documentation.yml │ └── test-publish-technical-documentation-release.yml └── CODEOWNERS ├── package.json ├── publish-technical-documentation-release └── determine-release-branch ├── README.md └── readability └── action.yml /docs/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/Google/vocab.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OK/testvalid.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/HTTP/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OK/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SQL/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wish/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admin/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admonitions/testvalid.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Agentless/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AltText/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AndOr/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Archives/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DropDown/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Gerunds/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/HTTP/testinvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Headings/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Latin/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OAuth/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Ordinal/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/React/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ReferTo/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/RepeatedWords/testvalid.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wordlist/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admonitions/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DatadogProxy/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Kubernetes/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ProductPossessives/testvalid.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Quickstart/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/RepeatedWords/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Shortcodes/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SmartQuotes/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wordlist/testinvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AmazonCloudWatch/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ApacheProjectNames/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/CommandLinePrompts/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DocumentationTeam/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OK/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.OK" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ProductPossessives/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/PrometheusExporters/testvalid.golden: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admin/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Admin" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AndOr/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.AndOr" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/HTTP/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.HTTP" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Latin/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Latin" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OAuth/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.OAuth" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/React/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.React" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SQL/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.SQL" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wish/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Wish" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AltText/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.AltText" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Gerunds/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Gerunds" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Ordinal/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Ordinal" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ReferTo/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.ReferTo" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Agentless/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Agentless" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Archives/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Archives" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DropDown/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.DropDown" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Headings/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Headings" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Kubernetes/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Kubernetes" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Quickstart/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Quickstart" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/RepeatedWords/testinvalid.md: -------------------------------------------------------------------------------- 1 | the the 2 | no no 3 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Shortcodes/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Shortcodes" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wish/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - wish 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wordlist/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Wordlist" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admin/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - admin 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admonitions/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.Admonitions" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DatadogProxy/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.DatadogProxy" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OAuth/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - OAuth 2.0 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/React/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - React 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SmartQuotes/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.SmartQuotes" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admin/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - administrator 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Gerunds/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | # Play games 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Headings/testvalid.md: -------------------------------------------------------------------------------- 1 | # Set up Beyla 2 | 3 | # AWS logs 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/RepeatedWords/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.RepeatedWords" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wish/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - need 4 | - want 5 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/vocabularies/Grafana/accept.txt: -------------------------------------------------------------------------------- 1 | Largest Contentful Paint 2 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AmazonCloudWatch/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.AmazonCloudWatch" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ApacheProjectNames/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - Mesos 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DocumentationTeam/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.DocumentationTeam" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DropDown/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - drop-down menu 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Gerunds/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | # Playing games 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Quickstart/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - quick start 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ReferTo/testvalid.md: -------------------------------------------------------------------------------- 1 | In order to check out the git repository. 2 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AltText/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - ![](/path/to/image/) 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ApacheProjectNames/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.ApacheProjectNames" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/CommandLinePrompts/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.CommandLinePrompts" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DatadogProxy/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - Datadog proxy 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ProductPossessives/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.ProductPossessives" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ProductPossessives/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - Grafana's 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/PrometheusExporters/filter.expr: -------------------------------------------------------------------------------- 1 | .Name == "Grafana.PrometheusExporters" -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DropDown/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - dropdown 4 | - drop down 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/PrometheusExporters/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - Node Exporter 4 | -------------------------------------------------------------------------------- /tools/cmd/generate-documentation/ruleDefault.tmpl: -------------------------------------------------------------------------------- 1 | {{ codify (format (escapeShortcodes .Message)) }} 2 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/dictionaries/en_US-places.dic: -------------------------------------------------------------------------------- 1 | 2 2 | Ashburn po:noun 3 | Dublin po:noun 4 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/dictionaries/en_US-places.wordlist: -------------------------------------------------------------------------------- 1 | Ashburn po:noun 2 | Dublin po:noun 3 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Quickstart/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - quickstart guide 4 | - quickstart 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ApacheProjectNames/testvalid.md: -------------------------------------------------------------------------------- 1 | Unless you have first used: 2 | 3 | - Apache Mesos 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Agentless/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - agentless deployment 4 | - agentless solution 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AltText/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.AltText:All images must have alt text. 2 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DocumentationTeam/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - the Grafana Labs documentation team 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OAuth/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - Oauth 4 | - Oauth 2 5 | - OAuth 6 | - OAuth 2 7 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/PrometheusExporters/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - Node exporter 4 | - node exporter 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wish/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Wish:Use 'need' or 'want' instead of 'wish'. 2 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Agentless/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - no-collector deployment 4 | - no-collector solution 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/HTTP/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - 4 | - [link text](http://grafana.com) 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/HTTP/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - 4 | - [link text](https://grafana.com) 5 | -------------------------------------------------------------------------------- /vale/Google/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "feed": "https://github.com/errata-ai/Google/releases.atom", 3 | "vale_version": ">=1.0.0" 4 | } 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DatadogProxy/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - The Datadog proxy 4 | - The datadog proxy 5 | - Datadog Proxy 6 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/React/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - ReactJS 4 | - reactJS 5 | - react.js 6 | - react.JS 7 | - react JS 8 | -------------------------------------------------------------------------------- /vale/Readability/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "feed": "https://github.com/errata-ai/Readability/releases.atom", 3 | "vale_version": ">=2.13.0" 4 | } 5 | -------------------------------------------------------------------------------- /docs/sources/write/front-matter/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grafana/writers-toolkit/HEAD/docs/sources/write/front-matter/twitter.png -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AmazonCloudWatch/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - AWS CloudWatch 4 | - cloudwatch 5 | - Cloudwatch 6 | - cloudWatch 7 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AltText/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - ![How you would describe the image to someone over the phone](/path/to/image/) 4 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AndOr/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - You can view and/or edit your own data. 4 | - You can export raw and/or processed events. 5 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/RepeatedWords.yml: -------------------------------------------------------------------------------- 1 | extends: repetition 2 | message: "'%s' is repeated" 3 | level: error 4 | alpha: true 5 | tokens: 6 | - '[^\s]+' 7 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/dictionaries/en_US-places.aff: -------------------------------------------------------------------------------- 1 | SET UTF-8 2 | TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' 3 | ICONV 1 4 | ICONV ’ ' 5 | NOSUGGEST ! 6 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AmazonCloudWatch/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - Amazon CloudWatch 4 | 5 | After the first use, it's OK to use: 6 | 7 | - CloudWatch 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AndOr/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - You can view and edit your own data. 4 | - You can export raw events, processed events, or both. 5 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ApacheProjectNames/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.ApacheProjectNames:Use the full Apache project name in the first instance. 2 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Ordinal/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - 1st 4 | - 2nd 5 | - 3rd 6 | - 4th 7 | - 5th 8 | - 6th 9 | - 7th 10 | - 8th 11 | - 9th 12 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SQL/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - An SQL database 4 | - an SQL database 5 | 6 | Or use: 7 | 8 | - A SQL Server 9 | - a SQL Server 10 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/RepeatedWords/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:1:1:Grafana.RepeatedWords:'the' is repeated 2 | testinvalid.md:2:1:Grafana.RepeatedWords:'no' is repeated 3 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SmartQuotes/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - ' (apostrophe) 4 | - ' (apostrophe) 5 | - ' (apostrophe) 6 | - " (quotation mark) 7 | - " (quotation mark) 8 | -------------------------------------------------------------------------------- /scripts/spellings: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | make vale \ 4 | | grep 'Grafana\.Spelling' \ 5 | | jq '.message' \ 6 | | perl -ne '/'"'"'(.*)'"'"'\?/ && print "$1\n"' \ 7 | | sort -u 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Archives/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - unarchive 4 | - uncompress 5 | - untar 6 | 7 | - unzip 8 | 9 | - ZIP file 10 | 11 | - zip 12 | - ZIP 13 | -------------------------------------------------------------------------------- /vale/Google/Will.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Avoid using '%s'." 3 | link: "https://developers.google.com/style/tense" 4 | ignorecase: true 5 | level: warning 6 | tokens: 7 | - will 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admin/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Admin:Use 'administrator' instead of 'admin' unless it's the name of the UI label like in the Grafana 'Admin' role. 2 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Latin/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - e.g 4 | - e.g. 5 | - e.g, 6 | - eg 7 | - eg. 8 | - eg, 9 | - i.e 10 | - i.e. 11 | - i.e, 12 | - ie 13 | - ie. 14 | - ie, 15 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SQL/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - A SQL database 4 | - a SQL database 5 | - a SQL server 6 | 7 | Also don't use: 8 | 9 | - An SQL Server 10 | - an SQL Server 11 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Ordinal/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - first 4 | - second 5 | - third 6 | - fourth 7 | - fifth 8 | - sixth 9 | - seventh 10 | - eighth 11 | - ninth 12 | - 10th 13 | - 75th 14 | -------------------------------------------------------------------------------- /vale/Google/Parens.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Use parentheses judiciously." 3 | link: "https://developers.google.com/style/parentheses" 4 | nonword: true 5 | level: suggestion 6 | tokens: 7 | - '\(.+\)' 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DocumentationTeam/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - docs squad 4 | - Docs squad 5 | - docs Squad 6 | - Docs Squad 7 | - docs team 8 | - Docs team 9 | - docs Team 10 | - Docs team 11 | -------------------------------------------------------------------------------- /docs/sources/shared/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2023-09-04T07:43:24-04:00" 3 | description: Only required to make the children of this page available as resources. 4 | headless: true 5 | review_date: "2024-02-22" 6 | --- 7 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | .ONESHELL: 2 | .DELETE_ON_ERROR: 3 | export SHELL := bash 4 | export SHELLOPTS := pipefail:errexit 5 | MAKEFLAGS += --warn-undefined-variables 6 | MAKEFLAGS += --no-builtin-rule 7 | 8 | include docs.mk 9 | -------------------------------------------------------------------------------- /vale/.vale.ini: -------------------------------------------------------------------------------- 1 | MinAlertLevel = suggestion 2 | Packages = Grafana, https://github.com/errata-ai/Hugo/releases/download/v0.2.0/Hugo.zip 3 | 4 | [*] 5 | BasedOnStyles = Grafana 6 | TokenIgnores = (+?), \*\*[^\n]+\*\* -------------------------------------------------------------------------------- /vale/Google/Colons.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "'%s' should be in lowercase." 3 | link: "https://developers.google.com/style/colons" 4 | nonword: true 5 | level: warning 6 | scope: sentence 7 | tokens: 8 | - ':\s[A-Z]' 9 | -------------------------------------------------------------------------------- /add-to-docs-project/project-id.graphql: -------------------------------------------------------------------------------- 1 | # Return the project ID for a specific project in the Grafana organization. 2 | query { 3 | organization(login: "grafana") { 4 | projectV2(number: 69) { 5 | id 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /vale/Google/Ordinal.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Spell out all ordinal numbers ('%s') in text." 3 | link: "https://developers.google.com/style/numbers" 4 | level: error 5 | nonword: true 6 | tokens: 7 | - \d+(?:st|nd|rd|th) 8 | -------------------------------------------------------------------------------- /vale/Google/Semicolons.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Use semicolons judiciously." 3 | link: "https://developers.google.com/style/semicolons" 4 | nonword: true 5 | scope: sentence 6 | level: suggestion 7 | tokens: 8 | - ";" 9 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Archives/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - extract 4 | 5 | - extract 6 | 7 | - archive 8 | - compressed file 9 | 10 | - archive 11 | - compressed file 12 | 13 | Also, Zipkin the product is OK. 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .idea 3 | /docs/variables.mk.local 4 | /node_modules/ 5 | /add-to-docs-project/node_modules/ 6 | /add-to-docs-project/index.mjs 7 | build.conf 8 | /dist 9 | /vale/Grafana.zip 10 | vale/tools/inhibit-rules 11 | -------------------------------------------------------------------------------- /.vale.ini: -------------------------------------------------------------------------------- 1 | MinAlertLevel = warning 2 | Packages = Google, https://github.com/errata-ai/Hugo/releases/download/v0.2.0/Hugo.zip, Readability, vale/Grafana 3 | [*.md] 4 | BasedOnStyles = Grafana 5 | TokenIgnores = (+?), \*\*[^\n]+\*\* -------------------------------------------------------------------------------- /vale/Google/OxfordComma.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Use the Oxford comma in '%s'." 3 | link: "https://developers.google.com/style/commas" 4 | scope: sentence 5 | level: warning 6 | tokens: 7 | - '(?:[^,]+,){1,}\s\w+\s(?:and|or)' 8 | -------------------------------------------------------------------------------- /vale/Google/Quotes.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Commas and periods go inside quotation marks." 3 | link: "https://developers.google.com/style/quotation-marks" 4 | level: error 5 | nonword: true 6 | tokens: 7 | - '"[^"]+"[.,?]' 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Kubernetes/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - cron job 4 | - deamonset 5 | - Kubernetes deployment 6 | - pod 7 | - replicaset 8 | - statefulset 9 | - kubelet 10 | - kubectl 11 | - Kubectl 12 | - Kubelet 13 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Shortcodes/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - {{% admonition type="caution" %}} 4 | - {{% admonition type="note" %}} 5 | - {{% admonition type="tip" %}} 6 | - {{% admonition type="warn" %}} 7 | - {{% /admonition %}} 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Shortcodes/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - {{< admonition type="caution" >}} 4 | - {{< admonition type="note" >}} 5 | - {{< admonition type="tip" >}} 6 | - {{< admonition type="warn" >}} 7 | - {{< /admonition >}} 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/DatadogProxy.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: Use '%s' instead of '%s'. 3 | level: warning 4 | action: 5 | name: replace 6 | swap: 7 | "[tT]he [Dd]atadog proxy": Datadog proxy 8 | Datadog Proxy: Datadog proxy 9 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/CommandLinePrompts/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - ```bash 4 | $ command 5 | ``` 6 | - ```bash 7 | # sudo 8 | ``` 9 | - ```console 10 | $ command 11 | ``` 12 | - ```console 13 | # sudo 14 | ``` 15 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Kubernetes/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - CronJob 4 | - DaemonSet 5 | - Kubernetes Deployment 6 | - ReplicaSet 7 | - StatefulSet 8 | - `kubelet` 9 | - `kubectl` 10 | 11 | Also OK: 12 | 13 | - `k8s.daemonset.name` 14 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/PrometheusExporters/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.PrometheusExporters:Use 'Node Exporter' instead of 'Node exporter'. 2 | testinvalid.md:4:3:Grafana.PrometheusExporters:Use 'Node Exporter' instead of 'node exporter'. 3 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SmartQuotes/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - ‘ (left single quotation mark) 4 | - ’ (right single quotation mark) 5 | - ʼ (modifier letter apostrophe) 6 | - “ (left double quotation mark) 7 | - ” (right double quotation mark) 8 | -------------------------------------------------------------------------------- /vale/Google/Ellipses.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "In general, don't use an ellipsis." 3 | link: "https://developers.google.com/style/ellipses" 4 | nonword: true 5 | level: warning 6 | action: 7 | name: remove 8 | tokens: 9 | - '\.\.\.' 10 | -------------------------------------------------------------------------------- /vale/Google/Periods.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't use periods with acronyms or initialisms such as '%s'." 3 | link: "https://developers.google.com/style/abbreviations" 4 | level: error 5 | nonword: true 6 | tokens: 7 | - '\b(?:[A-Z]\.){3,}' 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ReferTo/testinvalid.md: -------------------------------------------------------------------------------- 1 | See [here](https://example.com). 2 | Check out [the link](https://example.com). 3 | 4 | For more information, see [link text](https://example.com). 5 | For more information, check out [link text](https://example.com). 6 | -------------------------------------------------------------------------------- /vale/Readability/SMOG.yml: -------------------------------------------------------------------------------- 1 | extends: metric 2 | message: "Try to keep the SMOG grade (%s) below 10." 3 | link: https://en.wikipedia.org/wiki/SMOG 4 | 5 | formula: | 6 | 1.0430 * math.sqrt((polysyllabic_words * 30.0) / sentences) + 3.1291 7 | 8 | condition: "> 10" 9 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleSemicolons.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "level": "suggestion" 3 | "link": "https://developers.google.com/style/semicolons" 4 | "message": "Use semicolons judiciously." 5 | "nonword": true 6 | "scope": "sentence" 7 | "tokens": 8 | - ";" 9 | -------------------------------------------------------------------------------- /vale/Google/Ranges.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't add words such as 'from' or 'between' to describe a range of numbers." 3 | link: "https://developers.google.com/style/hyphens" 4 | nonword: true 5 | level: warning 6 | tokens: 7 | - '(?:from|between)\s\d+\s?-\s?\d+' 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Quickstart/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Quickstart:Use the compound adjective 'quickstart' without a hyphen instead of 'quick start' whether the noun is implied or explicit. For example, you can use _quickstart guide_ or just _quickstart_. 2 | -------------------------------------------------------------------------------- /vale/Readability/GunningFog.yml: -------------------------------------------------------------------------------- 1 | extends: metric 2 | message: "Try to keep the Gunning-Fog index (%s) below 10." 3 | link: https://en.wikipedia.org/wiki/Gunning_fog_index 4 | 5 | formula: | 6 | 0.4 * ((words / sentences) + 100 * (complex_words / words)) 7 | 8 | condition: "> 10" 9 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OK/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - O.K. 4 | - OK 5 | - ok 6 | - Ok 7 | - okay 8 | - Okay 9 | 10 | Also avoid: 11 | 12 | - A-OK 13 | - hokay 14 | - k 15 | - keh 16 | - kk 17 | - M'kay 18 | - oka 19 | - okeh 20 | - Okie dokie 21 | - Okily Dokily 22 | -------------------------------------------------------------------------------- /vale/Google/Gender.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't use '%s' as a gender-neutral pronoun." 3 | link: "https://developers.google.com/style/pronouns#gender-neutral-pronouns" 4 | level: error 5 | ignorecase: true 6 | tokens: 7 | - he/she 8 | - s/he 9 | - \(s\)he 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleOxfordComma.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "level": "suggestion" 3 | "link": "https://developers.google.com/style/commas" 4 | "message": "Use the Oxford comma in '%s'." 5 | "scope": "sentence" 6 | "tokens": 7 | - "(?:[^,]+,){1,}\\s\\w+\\s(?:and|or)" 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Wish.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | link: https://developers.google.com/style/word-list#wish 4 | message: Use '%s' instead of '%s'. 5 | 6 | ignorecase: false 7 | 8 | action: 9 | name: replace 10 | swap: 11 | wish: need|want 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/dictionaries/en_US-grafana.jsonnet: -------------------------------------------------------------------------------- 1 | local defs = (import '../../../../dictionary.libsonnet').words; 2 | local entries = std.map(function(word) '%s/%s po:%s' % [word.word, word.affixes, word.po], defs); 3 | '%d\n%s' % [std.length(entries), std.join('\n', entries)] 4 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReadabilityLIX.yml: -------------------------------------------------------------------------------- 1 | "condition": "> 0" 2 | "extends": "metric" 3 | "formula": | 4 | (words / sentences) + ((long_words * 100) / words) 5 | "level": "suggestion" 6 | "link": "https://en.wikipedia.org/wiki/Lix_(readability_test)" 7 | "message": "%s aim for below 35." 8 | -------------------------------------------------------------------------------- /vale/Google/AMPM.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Use 'AM' or 'PM' (preceded by a space)." 3 | link: "https://developers.google.com/style/word-list" 4 | level: error 5 | nonword: true 6 | tokens: 7 | - '\d{1,2}[AP]M\b' 8 | - '\d{1,2} ?[ap]m\b' 9 | - '\d{1,2} ?[aApP]\.[mM]\.' 10 | -------------------------------------------------------------------------------- /vale/Google/Slang.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't use internet slang abbreviations such as '%s'." 3 | link: "https://developers.google.com/style/abbreviations" 4 | ignorecase: true 5 | level: error 6 | tokens: 7 | - "tl;dr" 8 | - ymmv 9 | - rtfm 10 | - imo 11 | - fwiw 12 | -------------------------------------------------------------------------------- /vale/Google/Spacing.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "'%s' should have one space." 3 | link: "https://developers.google.com/style/sentence-spacing" 4 | level: error 5 | nonword: true 6 | action: 7 | name: remove 8 | tokens: 9 | - "[a-z][.?!] {2,}[A-Z]" 10 | - "[a-z][.?!][A-Z]" 11 | -------------------------------------------------------------------------------- /vale/Google/Units.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Put a nonbreaking space between the number and the unit in '%s'." 3 | link: "https://developers.google.com/style/units-of-measure" 4 | nonword: true 5 | level: error 6 | tokens: 7 | - \b\d+(?:B|kB|MB|GB|TB) 8 | - \b\d+(?:ns|ms|s|min|h|d) 9 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GooglePeriods.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "level": "error" 3 | "link": "https://developers.google.com/style/abbreviations" 4 | "message": "Don't use periods with acronyms or initialisms such as '%s'." 5 | "nonword": true 6 | "tokens": 7 | - "\\b(?:[A-Z]\\.){3,}" 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReadabilitySMOG.yml: -------------------------------------------------------------------------------- 1 | "condition": "> 0" 2 | "extends": "metric" 3 | "formula": | 4 | 1.0430 * math.sqrt((polysyllabic_words * 30.0) / sentences) + 3.1291 5 | "level": "suggestion" 6 | "link": "https://en.wikipedia.org/wiki/SMOG" 7 | "message": "%s aim for below 10." 8 | -------------------------------------------------------------------------------- /tools/cmd/generate-documentation/ruleExistence.tmpl: -------------------------------------------------------------------------------- 1 | {{ codify (format (escapeShortcodes .Message)) }} 2 | {{ with .Tokens }} 3 | _``_ was matched by one or more of the following regular expressions: 4 | 5 | {{ range $current := . -}} 6 | - `{{ $current }}` 7 | {{ end -}} 8 | {{ end }} 9 | -------------------------------------------------------------------------------- /tools/exit/exit.go: -------------------------------------------------------------------------------- 1 | // Package exit provides consistent exit codes for command-line tools. 2 | package exit 3 | 4 | const ( 5 | // Return codes inspired by buildifier tool. 6 | Success = 0 7 | InputError = 1 8 | UsageError = 2 9 | RuntimeError = 3 10 | CheckError = 4 11 | ) 12 | -------------------------------------------------------------------------------- /vale/Google/EmDash.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't put a space before or after a dash." 3 | link: "https://developers.google.com/style/dashes" 4 | nonword: true 5 | level: error 6 | action: 7 | name: edit 8 | params: 9 | - trim 10 | - " " 11 | tokens: 12 | - '\s[—–]\s' 13 | -------------------------------------------------------------------------------- /vale/Google/Spelling.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "In general, use American spelling instead of '%s'." 3 | link: "https://developers.google.com/style/spelling" 4 | ignorecase: true 5 | level: warning 6 | tokens: 7 | - '(?:\w+)nised?' 8 | - "colour" 9 | - "labour" 10 | - "centre" 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/EndToEnd.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: | 3 | Use '%s' instead of '%s'. 4 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#end-to-end 5 | level: warning 6 | action: 7 | name: replace 8 | swap: 9 | "[eE]2[eE]": end-to-end 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleEllipses.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "remove" 3 | "extends": "existence" 4 | "level": "warning" 5 | "link": "https://developers.google.com/style/ellipses" 6 | "message": "In general, don't use an ellipsis." 7 | "nonword": true 8 | "tokens": 9 | - "\\.\\.\\." 10 | -------------------------------------------------------------------------------- /add-to-docs-project/add-to-project.graphql: -------------------------------------------------------------------------------- 1 | # Add a content item to a project. 2 | mutation AddProjectItem($projectId: ID!, $contentId: ID!) { 3 | addProjectV2ItemById( 4 | input: { projectId: $projectId, contentId: $contentId } 5 | ) { 6 | item { 7 | id 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReadabilityGunningFog.yml: -------------------------------------------------------------------------------- 1 | "condition": "> 0" 2 | "extends": "metric" 3 | "formula": | 4 | 0.4 * ((words / sentences) + 100 * (complex_words / words)) 5 | "level": "suggestion" 6 | "link": "https://en.wikipedia.org/wiki/Gunning_fog_index" 7 | "message": "%s aim for below 10." 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ProductPossessives/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.ProductPossessives:Don't form a possessive from a feature name, product name, or trademark, regardless of who owns it. Instead, use the name as a modifier or rewrite to use a word like of to indicate the relationship. 2 | -------------------------------------------------------------------------------- /vale/Google/We.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Try to avoid using first-person plural like '%s'." 3 | link: "https://developers.google.com/style/pronouns#personal-pronouns" 4 | level: warning 5 | ignorecase: true 6 | tokens: 7 | - we 8 | - we'(?:ve|re) 9 | - ours? 10 | - us 11 | - let's 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/AllowsTo.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: | 3 | Did you mean '%s' instead of '%s'? 4 | 5 | Allows to is a common wording error. 6 | level: warning 7 | ignorecase: false 8 | action: 9 | name: replace 10 | swap: 11 | allows to: allows you to|makes it possible to 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Please.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "It's great to be polite, but using 'please' in a set of instructions is overdoing the politeness." 3 | level: error 4 | link: https://developers.google.com/style/tone#politeness 5 | ignorecase: true 6 | limit: 1 7 | tokens: 8 | - please 9 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Latin.yml: -------------------------------------------------------------------------------- 1 | action: 2 | name: replace 3 | extends: substitution 4 | ignorecase: true 5 | level: error 6 | link: https://developers.google.com/style/abbreviations#dont-use 7 | message: Use '%s' instead of '%s'. 8 | swap: 9 | 'e\.?g[,.]?': for example 10 | 'i\.?e[,.]?': that is 11 | -------------------------------------------------------------------------------- /vale/Readability/AutomatedReadability.yml: -------------------------------------------------------------------------------- 1 | extends: metric 2 | message: "Try to keep the Automated Readability Index (%s) below 8." 3 | link: https://en.wikipedia.org/wiki/Automated_readability_index 4 | 5 | formula: | 6 | (4.71 * (characters / words)) + (0.5 * (words / sentences)) - 21.43 7 | 8 | condition: "> 8" 9 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/CommandLinePrompts/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - ```bash 4 | command 5 | ``` 6 | - ```bash 7 | sudo 8 | ``` 9 | - ```console 10 | command 11 | ``` 12 | - ```console 13 | sudo 14 | ``` 15 | 16 | Edge cases: 17 | 18 | ```markdown 19 | # Set up Alerting 20 | ``` 21 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Latin/testvalid.md: -------------------------------------------------------------------------------- 1 | Instead use: 2 | 3 | - for example 4 | - for example 5 | - for example 6 | - for example 7 | - for example 8 | - for example 9 | - that is 10 | - that is 11 | - that is 12 | - that is 13 | - that is 14 | - that is 15 | 16 | Potential false positives 17 | 18 | - egg 19 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleRanges.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "level": "warning" 3 | "link": "https://developers.google.com/style/hyphens" 4 | "message": "Don't add words such as 'from' or 'between' to describe a range of numbers." 5 | "nonword": true 6 | "tokens": 7 | - "(?:from|between)\\s\\d+\\s?-\\s?\\d+" 8 | -------------------------------------------------------------------------------- /vale/Readability/ColemanLiau.yml: -------------------------------------------------------------------------------- 1 | extends: metric 2 | message: "Try to keep the Coleman–Liau Index grade (%s) below 9." 3 | link: https://en.wikipedia.org/wiki/Coleman%E2%80%93Liau_index 4 | 5 | formula: | 6 | (0.0588 * (characters / words) * 100) - (0.296 * (sentences / words) * 100) - 15.8 7 | 8 | condition: "> 9" 9 | -------------------------------------------------------------------------------- /vale/Readability/FleschKincaid.yml: -------------------------------------------------------------------------------- 1 | extends: metric 2 | message: "Try to keep the Flesch–Kincaid grade level (%s) below 8." 3 | link: https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests 4 | 5 | formula: | 6 | (0.39 * (words / sentences)) + (11.8 * (syllables / words)) - 15.59 7 | 8 | condition: "> 8" 9 | -------------------------------------------------------------------------------- /vale/Google/Exclamation.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't use exclamation points in text." 3 | link: "https://developers.google.com/style/exclamation-points" 4 | nonword: true 5 | level: error 6 | action: 7 | name: edit 8 | params: 9 | - trim_right 10 | - "!" 11 | tokens: 12 | - '\w+!(?:\s|$)' 13 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleGender.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "ignorecase": true 3 | "level": "error" 4 | "link": "https://developers.google.com/style/pronouns#gender-neutral-pronouns" 5 | "message": "Don't use '%s' as a gender-neutral pronoun." 6 | "tokens": 7 | - "he/she" 8 | - "s/he" 9 | - "\\(s\\)he" 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReadabilityAutomatedReadability.yml: -------------------------------------------------------------------------------- 1 | "condition": "> 0" 2 | "extends": "metric" 3 | "formula": | 4 | (4.71 * (characters / words)) + (0.5 * (words / sentences)) - 21.43 5 | "level": "suggestion" 6 | "link": "https://en.wikipedia.org/wiki/Automated_readability_index" 7 | "message": "%s aim for below 8." 8 | -------------------------------------------------------------------------------- /vale/Readability/FleschReadingEase.yml: -------------------------------------------------------------------------------- 1 | extends: metric 2 | message: "Try to keep the Flesch reading ease score (%s) above 70." 3 | link: https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests 4 | 5 | formula: | 6 | 206.835 - (1.015 * (words / sentences)) - (84.6 * (syllables / words)) 7 | 8 | condition: "< 70" 9 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DatadogProxy/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.DatadogProxy:Use 'Datadog proxy' instead of 'The Datadog proxy'. 2 | testinvalid.md:4:3:Grafana.DatadogProxy:Use 'Datadog proxy' instead of 'The datadog proxy'. 3 | testinvalid.md:5:3:Grafana.DatadogProxy:Use 'Datadog proxy' instead of 'Datadog Proxy'. 4 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReadabilityColemanLiau.yml: -------------------------------------------------------------------------------- 1 | "condition": "> 0" 2 | "extends": "metric" 3 | "formula": | 4 | (0.0588 * (characters / words) * 100) - (0.296 * (sentences / words) * 100) - 15.8 5 | "level": "suggestion" 6 | "link": "https://en.wikipedia.org/wiki/Coleman%E2%80%93Liau_index" 7 | "message": "%s aim for below 9." 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReadabilityFleschKincaid.yml: -------------------------------------------------------------------------------- 1 | "condition": "> 0" 2 | "extends": "metric" 3 | "formula": | 4 | (0.39 * (words / sentences)) + (11.8 * (syllables / words)) - 15.59 5 | "level": "suggestion" 6 | "link": "https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests" 7 | "message": "%s aim for below 8." 8 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/OAuth/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.OAuth:Use 'OAuth 2.0' instead of 'Oauth'. 2 | testinvalid.md:4:3:Grafana.OAuth:Use 'OAuth 2.0' instead of 'Oauth 2'. 3 | testinvalid.md:5:3:Grafana.OAuth:Use 'OAuth 2.0' instead of 'OAuth'. 4 | testinvalid.md:6:3:Grafana.OAuth:Use 'OAuth 2.0' instead of 'OAuth 2'. 5 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | prettier@3.5.3: 6 | version "3.5.3" 7 | resolved "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz" 8 | integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== 9 | -------------------------------------------------------------------------------- /vale/Google/LyHyphens.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "'%s' doesn't need a hyphen." 3 | link: "https://developers.google.com/style/hyphens" 4 | level: error 5 | ignorecase: false 6 | nonword: true 7 | action: 8 | name: edit 9 | params: 10 | - regex 11 | - "-" 12 | - " " 13 | tokens: 14 | - '\b[^\s-]+ly-\w+\b' 15 | -------------------------------------------------------------------------------- /vale/Google/OptionalPlurals.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't use plurals in parentheses such as in '%s'." 3 | link: "https://developers.google.com/style/plurals-parentheses" 4 | level: error 5 | nonword: true 6 | action: 7 | name: edit 8 | params: 9 | - trim_right 10 | - "(s)" 11 | tokens: 12 | - '\b\w+\(s\)' 13 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/DocumentationTeam.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | message: Use '%s' rather than '%s'. 4 | 5 | action: 6 | name: replace 7 | swap: 8 | "[Dd]ocs? (?:[Ss]quad|[Tt]eam)": the Grafana Labs documentation team 9 | "[Dd]ocumentation (?:[Ss]quad|Team)": the Grafana Labs documentation team 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleAMPM.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "level": "error" 3 | "link": "https://developers.google.com/style/word-list" 4 | "message": "Use 'AM' or 'PM' (preceded by a space)." 5 | "nonword": true 6 | "tokens": 7 | - "\\d{1,2}[AP]M\\b" 8 | - "\\d{1,2} ?[ap]m\\b" 9 | - "\\d{1,2} ?[aApP]\\.[mM]\\." 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleSpacing.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "remove" 3 | "extends": "existence" 4 | "level": "error" 5 | "link": "https://developers.google.com/style/sentence-spacing" 6 | "message": "'%s' should have one space." 7 | "nonword": true 8 | "tokens": 9 | - "[a-z][.?!] {2,}[A-Z]" 10 | - "[a-z][.?!][A-Z]" 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleSpelling.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "ignorecase": true 3 | "level": "warning" 4 | "link": "https://developers.google.com/style/spelling" 5 | "message": "In general, use American spelling instead of '%s'." 6 | "tokens": 7 | - "(?:\\w+)nised?" 8 | - "colour" 9 | - "labour" 10 | - "centre" 11 | -------------------------------------------------------------------------------- /vale/Google/Latin.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: "Use '%s' instead of '%s'." 3 | link: "https://developers.google.com/style/abbreviations" 4 | ignorecase: true 5 | level: error 6 | nonword: true 7 | action: 8 | name: replace 9 | swap: 10 | '\b(?:eg|e\.g\.)(?=[\s,;])': for example 11 | '\b(?:ie|i\.e\.)(?=[\s,;])': that is 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleSlang.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "ignorecase": true 3 | "level": "error" 4 | "link": "https://developers.google.com/style/abbreviations" 5 | "message": "Don't use internet slang abbreviations such as '%s'." 6 | "tokens": 7 | - "tl;dr" 8 | - "ymmv" 9 | - "rtfm" 10 | - "imo" 11 | - "fwiw" 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/OAuth.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: suggestion 3 | link: https://developers.google.com/style/word-list#oauth-20 4 | message: Use '%s' instead of '%s'. 5 | 6 | ignorecase: false 7 | 8 | action: 9 | name: replace 10 | swap: 11 | "O[Aa]uth 2(?!\\.0)": OAuth 2.0 12 | "O[Aa]uth(?! 2\\.0)": OAuth 2.0 13 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/React.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#react 4 | message: Use '%s' instead of '%s'. 5 | 6 | ignorecase: false 7 | nonword: true 8 | 9 | action: 10 | name: replace 11 | swap: 12 | "[Rr]eact[. ]?[Jj][Ss]": React 13 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReadabilityFleschReadingEase.yml: -------------------------------------------------------------------------------- 1 | "condition": "< 100" 2 | "extends": "metric" 3 | "formula": | 4 | 206.835 - (1.015 * (words / sentences)) - (84.6 * (syllables / words)) 5 | "level": "suggestion" 6 | "link": "https://en.wikipedia.org/wiki/Flesch%E2%80%93Kincaid_readability_tests" 7 | "message": "%s aim for above 70." 8 | -------------------------------------------------------------------------------- /vale/dictionary/y.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('YAML', '', 'noun') { abbreviation: true, elaboration: "YAML Ain't Markup Language", established_abbreviation: true }, 4 | word.new('YugabyteDB', '', 'noun') { product: true, description: "https://docs.yugabyte.com/", swaps: {yugabyte: 'YugabyteDB'} }, 5 | ] 6 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wordlist/testinvalid.md: -------------------------------------------------------------------------------- 1 | # Amazon Data Firehose 2 | 3 | Don't use: 4 | 5 | - Kinesis Data Firehose 6 | - Firehose 7 | - Kinesis Firehose 8 | 9 | # Dataset 10 | 11 | Don't use: 12 | 13 | - data set 14 | - data-set 15 | - data sets 16 | - data-sets 17 | 18 | # Promtail 19 | 20 | Don't use: 21 | 22 | - promtail 23 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Exclamation.yml: -------------------------------------------------------------------------------- 1 | action: 2 | name: remove 3 | extends: existence 4 | level: warning 5 | link: https://developers.google.com/style/tone#some-things-to-avoid-where-possible 6 | message: Avoid exclamation points in text, except in rare really exciting moments. 7 | nonword: true 8 | tokens: 9 | - "\\w+!(?:\\s|$)" 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleEmDash.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "edit" 3 | "params": 4 | - "trim" 5 | - " " 6 | "extends": "existence" 7 | "level": "error" 8 | "link": "https://developers.google.com/style/dashes" 9 | "message": "Don't put a space before or after a dash." 10 | "nonword": true 11 | "tokens": 12 | - "\\s[—–]\\s" 13 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Admin.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: | 3 | Use '%s' instead of '%s' unless it's the name of the UI label like in the Grafana 'Admin' role. 4 | link: https://developers.google.com/style/word-list#admin 5 | level: warning 6 | ignorecase: false 7 | action: 8 | name: replace 9 | swap: 10 | admin: administrator 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleEnDash.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "edit" 3 | "params": 4 | - "replace" 5 | - "-" 6 | - "—" 7 | "extends": "existence" 8 | "level": "error" 9 | "link": "https://developers.google.com/style/dashes" 10 | "message": "Use an em dash ('—') instead of '–'." 11 | "nonword": true 12 | "tokens": 13 | - "–" 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Parentheses.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | level: suggestion 3 | link: https://developers.google.com/style/parentheses 4 | message: Use parentheses judiciously. 5 | 6 | nonword: true 7 | 8 | tokens: 9 | # Allow for single characters in backticks. 10 | # For example, don't use single asterisks (`*`). 11 | - "\\(.{4,}\\)" 12 | -------------------------------------------------------------------------------- /vale/Google/FirstPerson.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Avoid first-person pronouns such as '%s'." 3 | link: "https://developers.google.com/style/pronouns#personal-pronouns" 4 | ignorecase: true 5 | level: warning 6 | nonword: true 7 | tokens: 8 | - (?:^|\s)I\s 9 | - (?:^|\s)I,\s 10 | - \bI'm\b 11 | - \bme\b 12 | - \bmy\b 13 | - \bmine\b 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ApacheProjectNames.yml: -------------------------------------------------------------------------------- 1 | "extends": "conditional" 2 | "first": "\\b(Mesos)\\b" 3 | "level": "warning" 4 | "link": "https://grafana.com/docs/writers-toolkit/write/style-guide/capitalization-punctuation/#apache-projects" 5 | "message": "Use the full Apache project name in the first instance." 6 | "scope": "text" 7 | "second": "Apache (Mesos)" 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleWill.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "ignorecase": true 3 | "level": "warning" 4 | "link": "https://developers.google.com/style/tense" 5 | "message": | 6 | Avoid using '%s'. 7 | 8 | Use present tense for statements that describe general behavior that's not associated with a particular time. 9 | "tokens": 10 | - "will" 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/MetaMonitoring.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: | 3 | Use '%s' instead of '%s'. 4 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#meta-monitoring 5 | level: warning 6 | action: 7 | name: replace 8 | swap: 9 | "meta ?monitoring": meta-monitoring 10 | "meat ?monitoring": meta-monitoring 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/PrometheusExporters.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#node-exporter 4 | message: Use '%s' instead of '%s'. 5 | 6 | ignorecase: false 7 | nonword: true 8 | 9 | action: 10 | name: replace 11 | swap: 12 | "[Nn]ode exporter": Node Exporter 13 | -------------------------------------------------------------------------------- /vale/dictionary/z.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('ZIP', '', 'noun') { abbreviation: true, established_abbreviation: true }, 4 | word.new('Zipkin', '', 'adjective'), 5 | word.new('Zipkin', '', 'noun') { product: true }, 6 | word.new('zlib', '', 'noun') { description: 'zlib is a general-purpose lossless data-compression library.' }, 7 | ] 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleProductNames.yml: -------------------------------------------------------------------------------- 1 | "extends": "conditional" 2 | "first": "\\b(Kubernetes Engine)\\b" 3 | "level": "warning" 4 | "link": "https://grafana.com/docs/writers-toolkit/write/style-guide/capitalization-punctuation/#google-products" 5 | "message": "Use the full Google product name in the first instance." 6 | "scope": "text" 7 | "second": "Google (Kubernetes Engine)" 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Ordinal.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | level: error 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/style-conventions/#numbers 4 | message: For ordinals, write out first through ninth. For 10th on, use numerals. 5 | tokens: 6 | - 1st 7 | - 2nd 8 | - 3rd 9 | - 4th 10 | - 5th 11 | - 6th 12 | - 7th 13 | - 8th 14 | - 9th 15 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/SelfManaged.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: | 3 | Use '%s' instead of '%s' when talking about Grafana deployment methods. 4 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#self-managed 5 | level: warning 6 | action: 7 | name: replace 8 | swap: 9 | self-hosted: self-managed 10 | "on-prem(?:ise)?": self-managed 11 | -------------------------------------------------------------------------------- /vale/dictionary/x.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('XML', '', 'noun') { abbreviation: true, elaboration: 'Extensible Markup Language', established_abbreviation: true }, 4 | word.new('XSS', '', 'noun') { abbreviation: true, elaboration: 'cross-site scripting' }, 5 | word.new('xy chart', 'S', 'noun') { description: 'A Grafana visualization type.' }, 6 | ] 7 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DropDown/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.DropDown:Use 'drop-down' instead of 'dropdown'. Use drop-down as a modifier rather than as a standalone noun. For example: _drop-down menu_. 2 | testinvalid.md:4:3:Grafana.DropDown:Use 'drop-down' instead of 'drop down'. Use drop-down as a modifier rather than as a standalone noun. For example: _drop-down menu_. 3 | -------------------------------------------------------------------------------- /tools/cmd/generate-documentation/ruleSubstitution.tmpl: -------------------------------------------------------------------------------- 1 | {{ codify (printf (escapeShortcodes .Message) "" "") }} 2 | {{ with .Swap }} 3 | | Current text | Replacement text | 4 | | ------------ | ---------------- | 5 | {{ range $current, $replacement := . -}} 6 | | `{{ escapeForTable $current }}` | `{{ escapeForTable $replacement }}` | 7 | {{ end -}} 8 | {{ end }} 9 | -------------------------------------------------------------------------------- /vale/Google/HeadingPunctuation.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Don't put a period at the end of a heading." 3 | link: "https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings" 4 | nonword: true 5 | level: warning 6 | scope: heading 7 | action: 8 | name: edit 9 | params: 10 | - trim_right 11 | - "." 12 | tokens: 13 | - '[a-z0-9][.]\s*$' 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleLyHyphens.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "edit" 3 | "params": 4 | - "regex" 5 | - "-" 6 | - " " 7 | "extends": "existence" 8 | "ignorecase": false 9 | "level": "error" 10 | "link": "https://developers.google.com/style/hyphens" 11 | "message": "'%s' doesn't need a hyphen." 12 | "nonword": true 13 | "tokens": 14 | - "\\b[^\\s-]+ly-\\w+\\b" 15 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleOptionalPlurals.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "edit" 3 | "params": 4 | - "trim_right" 5 | - "(s)" 6 | "extends": "existence" 7 | "level": "error" 8 | "link": "https://developers.google.com/style/plurals-parentheses" 9 | "message": "Don't use plurals in parentheses such as in '%s'." 10 | "nonword": true 11 | "tokens": 12 | - "\\b\\w+\\(s\\)" 13 | -------------------------------------------------------------------------------- /deploy-preview/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM nginx:1.21.6-alpine@sha256:a74534e76ee1121d418fa7394ca930eb67440deda413848bc67c68138535b989 2 | 3 | COPY ./dist /usr/share/nginx/dist 4 | 5 | RUN rm -rf /etc/nginx/sites-enabled && \ 6 | rm -rf /etc/nginx/nginx.conf 7 | 8 | COPY deploy-preview-files/deploy-preview/nginx.conf /etc/nginx/nginx.conf 9 | COPY build.conf /etc/nginx/build.conf 10 | 11 | RUN nginx -t -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Archives.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: suggestion 3 | link: https://developers.google.com/style/word-list#extract 4 | message: Use '%s' instead of '%s'. 5 | 6 | ignorecase: false 7 | 8 | action: 9 | name: replace 10 | swap: 11 | "[Uu]n(?:archive|compress|tar|zip)": extract 12 | unzip: extract 13 | "[Zz][Ii][Pp](?: file)?": archive|compressed file 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/DialogBox.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | message: Use '%s' rather than '%s'. 4 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#dialog-box 5 | 6 | ignorecase: false 7 | 8 | action: 9 | name: replace 10 | swap: 11 | dialog box appears: dialog box opens 12 | modal: dialog box 13 | "dialog(?! box)": dialog box 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/writers-toolkit/vale/config/tests 2 | 3 | go 1.22.0 4 | 5 | require ( 6 | github.com/d5/tengo/v2 v2.17.0 // indirect 7 | github.com/davecgh/go-spew v1.1.1 // indirect 8 | github.com/pmezard/go-difflib v1.0.0 // indirect 9 | github.com/stretchr/testify v1.9.0 // indirect 10 | gopkg.in/yaml.v3 v3.0.1 // indirect 11 | ) 12 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/React/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.React:Use 'React' instead of 'ReactJS'. 2 | testinvalid.md:4:3:Grafana.React:Use 'React' instead of 'reactJS'. 3 | testinvalid.md:5:3:Grafana.React:Use 'React' instead of 'react.js'. 4 | testinvalid.md:6:3:Grafana.React:Use 'React' instead of 'react.JS'. 5 | testinvalid.md:7:3:Grafana.React:Use 'React' instead of 'react JS'. 6 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Wordlist/testvalid.md: -------------------------------------------------------------------------------- 1 | # Amazon Data Firehose 2 | 3 | Instead use: 4 | 5 | - Amazon Data Firehose 6 | - Data Firehose 7 | 8 | # Dataset 9 | 10 | Instead use: 11 | 12 | - dataset 13 | 14 | # Promtail 15 | 16 | Instead use: 17 | 18 | - Promtail 19 | 20 | Also acceptable: 21 | 22 | - [lambda-promtail](https://github.com/grafana/loki/tree/main/tools/lambda-promtail) 23 | -------------------------------------------------------------------------------- /vale/dictionary/q.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('quantile', 'S', 'noun'), 4 | word.new('querier', 'MS', 'noun'), 5 | word.new('query', '', 'noun'), 6 | word.new('query', 'DGS', 'verb'), 7 | word.new('queryable', '', 'adjective'), 8 | word.new('queryless', '', 'adjective') { description: 'In contrast to using a query language like PromQL or SQL' }, 9 | ] 10 | -------------------------------------------------------------------------------- /tools/cmd/generate-documentation/rule.tmpl: -------------------------------------------------------------------------------- 1 | ### {{ .Name }} 2 | 3 | Extends: {{ .Extends }} 4 | 5 | {{ if eq "substitution" .Extends -}} 6 | {{ template "ruleSubstitution.tmpl" . -}} 7 | {{ else if eq "existence" .Extends -}} 8 | {{ template "ruleExistence.tmpl" . -}} 9 | {{ else -}} 10 | {{ template "ruleDefault.tmpl" . -}} 11 | {{ end }} 12 | 13 | {{ with .Link }}[More information ->]({{ . }}){{ end }} 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/AltText.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | message: All images must have alt text. 3 | link: https://grafana.com/docs/writers-toolkit/write/image-guidelines/#alt-text 4 | scope: raw 5 | script: | 6 | text := import("text") 7 | matches := [] 8 | for match in text.re_find(`!\[\]\(.*?\)`, scope, -1) { 9 | matches = append(matches, {begin: match[0].begin, end: match[0].end}) 10 | } 11 | -------------------------------------------------------------------------------- /vale/Readability/LIX.yml: -------------------------------------------------------------------------------- 1 | extends: metric 2 | message: "Try to keep the LIX score (%s) below 35." 3 | 4 | link: https://en.wikipedia.org/wiki/Lix_(readability_test) 5 | # Very Easy: 20 - 25 6 | # 7 | # Easy: 30 - 35 8 | # 9 | # Medium: 40 - 45 10 | # 11 | # Difficult: 50 - 55 12 | # 13 | # Very Difficult: 60+ 14 | formula: | 15 | (words / sentences) + ((long_words * 100) / words) 16 | 17 | condition: "> 35" 18 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AmazonCloudWatch/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.AmazonCloudWatch:Use 'Amazon CloudWatch' instead of 'AWS CloudWatch'. 2 | testinvalid.md:4:3:Grafana.AmazonCloudWatch:Use 'CloudWatch' instead of 'cloudwatch'. 3 | testinvalid.md:5:3:Grafana.AmazonCloudWatch:Use 'CloudWatch' instead of 'Cloudwatch'. 4 | testinvalid.md:6:3:Grafana.AmazonCloudWatch:Use 'CloudWatch' instead of 'cloudWatch'. 5 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Relref.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | scope: raw 3 | level: error 4 | link: https://grafana.com/docs/writers-toolkit/write/links/ 5 | message: | 6 | Don't use the relref shortcode for any links as they don't follow redirects and have confusing semantics. 7 | 8 | Instead use one of the links described in [links](https://grafana.com/docs/writers-toolkit/write/links/). 9 | script: Relref.tengo 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleFirstPerson.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "ignorecase": true 3 | "level": "warning" 4 | "link": "https://developers.google.com/style/pronouns#personal-pronouns" 5 | "message": "Avoid first-person pronouns such as '%s'." 6 | "nonword": true 7 | "tokens": 8 | - "(?:^|\\s)I\\s" 9 | - "(?:^|\\s)I,\\s" 10 | - "\\bI'm\\b" 11 | - "\\bme\\b" 12 | - "\\bmy\\b" 13 | - "\\bmine\\b" 14 | -------------------------------------------------------------------------------- /vale/.vale-config/1-Hugo.ini: -------------------------------------------------------------------------------- 1 | [*.md] 2 | # Exclude `{{< ... >}}`, `{{% ... %}}`, [Who]({{< ... >}}) 3 | TokenIgnores = ({{[%<] .* [%>]}}.*?{{[%<] ?/.* [%>]}}), \ 4 | (\[.+\]\({{< .+ >}}\)), \ 5 | ({{[%<] .+ [%>]}}) 6 | 7 | # Exclude `{{< myshortcode `This is some HTML, ... >}}` 8 | BlockIgnores = (?sm)^({{[%<] [^{]*? [%>]}})\n$, \ 9 | (?s) *({{< highlight [^>]* ?>}}.*?{{< ?/ ?highlight >}}), \ 10 | ({{[%<] .+ [%>]}}) 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/README.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: Use '%s' instead of '%s' unless you're referring to a specific file which has that spelling. 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#readme 4 | level: warning 5 | ignorecase: false 6 | action: 7 | name: replace 8 | swap: 9 | '[Rr]eadme\.md': README.md 10 | "[Rr]eadme": README 11 | "[Rr]eadmes": READMEs 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/DropDown.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: suggestion 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#drop-down 4 | message: | 5 | Use '%s' instead of '%s'. 6 | 7 | Use drop-down as a modifier rather than as a standalone noun. For example: _drop-down menu_. 8 | 9 | ignorecase: false 10 | 11 | action: 12 | name: replace 13 | swap: 14 | "drop ?down": drop-down 15 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/tengo.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | func mustParseMatches(a []interface{}) []map[string]int { 4 | matches := []map[string]int{} 5 | 6 | for _, i := range a { 7 | m, _ := i.(map[string]any) 8 | match := map[string]int{ 9 | "begin": int(m["begin"].(int64)), 10 | "end": int(m["end"].(int64)), 11 | } 12 | 13 | matches = append(matches, match) 14 | } 15 | 16 | return matches 17 | } 18 | -------------------------------------------------------------------------------- /vale/Google/DateFormat.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: "Use 'July 31, 2016' format, not '%s'." 3 | link: "https://developers.google.com/style/dates-times" 4 | ignorecase: true 5 | level: error 6 | nonword: true 7 | tokens: 8 | - '\d{1,2}(?:\.|/)\d{1,2}(?:\.|/)\d{4}' 9 | - '\d{1,2} (?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)|May|Jun(?:e)|Jul(?:y)|Aug(?:ust)|Sep(?:tember)?|Oct(?:ober)|Nov(?:ember)?|Dec(?:ember)?) \d{4}' 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Paragraphs.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | scope: raw 3 | level: error 4 | link: https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-br-element 5 | message: | 6 | br elements must be used only for line breaks that are actually part of the content, as in poems or addresses. 7 | 8 | In tables, instead of br elements, use p for paragraphs, and ul or ol for list items. 9 | script: Paragraphs.tengo 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/AmazonCloudWatch.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | link: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/WhatIsCloudWatch.html 4 | message: Use '%s' instead of '%s'. 5 | 6 | action: 7 | name: replace 8 | swap: 9 | AWS CloudWatch: Amazon CloudWatch 10 | aws CloudWatch: Amazon CloudWatch 11 | Cloudwatch: CloudWatch 12 | cloudwatch: CloudWatch 13 | cloudWatch: CloudWatch 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleHeadingPunctuation.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "edit" 3 | "params": 4 | - "trim_right" 5 | - "." 6 | "extends": "existence" 7 | "level": "warning" 8 | "link": "https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings" 9 | "message": "Don't put a period at the end of a heading." 10 | "nonword": true 11 | "scope": "heading" 12 | "tokens": 13 | - "[a-z0-9][.]\\s*$" 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/CHANGELOG.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: Use '%s' instead of '%s' unless you're referring to a specific file which has that spelling. 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#changelog 4 | level: warning 5 | ignorecase: false 6 | action: 7 | name: replace 8 | swap: 9 | '[Cc]hangelog\.md': CHANGELOG.md 10 | "[Cc]hangelog": CHANGELOG 11 | "[Cc]hangelogs": CHANGELOGs 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Quickstart.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: Use the compound adjective '%s' without a hyphen instead of '%s' whether the noun is implied or explicit. For example, you can use _quickstart guide_ or just _quickstart_. 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#quickstart 4 | level: warning 5 | ignorecase: false 6 | action: 7 | name: replace 8 | swap: 9 | "quick start": quickstart 10 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/ReferTo/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:1:1:Grafana.ReferTo:When linking in Markdown, use 'Refer to [' instead of 'See ['. 2 | testinvalid.md:2:1:Grafana.ReferTo:When linking in Markdown, use 'Refer to [' instead of 'Check out ['. 3 | testinvalid.md:4:23:Grafana.ReferTo:When linking in Markdown, use 'refer to [' instead of 'see ['. 4 | testinvalid.md:5:23:Grafana.ReferTo:When linking in Markdown, use 'refer to [' instead of 'check out ['. 5 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/AndOr.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | level: warning 3 | link: https://developers.google.com/style/slashes#and-or 4 | message: | 5 | Avoid writing and/or except when space is limited, such as in tables. 6 | 7 | Often, 'and' implies 'or', so you don't need to write both words. 8 | 9 | If you need to specify both in your content, write something like "You can export raw events, processed events, or both." 10 | tokens: 11 | - and/or 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/ReferTo.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: When linking in Markdown, use '%s' instead of '%s'. 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/style-conventions/#links-and-references 4 | level: error 5 | ignorecase: false 6 | action: 7 | name: replace 8 | scope: raw 9 | swap: 10 | "Check out \\[": "Refer to [" 11 | "See \\[": "Refer to [" 12 | "check out \\[": "refer to [" 13 | "see \\[": "refer to [" 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/CommandLinePrompts.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | scope: raw 3 | level: warning 4 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/write-for-developers/#command-lines 5 | message: | 6 | Don't add `$` or `#` as prompts before commands so users can copy and paste them. 7 | 8 | Also, don't use `#` to include comments in commands. 9 | That explanation should be outside of the code block. 10 | script: CommandLinePrompts.tengo 11 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleDateFormat.yml: -------------------------------------------------------------------------------- 1 | "extends": "existence" 2 | "ignorecase": true 3 | "level": "error" 4 | "link": "https://developers.google.com/style/dates-times" 5 | "message": "Use 'July 31, 2016' format, not '%s'." 6 | "nonword": true 7 | "tokens": 8 | - "\\d{1,2}(?:\\.|/)\\d{1,2}(?:\\.|/)\\d{4}" 9 | - "\\d{1,2} (?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)|May|Jun(?:e)|Jul(?:y)|Aug(?:ust)|Sep(?:tember)?|Oct(?:ober)|Nov(?:ember)?|Dec(?:ember)?) \\d{4}" 10 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GrafanaCom.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | ignorecase: false 3 | level: warning 4 | message: | 5 | Don't use `grafana.com`, instead use one of the following: 6 | 7 | - If you're talking about Grafana Cloud, use `Grafana Cloud`. 8 | - If you're talking about the company, use `Grafana Labs`. 9 | - If you're linking to a page on the website, use the page title or the full URL including scheme. For example, `https://grafana.com/`. 10 | tokens: 11 | - 'grafana\.com' 12 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/SmartQuotes.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | message: | 3 | Avoid smart quotes in the source file, especially in code blocks. 4 | 5 | Replace all smart double quotes like `“` or `”` with `"`. 6 | Replace all smart single quotes like `‘`, `’`, or `ʼ` with `'`. 7 | 8 | In some contexts, Unicode characters aren't supported and break configurations. 9 | 10 | The website renders paired quotes using smart quotes in paragraphs. 11 | scope: raw 12 | script: SmartQuotes.tengo 13 | -------------------------------------------------------------------------------- /docs/variables.mk: -------------------------------------------------------------------------------- 1 | # List of projects to provide to the make-docs script. 2 | PROJECTS = writers-toolkit 3 | 4 | # Test the nightly image. 5 | export DOCS_IMAGE := grafana/docs-base:nightly 6 | 7 | # Set the VALE_IMAGE to match the one defined in CI. 8 | export VALE_IMAGE := $(shell sed -En 's, *image: (grafana/vale.*),\1,p' "$(shell git rev-parse --show-toplevel)/.github/workflows/validate-documentation.yml" | head -n 1) 9 | 10 | export VALE_MINALERTLEVEL := warning 11 | 12 | export WEBSITE_MOUNTS := true 13 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/We.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: | 3 | Use first person plural pronouns like '%s' carefully. 4 | 5 | Don't use 'we' when you're talking about the reader, instead use 'you'. 6 | 7 | It's OK to use 'we' when you're talking about Grafana Labs. 8 | link: https://developers.google.com/style/person#use-first-person-plural-pronouns-carefully 9 | level: suggestion 10 | ignorecase: true 11 | tokens: 12 | - we 13 | - we'(?:ve|re) 14 | - ours? 15 | - us 16 | - let's 17 | -------------------------------------------------------------------------------- /add-to-docs-project/issues.graphql: -------------------------------------------------------------------------------- 1 | # Search for the first ten open issues that aren't already in the Docs project. 2 | { 3 | search( 4 | first: 10 5 | type: ISSUE 6 | query: "org:grafana is:issue state:open label:type/docs -project:grafana/69" 7 | ) { 8 | issueCount 9 | pageInfo { 10 | hasNextPage 11 | endCursor 12 | } 13 | nodes { 14 | ... on Issue { 15 | createdAt 16 | title 17 | url 18 | id 19 | } 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /scripts/add-date: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # https://stackoverflow.com/questions/2390199/finding-the-date-time-a-file-was-first-added-to-a-git-repository 3 | 4 | set -euf -o pipefail 5 | 6 | function usage { 7 | cat < 12 | 13 | Examples: 14 | $0 docs/sources/_index.md 15 | EOF 16 | } 17 | 18 | if [[ $# -ne 1 ]]; then 19 | usage 20 | exit 1 21 | fi 22 | 23 | git log --follow --format=%ad --date iso-strict -- "$1" | tail -1 24 | -------------------------------------------------------------------------------- /tools/rwfilefs/rwfilefs.go: -------------------------------------------------------------------------------- 1 | // Package rwfilefs extends the fs.FS interfaces to include the ability to write and remove files. 2 | package rwfilefs 3 | 4 | import ( 5 | "io/fs" 6 | ) 7 | 8 | type RemoveFileFS interface { 9 | fs.StatFS 10 | RemoveFile(name string) error 11 | } 12 | 13 | type WriteFileFS interface { 14 | fs.FS 15 | WriteFile(name string, data []byte, mode fs.FileMode) error 16 | } 17 | 18 | type RWFileFS interface { 19 | fs.ReadFileFS 20 | fs.StatFS 21 | RemoveFileFS 22 | WriteFileFS 23 | } 24 | -------------------------------------------------------------------------------- /.policy.yml: -------------------------------------------------------------------------------- 1 | policy: 2 | approval: 3 | - documentation validation passes or no documentation changes 4 | 5 | approval_rules: 6 | - name: documentation validation passes or no documentation changes 7 | if: 8 | file_not_deleted: 9 | paths: 10 | - .github/workflows/validate-documentation.yml 11 | requires: 12 | conditions: 13 | has_workflow_result: 14 | conclusions: 15 | - success 16 | workflows: 17 | - .github/workflows/validate-documentation.yml 18 | -------------------------------------------------------------------------------- /vale/dictionary/n.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('namespace', 'S', 'noun'), 4 | word.new('navigation', 'S', 'noun'), 5 | word.new('NAT', '', 'noun') { abbreviation: true, description: 'Network Address Translation', established_abbreviation: true }, 6 | word.new('nginx', '', 'noun'), 7 | word.new('Netlink', '', 'noun') { product: true, description: 'Netlink is a socket family used for inter-process communication (IPC) between both the kernel and userspace processes: https://en.wikipedia.org/wiki/Netlink' }, 8 | ] 9 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | - [ ] I've used a relevant pull request (PR) title. 8 | - [ ] I've added a link to any relevant issues in the PR description. 9 | - [ ] I've checked my changes on the deploy preview and they look good. 10 | - [ ] I've added an entry to the [What's new](https://github.com/grafana/writers-toolkit/blob/main/docs/sources/whats-new.md) page (only required for notable changes). 11 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Admonitions/testinvalid.md: -------------------------------------------------------------------------------- 1 | Don't use: 2 | 3 | - > **note:** 4 | - > **note**: 5 | - > **Note:** 6 | - > **Note**: 7 | - > **NOTE:** 8 | - > **NOTE**: 9 | 10 | - > **caution:** 11 | - > **caution**: 12 | - > **Caution:** 13 | - > **Caution**: 14 | - > **CAUTION:** 15 | - > **CAUTION**: 16 | 17 | - > **warning:** 18 | - > **warning**: 19 | - > **Warning:** 20 | - > **Warning**: 21 | - > **WARNING:** 22 | - > **WARNING**: 23 | 24 | - > **tip:** 25 | - > **tip**: 26 | - > **Tip:** 27 | - > **Tip**: 28 | - > **TIP:** 29 | - > **TIP**: 30 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/AmazonProductNames.yml: -------------------------------------------------------------------------------- 1 | "extends": "conditional" 2 | "first": "\\b(ARN|CloudWatch|Data Firehose|Elastic Kubernetes Service|Firehose|Kinesis|Relational Database Service|SSM|Timestream)\\b" 3 | "level": "warning" 4 | "link": "https://grafana.com/docs/writers-toolkit/write/style-guide/capitalization-punctuation/#amazon-products" 5 | "message": "Use the full Amazon product name in the first instance." 6 | "scope": "text" 7 | "second": "Amazon (ARN|CloudWatch|Data Firehose|Elastic Kubernetes Service|Firehose|Kinesis|Relational Database Service|SSM|Timestream)" 8 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Simple.yml: -------------------------------------------------------------------------------- 1 | action: 2 | name: remove 3 | extends: existence 4 | level: warning 5 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#simple 6 | message: | 7 | Avoid the word easy or simple -- what might be simple for you might not be simple for others. 8 | 9 | Try eliminating this word from the sentence because usually you can convey the same meaning without it. 10 | tokens: 11 | - "easy(?![ -]to[ -]understand)" 12 | - easily 13 | - simple 14 | - simply 15 | exceptions: 16 | - easy to understand 17 | - easy-to-understand 18 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Admonitions.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | message: | 3 | Prefer the `admonition` shortcode over blockquotes. 4 | 5 | The admonition shortcode renders its content in a blockquote with consistent styling across the website. 6 | link: https://grafana.com/docs/writers-toolkit/write/shortcodes/#admonition 7 | scope: raw 8 | script: | 9 | text := import("text") 10 | 11 | matches := [] 12 | 13 | for match in text.re_find(`(?i)> \*\*(?:note|warning|caution|tip):?\*\*`, scope, -1) { 14 | matches = append(matches, {begin: match[0].begin, end: match[0].end}) 15 | } 16 | -------------------------------------------------------------------------------- /vale/tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/writers-toolkit/vale/tools 2 | 3 | go 1.23.3 4 | 5 | require ( 6 | github.com/google/go-github/v72 v72.0.0 7 | github.com/grafana/writers-toolkit/tools v0.0.0-20250108111324-7ed051741521 8 | github.com/sourcegraph/go-diff v0.7.0 9 | github.com/stretchr/testify v1.10.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/google/go-querystring v1.1.0 // indirect 15 | github.com/kr/pretty v0.3.1 // indirect 16 | github.com/pmezard/go-difflib v1.0.0 // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Shortcodes.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | message: | 3 | Prefer `{{<` and `>}}` instead of `{{%` and `%}}` 4 | 5 | It has the most consistent semantics. 6 | 7 | The percent syntax is used for special behavior that isn't required with this shortcode. 8 | link: https://grafana.com/docs/writers-toolkit/write/shortcodes/#admonition 9 | scope: raw 10 | script: | 11 | text := import("text") 12 | 13 | matches := [] 14 | 15 | for match in text.re_find(`{{% +/?admonition .*%}}`, scope, -1) { 16 | matches = append(matches, {begin: match[0].begin, end: match[0].end}) 17 | } 18 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/OK.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | message: | 3 | Don't use any variation of okay in prose. 4 | The exceptions are when you’re referencing or quoting: 5 | 6 | - A user interface 7 | - HTTP status codes or other code 8 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#ok-okay 9 | level: warning 10 | ignorecase: false 11 | tokens: 12 | - O.K. 13 | - OK 14 | - ok 15 | - Ok 16 | - Okay 17 | - okay 18 | 19 | - A-OK 20 | - hokay 21 | - k 22 | - keh 23 | - kk 24 | - M'kay 25 | - oka 26 | - okeh 27 | - Okie dokie 28 | - Okily Dokily 29 | -------------------------------------------------------------------------------- /vale/Google/Headings.yml: -------------------------------------------------------------------------------- 1 | extends: capitalization 2 | message: "'%s' should use sentence-style capitalization." 3 | link: "https://developers.google.com/style/capitalization#capitalization-in-titles-and-headings" 4 | level: warning 5 | scope: heading 6 | match: $sentence 7 | indicators: 8 | - ":" 9 | exceptions: 10 | - Azure 11 | - CLI 12 | - Cosmos 13 | - Docker 14 | - Emmet 15 | - gRPC 16 | - I 17 | - Kubernetes 18 | - Linux 19 | - macOS 20 | - Marketplace 21 | - MongoDB 22 | - REPL 23 | - Studio 24 | - TypeScript 25 | - URLs 26 | - Visual 27 | - VS 28 | - Windows 29 | - JSON 30 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/AndOr/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:16:Grafana.AndOr:Avoid writing and/or except when space is limited, such as in tables. Often, 'and' implies 'or', so you don't need to write both words. If you need to specify both in your content, write something like "You can export raw events, processed events, or both." 2 | testinvalid.md:4:22:Grafana.AndOr:Avoid writing and/or except when space is limited, such as in tables. Often, 'and' implies 'or', so you don't need to write both words. If you need to specify both in your content, write something like "You can export raw events, processed events, or both." 3 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Archives/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Archives:Use 'extract' instead of 'unarchive'. 2 | testinvalid.md:4:3:Grafana.Archives:Use 'extract' instead of 'uncompress'. 3 | testinvalid.md:5:3:Grafana.Archives:Use 'extract' instead of 'untar'. 4 | testinvalid.md:7:3:Grafana.Archives:Use 'extract' instead of 'unzip'. 5 | testinvalid.md:9:3:Grafana.Archives:Use 'archive' or 'compressed file' instead of 'ZIP file'. 6 | testinvalid.md:11:3:Grafana.Archives:Use 'archive' or 'compressed file' instead of 'zip'. 7 | testinvalid.md:12:3:Grafana.Archives:Use 'archive' or 'compressed file' instead of 'ZIP'. 8 | -------------------------------------------------------------------------------- /vale/dictionary/word.jsonnet: -------------------------------------------------------------------------------- 1 | // The structure of the word object is documented in https://grafana.com/docs/writers-toolkit/review/lint-prose/dictionary/#word-metadata. 2 | { 3 | _prototype: { 4 | abbreviation: false, 5 | affixes: [], 6 | Amazon: false, 7 | Apache: false, 8 | Azure: false, 9 | Google: false, 10 | description: null, 11 | established_abbreviation: false, 12 | po: '', 13 | product: false, 14 | swaps: {}, 15 | word: '', 16 | }, 17 | 18 | new(word, affixes, po):: self._prototype { 19 | word: word, 20 | affixes: affixes, 21 | po: po, 22 | }, 23 | } 24 | -------------------------------------------------------------------------------- /vale/AmazonProductNames.jsonnet: -------------------------------------------------------------------------------- 1 | local defs = (import './dictionary.libsonnet').words; 2 | std.manifestYamlDoc({ 3 | extends: 'conditional', 4 | message: 'Use the full Amazon product name in the first instance.', 5 | link: 'https://grafana.com/docs/writers-toolkit/write/style-guide/capitalization-punctuation/#amazon-products', 6 | level: 'warning', 7 | 8 | local regexp = std.join('|', [ 9 | '%s' % def.word 10 | for def in defs 11 | if 'product' in def && def.product && 'Amazon' in def && def.Amazon 12 | ]), 13 | first: '\\b(%s)\\b' % regexp, 14 | second: 'Amazon (%s)' % regexp, 15 | scope: 'text', 16 | }) 17 | -------------------------------------------------------------------------------- /vale/ApacheProjectNames.jsonnet: -------------------------------------------------------------------------------- 1 | local defs = (import './dictionary.libsonnet').words; 2 | std.manifestYamlDoc({ 3 | extends: 'conditional', 4 | message: 'Use the full Apache project name in the first instance.', 5 | link: 'https://grafana.com/docs/writers-toolkit/write/style-guide/capitalization-punctuation/#apache-projects', 6 | level: 'warning', 7 | 8 | local regexp = std.join('|', [ 9 | '%s' % def.word 10 | for def in defs 11 | if 'product' in def && def.product && 'Apache' in def && def.Apache 12 | ]), 13 | first: '\\b(%s)\\b' % regexp, 14 | second: 'Apache (%s)' % regexp, 15 | scope: 'text', 16 | }) 17 | -------------------------------------------------------------------------------- /vale/GoogleProductNames.jsonnet: -------------------------------------------------------------------------------- 1 | local defs = (import './dictionary.libsonnet').words; 2 | std.manifestYamlDoc({ 3 | extends: 'conditional', 4 | message: 'Use the full Google product name in the first instance.', 5 | link: 'https://grafana.com/docs/writers-toolkit/write/style-guide/capitalization-punctuation/#google-products', 6 | level: 'warning', 7 | 8 | local regexp = std.join('|', [ 9 | '%s' % def.word 10 | for def in defs 11 | if 'product' in def && def.product && 'Google' in def && def.Google 12 | ]), 13 | first: '\\b(%s)\\b' % regexp, 14 | second: 'Google (%s)' % regexp, 15 | scope: 'text', 16 | }) 17 | -------------------------------------------------------------------------------- /deploy-preview/config.yaml: -------------------------------------------------------------------------------- 1 | "Params": 2 | "sitemapExclude": "/" 3 | "build": 4 | "buildStatus": 5 | "enable": false 6 | "disableKinds": 7 | - "robotstxt" 8 | - "rss" 9 | - "sitemap" 10 | - "taxonomy" 11 | - "term" 12 | "disableLanguages": 13 | - "de" 14 | - "fr" 15 | - "es" 16 | - "pt-br" 17 | - "zh-cn" 18 | - "ja" 19 | "enableGitInfo": false 20 | "outputs": 21 | "home": 22 | [ 23 | "HTML", 24 | "Header", 25 | "Footer", 26 | "head", 27 | "styles", 28 | "ssi_footer", 29 | "scripts", 30 | "Assets", 31 | ] 32 | "section": 33 | - "HTML" 34 | - "JSON" 35 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "writers-toolkit", 3 | "version": "1.0.0", 4 | "description": "Guidelines for contributors who are interested in improving our technical content", 5 | "scripts": {}, 6 | "repository": { 7 | "type": "git", 8 | "url": "git+https://github.com/grafana/writers-toolkit.git" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "Apache-2.0", 13 | "bugs": { 14 | "url": "https://github.com/grafana/writers-toolkit/issues" 15 | }, 16 | "homepage": "https://grafana.com/docs/writers-toolkit", 17 | "devDependencies": { 18 | "prettier": "3.5.3" 19 | }, 20 | "engines": {} 21 | } 22 | -------------------------------------------------------------------------------- /vale/README.md: -------------------------------------------------------------------------------- 1 | # Vale 2 | 3 | The [`.vale.ini`](.vale.ini) file in this directory is only for the container image. 4 | For linting of this repository, the [`.vale.ini`](../.vale.ini) file in the root of the repository is used. 5 | The two files should be mostly similar with the exception of the `Packages` and `StylesPath` configurations. 6 | Perhaps in the future, these will be sourced from a single place. 7 | 8 | The Grafana style extends the Google style and disables some rules. 9 | The Google style is vendored in the repository. 10 | To update the Google style, run `make sync`. 11 | 12 | To build the container image, run `make grafana/vale`. 13 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Agentless.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: | 3 | Use '%s' instead of '%s'. 4 | 5 | Grafana Agent has been replaced by Grafana Alloy, so you shouldn't use agent-based terminology. 6 | 7 | If you're talking about why and how to send signals directly from an application to Grafana Cloud, prefer no-collector to agentless. 8 | 9 | This is consistent with [OTel documentation](https://opentelemetry.io/docs/collector/deployment/no-collector/). 10 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#no-collector 11 | level: warning 12 | action: 13 | name: replace 14 | swap: 15 | agentless: no-collector 16 | -------------------------------------------------------------------------------- /vale/dictionary/e.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('eBPF', '', 'noun') { abbreviation: true, established_abbreviation: true }, 4 | word.new('EKS', '', 'noun') { abbreviation: true, elaboration: 'Elastic Kubernetes Service', product: true }, 5 | word.new('Elastic Kubernetes Service', '', 'noun') { Amazon: true, product: true }, 6 | word.new('email', '', 'noun') { swaps: { '(?:[eE]-mail)': 'email' } }, 7 | word.new('enablement', '', 'noun'), 8 | word.new('enqueue', 'DS', 'verb'), 9 | word.new('Entra', '', 'noun') { Azure: true, product: true }, 10 | word.new('ESLint', 'M', 'noun'), 11 | word.new('etcd', '', 'noun'), 12 | ] 13 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Gerunds/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Gerunds:For a task-based heading, start with a [bare infinitive](https://en.wikipedia.org/wiki/Infinitive#English), also known as a plain form or [base form](https://en.wikipedia.org/wiki/English_verbs#Base_form) verb. In English, the imperative mood also uses the base form verb, so it looks the same as the bare infinitive. Task-based headings are frequently used in quickstarts, how-to documents, and tutorials. For a conceptual or non-task-based heading, use a [noun phrase](https://en.wikipedia.org/wiki/Noun_phrase) that doesn't start with an -ing verb. Noun-phrase headings are frequently used in concept documentation. 2 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/Relref.tengo: -------------------------------------------------------------------------------- 1 | DEBUG := false 2 | 3 | fmt := import("fmt") 4 | text := import("text") 5 | 6 | matches := [] 7 | ruleActive := true 8 | 9 | cursor := 0 10 | for line in text.split(scope, "\n") { 11 | if DEBUG { 12 | fmt.println(text.pad_left(text.itoa(cursor), 3, " "), ": ", text.quote(line), " ", len(line)) 13 | } 14 | 15 | if ruleActive { 16 | for match in text.re_find(`\({{[%<] *relref`, line, -1) { 17 | matches = append(matches, {begin: cursor + match[0].begin, end: cursor + match[0].end}) 18 | } 19 | } 20 | 21 | cursor += len(line) + 1 22 | } 23 | 24 | if DEBUG { 25 | for match in matches { 26 | fmt.println(match) 27 | } 28 | } -------------------------------------------------------------------------------- /vale/.vale.jsonnet: -------------------------------------------------------------------------------- 1 | { 2 | configuration: { 3 | main: { 4 | StylesPath: '/etc/vale/styles', 5 | MinAlertLevel: 'suggestion', 6 | 7 | Packages: 'Google, https://github.com/errata-ai/Hugo/releases/download/v0.2.0/Hugo.zip, Readability', 8 | }, 9 | sections: { 10 | '*': { 11 | BasedOnStyles: 'Grafana', 12 | 13 | // https://github.com/errata-ai/vale/issues/288 14 | TokenIgnores: @'(+?), \*\*[^\n]+\*\*', 15 | }, 16 | }, 17 | }, 18 | 19 | container: std.manifestIni(self.configuration), 20 | 21 | repository: std.manifestIni(self.configuration { 22 | main+: { 23 | StylesPath: 'vale', 24 | }, 25 | }), 26 | } 27 | -------------------------------------------------------------------------------- /.github/workflows/prettier.yml: -------------------------------------------------------------------------------- 1 | name: Run `prettier` on a branch 2 | 3 | permissions: {} 4 | 5 | on: 6 | workflow_dispatch: 7 | inputs: 8 | path: 9 | default: docs/sources 10 | description: Path to run `prettier` on. 11 | type: string 12 | 13 | jobs: 14 | prettier: 15 | permissions: 16 | contents: read 17 | id-token: write 18 | if: github.repository == 'grafana/writers-toolkit' 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: grafana/writers-toolkit/prettier@main # zizmor: ignore[unpinned-uses] It's a protected branch in the same repository. 22 | with: 23 | branch: ${{ env.GITHUB_REF }} 24 | path: ${{ inputs.path }} 25 | -------------------------------------------------------------------------------- /vale/ProductPossessives.jsonnet: -------------------------------------------------------------------------------- 1 | local defs = (import './dictionary.libsonnet').words; 2 | std.manifestYamlDoc({ 3 | extends: 'existence', 4 | level: 'warning', 5 | link: 'https://developers.google.com/style/possessives#product,-feature,-and-company-names', 6 | message: ||| 7 | Don't form a possessive from a feature name, product name, or trademark, regardless of who owns it. 8 | Instead, use the name as a modifier or rewrite to use a word like of to indicate the relationship. 9 | |||, 10 | tokens: [ 11 | (if def.word[std.length(def.word) - 1] == 's' 12 | then def.word + "'" 13 | else def.word + "'s") 14 | for def in defs 15 | if 'product' in def && def.product 16 | ], 17 | }) 18 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Kubernetes.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/capitalization-punctuation/#kubernetes-objects 4 | message: Use '%s' instead of '%s'. 5 | 6 | ignorecase: false 7 | 8 | action: 9 | name: replace 10 | swap: 11 | cron job: CronJob 12 | 13 | # It would be nice to have deployment -> Deployment but I foresee more false positives. 14 | # deployment: Deployment 15 | "[Kk]ubernetes deployment": Kubernetes Deployment 16 | 17 | "d[ae][ae]mon[Ss]et": DaemonSet 18 | "replica[Ss]et": ReplicaSet 19 | "stateful[Ss]et": StatefulSet 20 | pod: Pod 21 | 22 | "[Kk]ubelet": "`kubelet`" 23 | "[Kk]ubectl": "`kubectl`" 24 | -------------------------------------------------------------------------------- /.github/workflows/publish-technical-documentation.yml: -------------------------------------------------------------------------------- 1 | name: publish-technical-documentation 2 | 3 | permissions: {} 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | paths: 10 | - "docs/sources/**" 11 | workflow_dispatch: 12 | 13 | jobs: 14 | sync: 15 | if: github.repository == 'grafana/writers-toolkit' 16 | permissions: 17 | contents: read 18 | id-token: write 19 | runs-on: ubuntu-latest 20 | steps: 21 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 22 | with: 23 | persist-credentials: false 24 | - uses: ./publish-technical-documentation 25 | with: 26 | website_directory: content/docs/writers-toolkit 27 | -------------------------------------------------------------------------------- /vale/Acronyms.jsonnet: -------------------------------------------------------------------------------- 1 | local defs = (import './dictionary.libsonnet').words; 2 | std.manifestYamlDoc({ 3 | extends: 'conditional', 4 | message: "Spell out '%s', if it's unfamiliar to the audience.", 5 | link: 'https://developers.google.com/style/abbreviations', 6 | level: 'suggestion', 7 | ignorecase: false, 8 | // Ensures that the existence of 'first' implies the existence of 'second'. 9 | first: '\\b([A-Z]{3,5})\\b', 10 | second: '(?:\\b[A-Z][a-z]+ )+\\(([A-Z]{3,5})\\)', 11 | // ... with the exception of these: 12 | exceptions: [ 13 | '%s' % def.word 14 | for def in defs 15 | if 'abbreviation' in def && def.abbreviation && 'established_abbreviation' in def && def.established_abbreviation 16 | ], 17 | }) 18 | -------------------------------------------------------------------------------- /vale/Google/Contractions.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: "Use '%s' instead of '%s'." 3 | link: "https://developers.google.com/style/contractions" 4 | level: suggestion 5 | ignorecase: true 6 | action: 7 | name: replace 8 | swap: 9 | are not: aren't 10 | cannot: can't 11 | could not: couldn't 12 | did not: didn't 13 | do not: don't 14 | does not: doesn't 15 | has not: hasn't 16 | have not: haven't 17 | how is: how's 18 | is not: isn't 19 | it is: it's 20 | should not: shouldn't 21 | that is: that's 22 | they are: they're 23 | was not: wasn't 24 | we are: we're 25 | we have: we've 26 | were not: weren't 27 | what is: what's 28 | when is: when's 29 | where is: where's 30 | will not: won't 31 | -------------------------------------------------------------------------------- /tools/rwfilefs/mapfs.go: -------------------------------------------------------------------------------- 1 | package rwfilefs 2 | 3 | import ( 4 | "io/fs" 5 | "testing/fstest" 6 | "time" 7 | ) 8 | 9 | // MapFS is an implementation of fstest.MapFS that implements 10 | // the RWFileFS interface. 11 | type MapFS struct { 12 | fstest.MapFS 13 | } 14 | 15 | // WriteFile implements the RWFileFS interface. 16 | func (fs MapFS) WriteFile(name string, data []byte, mode fs.FileMode) error { 17 | fs.MapFS[name] = &fstest.MapFile{ 18 | Data: data, 19 | Mode: mode, 20 | ModTime: time.Now(), 21 | Sys: nil, 22 | } 23 | 24 | return nil 25 | } 26 | 27 | // RemoveFile implements the RWFileFS interface. 28 | func (fs MapFS) RemoveFile(name string) error { 29 | delete(fs.MapFS, name) 30 | 31 | return nil 32 | } 33 | -------------------------------------------------------------------------------- /deploy-preview/urls: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euf -o pipefail 4 | 5 | if [[ -n "${RUNNER_DEBUG+x}" ]]; then 6 | set -x 7 | fi 8 | 9 | # All input comes from environment variables that are capitalized by convention in this script. 10 | readonly GITHUB_OUTPUT="${GITHUB_OUTPUT:-/dev/stdout}" 11 | readonly SOURCES="${SOURCES:-[]}" 12 | readonly URL="${URL:-}" 13 | 14 | if ! jq -e . <<<"${SOURCES}" >/dev/null; then 15 | echo "SOURCES environment variable is not valid JSON" 16 | 17 | exit 1 18 | fi 19 | 20 | echo "urls<> "${GITHUB_OUTPUT}" 21 | while read -r relative_prefix; do 22 | echo "- ${URL}${relative_prefix}" >> "${GITHUB_OUTPUT}" 23 | done < <(jq -r '.[].relative_prefix' <<<"${SOURCES}") 24 | echo "EOF" >> "${GITHUB_OUTPUT}" 25 | -------------------------------------------------------------------------------- /docs/sources/review/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | aliases: 3 | - /docs/writers-toolkit/writing-guide/tooling-and-workflows/ 4 | - /docs/writers-toolkit/review/ 5 | date: "2023-07-11T10:24:20-04:00" 6 | description: 7 | Build and review your content locally. Learn how to use documentation 8 | tools and understand our workflows. 9 | keywords: 10 | - build 11 | - documentation 12 | - review 13 | - test 14 | menuTitle: Build and review 15 | review_date: "2024-09-04" 16 | title: Build and review documentation 17 | weight: 800 18 | --- 19 | 20 | # Build and review documentation 21 | 22 | You should test any content that you create before you create a pull request. 23 | Reviewers use the same tooling to review pull requests. 24 | 25 | The build and review section covers the follow topics: 26 | 27 | {{< section withDescriptions="true" >}} 28 | -------------------------------------------------------------------------------- /vale/tools/.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable-all: true 3 | disable: 4 | # WARN The linter 'exportloopref' is deprecated (since v1.60.2) due to: Since Go1.22 (loopvar) this linter is no longer relevant. Replaced by copyloopvar. 5 | - exportloopref 6 | # Long line lengths are a presentation issue. 7 | - lll 8 | linters-settings: 9 | depguard: 10 | rules: 11 | main: 12 | allow: 13 | - $gostd 14 | - github.com/google/go-github/v60/github 15 | - github.com/grafana/writers-toolkit/vale/tools/cmd/filter-sarif/sarif 16 | - github.com/stretchr/testify/assert 17 | - github.com/stretchr/testify/require 18 | - github.com/grafana/writers-toolkit/tools/exit 19 | - rsc.io/tmp/patch 20 | varnamelen: 21 | ignore-names: 22 | - f # Files 23 | -------------------------------------------------------------------------------- /add-to-docs-project/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "@jdbaldry", 3 | "dependencies": { 4 | "@actions/core": "1.11.1", 5 | "@octokit/graphql": "8.2.2", 6 | "@octokit/rest": "21.1.1" 7 | }, 8 | "description": "Adds all issues labeled `type/docs` to the Docs organization project.", 9 | "devDependencies": { 10 | "@types/node": "22.15.17", 11 | "ts-node": "10.9.2", 12 | "typescript": "5.8.3" 13 | }, 14 | "engines": { 15 | "node": ">=22", 16 | "npm": ">=10" 17 | }, 18 | "license": "Apache-2.0", 19 | "main": "index.mts", 20 | "name": "add-to-docs-project", 21 | "private": false, 22 | "repository": "https://github.com/grafana/writers-toolkit/tree/main/add-to-docs-project", 23 | "scripts": { 24 | "build": "tsc", 25 | "execute": "node --loader ts-node/esm index.mts" 26 | }, 27 | "version": "1.0.0" 28 | } 29 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleContractions.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "replace" 3 | "extends": "substitution" 4 | "ignorecase": true 5 | "level": "suggestion" 6 | "link": "https://developers.google.com/style/contractions" 7 | "message": "Use '%s' instead of '%s'." 8 | "swap": 9 | "are not": "aren't" 10 | "cannot": "can't" 11 | "could not": "couldn't" 12 | "did not": "didn't" 13 | "do not": "don't" 14 | "does not": "doesn't" 15 | "has not": "hasn't" 16 | "have not": "haven't" 17 | "how is": "how's" 18 | "is not": "isn't" 19 | "it is": "it's" 20 | "should not": "shouldn't" 21 | "that is": "that's" 22 | "they are": "they're" 23 | "was not": "wasn't" 24 | "we are": "we're" 25 | "we have": "we've" 26 | "were not": "weren't" 27 | "what is": "what's" 28 | "when is": "when's" 29 | "where is": "where's" 30 | "will not": "won't" 31 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Kubernetes/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Kubernetes:Use 'CronJob' instead of 'cron job'. 2 | testinvalid.md:4:3:Grafana.Kubernetes:Use 'DaemonSet' instead of 'deamonset'. 3 | testinvalid.md:5:3:Grafana.Kubernetes:Use 'Kubernetes Deployment' instead of 'Kubernetes deployment'. 4 | testinvalid.md:6:3:Grafana.Kubernetes:Use 'Pod' instead of 'pod'. 5 | testinvalid.md:7:3:Grafana.Kubernetes:Use 'ReplicaSet' instead of 'replicaset'. 6 | testinvalid.md:8:3:Grafana.Kubernetes:Use 'StatefulSet' instead of 'statefulset'. 7 | testinvalid.md:9:3:Grafana.Kubernetes:Use '`kubelet`' instead of 'kubelet'. 8 | testinvalid.md:10:3:Grafana.Kubernetes:Use '`kubectl`' instead of 'kubectl'. 9 | testinvalid.md:11:3:Grafana.Kubernetes:Use '`kubectl`' instead of 'Kubectl'. 10 | testinvalid.md:12:3:Grafana.Kubernetes:Use '`kubelet`' instead of 'Kubelet'. 11 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Agentless/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Agentless:Use 'no-collector' instead of 'agentless'. Grafana Agent has been replaced by Grafana Alloy, so you shouldn't use agent-based terminology. If you're talking about why and how to send signals directly from an application to Grafana Cloud, prefer no-collector to agentless. This is consistent with [OTel documentation](https://opentelemetry.io/docs/collector/deployment/no-collector/). 2 | testinvalid.md:4:3:Grafana.Agentless:Use 'no-collector' instead of 'agentless'. Grafana Agent has been replaced by Grafana Alloy, so you shouldn't use agent-based terminology. If you're talking about why and how to send signals directly from an application to Grafana Cloud, prefer no-collector to agentless. This is consistent with [OTel documentation](https://opentelemetry.io/docs/collector/deployment/no-collector/). 3 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Latin/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Latin:Use 'for example' instead of 'e.g'. 2 | testinvalid.md:4:3:Grafana.Latin:Use 'for example' instead of 'e.g'. 3 | testinvalid.md:5:3:Grafana.Latin:Use 'for example' instead of 'e.g'. 4 | testinvalid.md:6:3:Grafana.Latin:Use 'for example' instead of 'eg'. 5 | testinvalid.md:7:3:Grafana.Latin:Use 'for example' instead of 'eg'. 6 | testinvalid.md:8:3:Grafana.Latin:Use 'for example' instead of 'eg'. 7 | testinvalid.md:9:3:Grafana.Latin:Use 'that is' instead of 'i.e'. 8 | testinvalid.md:10:3:Grafana.Latin:Use 'that is' instead of 'i.e'. 9 | testinvalid.md:11:3:Grafana.Latin:Use 'that is' instead of 'i.e'. 10 | testinvalid.md:12:3:Grafana.Latin:Use 'that is' instead of 'ie'. 11 | testinvalid.md:13:3:Grafana.Latin:Use 'that is' instead of 'ie'. 12 | testinvalid.md:14:3:Grafana.Latin:Use 'that is' instead of 'ie'. 13 | -------------------------------------------------------------------------------- /docs/sources/write/style-guide/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | aliases: 3 | - /docs/writers-toolkit/style-guide/ 4 | - /docs/writers-toolkit/write/style-guide 5 | date: "2022-06-27T11:51:13-05:00" 6 | description: Style guide for Grafana Labs 7 | keywords: 8 | - Grafana 9 | - style guide 10 | review_date: "2024-06-27" 11 | title: Style guide 12 | weight: 100 13 | --- 14 | 15 | # Style guide 16 | 17 | This style guide is a set of content guidelines that covers aspects of content style such as grammar, language, formatting, and tone. 18 | It's intended for anyone who contributes to technical documentation at Grafana Labs. 19 | 20 | It includes rules and best practices on the following: 21 | 22 | {{< section menuTitle="true" withDescriptions="true" >}} 23 | 24 | When a matter of style isn't covered here, refer to the [Google developer documentation style guide](https://developers.google.com/style). 25 | -------------------------------------------------------------------------------- /docs/sources/write/style-guide/security/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2025-12-04T14:00:01Z" 3 | description: Guidelines for how to write security-concious documentation. 4 | keywords: 5 | - Grafana 6 | - security 7 | review_date: "2025-12-04" 8 | title: Security 9 | weight: 0 10 | --- 11 | 12 | # Security 13 | 14 | While there is no expectation that writers or engineers are security experts, we want to ensure that our documentation takes security into mind. 15 | 16 | ## Invalid tokens 17 | 18 | It is rarely necessary for documentation to include tokens that are or look valid. 19 | We prefer to mimic valid token formats, where we replace the majority of the tokens with text that makes them obviously invalid. 20 | 21 | Examples of obviously invalid tokens would be: 22 | 23 | - Grafana Labs tokens: `glsa_iNValIdinValiDinvalidinvalidinva_5b582697`. 24 | - GitHub tokens: `github_pat_XXXXXXXXXXXXXXXX`. 25 | -------------------------------------------------------------------------------- /.github/workflows/validate-policy-bot-config.yml: -------------------------------------------------------------------------------- 1 | name: Validate Policy Bot Config 2 | 3 | permissions: {} 4 | 5 | on: 6 | pull_request: 7 | paths: 8 | - ".policy.yml" 9 | 10 | push: 11 | branches: 12 | - main 13 | paths: 14 | - ".policy.yml" 15 | 16 | jobs: 17 | validate: 18 | name: Validate policy bot config 19 | 20 | runs-on: ubuntu-latest 21 | permissions: 22 | contents: read 23 | 24 | steps: 25 | - name: Checkout code 26 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | with: 28 | persist-credentials: false 29 | 30 | - name: Validate policy bot config 31 | run: > 32 | curl 33 | --silent 34 | --fail-with-body 35 | --request PUT 36 | --upload-file .policy.yml 37 | https://github-policy-bot.grafana-ops.net/api/validate 38 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/SQL.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | level: warning 3 | link: https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/#sql-structured-query-language 4 | message: | 5 | Use '%s' instead of '%s'. 6 | 7 | The article—a or an—that you use before the acronym SQL depends on how the word is pronounced. 8 | 9 | When referring to the product Microsoft SQL Server, SQL should be pronounced "sequel". 10 | In this case, use the article 'a', as in "a SQL Server analysis". 11 | 12 | When referring to the term in any other context, such as SQL databases, errors, or servers, SQL should be pronounced "ess-cue-el". 13 | In this case, use the article 'an', as in "an SQL error". 14 | 15 | ignorecase: false 16 | 17 | action: 18 | name: replace 19 | swap: 20 | "[Aa] SQL server": an SQL server|a SQL Server 21 | "[Aa] SQL(?! [Ss]erver)": an SQL 22 | "[Aa]n SQL Server": a SQL Server 23 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Timeless.yml: -------------------------------------------------------------------------------- 1 | extends: existence 2 | level: suggestion 3 | link: https://developers.google.com/style/timeless-documentation 4 | message: | 5 | Avoid using '%s' to keep the documentation timeless. 6 | 7 | In general, document the current version of a product or feature. 8 | 9 | It reduces the maintenance required to keep documentation up to date. 10 | It avoids assuming the reader is familiar with earlier versions of the product. 11 | 12 | If you're writing procedural or time-stamped content such as press releases, blog posts, or release notes, such time-based words and phrases are OK. 13 | 14 | tokens: 15 | - as of this writing 16 | - currently 17 | - does not yet 18 | - eventually 19 | - existing 20 | - future 21 | - in the future 22 | - latest 23 | - new 24 | - newer 25 | - now 26 | - old 27 | - older 28 | - presently 29 | - at present 30 | - soon 31 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/Paragraphs.tengo: -------------------------------------------------------------------------------- 1 | DEBUG := false 2 | 3 | fmt := import("fmt") 4 | text := import("text") 5 | 6 | matches := [] 7 | ruleActive := true 8 | 9 | cursor := 0 10 | for line in text.split(scope, "\n") { 11 | if DEBUG { 12 | fmt.println(text.pad_left(text.itoa(cursor), 3, " "), ": ", text.quote(line), " ", len(line)) 13 | } 14 | 15 | if text.re_find(``, line, -1) { 16 | ruleActive = false 17 | } 18 | 19 | if text.re_find(``, line, -1) { 20 | ruleActive = true 21 | } 22 | 23 | if ruleActive { 24 | for match in text.re_find(`
`, line, -1) { 25 | matches = append(matches, {begin: cursor + match[0].begin, end: cursor + match[0].end}) 26 | } 27 | } 28 | 29 | cursor += len(line) + 1 30 | } 31 | 32 | if DEBUG { 33 | for match in matches { 34 | fmt.println(match) 35 | } 36 | } -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/SmartQuotes.tengo: -------------------------------------------------------------------------------- 1 | DEBUG := false 2 | 3 | fmt := import("fmt") 4 | text := import("text") 5 | 6 | matches := [] 7 | ruleActive := true 8 | 9 | cursor := 0 10 | for line in text.split(scope, "\n") { 11 | if DEBUG { 12 | fmt.println(text.pad_left(text.itoa(cursor), 3, " "), ": ", text.quote(line), " ", len(line)) 13 | } 14 | 15 | if text.re_find(``, line, -1) { 16 | ruleActive = false 17 | } 18 | 19 | if text.re_find(``, line, -1) { 20 | ruleActive = true 21 | } 22 | 23 | if ruleActive { 24 | for match in text.re_find(`[‘’ʼ“”]`, line, -1) { 25 | matches = append(matches, {begin: cursor + match[0].begin, end: cursor + match[0].end}) 26 | } 27 | } 28 | 29 | cursor += len(line) + 1 30 | } 31 | 32 | if DEBUG { 33 | for match in matches { 34 | fmt.println(match) 35 | } 36 | } -------------------------------------------------------------------------------- /vale/dictionary/h.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('Hashicorp', '', 'noun') { elaboration: 'A company that produces a suite of infrastructure automation products.' }, 4 | word.new('hashmod', '', 'noun') { description: 'A program that distributes an enabled / disabled flag across a cluster without coordination, using consistent hashing.', product: true }, 5 | word.new('heatmap', 'S', 'noun'), 6 | word.new('hostname', 'S', 'noun'), 7 | word.new('HPA', 'S', 'noun'), 8 | word.new('HTML', '', 'noun') { abbreviation: true, elaboration: 'HyperText Markup Language', established_abbreviation: true }, 9 | word.new('HTTP', '', 'noun') { abbreviation: true, elaboration: 'HyperText Transfer Protocol', established_abbreviation: true }, 10 | word.new('HTTPS', '', 'noun') { abbreviation: true, elaboration: 'HyperText Transfer Protocol Secure', established_abbreviation: true, swaps: { HTTPs: 'HTTPS' } }, 11 | ] 12 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/DocumentationTeam/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'docs squad'. 2 | testinvalid.md:4:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'Docs squad'. 3 | testinvalid.md:5:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'docs Squad'. 4 | testinvalid.md:6:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'Docs Squad'. 5 | testinvalid.md:7:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'docs team'. 6 | testinvalid.md:8:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'Docs team'. 7 | testinvalid.md:9:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'docs Team'. 8 | testinvalid.md:10:3:Grafana.DocumentationTeam:Use 'the Grafana Labs documentation team' rather than 'Docs team'. 9 | -------------------------------------------------------------------------------- /.github/workflows/image.yml: -------------------------------------------------------------------------------- 1 | name: Publish grafana/vale image 2 | 3 | permissions: {} 4 | 5 | on: 6 | push: 7 | branches: 8 | - main 9 | workflow_dispatch: 10 | 11 | jobs: 12 | build: 13 | if: ${{ github.repository == 'grafana/writers-toolkit' }} 14 | permissions: 15 | contents: read 16 | id-token: write 17 | runs-on: ubuntu-latest 18 | 19 | steps: 20 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | with: 22 | persist-credentials: false 23 | 24 | - id: push-to-dockerhub 25 | uses: grafana/shared-workflows/actions/build-push-to-dockerhub@45747d11c20341064eab8c186e00a46d20ba4e73 # build-push-to-dockerhub-v0.1.0 26 | with: 27 | context: vale 28 | platforms: linux/amd64,linux/arm64 29 | push: true 30 | repository: grafana/vale 31 | tags: |- 32 | ${{ github.sha }} 33 | latest 34 | -------------------------------------------------------------------------------- /vale/Dockerfile: -------------------------------------------------------------------------------- 1 | ################################################################################ 2 | FROM --platform=${BUILDPLATFORM} golang:alpine@sha256:26111811bc967321e7b6f852e914d14bede324cd1accb7f81811929a6a57fea9 AS filter-sarif 3 | ARG TARGETOS TARGETARCH 4 | 5 | RUN mkdir /src /out 6 | COPY /tools /src 7 | 8 | WORKDIR /src 9 | RUN GOOS="${TARGETOS}" GOARCH="${TARGETARCH}" go build -o filter-sarif ./cmd/filter-sarif 10 | RUN mv filter-sarif /out 11 | 12 | ################################################################################ 13 | FROM jdkato/vale:v3.8.0@sha256:a744bc4f8164bceab6bda0fad6253dcd9cdab2365b437aa5e08fe4f07d6e3357 14 | 15 | COPY --from=filter-sarif /out/filter-sarif /bin 16 | 17 | # Git is useful for diffing changed files. 18 | RUN apk add --no-cache git 19 | 20 | RUN mkdir -p /etc/vale 21 | WORKDIR /etc/vale 22 | 23 | COPY .vale.ini /etc/vale/.vale.ini 24 | COPY sarif.tmpl /etc/vale/sarif.tmpl 25 | COPY Grafana /etc/vale/Grafana 26 | 27 | RUN vale sync 28 | -------------------------------------------------------------------------------- /vale/dictionary/i.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('IBM', '', 'noun') { abbreviation: true, established_abbreviation: true, product: true }, 4 | word.new('ICU', '', 'noun') { abbreviation: true, elaboration: 'International Components for Unicode' }, 5 | word.new('IDE', 'S', 'noun') { abbreviation: true, elaboration: 'integrated development environment', established_abbreviation: true }, 6 | word.new('inclusivity', '', 'noun'), 7 | word.new('InfluxDB', '', 'noun') { product: true, swaps: { 'influx[Dd][Bb]': 'InfluxDB', 'Influx[Dd]b': 'InfluxDB', 'Influxd[Bb]': 'InfluxDB' } }, 8 | word.new('ingester', 'MS', 'noun'), 9 | word.new('inode', 'S', 'noun') { description: 'A data structure in a Unix-style file system that describes a file-system object such as a file or a directory (https://en.wikipedia.org/wiki/Inode)' }, 10 | word.new('instrumentation', 'S', 'noun'), 11 | word.new('intrinsic', 'S', 'noun'), 12 | word.new('Istio', '', 'noun'), 13 | ] 14 | -------------------------------------------------------------------------------- /docs/static/templates/section-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | cards: 3 | items: 4 | - description: 5 | height: 24 6 | href: 7 | logo: 8 | title: 9 | - description: <DESCRIPTION FOR SECOND PAGE> 10 | height: 24 11 | href: <LINK TO SECOND PAGE> 12 | logo: <IMAGE URL FOR SECOND PAGE> 13 | title: <TITLE OF SECOND PAGE> 14 | title_class: pt-0 lh-1 15 | description: <PAGE DESCRIPTION> 16 | hero: 17 | description: <HERO BODY TEXT DESCRIBING THE SECTION> 18 | height: 110 19 | image: <IMAGE URL FOR HERO> 20 | level: 1 21 | title: <PAGE TITLE> 22 | width: 110 23 | menuTitle: <MENU TITLE> 24 | title: <PAGE TITLE> 25 | --- 26 | 27 | {{< docs/hero-simple key="hero" >}} 28 | 29 | --- 30 | 31 | ## Overview 32 | 33 | <!-- Include an overview of the section explaining the content within. --> 34 | 35 | ## Explore 36 | 37 | {{< card-grid key="cards" type="simple" >}} 38 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/go.sum: -------------------------------------------------------------------------------- 1 | github.com/d5/tengo/v2 v2.17.0 h1:BWUN9NoJzw48jZKiYDXDIF3QrIVZRm1uV1gTzeZ2lqM= 2 | github.com/d5/tengo/v2 v2.17.0/go.mod h1:XRGjEs5I9jYIKTxly6HCF8oiiilk5E/RYXOZ5b0DZC8= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 6 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 7 | github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= 8 | github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 9 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 10 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 11 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 12 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Ordinal/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 2 | testinvalid.md:4:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 3 | testinvalid.md:5:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 4 | testinvalid.md:6:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 5 | testinvalid.md:7:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 6 | testinvalid.md:8:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 7 | testinvalid.md:9:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 8 | testinvalid.md:10:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 9 | testinvalid.md:11:3:Grafana.Ordinal:For ordinals, write out first through ninth. For 10th on, use numerals. 10 | -------------------------------------------------------------------------------- /vale/dictionary/f.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('FAQ', 'S', 'noun') { abbreviation: true, elaboration: 'frequently asked question', established_abbreviation: true }, 4 | word.new('Fargate', 'M', 'noun'), 5 | word.new('FCP', '', 'noun') { abbreviation: true, elaboration: 'First Contentful Paint' }, 6 | word.new('FID', '', 'noun') { abbreviation: true, elaboration: 'First Input Delay' }, 7 | word.new('Figma', '', 'noun') { description: 'Figma design tool (https://www.figma.com/login)', product: true, swaps: { figma: 'Figma' } }, 8 | word.new('filename', 'S', 'noun') { swaps: { 'file name': 'filename', 'file names': 'filenames' } }, 9 | word.new('Firehose', 'M', 'noun') { Amazon: true, product: true }, 10 | word.new('firewall rules', '', 'noun') { swaps: { firewalls: 'firewall rules' } }, 11 | word.new('FreeBSD', '', 'noun') { description: 'FreeBSD operating system', product: true }, 12 | word.new('frontend', 'S', 'noun') { swaps: { 'front[ -]end': 'frontend', 'front[ -]ends': 'frontends' } }, 13 | ] 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Gerunds.yml: -------------------------------------------------------------------------------- 1 | extends: script 2 | message: | 3 | For a task-based heading, start with a [bare infinitive](https://en.wikipedia.org/wiki/Infinitive#English), also known as a plain form or [base form](https://en.wikipedia.org/wiki/English_verbs#Base_form) verb. 4 | In English, the imperative mood also uses the base form verb, so it looks the same as the bare infinitive. 5 | 6 | Task-based headings are frequently used in quickstarts, how-to documents, and tutorials. 7 | 8 | For a conceptual or non-task-based heading, use a [noun phrase](https://en.wikipedia.org/wiki/Noun_phrase) that doesn't start with an -ing verb. 9 | 10 | Noun-phrase headings are frequently used in concept documentation. 11 | link: https://developers.google.com/style/headings#heading-and-title-text 12 | scope: heading 13 | script: | 14 | text := import("text") 15 | 16 | matches := [] 17 | 18 | for match in text.re_find(`^ *[A-Z][a-zA-Z]*ing .*$`, scope, -1) { 19 | matches = append(matches, {begin: match[0].begin, end: match[0].end}) 20 | } 21 | -------------------------------------------------------------------------------- /vale/dictionary/w.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('WAL', 'S', 'noun') { abbreviation: true, elaboration: 'write-ahead log' }, 4 | word.new('walkthrough', 'S', 'noun'), 5 | word.new('web', '', 'noun') { swaps: { '[Ww]orld [Ww]ide [Ww]eb': 'web' } }, 6 | word.new('Webpack', '', 'noun'), 7 | word.new('webserver', 'S', 'noun'), 8 | word.new('Webex', '', 'noun') { description: 'https://www.webex.com/', product: true, swaps: { webex: 'Webex' } }, 9 | word.new('Wi-Fi', '', 'noun') { description: 'wireless fidelity', swaps: { '(?:WiFi|wifi)': 'Wi-Fi' } }, 10 | word.new('WildFly', '', 'noun') { description: 'WildFly, formerly known as JBoss AS, or simply JBoss, is an application server written by JBoss, now developed by Red Hat (https://en.wikipedia.org/wiki/WildFly)', product: true }, 11 | word.new('windows_exporter', 'S', 'noun') { description: 'The Prometheus exporter for Windows machines (https://github.com/prometheus-community/windows_exporter)', product: true }, 12 | word.new('worktree', '', 'noun'), 13 | ] 14 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/dictionaries/Makefile: -------------------------------------------------------------------------------- 1 | .ONESHELL: 2 | .DELETE_ON_ERROR: 3 | export SHELL := bash 4 | export SHELLOPTS := pipefail:errexit 5 | MAKEFLAGS += --warn-undefined-variables 6 | MAKEFLAGS += --no-builtin-rule 7 | 8 | # Adapted from https://suva.sh/posts/well-documented-makefiles/ 9 | .PHONY: help 10 | help: ## Display this help 11 | help: 12 | @awk 'BEGIN {FS = ": ##"; printf "Usage:\n make <target>\n\nTargets:\n"} /^[a-zA-Z0-9_\.\-\/%]+: ##/ { printf " %-45s %s\n", $$1, $$2 }' $(MAKEFILE_LIST) 13 | 14 | .PHONY: all 15 | all: ## Create all dictionaries. 16 | all: en_US-grafana.dic en_US-places.dic 17 | 18 | en_US-places.dic: ## Create a Hunspell dictionary of places from a wordlist. 19 | en_US-places.dic: en_US-places.wordlist 20 | cat <(wc -l <$< | tr -d ' ') $< > $@ 21 | 22 | en_US-grafana.dic: ## Create a Hunspell dictionary for Grafana from the Jsonnet dictionary. 23 | en_US-grafana.dic: en_US-grafana.jsonnet ../../../../dictionary.libsonnet $(wildcard ../../../../dictionary/*.jsonnet) 24 | jsonnet -S en_US-grafana.jsonnet > $@ 25 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/CommandLinePrompts/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:4:3:Grafana.CommandLinePrompts:Don't add `$` or `#` as prompts before commands. Make it easy for users to copy and paste commands. Also, don't use `#` to include comments in commands. That explanation should be outside of the code block. 2 | testinvalid.md:7:3:Grafana.CommandLinePrompts:Don't add `$` or `#` as prompts before commands. Make it easy for users to copy and paste commands. Also, don't use `#` to include comments in commands. That explanation should be outside of the code block. 3 | testinvalid.md:10:3:Grafana.CommandLinePrompts:Don't add `$` or `#` as prompts before commands. Make it easy for users to copy and paste commands. Also, don't use `#` to include comments in commands. That explanation should be outside of the code block. 4 | testinvalid.md:13:3:Grafana.CommandLinePrompts:Don't add `$` or `#` as prompts before commands. Make it easy for users to copy and paste commands. Also, don't use `#` to include comments in commands. That explanation should be outside of the code block. 5 | -------------------------------------------------------------------------------- /publish-technical-documentation-release/determine-release-branch: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -euf -o pipefail 4 | 5 | function usage { 6 | cat <<EOF 7 | Return the first release branch matching the provided branch regular expression that contains the provided tag. 8 | 9 | Usage: 10 | $0 <BRANCH REGEXP> <TAG> 11 | 12 | Examples: 13 | $0 '^v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.x$' v11.3.1 14 | EOF 15 | } 16 | 17 | if [[ $# -ne 2 ]]; then 18 | usage 19 | 20 | exit 2 21 | fi 22 | 23 | BRANCH_REGEXP="$1" 24 | TAG="${2#refs/tags/}" 25 | 26 | contains="$(git branch -a --contains "tags/${TAG}")" 27 | IFS=$'\n' 28 | for branch in ${contains}; do 29 | branch="${branch# remotes/origin/}"; 30 | echo "Checking branch ${branch} against ${BRANCH_REGEXP}." >&2 31 | 32 | if [[ "${branch}" =~ ${BRANCH_REGEXP} ]]; then 33 | echo "${branch}"; 34 | 35 | exit 0; 36 | fi; 37 | done 38 | 39 | echo "No release branch found for tag ${TAG} matching ${BRANCH_REGEXP}. Exiting." >&2 40 | echo "Branches containing tag ${TAG}:" >&2 41 | echo "${contains}" >&2 42 | exit 1 43 | -------------------------------------------------------------------------------- /vale/WordList.jsonnet: -------------------------------------------------------------------------------- 1 | local defs = (import './dictionary.libsonnet').words; 2 | std.manifestYamlDoc({ 3 | extends: 'substitution', 4 | message: "Use '%s' instead of '%s'.", 5 | link: 'https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/', 6 | level: 'warning', 7 | ignorecase: false, 8 | action: { 9 | name: 'replace', 10 | }, 11 | 12 | swap: std.foldl( 13 | function(acc, def) acc + def.swaps, 14 | defs, 15 | { 16 | 'ad[- ]?hoc': 'free-form|user-written', 17 | 'the Grafana Agent': 'Grafana Agent', 18 | 'network IP address': 'internal IP address', 19 | 'left[- ]hand[- ]side': 'left-side', 20 | 'fewer data': 'less data', 21 | '(?:hamburger menu|kebab menu)': 'menu icon', 22 | '(?:cell ?phone|smart ?phone)': 'phone|mobile phone', 23 | 'right[- ]hand[- ]side': 'right-side', 24 | 'sign into': 'sign in to', 25 | '(?:kill|terminate|abort)': 'stop|exit|cancel|end', 26 | 'in order to': 'to', 27 | timeseries: 'time series|time-series', 28 | 'grayed-out': 'unavailable', 29 | }, 30 | ), 31 | }) 32 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Spelling.yml: -------------------------------------------------------------------------------- 1 | extends: spelling 2 | message: | 3 | Did you really mean '%s'? 4 | 5 | The Grafana dictionary might not know of this word yet. 6 | 7 | To add a new word, refer to [Add words to the Grafana Labs dictionary](https://grafana.com/docs/writers-toolkit/review/lint-prose/dictionary/add-words/). 8 | Alternatively, raise an [issue](https://github.com/grafana/writers-toolkit/issues/new?title=Grafana.Spelling%%3A%%20%[1]s) and a maintainer will add it for you. 9 | 10 | For UI elements, use [bold formatting](https://grafana.com/docs/writers-toolkit/write/style-guide/style-conventions/#bold). 11 | The spell checker doesn't check words with bold formatting. 12 | 13 | For paths; configuration; user input; code; class, method, and variable names; statuscodes; and console output, use [code formatting](https://grafana.com/docs/writers-toolkit/write/style-guide/style-conventions/#bold). 14 | The spell checker doesn't check words with code formatting. 15 | level: error 16 | append: true 17 | dicpath: config/dictionaries 18 | dictionaries: 19 | - en_US-grafana 20 | - en_US-places 21 | -------------------------------------------------------------------------------- /vale/Google/Acronyms.yml: -------------------------------------------------------------------------------- 1 | extends: conditional 2 | message: "Spell out '%s', if it's unfamiliar to the audience." 3 | link: "https://developers.google.com/style/abbreviations" 4 | level: suggestion 5 | ignorecase: false 6 | # Ensures that the existence of 'first' implies the existence of 'second'. 7 | first: '\b([A-Z]{3,5})\b' 8 | second: '(?:\b[A-Z][a-z]+ )+\(([A-Z]{3,5})\)' 9 | # ... with the exception of these: 10 | exceptions: 11 | - API 12 | - ASP 13 | - CLI 14 | - CPU 15 | - CSS 16 | - CSV 17 | - DEBUG 18 | - DOM 19 | - DPI 20 | - FAQ 21 | - GCC 22 | - GDB 23 | - GET 24 | - GPU 25 | - GTK 26 | - GUI 27 | - HTML 28 | - HTTP 29 | - HTTPS 30 | - IDE 31 | - JAR 32 | - JSON 33 | - JSX 34 | - LESS 35 | - LLDB 36 | - NET 37 | - NOTE 38 | - NVDA 39 | - OSS 40 | - PATH 41 | - PDF 42 | - PHP 43 | - POST 44 | - RAM 45 | - REPL 46 | - RSA 47 | - SCM 48 | - SCSS 49 | - SDK 50 | - SQL 51 | - SSH 52 | - SSL 53 | - SVG 54 | - TBD 55 | - TCP 56 | - TODO 57 | - URI 58 | - URL 59 | - USB 60 | - UTF 61 | - XML 62 | - XSS 63 | - YAML 64 | - ZIP 65 | -------------------------------------------------------------------------------- /vale/dictionary.libsonnet: -------------------------------------------------------------------------------- 1 | { 2 | words: 3 | (import 'dictionary/a.jsonnet') + 4 | (import 'dictionary/b.jsonnet') + 5 | (import 'dictionary/c.jsonnet') + 6 | (import 'dictionary/d.jsonnet') + 7 | (import 'dictionary/e.jsonnet') + 8 | (import 'dictionary/f.jsonnet') + 9 | (import 'dictionary/g.jsonnet') + 10 | (import 'dictionary/h.jsonnet') + 11 | (import 'dictionary/i.jsonnet') + 12 | (import 'dictionary/j.jsonnet') + 13 | (import 'dictionary/k.jsonnet') + 14 | (import 'dictionary/l.jsonnet') + 15 | (import 'dictionary/m.jsonnet') + 16 | (import 'dictionary/n.jsonnet') + 17 | (import 'dictionary/o.jsonnet') + 18 | (import 'dictionary/p.jsonnet') + 19 | (import 'dictionary/q.jsonnet') + 20 | (import 'dictionary/r.jsonnet') + 21 | (import 'dictionary/s.jsonnet') + 22 | (import 'dictionary/t.jsonnet') + 23 | (import 'dictionary/u.jsonnet') + 24 | (import 'dictionary/v.jsonnet') + 25 | (import 'dictionary/w.jsonnet') + 26 | (import 'dictionary/x.jsonnet') + 27 | (import 'dictionary/y.jsonnet') + 28 | (import 'dictionary/z.jsonnet'), 29 | } 30 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/CommandLinePrompts.tengo: -------------------------------------------------------------------------------- 1 | DEBUG := false 2 | 3 | fmt := import("fmt") 4 | text := import("text") 5 | 6 | matches := [] 7 | ruleActive := true 8 | info := "" 9 | 10 | cursor := 0 11 | for line in text.split(scope, "\n") { 12 | if DEBUG { 13 | fmt.println(text.pad_left(text.itoa(cursor), 3, " "), ": ", text.quote(line), " ", len(line)) 14 | } 15 | 16 | if text.re_find(`<!-- vale Grafana.CommandLinePrompts = NO -->`, line, -1) { 17 | ruleActive = false 18 | } 19 | 20 | if text.re_find(`<!-- vale Grafana.CommandLinePrompts = YES -->`, line, -1) { 21 | ruleActive = true 22 | } 23 | 24 | start := text.re_find("```(.*)", line, -1) 25 | if start { 26 | info = start[0][1].text 27 | } else { 28 | if text.contains(line, "```") { 29 | info = "" 30 | } 31 | } 32 | 33 | if ruleActive { 34 | if info == "bash" || info == "console" || info == "sh" || info == "shell" { 35 | for match in text.re_find(`^ *[#$] `, line, -1) { 36 | matches = append(matches, {begin: cursor + match[0].begin, end: cursor + match[0].end}) 37 | } 38 | } 39 | } 40 | 41 | cursor += len(line) + 1 42 | } 43 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/dictionaries/en_US-grafana.aff: -------------------------------------------------------------------------------- 1 | SET UTF-8 2 | TRY esianrtolcdugmphbyfvkwzESIANRTOLCDUGMPHBYFVKWZ' 3 | ICONV 1 4 | ICONV ’ ' 5 | NOSUGGEST ! 6 | 7 | PFX d Y 1 8 | PFX d 0 de . 9 | 10 | PFX u Y 1 11 | PFX u 0 un . 12 | 13 | PFX m Y 1 14 | PFX m 0 mis . 15 | 16 | PFX p Y 1 17 | PFX p 0 pre . 18 | 19 | SFX A Y 2 20 | SFX A e able e 21 | SFX A 0 able . 22 | 23 | SFX D Y 4 24 | SFX D 0 d e 25 | SFX D y ied [^aeiou]y 26 | SFX D 0 ed [^ey] 27 | SFX D 0 ed [aeiou]y 28 | 29 | SFX G Y 2 30 | SFX G e ing e 31 | SFX G 0 ing [^e] 32 | 33 | SFX M Y 2 34 | SFX M 0 ' s 35 | SFX M 0 's [^s] 36 | 37 | SFX N Y 3 38 | SFX N e ion e 39 | SFX N y ication y 40 | SFX N 0 en [^ey] 41 | 42 | SFX R Y 2 43 | SFX R 0 r e 44 | SFX R 0 ed . 45 | 46 | SFX S Y 5 47 | SFX S y ies [^aeiou]y 48 | SFX S 0 s [aeiou]y 49 | SFX S 0 s ph 50 | SFX S 0 es [sxzh] 51 | SFX S 0 s [^sxzhy] 52 | -------------------------------------------------------------------------------- /vale/dictionary/l.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('LangChain', '', 'noun') { description: 'https://www.langchain.com/', product: true, swaps: { langchain: 'LangChain' } }, 4 | word.new('launchd', '', 'noun') { description: 'An open-source service management framework used with macOS.', product: true }, 5 | word.new('LCP', '', 'noun') { abbreviation: true, elaboration: 'Largest Contentful Paint' }, 6 | word.new('LESS', '', 'noun') { abbreviation: true, elaboration: 'Leaner Style Sheets', established_abbreviation: true }, 7 | word.new('LLM', 'S', 'noun') { abbreviation: true, elaboration: 'large language model' }, 8 | word.new('Linode', 'M', 'noun'), 9 | word.new('LogQL', '', 'noun') { description: 'The Grafana Loki log query language.', swaps: { 'log(?:ql|QL)': 'LogQL' } }, 10 | word.new('Logs Drilldown', '', 'noun') { product: true }, 11 | word.new('Loki', '', 'noun') { product: true, swaps: { loki: 'Loki' } }, 12 | word.new('lookup', 'S', 'noun'), 13 | word.new('loopback', '', 'noun') { description: 'A network interface that is used to send data back to the same device.' }, 14 | word.new('Lucene', '', 'noun') { product: true, swaps: { lucene: 'Lucene' } }, 15 | ] 16 | -------------------------------------------------------------------------------- /vale/dictionary/j.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('Jaeger', '', 'adjective'), 4 | word.new('Jaeger', '', 'noun') { product: true }, 5 | word.new('JAR', '', 'noun') { abbreviation: true, established_abbreviation: true }, 6 | word.new('JavaScript', '', 'noun') { description: 'A high-level, interpreted programming language.', swaps: { '(?:java[Ss]cript|Javascript)': 'JavaScript' } }, 7 | word.new('Jira', '', 'noun') { product: true }, 8 | word.new('JMESPath', '', 'noun') { description: 'JMESPath is a query language for JSON. https://jmespath.org/', product: true, swaps: { '(?:[jJ][mM][eE][sS]p|jmesP)ath': 'JMESPath' } }, 9 | word.new('JMeter', 'M', 'noun'), 10 | word.new('journald', '', 'noun') { description: 'A system service that collects and stores logging data.', product: true }, 11 | word.new('JPG', '', 'noun') { abbreviation: true, established_abbreviation: true }, 12 | word.new('JSON', '', 'noun') { abbreviation: true, established_abbreviation: true }, 13 | word.new('Jsonnet', '', 'noun') { product: true, swaps: { jsonnet: 'Jsonnet' } }, 14 | word.new('JSX', '', 'noun') { abbreviation: true, established_abbreviation: true }, 15 | word.new('JUnit', 'M', 'noun'), 16 | ] 17 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | # Lines starting with '#' are comments. 2 | # Each line is a file pattern followed by one or more owners. 3 | 4 | # More details are here: https://help.github.com/articles/about-codeowners/ 5 | 6 | # The '*' pattern is global owners. 7 | 8 | # Order is important. The last matching pattern has the most precedence. 9 | # The folders are ordered as follows: 10 | 11 | # In each subsection folders are ordered first by depth, then alphabetically. 12 | # This should make it easy to add new rules without breaking existing ones. 13 | 14 | * @grafana/docs-tooling 15 | 16 | /vale/ @clayton-cornell @grafana/docs-tooling 17 | 18 | /docs/sources/ @chri2547 @clayton-cornell @grafana/docs-tooling @knylander-grafana 19 | 20 | /docs/sources/structure/ @chri2547 @clayton-cornell @grafana/docs-tooling @knylander-grafana @josmperez 21 | 22 | /docs/sources/contribute/release-notes/ @chri2547 @clayton-cornell @grafana/docs-tooling @knylander-grafana @imatwawana 23 | /docs/sources/write/style-guide/ @chri2547 @clayton-cornell @grafana/docs-tooling @knylander-grafana @josmperez 24 | 25 | /docs/sources/structure/topic-types/visualization/ @chri2547 @clayton-cornell @grafana/docs-tooling @knylander-grafana @imatwawana 26 | -------------------------------------------------------------------------------- /vale/dictionary/m.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('manage', 'uD', 'verb'), 4 | word.new('Markdown', '', 'noun') { product: true, swaps: { markdown: 'Markdown' } }, 5 | word.new('Mapbox', '', 'noun') { description: 'Another term for the MapLibre map layer type for geomap visualizations' }, 6 | word.new('marshal', 'u', 'verb'), 7 | word.new('matcher', 'S', 'noun'), 8 | word.new('media type', 'S', 'noun') { swaps: { '(?:content|media)-?type': 'media type', 'content type': 'media type' } }, 9 | word.new('memberlist', '', 'noun'), 10 | word.new('Memcached', '', 'noun') { product: true, swaps: { memcached: 'Memcached' } }, 11 | word.new('metadata', '', 'noun') { swaps: { 'meta[- ]data': 'metadata' } }, 12 | word.new('Metrics Drilldown', '', 'noun') { product: true }, 13 | word.new('Mesos', '', 'noun') { Apache: true, product: true, description: 'Apache Mesos' }, 14 | word.new('middleware', 'S', 'noun'), 15 | word.new('Mimir', 'M', 'noun') { product: true }, 16 | word.new('misconfiguration', 'S', 'noun'), 17 | word.new('mixin', 'S', 'noun') { swaps: { 'mix[- ]in': 'mixin' } }, 18 | word.new('Moodle', '', 'noun') { product: true }, 19 | word.new('MySQL', '', 'noun') { product: true, swaps: { mysql: 'MySQL' } }, 20 | ] 21 | -------------------------------------------------------------------------------- /tools/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/grafana/writers-toolkit/tools 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.24.3 6 | 7 | require ( 8 | github.com/BurntSushi/toml v1.5.0 9 | github.com/gohugoio/hugo v0.147.3 10 | gopkg.in/yaml.v3 v3.0.1 11 | ) 12 | 13 | require ( 14 | github.com/bep/godartsass/v2 v2.5.0 // indirect 15 | github.com/bep/golibsass v1.2.0 // indirect 16 | github.com/cespare/xxhash/v2 v2.3.0 // indirect 17 | github.com/clbanning/mxj/v2 v2.7.0 // indirect 18 | github.com/cli/safeexec v1.0.1 // indirect 19 | github.com/gobwas/glob v0.2.3 // indirect 20 | github.com/gohugoio/hashstructure v0.5.0 // indirect 21 | github.com/mattn/go-isatty v0.0.20 // indirect 22 | github.com/niklasfasching/go-org v1.7.0 // indirect 23 | github.com/pelletier/go-toml/v2 v2.2.4 // indirect 24 | github.com/spf13/afero v1.14.0 // indirect 25 | github.com/spf13/cast v1.7.1 // indirect 26 | github.com/tdewolff/parse/v2 v2.7.19 // indirect 27 | github.com/yuin/goldmark v1.7.11 // indirect 28 | golang.org/x/net v0.39.0 // indirect 29 | golang.org/x/sys v0.32.0 // indirect 30 | golang.org/x/text v0.24.0 // indirect 31 | google.golang.org/protobuf v1.36.5 // indirect 32 | gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect 33 | gopkg.in/yaml.v2 v2.4.0 // indirect 34 | ) 35 | -------------------------------------------------------------------------------- /vale/dictionary/u.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('UI', 'S', 'noun') { abbreviation: true, elaboration: 'user interface', established_abbreviation: true }, 4 | word.new('UID', 'S', 'noun') { abbreviation: true, elaboration: 'unique identifier', established_abbreviation: true }, 5 | word.new('uprobe', 'S', 'noun'), 6 | word.new('URI', 'S', 'noun') { abbreviation: true, elaboration: 'Uniform Resource Identifier', established_abbreviation: true }, 7 | word.new('URL', 'S', 'noun') { abbreviation: true, elaboration: 'Uniform Resource Locator', established_abbreviation: true, swaps: { url: 'URL', urls: 'URLs' } }, 8 | word.new('USB', '', 'noun') { abbreviation: true, elaboration: 'Universal Serial Bus', established_abbreviation: true }, 9 | word.new('UTC', '', 'noun') { abbreviation: true, elaboration: 'Coordinated Universal Time', established_abbreviation: true }, 10 | word.new('UTF', '', 'noun') { abbreviation: true, elaboration: 'Unicode Transformation Format', established_abbreviation: true }, 11 | word.new('UUID', 'S', 'noun') { abbreviation: true, elaboration: 'universally unique identifier', established_abbreviation: true }, 12 | word.new('UX', '', 'noun') { abbreviation: true, elaboration: 'user experience', established_abbreviation: true }, 13 | ] 14 | -------------------------------------------------------------------------------- /vale/dictionary/v.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('Velero', '', 'noun') { description: 'Velero is an open source tool to safely backup and restore, perform disaster recovery, and migrate Kubernetes cluster resources and persistent volumes.', product: true }, 4 | word.new('versus', '', 'preposition') { description: 'against (https://en.wiktionary.org/wiki/versus)', swaps: { 'vs\\.': 'versus' } }, 5 | word.new('viewport', 'S', 'noun') { description: 'A viewport is a polygon viewing region in computer graphics (https://en.wikipedia.org/wiki/Viewport)' }, 6 | word.new('Vite', '', 'noun') { description: 'Next Generation Frontend Tooling (https://vitejs.dev/)', product: true }, 7 | word.new('VM', 'S', 'noun') { description: 'Virtual Machine' }, 8 | word.new('VMware', '', 'noun') { description: 'VMware LLC is an American cloud computing and virtualization technology company.', product: true, swaps: { vmware: 'VMware', Vmware: 'VMware', VMWare: 'VMware' } }, 9 | word.new('VPC', 'S', 'noun') { abbreviation: true, elaboration: 'virtual private cloud', established_abbreviation: true }, 10 | word.new('VU', 'S', 'noun') { abbreviation: true, elaboration: 'virtual user' }, 11 | word.new('VUH', 'S', 'noun') { abbreviation: true, elaboration: 'virtual user hour' }, 12 | ] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Writers’ Toolkit 2 | 3 | <!-- vale Grafana.GoogleExclamation = NO --> 4 | <!-- vale Grafana.We = NO --> 5 | 6 | Welcome! 7 | 8 | We're glad you're here to help make our technical documentation even better. 9 | We develop content that leads our users to success using Grafana products. 10 | Technical accuracy is our primary consideration, and we value the use of inclusive language. 11 | We regard your feedback as a gift - thanks for reading through these guidelines. 12 | 13 | ## Intended audience 14 | 15 | We write these guidelines for contributors who're interested in improving our technical content. 16 | 17 | ## Ways to contribute 18 | 19 | We're thrilled that you are considering contributing to these writing guidelines. 20 | You can contribute content in the following ways: 21 | 22 | - Request a change 23 | - Edit a topic 24 | - Write a topic 25 | 26 | ## Pull request review and approval workflow 27 | 28 | When you open a pull request to this repository, the [CODEOWNERS](.github/CODEOWNERS) are notified for review. 29 | Pull requests are generally reviewed and merged [within a working day](https://ossinsight.io/analyze/grafana/writers-toolkit#pull-requests:~:text=Pull%20Request%20Time%20Cost). 30 | 31 | Thank you for reading these guidelines and contributing to Grafana Labs technical documentation! 32 | -------------------------------------------------------------------------------- /vale/dictionary/o.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('OAuth', '', 'noun'), 4 | word.new('Okta', '', 'noun') { product: true }, 5 | word.new('onboard', 'DG', 'verb'), 6 | word.new('OnCall', '', 'noun') { product: true }, 7 | word.new('OpenAI', '', 'noun') { description: 'https://openapi.com', product: true }, 8 | word.new('open source', '', 'noun') { swaps: { 'open-source': 'open source' } }, 9 | word.new('OpenShift', '', 'noun') { product: true, swaps: { '(?:[Oo]penshift|openShift)': 'OpenShift' } }, 10 | word.new('OpenTelemetry', '', 'adjective'), 11 | word.new('OpenTelemetry', '', 'noun') { product: true, swaps: { '(?:[oO]pentelemetry|openTelemetry)': 'OpenTelemetry' } }, 12 | word.new('Opsgenie', '', 'noun') { description: 'https://www.atlassian.com/software/opsgenie', product: true }, 13 | word.new('OSS', '', 'noun') { abbreviation: true, elaboration: 'open source software', established_abbreviation: true }, 14 | word.new('OTel', '', 'adjective'), 15 | word.new('OTel', '', 'noun') { product: true, swaps: { otel: 'OTel' } }, 16 | word.new('OTLP', '', 'noun') { abbreviation: true, elaboration: 'OpenTelemetry Protocol', established_abbreviation: true, swaps: { otlp: 'OTLP' } }, 17 | word.new('overbill', 'DG', 'verb'), 18 | word.new('overutilization', 'S', 'noun'), 19 | ] 20 | -------------------------------------------------------------------------------- /.github/workflows/deploy-pr-preview.yml: -------------------------------------------------------------------------------- 1 | name: Deploy pr preview 2 | 3 | permissions: {} 4 | 5 | on: 6 | pull_request: 7 | types: 8 | - opened 9 | - synchronize 10 | - closed 11 | paths: 12 | - "docs/sources/**" 13 | 14 | jobs: 15 | deploy-pr-preview: 16 | uses: grafana/writers-toolkit/.github/workflows/deploy-preview.yml@main # zizmor: ignore[unpinned-uses] It's a protected branch in the same repository. 17 | if: "!github.event.pull_request.head.repo.fork" 18 | permissions: 19 | contents: read # Clone repository. 20 | id-token: write # Fetch Vault secrets. 21 | pull-requests: write # Create or update pull request comments. 22 | statuses: write # Update GitHub status check with deploy preview link. 23 | with: 24 | branch: ${{ github.head_ref }} 25 | event_number: ${{ github.event.number }} 26 | repo: writers-toolkit 27 | sha: ${{ github.event.pull_request.head.sha }} 28 | sources: | 29 | [{ 30 | "index_file": null, 31 | "relative_prefix": "/docs/writers-toolkit/", 32 | "repo": "writers-toolkit", 33 | "source_directory": "docs/sources", 34 | "website_directory": "content/docs/writers-toolkit" 35 | }] 36 | title: ${{ github.event.pull_request.title }} 37 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Shortcodes/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.Shortcodes:Prefer `{{<` and `>}}` instead of `{{%!`(string={{% admonition type="caution" %}}) and `%!}(string=)}` It has the most consistent semantics. The percent syntax is used for special behavior that isn't required with this shortcode. 2 | testinvalid.md:4:3:Grafana.Shortcodes:Prefer `{{<` and `>}}` instead of `{{%!`(string={{% admonition type="note" %}}) and `%!}(string=)}` It has the most consistent semantics. The percent syntax is used for special behavior that isn't required with this shortcode. 3 | testinvalid.md:5:3:Grafana.Shortcodes:Prefer `{{<` and `>}}` instead of `{{%!`(string={{% admonition type="tip" %}}) and `%!}(string=)}` It has the most consistent semantics. The percent syntax is used for special behavior that isn't required with this shortcode. 4 | testinvalid.md:6:3:Grafana.Shortcodes:Prefer `{{<` and `>}}` instead of `{{%!`(string={{% admonition type="warn" %}}) and `%!}(string=)}` It has the most consistent semantics. The percent syntax is used for special behavior that isn't required with this shortcode. 5 | testinvalid.md:7:3:Grafana.Shortcodes:Prefer `{{<` and `>}}` instead of `{{%!`(string={{% /admonition %}}) and `%!}(string=)}` It has the most consistent semantics. The percent syntax is used for special behavior that isn't required with this shortcode. 6 | -------------------------------------------------------------------------------- /tools/cmd/generate-documentation/page.tmpl: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2024-06-25" 3 | description: A description of every Grafana Labs prose linting rule. 4 | menuTitle: Rules 5 | review_date: "{{ .ReviewDate }}" 6 | title: {{ .Title }} 7 | --- 8 | 9 | # {{ .Title }} 10 | 11 | <!-- These are our style rules. --> 12 | <!-- vale Grafana.We = NO --> 13 | 14 | Vale codifies our style guide into a series of rules that can be checked against your prose. 15 | The following is a list of all the rules that we've defined. 16 | 17 | <!-- This page breaks a number of rules in demonstrating them. --> 18 | {{ range .Rules -}} 19 | <!-- vale {{ .Name }} = NO --> 20 | {{ end -}} 21 | 22 | ## Errors 23 | 24 | The following rules are considered errors and must be fixed. 25 | 26 | {{ range .Rules -}} 27 | {{ if or (eq .Level "error") -}} 28 | {{ template "rule.tmpl" . }} 29 | {{ end -}} 30 | {{ end -}} 31 | 32 | ## Warnings 33 | 34 | The following rules are warnings and may need to be fixed or otherwise require consideration. 35 | 36 | {{ range .Rules -}} 37 | {{ if or (eq .Level "warning") (eq .Level "") -}} 38 | {{ template "rule.tmpl" . }} 39 | {{ end -}} 40 | {{ end -}} 41 | 42 | ## Suggestions 43 | 44 | The following rules are suggestions to consider a certain point of style. 45 | 46 | {{ range .Rules -}} 47 | {{ if or (eq .Level "suggestion") -}} 48 | {{ template "rule.tmpl" . }} 49 | {{ end -}} 50 | {{ end -}} 51 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/Acronyms.yml: -------------------------------------------------------------------------------- 1 | "exceptions": 2 | - "ADOT" 3 | - "API" 4 | - "APT" 5 | - "ARN" 6 | - "AWS" 7 | - "BPF" 8 | - "CLI" 9 | - "CORS" 10 | - "CPU" 11 | - "CRD" 12 | - "CSS" 13 | - "CSV" 14 | - "DNS" 15 | - "DOM" 16 | - "eBPF" 17 | - "FAQ" 18 | - "GNU" 19 | - "GPG" 20 | - "GPU" 21 | - "GUI" 22 | - "HTML" 23 | - "HTTP" 24 | - "HTTPS" 25 | - "IBM" 26 | - "IDE" 27 | - "JAR" 28 | - "JPG" 29 | - "JSON" 30 | - "JSX" 31 | - "LESS" 32 | - "NAT" 33 | - "OSS" 34 | - "OTLP" 35 | - "PDF" 36 | - "PHP" 37 | - "PNG" 38 | - "RAM" 39 | - "RBAC" 40 | - "RED" 41 | - "REPL" 42 | - "RHEL" 43 | - "RPM" 44 | - "RSA" 45 | - "SCM" 46 | - "SCSS" 47 | - "SDK" 48 | - "SEO" 49 | - "SHA-1" 50 | - "SQL" 51 | - "SSD" 52 | - "SSM" 53 | - "SSH" 54 | - "SSL" 55 | - "SSO" 56 | - "SUSE" 57 | - "SVG" 58 | - "TCP" 59 | - "TLS" 60 | - "TSDB" 61 | - "UI" 62 | - "UID" 63 | - "URI" 64 | - "URL" 65 | - "USB" 66 | - "UTC" 67 | - "UTF" 68 | - "UUID" 69 | - "UX" 70 | - "VPC" 71 | - "XML" 72 | - "YAML" 73 | - "ZIP" 74 | "extends": "conditional" 75 | "first": "\\b([A-Z]{3,5})\\b" 76 | "ignorecase": false 77 | "level": "suggestion" 78 | "link": "https://developers.google.com/style/abbreviations" 79 | "message": "Spell out '%s', if it's unfamiliar to the audience." 80 | "second": "(?:\\b[A-Z][a-z]+ )+\\(([A-Z]{3,5})\\)" 81 | -------------------------------------------------------------------------------- /vale/dictionary/b.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | 4 | word.new('backend', 'S', 'noun') { swaps: { 'back[ -]end': 'backend' } }, 5 | word.new('backoff', '', 'noun') { description: 'Refers to exponential backoff (retry logic)' }, 6 | word.new('backport', 'DGS', 'verb'), 7 | word.new('basemap', '', 'noun') { description: 'A type of map layer available in geomap visualizations' }, 8 | word.new('Beyla', '', 'noun') { product: true }, 9 | word.new('blackbox', '', 'noun'), 10 | word.new('blocklist', 'DGS', 'verb') { swaps: { blacklisted: 'blocklisted', blacklisting: 'blocklisting', blacklists: 'blocklists' } }, 11 | word.new('blocklist', 'S', 'noun') { swaps: { blacklist: 'blocklist' } }, 12 | word.new('blockquote', 'S', 'noun'), 13 | word.new('Bollinger', '', 'noun') { description: 'Bollinger Bands are a tool that help traders assess market volatility' }, 14 | word.new('boolean', '', 'noun'), 15 | word.new('BoringCrypto', '', 'noun') { product: true, description: 'An open-source cryptographic library used by BoringSSL and other user-space applications' }, 16 | word.new('BPF', '', 'noun') { abbreviation: true, elaboration: 'Berkeley Packet Filter', established_abbreviation: true }, 17 | word.new('Brotli', '', 'noun') { description: 'Brotli is a lossless data compression algorithm developed by Google' }, 18 | word.new('burndown', '', 'adjective'), 19 | word.new('bundler', 'S', 'noun'), 20 | ] 21 | -------------------------------------------------------------------------------- /readability/action.yml: -------------------------------------------------------------------------------- 1 | name: Report readability 2 | description: | 3 | Reports readability metrics for changed documentation files in a pull request. 4 | 5 | Note that the action assumes you are running the steps using the grafana/vale container image. 6 | inputs: 7 | directory: 8 | default: docs/sources 9 | description: Directory containing documentation for linting. 10 | required: false 11 | 12 | runs: 13 | using: composite 14 | steps: 15 | - name: Install Bash 16 | run: apk add bash 17 | shell: sh 18 | 19 | - name: Run tool 20 | env: 21 | BASE_SHA: ${{ github.event.pull_request.base.sha }} 22 | HEAD_SHA: ${{ github.event.pull_request.head.sha }} 23 | DIRECTORY: ${{ inputs.directory }} 24 | run: | 25 | (cd /etc/vale && vale sync) 26 | git config --global --add safe.directory "${GITHUB_WORKSPACE}" 27 | touch .output.txt 28 | for file in $(git --no-pager diff --name-only --diff-filter=ACMRT "${BASE_SHA}" -- "${DIRECTORY}"); do 29 | ${GITHUB_ACTION_PATH}/readability "${file}" "${BASE_SHA}" ${HEAD_SHA} | tee -a .output.txt 30 | done 31 | shell: bash 32 | 33 | - uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 34 | with: 35 | script: | 36 | const script = require(`${process.env.GITHUB_ACTION_PATH}/report-readability.js`); 37 | await script({ context, core, github }); 38 | -------------------------------------------------------------------------------- /vale/dictionary/k.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('KEDA', 'M', 'noun') { abbreviation: true, elaboration: 'Kubernetes-based Event-Driven Autoscaling' }, 4 | word.new('keepalive', '', 'noun') { description: 'A message sent by one device to another to check that the link between the two is operating (https://en.wikipedia.org/wiki/Keepalive).' }, 5 | word.new('Keycloak', '', 'noun') { description: 'Open source identity and access management solution.', product: true }, 6 | word.new('Kibana', '', 'noun') { product: true }, 7 | word.new('Killercoda', '', 'noun') { product: true }, 8 | word.new('Kinesis', '', 'noun') { Amazon: true, product: true }, 9 | word.new('Kotlin', '', 'noun') { product: true, swaps: { 'kotlin': 'Kotlin' } }, 10 | word.new('KPI', 'S', 'noun') { abbreviation: true, elaboration: 'key performance indicator' }, 11 | word.new('KQL', '', 'noun') { Azure: true, product: true, elaboration: 'Kusto Query Language' }, 12 | word.new('Kprobe', 'S', 'noun'), 13 | word.new('kubelet', '', 'noun'), 14 | word.new('Kubernetes', '', 'noun') { product: true, swap: '(?:[kK]8s|kubernetes)' }, 15 | word.new('Kubernetes Engine', '', 'noun') { Google: true, product: true }, 16 | word.new('Kusto', '', 'noun') { Azure: true, description: 'An Azure query language.', product: true }, 17 | word.new('Kustomize', '', 'noun') { description: 'A Kubernetes native configuration management tool.', product: true }, 18 | ] 19 | -------------------------------------------------------------------------------- /.github/workflows/from-comment.js: -------------------------------------------------------------------------------- 1 | // Uses https://github.com/actions/github-script 2 | // 3 | // To execute: 4 | // https://github.com/actions/github-script#run-a-separate-file-with-an-async-function 5 | // const script = require('./scripts/docs/vale/from-comment.js'); 6 | // 7 | // async script({ core, context, github }); 8 | module.exports = async ({ context, core, github }) => { 9 | const body = context.payload.comment.body || ""; 10 | 11 | const { data: files } = await github.rest.pulls.listFiles({ 12 | owner: context.repo.owner, 13 | repo: context.repo.repo, 14 | pull_number: context.issue.number, 15 | }); 16 | const modifiedFiles = files 17 | .filter((file) => file.additions > 0) 18 | .map((file) => file.filename); 19 | 20 | core.debug(`Modified files: ${modifiedFiles.join(" ")}`); 21 | 22 | // Expect file paths as unordered Markdown list preceded by any number of whitespace characters. 23 | const commentFiles = body 24 | .split("\n") 25 | .filter((line) => { 26 | return line.trim().match(/^\s*[-*]\s/); 27 | }) 28 | .map((line) => { 29 | return line.trim().replace(/^\s*[-*]\s*/, ""); 30 | }); 31 | 32 | core.debug(`Comment files: ${commentFiles.join(" ")}`); 33 | 34 | if (!commentFiles.length) { 35 | core.setOutput("to-lint", modifiedFiles.join(" ")); 36 | 37 | return; 38 | } 39 | 40 | const toLint = modifiedFiles.filter((file) => { 41 | return commentFiles.includes(file); 42 | }); 43 | 44 | core.setOutput("to-lint", toLint.join(" ")); 45 | }; 46 | -------------------------------------------------------------------------------- /docs/sources/write/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | aliases: 3 | - /docs/writers-toolkit/writing-guide/ 4 | - /docs/writers-toolkit/write/ 5 | date: "2022-06-30T17:58:48+01:00" 6 | description: Learn about Grafana Labs' technical documentation writing guidelines. 7 | keywords: 8 | - writing 9 | - guidelines 10 | menuTitle: Write 11 | review_date: "2024-06-26" 12 | title: Write documentation 13 | weight: 400 14 | --- 15 | 16 | # Write documentation 17 | 18 | This writing guide defines how Grafana Labs writes documentation. 19 | 20 | The guidelines are for anyone who's interested in improving Grafana Labs' technical content. 21 | They're intended to guide you on your documentation journey, whether you are requesting a change, editing a topic, or writing a set of documentation for a product or feature from scratch. 22 | 23 | If you write technical documentation for Grafana Labs, familiarize yourself with these guidelines. 24 | 25 | If you don't find what you're looking for, email [the Grafana Labs documentation team](mailto:docs@grafana.com). 26 | 27 | ## Before you write 28 | 29 | To learn how to structure documentation, refer to [Documentation structure](https://grafana.com/docs/writers-toolkit/structure/). 30 | 31 | For guidelines for writing documentation, refer to the following sections: 32 | 33 | {{< section menuTitle="true" withDescriptions="true" >}} 34 | 35 | ## After you write 36 | 37 | After you've written your content, the next step is to build the content locally, review the output, and then publish it. 38 | For details, refer to [Build and review](https://grafana.com/docs/writers-toolkit/review/). 39 | -------------------------------------------------------------------------------- /tools/rwfilefs/osdirfs.go: -------------------------------------------------------------------------------- 1 | //nolint:wrapcheck // This is a wrapper around os.DirFS. 2 | package rwfilefs 3 | 4 | import ( 5 | "io/fs" 6 | "os" 7 | "path/filepath" 8 | ) 9 | 10 | // OSDirFS is an implementation of os.DirFS that implements 11 | // the RWFileFS interface. 12 | type OSDirFS struct { 13 | fs.StatFS 14 | Root string 15 | } 16 | 17 | // NewOSDirFS returns a file system for the tree of files rooted at the directory dir. 18 | // 19 | // Note that all caveats of os.DirFS apply here, especially given the destructive 20 | // nature of these methods. 21 | func NewOSDirFS(root string) OSDirFS { 22 | dirFS := os.DirFS(root) 23 | 24 | return OSDirFS{ 25 | //nolint:forcetypeassert 26 | // This is safe as os.DirFS implements Stat from Go 1.17. 27 | StatFS: dirFS.(fs.StatFS), 28 | Root: root, 29 | } 30 | } 31 | 32 | // RemoveFile implements the RWFileFS interface. 33 | func (fs OSDirFS) RemoveFile(name string) error { 34 | return os.Remove(filepath.Join(fs.Root, name)) 35 | } 36 | 37 | // ReadFile implements the RWFileFS interface. 38 | func (fs OSDirFS) ReadFile(name string) ([]byte, error) { 39 | return os.ReadFile(filepath.Join(fs.Root, name)) 40 | } 41 | 42 | // WriteFile implements the RWFileFS interface. 43 | // It will create any parent directories of the named file before trying to write any data. 44 | func (fs OSDirFS) WriteFile(name string, data []byte, mode fs.FileMode) error { 45 | path := filepath.Join(fs.Root, name) 46 | 47 | if err := os.MkdirAll(filepath.Dir(path), os.ModePerm); err != nil { 48 | return err 49 | } 50 | 51 | return os.WriteFile(path, data, mode) 52 | } 53 | -------------------------------------------------------------------------------- /vale/Google/GenderBias.yml: -------------------------------------------------------------------------------- 1 | extends: substitution 2 | message: "Consider using '%s' instead of '%s'." 3 | ignorecase: true 4 | link: "https://developers.google.com/style/inclusive-documentation" 5 | level: error 6 | action: 7 | name: replace 8 | swap: 9 | (?:alumna|alumnus): graduate 10 | (?:alumnae|alumni): graduates 11 | air(?:m[ae]n|wom[ae]n): pilot(s) 12 | anchor(?:m[ae]n|wom[ae]n): anchor(s) 13 | authoress: author 14 | camera(?:m[ae]n|wom[ae]n): camera operator(s) 15 | door(?:m[ae]|wom[ae]n): concierge(s) 16 | draft(?:m[ae]n|wom[ae]n): drafter(s) 17 | fire(?:m[ae]n|wom[ae]n): firefighter(s) 18 | fisher(?:m[ae]n|wom[ae]n): fisher(s) 19 | fresh(?:m[ae]n|wom[ae]n): first-year student(s) 20 | garbage(?:m[ae]n|wom[ae]n): waste collector(s) 21 | lady lawyer: lawyer 22 | ladylike: courteous 23 | mail(?:m[ae]n|wom[ae]n): mail carriers 24 | man and wife: husband and wife 25 | man enough: strong enough 26 | mankind: human kind|humanity 27 | manmade: manufactured 28 | manpower: personnel 29 | middle(?:m[ae]n|wom[ae]n): intermediary 30 | news(?:m[ae]n|wom[ae]n): journalist(s) 31 | ombuds(?:man|woman): ombuds 32 | oneupmanship: upstaging 33 | poetess: poet 34 | police(?:m[ae]n|wom[ae]n): police officer(s) 35 | repair(?:m[ae]n|wom[ae]n): technician(s) 36 | sales(?:m[ae]n|wom[ae]n): salesperson or sales people 37 | service(?:m[ae]n|wom[ae]n): soldier(s) 38 | steward(?:ess)?: flight attendant 39 | tribes(?:m[ae]n|wom[ae]n): tribe member(s) 40 | waitress: waiter 41 | woman doctor: doctor 42 | woman scientist[s]?: scientist(s) 43 | work(?:m[ae]n|wom[ae]n): worker(s) 44 | -------------------------------------------------------------------------------- /.github/workflows/validate-documentation.yml: -------------------------------------------------------------------------------- 1 | name: Documentation CI 2 | 3 | permissions: {} 4 | 5 | on: 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | changed-files: 11 | runs-on: ubuntu-latest 12 | outputs: 13 | any_changed: ${{ steps.changed-files.outputs.any_changed }} 14 | steps: 15 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | - uses: step-security/changed-files@95b56dadb92a30ca9036f16423fd3c088a71ee94 # v46.0.5 17 | id: changed-files 18 | with: 19 | files: | 20 | docs/sources/** 21 | vale/** 22 | 23 | ci: 24 | needs: changed-files 25 | if: needs.changed-files.outputs.any_changed == 'true' 26 | permissions: 27 | contents: read 28 | checks: write 29 | pull-requests: write 30 | security-events: write 31 | uses: ./.github/workflows/docs-ci.yml 32 | with: 33 | build: true 34 | build-website-directory: content/docs/writers-toolkit 35 | prettier: true 36 | vale: true 37 | readability: true 38 | 39 | result: 40 | runs-on: ubuntu-latest 41 | needs: [changed-files, ci] 42 | if: always() 43 | steps: 44 | - name: Determine result 45 | run: | 46 | if [[ "${{ needs.changed-files.outputs.any_changed }}" == "false" ]]; then 47 | echo "No documentation files changed, skipping CI" 48 | exit 0 49 | elif [[ "${{ needs.ci.result }}" == "success" ]]; then 50 | echo "CI passed" 51 | exit 0 52 | else 53 | echo "CI failed or was cancelled" 54 | exit 1 55 | fi 56 | -------------------------------------------------------------------------------- /vale/readability.jsonnet: -------------------------------------------------------------------------------- 1 | std.prune({ 2 | 'Grafana/styles/Grafana/ReadabilityAutomatedReadability.yml': std.manifestYamlDoc(std.parseYaml(importstr 'Readability/AutomatedReadability.yml') { 3 | condition: '> 0', 4 | level: 'suggestion', 5 | message: '%s aim for below 8.', 6 | }), 7 | 'Grafana/styles/Grafana/ReadabilityColemanLiau.yml': std.manifestYamlDoc(std.parseYaml(importstr 'Readability/ColemanLiau.yml') { 8 | condition: '> 0', 9 | level: 'suggestion', 10 | message: '%s aim for below 9.', 11 | }), 12 | 'Grafana/styles/Grafana/ReadabilityFleschKincaid.yml': std.manifestYamlDoc(std.parseYaml(importstr 'Readability/FleschKincaid.yml') { 13 | condition: '> 0', 14 | level: 'suggestion', 15 | message: '%s aim for below 8.', 16 | }), 17 | 'Grafana/styles/Grafana/ReadabilityFleschReadingEase.yml': std.manifestYamlDoc(std.parseYaml(importstr 'Readability/FleschReadingEase.yml') { 18 | condition: '< 100', 19 | level: 'suggestion', 20 | message: '%s aim for above 70.', 21 | }), 22 | 'Grafana/styles/Grafana/ReadabilityGunningFog.yml': std.manifestYamlDoc(std.parseYaml(importstr 'Readability/GunningFog.yml') { 23 | condition: '> 0', 24 | level: 'suggestion', 25 | message: '%s aim for below 10.', 26 | }), 27 | 'Grafana/styles/Grafana/ReadabilityLIX.yml': std.manifestYamlDoc(std.parseYaml(importstr 'Readability/LIX.yml') { 28 | condition: '> 0', 29 | level: 'suggestion', 30 | message: '%s aim for below 35.', 31 | }), 32 | 'Grafana/styles/Grafana/ReadabilitySMOG.yml': std.manifestYamlDoc(std.parseYaml(importstr 'Readability/SMOG.yml') { 33 | condition: '> 0', 34 | level: 'suggestion', 35 | message: '%s aim for below 10.', 36 | }), 37 | }) 38 | -------------------------------------------------------------------------------- /vale/dictionary/d.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('data center', 'S', 'noun') { swaps: { datacenter: 'data center', datacenters: 'data centers' } }, 4 | word.new('data source', 'S', 'noun') { swaps: { 'data-?source': 'data source', 'data-?sources': 'data sources' } }, 5 | word.new('datagrid', 'S', 'noun') { description: 'A Grafana visualization type.' }, 6 | word.new('dataset', 'S', 'noun') { swaps: { 'data[- ]?set': 'dataset', 'data[- ]?sets': 'datasets' } }, 7 | word.new('Data Firehose', '', 'noun') { Amazon: true, product: true, swaps: { '(?:(?<!Data )Firehose|Kinesis Data Firehose|Kinesis Firehose)': 'Data Firehose' } }, 8 | word.new('Databricks', '', 'noun') { product: true }, 9 | word.new('Datadog', '', 'adjective'), 10 | word.new('Datadog', '', 'noun') { product: true }, 11 | word.new('deliverable', 'S', 'noun'), 12 | word.new('disaggregate', 'DS', 'verb'), 13 | word.new('distroless', '', 'adjective'), 14 | word.new('DNS', '', 'noun') { abbreviation: true, description: 'Domain Name System', established_abbreviation: true }, 15 | word.new('DOM', '', 'noun') { abbreviation: true, elaboration: 'Document Object Model', established_abbreviation: true }, 16 | word.new("don'ts", '', 'noun'), 17 | word.new('downsample', 'DG', 'verb'), 18 | word.new('drilldown', '', 'noun'), 19 | word.new('drill down', '', 'verb'), 20 | word.new('duplicate', 'dDSN', 'noun') { swaps: { 'de-duplicate': 'deduplicate', 'de-duplicated': 'deduplicated', 'de-duplicates': 'deduplicates', 'de-duplication': 'deduplication' } }, 21 | word.new('Dynatrace', '', 'noun') { product: true }, 22 | word.new('passwordless', '', 'adjective') { description: 'https://en.wikipedia.org/wiki/Passwordless_authentication' }, 23 | ] 24 | -------------------------------------------------------------------------------- /docs/static/templates/concept-template.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Concept title 3 | menuTitle: Concept 4 | description: Use this template when you write a concept topic. 5 | aliases: 6 | - /docs/writers-toolkit/latest/templates/concept-template 7 | weight: 100 8 | keywords: 9 | - keyword 1 10 | - keyword 2 11 | - keyword 3 12 | --- 13 | 14 | <!-- Refer to [Front matter]({{< relref "../../front-matter/" >}}) for more information about how to populate front matter. --> 15 | 16 | # Concept title 17 | 18 | <!-- The concept title is required. Use a noun-based title that includes the name of the product or feature. For example: Alerting fundamentals. 19 | 20 | A concept provides an overview and background information to help users understand a product, interface, or task. Concepts answer the question “what is it?”. Readers learn about features through concepts. Concepts do not include step-by-step procedures or reference material but often link to those materials. 21 | 22 | Refer to the [Concept topic documentation](https://grafana.com/docs/writers-toolkit/writing-guide/topic-types/concept/) for guidelines on writing a concept topic. 23 | --> 24 | 25 | Introduce the concept. 26 | 27 | <!-- The introduction is required. Add an introduction to the concept to summarize the purpose or main point of the feature. --> 28 | 29 | ## Sections 30 | 31 | <!-- Add sections replacing **Sections** with subtitles for each section. Concept topics or sections explain what and why. They do not explain how. If you are a new user, you might look for concept information to learn about what Grafana is, why it might be useful to you, and what the general workflow is. --> 32 | 33 | ## Useful links 34 | 35 | <!-- Link out to task or reference topics related to the concept. --> 36 | 37 | - [Link example](https://grafana.com) 38 | -------------------------------------------------------------------------------- /vale/Grafana/styles/Grafana/GoogleGenderBias.yml: -------------------------------------------------------------------------------- 1 | "action": 2 | "name": "replace" 3 | "extends": "substitution" 4 | "ignorecase": true 5 | "level": "error" 6 | "link": "https://developers.google.com/style/inclusive-documentation" 7 | "message": "Consider using '%s' instead of '%s'." 8 | "swap": 9 | "(?:alumnae|alumni)": "graduates" 10 | "(?:alumna|alumnus)": "graduate" 11 | "air(?:m[ae]n|wom[ae]n)": "pilot(s)" 12 | "anchor(?:m[ae]n|wom[ae]n)": "anchor(s)" 13 | "authoress": "author" 14 | "camera(?:m[ae]n|wom[ae]n)": "camera operator(s)" 15 | "door(?:m[ae]|wom[ae]n)": "concierge(s)" 16 | "draft(?:m[ae]n|wom[ae]n)": "drafter(s)" 17 | "fire(?:m[ae]n|wom[ae]n)": "firefighter(s)" 18 | "fisher(?:m[ae]n|wom[ae]n)": "fisher(s)" 19 | "fresh(?:m[ae]n|wom[ae]n)": "first-year student(s)" 20 | "garbage(?:m[ae]n|wom[ae]n)": "waste collector(s)" 21 | "lady lawyer": "lawyer" 22 | "ladylike": "courteous" 23 | "mail(?:m[ae]n|wom[ae]n)": "mail carriers" 24 | "man and wife": "husband and wife" 25 | "man enough": "strong enough" 26 | "mankind": "human kind|humanity" 27 | "manmade": "manufactured" 28 | "manpower": "personnel" 29 | "middle(?:m[ae]n|wom[ae]n)": "intermediary" 30 | "news(?:m[ae]n|wom[ae]n)": "journalist(s)" 31 | "ombuds(?:man|woman)": "ombuds" 32 | "oneupmanship": "upstaging" 33 | "poetess": "poet" 34 | "police(?:m[ae]n|wom[ae]n)": "police officer(s)" 35 | "repair(?:m[ae]n|wom[ae]n)": "technician(s)" 36 | "sales(?:m[ae]n|wom[ae]n)": "salesperson or sales people" 37 | "service(?:m[ae]n|wom[ae]n)": "soldier(s)" 38 | "steward(?:ess)?": "flight attendant" 39 | "tribes(?:m[ae]n|wom[ae]n)": "tribe member(s)" 40 | "waitress": "waiter" 41 | "woman doctor": "doctor" 42 | "woman scientist[s]?": "scientist(s)" 43 | "work(?:m[ae]n|wom[ae]n)": "worker(s)" 44 | -------------------------------------------------------------------------------- /docs/sources/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | cascade: 3 | github_branch: main 4 | github_dir: /docs/sources 5 | github_repo: https://github.com/grafana/writers-toolkit/ 6 | labels: 7 | products: 8 | - oss 9 | public_docs: true 10 | replace_dir: "docs/writers-toolkit/" 11 | search_section: Writers' Toolkit 12 | search_type: doc 13 | date: "2022-06-23T11:09:48+01:00" 14 | description: | 15 | A toolkit for writing technical documentation for Grafana Labs. 16 | Use it as the source of truth for voice and tone, grammar, style, templates, and more. 17 | keywords: 18 | - writing guide 19 | - style guide 20 | - Grafana 21 | - documentation 22 | review_date: "2025-06-12" 23 | title: Writers' Toolkit 24 | --- 25 | 26 | # Writers' Toolkit 27 | 28 | Writers' Toolkit is for anyone who writes or edits customer-facing technical documentation for Grafana Labs. 29 | Use it as the source of truth for voice and tone, grammar, style, templates, and more. 30 | 31 | Writers' Toolkit helps you to create technical documentation that's consistent and applies the voice and tone in use at Grafana Labs. 32 | 33 | The style guide extends [Google's developer documentation style guide](https://developers.google.com/style). 34 | If you can't find guidance on a specific topic in Writers' Toolkit, refer to Google's style guide. 35 | 36 | If it's your first time using the guide, start with the [Get started](https://grafana.com/docs/writers-toolkit/get-started/) section. 37 | 38 | ## Questions and feedback 39 | 40 | Writers' Toolkit is open source and available at [`grafana/writers-toolkit`](https://github.com/grafana/writers-toolkit). 41 | If you have questions, or feedback on how to improve this documentation, [open an issue](https://github.com/grafana/writers-toolkit/issues/new) and help make this an even better resource. 42 | -------------------------------------------------------------------------------- /vale/dictionary/t.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('TCP', '', 'noun') { abbreviation: true, elaboration: 'Transmission Control Protocol', established_abbreviation: true }, 4 | word.new('Telegraf', '', 'noun') { description: 'An open-source agent for collecting, processing, aggregating, and writing metrics and logs, originally developed by InfluxData.' }, 5 | word.new('templated', '', 'adjective'), 6 | word.new('Team Sync', '', 'noun') { description: 'Sync your auth providers teams and teams in Grafana.', product: true }, 7 | word.new('Tempo', '', 'noun') { product: true, swaps: { tempo: 'Tempo' } }, 8 | word.new('Thanos', '', 'noun') { product: true }, 9 | word.new('Threema', '', 'noun') { description: 'https://threema.ch/en', product: true, swaps: { threema: 'Threema' } }, 10 | word.new('Timestream', '', 'noun') { Amazon: true, product: true }, 11 | word.new('TLS', '', 'noun') { abbreviation: true, description: 'A cryptographic protocol designed to provide secure communications over network.', elaboration: 'Transport Layer Security', established_abbreviation: true }, 12 | word.new('toolset', 'S', 'noun'), 13 | word.new('tooltip', 'S', 'noun'), 14 | word.new('tracepoint', 'S', 'noun'), 15 | word.new('TraceQL', '', 'noun') { swaps: { 'trace(?:ql|QL)': 'TraceQL' } }, 16 | word.new('traceroute', 'S', 'noun'), 17 | word.new('Traces Drilldown', '', 'noun') { product: true }, 18 | word.new('trendline', 'S', 'noun') { description: 'A transformation that infers data points not represented using linear regression' }, 19 | word.new('triage', 'D', 'verb'), 20 | word.new('TSDB', 'S', 'noun') { abbreviation: true, elaboration: 'time-series database', established_abbreviation: true }, 21 | word.new('TTL', 'S', 'noun') { abbreviation: true, elaboration: 'time to live' }, 22 | ] 23 | -------------------------------------------------------------------------------- /docs/sources/shared/make-help.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2023-10-05T10:43:16+01:00" 3 | description: Understand GNU Make and see and example of Make targets. 4 | review_date: "2024-05-29" 5 | title: GNU Make help output 6 | --- 7 | 8 | Every project keeps technical documentation that's published to the website in the `docs/sources` directory. 9 | That documentation is published to the `content/docs` directory in the website repository. 10 | 11 | Additionally, every project uses [GNU Make](https://www.gnu.org/software/make/) to perform tasks related to technical documentation. 12 | To learn more about GNU Make, refer to [GNU Make Manual](https://www.gnu.org/software/make/manual/). 13 | 14 | To see a list of targets and their descriptions, run `make help` from the `docs/` directory. 15 | If you are in the website repository, run `make help` from the root of the repository instead. 16 | 17 | The output is similar to the following: 18 | 19 | ```console 20 | Usage: 21 | make <target> 22 | 23 | Targets: 24 | help Display this help. 25 | docs-rm Remove the docs container. 26 | docs-pull Pull documentation base image. 27 | make-docs Fetch the latest make-docs script. 28 | docs Serve documentation locally, which includes pulling the latest `DOCS_IMAGE` (default: `grafana/docs-base:latest`) container image. To not pull the image, set `PULL=false`. 29 | docs-debug Run Hugo web server with debugging enabled. TODO: support all SERVER_FLAGS defined in website Makefile. 30 | vale Run vale on the entire docs folder which includes pulling the latest `VALE_IMAGE` (default: `grafana/vale:latest`) container image. To not pull the image, set `PULL=false`. 31 | update Fetch the latest version of this Makefile and the `make-docs` script from Writers' Toolkit. 32 | ``` 33 | -------------------------------------------------------------------------------- /vale/tools/cmd/filter-sarif/sarif/sarif.go: -------------------------------------------------------------------------------- 1 | // Package sarif is a non-exhuastive representation of the SARIF format. 2 | // It just exposes the types for fields that are actively used by the Grafana Vale template. 3 | package sarif 4 | 5 | import ( 6 | "encoding/json" 7 | "os" 8 | ) 9 | 10 | type File struct { 11 | Runs []Run `json:"runs"` 12 | Version string `json:"version"` 13 | Schema string `json:"$schema"` 14 | } 15 | 16 | type Run struct { 17 | Results []Result `json:"results"` 18 | Tool Tool `json:"tool"` 19 | } 20 | 21 | type Result struct { 22 | Level string `json:"level"` 23 | Message Message `json:"message"` 24 | Locations []Location `json:"locations"` 25 | RuleID string `json:"ruleId"` 26 | } 27 | 28 | type Message struct { 29 | Text string `json:"text"` 30 | } 31 | 32 | type Location struct { 33 | PhysicalLocation PhysicalLocation `json:"physicalLocation"` 34 | } 35 | 36 | type PhysicalLocation struct { 37 | ArtifactLocation ArtifactLocation `json:"artifactLocation"` 38 | Region Region `json:"region"` 39 | } 40 | 41 | type ArtifactLocation struct { 42 | URI string `json:"uri"` 43 | } 44 | 45 | type Region struct { 46 | StartLine int `json:"startLine"` 47 | StartColumn int `json:"startColumn"` 48 | } 49 | 50 | type Tool struct { 51 | Driver Driver `json:"driver"` 52 | } 53 | 54 | type Driver struct { 55 | Name string `json:"name"` 56 | InformationURI string `json:"informationUri"` 57 | Version string `json:"version"` 58 | } 59 | 60 | func NewFromFile(path string) (File, error) { 61 | var file File 62 | 63 | data, err := os.ReadFile(path) 64 | if err != nil { 65 | return file, err 66 | } 67 | 68 | if err := json.Unmarshal(data, &file); err != nil { 69 | return file, err 70 | } 71 | 72 | return file, nil 73 | } 74 | -------------------------------------------------------------------------------- /add-to-docs-project/index.mts: -------------------------------------------------------------------------------- 1 | import { GraphQlQueryResponseData } from "@octokit/graphql"; 2 | import { Octokit } from "@octokit/rest"; 3 | import process from "node:process"; 4 | import core from "@actions/core"; 5 | import fs from "fs"; 6 | 7 | // The project ID for the Docs project. 8 | // You can find this by running the `project-id.graphql` query. 9 | const PROJECT_ID = "PVT_kwDOAG3Mbc027w"; 10 | const ISSUES_QUERY = fs.readFileSync("issues.graphql", "utf8"); 11 | const ADD_TO_PROJECT_MUTATION = fs.readFileSync( 12 | "add-to-project.graphql", 13 | "utf8", 14 | ); 15 | 16 | async function addIssuesToProject(): Promise<Array<string>> { 17 | const added: Array<string> = []; 18 | try { 19 | const octokit = new Octokit({ 20 | auth: process.env.GITHUB_TOKEN, 21 | }); 22 | 23 | const issues = ( 24 | (await octokit.graphql(ISSUES_QUERY)) as GraphQlQueryResponseData 25 | ).search.nodes; 26 | 27 | for (const issue of issues) { 28 | console.log( 29 | `Adding issue ${issue.title} (${issue.url}) to the Docs project.`, 30 | ); 31 | added.push( 32 | // https://api.slack.com/reference/surfaces/formatting#escaping 33 | `${issue.url}|${issue.title}` 34 | .replaceAll("&", "&") 35 | .replaceAll("<", "<") 36 | .replaceAll(">", ">"), 37 | ); 38 | 39 | await octokit.graphql(ADD_TO_PROJECT_MUTATION, { 40 | projectId: PROJECT_ID, 41 | contentId: issue.id, 42 | }); 43 | } 44 | } catch (error: any) { 45 | console.error("Error adding issues to the project:", error.message); 46 | core.setFailed(error.message); 47 | } 48 | 49 | return added; 50 | } 51 | 52 | const added = await addIssuesToProject(); 53 | core.setOutput( 54 | "added", 55 | added.map((issue) => `- <${issue}>`.replaceAll('"', '\\"')).join("\\n"), 56 | ); 57 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/SmartQuotes/testinvalid.golden: -------------------------------------------------------------------------------- 1 | testinvalid.md:3:3:Grafana.SmartQuotes:Avoid smart quotes in the source file, especially in code blocks. Replace all smart double quotes like `“` or `”` with `"`. Replace all smart single quotes like `‘`, `’`, or `ʼ` with `'`. In some contexts, Unicode characters aren't supported and break configurations. The website renders paired quotes using smart quotes in paragraphs. 2 | testinvalid.md:4:3:Grafana.SmartQuotes:Avoid smart quotes in the source file, especially in code blocks. Replace all smart double quotes like `“` or `”` with `"`. Replace all smart single quotes like `‘`, `’`, or `ʼ` with `'`. In some contexts, Unicode characters aren't supported and break configurations. The website renders paired quotes using smart quotes in paragraphs. 3 | testinvalid.md:5:3:Grafana.SmartQuotes:Avoid smart quotes in the source file, especially in code blocks. Replace all smart double quotes like `“` or `”` with `"`. Replace all smart single quotes like `‘`, `’`, or `ʼ` with `'`. In some contexts, Unicode characters aren't supported and break configurations. The website renders paired quotes using smart quotes in paragraphs. 4 | testinvalid.md:6:3:Grafana.SmartQuotes:Avoid smart quotes in the source file, especially in code blocks. Replace all smart double quotes like `“` or `”` with `"`. Replace all smart single quotes like `‘`, `’`, or `ʼ` with `'`. In some contexts, Unicode characters aren't supported and break configurations. The website renders paired quotes using smart quotes in paragraphs. 5 | testinvalid.md:7:3:Grafana.SmartQuotes:Avoid smart quotes in the source file, especially in code blocks. Replace all smart double quotes like `“` or `”` with `"`. Replace all smart single quotes like `‘`, `’`, or `ʼ` with `'`. In some contexts, Unicode characters aren't supported and break configurations. The website renders paired quotes using smart quotes in paragraphs. 6 | -------------------------------------------------------------------------------- /tools/hugo/hugo.go: -------------------------------------------------------------------------------- 1 | // Package hugo has functions for working with Hugo source files. 2 | package hugo 3 | 4 | import ( 5 | "bytes" 6 | "fmt" 7 | 8 | "github.com/BurntSushi/toml" 9 | "github.com/gohugoio/hugo/parser/metadecoders" 10 | "github.com/gohugoio/hugo/parser/pageparser" 11 | "gopkg.in/yaml.v3" 12 | ) 13 | 14 | var errUnsupportedFrontMatterFormat = fmt.Errorf("unsupported front matter format") 15 | 16 | // Unparse reverses the Hugo page parsing process. 17 | // Front matter is not round tripped exactly. 18 | // It's expected that some formatting tool is run on the output. 19 | func Unparse(cfm pageparser.ContentFrontMatter) ([]byte, error) { 20 | buf := bytes.NewBuffer([]byte{}) 21 | 22 | switch cfm.FrontMatterFormat { 23 | case metadecoders.YAML: 24 | if _, err := buf.Write([]byte("---\n")); err != nil { 25 | return buf.Bytes(), err 26 | } 27 | fm, err := yaml.Marshal(cfm.FrontMatter) 28 | if err != nil { 29 | return buf.Bytes(), err 30 | } 31 | if _, err := buf.Write(fm); err != nil { 32 | return buf.Bytes(), err 33 | } 34 | if _, err := buf.Write([]byte("---\n")); err != nil { 35 | return buf.Bytes(), err 36 | } 37 | case metadecoders.TOML: 38 | if _, err := buf.Write([]byte("+++\n")); err != nil { 39 | return buf.Bytes(), err 40 | } 41 | fm := bytes.NewBuffer([]byte{}) 42 | if err := toml.NewEncoder(fm).Encode(cfm.FrontMatter); err != nil { 43 | return buf.Bytes(), err 44 | } 45 | if _, err := buf.Write(fm.Bytes()); err != nil { 46 | return buf.Bytes(), err 47 | } 48 | if _, err := buf.Write([]byte("+++\n")); err != nil { 49 | return buf.Bytes(), err 50 | } 51 | default: 52 | return buf.Bytes(), fmt.Errorf("%w: %s", errUnsupportedFrontMatterFormat, cfm.FrontMatterFormat) 53 | } 54 | 55 | if _, err := buf.Write(cfm.Content); err != nil { 56 | return buf.Bytes(), err 57 | } 58 | 59 | return buf.Bytes(), nil 60 | } 61 | -------------------------------------------------------------------------------- /.github/workflows/test-publish-technical-documentation-release.yml: -------------------------------------------------------------------------------- 1 | # To use this workflow to test the publish-technical-documentation-release action: 2 | # 1. Create a branch `test/publish-technical-documentation/v<MAJOR>.<MINOR>.x`. 3 | # 2. Iterate on the workflow or action. 4 | # 3a. To test push events, push the branch. 5 | # 3b. To test tag events, tag the branch with `test/publish-technical-documentation/v<MAJOR>.<MINOR>.<PATCH>`. 6 | # 4. Check the workflow output in https://github.com/grafana/writers-toolkit/actions. 7 | 8 | name: test-publish-technical-documentation-release 9 | 10 | permissions: {} 11 | 12 | on: 13 | push: 14 | branches: 15 | - test/publish-technical-documentation-release/v[0-9]+.[0-9]+.x 16 | tags: 17 | - test/publish-technical-documentation-release/v[0-9]+.[0-9]+.[0-9]+ 18 | workflow_dispatch: 19 | 20 | jobs: 21 | sync: 22 | if: github.repository == 'grafana/writers-toolkit' 23 | permissions: 24 | contents: read 25 | id-token: write 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | fetch-depth: 0 31 | persist-credentials: false 32 | - uses: ./publish-technical-documentation-release 33 | with: 34 | release_tag_regexp: "^test/publish-technical-documentation-release/v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" 35 | release_branch_regexp: "^test/publish-technical-documentation-release/v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.x$" 36 | release_branch_with_patch_regexp: "^test/publish-technical-documentation-release/v(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)$" 37 | website_branch: test/publish-technical-documentation-release 38 | website_directory: content/docs/publish-technical-documetation-release 39 | version_suffix: "" 40 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Technical documentation 2 | 3 | This repository publishes technical documentation to the https://grafana.com website. 4 | The [`publish-technical-documentation-next.yml`](../.github/workflows/publish-technical-documentation-next.yml) commits the contents of the [`/docs/sources`](./sources) directory to the `/content/docs/cloud-onboarding` directory in the [`grafana/website`](https://github.com/grafana/website) repository. 5 | 6 | Pushes to the `main` branch that add, delete, or modify files in the `/docs/sources` directory trigger the workflow. 7 | To manually run the workflow, refer to [Manually run the workflow](https://github.com/grafana/technical-documentation/blob/main/docs/sources/publish-technical-documentation/index.md#manually-run-the-workflow). 8 | 9 | If the workflow fails unexpectedly, reach out to the `#docs` channel on Slack with a link to the source commit or pull request, and the workflow run. 10 | 11 | Successful completion of the workflow means that the contents have been committed to the [`grafana/website`](https://github.com/grafana/website) repository. 12 | There are subsequent build pipelines that perform the production build and deploy. 13 | For insight into the full procedure, refer to the [Website dashboard](https://ops.grafana-ops.net/d/c88932b3-7302-4695-b5eb-7b3c9d501b94/website?orgId=1&refresh=1m). 14 | 15 | ## Local development 16 | 17 | A local webserver serves from http://localhost:3002/docs/grafana-cloud/data-configuration/integrations/. 18 | For more information about the webserver, refer to [Run a local documentation webserver | Writers' Toolkit documentation](https://grafana.com/docs/writers-toolkit/writing-guide/tooling-and-workflows/run-a-local-webserver/). 19 | 20 | The supporting scripts and Makefiles are maintained in the [`grafana/writers-toolkit`](https://github.com/grafana/writers-toolkit) repository. 21 | To update those files, run `make update`. 22 | -------------------------------------------------------------------------------- /vale/tools/cmd/filter-sarif/testdata/102941-filtered.sarif: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.1.0", 3 | "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json", 4 | "runs": [ 5 | { 6 | "tool": { 7 | "driver": { 8 | "name": "Vale", 9 | "informationUri": "https://vale.sh", 10 | "version": "0.1.0" 11 | } 12 | }, 13 | "results": [ 14 | { 15 | "ruleId": "Grafana.WordList", 16 | "level": "warning", 17 | "message": { 18 | "markdown": "Use 'free-form' or 'user-written' instead of 'ad-hoc'.\n\nFor more information, refer to \u003chttps://grafana.com/docs/writers-toolkit/write/style-guide/word-list/\u003e.\n\nIf the rule is incorrect or needs improving, [report an issue](https://github.com/grafana/writers-toolkit/issues/new?title=Grafana.WordList%20%3A%20%3CISSUE%3E).\n\nIf you have reason to diverge from the style guidance,\nto skip a rule, refer to [Skip rules](https://grafana.com/docs/writers-toolkit/review/lint-prose/#skip-rules).\n\nTo fix this, Replace the matched content with one of the following:\n\n- `free-form`\n- `user-written`.", 19 | "text": "Use 'free-form' or 'user-written' instead of 'ad-hoc'.\n\nFor more information, refer to https://grafana.com/docs/writers-toolkit/write/style-guide/word-list/.\n\nTo fix this, Replace the matched content with one of the following:\n\n- `free-form`\n- `user-written`." 20 | }, 21 | "locations": [ 22 | { 23 | "physicalLocation": { 24 | "artifactLocation": { 25 | "uri": "docs/sources/upgrade-guide/when-to-upgrade/index.md" 26 | }, 27 | "region": { 28 | "startLine": 33, 29 | "startColumn": 387, 30 | "endColumn": 392 31 | } 32 | } 33 | } 34 | ] 35 | } 36 | ] 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /vale/fixtures/Grafana/Headings/testinvalid.md: -------------------------------------------------------------------------------- 1 | # Grafana/Headings 2 | 3 | ## Thresholds 4 | 5 | The following headings test the behavior of the `thresholds` parameter. 6 | Each heading is sentence cased and each word represents the word's index in the sentence. 7 | 8 | ### One Two Three Four 9 | 10 | Given one correctly sentence cased words, you need three additional incorrectly cased words to trigger the rule. 11 | 12 | The measured ratio is 0.25. 13 | 14 | ### One two Three Four Five Six Seven Eight Nine Ten 15 | 16 | Given two correctly sentence cased words, you need eight additional incorrectly cased words to trigger the rule. 17 | 18 | The measured ratio is 0.2. 19 | 20 | ### One two three Four Five Six Seven Eight Nine Ten Eleven 21 | 22 | Given three correctly sentence cased words, you need eight additional incorrectly cased words to trigger the rule. 23 | 24 | The measured ratio is approximately 0.273. 25 | 26 | ### One two three four Five Six Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen 27 | 28 | Given four correctly sentence cased words, you need ten additional incorrectly cased words to trigger the rule. 29 | 30 | The measured ratio is approximately 0.286. 31 | 32 | ### One two three four five Six Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen Sixteen Seventeen 33 | 34 | Given four correctly sentence cased words, you need twelve additional incorrectly cased words to trigger the rule. 35 | 36 | The measured ratio is approximately 0.294. 37 | 38 | ### One Two Three Beyla 39 | 40 | Since this heading doesn't trigger the rule, Vale must consider exceptions to be correctly cased. 41 | Without an exception for Beyla, the ratio is 0.25. 42 | With the exception, the ratio is 0.5. 43 | 44 | ### Grafana Enterprise Metrics Four Five Six 45 | 46 | Vale must consider multi-word exceptions as a single word in the ratio. 47 | If Vale considered the exception _Grafana Enterprise Metrics_ as three separate words, the ratio would be 0.5. 48 | Since Vale considers the exception as one word, the ratio is 0.25. 49 | -------------------------------------------------------------------------------- /docs/sources/shared/hugo-error-example-bad-link.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2023-09-04T07:43:24-04:00" 3 | description: Understand the REF_NOT_FOUND error Hugo emits for broken relref links. 4 | review_date: "2024-05-28" 5 | title: REF_NOT_FOUND Hugo output 6 | --- 7 | 8 | [//]: # "This file documents an example Hugo error output for relref and links." 9 | [//]: # "This shared file is included in these locations:" 10 | [//]: # "- Page: [Test documentation changes](https://grafana.com/docs/writers-toolkit/review/test-documentation-changes/#example-rebuild-failed-due-to-missing-shortcode)" 11 | [//]: # " Source: [test-documentation-changes/index.md](https://github.com/grafana/writers-toolkit/blob/main/docs/sources/review/test-documentation-changes/index.md?plain=1#L99)" 12 | [//]: # 13 | [//]: # "If you make changes to this file, verify that the meaning and content are not changed in any place where the file is included." 14 | 15 | Hugo emits `REF_NOT_FOUND` warnings indicating the filename and location of such references when building the docs, for example with `make docs` in `grafana/grafana` or `make server-quick` in `grafana/website`: 16 | 17 | ``` 18 | WARN 2022/08/04 21:35:37 [en] REF_NOT_FOUND: Ref "../../enterprise": "/hugo/content/docs/grafana/next/administration/roles-and-permissions/access-control/assign-rbac-roles.md:14:47": page not found 19 | ``` 20 | 21 | In this example, 22 | 23 | - `Ref "../../enterprise"` is the destination of the reference that Hugo can't resolve 24 | - `\/hugo/content/docs/grafana/next/administration/roles-and-permissions/access-control/assign-rbac-roles.md` is the document containing the reference, where the path after `/next/` is relative to the documentation root of the component repository 25 | - `:14` represents the line number containing the unresolved reference 26 | - `:47` represents the character in that line where the unresolved reference begins 27 | 28 | If you see this error, then the reference's destination is invalid. 29 | This may be due to a typo in the reference or having the incorrect path to the destination directory. 30 | Fix the error by correcting the reference target. 31 | -------------------------------------------------------------------------------- /vale/dictionary/g.jsonnet: -------------------------------------------------------------------------------- 1 | local word = import './word.jsonnet'; 2 | [ 3 | word.new('GEM', '', 'noun') { abbreviation: true, elaboration: 'Grafana Enterprise Metrics', product: true, swaps: { GME: 'GEM' } }, 4 | word.new('geomap', 'S', 'noun') { description: 'A Grafana visualization type.' }, 5 | word.new('geospatial', '', 'adjective'), 6 | word.new('GKE', '', 'noun') { abbreviation: true, elaboration: 'Google Kubernetes Engine', product: true }, // Doesn't need Google: true because Google is in the name. 7 | word.new('Git', '', 'noun') { product: true, swaps: { git: 'Git' } }, 8 | word.new('GitHub', '', 'noun') { product: true, swaps: { '(?:github|gitHub|Github)': 'GitHub' } }, 9 | word.new('GitLab', '', 'noun') { product: true, swaps: { '(?:gitlab|gitLab|Gitlab)': 'GitLab' } }, 10 | word.new('glob', 'G', 'noun') { description: 'In computer programming, glob patterns specify sets of filenames with wildcard characters.' }, 11 | word.new('globbing', '', 'verb') { description: 'In computer programming, glob patterns specify sets of filenames with wildcard characters.' }, 12 | word.new('GNU', '', 'noun') { abbreviation: true, established_abbreviation: true, product: true }, 13 | word.new('Goldmark', '', 'noun') { description: 'Goldmark is a markdown parser written in Go (https://github.com/yuin/goldmark)' }, 14 | word.new('goroutine', 'S', 'noun'), 15 | word.new('GPG', '', 'noun') { abbreviation: true, description: 'GNU Privacy Guard', established_abbreviation: true }, 16 | word.new('GPU', 'S', 'noun') { abbreviation: true, elaboration: 'graphics processing unit', established_abbreviation: true }, 17 | word.new('Grafana', '', 'adjective'), 18 | word.new('Grafana', '', 'noun') { product: true, swaps: { grafana: 'Grafana' } }, 19 | word.new('Gravatar', '', 'adjective'), 20 | word.new('Gravatar', '', 'noun') { product: true }, 21 | word.new('Graylog', '', 'noun') { product: true }, 22 | word.new('GUI', 'S', 'noun') { abbreviation: true, elaboration: 'graphical user interface', established_abbreviation: true }, 23 | word.new('Gunicorn', '', 'noun') { product: true, swaps: { gunicorn: 'Gunicorn' } }, 24 | word.new('Gzip', '', 'noun'), 25 | ] 26 | -------------------------------------------------------------------------------- /vale/Grafana/styles/config/scripts/Paragraphs_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "context" 5 | "os" 6 | "regexp" 7 | "testing" 8 | 9 | "github.com/d5/tengo/v2" 10 | "github.com/d5/tengo/v2/stdlib" 11 | "github.com/stretchr/testify/assert" 12 | "github.com/stretchr/testify/require" 13 | ) 14 | 15 | func TestParagraphs(t *testing.T) { 16 | t.Run("don't use", func(t *testing.T) { 17 | src := `Don't use: 18 | 19 | - <br> 20 | - <br /> 21 | - <br/> 22 | ` 23 | data, err := os.ReadFile("Paragraphs.tengo") 24 | require.NoError(t, err) 25 | 26 | data = regexp.MustCompile(`DEBUG := false`).ReplaceAll(data, []byte(`DEBUG := true`)) 27 | 28 | script := tengo.NewScript(data) 29 | script.SetImports(stdlib.GetModuleMap("text", "fmt", "math")) 30 | 31 | err = script.Add("scope", src) 32 | require.NoError(t, err) 33 | 34 | compiled, err := script.RunContext(context.Background()) 35 | require.NoError(t, err) 36 | 37 | want := []map[string]int{ 38 | {"begin": 14, "end": 18}, 39 | {"begin": 21, "end": 27}, 40 | {"begin": 30, "end": 35}, 41 | } 42 | 43 | assert.Equal(t, want, mustParseMatches(compiled.Get("matches").Array())) 44 | }) 45 | 46 | t.Run("with exclusions", func(t *testing.T) { 47 | src := ` 48 | Test exclusions: 49 | 50 | <!-- vale Grafana.Paragraphs = NO --> 51 | 52 | - <br> 53 | - <br /> 54 | - <br/> 55 | 56 | <!-- vale Grafana.Paragraphs = YES --> 57 | 58 | Don't use: 59 | 60 | - <br> 61 | - <br /> 62 | - <br/> 63 | ` 64 | 65 | data, err := os.ReadFile("Paragraphs.tengo") 66 | require.NoError(t, err) 67 | 68 | data = regexp.MustCompile(`DEBUG := false`).ReplaceAll(data, []byte(`DEBUG := true`)) 69 | 70 | script := tengo.NewScript(data) 71 | script.SetImports(stdlib.GetModuleMap("text", "fmt", "math")) 72 | 73 | err = script.Add("scope", src) 74 | require.NoError(t, err) 75 | 76 | compiled, err := script.RunContext(context.Background()) 77 | require.NoError(t, err) 78 | 79 | want := []map[string]int{ 80 | {"begin": 137, "end": 141}, 81 | {"begin": 144, "end": 150}, 82 | {"begin": 153, "end": 158}, 83 | } 84 | 85 | assert.Equal(t, want, mustParseMatches(compiled.Get("matches").Array())) 86 | }) 87 | } 88 | -------------------------------------------------------------------------------- /docs/sources/shared/refs-example.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2024-04-04T12:05:52+01:00" 3 | description: An example of the `refs` front matter. 4 | review_date: "2024-06-24" 5 | title: An example of the `refs` front matter 6 | --- 7 | 8 | A partial front matter containing the `refs` field looks like: 9 | 10 | ```yaml 11 | refs: 12 | <KEY>: 13 | - pattern: <URL PATH PREFIX> 14 | destination: <FULL URL> 15 | - pattern: <URL PATH PREFIX> 16 | destination: <FULL URL> 17 | ``` 18 | 19 | - _`<URL PATH PREFIX>`_ - Enter the part of the page URL that represents the project in which the documentation is published. 20 | - `destination` - Enter the full URL of the destination page for that project including trailing slashes. 21 | 22 | If the page's URL matches the pattern _`<URL PATH PREFIX>`_, then Hugo uses `destination` as the link destination. 23 | If no pattern matches the current page, Hugo logs a build error. 24 | 25 | The _`<FULL URL>`_ destination has the same behavior as described in [Link to `grafana.com` pages](https://grafana.com/docs/writers-toolkit/write/links/#link-to-grafanacom-pages) 26 | 27 | # Example 28 | 29 | The following Markdown snippet demonstrates the `refs` front matter and link that uses a `ref` URI. 30 | 31 | ```markdown 32 | --- 33 | refs: 34 | find-plugins: 35 | - pattern: /docs/grafana/ 36 | destination: /docs/grafana/<GRAFANA_VERSION>/administration/plugin-management/#browse-plugins 37 | - pattern: /docs/grafana-cloud/ 38 | destination: /docs/grafana-cloud/introduction/find-and-use-plugins/ 39 | --- 40 | 41 | # Manage plugins 42 | 43 | ## Before you begin 44 | 45 | - Find the plugin you want to install. To find a plugin, refer to [Find and use plugins](ref:find-plugins). 46 | ``` 47 | 48 | In the latest version of a Grafana documentation page, the link destination is <https://grafana.com/docs/grafana/latest/administration/plugin-management/#browse-plugins>. 49 | Hugo replaces the [version substitution syntax](https://grafana.com/docs/writers-toolkit/write/shortcodes/#about-version-substitution) `<GRAFANA_VERSION>` with the version inferred from the current page. 50 | 51 | In a Grafana Cloud page, the link destination is <https://grafana.com/docs/grafana-cloud/introduction/find-and-use-plugins/>. 52 | --------------------------------------------------------------------------------