diff --git a/content/actions/concepts/overview/about-continuous-deployment-with-github-actions.md b/content/actions/concepts/overview/continuous-deployment.md similarity index 79% rename from content/actions/concepts/overview/about-continuous-deployment-with-github-actions.md rename to content/actions/concepts/overview/continuous-deployment.md index 341f1e03cf33..30d09201993d 100644 --- a/content/actions/concepts/overview/about-continuous-deployment-with-github-actions.md +++ b/content/actions/concepts/overview/continuous-deployment.md @@ -1,6 +1,5 @@ --- -title: About continuous deployment with GitHub Actions -shortTitle: Continuous deployment +title: Continuous deployment intro: 'You can create custom continuous deployment (CD) workflows directly in your {% data variables.product.prodname_dotcom %} repository with {% data variables.product.prodname_actions %}.' versions: fpt: '*' @@ -13,6 +12,7 @@ redirect_from: - /actions/deployment/about-deployments - /actions/about-github-actions/about-continuous-deployment - /actions/about-github-actions/about-continuous-deployment-with-github-actions + - /actions/concepts/overview/about-continuous-deployment-with-github-actions topics: - CD --- @@ -33,17 +33,10 @@ You can configure your CD workflow to run when an event occurs (for example, whe {% data variables.product.prodname_actions %} provides features that give you more control over deployments. For example, you can use environments to require approval for a job to proceed, restrict which branches can trigger a workflow, or limit access to secrets. You can use concurrency to limit your CD pipeline to a maximum of one in-progress deployment and one pending deployment. For more information about these features, see [AUTOTITLE](/actions/deployment/about-deployments/deploying-with-github-actions) and [AUTOTITLE](/actions/deployment/targeting-different-environments/managing-environments-for-deployment). -## Using OpenID Connect to access cloud resources - -{% data reusables.actions.about-oidc-short-overview %} - -## Workflow templates and third party actions +## Workflow templates and third-party actions {% data reusables.actions.cd-templates-actions %} -## Further reading +## Next steps -* [AUTOTITLE](/actions/use-cases-and-examples/deploying) -* [AUTOTITLE](/actions/deployment/about-deployments/deploying-with-github-actions) -* [AUTOTITLE](/actions/deployment/targeting-different-environments/managing-environments-for-deployment){% ifversion fpt or ghec %} -* [AUTOTITLE](/billing/managing-billing-for-github-actions){% endif %} +If your {% data variables.product.prodname_actions %} workflows need to access resources from a cloud provider that supports OpenID Connect (OIDC), you can configure your workflows to authenticate directly to the cloud provider. This will let you stop storing these credentials as long-lived secrets and provide other security benefits. For more information, see [AUTOTITLE](/actions/deployment/security-hardening-your-deployments/about-security-hardening-with-openid-connect). diff --git a/content/actions/concepts/overview/github-actions-vs-github-apps.md b/content/actions/concepts/overview/github-actions-vs-github-apps.md new file mode 100644 index 000000000000..2f486d35a0f6 --- /dev/null +++ b/content/actions/concepts/overview/github-actions-vs-github-apps.md @@ -0,0 +1,27 @@ +--- +title: GitHub Actions vs GitHub Apps +shortTitle: Actions vs Apps +intro: 'Learn about the key differences between {% data variables.product.prodname_actions %} and {% data variables.product.prodname_github_apps %} to help you decide which is right for your use cases.' +versions: + fpt: '*' + ghes: '*' + ghec: '*' +type: overview +topics: + - CD +--- + +{% data variables.product.prodname_marketplace %} offers both {% data variables.product.prodname_actions %} and {% data variables.product.prodname_github_apps %}, each of which can be valuable automation and workflow tools. Understanding the differences and the benefits of each option will allow you to select the best fit for your job. + +{% data variables.product.prodname_github_apps %}: +* Run persistently and can react to events quickly. +* Work great when persistent data is needed. +* Work best with API requests that aren't time consuming. +* Run on a server or compute infrastructure that you provide. + +{% data variables.product.prodname_actions %}: +* Provide automation that can perform continuous integration and continuous deployment. +* Can run directly on runner machines or in Docker containers. +* Can include access to a clone of your repository, enabling deployment and publishing tools, code formatters, and command line tools to access your code. +* Don't require you to deploy code or serve an app. +* Have a simple interface to create and use secrets, which enables actions to interact with third-party services without needing to store the credentials of the person using the action. diff --git a/content/actions/concepts/overview/index.md b/content/actions/concepts/overview/index.md index 8a77af07f443..665ab660aa57 100644 --- a/content/actions/concepts/overview/index.md +++ b/content/actions/concepts/overview/index.md @@ -7,6 +7,7 @@ versions: ghes: '*' ghec: '*' children: - - /about-continuous-deployment-with-github-actions - /continuous-integration + - /continuous-deployment + - /github-actions-vs-github-apps --- diff --git a/content/actions/concepts/workflows-and-actions/about-custom-actions.md b/content/actions/concepts/workflows-and-actions/about-custom-actions.md index 2cc0243fb694..23fb87ab514b 100644 --- a/content/actions/concepts/workflows-and-actions/about-custom-actions.md +++ b/content/actions/concepts/workflows-and-actions/about-custom-actions.md @@ -65,117 +65,6 @@ If you're developing a Node.js project, the {% data variables.product.prodname_a A _composite_ action allows you to combine multiple workflow steps within one action. For example, you can use this feature to bundle together multiple run commands into an action, and then have a workflow that executes the bundled commands as a single step using that action. To see an example, check out [AUTOTITLE](/actions/creating-actions/creating-a-composite-action). -## Choosing a location for your action +## Next steps -If you're developing an action for other people to use, we recommend keeping the action in its own repository instead of bundling it with other application code. This allows you to version, track, and release the action just like any other software. - -{% ifversion fpt or ghec %} -Storing an action in its own repository makes it easier for the {% data variables.product.prodname_dotcom %} community to discover the action, narrows the scope of the code base for developers fixing issues and extending the action, and decouples the action's versioning from the versioning of other application code. -{% endif %} - -{% data reusables.actions.internal-actions-summary %} - -{% ifversion fpt or ghec %}If you're building an action that you don't plan to make available to others, you {% else %} You{% endif %} can store the action's files in any location in your repository. If you plan to combine action, workflow, and application code in a single repository, we recommend storing actions in the `.github` directory. For example, `.github/actions/action-a` and `.github/actions/action-b`. - -## Ensuring compatibility with other platforms - -Many people access {% data variables.product.github %} at a domain other than {% data variables.product.prodname_dotcom_the_website %}, such as {% data variables.enterprise.data_residency_site %} or a custom domain for {% data variables.product.prodname_ghe_server %}. - -To ensure that your action is compatible with other platforms, do not use any hard-coded references to API URLs such as `https://api.github.com`. Instead, you can: - -* Use environment variables (see [AUTOTITLE](/actions/reference/variables-reference#default-environment-variables)): - - * For the REST API, use the `GITHUB_API_URL` environment variable. - * For GraphQL, use the `GITHUB_GRAPHQL_URL` environment variable. - -* Use a toolkit such as [`@actions/github`](https://github.com/actions/toolkit/tree/main/packages/github), which can automatically set the correct URLs. - -## Using release management for actions - -This section explains how you can use release management to distribute updates to your actions in a predictable way. - -### Good practices for release management - -If you're developing an action for other people to use, we recommend using release management to control how you distribute updates. Users can expect an action's patch version to include necessary critical fixes and security patches, while still remaining compatible with their existing workflows. You should consider releasing a new major version whenever your changes affect compatibility. - -Under this release management approach, users should not be referencing an action's default branch, as it's likely to contain the latest code and consequently might be unstable. Instead, you can recommend that your users specify a major version when using your action, and only direct them to a more specific version if they encounter issues. - -To use a specific action version, users can configure their {% data variables.product.prodname_actions %} workflow to target a tag, a commit's SHA, or a branch named for a release. - -### Using tags for release management - -We recommend using tags for actions release management. Using this approach, your users can easily distinguish between major and minor versions: - -* Create and validate a release on a release branch (such as `release/v1`) before creating the release tag (for example, `v1.0.2`). -* Create a release using semantic versioning. For more information, see [AUTOTITLE](/repositories/releasing-projects-on-github/managing-releases-in-a-repository). -* Move the major version tag (such as `v1`, `v2`) to point to the Git ref of the current release. For more information, see [Git basics - tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging). -* Introduce a new major version tag (`v2`) for changes that will break existing workflows. For example, changing an action's inputs would be a breaking change. -* Major versions can be initially released with a `beta` tag to indicate their status, for example, `v2-beta`. The `-beta` tag can then be removed when ready. - -This example demonstrates how a user can reference a major release tag: - -```yaml -steps: - - uses: actions/javascript-action@v1 -``` - -This example demonstrates how a user can reference a specific patch release tag: - -```yaml -steps: - - uses: actions/javascript-action@v1.0.1 -``` - -### Using branches for release management - -If you prefer to use branch names for release management, this example demonstrates how to reference a named branch: - -```yaml -steps: - - uses: actions/javascript-action@v1-beta -``` - -### Using a commit's SHA for release management - -Each Git commit receives a calculated SHA value, which is unique and immutable. Your action's users might prefer to rely on a commit's SHA value, as this approach can be more reliable than specifying a tag, which could be deleted or moved. However, this means that users will not receive further updates made to the action. You must use a commit's full SHA value, and not an abbreviated value. - -```yaml -steps: - - uses: actions/javascript-action@a824008085750b8e136effc585c3cd6082bd575f -``` - -## Creating a README file for your action - -We recommend creating a README file to help people learn how to use your action. You can include this information in your `README.md`: - -* A detailed description of what the action does -* Required input and output arguments -* Optional input and output arguments -* Secrets the action uses -* Environment variables the action uses -* An example of how to use your action in a workflow - -## Comparing {% data variables.product.prodname_actions %} to {% data variables.product.prodname_github_apps %} - -{% data variables.product.prodname_marketplace %} offers tools to improve your workflow. Understanding the differences and the benefits of each tool will allow you to select the best tool for your job. For more information about building apps, see [AUTOTITLE](/apps/creating-github-apps/setting-up-a-github-app/about-creating-github-apps). - -### Strengths of GitHub Actions and GitHub Apps - -While both {% data variables.product.prodname_actions %} and {% data variables.product.prodname_github_apps %} provide ways to build automation and workflow tools, they each have strengths that make them useful in different ways. - -{% data variables.product.prodname_github_apps %}: -* Run persistently and can react to events quickly. -* Work great when persistent data is needed. -* Work best with API requests that aren't time consuming. -* Run on a server or compute infrastructure that you provide. - -{% data variables.product.prodname_actions %}: -* Provide automation that can perform continuous integration and continuous deployment. -* Can run directly on runner machines or in Docker containers. -* Can include access to a clone of your repository, enabling deployment and publishing tools, code formatters, and command line tools to access your code. -* Don't require you to deploy code or serve an app. -* Have a simple interface to create and use secrets, which enables actions to interact with third-party services without needing to store the credentials of the person using the action. - -## Further reading - -* [AUTOTITLE](/actions/using-workflows/workflow-commands-for-github-actions) +To learn about how to manage your custom actions, see [AUTOTITLE](/actions/how-tos/administering-github-actions/managing-custom-actions). diff --git a/content/actions/how-tos/administering-github-actions/index.md b/content/actions/how-tos/administering-github-actions/index.md index e164afec891e..b875ec6bb71d 100644 --- a/content/actions/how-tos/administering-github-actions/index.md +++ b/content/actions/how-tos/administering-github-actions/index.md @@ -9,6 +9,7 @@ versions: children: - /viewing-github-actions-metrics - /making-retired-namespaces-available-on-ghecom + - /managing-custom-actions redirect_from: - /actions/administering-github-actions --- diff --git a/content/actions/how-tos/administering-github-actions/managing-custom-actions.md b/content/actions/how-tos/administering-github-actions/managing-custom-actions.md new file mode 100644 index 000000000000..54b321120a95 --- /dev/null +++ b/content/actions/how-tos/administering-github-actions/managing-custom-actions.md @@ -0,0 +1,102 @@ +--- +title: Managing custom actions +intro: 'Learn how to create and manage your own actions, and customize actions shared by the {% data variables.product.prodname_dotcom %} community.' +versions: + fpt: '*' + ghes: '*' + ghec: '*' +type: overview +topics: + - Action development + - Fundamentals +--- + +## Choosing a location for your action + +If you're developing an action for other people to use, we recommend keeping the action in its own repository instead of bundling it with other application code. This allows you to version, track, and release the action just like any other software. + +{% ifversion fpt or ghec %} +Storing an action in its own repository makes it easier for the {% data variables.product.prodname_dotcom %} community to discover the action, narrows the scope of the code base for developers fixing issues and extending the action, and decouples the action's versioning from the versioning of other application code. +{% endif %} + +{% data reusables.actions.internal-actions-summary %} + +{% ifversion fpt or ghec %}If you're building an action that you don't plan to make available to others, you {% else %} You{% endif %} can store the action's files in any location in your repository. If you plan to combine action, workflow, and application code in a single repository, we recommend storing actions in the `.github` directory. For example, `.github/actions/action-a` and `.github/actions/action-b`. + +## Ensuring compatibility with other platforms + +Many people access {% data variables.product.github %} at a domain other than {% data variables.product.prodname_dotcom_the_website %}, such as {% data variables.enterprise.data_residency_site %} or a custom domain for {% data variables.product.prodname_ghe_server %}. + +To ensure that your action is compatible with other platforms, do not use any hard-coded references to API URLs such as `https://api.github.com`. Instead, you can: + +* Use environment variables (see [AUTOTITLE](/actions/reference/variables-reference#default-environment-variables)): + + * For the REST API, use the `GITHUB_API_URL` environment variable. + * For GraphQL, use the `GITHUB_GRAPHQL_URL` environment variable. + +* Use a toolkit such as [`@actions/github`](https://github.com/actions/toolkit/tree/main/packages/github), which can automatically set the correct URLs. + +## Using release management for actions + +This section explains how you can use release management to distribute updates to your actions in a predictable way. + +### Good practices for release management + +If you're developing an action for other people to use, we recommend using release management to control how you distribute updates. Users can expect an action's patch version to include necessary critical fixes and security patches, while still remaining compatible with their existing workflows. You should consider releasing a new major version whenever your changes affect compatibility. + +Under this release management approach, users should not be referencing an action's default branch, as it's likely to contain the latest code and consequently might be unstable. Instead, you can recommend that your users specify a major version when using your action, and only direct them to a more specific version if they encounter issues. + +To use a specific action version, users can configure their {% data variables.product.prodname_actions %} workflow to target a tag, a commit's SHA, or a branch named for a release. + +### Using tags for release management + +We recommend using tags for actions release management. Using this approach, your users can easily distinguish between major and minor versions: + +* Create and validate a release on a release branch (such as `release/v1`) before creating the release tag (for example, `v1.0.2`). +* Create a release using semantic versioning. For more information, see [AUTOTITLE](/repositories/releasing-projects-on-github/managing-releases-in-a-repository). +* Move the major version tag (such as `v1`, `v2`) to point to the Git ref of the current release. For more information, see [Git basics - tagging](https://git-scm.com/book/en/v2/Git-Basics-Tagging). +* Introduce a new major version tag (`v2`) for changes that will break existing workflows. For example, changing an action's inputs would be a breaking change. +* Major versions can be initially released with a `beta` tag to indicate their status, for example, `v2-beta`. The `-beta` tag can then be removed when ready. + +This example demonstrates how a user can reference a major release tag: + +```yaml +steps: + - uses: actions/javascript-action@v1 +``` + +This example demonstrates how a user can reference a specific patch release tag: + +```yaml +steps: + - uses: actions/javascript-action@v1.0.1 +``` + +### Using branches for release management + +If you prefer to use branch names for release management, this example demonstrates how to reference a named branch: + +```yaml +steps: + - uses: actions/javascript-action@v1-beta +``` + +### Using a commit's SHA for release management + +Each Git commit receives a calculated SHA value, which is unique and immutable. Your action's users might prefer to rely on a commit's SHA value, as this approach can be more reliable than specifying a tag, which could be deleted or moved. However, this means that users will not receive further updates made to the action. You must use a commit's full SHA value, and not an abbreviated value. + +```yaml +steps: + - uses: actions/javascript-action@a824008085750b8e136effc585c3cd6082bd575f +``` + +## Creating a README file for your action + +We recommend creating a README file to help people learn how to use your action. You can include this information in your `README.md`: + +* A detailed description of what the action does +* Required input and output arguments +* Optional input and output arguments +* Secrets the action uses +* Environment variables the action uses +* An example of how to use your action in a workflow diff --git a/content/actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners/monitoring-and-troubleshooting-self-hosted-runners.md b/content/actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners/monitoring-and-troubleshooting-self-hosted-runners.md index edaf7a2e9c94..926f76530069 100644 --- a/content/actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners/monitoring-and-troubleshooting-self-hosted-runners.md +++ b/content/actions/how-tos/hosting-your-own-runners/managing-self-hosted-runners/monitoring-and-troubleshooting-self-hosted-runners.md @@ -18,7 +18,7 @@ shortTitle: Monitor & troubleshoot {% data reusables.actions.enterprise-github-hosted-runners %} -## Using repository-level self-hosted runners +## Checking access levels You may not be able to create a self-hosted runner for an organization-owned repository. diff --git a/content/apps/creating-github-apps/about-creating-github-apps/deciding-when-to-build-a-github-app.md b/content/apps/creating-github-apps/about-creating-github-apps/deciding-when-to-build-a-github-app.md index 5ea7a2c3e318..8a61f67ba824 100644 --- a/content/apps/creating-github-apps/about-creating-github-apps/deciding-when-to-build-a-github-app.md +++ b/content/apps/creating-github-apps/about-creating-github-apps/deciding-when-to-build-a-github-app.md @@ -74,7 +74,7 @@ _{% data variables.product.prodname_actions %}_ provide automation that can perf _{% data variables.product.prodname_github_apps %}_ run persistently on a server or compute infrastructure that you provide or run on a user device. They can react to {% data variables.product.company_short %} webhook events as well as events from outside the {% data variables.product.prodname_dotcom %} ecosystem. They are a good option for operations that span multiple repositories or organizations, or for providing hosted services to other organizations and enterprises. A {% data variables.product.prodname_github_app %} is the best choice when building a tool with functions that occur primarily outside of {% data variables.product.prodname_dotcom %} or require more execution time or permissions than what a {% data variables.product.prodname_actions %} workflow is allotted. -For more information about comparing {% data variables.product.prodname_actions %} to {% data variables.product.prodname_github_apps %}, see [AUTOTITLE](/actions/creating-actions/about-custom-actions#comparing-github-actions-to-github-apps). +For more information about comparing {% data variables.product.prodname_actions %} to {% data variables.product.prodname_github_apps %}, see [AUTOTITLE](/actions/concepts/overview/github-actions-vs-github-apps#comparing-github-actions-to-github-apps). You can use a {% data variables.product.prodname_github_app %} to authenticate in a {% data variables.product.prodname_actions %} workflow if the built in `GITHUB_TOKEN` does not have sufficient permissions. For more information, see [AUTOTITLE](/apps/creating-github-apps/guides/making-authenticated-api-requests-with-a-github-app-in-a-github-actions-workflow). diff --git a/src/content-linter/scripts/lint-content.js b/src/content-linter/scripts/lint-content.js index 81e7c2367073..3c5342a4be2d 100755 --- a/src/content-linter/scripts/lint-content.js +++ b/src/content-linter/scripts/lint-content.js @@ -568,6 +568,7 @@ function getMarkdownLintConfig(errorsOnly, runRules) { const searchReplaceRules = [] const dataSearchReplaceRules = [] const ymlSearchReplaceRules = [] + const frontmatterSearchReplaceRules = [] for (const searchRule of ruleConfig.rules) { const searchRuleSeverity = getRuleSeverity(searchRule, isPrecommit) @@ -579,6 +580,11 @@ function getMarkdownLintConfig(errorsOnly, runRules) { if (searchRule['yml-files']) { ymlSearchReplaceRules.push(searchRule) } + // Add search-replace rules to frontmatter configuration for rules that make sense in frontmatter + // This ensures rules like TODOCS detection work in frontmatter + if (searchRule.applyToFrontmatter) { + frontmatterSearchReplaceRules.push(searchRule) + } } if (searchReplaceRules.length > 0) { @@ -593,6 +599,10 @@ function getMarkdownLintConfig(errorsOnly, runRules) { config.yml[ruleName] = { ...ruleConfig, rules: ymlSearchReplaceRules } if (customRule) configuredRules.yml.push(customRule) } + if (frontmatterSearchReplaceRules.length > 0) { + config.frontMatter[ruleName] = { ...ruleConfig, rules: frontmatterSearchReplaceRules } + if (customRule) configuredRules.frontMatter.push(customRule) + } continue } diff --git a/src/content-linter/style/github-docs.js b/src/content-linter/style/github-docs.js index dec20d56789a..2600cffd27c5 100644 --- a/src/content-linter/style/github-docs.js +++ b/src/content-linter/style/github-docs.js @@ -342,6 +342,7 @@ export const searchReplaceConfig = { precommitSeverity: 'warning', 'partial-markdown-files': true, 'yml-files': true, + applyToFrontmatter: true, // Critical for content quality - prevents placeholders in titles, intros, etc. }, { name: 'docs-domain', @@ -351,6 +352,7 @@ export const searchReplaceConfig = { severity: 'error', 'partial-markdown-files': true, 'yml-files': true, + applyToFrontmatter: true, // Should not appear in frontmatter }, { name: 'help-domain', @@ -360,6 +362,7 @@ export const searchReplaceConfig = { severity: 'error', 'partial-markdown-files': true, 'yml-files': true, + applyToFrontmatter: true, // Should not appear in frontmatter }, { name: 'developer-domain', @@ -373,6 +376,7 @@ export const searchReplaceConfig = { severity: 'error', 'partial-markdown-files': true, 'yml-files': true, + applyToFrontmatter: true, // Should not appear in frontmatter }, { // Catches usage of old liquid data reusable syntax. For example: @@ -384,6 +388,7 @@ export const searchReplaceConfig = { severity: 'error', 'partial-markdown-files': true, 'yml-files': true, + applyToFrontmatter: true, // Can appear in frontmatter strings }, { // Catches usage of old octicon variable syntax. For example: @@ -396,6 +401,7 @@ export const searchReplaceConfig = { severity: 'error', 'partial-markdown-files': true, 'yml-files': true, + applyToFrontmatter: true, // Can appear in frontmatter strings }, ], }, diff --git a/src/content-linter/tests/unit/frontmatter-search-replace.js b/src/content-linter/tests/unit/frontmatter-search-replace.js new file mode 100644 index 000000000000..152e61e67290 --- /dev/null +++ b/src/content-linter/tests/unit/frontmatter-search-replace.js @@ -0,0 +1,119 @@ +import { describe, expect, test } from 'vitest' +import markdownlint from 'markdownlint' +import searchReplace from 'markdownlint-rule-search-replace' + +import { searchReplaceConfig } from '../../style/github-docs' + +describe('search-replace rule in frontmatter', () => { + test('TODOCS placeholder in frontmatter is detected', async () => { + const markdown = ['---', 'title: TODOCS', '---', '', 'Clean content.'].join('\n') + + const result = await markdownlint.promises.markdownlint({ + frontMatter: null, + strings: { markdown }, + config: { + 'search-replace': searchReplaceConfig['search-replace'], + }, + customRules: [searchReplace], + }) + + const errors = result.markdown || [] + + // Should find TODOCS in frontmatter + const todosErrors = errors.filter((e) => e.errorDetail && /TODOCS/.test(e.errorDetail)) + expect(todosErrors.length).toBe(1) + expect(todosErrors[0].lineNumber).toBe(2) // title: TODOCS + }) + + test('multiple TODOCS in frontmatter are all detected', async () => { + const markdown = [ + '---', + 'title: TODOCS', + 'shortTitle: TODOCS', + 'intro: TODOCS', + '---', + '', + 'Content without placeholder.', + ].join('\n') + + const result = await markdownlint.promises.markdownlint({ + frontMatter: null, + strings: { markdown }, + config: { + 'search-replace': searchReplaceConfig['search-replace'], + }, + customRules: [searchReplace], + }) + + const errors = result.markdown || [] + + // Should find all TODOCS instances in frontmatter + const todosErrors = errors.filter((e) => e.errorDetail && /TODOCS/.test(e.errorDetail)) + expect(todosErrors.length).toBe(3) + expect(todosErrors[0].lineNumber).toBe(2) // title: TODOCS + expect(todosErrors[1].lineNumber).toBe(3) // shortTitle: TODOCS + expect(todosErrors[2].lineNumber).toBe(4) // intro: TODOCS + }) + + test('domain rules work in frontmatter', async () => { + const markdown = [ + '---', + 'title: Check docs.github.com for info', + 'shortTitle: Visit help.github.com', + 'intro: See developer.github.com for API docs', + '---', + '', + 'Content without domain references.', + ].join('\n') + + const result = await markdownlint.promises.markdownlint({ + frontMatter: null, + strings: { markdown }, + config: { + 'search-replace': searchReplaceConfig['search-replace'], + }, + customRules: [searchReplace], + }) + + const errors = result.markdown || [] + + // Should find domain errors in frontmatter + const domainErrors = errors.filter( + (e) => e.errorDetail && /docs-domain|help-domain|developer-domain/.test(e.errorDetail), + ) + expect(domainErrors.length).toBe(3) + expect(domainErrors[0].lineNumber).toBe(2) // docs domain in title + expect(domainErrors[1].lineNumber).toBe(3) // help domain in shortTitle + expect(domainErrors[2].lineNumber).toBe(4) // developer domain in intro + }) + + test('deprecated liquid syntax in frontmatter is detected', async () => { + const markdown = [ + '---', + 'title: "{{ site.data.variables.product.product_name }}"', + 'intro: "Use {{ octicon-plus An icon }} here"', + '---', + '', + 'Clean content.', + ].join('\n') + + const result = await markdownlint.promises.markdownlint({ + frontMatter: null, + strings: { markdown }, + config: { + 'search-replace': searchReplaceConfig['search-replace'], + }, + customRules: [searchReplace], + }) + + const errors = result.markdown || [] + + // Should find deprecated syntax errors in frontmatter + const deprecatedErrors = errors.filter( + (e) => e.errorDetail && /site\.data|octicon/.test(e.errorDetail), + ) + expect(deprecatedErrors.length).toBe(2) + expect(deprecatedErrors[0].lineNumber).toBe(2) // site.data syntax + expect(deprecatedErrors[1].lineNumber).toBe(3) // octicon syntax + }) +}) diff --git a/src/content-linter/tests/unit/search-replace.js b/src/content-linter/tests/unit/search-replace.js index af1317325f78..221db55d8449 100644 --- a/src/content-linter/tests/unit/search-replace.js +++ b/src/content-linter/tests/unit/search-replace.js @@ -60,4 +60,102 @@ describe(searchReplace.names.join(' - '), () => { const errors = result.markdown expect(errors.length).toBe(4) }) + + test('TODOCS placeholder in frontmatter causes errors when frontmatter is included', async () => { + const markdown = [ + '---', + 'title: TODOCS', + 'shortTitle: TODOCS', + 'intro: TODOCS', + 'versions:', + ' ghec: "*"', + '---', + '', + 'This is content that has no placeholder.', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + ruleConfig: searchReplaceConfig['search-replace'], + markdownlintOptions: { frontMatter: null }, // Include frontmatter in linting + }) + const errors = result.markdown + // Should find 3 TODOCS occurrences in frontmatter + expect(errors.length).toBe(3) + expect(errors[0].lineNumber).toBe(2) // title: TODOCS + expect(errors[1].lineNumber).toBe(3) // shortTitle: TODOCS + expect(errors[2].lineNumber).toBe(4) // intro: TODOCS + }) + + test('TODOCS placeholder in both frontmatter and content', async () => { + const markdown = [ + '---', + 'title: TODOCS', + 'intro: TODOCS', + '---', + '', + 'This content has TODOCS placeholder.', + 'And another TODOCS here.', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + ruleConfig: searchReplaceConfig['search-replace'], + markdownlintOptions: { frontMatter: null }, // Include frontmatter in linting + }) + const errors = result.markdown + // Should find 4 TODOCS occurrences total (2 in frontmatter + 2 in content) + expect(errors.length).toBe(4) + expect(errors[0].lineNumber).toBe(2) // title: TODOCS + expect(errors[1].lineNumber).toBe(3) // intro: TODOCS + expect(errors[2].lineNumber).toBe(6) // content TODOCS + expect(errors[3].lineNumber).toBe(7) // content TODOCS + }) + + test('TODOCS placeholder in frontmatter is not caught with default frontmatter handling', async () => { + const markdown = [ + '---', + 'title: TODOCS', + 'shortTitle: TODOCS', + 'intro: TODOCS', + 'versions:', + ' ghec: "*"', + '---', + '', + 'This is content that has no placeholder.', + ].join('\n') + const result = await runRule(searchReplace, { + strings: { markdown }, + ruleConfig: searchReplaceConfig['search-replace'], + // Default frontmatter handling (frontmatter is stripped from content) + }) + const errors = result.markdown + // When using default frontmatter handling (frontmatter is stripped from content), + // this unit test only tests the search-replace rule in isolation on the content portion. + // Frontmatter linting happens separately in the actual linting system. + expect(errors.length).toBe(0) + }) + + test('TODOCS in frontmatter is detected when frontmatter is included in content', async () => { + // This test shows that search-replace works on frontmatter when it's included in content + const frontmatterOnly = [ + '---', + 'title: TODOCS', + 'shortTitle: TODOCS', + 'intro: TODOCS', + '---', + ].join('\n') + + // When frontmatter is treated as content, search-replace works + const result = await runRule(searchReplace, { + strings: { markdown: frontmatterOnly }, + ruleConfig: searchReplaceConfig['search-replace'], + markdownlintOptions: { frontMatter: null }, // Include frontmatter in content + }) + const errors = result.markdown + + // Finds all 3 TODOCS in frontmatter when frontmatter is included in content + expect(errors.length).toBe(3) + expect(errors[0].lineNumber).toBe(2) // title: TODOCS + expect(errors[1].lineNumber).toBe(3) // shortTitle: TODOCS + expect(errors[2].lineNumber).toBe(4) // intro: TODOCS + }) }) pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy