From 4819fa2ec751fa0aa583663409b22274688eee11 Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Fri, 22 Sep 2023 11:12:49 -0700 Subject: [PATCH 1/2] Add additional search-replace rules and tests (#42826) Co-authored-by: Peter Bengtsson --- .../lib/default-markdownlint-options.js | 4 +- src/content-linter/lib/helpers/get-rules.js | 4 +- src/content-linter/lib/init-test.js | 4 +- src/content-linter/style/github-docs.js | 63 ++++++++++++- .../tests/unit/search-replace.js | 93 +++++++++++++++++++ 5 files changed, 159 insertions(+), 9 deletions(-) create mode 100644 src/content-linter/tests/unit/search-replace.js diff --git a/src/content-linter/lib/default-markdownlint-options.js b/src/content-linter/lib/default-markdownlint-options.js index d7e609d12f3c..9655eda82782 100644 --- a/src/content-linter/lib/default-markdownlint-options.js +++ b/src/content-linter/lib/default-markdownlint-options.js @@ -1,7 +1,7 @@ -export function testOptions(rule, module, { strings, files }) { +export function testOptions(rule, module, { strings, files, testConfig }) { const config = { default: false, - [rule]: true, + [rule]: testConfig || true, } const options = { diff --git a/src/content-linter/lib/helpers/get-rules.js b/src/content-linter/lib/helpers/get-rules.js index 2b6dff4a0a26..7bfee336f46d 100644 --- a/src/content-linter/lib/helpers/get-rules.js +++ b/src/content-linter/lib/helpers/get-rules.js @@ -1,8 +1,8 @@ import rules from '../../../../node_modules/markdownlint/lib/rules.js' import { gitHubDocsMarkdownlint } from '../linting-rules/index.js' import { baseConfig } from '../../style/base.js' -import { githubDocsConfig } from '../../style/github-docs.js' +import { githubDocsConfig, searchReplaceConfig } from '../../style/github-docs.js' export const customRules = gitHubDocsMarkdownlint.rules export const allRules = [...rules, ...gitHubDocsMarkdownlint.rules] -export const allConfig = { ...baseConfig, ...githubDocsConfig } +export const allConfig = { ...baseConfig, ...githubDocsConfig, ...searchReplaceConfig } diff --git a/src/content-linter/lib/init-test.js b/src/content-linter/lib/init-test.js index 0a055504b87b..610d099f43fe 100644 --- a/src/content-linter/lib/init-test.js +++ b/src/content-linter/lib/init-test.js @@ -2,10 +2,10 @@ import markdownlint from 'markdownlint' import { testOptions } from './default-markdownlint-options.js' -export async function runRule(module, { strings, files } = {}) { +export async function runRule(module, { strings, files, testConfig }) { if ((!strings && !files) || (strings && files)) throw new Error('Must provide either Markdown strings or files to run a rule') - const options = testOptions(module.names[0], module, { strings, files }) + const options = testOptions(module.names[0], module, { strings, files, testConfig }) return await markdownlint.promises.markdownlint(options) } diff --git a/src/content-linter/style/github-docs.js b/src/content-linter/style/github-docs.js index 4ef6fa75dfd8..df56487fe423 100644 --- a/src/content-linter/style/github-docs.js +++ b/src/content-linter/style/github-docs.js @@ -48,12 +48,15 @@ export const githubDocsConfig = { severity: 'error', 'partial-markdown-files': true, }, +} + +export const searchReplaceConfig = { 'search-replace': { rules: [ { name: 'todocs-placeholder', message: 'Catch occurrences of TODOCS placeholder.', - search: 'TODOCS', + searchPattern: '/todocs/gi', searchScope: 'all', severity: 'error', 'severity-local': 'warning', @@ -62,7 +65,7 @@ export const githubDocsConfig = { { name: 'docs-domain', message: 'Catch occurrences of docs.gitub.com domain.', - search: 'docs.gitub.com', + search: 'docs.github.com', searchScope: 'all', severity: 'error', 'partial-markdown-files': true, @@ -90,11 +93,65 @@ export const githubDocsConfig = { // developer.github.com/enterprise/[0-9] or // developer.github.com/enterprise/{{something}} (e.g. liquid). // There are occurences that will likely always remain in the content. - searchPattern: '/developer.github.com(?!/(changes|enterprise/([0-9]|{))).*/g', + searchPattern: '/developer\\.github\\.com(?!\\/(changes|enterprise\\/([0-9]|{))).*/g', searchScope: 'all', severity: 'error', 'partial-markdown-files': true, }, + { + // Catches usage of old liquid data reusable syntax. For example: + // {{ site.data.variables.product_releases }} + name: 'deprecated liquid syntax: site.data', + message: 'Catch occurrences of deprecated liquid data syntax.', + searchPattern: '/{{\\s*?site\\.data\\.([a-zA-Z0-9-_]+(?:\\.[a-zA-Z0-9-_]+)+)\\s*?}}/g', + replace: '{% data $1 %}', + }, + { + // Catches usage of old octicon variable syntax. For example: + // - {{ octicon-plus }} + // - {{ octicon-plus An example label }} + name: 'deprecated liquid syntax: octicon-', + message: + 'The octicon liquid syntax used is deprecated. Use this format instead {% octicon "" aria-label="" %}', + searchPattern: '/{{\\s*?octicon-([a-z-]+)(\\s[\\w\\s\\d-]+)?\\s*?}}/g', + }, + { + // Catches usage of string personal access token, which should + // be replaced with a reusable data variable. + name: 'personal access token reusable', + message: + 'The string "personal access token" can be replaced with a variable. You should use one of the variables from data/variables/product.yml instead of the literal phrase(s):', + searchPattern: '/personal access tokens?/gi', + }, + { + // Catches usage of GitHub-owned actions that don't use a + // resuable. + // GitHub-owned actions (e.g. actions/checkout@v2) should use a + // reusable in examples. + // + // - actions/checkout@v2 + // - actions/delete-package-versions@v2 + // - actions/download-artifact@v2 + // - actions/upload-artifact@v2 + // - actions/github-script@v2 + // - actions/setup-dotnet@v2 + // - actions/setup-go@v2 + // - actions/setup-java@v2 + // - actions/setup-node@v2 + // - actions/setup-python@v2 + // - actions/stale@v2 + // - actions/cache@v2 + // - github/codeql-action/init@v2 + // - github/codeql-action/analyze@v2 + // - github/codeql-action/autobuild@v2 + // - github/codeql-action/upload-sarif@v2 + // + name: 'GitHub-owned action references should use a reusable', + message: + 'A GitHub-owned action is referenced, but should be replaced with a reusable from data/reusables/actions.', + searchPattern: + '/(actions\\/(checkout|delete-package-versions|download-artifact|upload-artifact|github-script|setup-dotnet|setup-go|setup-java|setup-node|setup-python|stale|cache)|github\\/codeql-action[/a-zA-Z-]*)/g', + }, ], }, } diff --git a/src/content-linter/tests/unit/search-replace.js b/src/content-linter/tests/unit/search-replace.js new file mode 100644 index 000000000000..9542c46dd296 --- /dev/null +++ b/src/content-linter/tests/unit/search-replace.js @@ -0,0 +1,93 @@ +import searchReplace from 'markdownlint-rule-search-replace' + +import { runRule } from '../../lib/init-test.js' +import { searchReplaceConfig } from '../../style/github-docs.js' + +describe(searchReplace.names.join(' - '), () => { + test('TODOCS placeholder occurrences cause errors', async () => { + const markdown = [ + '## TODOCS', + '- Todocs', + '[ToDOCS](/todocs)', + '![TODOCS](./ToDocs.png)', + 'HelloTODOCS', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + testConfig: searchReplaceConfig['search-replace'], + }) + const errors = result.markdown + expect(errors.length).toBe(7) + }) + + test('docs domain occurrences cause error', async () => { + const markdown = [ + 'These are not ok:', + 'docs.github.com', + '- help.github.com', + '[help.github.com](//developer.github.com)', + '![developer.github.com](//preview.ghdocs.com)', + ' docs.github.com', + 'developer.github.com/enterprise', + 'developer.github.com/enterprise/', + '', + 'These are ok:', + 'developer.github.com/changes', + 'developer.github.com/changes/', + 'developer.github.com/changes/changes', + 'developer.github.com/enterprise/1', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + testConfig: searchReplaceConfig['search-replace'], + }) + const errors = result.markdown + expect(errors.length).toBe(9) + }) + + test('Deprecated Liquid syntax causes error', async () => { + const markdown = [ + '{{ site.data.thing1.thing2 }}', + '{{site.data.thing1.thing2}}', + '{{ octicon-plus An example label }}', + '{{octicon-icon}}', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + testConfig: searchReplaceConfig['search-replace'], + }) + const errors = result.markdown + expect(errors.length).toBe(4) + }) + + test('Using hardcoded personal access token string causes error', async () => { + const markdown = [ + 'Hello personal access token for apps.', + 'A Personal access token for apps.', + 'Lots of PERSONAL ACCESS TOKENS for apps.', + 'access tokens for apps.', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + testConfig: searchReplaceConfig['search-replace'], + }) + const errors = result.markdown + expect(errors.length).toBe(3) + }) + + test('Using hardcoded personal access token string causes error', async () => { + const markdown = [ + 'Hello actions/checkout@v2 apps.', + 'A actions/delete-package-versions@v2 for apps.', + 'Hello actions/download-artifact@v2.', + 'actions/cache@432433423423', + 'actions/cache@', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + testConfig: searchReplaceConfig['search-replace'], + }) + const errors = result.markdown + expect(errors.length).toBe(5) + }) +}) From 5c56c7d6d8db00a7e0fe948c27eabbd541906c8c Mon Sep 17 00:00:00 2001 From: Rachael Sewell Date: Fri, 22 Sep 2023 11:16:51 -0700 Subject: [PATCH 2/2] fix remaining code fence blank violations (#43100) --- .../automating-builds-and-tests/building-and-testing-go.md | 1 + .../building-and-testing-java-with-ant.md | 1 + .../building-and-testing-java-with-gradle.md | 1 + .../building-and-testing-java-with-maven.md | 1 + .../automating-builds-and-tests/building-and-testing-net.md | 1 + .../automating-builds-and-tests/building-and-testing-nodejs.md | 1 + .../automating-builds-and-tests/building-and-testing-python.md | 1 + .../automating-builds-and-tests/building-and-testing-ruby.md | 1 + .../automating-builds-and-tests/building-and-testing-swift.md | 1 + 9 files changed, 9 insertions(+) diff --git a/content/actions/automating-builds-and-tests/building-and-testing-go.md b/content/actions/automating-builds-and-tests/building-and-testing-go.md index af1ee913bbe6..b293dbf9613c 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-go.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-go.md @@ -74,6 +74,7 @@ We recommend that you have a basic understanding of the Go language. For more in - name: Test run: go test -v ./... ``` + {%- endif %} 1. Edit the workflow as required. For example, change the version of Go. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-java-with-ant.md b/content/actions/automating-builds-and-tests/building-and-testing-java-with-ant.md index 4532474d21c3..ffdc9ece7f04 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-java-with-ant.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-java-with-ant.md @@ -78,6 +78,7 @@ We recommend that you have a basic understanding of Java and the Ant framework. - name: Build with Ant run: ant -noinput -buildfile build.xml ``` + {%- endif %} 1. Edit the workflow as required. For example, change the Java version. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-java-with-gradle.md b/content/actions/automating-builds-and-tests/building-and-testing-java-with-gradle.md index 7cadce8fdd02..b3387b5e8acd 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-java-with-gradle.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-java-with-gradle.md @@ -83,6 +83,7 @@ We recommend that you have a basic understanding of Java and the Gradle framewor with: arguments: build ``` + {%- endif %} 1. Edit the workflow as required. For example, change the Java version. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-java-with-maven.md b/content/actions/automating-builds-and-tests/building-and-testing-java-with-maven.md index 38e60bcddbfb..51648c6c7a82 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-java-with-maven.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-java-with-maven.md @@ -83,6 +83,7 @@ We recommend that you have a basic understanding of Java and the Maven framework - name: Update dependency graph uses: advanced-security/maven-dependency-submission-action@571e99aab1055c2e71a1e2309b9691de18d6b7d6 ``` + {%- endif %} 1. Edit the workflow as required. For example, change the Java version. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-net.md b/content/actions/automating-builds-and-tests/building-and-testing-net.md index c0805a08554f..1e7da9692772 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-net.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-net.md @@ -69,6 +69,7 @@ We recommend that you have a basic understanding of the .NET Core SDK. For more - name: Test run: dotnet test --no-build --verbosity normal ``` + {%- endif %} 1. Edit the workflow as required. For example, change the .NET version. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-nodejs.md b/content/actions/automating-builds-and-tests/building-and-testing-nodejs.md index 3467b3ef84c8..a474a1d7c62a 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-nodejs.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-nodejs.md @@ -79,6 +79,7 @@ We recommend that you have a basic understanding of Node.js, YAML, workflow conf - run: npm run build --if-present - run: npm test ``` + {%- endif %} 1. Edit the workflow as required. For example, change the Node versions you want to use. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-python.md b/content/actions/automating-builds-and-tests/building-and-testing-python.md index 8f4ea5a687cd..774356addcbf 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-python.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-python.md @@ -92,6 +92,7 @@ We recommend that you have a basic understanding of Python, PyPy, and pip. For m run: | pytest ``` + {%- endif %} 1. Edit the workflow as required. For example, change the Python version. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-ruby.md b/content/actions/automating-builds-and-tests/building-and-testing-ruby.md index e564bdd81f29..73b616879438 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-ruby.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-ruby.md @@ -77,6 +77,7 @@ We recommend that you have a basic understanding of Ruby, YAML, workflow configu - name: Run tests run: bundle exec rake ``` + {%- endif %} 1. Edit the workflow as required. For example, change the Ruby versions you want to use. diff --git a/content/actions/automating-builds-and-tests/building-and-testing-swift.md b/content/actions/automating-builds-and-tests/building-and-testing-swift.md index efa8a7ce9655..16a3d635531e 100644 --- a/content/actions/automating-builds-and-tests/building-and-testing-swift.md +++ b/content/actions/automating-builds-and-tests/building-and-testing-swift.md @@ -67,6 +67,7 @@ We recommend that you have a basic understanding of Swift packages. For more inf - name: Run tests run: swift test -v ``` + {%- endif %} 1. Edit the workflow as required. For example, change the branch on which the workflow will run.